public static void solve(CharacterCalculationsShadowPriest calculatedStats, CalculationOptionsShadowPriest calcOpts, BossOptions bossOpts) { Stats stats = calculatedStats.BasicStats; Character character = calculatedStats.LocalCharacter; PriestTalents talents = character.PriestTalents; Solver e; Rotation rot; float FightDuration = bossOpts.BerserkTimer; // WITHOUT PROCS e = new Solver(stats, new Stats { }, talents, calcOpts); rot = e.getPriorityRotation(); calculatedStats.DpsPoints = rot.DPS; calculatedStats.SurvivalPoints = stats.Stamina / FightDuration; //TODO: meaningful surv points calculatedStats.CombatStats = stats.Clone(); calculatedStats.DevouringPlauge = rot.DP; calculatedStats.MindBlast = rot.MB; calculatedStats.MindFlay = rot.MF; calculatedStats.MindSpike = rot.Spike; //calculatedStats.PowerWordShield = rot.shield; calculatedStats.ShadowFiend = rot.Fiend; calculatedStats.ShadowWordDeath = rot.SWD; calculatedStats.ShadowWordPain = rot.SWP; calculatedStats.VampiricTouch = rot.VT; calculatedStats.Rotation = rot.ToString(); calculatedStats.RotationDetails = rot.ToDetailedString(); }
public BurstCalculations(Stats stats, CalculationOptionsShadowPriest options, BossOptions boss, PriestTalents talents) { _stats = stats; _boss = boss; _talents = talents; _options = options; }
public BaseCharacterStatCalculations(Stats stats, CalculationOptionsShadowPriest options, BossOptions boss, PriestTalents talents) { _stats = stats; _target = boss; _talents = talents; _options = options; }
public CombatFactors(PriestTalents talents, Stats stats, int additionalTargets, float latencyCast, float latencyGcd) { Talents = talents; Stats = stats; AdditionalTargets = additionalTargets; LatencyCast = latencyCast; LatencyGCD = latencyGcd; }
public static ePriestSpec GetPriestSpec(PriestTalents pt) { int spec = pt.HighestTree; if (spec == 0) return ePriestSpec.Spec_Disc; else if (spec == 1) return ePriestSpec.Spec_Holy; else if (spec == 2) return ePriestSpec.Spec_Shadow; return ePriestSpec.Spec_ERROR; }
/// <summary> /// Beware when updating: The spells from an earlier returned Rotation are references to the SpellBox from this Estimation. /// </summary> /// <param name="baseStats"></param> /// <param name="procStats"></param> /// <param name="talents"></param> /// <param name="calcOpts"></param> public void Update(Stats baseStats, Stats procStats, PriestTalents talents, CalculationOptionsShadowPriest calcOpts) { this.baseStats = baseStats; this.procStats = procStats; this.talents = talents; this.calcOpts = calcOpts; Stats addedStats = baseStats.Clone(); addedStats.Accumulate(procStats); CombatFactors combatFactors = new CombatFactors(talents, addedStats, Math.Max(calcOpts.NumberOfTargets - 1, 0), calcOpts.LatencyCast, calcOpts.LatencyGcd); spellbox.Update(combatFactors); }
public TalentsBase TalentSpec() { if (Spec == null) { return(null); } TalentsBase spec; if (Class == CharacterClass.DeathKnight) { spec = new DeathKnightTalents(Spec); } else if (Class == CharacterClass.Warrior) { spec = new WarriorTalents(Spec); } else if (Class == CharacterClass.Paladin) { spec = new PaladinTalents(Spec); } else if (Class == CharacterClass.Shaman) { spec = new ShamanTalents(Spec); } else if (Class == CharacterClass.Hunter) { spec = new HunterTalents(Spec); } else if (Class == CharacterClass.Rogue) { spec = new RogueTalents(Spec); } else if (Class == CharacterClass.Druid) { spec = new DruidTalents(Spec); } else if (Class == CharacterClass.Warlock) { spec = new WarlockTalents(Spec); } else if (Class == CharacterClass.Priest) { spec = new PriestTalents(Spec); } else { spec = new MageTalents(Spec); } return(spec); }
/// <summary> /// Suggested talent set from http://elitistjerks.com/f77/t112651-shadow_priest_--_cataclysm/ /// circa 27/02/2011 /// </summary> /// <param name="talents"></param> public static void LoadSuggested(PriestTalents talents) { // Discipline Talents talents.ImprovedPowerWordShield = 0; talents.TwinDisciplines = 3; talents.MentalAgility = 2; talents.Evangelism = 2; talents.Archangel = 1; talents.InnerSanctum = 0; talents.SoulWarding = 0; // Holy Talents talents.ImprovedRenew = 0; talents.EmpoweredHealing = 0; talents.DivineFury = 0; talents.DesperatePrayer = 0; talents.SurgeOfLight = 0; talents.Inspiration = 0; // Shadow Talents talents.Darkness = 3; talents.ImprovedShadowWordPain = 2; talents.VeiledShadows = 2; talents.ImprovedPsychicScream = 0; talents.ImprovedMindBlast = 3; talents.ImprovedDevouringPlague = 2; talents.TwistedFaith = 2; talents.Shadowform = 1; talents.Phantasm = 0; talents.HarnessedShadows = 2; talents.Silence = 0; talents.VampiricEmbrace = 1; talents.Masochism = 2; talents.MindMelt = 2; talents.PainAndSuffering = 2; talents.VampiricTouch = 1; talents.Paralysis = 0; talents.PsychicHorror = 0; talents.SinAndPunishment = 2; talents.ShadowyApparition = 3; talents.Dispersion = 1; }
public Rotation(SpellBox spellBox, PriestTalents talents, IRotationOptions rotOpt) : this() { Talents = talents; DP = spellBox.DP; MB = spellBox.MB; MF = spellBox.MF; Fiend = spellBox.Fiend; SWD = spellBox.SWD; SWP = spellBox.SWP; VT = spellBox.VT; Spike = spellBox.Spike; //useXXX = rotOpt.UseDpsFireTotem; CalculateRotation(); }
public static ePriestSpec GetPriestSpec(PriestTalents pt) { int spec = pt.HighestTree; if (spec == 0) { return(ePriestSpec.Spec_Disc); } else if (spec == 1) { return(ePriestSpec.Spec_Holy); } else if (spec == 2) { return(ePriestSpec.Spec_Shadow); } return(ePriestSpec.Spec_ERROR); }
public static bool HasTalent(PriestTalents tal) { return(TalentManager.IsSelected((int)tal)); }
TalentsBase parse_talents_wowhead(CharacterClass characterclass, string talent_string) { // wowhead format: [tree_1]Z[tree_2]Z[tree_3] where the trees are character encodings // each character expands to a pair of numbers [0-5][0-5] // unused deeper talents are simply left blank instead of filling up the string with zero-zero encodings bool hasGlyphs = talent_string.Contains(":"); int[] talent_trees = new int[] { 0, 0, 0 }; int[] glyph_trees = new int[] { 3, 3, 3 }; switch (characterclass) { case CharacterClass.Warrior: { WarriorTalents talents = new WarriorTalents(); talent_trees = talents.TreeLengths; break; } case CharacterClass.Paladin: { PaladinTalents talents = new PaladinTalents(); talent_trees = talents.TreeLengths; break; } case CharacterClass.Hunter: { HunterTalents talents = new HunterTalents(); talent_trees = talents.TreeLengths; break; } case CharacterClass.Rogue: { RogueTalents talents = new RogueTalents(); talent_trees = talents.TreeLengths; break; } case CharacterClass.Priest: { PriestTalents talents = new PriestTalents(); talent_trees = talents.TreeLengths; break; } case CharacterClass.DeathKnight: { DeathKnightTalents talents = new DeathKnightTalents(); talent_trees = talents.TreeLengths; break; } case CharacterClass.Shaman: { ShamanTalents talents = new ShamanTalents(); talent_trees = talents.TreeLengths; break; } case CharacterClass.Mage: { MageTalents talents = new MageTalents(); talent_trees = talents.TreeLengths; break; } case CharacterClass.Warlock: { WarlockTalents talents = new WarlockTalents(); talent_trees = talents.TreeLengths; break; } case CharacterClass.Druid: { DruidTalents talents = new DruidTalents(); talent_trees = talents.TreeLengths; break; } } int[] encoding = new int[talent_trees[0] + talent_trees[1] + talent_trees[2]]; int[][] glyphEncoding = new int[][] { new int[3], new int[3], new int[3], }; int[] tree_count = new int[] { 0, 0, 0 }; int[] glyph_count = new int[] { 0, 0, 0 }; int tree = 0; int count = 0; #region Talents parsing for (int i = 1; i < talent_string.Length; i++) { if (tree >= 3) { //sim -> errorf( "Player %s has malformed wowhead talent string. Too many talent trees specified.\n", name() ); return(null); } char c = talent_string[i]; if (c == ':') { break; // glyph encoding follows } if (c == 'Z') { count = 0; for (int j = 0; j <= tree; j++) { count += talent_trees[tree]; } tree++; continue; } decode_t decode = null; for (int j = 0; decoding[j].key != '\0' && decode == null; j++) { if (decoding[j].key == c) { decode = decoding[j]; } } if (decode == null) { //sim -> errorf( "Player %s has malformed wowhead talent string. Translation for '%c' unknown.\n", name(), c ); return(null); } encoding[count++] += decode.first - '0'; tree_count[tree] += 1; if (tree_count[tree] < talent_trees[tree]) { encoding[count++] += decode.second - '0'; tree_count[tree] += 1; } if (tree_count[tree] >= talent_trees[tree]) { tree++; } } #endregion #region Glyphs Parsing #region Notes /* This is totally crappy.... * Glyphs do not follow the same parsing rules. If you apply what was there for talents directly * to glyphs you get 1202032213120011050000000000000000. Which should only have 1's and 0's * * * Warriors: As I'm checking glyphs, here's what I get: * == PRIMES == * Link decode id Name * * http://www.wowhead.com/talent#L:0 00 43415 58388 Devastate * * http://www.wowhead.com/talent#L:z 01 43416 58367 Bloodthirst * * http://www.wowhead.com/talent#L:M 02 43421 58368 Mortal Strike * * http://www.wowhead.com/talent#L:c 03 43422 58386 Overpower * * http://www.wowhead.com/talent#L:m 04 43423 58385 Slam * * http://www.wowhead.com/talent#L:V 05 43424 58364 Revenge * * http://www.wowhead.com/talent#L:o 10 43425 58375 Shield Slam * * http://www.wowhead.com/talent#L:k 11 43432 58370 Raging Blow * * http://www.wowhead.com/talent#L:R 12 45790 63324 Bladestorm * == MAJORS == * * http://www.wowhead.com/talent#L:0 00 43397 Long Charge * * http://www.wowhead.com/talent#L:z 01 43399 Thunder Clap * * http://www.wowhead.com/talent#L:M 02 43413 Rapid Charge * * http://www.wowhead.com/talent#L:c 03 43414 Cleaving * * http://www.wowhead.com/talent#L:m 04 43417 Piercing Howl * * http://www.wowhead.com/talent#L:V 05 43418 Heroic Throw * * http://www.wowhead.com/talent#L:o 10 43419 Intervene * * http://www.wowhead.com/talent#L:k 11 43427 Sunder Armor * * http://www.wowhead.com/talent#L:R 12 43428 Sweeping Strikes * * http://www.wowhead.com/talent#L:s 13 43430 Resonating Power * * http://www.wowhead.com/talent#L:a 14 43431 Victory Rush * * http://www.wowhead.com/talent#L:q 15 45792 Shockwave * * http://www.wowhead.com/talent#L:b 20 45795 Spell Reflection * * http://www.wowhead.com/talent#L:d 21 45797 Shield Wall * * http://www.wowhead.com/talent#L:r 22 63481 Colossus Smash * * http://www.wowhead.com/talent#L:f 23 67482 Intercept * * http://www.wowhead.com/talent#L:w 24 67483 Death Wish * == MINORS == * * http://www.wowhead.com/talent#L:0 00 43395 Battle * * http://www.wowhead.com/talent#L:z 01 43396 Berserker Rage * * http://www.wowhead.com/talent#L:M 02 43398 Demoralizing Shout * * http://www.wowhead.com/talent#L:c 03 43400 Enduring Victory * * http://www.wowhead.com/talent#L:m 04 43412 Bloody Healing * * http://www.wowhead.com/talent#L:V 05 45793 Furious Sundering * * http://www.wowhead.com/talent#L:o 10 45794 Intimidating Shout * * http://www.wowhead.com/talent#L:k 11 49084 Command * * So http://www.wowhead.com/talent#LubcfRMRurkcrZ0b:RMcrsR0kV would mean: * Prime: Bladestorm, Mortal Strike, Overpower * Major: Colossus Smash, Resonating Power, Sweeping Strikes * Minor: Battle, Command, Furious Sundering * Which is correct, that's what we come out to */ #endregion tree = 0; count = 0; if (hasGlyphs) { for (int i = talent_string.IndexOf(":") + 1; i < talent_string.Length; i++) { if (tree >= 3) { //sim -> errorf( "Player %s has malformed wowhead talent string. Too many talent trees specified.\n", name() ); return(null); } char c = talent_string[i]; if (c == 'Z') { count = 0; /*for (int j = 0; j <= tree; j++) { * count += glyph_trees[tree]; * }*/ tree++; continue; } decode_t decode = null; for (int j = 0; decoding[j].key != '\0' && decode == null; j++) { if (decoding[j].key == c) { decode = decoding[j]; } } if (decode == null) { //sim -> errorf( "Player %s has malformed wowhead talent string. Translation for '%c' unknown.\n", name(), c ); return(null); } glyphEncoding[tree][count++] += (decode.first - '0') * 10 + decode.second - '0'; glyph_count[tree] += 1; if (glyph_count[tree] >= (glyph_trees[tree])) { tree++; count = 0; } } } #endregion string newtalentstring = ""; foreach (int i in encoding) { newtalentstring += i.ToString(); } if (hasGlyphs) { //newtalentstring += "."; //for (int t = 0; t < 3; t++) { // foreach (int i in glyphEncoding[t]) { newtalentstring += i.ToString(); } //} } switch (characterclass) { case CharacterClass.Warrior: { return(new WarriorTalents(newtalentstring, hasGlyphs ? glyphEncoding : null)); } case CharacterClass.Paladin: { return(new PaladinTalents(newtalentstring, hasGlyphs ? glyphEncoding : null)); } case CharacterClass.Hunter: { return(new HunterTalents(newtalentstring, hasGlyphs ? glyphEncoding : null)); } case CharacterClass.Rogue: { return(new RogueTalents(newtalentstring, hasGlyphs ? glyphEncoding : null)); } case CharacterClass.Priest: { return(new PriestTalents(newtalentstring, hasGlyphs ? glyphEncoding : null)); } case CharacterClass.DeathKnight: { return(new DeathKnightTalents(newtalentstring, hasGlyphs ? glyphEncoding : null)); } case CharacterClass.Shaman: { return(new ShamanTalents(newtalentstring, hasGlyphs ? glyphEncoding : null)); } case CharacterClass.Mage: { return(new MageTalents(newtalentstring, hasGlyphs ? glyphEncoding : null)); } case CharacterClass.Warlock: { return(new WarlockTalents(newtalentstring, hasGlyphs ? glyphEncoding : null)); } case CharacterClass.Druid: { return(new DruidTalents(newtalentstring, hasGlyphs ? glyphEncoding : null)); } } return(null); }
TalentsBase parse_talents_wowhead(CharacterClass characterclass, string talent_string) { // wowhead format: [tree_1]Z[tree_2]Z[tree_3] where the trees are character encodings // each character expands to a pair of numbers [0-5][0-5] // unused deeper talents are simply left blank instead of filling up the string with zero-zero encodings bool hasGlyphs = talent_string.Contains(":"); int[] talent_trees = new int[] { 0, 0, 0 }; int[] glyph_trees = new int[] { 3, 3, 3 }; switch (characterclass) { case CharacterClass.Warrior: { WarriorTalents talents = new WarriorTalents(); talent_trees = talents.TreeLengths; break; } case CharacterClass.Paladin: { PaladinTalents talents = new PaladinTalents(); talent_trees = talents.TreeLengths; break; } case CharacterClass.Hunter: { HunterTalents talents = new HunterTalents(); talent_trees = talents.TreeLengths; break; } case CharacterClass.Rogue: { RogueTalents talents = new RogueTalents(); talent_trees = talents.TreeLengths; break; } case CharacterClass.Priest: { PriestTalents talents = new PriestTalents(); talent_trees = talents.TreeLengths; break; } case CharacterClass.DeathKnight: { DeathKnightTalents talents = new DeathKnightTalents(); talent_trees = talents.TreeLengths; break; } case CharacterClass.Shaman: { ShamanTalents talents = new ShamanTalents(); talent_trees = talents.TreeLengths; break; } case CharacterClass.Mage: { MageTalents talents = new MageTalents(); talent_trees = talents.TreeLengths; break; } case CharacterClass.Warlock: { WarlockTalents talents = new WarlockTalents(); talent_trees = talents.TreeLengths; break; } case CharacterClass.Druid: { DruidTalents talents = new DruidTalents(); talent_trees = talents.TreeLengths; break; } } int[] encoding = new int[talent_trees[0] + talent_trees[1] + talent_trees[2]]; int[][] glyphEncoding = new int[][] { new int[3], new int[3], new int[3], }; int[] tree_count = new int[] { 0, 0, 0 }; int[] glyph_count = new int[] { 0, 0, 0 }; int tree = 0; int count = 0; #region Talents parsing for (int i=1; i < talent_string.Length; i++) { if (tree >= 3) { //sim -> errorf( "Player %s has malformed wowhead talent string. Too many talent trees specified.\n", name() ); return null; } char c = talent_string[i]; if (c == ':') break; // glyph encoding follows if (c == 'Z') { count = 0; for (int j = 0; j <= tree; j++) { count += talent_trees[tree]; } tree++; continue; } decode_t decode = null; for (int j=0; decoding[j].key != '\0' && decode==null; j++) { if (decoding[j].key == c) { decode = decoding[j]; } } if (decode == null) { //sim -> errorf( "Player %s has malformed wowhead talent string. Translation for '%c' unknown.\n", name(), c ); return null; } encoding[count++] += decode.first - '0'; tree_count[tree] += 1; if (tree_count[tree] < talent_trees[tree]) { encoding[count++] += decode.second - '0'; tree_count[tree] += 1; } if (tree_count[tree] >= talent_trees[tree]) { tree++; } } #endregion #region Glyphs Parsing #region Notes /* This is totally crappy.... * Glyphs do not follow the same parsing rules. If you apply what was there for talents directly * to glyphs you get 1202032213120011050000000000000000. Which should only have 1's and 0's * * * Warriors: As I'm checking glyphs, here's what I get: * == PRIMES == * Link decode id Name * * http://www.wowhead.com/talent#L:0 00 43415 58388 Devastate * * http://www.wowhead.com/talent#L:z 01 43416 58367 Bloodthirst * * http://www.wowhead.com/talent#L:M 02 43421 58368 Mortal Strike * * http://www.wowhead.com/talent#L:c 03 43422 58386 Overpower * * http://www.wowhead.com/talent#L:m 04 43423 58385 Slam * * http://www.wowhead.com/talent#L:V 05 43424 58364 Revenge * * http://www.wowhead.com/talent#L:o 10 43425 58375 Shield Slam * * http://www.wowhead.com/talent#L:k 11 43432 58370 Raging Blow * * http://www.wowhead.com/talent#L:R 12 45790 63324 Bladestorm * == MAJORS == * * http://www.wowhead.com/talent#L:0 00 43397 Long Charge * * http://www.wowhead.com/talent#L:z 01 43399 Thunder Clap * * http://www.wowhead.com/talent#L:M 02 43413 Rapid Charge * * http://www.wowhead.com/talent#L:c 03 43414 Cleaving * * http://www.wowhead.com/talent#L:m 04 43417 Piercing Howl * * http://www.wowhead.com/talent#L:V 05 43418 Heroic Throw * * http://www.wowhead.com/talent#L:o 10 43419 Intervene * * http://www.wowhead.com/talent#L:k 11 43427 Sunder Armor * * http://www.wowhead.com/talent#L:R 12 43428 Sweeping Strikes * * http://www.wowhead.com/talent#L:s 13 43430 Resonating Power * * http://www.wowhead.com/talent#L:a 14 43431 Victory Rush * * http://www.wowhead.com/talent#L:q 15 45792 Shockwave * * http://www.wowhead.com/talent#L:b 20 45795 Spell Reflection * * http://www.wowhead.com/talent#L:d 21 45797 Shield Wall * * http://www.wowhead.com/talent#L:r 22 63481 Colossus Smash * * http://www.wowhead.com/talent#L:f 23 67482 Intercept * * http://www.wowhead.com/talent#L:w 24 67483 Death Wish * == MINORS == * * http://www.wowhead.com/talent#L:0 00 43395 Battle * * http://www.wowhead.com/talent#L:z 01 43396 Berserker Rage * * http://www.wowhead.com/talent#L:M 02 43398 Demoralizing Shout * * http://www.wowhead.com/talent#L:c 03 43400 Enduring Victory * * http://www.wowhead.com/talent#L:m 04 43412 Bloody Healing * * http://www.wowhead.com/talent#L:V 05 45793 Furious Sundering * * http://www.wowhead.com/talent#L:o 10 45794 Intimidating Shout * * http://www.wowhead.com/talent#L:k 11 49084 Command * * So http://www.wowhead.com/talent#LubcfRMRurkcrZ0b:RMcrsR0kV would mean: * Prime: Bladestorm, Mortal Strike, Overpower * Major: Colossus Smash, Resonating Power, Sweeping Strikes * Minor: Battle, Command, Furious Sundering * Which is correct, that's what we come out to */ #endregion tree = 0; count = 0; if (hasGlyphs) { for (int i=talent_string.IndexOf(":")+1; i < talent_string.Length; i++) { if (tree >= 3) { //sim -> errorf( "Player %s has malformed wowhead talent string. Too many talent trees specified.\n", name() ); return null; } char c = talent_string[i]; if (c == 'Z') { count = 0; /*for (int j = 0; j <= tree; j++) { count += glyph_trees[tree]; }*/ tree++; continue; } decode_t decode = null; for (int j=0; decoding[j].key != '\0' && decode==null; j++) { if (decoding[j].key == c) { decode = decoding[j]; } } if (decode == null) { //sim -> errorf( "Player %s has malformed wowhead talent string. Translation for '%c' unknown.\n", name(), c ); return null; } glyphEncoding[tree][count++] += (decode.first - '0') * 10 + decode.second - '0'; glyph_count[tree] += 1; if (glyph_count[tree] >= (glyph_trees[tree])) { tree++; count = 0; } } } #endregion string newtalentstring = ""; foreach (int i in encoding) { newtalentstring += i.ToString(); } if (hasGlyphs) { //newtalentstring += "."; //for (int t = 0; t < 3; t++) { // foreach (int i in glyphEncoding[t]) { newtalentstring += i.ToString(); } //} } switch (characterclass) { case CharacterClass.Warrior: { return new WarriorTalents(newtalentstring, hasGlyphs ? glyphEncoding : null); } case CharacterClass.Paladin: { return new PaladinTalents(newtalentstring, hasGlyphs ? glyphEncoding : null); } case CharacterClass.Hunter: { return new HunterTalents(newtalentstring, hasGlyphs ? glyphEncoding : null); } case CharacterClass.Rogue: { return new RogueTalents(newtalentstring, hasGlyphs ? glyphEncoding : null); } case CharacterClass.Priest: { return new PriestTalents(newtalentstring, hasGlyphs ? glyphEncoding : null); } case CharacterClass.DeathKnight: { return new DeathKnightTalents(newtalentstring, hasGlyphs ? glyphEncoding : null); } case CharacterClass.Shaman: { return new ShamanTalents(newtalentstring, hasGlyphs ? glyphEncoding : null); } case CharacterClass.Mage: { return new MageTalents(newtalentstring, hasGlyphs ? glyphEncoding : null); } case CharacterClass.Warlock: { return new WarlockTalents(newtalentstring, hasGlyphs ? glyphEncoding : null); } case CharacterClass.Druid: { return new DruidTalents(newtalentstring, hasGlyphs ? glyphEncoding : null); } } return null; }
public MindBlast(PriestTalents talents, Stats stats, BossHandler target) { _talents = talents; _stats = stats; _target = target; }
public static bool HasTalent(PriestTalents tal) { return TalentManager.IsSelected((int)tal); }
public override Stats GetCharacterStats(Character character, Item additionalItem) { PriestTalents talents = character.PriestTalents; Stats statsTotal = new Stats(); Stats baseStats = BaseStats.GetBaseStats(character.Level, character.Class, character.Race); Stats itemStats = GetItemStats(character, additionalItem); Stats buffStats = GetBuffsStats(character, _calculationOptions); // Get the gear/enchants/buffs stats loaded in statsTotal.Accumulate(baseStats); statsTotal.Accumulate(itemStats); statsTotal.Accumulate(buffStats); Stats statsTalents = new Stats() { // we can only wear items that are cloth so we always have our specialization, even naked. BonusIntellectMultiplier = 0.05f, BonusShadowDamageMultiplier = (1 + 0.02f * talents.TwinDisciplines) * (1 + 0.02f * talents.TwistedFaith) * (1 + 0.15f * talents.Shadowform) - 1, BonusHolyDamageMultiplier = (1 + 0.02f * talents.TwinDisciplines) - 1, // this is the shadow priest model so they must have 'Shadow Power' BonusSpellPowerMultiplier = .15f, }; statsTotal.Accumulate(statsTalents); statsTotal.Stamina = (float)Math.Floor(statsTotal.Stamina * (1 + statsTotal.BonusStaminaMultiplier)); statsTotal.Intellect += (float)Math.Floor(itemStats.Intellect * statsTotal.BonusIntellectMultiplier); statsTotal.Spirit = (float)Math.Round(statsTotal.Spirit * (1 + statsTotal.BonusSpiritMultiplier)); statsTotal.Health += (float)Math.Floor(StatConversion.GetHealthFromStamina(statsTotal.Stamina) * (1f + statsTotal.BonusHealthMultiplier)); statsTotal.Mana = (float)Math.Round(statsTotal.Mana + StatConversion.GetManaFromIntellect(statsTotal.Intellect)); statsTotal.Mana = (float)Math.Round(statsTotal.Mana * (1f + statsTotal.BonusManaMultiplier)); statsTotal.SpellPower += statsTotal.Intellect - 10; float hasteFromRating = StatConversion.GetSpellHasteFromRating(statsTotal.HasteRating); float talentedHaste = (1 + hasteFromRating) * (1 + talents.Darkness * .01f) - 1; statsTotal.SpellHaste += character.Race == CharacterRace.Goblin ? talentedHaste * 1.01f : talentedHaste; float baseBonus = (float)Math.Floor(baseStats.Spirit * statsTotal.BonusSpiritMultiplier); float itemBonus = (float)Math.Floor(itemStats.Spirit * statsTotal.BonusSpiritMultiplier); float spiritFromItemsAndEffects = baseBonus + itemBonus + itemStats.Spirit; float hitRatingFromSpirit = (0.5f * talents.TwistedFaith) * Math.Max(0f, spiritFromItemsAndEffects); statsTotal.HitRating += hitRatingFromSpirit; statsTotal.SpellHit += StatConversion.GetSpellHitFromRating(statsTotal.HitRating); // ignoring the base crit percentage here as the in-game tooltip says that the int -> crit conversion contains the base. float critFromInt = StatConversion.GetSpellCritFromIntellect(statsTotal.Intellect) + 0.012375f; float critFromRating = StatConversion.GetSpellCritFromRating(statsTotal.CritRating); statsTotal.SpellCrit = character.Race == CharacterRace.Worgen ? (critFromInt + critFromRating) + .01f : (critFromInt + critFromRating); // Armor statsTotal.Armor = statsTotal.Armor * (1f + statsTotal.BaseArmorMultiplier); statsTotal.BonusArmor = statsTotal.BonusArmor * (1f + statsTotal.BonusArmorMultiplier); statsTotal.Armor += statsTotal.BonusArmor; statsTotal.Armor = (float)Math.Round(statsTotal.Armor); return(statsTotal); }