public Player(Character character) { this.Character = character; this.Stats = new Base.StatsWarrior(); this.Talents = this.Character.WarriorTalents; this.CalcOpts = this.Character.CalculationOptions as CalculationOptionsProtWarr; this.BossOpts = this.Character.BossOptions; this.DefendModel = null; this.AttackModel = null; }
protected void Initialize(Character character, Base.StatsWarrior stats, CombatFactors cf, BossOptions bo, Skills.Ability ability, bool ismh, bool usespellhit, bool userangedhit, bool alwaysHit) { Char = character; StatS = stats; bossOpts = bo; combatFactors = cf; Abil = ability; isWhite = (Abil == null); isMH = ismh; useSpellHit = usespellhit; useRangedHit = userangedhit; // Start a calc Reset(alwaysHit); }
public CombatFactors(Character character, Base.StatsWarrior stats, CalculationOptionsDPSWarr calcOpts, BossOptions bossOpts) { Char = character; MH = Char == null || Char.MainHand == null ? new Knuckles() : Char.MainHand.Item; OH = Char == null || Char.OffHand == null || (Char.WarriorTalents.TitansGrip == 0 && Char.WarriorTalents.SingleMindedFury == 0) ? null : Char.OffHand.Item; Talents = Char == null || Char.WarriorTalents == null ? new WarriorTalents() : Char.WarriorTalents; CalcOpts = (calcOpts == null ? new CalculationOptionsDPSWarr() : calcOpts); BossOpts = (bossOpts == null ? new BossOptions() : bossOpts); StatS = stats; CritProcs = new WeightedStat[] { new WeightedStat() { Chance = 1f, Value = 0f } }; InvalidateCache(); // Optimizations //SetCvalues(); #if DEBUG //ConstructionCounts["CombatFactors"]++; #endif }
public StatsWarrior GetBuffsStats(Player player) { Base.StatsWarrior statsBuffs = new Base.StatsWarrior(); statsBuffs.Accumulate(GetBuffsStats(player.Character.ActiveBuffs, player.Character.SetBonusCount)); if (player.Character.ActiveBuffs.Find<Buff>(x => x.SpellId == 22738) != null) { statsBuffs.BonusWarrior_PvP_4P_InterceptCDReduc = 5f; } if (player.Character.ActiveBuffs.Find<Buff>(x => x.SpellId == 70843) != null) { statsBuffs.BonusShieldSlamDamageMultiplier = 0.20f; statsBuffs.BonusShockwaveDamageMultiplier = 0.20f; } if (player.Character.ActiveBuffs.Find<Buff>(x => x.SpellId == 70844) != null) { //Your Battle Shout and Commanding Shout abilities now cause you to absorb damage equal to 20% of your maximum health. Lasts 10 sec. //statsBuffs.BonusWarrior_PvP_4P_InterceptCDReduc = 5f; } if (player.Character.ActiveBuffs.Find<Buff>(x => x.SpellId == 90296) != null) { statsBuffs.BonusShieldSlamDamageMultiplier = 0.05f; } if (player.Character.ActiveBuffs.Find<Buff>(x => x.SpellId == 90296) != null) { statsBuffs.BonusShieldWallDurMultiplier = 0.50f; } int T12count; player.Character.SetBonusCount.TryGetValue("Molten Giant Battleplate", out T12count); if (T12count >= 2) { statsBuffs.BonusShieldSlamDamageMultiplier = 0.20f; } if (T12count >= 4) { statsBuffs.AddSpecialEffect(_SE_4T12[player.Talents.ShieldMastery]); } return statsBuffs; }
public AttackTable(Character character, Base.StatsWarrior stats, CombatFactors cf, BossOptions bo, Skills.Ability ability, bool ismh, bool useSpellHit, bool useRangedHit, bool alwaysHit) { Initialize(character, stats, cf, bo, ability, ismh, useSpellHit, useRangedHit, alwaysHit); }
public Base.StatsWarrior GetBuffsStats(DPSWarrCharacter dpswarchar) { List<Buff> removedBuffs = new List<Buff>(); List<Buff> addedBuffs = new List<Buff>(); List<Buff> buffGroup = new List<Buff>(); #region Maintenance Auto-Fixing // Removes the Sunder Armor if you are maintaining it yourself // Also removes Acid Spit and Expose Armor // We are now calculating this internally for better accuracy and to provide value to relevant talents if (dpswarchar.CalcOpts.M_SunderArmor) { buffGroup.Clear(); buffGroup.Add(Buff.GetBuffBySpellId(7386));//Buff.GetBuffByName("Sunder Armor")); buffGroup.Add(Buff.GetBuffBySpellId(8647));//Buff.GetBuffByName("Expose Armor")); buffGroup.Add(Buff.GetBuffBySpellId(770));//Buff.GetBuffByName("Faerie Fire")); buffGroup.Add(Buff.GetBuffBySpellId(35387));//Buff.GetBuffByName("Corrosive Spit")); buffGroup.Add(Buff.GetBuffBySpellId(50498));//Buff.GetBuffByName("Tear Armor")); MaintBuffHelper(buffGroup, dpswarchar.Char, removedBuffs); } // Removes the Shattering Throw Buff if you are maintaining it yourself // We are now calculating this internally for better accuracy and to provide value to relevant talents if (dpswarchar.CalcOpts.M_ShatteringThrow) { buffGroup.Clear(); buffGroup.Add(Buff.GetBuffBySpellId(64382));//Buff.GetBuffByName("Shattering Throw")); MaintBuffHelper(buffGroup, dpswarchar.Char, removedBuffs); } // Removes the Thunder Clap & Improved Buffs if you are maintaining it yourself // Also removes Judgements of the Just, Infected Wounds, Frost Fever, Improved Icy Touch // We are now calculating this internally for better accuracy and to provide value to relevant talents if (dpswarchar.CalcOpts.M_ThunderClap) { buffGroup.Clear(); buffGroup.Add(Buff.GetBuffBySpellId(6343));//Buff.GetBuffByName("Thunder Clap")); buffGroup.Add(Buff.GetBuffBySpellId(59921));//Buff.GetBuffByName("Frost Fever")); buffGroup.Add(Buff.GetBuffBySpellId(53696));//Buff.GetBuffByName("Judgements of the Just")); buffGroup.Add(Buff.GetBuffBySpellId(48484));//Buff.GetBuffByName("Infected Wounds")); MaintBuffHelper(buffGroup, dpswarchar.Char, removedBuffs); } // Removes the Demoralizing Shout & Improved Buffs if you are maintaining it yourself // We are now calculating this internally for better accuracy and to provide value to relevant talents if (dpswarchar.CalcOpts.M_DemoralizingShout) { buffGroup.Clear(); buffGroup.Add(Buff.GetBuffBySpellId(1160));//Buff.GetBuffByName("Demoralizing Shout")); buffGroup.Add(Buff.GetBuffBySpellId(99));//Buff.GetBuffByName("Demoralizing Roar")); buffGroup.Add(Buff.GetBuffBySpellId(26016));//Buff.GetBuffByName("Vindication")); buffGroup.Add(Buff.GetBuffBySpellId(702));//Buff.GetBuffByName("Curse of Weakness")); buffGroup.Add(Buff.GetBuffBySpellId(81132));//Buff.GetBuffByName("Scarlet Fever")); MaintBuffHelper(buffGroup, dpswarchar.Char, removedBuffs); } // Removes the Battle Shout & Commanding Presence Buffs if you are maintaining it yourself // Also removes their equivalent of Blessing of Might (+Improved) // We are now calculating this internally for better accuracy and to provide value to relevant talents if (dpswarchar.CalcOpts.M_BattleShout) { buffGroup.Clear(); buffGroup.Add(Buff.GetBuffBySpellId(6673));//Buff.GetBuffByName("Battle Shout")); buffGroup.Add(Buff.GetBuffBySpellId(8075));//Buff.GetBuffByName("Strength of Earth Totem")); buffGroup.Add(Buff.GetBuffBySpellId(57730));//Buff.GetBuffByName("Horn of Winter")); buffGroup.Add(Buff.GetBuffBySpellId(93435));//Buff.GetBuffByName("Roar of Courage")); MaintBuffHelper(buffGroup, dpswarchar.Char, removedBuffs); } // Removes the Commanding Shout & Commanding Presence Buffs if you are maintaining it yourself // Also removes their equivalent of Blood Pact (+Improved Imp) // We are now calculating this internally for better accuracy and to provide value to relevant talents if (dpswarchar.CalcOpts.M_CommandingShout) { buffGroup.Clear(); buffGroup.Add(Buff.GetBuffBySpellId(469));//Buff.GetBuffByName("Commanding Shout")); buffGroup.Add(Buff.GetBuffBySpellId(21562));//Buff.GetBuffByName("Power Word: Fortitude")); buffGroup.Add(Buff.GetBuffBySpellId(90364));//Buff.GetBuffByName("Quiraji Fortitude")); buffGroup.Add(Buff.GetBuffBySpellId(6307));//Buff.GetBuffByName("Blood Pact")); MaintBuffHelper(buffGroup, dpswarchar.Char, removedBuffs); } #endregion #region Passive Ability Auto-Fixing // Removes the Blood Frenzy Buff and it's equivalent of Savage Combat if you are maintaining it yourself // Cata also has BF giving what Trauma used to // We are now calculating this internally for better accuracy and to provide value to relevant talents if (dpswarchar.Char.WarriorTalents.BloodFrenzy > 0) { buffGroup.Clear(); buffGroup.Add(Buff.GetBuffBySpellId(29859));//Buff.GetBuffByName("Blood Frenzy (Bleed)")); buffGroup.Add(Buff.GetBuffBySpellId(33876));//Buff.GetBuffByName("Mangle")); buffGroup.Add(Buff.GetBuffBySpellId(16511));//Buff.GetBuffByName("Hemorrhage")); buffGroup.Add(Buff.GetBuffBySpellId(50271));//Buff.GetBuffByName("Tendon Rip")); buffGroup.Add(Buff.GetBuffBySpellId(35290));//Buff.GetBuffByName("Gore")); buffGroup.Add(Buff.GetBuffBySpellId(57386));//Buff.GetBuffByName("Stampede")); // buffGroup.Add(Buff.GetBuffBySpellId(29859*10));//Buff.GetBuffByName("Blood Frenzy (Vuln)")); buffGroup.Add(Buff.GetBuffBySpellId(58413));//Buff.GetBuffByName("Savage Combat")); buffGroup.Add(Buff.GetBuffBySpellId(81328));//Buff.GetBuffByName("Brittle Bones")); buffGroup.Add(Buff.GetBuffBySpellId(50518));//Buff.GetBuffByName("Ravage")); buffGroup.Add(Buff.GetBuffBySpellId(55749));//Buff.GetBuffByName("Acid Spit")); MaintBuffHelper(buffGroup, dpswarchar.Char, removedBuffs); } // Removes the Rampage Buff and it's equivalent of Leader of the Pack if you are maintaining it yourself // We are now calculating this internally for better accuracy and to provide value to relevant talents if (dpswarchar.Char.WarriorTalents.Rampage > 0 && dpswarchar.CombatFactors.FuryStance) { buffGroup.Clear(); buffGroup.Add(Buff.GetBuffBySpellId(29801));//Buff.GetBuffByName("Rampage")); buffGroup.Add(Buff.GetBuffBySpellId(17007));//Buff.GetBuffByName("Leader of the Pack")); buffGroup.Add(Buff.GetBuffBySpellId(51701));//Buff.GetBuffByName("Honor Among Thieves")); buffGroup.Add(Buff.GetBuffBySpellId(51470));//Buff.GetBuffByName("Elemental Oath")); buffGroup.Add(Buff.GetBuffBySpellId(24604));//Buff.GetBuffByName("Furious Howl")); buffGroup.Add(Buff.GetBuffBySpellId(90309));//Buff.GetBuffByName("Terrifying Roar")); MaintBuffHelper(buffGroup, dpswarchar.Char, removedBuffs); } #endregion Base.StatsWarrior statsBuffs = new Base.StatsWarrior(); statsBuffs.Accumulate(GetBuffsStats(dpswarchar.Char.ActiveBuffs)); AccumulateSetBonusStats(statsBuffs, dpswarchar.Char.SetBonusCount); if (dpswarchar.Char.ActiveBuffs.Find<Buff>(x => x.SpellId == 22738) != null) { statsBuffs.BonusWarrior_PvP_4P_InterceptCDReduc = 5f; } /*if (dpswarchar.Char.ActiveBuffs.Find<Buff>(x => x.SpellId == 70854) != null) { statsBuffs.BonusWarrior_PvP_4P_InterceptCDReduc = 5f; } if (dpswarchar.Char.ActiveBuffs.Find<Buff>(x => x.SpellId == 70847) != null) { statsBuffs.BonusWarrior_PvP_4P_InterceptCDReduc = 5f; }*/ int T11count; dpswarchar.Char.SetBonusCount.TryGetValue("Earthen Warplate", out T11count); if (T11count >= 2) {//dpswarchar.Char.ActiveBuffs.Find<Buff>(x => x.SpellId == 90293) != null) { statsBuffs.BonusMortalStrikeDamageMultiplier = 0.05f; statsBuffs.BonusBloodthirstDamageMultiplier = 0.05f; } if (T11count >= 4) {//dpswarchar.Char.ActiveBuffs.Find<Buff>(x => x.SpellId == 90295) != null) { statsBuffs.AddSpecialEffect(_SE_4T11); } int T12count; dpswarchar.Char.SetBonusCount.TryGetValue("Molten Giant Warplate", out T12count); if (T12count >= 2) { statsBuffs.AddSpecialEffect(_SE_2T12[dpswarchar.Talents.BoomingVoice]); } if (T12count >= 4) { statsBuffs.AddSpecialEffect(_SE_4T12); } foreach (Buff b in removedBuffs) { dpswarchar.Char.ActiveBuffsAdd(b); } foreach (Buff b in addedBuffs) { dpswarchar.Char.ActiveBuffs.Remove(b); } return statsBuffs; }
private float ApplySpecialEffect(SpecialEffect effect, DPSWarrCharacter charStruct, Dictionary<Trigger, float> triggerIntervals, Dictionary<Trigger, float> triggerChances, ref Base.StatsWarrior applyTo) { #if DEBUG //ConstructionCounts["ApplySpecialEffect"]++; #endif float fightDuration = charStruct.BossOpts.BerserkTimer; float fightDuration2Pass = charStruct.CalcOpts.SE_UseDur ? fightDuration : 0; Stats effectStats = effect.Stats; float upTime = 0f; //float avgStack = 1f; /*if (effect.Stats.TargetArmorReduction > 0f || effect.Stats.ArmorPenetrationRating > 0f) { //int j = 0; }*/ if (effect.Trigger == Trigger.Use) { if (effect.Stats._rawSpecialEffectDataSize == 1) { upTime = effect.GetAverageUptime(0f, 1f, charStruct.CombatFactors.CMHItemSpeed, fightDuration2Pass); //float uptime = (effect.Cooldown / fightDuration); List<SpecialEffect> nestedEffect = new List<SpecialEffect>(); nestedEffect.Add(effect.Stats._rawSpecialEffectData[0]); Base.StatsWarrior _stats2 = new Base.StatsWarrior(); ApplySpecialEffect(effect.Stats._rawSpecialEffectData[0], charStruct, triggerIntervals, triggerChances, ref _stats2); effectStats = _stats2; } else { upTime = effect.GetAverageStackSize(0f, 1f, charStruct.CombatFactors.CMHItemSpeed, fightDuration2Pass); } } else if (effect.Duration == 0f && triggerIntervals.ContainsKey(effect.Trigger) && !float.IsInfinity(triggerIntervals[effect.Trigger])) { upTime = effect.GetAverageProcsPerSecond(triggerIntervals[effect.Trigger], triggerChances[effect.Trigger], charStruct.CombatFactors.CMHItemSpeed, fightDuration2Pass); } else if (effect.Trigger == Trigger.ExecuteHit) { upTime = effect.GetAverageStackSize(triggerIntervals[effect.Trigger], triggerChances[effect.Trigger], charStruct.CombatFactors.CMHItemSpeed, fightDuration2Pass * (float)charStruct.BossOpts.Under20Perc); } else if (triggerIntervals.ContainsKey(effect.Trigger) && !float.IsInfinity(triggerIntervals[effect.Trigger])) { upTime = effect.GetAverageStackSize(triggerIntervals[effect.Trigger], triggerChances[effect.Trigger], charStruct.CombatFactors.CMHItemSpeed, fightDuration2Pass); } if (upTime > 0f) { if (effect.Duration == 0f) { applyTo.Accumulate(effectStats, upTime * fightDuration); } else if (upTime <= effect.MaxStack) { applyTo.Accumulate(effectStats, upTime); } return upTime; } return 0f; }
private Stats IterativeSpecialEffectsStats(DPSWarrCharacter charStruct, List<SpecialEffect> specialEffects, List<SpecialEffect> critEffects, Dictionary<Trigger, float> triggerIntervals, Dictionary<Trigger, float> triggerChances, float oldFlurryUptime, bool iterate, Base.StatsWarrior iterateOld, Base.StatsWarrior originalStats) { #if DEBUG //ConstructionCounts["IterativeSpecialEffectsStats"]++; #endif WarriorTalents talents = charStruct.Char.WarriorTalents; float fightDuration = charStruct.BossOpts.BerserkTimer; Base.StatsWarrior statsProcs = new Base.StatsWarrior(); try { float dmgTakenInterval = fightDuration / charStruct.BossOpts.AoETargsFreq; //float attempted = charStruct.Rot.AttemptedAtksOverDur; //float land = charStruct.Rot.LandedAtksOverDur; //float crit = charStruct.Rot.CriticalAtksOverDur; //int LevelDif = charStruct.bossOpts.Level - charStruct.Char.Level; List<Trigger> critTriggers = new List<Trigger>(); List<float> critWeights = new List<float>(); bool needsHitTableReset = false; foreach (SpecialEffect effect in critEffects) { needsHitTableReset = true; critTriggers.Add(effect.Trigger); critWeights.Add(1f); } foreach (SpecialEffect effect in specialEffects) { #region old arp code /*if (effect.Stats.ArmorPenetrationRating > 0) { float arpenBuffs = ((combatFactors.CmhItemType == ItemType.TwoHandMace) ? talents.MaceSpecialization * 0.03f : 0.00f) + (!calcOpts.FuryStance ? (0.10f + originalStats.BonusWarrior_T9_2P_ArP) : 0.0f); float OriginalArmorReduction = StatConversion.GetArmorDamageReduction(Char.Level, (int)StatConversion.NPC_ARMOR[LevelDif], originalStats.ArmorPenetration, arpenBuffs, originalStats.ArmorPenetrationRating); float ProccedArmorReduction = StatConversion.GetArmorDamageReduction(Char.Level, (int)StatConversion.NPC_ARMOR[LevelDif], originalStats.ArmorPenetration + effect.Stats.ArmorPenetration, arpenBuffs, originalStats.ArmorPenetrationRating + effect.Stats.ArmorPenetrationRating); Stats dummyStats = new Stats(); float procUptime = ApplySpecialEffect(effect, Char, Rot, combatFactors, calcOpts, originalStats.Dodge + originalStats.Parry, ref dummyStats); float targetReduction = ProccedArmorReduction * procUptime + OriginalArmorReduction * (1f - procUptime); //float arpDiff = OriginalArmorReduction - targetReduction; float procArp = StatConversion.GetRatingFromArmorReduction(Char.Level, (int)StatConversion.NPC_ARMOR[LevelDif], originalStats.ArmorPenetration, arpenBuffs, targetReduction); statsProcs.ArmorPenetrationRating += (procArp - originalStats.ArmorPenetrationRating); } else */ #endregion float numProcs = 0; if (effect.Stats.ManaorEquivRestore > 0f && effect.Stats.HealthRestoreFromMaxHealth > 0f) { // effect.Duration = 0, so GetAverageStats won't work float value1 = effect.Stats.ManaorEquivRestore; float value2 = effect.Stats.HealthRestoreFromMaxHealth; SpecialEffect dummy = new SpecialEffect(effect.Trigger, new Stats() { ManaorEquivRestore = value1, HealthRestoreFromMaxHealth = value2 }, effect.Duration, effect.Cooldown, effect.Chance) { BypassCache = true }; numProcs = dummy.GetAverageProcsPerSecond(dmgTakenInterval, originalStats.Dodge + originalStats.Parry, 0f, 0f) * fightDuration; statsProcs.ManaorEquivRestore += dummy.Stats.ManaorEquivRestore * numProcs; dummy.Stats.ManaorEquivRestore = 0f; //numProcs = effect.GetAverageProcsPerSecond(triggerIntervals[Trigger.PhysicalCrit], triggerChances[Trigger.PhysicalCrit], 0f, 0f) * fightDuration; //statsProcs.HealthRestoreFromMaxHealth += effect.Stats.HealthRestoreFromMaxHealth * numProcs; ApplySpecialEffect(dummy, charStruct, triggerIntervals, triggerChances, ref statsProcs); } else if (effect.Stats.ManaorEquivRestore > 0f) { // effect.Duration = 0, so GetAverageStats won't work numProcs = effect.GetAverageProcsPerSecond(dmgTakenInterval, originalStats.Dodge + originalStats.Parry, 0f, 0f) * fightDuration; statsProcs.ManaorEquivRestore += effect.Stats.ManaorEquivRestore * numProcs; } else if (effect.Stats.HealthRestoreFromMaxHealth > 0f) { // effect.Duration = 0, so GetAverageStats won't work numProcs = effect.GetAverageProcsPerSecond(dmgTakenInterval, originalStats.Dodge + originalStats.Parry, 0f, 0f) * fightDuration; statsProcs.HealthRestoreFromMaxHealth += effect.Stats.HealthRestoreFromMaxHealth * numProcs; } else { ApplySpecialEffect(effect, charStruct, triggerIntervals, triggerChances, ref statsProcs); } } WeightedStat[] critProcs; if (critEffects.Count == 0) { critProcs = new WeightedStat[] { new WeightedStat() { Value = 0f, Chance = 1f } }; } else if (critEffects.Count == 1) { float interval = triggerIntervals[critEffects[0].Trigger]; float chance = triggerChances[critEffects[0].Trigger]; float upTime = critEffects[0].GetAverageStackSize(interval, chance, charStruct.CombatFactors.CMHItemSpeed, (charStruct.CalcOpts.SE_UseDur ? charStruct.BossOpts.BerserkTimer : 0f)); upTime *= critWeights[0]; critProcs = new WeightedStat[] { new WeightedStat() { Value = critEffects[0].Stats.CritRating, Chance = upTime }, new WeightedStat() { Value = 0f, Chance = 1f - upTime } }; } else { float[] intervals = new float[critEffects.Count]; float[] chances = new float[critEffects.Count]; float[] offset = new float[critEffects.Count]; for (int i = 0; i < critEffects.Count; i++) { intervals[i] = triggerIntervals[critEffects[i].Trigger]; chances[i] = triggerChances[critEffects[i].Trigger]; } critProcs = SpecialEffect.GetAverageCombinedUptimeCombinations(critEffects.ToArray(), intervals, chances, offset, critWeights.ToArray(), charStruct.CombatFactors.CMHItemSpeed, charStruct.BossOpts.BerserkTimer, AdditiveStat.CritRating); } charStruct.CombatFactors.CritProcs = critProcs; float flurryUptime = 0f; if (iterate && talents.Flurry > 0f && charStruct.CombatFactors.FuryStance && charStruct.Char.MainHand != null && charStruct.Char.MainHand.Item != null) { float numFlurryHits = 3f; // default float mhPerc = 1f; // 100% by default float flurryHaste = 0.25f / 3f * talents.Flurry; bool useOffHand = false; float flurryHitsPerSec = charStruct.CombatFactors.TotalHaste * (1f + flurryHaste) / (1f + flurryHaste * oldFlurryUptime); float temp = 1f / charStruct.Char.MainHand.Item.Speed; if (charStruct.Char.OffHand != null && charStruct.Char.OffHand.Item != null) { useOffHand = true; temp += 1f / charStruct.Char.OffHand.Item.Speed; mhPerc = (charStruct.Char.MainHand.Speed / charStruct.Char.OffHand.Speed) / (1f + charStruct.Char.MainHand.Speed / charStruct.Char.OffHand.Speed); if (charStruct.Char.OffHand.Speed == charStruct.Char.MainHand.Speed) numFlurryHits = 4f; } flurryHitsPerSec *= temp; float flurryDuration = numFlurryHits / flurryHitsPerSec; flurryUptime = 1f; foreach (AbilityWrapper aw in charStruct.Rot.DamagingAbilities) { if (aw.Ability.CanCrit && aw.AllNumActivates > 0f) { float tempFactor = (float) Math.Pow(1f - aw.Ability.MHAtkTable.Crit, flurryDuration* (aw.AllNumActivates*aw.Ability.SwingsPerActivate* aw.Ability.AvgTargets/fightDuration)); flurryUptime *= tempFactor; if (aw.Ability.SwingsOffHand && useOffHand) { flurryUptime *= (float) Math.Pow(1f - aw.Ability.OHAtkTable.Crit, flurryDuration* (aw.AllNumActivates*aw.Ability.SwingsPerActivate* aw.Ability.AvgTargets/fightDuration)); } } } flurryUptime *= (float)Math.Pow(1f - charStruct.Rot.DPSWarrChar.Whiteattacks.MHAtkTable.Crit, numFlurryHits * mhPerc); flurryUptime *= (float)Math.Pow(1f - charStruct.Rot.DPSWarrChar.Whiteattacks.OHAtkTable.Crit, numFlurryHits * (1f - mhPerc)); flurryUptime = 1f - flurryUptime; statsProcs.PhysicalHaste = (1f + statsProcs.PhysicalHaste) * (1f + flurryHaste * flurryUptime) - 1f; } charStruct.CombatFactors.StatS = UpdateStatsAndAdd(statsProcs, originalStats, charStruct.Char); charStruct.CombatFactors.InvalidateCache(); //Rot.InvalidateCache(); if (iterate) { const float precisionWhole = 0.01f; const float precisionDec = 0.0001f; if (statsProcs.Agility - iterateOld.Agility > precisionWhole || statsProcs.HasteRating - iterateOld.HasteRating > precisionWhole || statsProcs.HitRating - iterateOld.HitRating > precisionWhole || statsProcs.CritRating - iterateOld.CritRating > precisionWhole || statsProcs.PhysicalHaste - iterateOld.PhysicalHaste > precisionDec || statsProcs.PhysicalCrit - iterateOld.PhysicalCrit > precisionDec || statsProcs.PhysicalHit - iterateOld.PhysicalHit > precisionDec) { if (needsHitTableReset) charStruct.Rot.ResetHitTables(); charStruct.Rot.DoIterations(); CalculateTriggers(charStruct, triggerIntervals, triggerChances); return IterativeSpecialEffectsStats(charStruct, specialEffects, critEffects, triggerIntervals, triggerChances, flurryUptime, true, statsProcs, originalStats); } else { /*int j = 0;*/ } } return statsProcs; } catch (Exception ex) { new Base.ErrorBox() { Title = "Error in creating SpecialEffects Stats", Function = "GetSpecialEffectsStats()", TheException = ex, }.Show(); return new Stats(); } }
private Base.StatsWarrior GetCharacterStats(Character character, Item additionalItem, StatType statType, CalculationOptionsDPSWarr calcOpts, BossOptions bossOpts, out Base.StatsWarrior statsRace, out CombatFactors combatFactors, out Skills.WhiteAttacks whiteAttacks, out Rotation Rot) { #if DEBUG //ConstructionCounts["GetCharacterStats_Inner"]++; #endif DPSWarrCharacter dpswarchar = new DPSWarrCharacter { Char = character, CalcOpts = calcOpts, BossOpts = bossOpts, Talents = character.WarriorTalents, CombatFactors = null, Rot = null }; Base.StatsWarrior statsTotal = GetCharacterStats_Buffed(dpswarchar, additionalItem, statType != StatType.Unbuffed, out statsRace); dpswarchar.StatS = statsTotal; combatFactors = new CombatFactors(character, statsTotal, calcOpts, bossOpts); // we have to regenerate it here dpswarchar.CombatFactors = combatFactors; whiteAttacks = new Skills.WhiteAttacks(dpswarchar); dpswarchar.Whiteattacks = whiteAttacks; if (combatFactors.FuryStance) Rot = new FuryRotation(dpswarchar); else Rot = new ArmsRotation(dpswarchar); dpswarchar.Rot = Rot; if (statType == (StatType.Buffed | StatType.Unbuffed)) { return statsTotal; } // SpecialEffects: Supposed to handle all procs such as Berserking, Mirror of Truth, Grim Toll, etc. Rot.Initialize(); Rot.MakeRotationandDoDPS(false, false); Rot.AddValidatedSpecialEffects(statsTotal, character.WarriorTalents); DPSWarrCharacter charStruct = new DPSWarrCharacter(){ CalcOpts = calcOpts, BossOpts = bossOpts, Char = character, CombatFactors = combatFactors, Rot = Rot, Talents = character.WarriorTalents, StatS = statsTotal, Whiteattacks = whiteAttacks, }; float fightDuration = bossOpts.BerserkTimer; List<SpecialEffect> bersMainHand = new List<SpecialEffect>(); List<SpecialEffect> bersOffHand = new List<SpecialEffect>(); if (character.MainHandEnchant != null/* && character.MainHandEnchant.Id == 3789*/) { // 3789 = Berserker Enchant ID, but now supporting other proc effects as well Stats.SpecialEffectEnumerator mhEffects = character.MainHandEnchant.Stats.SpecialEffects(); if (mhEffects.MoveNext()) { bersMainHand.Add(mhEffects.Current); } } if (character.MainHand != null && character.MainHand.Item.Stats._rawSpecialEffectData != null) { Stats.SpecialEffectEnumerator mhEffects = character.MainHand.Item.Stats.SpecialEffects(); if (mhEffects.MoveNext()) { bersMainHand.Add(mhEffects.Current); } } if (combatFactors.useOH && character.OffHandEnchant != null /*&& character.OffHandEnchant.Id == 3789*/) { Stats.SpecialEffectEnumerator ohEffects = character.OffHandEnchant.Stats.SpecialEffects(); if (ohEffects.MoveNext()) { bersOffHand.Add(ohEffects.Current); } } if (character.OffHand != null && character.OffHand.Item.Stats._rawSpecialEffectData != null) { Stats.SpecialEffectEnumerator ohEffects = character.OffHand.Item.Stats.SpecialEffects(); if (ohEffects.MoveNext()) { bersOffHand.Add(ohEffects.Current); } } if (statType == StatType.Average) { DoSpecialEffects(charStruct, bersMainHand, bersOffHand, statsTotal); } else // if (statType == StatType.Maximum) { Base.StatsWarrior maxSpecEffects = new Base.StatsWarrior(); foreach (SpecialEffect effect in statsTotal.SpecialEffects()) maxSpecEffects.Accumulate(effect.Stats); return UpdateStatsAndAdd(maxSpecEffects as Base.StatsWarrior, combatFactors.StatS, character); } //UpdateStatsAndAdd(statsProcs, statsTotal, character); // Already done in GetSpecialEffectStats // special case for dual wielding w/ berserker enchant on one/both weapons, as they act independently //combatFactors.StatS = statsTotal; Base.StatsWarrior bersStats = new Base.StatsWarrior(); foreach (SpecialEffect e in bersMainHand) { if (e.Duration == 0) { bersStats.ShadowDamage = e.GetAverageProcsPerSecond(fightDuration / Rot.AttemptedAtksOverDurMH, Rot.LandedAtksOverDurMH / Rot.AttemptedAtksOverDurMH, combatFactors.CMHItemSpeed, calcOpts.SE_UseDur ? fightDuration : 0); } else { // berserker enchant id float f = e.GetAverageUptime(fightDuration / Rot.AttemptedAtksOverDurMH, Rot.LandedAtksOverDurMH / Rot.AttemptedAtksOverDurMH, combatFactors.CMHItemSpeed, calcOpts.SE_UseDur ? fightDuration : 0); bersStats.Accumulate(e.Stats, f); } } foreach (SpecialEffect e in bersOffHand) { if (e.Duration == 0) { bersStats.ShadowDamage += e.GetAverageProcsPerSecond(fightDuration / Rot.AttemptedAtksOverDurOH, Rot.LandedAtksOverDurOH / Rot.AttemptedAtksOverDurOH, combatFactors.COHItemSpeed, calcOpts.SE_UseDur ? fightDuration : 0); } else { float f = e.GetAverageUptime(fightDuration / Rot.AttemptedAtksOverDurOH, Rot.LandedAtksOverDurOH / Rot.AttemptedAtksOverDurOH, combatFactors.COHItemSpeed, calcOpts.SE_UseDur ? fightDuration : 0); bersStats.Accumulate(e.Stats, f); } } combatFactors.StatS = UpdateStatsAndAdd(bersStats, combatFactors.StatS, character); combatFactors.InvalidateCache(); return combatFactors.StatS; }
private Base.StatsWarrior GetCharacterStats_Buffed(DPSWarrCharacter dpswarchar, Item additionalItem, bool isBuffed, out Base.StatsWarrior statsRace) { #if DEBUG //ConstructionCounts["GetCharacterStats_Buffed"]++; #endif if (dpswarchar.CalcOpts == null) { dpswarchar.CalcOpts = dpswarchar.Char.CalculationOptions as CalculationOptionsDPSWarr; } if (dpswarchar.BossOpts == null) { dpswarchar.BossOpts = dpswarchar.Char.BossOptions; } if (dpswarchar.CombatFactors == null) { dpswarchar.CombatFactors = new CombatFactors(dpswarchar.Char, new Base.StatsWarrior(), dpswarchar.CalcOpts, dpswarchar.BossOpts); } WarriorTalents talents = dpswarchar.Char.WarriorTalents; #region From Race statsRace = new Base.StatsWarrior(); statsRace.Accumulate(BaseStats.GetBaseStats(dpswarchar.Char.Level, CharacterClass.Warrior, dpswarchar.Char.Race)); #endregion #region From Gear/Buffs Base.StatsWarrior statsBuffs = (isBuffed ? GetBuffsStats(dpswarchar) : new Base.StatsWarrior()); Base.StatsWarrior statsItems = new Base.StatsWarrior(); statsItems.Accumulate(GetItemStats(dpswarchar.Char, additionalItem)); #endregion #region From Options Base.StatsWarrior statsOptionsPanel = new Base.StatsWarrior() { //BonusStrengthMultiplier = (dpswarchar.combatFactors.FuryStance ? talents.ImprovedBerserkerStance * 0.04f : 0f), //PhysicalCrit = (dpswarchar.combatFactors.FuryStance ? 0.03f + statsBuffs.BonusWarrior_T9_2P_Crit : 0f), // Stance Related Damage Given/Taken mods /* Battle Stance A balanced combat stance. Increases damage done by 5%. Decreases damage taken by 5%. Berserker Stance An aggressive combat stance. Increases damage done by 10%. */ DamageTakenReductionMultiplier = (!dpswarchar.CombatFactors.FuryStance ? -0.05f : 0f), BonusDamageMultiplier = (!dpswarchar.CombatFactors.FuryStance ? 0.05f : 0.10f), // Battle Shout Strength = (dpswarchar.CalcOpts.M_BattleShout ? 549f : 0f), Agility = (dpswarchar.CalcOpts.M_BattleShout ? 549f : 0f), // Commanding Shout Stamina = (dpswarchar.CalcOpts.M_CommandingShout ? 585f : 0f), // Demo Shout BossPhysicalDamageDealtReductionMultiplier = (dpswarchar.CalcOpts.M_DemoralizingShout ? 0.10f : 0f), // Sunder Armor ArmorPenetration = (dpswarchar.CalcOpts.M_SunderArmor ? 0.04f * 3f : 0f), // Thunder Clap BossAttackSpeedReductionMultiplier = (dpswarchar.CalcOpts.M_ThunderClap ? 0.20f : 0f), }; if (dpswarchar.CalcOpts.M_ColossusSmash) { statsOptionsPanel.AddSpecialEffect(TalentsAsSpecialEffects.ColossusSmash); } #endregion #region From Talents Base.StatsWarrior statsTalents = new Base.StatsWarrior() { // Offensive BonusDamageMultiplier = ((!dpswarchar.CombatFactors.FuryStance && dpswarchar.Char.MainHand != null && dpswarchar.Char.MainHand.Slot == ItemSlot.TwoHand ? 1.12f : 1.00f) * (dpswarchar.CombatFactors.FuryStance && talents.SingleMindedFury > 0 && HelperFunctions.ValidateSMTBonus(dpswarchar) ? 1.20f : 1.00f)) - 1f, BonusPhysicalDamageMultiplier = ((dpswarchar.CalcOpts.M_Rend // Have Rend up || talents.DeepWounds > 0 // Have Deep Wounds ? (1.0f + talents.BloodFrenzy * 0.02f) : 1.0f) * (dpswarchar.CombatFactors.FuryStance ? 1.05f : 1.0f)) - 1f, BonusBleedDamageMultiplier = (dpswarchar.CalcOpts.M_Rend // Have Rend up || talents.DeepWounds > 0 // Have Deep Wounds ? talents.BloodFrenzy * 0.15f : 0f), PhysicalCrit = (talents.Rampage > 0 && dpswarchar.CombatFactors.FuryStance && isBuffed ? 0.05f + 0.02f : 0f), // Cata has a new +2% on self (group gets 5%, self gets total 7%) PhysicalHit = (dpswarchar.CombatFactors.FuryStance ? 0.03f : 0f), // Fury Spec has passive 3% Hit BonusWhiteDamageMultiplier = (dpswarchar.CombatFactors.FuryStance ? 0.40f : 0f), // Fury Spec has passive 40% Bonus White Damage Mult // Defensive BaseArmorMultiplier = talents.Toughness * 0.10f / 3f, BonusHealingReceived = talents.FieldDressing * 0.03f, BonusStrengthMultiplier = HelperFunctions.ValidatePlateSpec(dpswarchar) ? 0.05f : 0f, // Specific Abilities BonusMortalStrikeDamageMultiplier = (1f + (dpswarchar.Talents.GlyphOfMortalStrike ? 0.10f : 0f)) * (1f + dpswarchar.Talents.WarAcademy * 0.05f) - 1f, BonusRagingBlowDamageMultiplier = dpswarchar.Talents.WarAcademy * 0.05f, BonusOverpowerDamageMultiplier = (dpswarchar.Talents.GlyphOfOverpower ? 0.10f : 0f), BonusSlamDamageMultiplier = (1f + dpswarchar.Talents.ImprovedSlam * 0.20f) * (1f + dpswarchar.Talents.WarAcademy * 0.05f) - 1f, BonusVictoryRushDamageMultiplier = dpswarchar.Talents.WarAcademy * 0.05f, BonusBloodthirstDamageMultiplier = (dpswarchar.Talents.GlyphOfBloodthirst ? 0.10f : 0f), }; // Add Talents that give SpecialEffects if (talents.WreckingCrew > 0 && dpswarchar.Char.MainHand != null) { statsTalents.AddSpecialEffect(TalentsAsSpecialEffects.WreckingCrew[talents.WreckingCrew]); } if (talents.LambsToTheSlaughter > 0 && dpswarchar.CalcOpts.M_MortalStrike) { statsTalents.AddSpecialEffect(TalentsAsSpecialEffects.LambsToTheSlaughter[talents.LambsToTheSlaughter]); // TODO: This should also refresh rend in 4.1.0 } if (talents.BloodCraze > 0) { statsTalents.AddSpecialEffect(TalentsAsSpecialEffects.BloodCraze[talents.BloodCraze]); } if (talents.Executioner > 0 && dpswarchar.CalcOpts.M_ExecuteSpam) { statsTalents.AddSpecialEffect(TalentsAsSpecialEffects.Executioner[talents.Executioner]); } if (talents.BloodFrenzy > 0) { statsTalents.AddSpecialEffect(TalentsAsSpecialEffects.BloodFrenzy[talents.BloodFrenzy]); } if (talents.MeatCleaver > 0 && (dpswarchar.CalcOpts.M_Whirlwind || dpswarchar.CalcOpts.M_Cleave)) { statsTalents.AddSpecialEffect(TalentsAsSpecialEffects.MeatCleaver[talents.MeatCleaver]); } #endregion Base.StatsWarrior statsTotal = new Base.StatsWarrior(); statsTotal.Accumulate(statsRace); statsTotal.Accumulate(statsItems); statsTotal.Accumulate(statsBuffs); statsTotal.Accumulate(statsTalents); statsTotal.Accumulate(statsOptionsPanel); statsTotal = UpdateStatsAndAdd(statsTotal, null, dpswarchar.Char); float multiplier = 0.0560f; float masteryBonusVal = (2f*0.056f + multiplier * StatConversion.GetMasteryFromRating(statsTotal.MasteryRating, CharacterClass.Warrior)); if (talents.DeathWish > 0 && dpswarchar.CalcOpts.M_DeathWish && dpswarchar.CombatFactors.FuryStance) { statsTotal.AddSpecialEffect(TalentsAsSpecialEffects.GetDeathWishWithMastery(masteryBonusVal, dpswarchar)); } if (talents.Enrage > 0 && dpswarchar.CombatFactors.FuryStance) { statsTotal.AddSpecialEffect(TalentsAsSpecialEffects.GetEnragedRegenerationWithMastery(masteryBonusVal, dpswarchar)); } //Stats statsProcs = new Stats(); // Dodge (your dodging incoming attacks) // Warriors no longer gain dodge from Agility since patch 4.2 // statsTotal.Dodge += StatConversion.GetDodgeFromAgility(statsTotal.Agility, dpswarchar.Char.Class); statsTotal.Dodge += StatConversion.GetDodgeFromRating(statsTotal.DodgeRating, dpswarchar.Char.Class); // Parry (your parrying incoming attacks) statsTotal.Parry += StatConversion.GetParryFromRating(statsTotal.ParryRating, dpswarchar.Char.Class); return statsTotal; }