public override float GetOptimizableCalculationValue(string calculation) { switch (calculation) { case "Health": return(BasicStats.Health); case "Avoided Attacks %": return(AvoidedAttacks); case "Hit Rating": return(BasicStats.HitRating); case "Hit Rating %": return(StatConversion.GetPhysicalHitFromRating(BasicStats.HitRating) * 100); case "Expertise Rating": return(BasicStats.ExpertiseRating); case "Expertise": return(StatConversion.GetExpertiseFromRating(BasicStats.ExpertiseRating)); case "Expertise Rating %": return(StatConversion.GetExpertiseFromRating(BasicStats.ExpertiseRating) * 0.25f); case "Nature Resist": return(BasicStats.NatureResistance); case "Fire Resist": return(BasicStats.FireResistance); case "Frost Resist": return(BasicStats.FrostResistance); case "Shadow Resist": return(BasicStats.ShadowResistance); case "Arcane Resist": return(BasicStats.ArcaneResistance); //case "Custom Rotation DPS": return CustomRotation.DPS; } return(0f); }
public static float BonusExpertisePercentage(Character character, Stats stats) { return(StatConversion.GetDodgeParryReducFromExpertise(stats.Expertise + StatConversion.GetExpertiseFromRating(stats.ExpertiseRating), CharacterClass.Warrior)); //return (((stats.ExpertiseRating * ProtWarr.ExpertiseRatingToExpertise) + stats.Expertise) // * ProtWarr.ExpertiseToDodgeParryReduction) / 100.0f; }
private void Set_c_values() { _c_rwItemType = RW.Type; _c_rwItemSpeed = RW.Speed; useRW = _useRW; // public variable gets set once _c_rwRacialExpertise = GetRacialExpertiseFromWeaponType(_c_rwItemType); _c_rwexpertise = StatS.Expertise + StatConversion.GetExpertiseFromRating(StatS.ExpertiseRating) + _c_rwRacialExpertise; _c_ymiss = YwMissChance; _c_wmiss = WhMissChance; _c_rwdodge = RwDodgeChance; _c_rwparry = RwParryChance; _c_rwblock = RwBlockChance; _c_rwwcrit = RwWhCritChance; _c_rwycrit = RwYwCritChance; _c_glance = GlanceChance; }
private void Set_c_values() { _c_mhItemType = MH.Type; _c_mhItemSpeed = MH.Speed; if (OH != null) { _c_ohItemType = OH.Type; _c_ohItemSpeed = OH.Speed; } useMH = _useMH; // public variable gets set once useOH = _useOH; _c_mhRacialExpertise = GetRacialExpertiseFromWeaponType(_c_mhItemType); _c_mhexpertise = StatS.Expertise + StatConversion.GetExpertiseFromRating(Math.Max(0, StatS.ExpertiseRating)) + _c_mhRacialExpertise; _c_ymiss = YwMissChance; _c_wmiss = WhMissChance; _c_mhdodge = MhDodgeChance; _c_mhparry = MhParryChance; _c_mhblock = MhBlockChance; _c_mhwcrit = MhWhCritChance; _c_mhycrit = MhYwCritChance; _c_glance = GlanceChance; if (useOH) { _c_ohRacialExpertise = GetRacialExpertiseFromWeaponType(_c_ohItemType); _c_ohexpertise = StatS.Expertise + StatConversion.GetExpertiseFromRating(Math.Max(0, StatS.ExpertiseRating)) + _c_ohRacialExpertise; _c_ohdodge = OhDodgeChance; _c_ohparry = OhParryChance; _c_ohblock = OhBlockChance; _c_ohwcrit = OhWhCritChance; _c_ohycrit = OhYwCritChance; } else { _c_ohItemType = ItemType.None; _c_ohItemSpeed = 0f; _c_ohRacialExpertise = 0f; _c_ohexpertise = 0f; _c_ohdodge = StatConversion.WHITE_DODGE_CHANCE_CAP[levelDif]; _c_ohparry = StatConversion.WHITE_PARRY_CHANCE_CAP[levelDif]; _c_ohblock = 0.0f; _c_ohwcrit = 0.0f; _c_ohycrit = 0.0f; } }
private void SetCvalues() { CMHItemType = MH.Type; CMHItemSpeed = MH.Speed; if (OH != null) { COHItemType = OH.Type; COHItemSpeed = OH.Speed; } useMH = _useMH; // public variable gets set once useOH = _useOH; CMHRacialExpertise = BaseStats.GetRacialExpertise(Char, ItemSlot.MainHand); //GetRacialExpertiseFromWeaponType(CmhItemType); CMHexpertise = StatS.Expertise + StatConversion.GetExpertiseFromRating(Math.Max(0, StatS.ExpertiseRating)) + CMHRacialExpertise; CYmiss = YwMissChance; CWmiss = WhMissChance; CMHdodge = MhDodgeChance; CMHparry = MhParryChance; CMHblock = MhBlockChance; CMHwcrit = MhWhCritChance; CMHycrit = MhYwCritChance; CGlance = GlanceChance; if (useOH) { COHRacialExpertise = BaseStats.GetRacialExpertise(Char, ItemSlot.OffHand);// GetRacialExpertiseFromWeaponType(CohItemType); COhexpertise = StatS.Expertise + StatConversion.GetExpertiseFromRating(Math.Max(0, StatS.ExpertiseRating)) + COHRacialExpertise; COhdodge = OhDodgeChance; COhparry = OhParryChance; COhblock = OhBlockChance; COhwcrit = OhWhCritChance; COhycrit = OhYwCritChance; } else { COHItemType = ItemType.None; COHItemSpeed = 0f; COHRacialExpertise = 0f; COhexpertise = 0f; COhdodge = StatConversion.WHITE_DODGE_CHANCE_CAP[LevelDif]; COhparry = StatConversion.WHITE_PARRY_CHANCE_CAP[LevelDif]; COhblock = 0.0f; COhwcrit = 0.0f; COhycrit = 0.0f; } }
protected override void Calculate() { float tableSize = 0f; // Miss if (useSpellHit) { Miss = Math.Min(1f - tableSize, Math.Max(0f, StatConversion.GetSpellMiss(-LevelDelta, false) - StatS.SpellHit - StatConversion.GetSpellHitFromRating(StatS.HitRating))); } else { Miss = Math.Min(1f - tableSize, Math.Max(0f, StatConversion.YELLOW_MISS_CHANCE_CAP[LevelDelta] - StatS.PhysicalHit - StatConversion.GetSpellHitFromRating(StatS.HitRating))); } tableSize += Miss; // Dodge if (!useSpellHit) { Dodge = Math.Min(1f - tableSize, Math.Max(0f, StatConversion.YELLOW_DODGE_CHANCE_CAP[LevelDelta] - StatConversion.GetDodgeParryReducFromExpertise( StatConversion.GetExpertiseFromRating(StatS.ExpertiseRating, Char.Class), Char.Class)) ); tableSize += Dodge; } else { Dodge = 0f; } // Parry if (!useSpellHit) { Parry = Math.Min(1f - tableSize, Math.Max(0f, StatConversion.YELLOW_PARRY_CHANCE_CAP[LevelDelta] - StatConversion.GetDodgeParryReducFromExpertise( StatConversion.GetExpertiseFromRating(StatS.ExpertiseRating, Char.Class), Char.Class)) ); tableSize += Parry; } else { Parry = 0f; } // Block //if (isWhite || Abil.CanBeBlocked) { //Block = Math.Min(1f - tableSize, isMH ? combatFactors._c_mhblock : combatFactors._c_ohblock); //tableSize += Block; //} else { Block = 0f; } // Glancing Blow //if (isWhite) { //Glance = Math.Min(1f - tableSize, combatFactors._c_glance); //tableSize += Glance; //} else { Glance = 0f; } // Critical Hit Crit = 0; /*if (isWhite) { * float critValueToUse = (isMH ? combatFactors._c_mhwcrit : combatFactors._c_ohwcrit); * foreach (WeightedStat ws in combatFactors.critProcs) * { * float modCritChance = Math.Min(1f - tableSize, critValueToUse + StatConversion.GetCritFromRating(ws.Value, Char.Class)) + StatConversion.NPC_LEVEL_CRIT_MOD[calcOpts.TargetLevel - Char.Level]; + Crit += ws.Chance * modCritChance; + } + tableSize += Crit; + } else if (Abil.CanCrit) {*/ float critValueToUse = StatConversion.NPC_LEVEL_CRIT_MOD[LevelDelta] + (useSpellHit ? StatS.SpellCrit : StatS.PhysicalCrit); foreach (WeightedStat ws in critProcs) { float modCritChance = Math.Min(1f - tableSize, (critValueToUse + StatConversion.GetCritFromRating(ws.Value, Char.Class)) * (1f - Dodge - Miss)); Crit += ws.Chance * modCritChance; } if (Crit < 0) { Crit = 0f; } tableSize += Crit; //} // Normal Hit Hit = Math.Max(0f, 1f - tableSize); base.Calculate(); }
public override Dictionary <string, string> GetCharacterDisplayCalculationValues() { Dictionary <string, string> dictValues = new Dictionary <string, string>(); dictValues.Add("Health", BasicStats.Health.ToString()); dictValues.Add("Strength", BasicStats.Strength.ToString()); dictValues.Add("Agility", BasicStats.Agility.ToString()); dictValues.Add("Stamina", BasicStats.Stamina.ToString()); dictValues.Add("Armor", string.Format("{0}*Reduces physical damage taken by {1:0.00%}", BasicStats.Armor, ArmorReduction)); dictValues.Add("Defense", Defense.ToString() + string.Format("*Defense Rating {0}", BasicStats.DefenseRating)); dictValues.Add("Dodge", string.Format("{0:0.00%}*Dodge Rating {1}", Dodge, BasicStats.DodgeRating)); dictValues.Add("Parry", string.Format("{0:0.00%}*Parry Rating {1}", Parry, BasicStats.ParryRating)); dictValues.Add("Block", string.Format("{0:0.00%}*Block Rating {1}", Block, BasicStats.BlockRating)); dictValues.Add("Miss", string.Format("{0:0.00%}", Miss)); dictValues.Add("Block Value", string.Format("{0}", BlockValue)); dictValues.Add("Guaranteed Reduction", string.Format("{0:0.00%}", GuaranteedReduction)); dictValues.Add("Avoidance", string.Format("{0:0.00%} (+Block {1:0.00%})", DodgePlusMissPlusParry, DodgePlusMissPlusParryPlusBlock)); dictValues.Add("Total Mitigation", string.Format("{0:0.00%}", TotalMitigation)); if (AttackerSpeed == BaseAttackerSpeed) { dictValues.Add("Attacker Speed", string.Format("{0:0.00}s", AttackerSpeed)); } else { dictValues.Add("Attacker Speed", string.Format("{0:0.00}s*Base speed of {1:0.00}s (modified by haste)", AttackerSpeed, BaseAttackerSpeed)); } dictValues.Add("Damage Taken", string.Format("{0:0.0} DPS*{1:0} damage per normal attack" + Environment.NewLine + "{2:0} damage per blocked attack" + Environment.NewLine + "{3:0} damage per critically blocked attack" + Environment.NewLine + "{4:0} damage per critical attack", DamageTaken, DamageTakenPerHit, DamageTakenPerBlock, DamageTakenPerCritBlock, DamageTakenPerCrit)); dictValues.Add("Resilience", string.Format(@"{0}*Reduces the damage of critical strikes and chance to be critically hit by {1}%.", BasicStats.Resilience, StatConversion.GetCritReductionFromResilience(BasicStats.Resilience, CharacterClass.Warrior))); if (CritVulnerability > 0.0001f) { float resilienceNeeded = (float)Math.Ceiling((StatConversion.RATING_PER_RESILIENCE * CritVulnerability)); dictValues.Add("Chance to be Crit", string.Format("{0:0.00%}*CRITTABLE! Short by {1:0} defense or {2:0} resilience to be uncrittable.", CritVulnerability, DefenseRatingNeeded, resilienceNeeded)); } else { dictValues.Add("Chance to be Crit", string.Format("{0:0.00%}*Chance to crit reduced by {1:0.00%}", CritVulnerability, CritReduction)); } dictValues.Add("Nature Resist", string.Format("{0:0}*{1:0.00%} Total Reduction in Defensive Stance", BasicStats.NatureResistance, NatureReduction)); dictValues.Add("Arcane Resist", string.Format("{0:0}*{1:0.00%} Total Reduction in Defensive Stance", BasicStats.ArcaneResistance, ArcaneReduction)); dictValues.Add("Frost Resist", string.Format("{0:0}*{1:0.00%} Total Reduction in Defensive Stance", BasicStats.FrostResistance, FrostReduction)); dictValues.Add("Fire Resist", string.Format("{0:0}*{1:0.00%} Total Reduction in Defensive Stance", BasicStats.FireResistance, FireReduction)); dictValues.Add("Shadow Resist", string.Format("{0:0}*{1:0.00%} Total Reduction in Defensive Stance", BasicStats.ShadowResistance, ShadowReduction)); dictValues["Nature Survival"] = NatureSurvivalPoints.ToString(); dictValues["Frost Survival"] = FrostSurvivalPoints.ToString(); dictValues["Fire Survival"] = FireSurvivalPoints.ToString(); dictValues["Shadow Survival"] = ShadowSurvivalPoints.ToString(); dictValues["Arcane Survival"] = ArcaneSurvivalPoints.ToString(); dictValues.Add("Weapon Speed", string.Format("{0:0.00}*{1:0.00%} Haste", WeaponSpeed, Haste)); dictValues.Add("Attack Power", string.Format("{0}", BasicStats.AttackPower)); dictValues.Add("Hit", string.Format("{0:0.00%}*Hit Rating {1}", Hit, BasicStats.HitRating)); dictValues.Add("Expertise", string.Format("{0}*Expertise Rating {1}" + Environment.NewLine + "Reduces chance to be dodged or parried by {2:0.00%}.", Math.Round(StatConversion.GetExpertiseFromRating(BasicStats.ExpertiseRating, CharacterClass.Warrior) + BasicStats.Expertise), BasicStats.ExpertiseRating, Expertise)); dictValues.Add("Haste", string.Format("{0:0.00%}*Haste Rating {1:0.00}", Haste, BasicStats.HasteRating)); dictValues.Add("Armor Penetration", string.Format("{0:0.00%}*Armor Penetration Rating {1}" + Environment.NewLine + "Armor Reduction {2}", ArmorPenetration, BasicStats.ArmorPenetrationRating, BasicStats.ArmorPenetration)); dictValues.Add("Crit", string.Format("{0:0.00%}*Crit Rating {1}", Crit, BasicStats.CritRating)); // Never really used in current WoW itemization, just taking up space // dictValues.Add("Weapon Damage", string.Format("{0}", BasicStats.WeaponDamage)); dictValues.Add("Missed Attacks", string.Format("{0:0.00%}*Attacks Missed: {1:0.00%}" + Environment.NewLine + "Attacks Dodged: {2:0.00%}" + Environment.NewLine + "Attacks Parried: {3:0.00%}", AvoidedAttacks, MissedAttacks, DodgedAttacks, ParriedAttacks)); dictValues.Add("Total Damage/sec", string.Format("{0:0.0}", TotalDamagePerSecond)); dictValues.Add("Total Threat/sec", string.Format("{0:0.0}*{1:0%} of Swings converted to Heroic Strikes", ThreatPerSecond, HeroicStrikeFrequency)); dictValues.Add("Rotation", ThreatModelName + "*" + ThreatModel); switch (RankingMode) { case 2: dictValues.Add("Ranking Mode", "TankPoints*The average amount of unmitigated damage which can be taken before dying"); dictValues.Add("Survival Points", string.Format("{0:0}*Effective Health", SurvivalPoints)); break; case 3: dictValues.Add("Ranking Mode", "Burst Time*The average amount of time between events which have a chance to result in a burst death"); dictValues.Add("Survival Points", string.Format("{0:0}*{1:0.00} seconds between events", SurvivalPoints, SurvivalPoints / 100.0f)); break; case 4: dictValues.Add("Ranking Mode", "Damage Output*The average amount of DPS which can be produced"); dictValues.Add("Survival Points", string.Format("{0:0}*Survival is not weighted in this mode", SurvivalPoints, SurvivalPoints / 100.0f)); break; default: dictValues.Add("Ranking Mode", "Mitigation Scale*Customizable scale which allows you to weight mitigation vs. effective health."); dictValues.Add("Survival Points", string.Format("{0:0}*Effective Health", SurvivalPoints)); break; } dictValues.Add("Overall Points", string.Format("{0:0}", OverallPoints)); dictValues.Add("Mitigation Points", string.Format("{0:0}", MitigationPoints)); dictValues.Add("Threat Points", string.Format("{0:0}", ThreatPoints)); return(dictValues); }
public override Dictionary <string, string> GetCharacterDisplayCalculationValues() { Dictionary <string, string> dictValues = new Dictionary <string, string>(); dictValues.Add("Health", BasicStats.Health.ToString()); dictValues.Add("Mana", BasicStats.Mana.ToString()); dictValues.Add("Strength", BasicStats.Strength.ToString()); dictValues.Add("Agility", BasicStats.Agility.ToString()); dictValues.Add("Stamina", string.Format("{0}*Increases Health by {1}", BasicStats.Stamina, (BasicStats.Stamina - 20f) * 10f + 20f)); dictValues.Add("Intellect", BasicStats.Intellect.ToString()); dictValues.Add("Armor", string.Format("{0}*Reduces physical damage taken by {1:0.00%}" + Environment.NewLine + "Armor Damage Reduction depends on Attacker Level.", BasicStats.Armor, ArmorReduction)); dictValues.Add("Dodge", string.Format("{0:0.0000%}*Dodge Rating {1}", Dodge, BasicStats.DodgeRating)); dictValues.Add("Parry", string.Format("{0:0.0000%}*Parry Rating {1}", Parry, BasicStats.ParryRating)); dictValues.Add("Block", string.Format("{0:0.0000%}*Block Rating {1}", Block, BasicStats.BlockRating)); dictValues.Add("Mastery", string.Format("{0}*Mastery Rating {1}" + Environment.NewLine + "Adds {2:0.0000%} Block", Mastery, BasicStats.MasteryRating, Mastery * 0.0225f)); dictValues.Add("Miss", string.Format("{0:0.0000%}", Miss)); dictValues.Add("Guaranteed Reduction", string.Format("{0:0.00%}", GuaranteedReduction)); dictValues.Add("Avoidance", string.Format("{0:0.0000%}*Avoidance Points {1}", DodgePlusMissPlusParry, (DodgePlusMissPlusParry * 10000f))); dictValues.Add("Avoidance + Block", string.Format("{0:0.0000%}", DodgePlusMissPlusParryPlusBlock)); dictValues.Add("Total Mitigation", string.Format("{0:0.00%}", TotalMitigation)); dictValues.Add("Attacker Speed", string.Format("{0:0.00}s", AttackerSpeed)); dictValues.Add("Damage Taken", string.Format("{0:0.0} DPS*{1:0} damage per normal attack" + Environment.NewLine + "{2:0} damage per blocked attack" + Environment.NewLine + "{3:0} damage per critical attack" + Environment.NewLine + "On Average, you take" + Environment.NewLine + "{4:0.00%} of incoming damage", DPSTaken, DamageTakenPerHit, DamageTakenPerBlock, DamageTakenPerCrit, DamageTaken)); dictValues.Add("Resilience", string.Format(@"{0}" /* + "*Reduces periodic damage by {1:0.00%}." + Environment.NewLine + * "Reduces the effect of mana-drains and the damage of critical strikes by {2:0.00%}."*/, BasicStats.Resilience //, //StatConversion.GetCritReductionFromResilience(BasicStats.Resilience,CharacterClass.Paladin), //StatConversion.GetCritReductionFromResilience(BasicStats.Resilience,CharacterClass.Paladin)*2f )); if (CritVulnerability > 0.0001f) { dictValues.Add("Chance to be Crit", string.Format("{0:0.00%}*CRITTABLE! Spec 3 points into the protection talent Sanctuary to be uncrittable.", CritVulnerability)); } else { dictValues.Add("Chance to be Crit", string.Format("{0:0.00%}*Chance to be crit reduced by {1:0.00%}", CritVulnerability, CritReduction)); } dictValues.Add("Nature Resist", string.Format("{0:0}*{1:0.00%} Total Reduction", BasicStats.NatureResistance, NatureReduction)); dictValues.Add("Arcane Resist", string.Format("{0:0}*{1:0.00%} Total Reduction", BasicStats.ArcaneResistance, ArcaneReduction)); dictValues.Add("Frost Resist", string.Format("{0:0}*{1:0.00%} Total Reduction", BasicStats.FrostResistance, FrostReduction)); dictValues.Add("Fire Resist", string.Format("{0:0}*{1:0.00%} Total Reduction", BasicStats.FireResistance, FireReduction)); dictValues.Add("Shadow Resist", string.Format("{0:0}*{1:0.00%} Total Reduction", BasicStats.ShadowResistance, ShadowReduction)); dictValues["Nature Survival"] = NatureSurvivalPoints.ToString(); dictValues["Frost Survival"] = FrostSurvivalPoints.ToString(); dictValues["Fire Survival"] = FireSurvivalPoints.ToString(); dictValues["Shadow Survival"] = ShadowSurvivalPoints.ToString(); dictValues["Arcane Survival"] = ArcaneSurvivalPoints.ToString(); dictValues.Add("Weapon Speed", string.Format("{0:0.00}*{1:0.00%} Haste", WeaponSpeed, PhysicalHaste)); dictValues.Add("Attack Power", string.Format("{0}", BasicStats.AttackPower)); dictValues.Add("Spell Power", string.Format("{0}", BasicStats.SpellPower)); dictValues.Add("Hit", string.Format("{0:0.00%}*Hit Rating {1}" + Environment.NewLine + "Against a Target of Level {2}", Hit, BasicStats.HitRating, TargetLevel)); dictValues.Add("Spell Hit", string.Format("{0:0.00%}*Hit Rating {1}" + Environment.NewLine + "Against a Target of Level {2}", SpellHit, BasicStats.HitRating, TargetLevel)); dictValues.Add("Expertise", string.Format("{0:0.00}*Expertise Rating {1}" + Environment.NewLine + "Reduces chance to be dodged or parried by {2:0.00%}.", StatConversion.GetExpertiseFromRating(BasicStats.ExpertiseRating, CharacterClass.Paladin) + BasicStats.Expertise, BasicStats.ExpertiseRating, Expertise)); dictValues.Add("Physical Haste", string.Format("{0:0.00%}*Haste Rating {1:0.00}", PhysicalHaste, BasicStats.HasteRating)); dictValues.Add("Effective Target Armor", string.Format("{0}*Reduces the physical damage you deal by {1:0.00%}" + Environment.NewLine + Environment.NewLine + "Effective Armor depends on Armor ignore debuffs," + Environment.NewLine + "your Armor Penetration buffs and talents." + Environment.NewLine + "Enemy Damage Reduction depends on your Level.", (float)Math.Floor(EffectiveTargetArmor), EffectiveTargetArmorDamageReduction)); dictValues.Add("Crit", string.Format("{0:0.00%}*Crit Rating {1}" + Environment.NewLine + "Against a Target of Level {2}", Crit, BasicStats.CritRating, TargetLevel)); dictValues.Add("Spell Crit", string.Format("{0:0.00%}*Crit Rating {1}" + Environment.NewLine + "Against a Target of Level {2}", SpellCrit, BasicStats.CritRating, TargetLevel)); dictValues.Add("Weapon Damage", string.Format("{0:0.00}*As average damage per {1}" + Environment.NewLine + "Before Armor", BasicStats.WeaponDamage, Lookup.Name(Ability.MeleeSwing))); dictValues.Add("Missed Attacks", string.Format("{0:0.00%}*Attacks Missed: {1:0.00%}" + Environment.NewLine + "Attacks Dodged: {2:0.00%}" + Environment.NewLine + "Attacks Parried: {3:0.00%}", AvoidedAttacks, MissedAttacks, DodgedAttacks, ParriedAttacks)); dictValues.Add("Glancing Attacks", string.Format("{0:0.00%}*{1:0.00%} Reduction" + Environment.NewLine + "Against a Target of Level {2}", GlancingAttacks, 1.0f - GlancingReduction, TargetLevel)); dictValues.Add("Total Damage/sec", string.Format("{0:0.0}", TotalDamagePerSecond) + "*" + ThreatModel); dictValues.Add("Threat/sec", string.Format("{0:0.0}", ThreatPerSecond) + "*" + ThreatModel); //dictValues.Add("Unlimited Threat/sec", string.Format("{0:0.0}", UnlimitedThreat) + "*" + ThreatModel); switch (RankingMode) { case 1: dictValues.Add("Ranking Mode", "Burst Time*The average amount of time between events which have a chance to result in a burst death"); dictValues.Add("Survival Points", string.Format("{0:0}*{1:0.00} seconds between events", SurvivabilityPoints, SurvivabilityPoints / 100.0f)); break; case 2: dictValues.Add("Ranking Mode", "Damage Output*The average amount of DPS which can be produced"); dictValues.Add("Survival Points", string.Format("{0:0}*Survival is not weighted in this mode", SurvivabilityPoints, SurvivabilityPoints / 100.0f)); break; case 0: default: dictValues.Add("Ranking Mode", "Mitigation Scale*Customizable scale which allows you to weight mitigation vs. effective health."); dictValues.Add("Survival Points", string.Format("{0:0}*Effective Health", SurvivabilityPoints)); break; } dictValues.Add("Overall Points", string.Format("{0:0}", OverallPoints)); dictValues.Add("Mitigation Points", string.Format("{0:0}", MitigationPoints)); dictValues.Add("Threat Points", string.Format("{0:0}", ThreatPoints)); dictValues.Add("CTC Points", string.Format("{0:0}", CTCPoints)); return(dictValues); }
public void UpdateCalcs(bool firstPass) { // talents if (_calcOpts.PriorityInUse(EnhanceAbility.StormStrike)) { stormstrikeBonusCrit = .25f * _talents.Stormstrike + (_talents.GlyphofStormstrike ? .1f : 0f); } else { stormstrikeBonusCrit = 0f; } //set bonus enhance4T11 = 0f; _character.SetBonusCount.TryGetValue("Battlegear of the Raging Elements", out setCount); if (setCount >= 4) { enhance4T11 = 0.1f; } critMultiplierSpell = 1.5f * (1 + _stats.BonusSpellCritDamageMultiplier); critMultiplierMelee = 2f * (1 + _stats.BonusCritDamageMultiplier); // Melee float hitBonus = _stats.PhysicalHit + StatConversion.GetHitFromRating(_stats.HitRating) + 0.06f; //DualWieldSpecialization expertiseBonusMH = GetDPRfromExp(_stats.Expertise + StatConversion.GetExpertiseFromRating(_stats.ExpertiseRating) + BaseStats.GetRacialExpertise(_character, ItemSlot.MainHand)); expertiseBonusOH = GetDPRfromExp(_stats.Expertise + StatConversion.GetExpertiseFromRating(_stats.ExpertiseRating) + BaseStats.GetRacialExpertise(_character, ItemSlot.OffHand)); float meleeCritModifier = _stats.PhysicalCrit; float baseMeleeCrit = StatConversion.GetCritFromRating(_stats.CritRating) + StatConversion.GetCritFromAgility(_stats.Agility, _character.Class) + .01f * _talents.Acuity; chanceDodgeMH = Math.Max(0f, DodgeChanceCap - expertiseBonusMH); chanceDodgeOH = Math.Max(0f, DodgeChanceCap - expertiseBonusOH); float ParryChance = ParryChanceCap - expertiseBonusMH; //chanceParryMH = (float)Math.Max(0f, _bossOpts.InBack ? ParryChance * PecentageInfrontBoss : ParryChance); ParryChance = ParryChanceCap - expertiseBonusOH; //chanceParryOH = (float)Math.Max(0f, _bossOpts.InBack ? ParryChance * PecentageInfrontBoss : ParryChance); chanceWhiteMissMH = Math.Max(0f, WhiteHitCap - hitBonus) + chanceDodgeMH + chanceParryMH; chanceWhiteMissOH = Math.Max(0f, WhiteHitCap - hitBonus) + chanceDodgeOH + chanceParryOH; chanceYellowMissMH = Math.Max(0f, YellowHitCap - hitBonus) + chanceDodgeMH + chanceParryMH; // base miss 8% now chanceYellowMissOH = Math.Max(0f, YellowHitCap - hitBonus) + chanceDodgeOH + chanceParryOH; // base miss 8% now // SetCritValues((1 + _stats.BonusCritChance) * (baseMeleeCrit + meleeCritModifier) + .00005f); //fudge factor for rounding SetCritValues(baseMeleeCrit + meleeCritModifier + .00005f); //fudge factor for rounding // set two export values so that ED crit isn't included exportMeleeCritMH = chanceWhiteCritMH + whiteCritDepression; exportMeleeCritOH = chanceWhiteCritOH + whiteCritDepression; // Spells ftBonusCrit = 0f; if (_calcOpts.MainhandImbue == "Flametongue") { ftBonusCrit += _talents.GlyphofFlametongueWeapon ? .02f : 0f; } if (_calcOpts.OffhandImbue == "Flametongue") { ftBonusCrit += _talents.GlyphofFlametongueWeapon ? .02f : 0f; } if (baseStats == null) { baseStats = BaseStats.GetBaseStats(_character); } elemPrecMod = _talents.ElementalPrecision > 0 ? (_stats.Spirit - baseStats.Spirit) * (_talents.ElementalPrecision / 3f) : 0f; float hitBonusSpell = _stats.SpellHit + StatConversion.GetSpellHitFromRating(_stats.HitRating + elemPrecMod); chanceSpellMiss = Math.Max(0f, SpellMissRate - hitBonusSpell); overSpellHitCap = Math.Max(0f, hitBonusSpell - SpellMissRate); float spellCritModifier = _stats.SpellCrit + _stats.SpellCritOnTarget + ftBonusCrit; float baseSpellCrit = StatConversion.GetSpellCritFromRating(_stats.CritRating) + StatConversion.GetSpellCritFromIntellect(_stats.Intellect) + .01f * _talents.Acuity; //chanceSpellCrit = Math.Min(0.75f, (1 + _stats.BonusCritChance) * (baseSpellCrit + spellCritModifier) + .00005f); //fudge factor for rounding chanceSpellCrit = Math.Min(0.75f, baseSpellCrit + spellCritModifier + .00005f); //fudge factor for rounding float hasteBonus = StatConversion.GetHasteFromRating(_stats.HasteRating, _character.Class); unhastedMHSpeed = _character.MainHand == null ? 3.0f : _character.MainHand.Item.Speed; unhastedOHSpeed = _character.OffHand == null ? 3.0f : _character.OffHand.Item.Speed; float baseHastedMHSpeed = unhastedMHSpeed / (1f + hasteBonus) / (1f + _stats.PhysicalHaste); float baseHastedOHSpeed = unhastedOHSpeed / (1f + hasteBonus) / (1f + _stats.PhysicalHaste); float chanceToProcWFPerHit = .2f + (_character.ShamanTalents.GlyphofWindfuryWeapon ? .02f : 0f); if (_bossOpts.MultiTargs && _bossOpts.Targets != null && _bossOpts.Targets.Count > 0) { foreach (TargetGroup tg in _bossOpts.Targets) { if (tg.Frequency <= 0 || tg.Chance <= 0) { continue; //bad one, skip it } float upTime = (tg.Frequency / fightLength * (tg.Duration / 1000f) * tg.Chance) / fightLength; multiTargetMultiplier += (Math.Max(10, tg.NumTargs - (tg.NearBoss ? 0 : 1))) * upTime; } } //The Swing Loop //This is where we figure out feedback systems -- WF, MW, ED, Flurry, etc. //-------------- flurryUptime = 1f; uWUptime = 0f; //uFUptime = 0f; edUptime = 0f; float stormstrikeSpeed = firstPass ? (_talents.Stormstrike == 1 ? 8f : 0f) : AbilityCooldown(EnhanceAbility.StormStrike); float shockSpeed = firstPass ? BaseShockSpeed : AbilityCooldown(EnhanceAbility.EarthShock); float lavaLashSpeed = firstPass ? 10f : AbilityCooldown(EnhanceAbility.LavaLash); float fireNovaSpeed = firstPass ? BaseFireNovaSpeed : AbilityCooldown(EnhanceAbility.FireNova); if (_calcOpts.PriorityInUse(EnhanceAbility.MagmaTotem)) { fireTotemUptime = firstPass ? 1.0f : 60f / AbilityCooldown(EnhanceAbility.MagmaTotem); } else if (_calcOpts.PriorityInUse(EnhanceAbility.SearingTotem)) { fireTotemUptime = firstPass ? 1.0f : 60f / AbilityCooldown(EnhanceAbility.SearingTotem); } else if (_calcOpts.PriorityInUse(EnhanceAbility.RefreshTotems)) // if no Searing or Magma totem use refresh of Flametongue totem. { fireTotemUptime = firstPass ? 1.0f : 300f / AbilityCooldown(EnhanceAbility.RefreshTotems); } float mwPPM = (10f / 3f) * _talents.MaelstromWeapon; float flurryHasteBonus = .10f * _talents.Flurry; float uWHasteBonus = .4f + .1f * _talents.ElementalWeapons; float edCritBonus = .03f * _talents.ElementalDevastation; float staticShockChance = .15f * _character.ShamanTalents.StaticShock; hitsPerSMHSS = 0f; hitsPerSOHSS = 0f; hitsPerSOH = 0f; hitsPerSMH = 0f; hitsPerSWF = 0f; if (_talents.Stormstrike == 1) { hitsPerSMHSS = (1f - chanceYellowMissMH) / stormstrikeSpeed; hitsPerSOHSS = (1f - 2 * chanceYellowMissOH) / stormstrikeSpeed; //OH only swings if MH connect } hitsPerSLL = lavaLashSpeed == 0 ? 0f : (1f - chanceYellowMissOH) / lavaLashSpeed; float swingsPerSMHMelee = 0f; float swingsPerSOHMelee = 0f; float wfProcsPerSecond = 0f; float mwProcsPerSecond = 0f; secondsToFiveStack = 10f; float averageMeleeCritChance = (chanceWhiteCritMH + chanceWhiteCritOH + chanceYellowCritMH + chanceYellowCritOH) / 4f; float averageMeleeHitChance = ((1f - chanceWhiteMissMH - chanceDodgeMH - chanceParryMH) + (1f - chanceWhiteMissOH - chanceDodgeOH - chanceParryOH)) / 2f; float averageMeleeMissChance = (chanceWhiteMissMH + chanceWhiteMissOH) / 2f; float whiteHitsPerSMH = 0f; float whiteHitsPerSOH = 0f; float moteHitsPerS = 0f; float yellowHitsPerSMH = 0f; float yellowHitsPerSOH = 0f; float flameTongueHitsPerSecond = 0f; for (int i = 0; i < 5; i++) { // float bonusHaste = (1f + (flurryUptime * flurryHasteBonus)); float bonusHaste = 1 / (1 - flurryUptime + flurryUptime / (1 + flurryHasteBonus)) / (1 - uWUptime + uWUptime / (1 + uWHasteBonus)); // use time based not proc based flurryUptime hastedMHSpeed = baseHastedMHSpeed / bonusHaste; hastedOHSpeed = baseHastedOHSpeed / bonusHaste; swingsPerSMHMelee = 1f / hastedMHSpeed; swingsPerSOHMelee = (hastedOHSpeed == 0f) ? 0f : 1f / hastedOHSpeed; whiteHitsPerSMH = ChanceWhiteHitMH * swingsPerSMHMelee; whiteHitsPerSOH = ChanceWhiteHitOH * swingsPerSOHMelee; moteHitsPerS = _stats.MoteOfAnger * 2 * AverageWhiteHitChance; // Windfury model if (_calcOpts.MainhandImbue == "Windfury") { float hitsThatProcWFPerS = whiteHitsPerSMH + hitsPerSMHSS; if (unhastedOHSpeed != 0f) { hitsThatProcWFPerS += moteHitsPerS / 2; // half the hits will be OH and thus won't proc WF } else { hitsThatProcWFPerS += moteHitsPerS; // if no offhand then all motes will be MH weapon by definition } float maxExpectedWFPerFight = hitsThatProcWFPerS * chanceToProcWFPerHit * fightLength; float ineligibleSeconds = maxExpectedWFPerFight * (3.25f - hastedMHSpeed); float expectedWFPerFight = hitsThatProcWFPerS * chanceToProcWFPerHit * (fightLength - ineligibleSeconds); wfProcsPerSecond = expectedWFPerFight / fightLength; hitsPerSWF = 3f * wfProcsPerSecond * (1f - chanceYellowMissMH); } yellowHitsPerSMH = hitsPerSWF + hitsPerSMHSS; yellowHitsPerSOH = hitsPerSOHSS + hitsPerSLL; //Due to attack table, a white swing has the same chance to crit as a yellow hit // Old Flurry calc changed 10 Nov 2009 // couldCritSwingsPerSecond = whiteHitsPerSMH + whiteHitsPerSOH + yellowHitsPerSMH + yellowHitsPerSOH; // float swingsThatConsumeFlurryPerSecond = swingsPerSMHMelee + swingsPerSOHMelee; // flurryUptime = 1f - (float)Math.Pow(1 - averageMeleeCritChance, (3 / swingsThatConsumeFlurryPerSecond) * couldCritSwingsPerSecond); // old formulae flurryUptime = CalculateFlurryUptime(averageMeleeCritChance, averageMeleeHitChance, averageMeleeMissChance); //uWUptime = (float)Math.Max(12f / 15f, ??); //FIXME!!!! uWUptime = 7.5f / 15f; //Temp Uptime until above line is fixed // Maelstrom Weapon time to 5 stacks calc if (unhastedOHSpeed != 0f) { hitsPerSMH = whiteHitsPerSMH + yellowHitsPerSMH + moteHitsPerS / 2; hitsPerSOH = whiteHitsPerSOH + yellowHitsPerSOH + moteHitsPerS / 2; mwProcsPerSecond = (mwPPM / (60f / unhastedMHSpeed)) * hitsPerSMH + (mwPPM / (60f / unhastedOHSpeed)) * hitsPerSOH; } else { hitsPerSMH = whiteHitsPerSMH + yellowHitsPerSMH + moteHitsPerS; hitsPerSOH = 0f; mwProcsPerSecond = (mwPPM / (60f / unhastedMHSpeed)) * hitsPerSMH; } secondsToFiveStack = 5f / mwProcsPerSecond; // Elemental Devastation Uptime calc staticShocksPerSecond = (hitsPerSLL + hitsPerSMHSS + hitsPerSOHSS) * staticShockChance; flameTongueHitsPerSecond = (_calcOpts.MainhandImbue == "Flametongue" ? HitsPerSMH : 0f) + ((_calcOpts.OffhandImbue == "Flametongue") ? HitsPerSOH : 0f); spellAttacksPerSec = (1f / secondsToFiveStack + 1f / shockSpeed + 1f / fireNovaSpeed + staticShocksPerSecond) // + flameTongueHitsPerSecond) * (1f - chanceSpellMiss); float couldCritSpellsPerS = spellAttacksPerSec; edUptime = 1f - (float)Math.Pow(1 - chanceSpellCrit, 10 * couldCritSpellsPerS); averageMeleeCritChance = (chanceWhiteCritMH + chanceWhiteCritOH + chanceYellowCritMH + chanceYellowCritOH) / 4f + edUptime * edCritBonus; } float yellowAttacksPerSecond = hitsPerSWF + hitsPerSMHSS; if (unhastedMHSpeed != 0) { yellowAttacksPerSecond += hitsPerSOHSS; } // set output variables edBonusCrit = edUptime * edCritBonus; //SetCritValues((1 + _stats.BonusCritChance) * (baseMeleeCrit + meleeCritModifier) + edBonusCrit + .00005f); //fudge factor for rounding SetCritValues(baseMeleeCrit + meleeCritModifier + edBonusCrit + .00005f); //fudge factor for rounding meleeAttacksPerSec = hitsPerSMH + hitsPerSOH; meleeCritsPerSec = (whiteHitsPerSMH * chanceWhiteCritMH) + (whiteHitsPerSOH * chanceWhiteCritOH) + (yellowHitsPerSMH * chanceYellowCritMH) + (yellowHitsPerSOH * chanceYellowCritOH) + (_stats.MoteOfAnger * 2 * AverageWhiteCritChance); spellCritsPerSec = spellAttacksPerSec * ChanceSpellCrit; spellCastsPerSec = spellAttacksPerSec; spellMissesPerSec = spellAttacksPerSec * chanceSpellMiss; chanceMeleeHit = meleeAttacksPerSec / (swingsPerSMHMelee + swingsPerSOHMelee + 2f * wfProcsPerSecond + .25f + 1f / 6f); maxMana = _stats.Mana; float spellhaste = _stats.SpellHaste + StatConversion.GetSpellHasteFromRating(_stats.HasteRating); averageFSDotTime = _talents.GlyphofFlameShock ? 27f : 18f; averageFSTickTime = 3f / (1f + spellhaste); }
public static float BonusExpertisePercentage(Player player) { return(StatConversion.GetDodgeParryReducFromExpertise(player.Stats.Expertise + StatConversion.GetExpertiseFromRating(player.Stats.ExpertiseRating), CharacterClass.Warrior)); }
public override Dictionary <string, string> GetCharacterDisplayCalculationValues() { Dictionary <string, string> dictValues = new Dictionary <string, string>(); dictValues.Add("Health", BasicStats.Health.ToString()); dictValues.Add("Strength", BasicStats.Strength.ToString()); dictValues.Add("Agility", BasicStats.Agility.ToString()); dictValues.Add("Stamina", BasicStats.Stamina.ToString()); dictValues.Add("Armor", string.Format("{0}*Reduces physical damage taken by {1:0.00%}", BasicStats.Armor, ArmorReduction)); dictValues.Add("Dodge", string.Format("{0:0.00%}*Dodge Rating {1}", Dodge, BasicStats.DodgeRating)); dictValues.Add("Parry", string.Format("{0:0.00%}*Parry Rating {1}", Parry, BasicStats.ParryRating)); dictValues.Add("Miss", string.Format("{0:0.00%}", Miss)); if (Block != BuffedBlock) { dictValues.Add("Block", string.Format("{0:0.00%}*Mastery Rating {1}" + Environment.NewLine + "{2:0.00%} Normal Block Chance" + Environment.NewLine + "{3:0.00%} Block Chance w/ Shield Block", Block, BasicStats.MasteryRating, BaseBlock, BuffedBlock)); } else { dictValues.Add("Block", string.Format("{0:0.00%}*Mastery Rating {1}", Block, BasicStats.MasteryRating)); } if (Block > 0) { dictValues.Add("Critical Block", string.Format("{0:0.00%} ({1:0.00%} actual)*Mastery Rating {2}", CriticalBlock / Block, CriticalBlock, BasicStats.MasteryRating)); } else { dictValues.Add("Critical Block", string.Format("{0:0.00%}*Mastery Rating {1}", 0, BasicStats.MasteryRating)); } dictValues.Add("Guaranteed Reduction", string.Format("{0:0.00%}", GuaranteedReduction)); if (AnyAvoid != BaseAnyAvoid) { dictValues.Add("Avoidance", string.Format("{0:0.00%}*Avoidance: {0:0.00%}" + Environment.NewLine + "+ Normal Block Chance: {1:0.00%}" + Environment.NewLine + "+ Average Block Chance: {2:0.00%}" + Environment.NewLine + "+ Block Chance w/ Shield Block: {3:0.00%}", AnyMiss, BaseAnyAvoid, AnyAvoid, BuffedAnyAvoid)); } else { dictValues.Add("Avoidance", string.Format("{0:0.00%}*Avoidance: {0:0.00%}" + Environment.NewLine + "Avoidance + Block: {1:0.00%}", AnyMiss, BaseAnyAvoid)); } dictValues.Add("Total Mitigation", string.Format("{0:0.00%}", TotalMitigation)); if (AttackerSpeed == BaseAttackerSpeed) { dictValues.Add("Attacker Speed", string.Format("{0:0.00}s", AttackerSpeed)); } else { dictValues.Add("Attacker Speed", string.Format("{0:0.00}s*Base speed of {1:0.00}s (modified by haste)", AttackerSpeed, BaseAttackerSpeed)); } dictValues.Add("Damage Taken", string.Format("{0:0.0} DPS*{1:0} damage per normal attack" + Environment.NewLine + "{2:0} damage per blocked attack" + Environment.NewLine + "{3:0} damage per critically blocked attack" + Environment.NewLine + "{4:0} damage per critical attack", DamageTaken, DamageTakenPerHit, DamageTakenPerBlock, DamageTakenPerCritBlock, DamageTakenPerCrit)); if (CritVulnerability > 0.0001f) { dictValues.Add("Chance to be Crit", string.Format("{0:0.00%}*CRITTABLE!", CritVulnerability)); } else { dictValues.Add("Chance to be Crit", string.Format("{0:0.00%}*Chance to crit reduced by {1:0.00%}", CritVulnerability, CritReduction)); } dictValues.Add("Nature Resist", string.Format("{0:0}*{1:0.00%} Total Reduction in Defensive Stance", BasicStats.NatureResistance, NatureReduction)); dictValues.Add("Arcane Resist", string.Format("{0:0}*{1:0.00%} Total Reduction in Defensive Stance", BasicStats.ArcaneResistance, ArcaneReduction)); dictValues.Add("Frost Resist", string.Format("{0:0}*{1:0.00%} Total Reduction in Defensive Stance", BasicStats.FrostResistance, FrostReduction)); dictValues.Add("Fire Resist", string.Format("{0:0}*{1:0.00%} Total Reduction in Defensive Stance", BasicStats.FireResistance, FireReduction)); dictValues.Add("Shadow Resist", string.Format("{0:0}*{1:0.00%} Total Reduction in Defensive Stance", BasicStats.ShadowResistance, ShadowReduction)); dictValues["Nature Survival"] = NatureSurvivalPoints.ToString(); dictValues["Frost Survival"] = FrostSurvivalPoints.ToString(); dictValues["Fire Survival"] = FireSurvivalPoints.ToString(); dictValues["Shadow Survival"] = ShadowSurvivalPoints.ToString(); dictValues["Arcane Survival"] = ArcaneSurvivalPoints.ToString(); dictValues.Add("Weapon Speed", string.Format("{0:0.00}*{1:0.00%} Haste", WeaponSpeed, Haste)); dictValues.Add("Attack Power", string.Format("{0}", BasicStats.AttackPower)); dictValues.Add("Hit", string.Format("{0:0.00%}*Hit Rating {1}", Hit, BasicStats.HitRating)); dictValues.Add("Expertise", string.Format("{0}*Expertise Rating {1}" + Environment.NewLine + "Reduces chance to be dodged or parried by {2:0.00%}.", Math.Round(StatConversion.GetExpertiseFromRating(BasicStats.ExpertiseRating, CharacterClass.Warrior) + BasicStats.Expertise), BasicStats.ExpertiseRating, Expertise)); dictValues.Add("Haste", string.Format("{0:0.00%}*Haste Rating {1:0.00}", Haste, BasicStats.HasteRating)); dictValues.Add("Armor Penetration", string.Format("{0:0.00%}*" + /*"Armor Penetration Rating {1}" + Environment.NewLine +*/ "Armor Reduction {1}", ArmorPenetration, /*BasicStats.ArmorPenetrationRating,*/ BasicStats.ArmorPenetration)); dictValues.Add("Crit", string.Format("{0:0.00%}*Crit Rating {1}", Crit, BasicStats.CritRating)); dictValues.Add("Missed Attacks", string.Format("{0:0.00%}*Attacks Missed: {1:0.00%}" + Environment.NewLine + "Attacks Dodged: {2:0.00%}" + Environment.NewLine + "Attacks Parried: {3:0.00%}", AvoidedAttacks, MissedAttacks, DodgedAttacks, ParriedAttacks)); dictValues.Add("Total Damage/sec", string.Format("{0:0.0}", TotalDamagePerSecond)); dictValues.Add("Total Threat/sec", string.Format("{0:0.0}*Heroic Strike used every {1:0.0} seconds", ThreatPerSecond, 3.0f / HeroicStrikeFrequency)); dictValues.Add("Rotation", ThreatModelName + "*" + ThreatModel); switch (RankingMode) { case 3: dictValues.Add("Ranking Mode", "Burst Time*The average amount of time between events which have a chance to result in a burst death"); dictValues.Add("Survival Points", string.Format("{0:0}*{1:0.00} seconds between events", SurvivalPoints, SurvivalPoints / 100.0f)); break; case 4: dictValues.Add("Ranking Mode", "Damage Output*The average amount of DPS which can be produced"); dictValues.Add("Survival Points", string.Format("{0:0}*Survival is not weighted in this mode", SurvivalPoints, SurvivalPoints / 100.0f)); break; default: dictValues.Add("Ranking Mode", "Mitigation Scale*Default scale which compares mitigation, effective health, and threat."); dictValues.Add("Survival Points", string.Format("{0:0}*Effective Health", SurvivalPoints)); break; } dictValues.Add("Overall Points", string.Format("{0:0}", OverallPoints)); dictValues.Add("Mitigation Points", string.Format("{0:0}", MitigationPoints)); dictValues.Add("Threat Points", string.Format("{0:0}", ThreatPoints)); return(dictValues); }
public override Dictionary <string, string> GetCharacterDisplayCalculationValues() { Dictionary <string, string> dictValues = new Dictionary <string, string>(); try { dictValues.Add("Overall Points", OverallPoints.ToString()); dictValues.Add("DPS Points", DPSPoints.ToString()); dictValues.Add("Survivability Points", SurvivabilityPoints.ToString()); float baseMiss = StatConversion.WHITE_MISS_CHANCE_CAP[TargetLevel - 85] - BasicStats.PhysicalHit; float baseDodge = StatConversion.WHITE_DODGE_CHANCE_CAP[TargetLevel - 85] - StatConversion.GetDodgeParryReducFromExpertise(BasicStats.Expertise); float capMiss = (float)Math.Ceiling(baseMiss * StatConversion.RATING_PER_PHYSICALHIT); float capDodge = (float)Math.Ceiling(baseDodge * 400f * StatConversion.RATING_PER_EXPERTISE); string tipMiss = string.Empty; if (BasicStats.HitRating > capMiss) { tipMiss = string.Format("*Hit Rating %: {0}%\nOver the cap by {1} Hit Rating", StatConversion.GetPhysicalHitFromRating(BasicStats.HitRating) * 100, BasicStats.HitRating - capMiss); } else if (BasicStats.HitRating < capMiss) { tipMiss = string.Format("*Hit Rating %: {0}%\nUnder the cap by {1} Hit Rating", StatConversion.GetPhysicalHitFromRating(BasicStats.HitRating) * 100, capMiss - BasicStats.HitRating); } else { tipMiss = string.Format("*Hit Rating %: {0}%\nExactly at the cap", StatConversion.GetPhysicalHitFromRating(BasicStats.HitRating) * 100); } string tipDodge = string.Empty; if (BasicStats.ExpertiseRating > capDodge) { tipDodge = string.Format("*Expertise Rating %: {0}%\nOver the cap by {1} Expertise Rating", StatConversion.GetExpertiseFromRating(BasicStats.ExpertiseRating) * 0.25f, BasicStats.ExpertiseRating - capDodge); } else if (BasicStats.ExpertiseRating < capDodge) { tipDodge = string.Format("*Expertise Rating %: {0}%\nUnder the cap by {1} Expertise Rating", StatConversion.GetExpertiseFromRating(BasicStats.ExpertiseRating) * 0.25f, capDodge - BasicStats.ExpertiseRating); } else { tipDodge = string.Format("*Expertise Rating %: {0}%\nExactly at the cap", StatConversion.GetExpertiseFromRating(BasicStats.ExpertiseRating) * 0.25f); } string tipHaste = string.Format("*Haste Rating %: {0}%", StatConversion.GetPhysicalHasteFromRating(BasicStats.HasteRating, CharacterClass.Druid) * 100f); string tipMastery = string.Format("*Increases the damage done by your bleed abilities by {0}%", ((StatConversion.GetMasteryFromRating(BasicStats.MasteryRating, CharacterClass.Druid) + 8f) * 0.031f) * 100f); dictValues.Add("Health", BasicStats.Health.ToString()); dictValues.Add("Attack Power", BasicStats.AttackPower.ToString()); dictValues.Add("Agility", BasicStats.Agility.ToString()); dictValues.Add("Strength", BasicStats.Strength.ToString()); dictValues.Add("Crit Rating", BasicStats.CritRating.ToString()); dictValues.Add("Hit Rating", BasicStats.HitRating.ToString() + tipMiss); dictValues.Add("Expertise Rating", BasicStats.ExpertiseRating.ToString() + tipDodge); dictValues.Add("Mastery Rating", BasicStats.MasteryRating.ToString() + tipMastery); dictValues.Add("Haste Rating", BasicStats.HasteRating.ToString() + tipHaste); dictValues.Add("Avoided Attacks", string.Format("{0}%*{1}% Dodged, {2}% Missed", AvoidedAttacks, DodgedAttacks, MissedAttacks)); dictValues.Add("Crit Chance", CritChance.ToString() + "%"); dictValues.Add("Attack Speed", AttackSpeed.ToString() + "s"); dictValues.Add("Armor Mitigation", ArmorMitigation.ToString() + "%"); dictValues.Add("Optimal Rotation", HighestDPSRotation.ToString()); //dictValues.Add("Optimal Rotation DPS", HighestDPSRotation.DPS.ToString()); //dictValues.Add("Custom Rotation DPS", CustomRotation.DPS.ToString()); float chanceNonAvoided = 1f - (AvoidedAttacks / 100f); dictValues.Add("Melee", Abilities.MeleeStats.ToString()); dictValues.Add("Mangle", Abilities.MangleStats.ToString()); dictValues.Add("Shred", Abilities.ShredStats.ToString()); dictValues.Add("Ravage", Abilities.RavageStats.ToString()); dictValues.Add("Rake", Abilities.RakeStats.ToString()); dictValues.Add("Rip", Abilities.RipStats.ToString()); dictValues.Add("Bite", Abilities.BiteStats.ToString()); //string[] abilityStats = MeleeStats.GetStatsTexts(HighestDPSRotation.MeleeCount, 0, HighestDPSRotation.TotalDamage, chanceNonAvoided, Duration); //dictValues.Add("Melee Usage", abilityStats[0]); //dictValues.Add("Melee Stats", abilityStats[1]); //abilityStats = MangleStats.GetStatsTexts(HighestDPSRotation.MangleCount, 0, HighestDPSRotation.TotalDamage, chanceNonAvoided, Duration); //dictValues.Add("Mangle Usage", abilityStats[0]); //dictValues.Add("Mangle Stats", abilityStats[1]); //abilityStats = ShredStats.GetStatsTexts(HighestDPSRotation.ShredCount, 0, HighestDPSRotation.TotalDamage, chanceNonAvoided, Duration); //dictValues.Add("Shred Usage", abilityStats[0]); //dictValues.Add("Shred Stats", abilityStats[1]); //abilityStats = RakeStats.GetStatsTexts(HighestDPSRotation.RakeCount, 0, HighestDPSRotation.TotalDamage, chanceNonAvoided, Duration); //dictValues.Add("Rake Usage", abilityStats[0]); //dictValues.Add("Rake Stats", abilityStats[1]); //abilityStats = RipStats.GetStatsTexts(HighestDPSRotation.RipCount, 0, HighestDPSRotation.TotalDamage, chanceNonAvoided, Duration); //dictValues.Add("Rip Usage", abilityStats[0]); //dictValues.Add("Rip Stats", abilityStats[1]); //abilityStats = RoarStats.GetStatsTexts(HighestDPSRotation.RoarCount, HighestDPSRotation.RoarCP, HighestDPSRotation.TotalDamage, chanceNonAvoided, Duration); //dictValues.Add("Roar Usage", abilityStats[0]); //dictValues.Add("Roar Stats", abilityStats[1]); //abilityStats = BiteStats.GetStatsTexts(HighestDPSRotation.BiteCount, HighestDPSRotation.BiteCP, HighestDPSRotation.TotalDamage, chanceNonAvoided, Duration); //dictValues.Add("Bite Usage", abilityStats[0]); //dictValues.Add("Bite Stats", abilityStats[1]); //string attackFormat = "{0}%*Damage Per Hit: {1}, Damage Per Swing: {2}\r\n{0}% of Total Damage, {3} Damage Done"; //dictValues.Add("Melee Damage", string.Empty);//.Format(attackFormat, 100f * HighestDPSRotation.MeleeDamageTotal / HighestDPSRotation.DamageTotal, MeleeDamagePerHit, MeleeDamagePerSwing, HighestDPSRotation.MeleeDamageTotal)); //dictValues.Add("Mangle Damage", string.Empty);//.Format(attackFormat, 100f * HighestDPSRotation.MangleDamageTotal / HighestDPSRotation.DamageTotal, MangleDamagePerHit, MangleDamagePerSwing, HighestDPSRotation.MangleDamageTotal)); //dictValues.Add("Shred Damage", string.Empty);//.Format(attackFormat, 100f * HighestDPSRotation.ShredDamageTotal / HighestDPSRotation.DamageTotal, ShredDamagePerHit, ShredDamagePerSwing, HighestDPSRotation.ShredDamageTotal)); //dictValues.Add("Rake Damage", string.Empty);//.Format(attackFormat, 100f * HighestDPSRotation.RakeDamageTotal / HighestDPSRotation.DamageTotal, RakeDamagePerHit, RakeDamagePerSwing, HighestDPSRotation.RakeDamageTotal)); //dictValues.Add("Rip Damage", string.Empty);//.Format(attackFormat, 100f * HighestDPSRotation.RipDamageTotal / HighestDPSRotation.DamageTotal, RipDamagePerHit, RipDamagePerSwing, HighestDPSRotation.RipDamageTotal)); //dictValues.Add("Bite Damage", string.Empty);//.Format(attackFormat, 100f * HighestDPSRotation.BiteDamageTotal / HighestDPSRotation.DamageTotal, BiteDamagePerHit, BiteDamagePerSwing, HighestDPSRotation.BiteDamageTotal)); //string rotationDescription = string.Empty; //try //{ // rotationDescription = string.Format("{0}*Keep {1}cp Savage Roar up.\r\n{2}{3}{4}{5}Use {6} for combo points.", // HighestDPSRotation.Name.Replace(" + ", "+"), HighestDPSRotation.RoarCP, // HighestDPSRotation.Name.Contains("Rake") ? "Keep Rake up.\r\n" : "", // HighestDPSRotation.Name.Contains("Rip") ? "Keep 5cp Rip up.\r\n" : "", // HighestDPSRotation.Name.Contains("Mangle") ? "Keep Mangle up.\r\n" : "", // HighestDPSRotation.Name.Contains("Bite") ? string.Format("Use {0}cp Ferocious Bites to spend extra combo points.\r\n", HighestDPSRotation.BiteCP) : "", // HighestDPSRotation.Name.Contains("Shred") ? "Shred" : "Mangle"); //} //catch (Exception ex) //{ // ex.ToString(); //} } catch (Exception ex) { new Base.ErrorBox() { Title = "Error Getting Cat Dictionary Values", Function = "GetCharacterDisplayCalculationValues()", TheException = ex, }.Show(); } return(dictValues); }
public void UpdateCalcs(bool firstPass) { // talents callOfThunder = .05f * _talents.CallOfThunder; critMultiplierMelee = 2f * (1 + _stats.BonusCritMultiplier); critMultiplierSpell = (1.5f + .1f * _character.ShamanTalents.ElementalFury) * (1 + _stats.BonusSpellCritMultiplier); // Melee float hitBonus = _stats.PhysicalHit + StatConversion.GetHitFromRating(_stats.HitRating) + 0.02f * _talents.DualWieldSpecialization; expertiseBonusMH = GetDPRfromExp(_stats.Expertise + StatConversion.GetExpertiseFromRating(_stats.ExpertiseRating)); expertiseBonusOH = GetDPRfromExp(_stats.Expertise + StatConversion.GetExpertiseFromRating(_stats.ExpertiseRating)); // Need to modify expertiseBonusMH & OH if Orc and have racial bonus weapons if (_character.Race == CharacterRace.Orc) { ItemType mhType = _character.MainHand == null ? ItemType.None : _character.MainHand.Type; ItemType ohType = _character.OffHand == null ? ItemType.None : _character.OffHand.Type; if (mhType == ItemType.OneHandAxe || mhType == ItemType.FistWeapon) // patch 3.2 includes fists { expertiseBonusMH += 0.0125f; } if (ohType == ItemType.OneHandAxe || ohType == ItemType.FistWeapon) // patch 3.2 includes fists { expertiseBonusOH += 0.0125f; } } float meleeCritModifier = _stats.PhysicalCrit; float baseMeleeCrit = StatConversion.GetCritFromRating(_stats.CritRating) + StatConversion.GetCritFromAgility(_stats.Agility, _character.Class) + .01f * _talents.ThunderingStrikes; chanceDodgeMH = Math.Max(0f, DodgeChanceCap - expertiseBonusMH); chanceDodgeOH = Math.Max(0f, DodgeChanceCap - expertiseBonusOH); float ParryChance = ParryChanceCap - expertiseBonusMH; chanceParryMH = (float)Math.Max(0f, _calcOpts.InBack ? ParryChance * (1f - _calcOpts.InBackPerc / 100f) : ParryChance); ParryChance = ParryChanceCap - expertiseBonusOH; chanceParryOH = (float)Math.Max(0f, _calcOpts.InBack ? ParryChance * (1f - _calcOpts.InBackPerc / 100f) : ParryChance); chanceWhiteMissMH = Math.Max(0f, WhiteHitCap - hitBonus) + chanceDodgeMH + chanceParryMH; chanceWhiteMissOH = Math.Max(0f, WhiteHitCap - hitBonus) + chanceDodgeOH + chanceParryOH; chanceYellowMissMH = Math.Max(0f, YellowHitCap - hitBonus) + chanceDodgeMH + chanceParryMH; // base miss 8% now chanceYellowMissOH = Math.Max(0f, YellowHitCap - hitBonus) + chanceDodgeOH + chanceParryOH; // base miss 8% now // SetCritValues((1 + _stats.BonusCritChance) * (baseMeleeCrit + meleeCritModifier) + .00005f); //fudge factor for rounding SetCritValues(baseMeleeCrit + meleeCritModifier + .00005f); //fudge factor for rounding // set two export values so that ED crit isn't included exportMeleeCritMH = chanceWhiteCritMH + whiteCritDepression; exportMeleeCritOH = chanceWhiteCritOH + whiteCritDepression; // Spells ftBonusCrit = 0f; if (_calcOpts.MainhandImbue == "Flametongue") { ftBonusCrit += _talents.GlyphofFlametongueWeapon ? .02f : 0f; } if (_calcOpts.OffhandImbue == "Flametongue" && _talents.DualWield == 1) { ftBonusCrit += _talents.GlyphofFlametongueWeapon ? .02f : 0f; } float spellCritModifier = _stats.SpellCrit + _stats.SpellCritOnTarget + ftBonusCrit; float hitBonusSpell = _stats.SpellHit + StatConversion.GetSpellHitFromRating(_stats.HitRating); chanceSpellMiss = Math.Max(0f, SpellMissRate - hitBonusSpell); overSpellHitCap = Math.Max(0f, hitBonusSpell - SpellMissRate); float baseSpellCrit = StatConversion.GetSpellCritFromRating(_stats.CritRating) + StatConversion.GetSpellCritFromIntellect(_stats.Intellect) + .01f * _talents.ThunderingStrikes; //chanceSpellCrit = Math.Min(0.75f, (1 + _stats.BonusCritChance) * (baseSpellCrit + spellCritModifier) + .00005f); //fudge factor for rounding chanceSpellCrit = Math.Min(0.75f, baseSpellCrit + spellCritModifier + .00005f); //fudge factor for rounding float hasteBonus = StatConversion.GetHasteFromRating(_stats.HasteRating, _character.Class); unhastedMHSpeed = _character.MainHand == null ? 3.0f : _character.MainHand.Item.Speed; unhastedOHSpeed = _character.OffHand == null ? 3.0f : _character.OffHand.Item.Speed; float baseHastedMHSpeed = unhastedMHSpeed / (1f + hasteBonus) / (1f + _stats.PhysicalHaste); float baseHastedOHSpeed = unhastedOHSpeed / (1f + hasteBonus) / (1f + _stats.PhysicalHaste); float chanceToProcWFPerHit = .2f + (_character.ShamanTalents.GlyphofWindfuryWeapon ? .02f : 0f); //The Swing Loop //This is where we figure out feedback systems -- WF, MW, ED, Flurry, etc. //-------------- flurryUptime = 1f; edUptime = 0f; float stormstrikeSpeed = firstPass ? (_talents.Stormstrike == 1 ? 8f : 0f) : AbilityCooldown(EnhanceAbility.StormStrike); float shockSpeed = firstPass ? BaseShockSpeed : AbilityCooldown(EnhanceAbility.EarthShock); float lavaLashSpeed = firstPass ? (_talents.LavaLash == 1 ? 6f : 0f) : AbilityCooldown(EnhanceAbility.LavaLash); float fireNovaSpeed = firstPass ? BaseFireNovaSpeed : AbilityCooldown(EnhanceAbility.FireNova); if (_calcOpts.PriorityInUse(EnhanceAbility.MagmaTotem)) { fireTotemUptime = firstPass ? 1.0f : 20f / AbilityCooldown(EnhanceAbility.MagmaTotem); } else if (_calcOpts.PriorityInUse(EnhanceAbility.SearingTotem)) { fireTotemUptime = firstPass ? 1.0f : 60f / AbilityCooldown(EnhanceAbility.SearingTotem); } else if (_calcOpts.PriorityInUse(EnhanceAbility.RefreshTotems)) // if no Searing or Magma totem use refresh of Flametongue totem. { fireTotemUptime = firstPass ? 1.0f : 300f / AbilityCooldown(EnhanceAbility.RefreshTotems); } float mwPPM = 2 * _talents.MaelstromWeapon * (1 + _stats.Enhance4T8 * 0.2f); float flurryHasteBonus = .06f * _talents.Flurry + _stats.Enhance4T7; float edCritBonus = .03f * _talents.ElementalDevastation; float staticShockChance = (.02f * _character.ShamanTalents.StaticShock + (_stats.Enhance2T9 == 1f ? 0.03f : 0f)); hitsPerSMHSS = 0f; hitsPerSOHSS = 0f; hitsPerSOH = 0f; hitsPerSMH = 0f; hitsPerSWF = 0f; if (_talents.Stormstrike == 1) { hitsPerSMHSS = (1f - chanceYellowMissMH) / stormstrikeSpeed; hitsPerSOHSS = _character.ShamanTalents.DualWield == 1 ? ((1f - 2 * chanceYellowMissOH) / stormstrikeSpeed) : 0f; //OH only swings if MH connects } hitsPerSLL = lavaLashSpeed == 0 ? 0f : (1f - chanceYellowMissOH) / lavaLashSpeed; float swingsPerSMHMelee = 0f; float swingsPerSOHMelee = 0f; float wfProcsPerSecond = 0f; float mwProcsPerSecond = 0f; secondsToFiveStack = 10f; float averageMeleeCritChance = (chanceWhiteCritMH + chanceWhiteCritOH + chanceYellowCritMH + chanceYellowCritOH) / 4f; float averageMeleeHitChance = ((1f - chanceWhiteMissMH - chanceDodgeMH - chanceParryMH) + (1f - chanceWhiteMissOH - chanceDodgeOH - chanceParryOH)) / 2f; float averageMeleeMissChance = (chanceWhiteMissMH + chanceWhiteMissOH) / 2f; float whiteHitsPerSMH = 0f; float whiteHitsPerSOH = 0f; float moteHitsPerS = 0f; float yellowHitsPerSMH = 0f; float yellowHitsPerSOH = 0f; float flameTongueHitsPerSecond = 0f; for (int i = 0; i < 5; i++) { // float bonusHaste = (1f + (flurryUptime * flurryHasteBonus)); float bonusHaste = 1 / (1 - flurryUptime + flurryUptime / (1 + flurryHasteBonus)); // use time based not proc based flurryUptime hastedMHSpeed = baseHastedMHSpeed / bonusHaste; hastedOHSpeed = baseHastedOHSpeed / bonusHaste; swingsPerSMHMelee = 1f / hastedMHSpeed; swingsPerSOHMelee = (hastedOHSpeed == 0f) ? 0f : 1f / hastedOHSpeed; whiteHitsPerSMH = ChanceWhiteHitMH * swingsPerSMHMelee; whiteHitsPerSOH = ChanceWhiteHitOH * swingsPerSOHMelee; moteHitsPerS = _stats.MoteOfAnger * 2 * AverageWhiteHitChance; // Windfury model if (_calcOpts.MainhandImbue == "Windfury") { float hitsThatProcWFPerS = whiteHitsPerSMH + hitsPerSMHSS; if (_character.ShamanTalents.DualWield == 1) { hitsThatProcWFPerS += moteHitsPerS / 2; // half the hits will be OH and thus won't proc WF } else { hitsThatProcWFPerS += moteHitsPerS; // if no offhand then all motes will be MH weapon by definition } float maxExpectedWFPerFight = hitsThatProcWFPerS * chanceToProcWFPerHit * fightLength; float ineligibleSeconds = maxExpectedWFPerFight * (3.25f - hastedMHSpeed); float expectedWFPerFight = hitsThatProcWFPerS * chanceToProcWFPerHit * (fightLength - ineligibleSeconds); wfProcsPerSecond = expectedWFPerFight / fightLength; hitsPerSWF = 2f * wfProcsPerSecond * (1f - chanceYellowMissMH); } yellowHitsPerSMH = hitsPerSWF + hitsPerSMHSS; yellowHitsPerSOH = hitsPerSOHSS + hitsPerSLL; //Due to attack table, a white swing has the same chance to crit as a yellow hit // Old Flurry calc changed 10 Nov 2009 // couldCritSwingsPerSecond = whiteHitsPerSMH + whiteHitsPerSOH + yellowHitsPerSMH + yellowHitsPerSOH; // float swingsThatConsumeFlurryPerSecond = swingsPerSMHMelee + swingsPerSOHMelee; // flurryUptime = 1f - (float)Math.Pow(1 - averageMeleeCritChance, (3 / swingsThatConsumeFlurryPerSecond) * couldCritSwingsPerSecond); // old formulae flurryUptime = CalculateFlurryUptime(averageMeleeCritChance, averageMeleeHitChance, averageMeleeMissChance); // Maelstrom Weapon time to 5 stacks calc if (_character.ShamanTalents.DualWield == 1 && unhastedOHSpeed != 0f) { hitsPerSMH = whiteHitsPerSMH + yellowHitsPerSMH + moteHitsPerS / 2; hitsPerSOH = whiteHitsPerSOH + yellowHitsPerSOH + moteHitsPerS / 2; mwProcsPerSecond = (mwPPM / (60f / unhastedMHSpeed)) * hitsPerSMH + (mwPPM / (60f / unhastedOHSpeed)) * hitsPerSOH; } else { hitsPerSMH = whiteHitsPerSMH + yellowHitsPerSMH + moteHitsPerS; hitsPerSOH = 0f; mwProcsPerSecond = (mwPPM / (60f / unhastedMHSpeed)) * hitsPerSMH; } secondsToFiveStack = 5f / mwProcsPerSecond; // Elemental Devastation Uptime calc staticShocksPerSecond = (hitsPerSMH + hitsPerSOH) * staticShockChance; flameTongueHitsPerSecond = (_calcOpts.MainhandImbue == "Flametongue" ? HitsPerSMH : 0f) + ((_calcOpts.OffhandImbue == "Flametongue" && _talents.DualWield == 1) ? HitsPerSOH : 0f); spellAttacksPerSec = (1f / secondsToFiveStack + 1f / shockSpeed + 1f / fireNovaSpeed + staticShocksPerSecond) // + flameTongueHitsPerSecond) * (1f - chanceSpellMiss); float couldCritSpellsPerS = spellAttacksPerSec - staticShocksPerSecond; // LS procs from Static Shock cannot crit edUptime = 1f - (float)Math.Pow(1 - chanceSpellCrit, 10 * couldCritSpellsPerS); averageMeleeCritChance = (chanceWhiteCritMH + chanceWhiteCritOH + chanceYellowCritMH + chanceYellowCritOH) / 4f + edUptime * edCritBonus; } float yellowAttacksPerSecond = hitsPerSWF + hitsPerSMHSS; if (_character.ShamanTalents.DualWield == 1 && unhastedMHSpeed != 0) { yellowAttacksPerSecond += hitsPerSOHSS; } // set output variables edBonusCrit = edUptime * edCritBonus; //SetCritValues((1 + _stats.BonusCritChance) * (baseMeleeCrit + meleeCritModifier) + edBonusCrit + .00005f); //fudge factor for rounding SetCritValues(baseMeleeCrit + meleeCritModifier + edBonusCrit + .00005f); //fudge factor for rounding meleeAttacksPerSec = hitsPerSMH + hitsPerSOH; meleeCritsPerSec = (whiteHitsPerSMH * chanceWhiteCritMH) + (whiteHitsPerSOH * chanceWhiteCritOH) + (yellowHitsPerSMH * chanceYellowCritMH) + (yellowHitsPerSOH * chanceYellowCritOH) + (_stats.MoteOfAnger * 2 * AverageWhiteCritChance); spellCritsPerSec = spellAttacksPerSec * ChanceSpellCrit; spellCastsPerSec = spellAttacksPerSec; spellMissesPerSec = spellAttacksPerSec * chanceSpellMiss; chanceMeleeHit = meleeAttacksPerSec / (swingsPerSMHMelee + swingsPerSOHMelee + 2f * wfProcsPerSecond + .25f + 1f / 6f); maxMana = _stats.Mana; float spellhaste = _stats.SpellHaste + StatConversion.GetSpellHasteFromRating(_stats.HasteRating); averageFSDotTime = 18f / (1f + spellhaste); }
public static float BonusExpertisePercentage(Character character, Stats stats) { return(StatConversion.GetDodgeParryReducFromExpertise(StatConversion.GetExpertiseFromRating(stats.ExpertiseRating, CharacterClass.Paladin) + stats.Expertise, CharacterClass.Paladin)); }
public override Dictionary <string, string> GetCharacterDisplayCalculationValues() { Dictionary <string, string> dictValues = new Dictionary <string, string>(); dictValues.Add("Health", BasicStats.Health.ToString()); dictValues.Add("Mana", BasicStats.Mana.ToString()); dictValues.Add("Strength", BasicStats.Strength.ToString()); dictValues.Add("Agility", BasicStats.Agility.ToString()); dictValues.Add("Stamina", string.Format("{0}*Increases Health by {1}", BasicStats.Stamina, (BasicStats.Stamina - 20f) * 10f + 20f)); dictValues.Add("Intellect", BasicStats.Intellect.ToString()); dictValues.Add("Armor", string.Format("{0}*Reduces physical damage taken by {1:0.00%}" + Environment.NewLine + "Armor Damage Reduction depends on Attacker Level.", BasicStats.Armor, ArmorReduction)); dictValues.Add("Defense", Defense.ToString() + string.Format("*Defense Rating {0}", BasicStats.DefenseRating)); dictValues.Add("Dodge", string.Format("{0:0.0000%}*Dodge Rating {1}", Dodge, BasicStats.DodgeRating)); dictValues.Add("Parry", string.Format("{0:0.0000%}*Parry Rating {1}", Parry, BasicStats.ParryRating)); dictValues.Add("Block", string.Format("{0:0.0000%}*Block Rating {1}", Block, BasicStats.BlockRating)); dictValues.Add("Miss", string.Format("{0:0.0000%}", Miss)); dictValues.Add("Block Value", string.Format("{0}*{1} Active Block Value (Libram etc)", StaticBlockValue, ActiveBlockValue)); dictValues.Add("Guaranteed Reduction", string.Format("{0:0.00%}", GuaranteedReduction)); dictValues.Add("Avoidance", string.Format("{0:0.0000%}*Avoidance Points {1}", DodgePlusMissPlusParry, (DodgePlusMissPlusParry * 10000f))); dictValues.Add("Avoidance + Block", string.Format("{0:0.0000%}", DodgePlusMissPlusParryPlusBlock)); dictValues.Add("Total Mitigation", string.Format("{0:0.00%}", TotalMitigation)); if (AttackerSpeed == BaseAttackerSpeed) { dictValues.Add("Attacker Speed", string.Format("{0:0.00}s", AttackerSpeed)); } else { dictValues.Add("Attacker Speed", string.Format("{0:0.00}s*Base speed of {1:0.00}s (reduced by parry haste)", AttackerSpeed, BaseAttackerSpeed)); } dictValues.Add("Damage Taken", string.Format("{0:0.0} DPS*{1:0} damage per normal attack" + Environment.NewLine + "{2:0} damage per blocked attack" + Environment.NewLine + "{3:0} damage per critical attack" + Environment.NewLine + "On Average, you take" + Environment.NewLine + "{4:0.00%} of incoming damage", DPSTaken, DamageTakenPerHit, DamageTakenPerBlock, DamageTakenPerCrit, DamageTaken)); dictValues.Add("Resilience", string.Format(@"{0}*Reduces periodic damage and chance to be critically hit by {1:0.00%}." + Environment.NewLine + "Reduces the effect of mana-drains and the damage of critical strikes by {2:0.00%}.", BasicStats.Resilience, StatConversion.GetCritReductionFromResilience(BasicStats.Resilience, CharacterClass.Paladin), StatConversion.GetCritReductionFromResilience(BasicStats.Resilience, CharacterClass.Paladin) * 2f)); if (CritVulnerability > 0.0001f) { double defenseNeeded = Math.Ceiling((100 * CritVulnerability / StatConversion.DEFENSE_RATING_AVOIDANCE_MULTIPLIER) * StatConversion.RATING_PER_DEFENSE); double resilienceNeeded = Math.Ceiling(CritVulnerability * StatConversion.RATING_PER_RESILIENCE); dictValues.Add("Chance to be Crit", string.Format("{0:0.00%}*CRITTABLE! Short by approximately {1:0} defense rating or approximately {2:0} resilience rating to be uncrittable.", CritVulnerability, defenseNeeded, resilienceNeeded)); } else { dictValues.Add("Chance to be Crit", string.Format("{0:0.00%}*Chance to be crit reduced by {1:0.00%}", CritVulnerability, CritReduction)); } if (UsingHolyShield) { if (CritVulnerabilityWithoutHolyShield > 0.0001f) { double defenseNeeded = Math.Ceiling((100 * CritVulnerabilityWithoutHolyShield / StatConversion.DEFENSE_RATING_AVOIDANCE_MULTIPLIER) * StatConversion.RATING_PER_DEFENSE); double resilienceNeeded = Math.Ceiling(CritVulnerability * StatConversion.RATING_PER_RESILIENCE); dictValues.Add("...Without Holy Shield", string.Format("{0:0.00%}*CRITTABLE! Short by approximately {1:0} defense rating or approximately {2:0} resilience rating to be uncrittable without holy shield.", CritVulnerabilityWithoutHolyShield, defenseNeeded, resilienceNeeded)); } else { dictValues.Add("...Without Holy Shield", string.Format("{0:0.00%}*Chance to be crit reduced by {1:0.00%}", CritVulnerabilityWithoutHolyShield, CritReduction)); } } else { dictValues.Add("...Without Holy Shield", "N/A*Not applicable"); } dictValues.Add("Nature Resist", string.Format("{0:0}*{1:0.00%} Total Reduction", BasicStats.NatureResistance, NatureReduction)); dictValues.Add("Arcane Resist", string.Format("{0:0}*{1:0.00%} Total Reduction", BasicStats.ArcaneResistance, ArcaneReduction)); dictValues.Add("Frost Resist", string.Format("{0:0}*{1:0.00%} Total Reduction", BasicStats.FrostResistance, FrostReduction)); dictValues.Add("Fire Resist", string.Format("{0:0}*{1:0.00%} Total Reduction", BasicStats.FireResistance, FireReduction)); dictValues.Add("Shadow Resist", string.Format("{0:0}*{1:0.00%} Total Reduction", BasicStats.ShadowResistance, ShadowReduction)); dictValues["Nature Survival"] = NatureSurvivalPoints.ToString(); dictValues["Frost Survival"] = FrostSurvivalPoints.ToString(); dictValues["Fire Survival"] = FireSurvivalPoints.ToString(); dictValues["Shadow Survival"] = ShadowSurvivalPoints.ToString(); dictValues["Arcane Survival"] = ArcaneSurvivalPoints.ToString(); dictValues.Add("Weapon Speed", string.Format("{0:0.00}*{1:0.00%} Haste", WeaponSpeed, PhysicalHaste)); dictValues.Add("Attack Power", string.Format("{0}", BasicStats.AttackPower)); dictValues.Add("Spell Power", string.Format("{0}", BasicStats.SpellPower)); dictValues.Add("Hit", string.Format("{0:0.00%}*Hit Rating {1}" + Environment.NewLine + "Against a Target of Level {2}", Hit, BasicStats.HitRating, TargetLevel)); dictValues.Add("Spell Hit", string.Format("{0:0.00%}*Hit Rating {1}" + Environment.NewLine + "Against a Target of Level {2}", SpellHit, BasicStats.HitRating, TargetLevel)); dictValues.Add("Expertise", string.Format("{0:0.00}*Expertise Rating {1}" + Environment.NewLine + "Reduces chance to be dodged or parried by {2:0.00%}.", StatConversion.GetExpertiseFromRating(BasicStats.ExpertiseRating, CharacterClass.Paladin) + BasicStats.Expertise, BasicStats.ExpertiseRating, Expertise)); dictValues.Add("Physical Haste", string.Format("{0:0.00%}*Haste Rating {1:0.00}", PhysicalHaste, BasicStats.HasteRating)); dictValues.Add("Effective Target Armor", string.Format("{0}*Reduces the physical damage you deal by {1:0.00%}" + Environment.NewLine + Environment.NewLine + "Effective Armor depends on Armor ignore debuffs," + Environment.NewLine + "your Armor Penetration buffs and talents." + Environment.NewLine + "Enemy Damage Reduction depends on your Level.", (float)Math.Floor(EffectiveTargetArmor), EffectiveTargetArmorDamageReduction)); dictValues.Add("Effective Armor Penetration", string.Format("{0:0.00%}*Armor Penetration Rating {1} = {2:0.00%}." + Environment.NewLine + "" + Environment.NewLine + "Your Armor Penetration Cap is {3} Armor, this is" + Environment.NewLine + "the highest amount your Arp Rating will ignore." + Environment.NewLine + "Your Rating currently reduces Enemy Armor by {4}." + Environment.NewLine + "" + Environment.NewLine + "Your Arp Rating is {5:0.00%} effective (GC)." + Environment.NewLine + "Note that debuffs like Sunder reduce the Cap.", EffectiveArmorPenetration, BasicStats.ArmorPenetrationRating, ArmorPenetrationFromRating, (float)Math.Floor(ArmorPenetrationCap), (float)Math.Floor(ArmorPenetrationCap * ArmorPenetrationFromRating), EffectiveArmorPenetrationRating)); dictValues.Add("Crit", string.Format("{0:0.00%}*Crit Rating {1}" + Environment.NewLine + "Against a Target of Level {2}", Crit, BasicStats.CritRating, TargetLevel)); dictValues.Add("Spell Crit", string.Format("{0:0.00%}*Crit Rating {1}" + Environment.NewLine + "Against a Target of Level {2}", SpellCrit, BasicStats.CritRating, TargetLevel)); dictValues.Add("Weapon Damage", string.Format("{0:0.00}*As average damage per {1}" + Environment.NewLine + "Before Armor", BasicStats.WeaponDamage, Lookup.Name(Ability.None))); dictValues.Add("Missed Attacks", string.Format("{0:0.00%}*Attacks Missed: {1:0.00%}" + Environment.NewLine + "Attacks Dodged: {2:0.00%}" + Environment.NewLine + "Attacks Parried: {3:0.00%}", AvoidedAttacks, MissedAttacks, DodgedAttacks, ParriedAttacks)); dictValues.Add("Glancing Attacks", string.Format("{0:0.00%}*{1:0.00%} Reduction" + Environment.NewLine + "Against a Target of Level {2}", GlancingAttacks, 1.0f - GlancingReduction, TargetLevel)); dictValues.Add("Total Damage/sec", string.Format("{0:0.0}", TotalDamagePerSecond) + "*" + ThreatModel); dictValues.Add("Threat/sec", string.Format("{0:0.0}", ThreatPerSecond) + "*" + ThreatModel); //dictValues.Add("Unlimited Threat/sec", string.Format("{0:0.0}", UnlimitedThreat) + "*" + ThreatModel); switch (RankingMode) { case 2: dictValues.Add("Ranking Mode", "TankPoints*The average amount of unmitigated damage which can be taken before dying"); dictValues.Add("Survival Points", string.Format("{0:0}*Effective Health", SurvivalPoints)); break; case 3: dictValues.Add("Ranking Mode", "Burst Time*The average amount of time between events which have a chance to result in a burst death"); dictValues.Add("Survival Points", string.Format("{0:0}*{1:0.00} seconds between events", SurvivalPoints, SurvivalPoints / 100.0f)); break; case 4: dictValues.Add("Ranking Mode", "Damage Output*The average amount of DPS which can be produced"); dictValues.Add("Survival Points", string.Format("{0:0}*Survival is not weighted in this mode", SurvivalPoints, SurvivalPoints / 100.0f)); break; case 5: dictValues.Add("Ranking Mode", "ProtWarr Mode*Average mitigated damage vs Effective Health"); dictValues.Add("Survival Points", string.Format("{0:0}*Effective Health", SurvivalPoints)); break; case 6: dictValues.Add("Ranking Mode", "Damage Taken*Average taken damage vs. Effective Health"); dictValues.Add("Survival Points", string.Format("{0:0}*Effective Health", SurvivalPoints)); break; case 7: dictValues.Add("Ranking Mode", "Ranking Mode 7*Dummy Placeholder"); dictValues.Add("Survival Points", string.Format("{0:0}*Survival Placeholder", SurvivalPoints)); break; case 8: dictValues.Add("Ranking Mode", "Ranking Mode 8*Dummy Placeholder"); dictValues.Add("Survival Points", string.Format("{0:0}*Survival Placeholder", SurvivalPoints)); break; default: dictValues.Add("Ranking Mode", "Mitigation Scale*Customizable scale which allows you to weight mitigation vs. effective health."); dictValues.Add("Survival Points", string.Format("{0:0}*Effective Health", SurvivalPoints)); break; } dictValues.Add("Overall Points", string.Format("{0:0}", OverallPoints)); dictValues.Add("Mitigation Points", string.Format("{0:0}", MitigationPoints)); dictValues.Add("Threat Points", string.Format("{0:0}", ThreatPoints)); return(dictValues); }