private void txtslamLatency_TextChanged(object sender, EventArgs e) { CalculationOptionsDPSWarr calcOpts = Character.CalculationOptions as CalculationOptionsDPSWarr; calcOpts.SlamLatency = float.Parse(txtslamLatency.Text, System.Globalization.CultureInfo.InvariantCulture); Character.OnItemsChanged(); }
private void radioButtonScryer_CheckedChanged(object sender, EventArgs e) { CalculationOptionsDPSWarr calcOpts = Character.CalculationOptions as CalculationOptionsDPSWarr; calcOpts.ShattrathFaction = radioButtonAldor.Checked ? "Aldor" : "Scryer"; Character.OnItemsChanged(); }
private void comboBoxTargetLevel_SelectedIndexChanged(object sender, EventArgs e) { CalculationOptionsDPSWarr calcOpts = Character.CalculationOptions as CalculationOptionsDPSWarr; calcOpts.TargetLevel = int.Parse(comboBoxTargetLevel.SelectedItem.ToString()); Character.OnItemsChanged(); }
private void txtArmor_TextChanged(object sender, EventArgs e) { CalculationOptionsDPSWarr calcOpts = Character.CalculationOptions as CalculationOptionsDPSWarr; calcOpts.BossArmor = int.Parse(txtArmor.Text); Character.OnItemsChanged(); }
private void trackBarFightLength_Scroll(object sender, EventArgs e) { CalculationOptionsDPSWarr calcOpts = Character.CalculationOptions as CalculationOptionsDPSWarr; calcOpts.FightLength = trackBarFightLength.Value; lblLength.Text = trackBarFightLength.Value.ToString(); Character.OnItemsChanged(); }
public override ICalculationOptionBase DeserializeDataObject(string xml) { System.Xml.Serialization.XmlSerializer serializer = new System.Xml.Serialization.XmlSerializer(typeof(CalculationOptionsDPSWarr)); System.IO.StringReader reader = new System.IO.StringReader(xml); CalculationOptionsDPSWarr calcOpts = serializer.Deserialize(reader) as CalculationOptionsDPSWarr; return(calcOpts); }
private void rbBerserker_CheckedChanged(object sender, EventArgs e) { CalculationOptionsDPSWarr calcOpts = Character.CalculationOptions as CalculationOptionsDPSWarr; if (rbBerserker.Checked) { calcOpts.Stance = 3; } else { calcOpts.Stance = 0; } Character.OnItemsChanged(); }
private void flurryCheck_CheckedChanged(object sender, EventArgs e) { CalculationOptionsDPSWarr calcOpts = Character.CalculationOptions as CalculationOptionsDPSWarr; if (flurryCheck.Checked) { calcOpts.FlurryUptime = 1; } else { calcOpts.FlurryUptime = 0; } Character.OnItemsChanged(); }
public CombatFactors(Character character, Stats 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 ? null : Char.OffHand.Item; Talents = Char == null || Char.WarriorTalents == null ? new WarriorTalents() : Char.WarriorTalents; //TalentsCata = Char == null || Char.WarriorTalentsCata == null ? new WarriorTalentsCata() : Char.WarriorTalentsCata; 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 //Set_c_values(); }
protected override void LoadCalculationOptions() { if (Character.CalculationOptions == null) { Character.CalculationOptions = new CalculationOptionsDPSWarr(Character); } //if (!Character.CalculationOptions.ContainsKey("TargetLevel")) // Character.CalculationOptions["TargetLevel"] = "73"; //if (!Character.CalculationOptions.ContainsKey("BossArmor")) // Character.CalculationOptions["BossArmor"] = "7700"; //if (!Character.CalculationOptions.ContainsKey("FightLength")) // Character.CalculationOptions["FightLength"] = "10"; //if (!Character.CalculationOptions.ContainsKey("EnforceMetagemRequirements")) // Character.CalculationOptions["EnforceMetagemRequirements"] = "No"; //if (!Character.CalculationOptions.ContainsKey("ShattrathFaction")) // Character.CalculationOptions["ShattrathFaction"] = "Aldor"; //if (!Character.CalculationOptions.ContainsKey("Stance")) // Character.CalculationOptions["Stance"] = "3"; //if (!Character.CalculationOptions.ContainsKey("SlamLatency")) // Character.CalculationOptions["SlamLatency"] = "0.3"; //if (!Character.CalculationOptions.ContainsKey("FlurryUptime")) // Character.CalculationOptions["FlurryUptime"] = "1"; CalculationOptionsDPSWarr calcOpts = Character.CalculationOptions as CalculationOptionsDPSWarr; comboBoxTargetLevel.SelectedItem = calcOpts.TargetLevel.ToString(); txtArmor.Text = calcOpts.BossArmor.ToString(); trackBarFightLength.Value = calcOpts.FightLength; lblLength.Text = trackBarFightLength.Value.ToString(); if (calcOpts.Stance == 0) { rbBattle.Checked = true; } else { rbBerserker.Checked = true; } if (calcOpts.FlurryUptime == 0) { flurryCheck.Checked = false; } else { flurryCheck.Checked = true; } }
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 }
private void Talents_Load(object sender, EventArgs e) { CalculationOptionsDPSWarr calcOpts = Character.CalculationOptions as CalculationOptionsDPSWarr; if (calcOpts.TalentsSaved) { _loading = true; comboBoxTwoHandedSpec.SelectedItem = calcOpts.TwoHandedSpec.ToString(); comboBoxDeathWish.SelectedItem = calcOpts.DeathWish.ToString(); comboBoxImpale.SelectedItem = calcOpts.Impale.ToString(); comboBoxDeepWounds.SelectedItem = calcOpts.DeepWounds.ToString(); comboBoxMortalStrike.SelectedItem = calcOpts.MortalStrike.ToString(); comboBoxCruelty.SelectedItem = calcOpts.Cruelty.ToString(); comboBoxFlurry.SelectedItem = calcOpts.Flurry.ToString(); comboBoxWeaponMastery.SelectedItem = calcOpts.WeaponMastery.ToString(); comboBoxImpSlam.SelectedItem = calcOpts.ImpSlam.ToString(); _loading = false; } }
private void comboBox_SelectedIndexChanged(object sender, EventArgs e) { if (!_loading) { CalculationOptionsDPSWarr calcOpts = Character.CalculationOptions as CalculationOptionsDPSWarr; //ComboBox cb = (ComboBox)sender; //string talent = cb.Name.Substring(8); //Character.CalculationOptions[talent] = cb.SelectedItem.ToString(); calcOpts.TwoHandedSpec = int.Parse((comboBoxTwoHandedSpec.SelectedItem ?? "0").ToString()); calcOpts.DeathWish = int.Parse((comboBoxDeathWish.SelectedItem ?? "0").ToString()); calcOpts.Impale = int.Parse((comboBoxImpale.SelectedItem ?? "0").ToString()); calcOpts.DeepWounds = int.Parse((comboBoxDeepWounds.SelectedItem ?? "0").ToString()); calcOpts.MortalStrike = int.Parse((comboBoxMortalStrike.SelectedItem ?? "0").ToString()); calcOpts.Cruelty = int.Parse((comboBoxCruelty.SelectedItem ?? "0").ToString()); calcOpts.Flurry = int.Parse((comboBoxFlurry.SelectedItem ?? "0").ToString()); calcOpts.WeaponMastery = int.Parse((comboBoxWeaponMastery.SelectedItem ?? "0").ToString()); calcOpts.ImpSlam = int.Parse((comboBoxImpSlam.SelectedItem ?? "0").ToString()); calcOpts.TalentsSaved = true; Character.OnItemsChanged(); } }
protected void Initialize(Character character, Stats stats, CombatFactors cf, CalculationOptionsDPSWarr co, BossOptions bo, Skills.Ability ability, bool ismh, bool useSpellHit, bool alwaysHit) { Char = character; StatS = stats; calcOpts = co; bossOpts = bo; combatFactors = cf; Abil = ability; isWhite = (Abil == null); isMH = ismh; this.useSpellHit = useSpellHit; /*// Defaults * Miss * Dodge * Parry * Block * Glance * Critical * Hit*/ // Start a calc Reset(alwaysHit); }
public FuryRotation(Character character, Stats stats, CombatFactors cf, Skills.WhiteAttacks wa, CalculationOptionsDPSWarr co, BossOptions bo) { Char = character; StatS = stats; Talents = Char == null || Char.WarriorTalents == null ? new WarriorTalents() : Char.WarriorTalents; //TalentsCata = Char == null || Char.WarriorTalentsCata == null ? new WarriorTalentsCata() : Char.WarriorTalentsCata; CombatFactors = cf; CalcOpts = (co == null ? new CalculationOptionsDPSWarr() : co); BossOpts = (bo == null ? new BossOptions() : bo); WhiteAtks = wa; _cachedLatentGCD = 1.5f + CalcOpts.Latency + CalcOpts.AllowedReact; _cachedNumGCDs = CalcOpts.AllowFlooring ? (float)Math.Floor(FightDuration / LatentGCD) : FightDuration / LatentGCD; // Initialize(); }
/// <summary>Load the Character.CalculationOptions into the form as DataContext</summary> public void LoadCalculationOptions() { //string info = ""; IsLoadingCalculationOptions = true; try { if (Character != null && Character.CalculationOptions == null) { // If it's broke, make a new one with the defaults Character.CalculationOptions = new CalculationOptionsDPSWarr(); IsLoadingCalculationOptions = true; } else if (Character == null) { return; } calcOpts = Character.CalculationOptions as CalculationOptionsDPSWarr; // == Model Specific Code == // Bad Gear Hiding CalculationsDPSWarr.HidingBadStuff_Def = calcOpts.HideBadItems_Def; CalculationsDPSWarr.HidingBadStuff_Spl = calcOpts.HideBadItems_Spl; CalculationsDPSWarr.HidingBadStuff_PvP = calcOpts.HideBadItems_PvP; ItemCache.OnItemsChanged(); // Abilities to Maintain LoadAbilBools(calcOpts); } catch (Exception ex) { new Base.ErrorBox() { Title = "Error in loading the DPSWarr Options Pane", Function = "LoadCalculationOptions()", TheException = ex, //Info = info, }.Show(); } IsLoadingCalculationOptions = false; }
private void LoadAbilBools(CalculationOptionsDPSWarr ocalcOpts) { CalculationOptionsPanelDPSWarr.CheckSize(ocalcOpts); CalculationOptionsPanelDPSWarr_PropertyChanged(null, null); }
// Abilities to Maintain Changes /// <summary>Validates the Maintenance Tree for being the wrong size. This occurs when a change happens between releases to the number of abilities in the tree</summary> public static void CheckSize(CalculationOptionsDPSWarr calcOpts) { if (calcOpts == null) { calcOpts = new CalculationOptionsDPSWarr(); } if (calcOpts.MaintenanceTree.Length != (int)Maintenance.InnerRage + 1) { bool[] newArray = new bool[] { true, // == Rage Gen == true, // Start With A Charge false, // Berserker Rage true, // Deadly Calm false, // == Maintenance == false, // Shout Choice false, // Battle Shout false, // Commanding Shout false, // Rallying Cry false, // Demoralizing Shout false, // Sunder Armor true, // Thunder Clap false, // Hamstring true, // == Periodics == true, // Shattering Throw true, // Sweeping Strikes true, // DeathWish true, // Recklessness false, // Enraged Regeneration true, // == Damage Dealers == true, // Fury true, // Whirlwind true, // Bloodthirst true, // Bloodsurge true, // Raging Blow true, // Arms true, // Bladestorm true, // Mortal Strike true, // Rend true, // Overpower true, // Taste for Blood true, // Colossus Smash true, // Victory Rush true, // Slam true, // <20% Execute Spamming true, // <20% Execute Spamming (Stage 2) true, // == Rage Dumps == true, // Cleave true, // Heroic Strike true, // Inner Rage }; calcOpts.MaintenanceTree = newArray; } }
/// <summary> /// GetCharacterStats is the 2nd-most calculation intensive method in a model. Here the model will /// combine all of the information about the character, including race, gear, enchants, buffs, /// calculationoptions, etc., to form a single combined Stats object. Three of the methods below /// can be called from this method to help total up stats: GetItemStats(character, additionalItem), /// GetEnchantsStats(character), and GetBuffsStats(character.ActiveBuffs). /// </summary> /// <param name="character">The character whose stats should be totaled.</param> /// <param name="additionalItem">An additional item to treat the character as wearing. /// This is used for gems, which don't have a slot on the character to fit in, so are just /// added onto the character, in order to get gem calculations.</param> /// <returns>A Stats object containing the final totaled values of all character stats.</returns> public override Stats GetCharacterStats(Character character, Item additionalItem) { Stats statsRace = GetRaceStats(character); Stats statsBaseGear = GetItemStats(character, additionalItem); Stats statsEnchants = GetEnchantsStats(character); Stats statsBuffs = GetBuffsStats(character.ActiveBuffs); //Add Expose Weakness since it's not listed as an AP buff if (statsBuffs.ExposeWeakness > 0) { statsBuffs.AttackPower += 200f; } //Mongoose if (character.MainHand != null && character.MainHandEnchant != null && character.MainHandEnchant.Id == 2673) { statsBuffs.Agility += 120f * ((40f * (1f / (60f / character.MainHand.Speed)) / 6f)); statsBuffs.HasteRating += (15.76f * 2f) * ((40f * (1f / (60f / character.MainHand.Speed)) / 6f)); } //Executioner if (character.MainHand != null && character.MainHandEnchant != null && character.MainHandEnchant.Id == 3225) { statsBuffs.ArmorPenetration += 840f * ((40f * (1f / (60f / character.MainHand.Speed)) / 6f)); } //base Stats statsGearEnchantsBuffs = statsBaseGear + statsEnchants + statsBuffs; TalentTree tree = character.Talents; float agiBase = (float)Math.Floor(statsRace.Agility * (1 + statsRace.BonusAgilityMultiplier)); float agiBonus = (float)Math.Floor(statsGearEnchantsBuffs.Agility * (1 + statsRace.BonusAgilityMultiplier)); float strBase = (float)Math.Floor(statsRace.Strength * (1 + statsRace.BonusStrengthMultiplier)); float strBonus = (float)Math.Floor(statsGearEnchantsBuffs.Strength * (1 + statsRace.BonusStrengthMultiplier)); float staBase = (float)Math.Floor(statsRace.Stamina * (1 + statsRace.BonusStaminaMultiplier)); float staBonus = (float)Math.Floor(statsGearEnchantsBuffs.Stamina * (1 + statsRace.BonusStaminaMultiplier)); Stats statsTotal = new Stats(); statsTotal.BonusAttackPowerMultiplier = ((1 + statsRace.BonusAttackPowerMultiplier) * (1 + statsGearEnchantsBuffs.BonusAttackPowerMultiplier)) - 1; statsTotal.BonusAgilityMultiplier = ((1 + statsRace.BonusAgilityMultiplier) * (1 + statsGearEnchantsBuffs.BonusAgilityMultiplier)) - 1; statsTotal.BonusStrengthMultiplier = ((1 + statsRace.BonusStrengthMultiplier) * (1 + statsGearEnchantsBuffs.BonusStrengthMultiplier)) - 1; statsTotal.BonusStaminaMultiplier = ((1 + statsRace.BonusStaminaMultiplier) * (1 + statsGearEnchantsBuffs.BonusStaminaMultiplier)) - 1; statsTotal.Agility = (agiBase + (float)Math.Floor((agiBase * statsBuffs.BonusAgilityMultiplier) + agiBonus * (1 + statsBuffs.BonusAgilityMultiplier))); statsTotal.Strength = (strBase + (float)Math.Floor((strBase * statsBuffs.BonusStrengthMultiplier) + strBonus * (1 + statsBuffs.BonusStrengthMultiplier))); statsTotal.Stamina = (staBase + (float)Math.Round((staBase * statsBuffs.BonusStaminaMultiplier) + staBonus * (1 + statsBuffs.BonusStaminaMultiplier))); statsTotal.Health = (float)Math.Round(((statsRace.Health + statsGearEnchantsBuffs.Health + ((statsTotal.Stamina - staBase) * 10f)))); statsTotal.AttackPower = (float)Math.Floor((statsRace.AttackPower + statsGearEnchantsBuffs.AttackPower + (statsTotal.Strength * 2)) * (1f + statsTotal.BonusAttackPowerMultiplier)); statsTotal.CritRating = statsRace.Crit + statsGearEnchantsBuffs.CritRating; statsTotal.CritRating += ((statsTotal.Agility / 33.333f) * 22.08f); statsTotal.CritRating += statsBuffs.LotPCritRating; /*Check if axe, if so assume poleaxe spec * -This allows easier comparison between weapon specs */ if ((character.MainHand != null) && ((character.MainHand.Type == Item.ItemType.TwoHandAxe) || (character.MainHand.Type == Item.ItemType.Polearm))) { statsTotal.CritRating += (22.08f * 5.0f); } CalculationOptionsDPSWarr calcOpts = character.CalculationOptions as CalculationOptionsDPSWarr; statsTotal.CritRating += (22.08f * calcOpts.Cruelty); statsTotal.CritRating += (22.08f * calcOpts.Stance); statsTotal.HitRating = statsRace.HitRating + statsGearEnchantsBuffs.HitRating; statsTotal.HitRating += (15.76f * calcOpts.Precision); statsTotal.ExpertiseRating = (statsRace.Expertise * 3.9f) + statsGearEnchantsBuffs.ExpertiseRating; statsTotal.HasteRating = statsRace.HasteRating + statsGearEnchantsBuffs.HasteRating; statsTotal.DodgeRating = statsRace.DodgeRating + statsGearEnchantsBuffs.DodgeRating; statsTotal.DodgeRating = ((statsTotal.Agility / 20f) * 18.92f); statsTotal.ParryRating = statsRace.ParryRating + statsGearEnchantsBuffs.ParryRating; statsTotal.ArmorPenetration = statsRace.ArmorPenetration + statsGearEnchantsBuffs.ArmorPenetration; statsTotal.Bloodlust = statsGearEnchantsBuffs.Bloodlust; statsTotal.DrumsOfBattle = statsGearEnchantsBuffs.DrumsOfBattle; statsTotal.BonusCritMultiplier = statsGearEnchantsBuffs.BonusCritMultiplier; statsTotal.BonusPhysicalDamageMultiplier = statsGearEnchantsBuffs.BonusPhysicalDamageMultiplier; statsTotal.WindfuryAPBonus = statsGearEnchantsBuffs.WindfuryAPBonus; statsTotal.WeaponDamage = statsGearEnchantsBuffs.WeaponDamage; statsTotal.ShatteredSunMightProc = statsGearEnchantsBuffs.ShatteredSunMightProc; return(statsTotal); }
/// <summary> /// GetCharacterCalculations is the primary method of each model, where a majority of the calculations /// and formulae will be used. GetCharacterCalculations should call GetCharacterStats(), and based on /// those total stats for the character, and any calculationoptions on the character, perform all the /// calculations required to come up with the final calculations defined in /// CharacterDisplayCalculationLabels, including an Overall rating, and all Sub ratings defined in /// SubPointNameColors. /// </summary> /// <param name="character">The character to perform calculations for.</param> /// <param name="additionalItem">An additional item to treat the character as wearing. /// This is used for gems, which don't have a slot on the character to fit in, so are just /// added onto the character, in order to get gem calculations.</param> /// <returns>A custom CharacterCalculations object which inherits from CharacterCalculationsBase, /// containing all of the final calculations defined in CharacterDisplayCalculationLabels. See /// CharacterCalculationsBase comments for more details.</returns> public override CharacterCalculationsBase GetCharacterCalculations(Character character, Item additionalItem) { /* * To Do: * -Deep wounds * -Allow more talent choices * -Check for certain talents before calculating * -Add in rotation choice * -Add in GCD check for haste and slam rotations. (2.5 second min swing timer otherwise gcd ruins it) * -Add in control for changing rotation during heroism/bloodlust? * -Handle bloodlust/heroism same as mage model instead of average over fight. * */ //character = GetTalents(character); Stats stats = GetCharacterStats(character, additionalItem); CharacterCalculationsDPSWarr calcs = new CharacterCalculationsDPSWarr(); calcs.BasicStats = stats; CalculationOptionsDPSWarr calcOpts = character.CalculationOptions as CalculationOptionsDPSWarr; float avgBaseWeaponHit = 0.0f, hastedSpeed = 2.0f, physicalCritModifier = 0.0f, chanceToBeDodged = 6.5f, chanceToMiss = 9.0f;; float chanceToGlance = 0.25f, glancingAmount = 0.35f; float slamDPS = 0.0f, msDPS = 0.0f, wfDPS = 0.0f, wwDPS = 0.0f; float rotationTime; float FlurryHaste; #region Mitigation //Default Boss Armor float bossArmor = calcOpts.BossArmor; float totalArP = stats.ArmorPenetration; float modifiedTargetArmor = bossArmor - totalArP; float mitigation = 1 - modifiedTargetArmor / (modifiedTargetArmor + 10557.5f); #endregion //Flurry *Assumes 4 attakcs per flurry to refresh. This is a loose average of the # of attacks //for each flurry including instants & slams. //Also allows user to check 100% uptime flurry if desired. FlurryHaste = (0.05f * calcOpts.Flurry); if (calcOpts.FlurryUptime == 0) { FlurryHaste = 1.0f + (1 - (float)Math.Pow((1 - (stats.CritRating / 22.08f / 100.0f)), 4.0f)) * FlurryHaste; } else { FlurryHaste += 1.0f; } //Variables for Bloodlust/Deathwish uptime int remainder = 0, noOfFullDW = 0, noOfFullBL; int div; float partialUptime, totalUptime; //Fight duration float fightDuration = calcOpts.FightLength * 60; float bloodlust = 1.0f; #region Bloodlust if (stats.Bloodlust > 0) { //Bloodlust -- Calculating uptime *Credit to Ret Model //Note, not working correctly in the ret model //Haste is multiplicative something the ret model isn't handling. div = Math.DivRem(Convert.ToInt32(fightDuration), 600, out remainder); if (remainder == 0) { noOfFullBL = div; } else { noOfFullBL = Convert.ToInt32(Math.Ceiling(Convert.ToDouble((fightDuration + 40) / 600))); } partialUptime = fightDuration - noOfFullBL * 600; if (partialUptime < 0) { partialUptime = 0; } totalUptime = partialUptime + noOfFullBL * 40f; bloodlust = (1.0f + (0.30f * (totalUptime / fightDuration))); } #endregion string shattrathFaction = calcOpts.ShattrathFaction; if (stats.ShatteredSunMightProc > 0) { switch (shattrathFaction) { case "Aldor": stats.AttackPower += 39.13f; break; } } //Check if we have the talent impale. float impale = 1.0f + (0.1f * calcOpts.Impale); #region White Damage and Multipliers //2 Handed Spec float twoHandedSpec = 1.0f + (0.01f * calcOpts.TwoHandedSpec); if (character.MainHand != null) { avgBaseWeaponHit = twoHandedSpec * (character.MainHand.MinDamage + character.MainHand.MaxDamage + stats.WeaponDamage * 2f) / 2.0f; hastedSpeed = (stats.HasteRating == 0) ? character.MainHand.Speed : character.MainHand.Speed / (1 + (stats.HasteRating + stats.DrumsOfBattle) / 1576f); hastedSpeed = hastedSpeed / FlurryHaste; hastedSpeed = hastedSpeed / bloodlust; } rotationTime = (hastedSpeed * 4) + (0.5f * 4); rotationTime += ((calcOpts.SlamLatency) * 4); //Add Attack Power Bonus avgBaseWeaponHit += twoHandedSpec * (stats.AttackPower / 14.0f) * ((character.MainHand == null) ? 2.0f : character.MainHand.Speed); //Take Non-Stat Buffs into account physicalCritModifier = 1.0f + ((stats.CritRating / 22.08f) / 100.0f) * (1f + stats.BonusCritMultiplier * 2f); chanceToBeDodged -= (float)(Math.Floor(stats.ExpertiseRating / 3.89f) * 0.25f); chanceToBeDodged -= calcOpts.WeaponMastery; if (chanceToBeDodged < 0.0f) { chanceToBeDodged = 0.0f; } chanceToMiss -= stats.HitRating / 15.76f; if (chanceToMiss < 0.0f) { chanceToMiss = 0.0f; } float avgBaseWeaponHitPost = (avgBaseWeaponHit * physicalCritModifier - avgBaseWeaponHit * (chanceToMiss + chanceToBeDodged) / 100.0f - avgBaseWeaponHit * chanceToGlance * glancingAmount); //Death Wish -- Calculating uptime *Credit to Ret model AW up time. div = Math.DivRem(Convert.ToInt32(fightDuration), 180, out remainder); if (remainder == 0) { noOfFullDW = div; } else { noOfFullDW = Convert.ToInt32(Math.Ceiling(Convert.ToDouble((fightDuration + 20) / 180))); } partialUptime = fightDuration - noOfFullDW * 180; if (partialUptime < 0) { partialUptime = 0; } totalUptime = partialUptime + noOfFullDW * 20f; float deathWish = 1f + 0.20f * totalUptime / fightDuration; //Misery float misery = 1f + stats.BonusSpellPowerMultiplier; //Blood Frenzy : TODO Take from Debuff List float damageMod = 1.0f + stats.BonusPhysicalDamageMultiplier; float impSancAura = 1.0f; //Added Imp Sanc aura to the buff list, if total damage mod is greater then just //blood frenzy assume we have imp sanc... (not the best way...) if (damageMod > 1.04f) { impSancAura = 1.02f; } float ssoNeckProcDPS = 0f; //TODO: Add Mitigation avgBaseWeaponHitPost *= damageMod * deathWish * mitigation; float dpsWhite = (avgBaseWeaponHitPost * 4) / rotationTime; calcs.WhiteDPSPoints = dpsWhite; calcs.HastedSpeed = hastedSpeed; #endregion if (stats.ShatteredSunMightProc > 0) { switch (shattrathFaction) { case "Scryer": ssoNeckProcDPS = 350f * deathWish * misery * impSancAura * physicalCritModifier / 50f; break; } } #region Slam if (character.MainHand != null) { avgBaseWeaponHit = twoHandedSpec * (character.MainHand.MinDamage + character.MainHand.MaxDamage + stats.WeaponDamage * 2f) / 2.0f; } avgBaseWeaponHit += twoHandedSpec * (stats.AttackPower / 14.0f) * ((character.MainHand == null) ? 1.0f : character.MainHand.Speed); //add in slam damage avgBaseWeaponHit += twoHandedSpec * 140; physicalCritModifier = 1.0f + ((stats.CritRating / 22.08f) / 100.0f) * ((1f + stats.BonusCritMultiplier * 2f) * impale); avgBaseWeaponHitPost = (avgBaseWeaponHit * physicalCritModifier - avgBaseWeaponHit * (chanceToMiss + chanceToBeDodged) / 100.0f); avgBaseWeaponHitPost *= damageMod * deathWish * mitigation; slamDPS = (avgBaseWeaponHitPost * 4) / rotationTime; calcs.SlamDPSPoints = slamDPS; #endregion //WW and MS are normalized (2h = 3.3 speed) float normalizedAP = twoHandedSpec * (stats.AttackPower / 14.0f) * 3.3f; #region Mortal Strike if (character.MainHand != null) { avgBaseWeaponHit = twoHandedSpec * (character.MainHand.MinDamage + character.MainHand.MaxDamage + stats.WeaponDamage * 2f) / 2.0f; } avgBaseWeaponHit += normalizedAP; //add in MS damage avgBaseWeaponHit += twoHandedSpec * 210; avgBaseWeaponHitPost = (avgBaseWeaponHit * physicalCritModifier - avgBaseWeaponHit * (chanceToMiss + chanceToBeDodged) / 100.0f); avgBaseWeaponHitPost *= damageMod * deathWish * mitigation; msDPS = (avgBaseWeaponHitPost * 2) / rotationTime; calcs.MSDPSPoints = msDPS; #endregion #region WhirlWind if (character.MainHand != null) { avgBaseWeaponHit = twoHandedSpec * (character.MainHand.MinDamage + character.MainHand.MaxDamage + stats.WeaponDamage * 2f) / 2.0f; } avgBaseWeaponHit += normalizedAP; avgBaseWeaponHitPost = (avgBaseWeaponHit * physicalCritModifier - avgBaseWeaponHit * (chanceToMiss + chanceToBeDodged) / 100.0f); avgBaseWeaponHitPost *= damageMod * deathWish * mitigation; wwDPS = (avgBaseWeaponHitPost * 1) / rotationTime; calcs.WWDPSPoints = wwDPS; #endregion #region Windfury //WF only procs on whites. //White time = rotation time/4 float avgTimeBetnWF = ((rotationTime / 4) / (1.0f - (chanceToBeDodged + chanceToMiss) / 100f)) * 5.0f; float wfAPIncrease = stats.WindfuryAPBonus; float wfHitPre = avgBaseWeaponHit + (wfAPIncrease / 14f) * ((character.MainHand == null) ? 0 : character.MainHand.Speed); float wfHitPost = (wfHitPre * physicalCritModifier) - (wfHitPre * (chanceToMiss + chanceToBeDodged) / 100f) - (wfHitPre * glancingAmount * chanceToGlance); if (wfAPIncrease > 0) { wfHitPost *= damageMod * deathWish * mitigation; } else { wfHitPost = 0f; } wfDPS = wfHitPost / avgTimeBetnWF; calcs.WFDPSPoints = wfDPS; #endregion #region SwordSpec float swordSpecDps = 0.0f; if ((character.MainHand != null) && (character.MainHand.Type == Item.ItemType.TwoHandSword)) { //Assume 11 sword procs every 220 attacks (5%) //Each rotation has 11 attacks float swordSpecHit = (rotationTime * dpsWhite) / 4; swordSpecDps = (swordSpecHit * 11) / (rotationTime * 20); dpsWhite += swordSpecDps; calcs.WhiteDPSPoints += swordSpecDps; } #endregion calcs.DPSPoints = dpsWhite + (character.MainHand == null ? 0 : slamDPS + msDPS + wwDPS) + wfDPS + ssoNeckProcDPS; calcs.SubPoints = new float[] { calcs.DPSPoints }; calcs.OverallPoints = calcs.DPSPoints; calcs.BasicStats.WeaponDamage = avgBaseWeaponHit * impSancAura; return(calcs); }
private Base.StatsWarrior GetCharacterStats(Character character, Item additionalItem, StatType statType, CalculationOptionsDPSWarr calcOpts, BossOptions bossOpts, out Base.StatsWarrior statsRace) { #if DEBUG //ConstructionCounts["GetCharacterStats"]++; #endif CombatFactors temp; Skills.WhiteAttacks temp2; Rotation temp3; return GetCharacterStats(character, additionalItem, statType, calcOpts, bossOpts, out statsRace, out temp, out temp2, out temp3); }
public AttackTable(Character character, Stats stats, CombatFactors cf, CalculationOptionsDPSWarr co, BossOptions bo, Skills.Ability ability, bool ismh, bool useSpellHit, bool alwaysHit) { Initialize(character, stats, cf, co, bo, ability, ismh, useSpellHit, alwaysHit); }
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; }