public static float StanceDamageReduction(Character character, Stats stats, DamageType damageType) { PaladinTalents talents = character.PaladinTalents; float damageTaken = 1.0f * (1.0f + stats.DamageTakenMultiplier); //Talents damageTaken *= (1f - talents.ImprovedRighteousFury * 0.02f) * (1f - talents.ShieldOfTheTemplar * 0.01f); if (talents.GlyphOfDivinePlea) { damageTaken *= (1f - 0.03f); } switch (damageType) { case DamageType.Arcane: case DamageType.Fire: case DamageType.Frost: case DamageType.Nature: case DamageType.Shadow: case DamageType.Holy: return(damageTaken * (1.0f - talents.GuardedByTheLight * 0.03f)); default: return(damageTaken); } }
public AbilityModel(Character character, Stats stats, Ability ability, CalculationOptionsProtPaladin calcOpts) { #endif Character = character; Stats = stats; Ability = ability; CalcOpts = calcOpts; #if (RAWR3) BossOpts = bossOpts; #endif Talents = Character.PaladinTalents; #if (RAWR3) AttackTable = new AttackTable(character, stats, ability, CalcOpts, BossOpts); #else AttackTable = new AttackTable(character, stats, ability, CalcOpts); #endif if (!Lookup.IsSpell(Ability)) #if (RAWR3) { ArmorReduction = Lookup.EffectiveTargetArmorReduction(Character, Stats, BossOpts.Armor, BossOpts.Level); } #else { ArmorReduction = Lookup.EffectiveTargetArmorReduction(Character, Stats, CalcOpts.TargetArmor, CalcOpts.TargetLevel); } #endif Name = Lookup.Name(Ability); DamageMultiplier = Lookup.StanceDamageMultipler(Character, Stats); DamageMultiplier *= Lookup.CreatureTypeDamageMultiplier(Character, CalcOpts.TargetType); CalculateDamage(); CalculateThreat(); }
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); }
private void ConvertRatings(Stats stats, PaladinTalents talents, CalculationOptionsHealadin calcOpts) { stats.Stamina *= 1f + stats.BonusStaminaMultiplier; // Intellect is used to calculate initial mana pool. // To avoid temporary intellect from highest stat procs changing initial mana pool // we track temporary intellect separatly in HighestStat property and combine it with intellect // when needed. // TODO: However this doesn't help to deal with pure temporary intellect procs (if there are any). // NOTE: If we add highest stat to intellect after we calculate mana, the only visible change // will be the displayed intellect for the character. stats.Intellect *= (1f + stats.BonusIntellectMultiplier); stats.HighestStat *= (1f + stats.BonusIntellectMultiplier); stats.SpellCrit = stats.SpellCrit + StatConversion.GetSpellCritFromIntellect( stats.Intellect + stats.HighestStat, CharacterClass.Paladin) + StatConversion.GetSpellCritFromRating(stats.CritRating, CharacterClass.Paladin); // I want to track haste before talent seperately, going to use RangedHaste for that. // I plan to use this on the "Stats" page so I can report sources of haste seperatly stats.RangedHaste = (1f + stats.SpellHaste) * (1f + StatConversion.GetSpellHasteFromRating(stats.HasteRating, CharacterClass.Paladin)) - 1f; // calculating physical haste for use in melee attacks, which will generate mana // can also divide spellhaste / physicalhaste to get orignal value of spellhaste, which is from buffs as far as I can tell stats.PhysicalHaste = (1f + talents.JudgementsOfThePure * 0.03f) * (1f + talents.SpeedOfLight * 0.01f) * (1f + StatConversion.GetSpellHasteFromRating(stats.HasteRating, CharacterClass.Paladin)) - 1f; stats.SpellHaste = (1f + talents.JudgementsOfThePure * 0.03f) * (1f + talents.SpeedOfLight * 0.01f) * (1f + stats.SpellHaste) * (1f + StatConversion.GetSpellHasteFromRating(stats.HasteRating, CharacterClass.Paladin)) - 1f; // GetManaFromIntellect/GetHealthFromStamina account for the fact // that the first 20 Int/Sta only give 1 Mana/Health each. stats.Mana += StatConversion.GetManaFromIntellect(stats.Intellect, CharacterClass.Paladin) * (1f + stats.BonusManaMultiplier); stats.Health += StatConversion.GetHealthFromStamina(stats.Stamina, CharacterClass.Paladin); stats.PhysicalHit += StatConversion.GetPhysicalHitFromRating( stats.HitRating, CharacterClass.Paladin); }
public override CharacterCalculationsBase GetCharacterCalculations(Character character, Item additionalItem, bool referenceCalculation, bool significantChange, bool needsDisplayCalculations) { // First things first, we need to ensure that we aren't using bad data CharacterCalculationsHealadin calc = new CharacterCalculationsHealadin(); if (character == null) { return(calc); } CalculationOptionsHealadin calcOpts = character.CalculationOptions as CalculationOptionsHealadin; if (calcOpts == null) { return(calc); } // Stats stats; calc = null; PaladinTalents talents = character.PaladinTalents; for (int i = 0; i < 5; i++) { float oldBurst = 0; if (i > 0) { oldBurst = calc.BurstPoints; } stats = GetCharacterStats(character, additionalItem, true, calc); calc = new CharacterCalculationsHealadin(); Rotation rot = new Rotation(character, stats); if (i > 0) { calc.BurstPoints = oldBurst; } else { calc.BurstPoints = rot.CalculateBurstHealing(calc); } calc.FightPoints = rot.CalculateFightHealing(calc); calc.OverallPoints = calc.BurstPoints + calc.FightPoints; } calc.BasicStats = GetCharacterStats(character, additionalItem, false, null); return(calc); }
public AbilityModel(Character character, Base.StatsPaladin stats, Ability ability, CalculationOptionsProtPaladin calcOpts, BossOptions bossOpts) { Character = character; Stats = stats; Ability = ability; CalcOpts = calcOpts; BossOpts = bossOpts; Talents = Character.PaladinTalents; AttackTable = new AttackTable(character, stats, ability, CalcOpts, BossOpts); if (!Lookup.IsSpell(Ability)) { ArmorReduction = Lookup.EffectiveTargetArmorReduction(Stats.ArmorPenetration, BossOpts.Armor, BossOpts.Level); } Name = Lookup.Name(Ability); CalculateDamage(); CalculateThreat(); }
private void ConvertRatings(Stats stats, PaladinTalents talents, CalculationOptionsHealadin calcOpts) { stats.Stamina *= 1f + stats.BonusStaminaMultiplier; // Intellect is used to calculate initial mana pool. // To avoid temporary intellect from highest stat procs changing initial mana pool // we track temporary intellect separatly in HighestStat property and combine it with intellect // when needed. // TODO: However this doesn't help to deal with pure temporary intellect procs (if there are any). // NOTE: If we add highest stat to intellect after we calculate mana, the only visible change // will be the displayed intellect for the character. stats.Intellect *= (1f + stats.BonusIntellectMultiplier) * (1f + talents.DivineIntellect * .02f); stats.HighestStat *= (1f + stats.BonusIntellectMultiplier) * (1f + talents.DivineIntellect * .02f); stats.SpellPower += 0.04f * (stats.Intellect + stats.HighestStat) * talents.HolyGuidance; stats.SpellCrit = stats.SpellCrit + StatConversion.GetSpellCritFromIntellect( stats.Intellect + stats.HighestStat, CharacterClass.Paladin) + StatConversion.GetSpellCritFromRating(stats.CritRating, CharacterClass.Paladin) + talents.SanctityOfBattle * .01f + talents.Conviction * .01f; stats.SpellHaste = (1f + talents.JudgementsOfThePure * (calcOpts.JotP ? .03f : 0f)) * (1f + stats.SpellHaste) * (1f + StatConversion.GetSpellHasteFromRating(stats.HasteRating, CharacterClass.Paladin)) - 1f; // GetManaFromIntellect/GetHealthFromStamina account for the fact // that the first 20 Int/Sta only give 1 Mana/Health each. stats.Mana += StatConversion.GetManaFromIntellect(stats.Intellect, CharacterClass.Paladin) * (1f + stats.BonusManaMultiplier); stats.Health += StatConversion.GetHealthFromStamina(stats.Stamina, CharacterClass.Paladin); stats.PhysicalHit += StatConversion.GetPhysicalHitFromRating( stats.HitRating, CharacterClass.Paladin); }
public static bool HasTalent(PaladinTalents tal) { return(TalentManager.IsSelected((int)tal)); }
public static bool HasTalent(PaladinTalents 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); }
// Combine talents and buffs into primary and secondary stats. // Convert ratings into their percentage values. private void ConvertRatings(Stats stats, PaladinTalents talents, Character character) { // Primary stats stats.Strength += stats.HighestStat; stats.Strength *= (1 + stats.BonusStrengthMultiplier + (Character.ValidateArmorSpecialization(character, ItemType.Plate) ? .05f : 0f)); stats.Agility *= (1 + stats.BonusAgilityMultiplier); stats.Stamina *= (1 + stats.BonusStaminaMultiplier); stats.Intellect *= (1 + stats.BonusIntellectMultiplier); // Secondary stats // GetManaFromIntellect/GetHealthFromStamina account for the fact // that the first 20 Int/Sta only give 1 Mana/Health each. stats.Mana += StatConversion.GetManaFromIntellect(stats.Intellect, CharacterClass.Paladin); stats.Mana *= (1f + stats.BonusManaMultiplier); stats.Health += StatConversion.GetHealthFromStamina(stats.Stamina, CharacterClass.Paladin); stats.Health *= (1f + stats.BonusHealthMultiplier); stats.AttackPower += stats.Strength * 2; stats.AttackPower *= (1f + stats.BonusAttackPowerMultiplier); // Combat ratings if (stats.HighestSecondaryStat > 0) { if (stats.CritRating > stats.MasteryRating) if (stats.HasteRating > stats.CritRating) stats.HasteRating += stats.HighestSecondaryStat; else stats.CritRating += stats.HighestSecondaryStat; else if (stats.HasteRating > stats.MasteryRating) stats.HasteRating += stats.HighestSecondaryStat; else stats.MasteryRating += stats.HighestSecondaryStat; } stats.Expertise += (talents.GlyphOfSealOfTruth ? PaladinConstants.GLYPH_OF_SEAL_OF_TRUTH : 0) + StatConversion.GetExpertiseFromRating(stats.ExpertiseRating, CharacterClass.Paladin); stats.PhysicalHit += StatConversion.GetPhysicalHitFromRating(stats.HitRating, CharacterClass.Paladin); stats.SpellHit += StatConversion.GetSpellHitFromRating(stats.HitRating, CharacterClass.Paladin) + PaladinConstants.SHEATH_SPHIT_COEFF; stats.PhysicalCrit += StatConversion.GetPhysicalCritFromRating(stats.CritRating, CharacterClass.Paladin) + StatConversion.GetPhysicalCritFromAgility(stats.Agility, CharacterClass.Paladin); stats.SpellCrit += stats.SpellCritOnTarget + StatConversion.GetSpellCritFromRating(stats.CritRating, CharacterClass.Paladin) + StatConversion.GetSpellCritFromIntellect(stats.Intellect, CharacterClass.Paladin); stats.PhysicalHaste = (1f + stats.PhysicalHaste) * (1f + StatConversion.GetPhysicalHasteFromRating(stats.HasteRating, CharacterClass.Paladin)) - 1f; stats.SpellHaste = (1f + stats.SpellHaste) * (1f + StatConversion.GetSpellHasteFromRating(stats.HasteRating, CharacterClass.Paladin)) - 1f; stats.BonusDamageMultiplier += talents.Communion * PaladinConstants.COMMUNION; stats.SpellPower += stats.AttackPower * PaladinConstants.SHEATH_AP_COEFF; stats.SpellPower *= (1f + stats.BonusSpellPowerMultiplier); }
public Stats GetCharacterStats(Character character, Item additionalItem, bool computeAverageStats, CharacterCalculationsHealadin calc) { PaladinTalents talents = character.PaladinTalents; CalculationOptionsHealadin calcOpts = character.CalculationOptions as CalculationOptionsHealadin; if (calcOpts == null) { calcOpts = new CalculationOptionsHealadin(); } #if (RAWR3) BossOptions bossOpts = character.BossOptions; if (bossOpts == null) { bossOpts = new BossOptions(); } #endif #if (RAWR3) float fightLength = bossOpts.BerserkTimer * 60f; #else float fightLength = calcOpts.Length * 60f; #endif Stats statsRace = BaseStats.GetBaseStats(character.Level, CharacterClass.Paladin, character.Race); Stats statsBaseGear = GetItemStats(character, additionalItem); Stats statsBuffs = GetBuffsStats(character, calcOpts); Stats stats = statsBaseGear + statsBuffs + statsRace; ConvertRatings(stats, talents, calcOpts); if (computeAverageStats) { Stats statsAverage = new Stats(); foreach (SpecialEffect effect in stats.SpecialEffects()) { float trigger = 0f; if (calc == null) { trigger = 1.5f / calcOpts.Activity / (1f + stats.SpellHaste); if (effect.Trigger == Trigger.HealingSpellCrit || effect.Trigger == Trigger.SpellCrit) { trigger *= stats.SpellCrit; } else if (effect.Trigger == Trigger.HolyShockCast) { trigger = 6f / calcOpts.HolyShock; } } else { if (effect.Trigger == Trigger.HealingSpellCast || effect.Trigger == Trigger.HealingSpellHit) { trigger = 1f / Rotation.GetHealingCastsPerSec(calc); } else if (effect.Trigger == Trigger.HealingSpellCrit || effect.Trigger == Trigger.SpellCrit) { trigger = 1f / Rotation.GetHealingCritsPerSec(calc); } else if (effect.Trigger == Trigger.SpellCast || effect.Trigger == Trigger.SpellHit) { trigger = 1f / Rotation.GetSpellCastsPerSec(calc); } else if (effect.Trigger == Trigger.DamageOrHealingDone) { trigger = 1f / Rotation.GetHealingCastsPerSec(calc); } else if (effect.Trigger == Trigger.HolyShockCast) { trigger = 6f / calcOpts.HolyShock; } else if (effect.Trigger == Trigger.Use) { trigger = 0f; foreach (SpecialEffect childEffect in effect.Stats.SpecialEffects()) { float childTrigger = 0f; if (effect.Trigger == Trigger.HealingSpellCast || effect.Trigger == Trigger.HealingSpellHit) { childTrigger = 1f / Rotation.GetHealingCastsPerSec(calc); } else if (effect.Trigger == Trigger.HealingSpellCrit || effect.Trigger == Trigger.SpellCrit) { childTrigger = 1f / Rotation.GetHealingCritsPerSec(calc); } else if (effect.Trigger == Trigger.SpellCast || effect.Trigger == Trigger.SpellHit) { childTrigger = 1f / Rotation.GetSpellCastsPerSec(calc); } statsAverage.Accumulate(childEffect.Stats, effect.GetAverageUptime(0.0f, 1.0f) * childEffect.GetAverageStackSize(childTrigger, 1f, 1.5f, effect.Duration)); } } else if (effect.Trigger == Trigger.HolyLightCast) { trigger = 1f / Rotation.GetHolyLightCastsPerSec(calc); } else { continue; } } statsAverage.Accumulate(effect.GetAverageStats(trigger, 1f, 1.5f, fightLength)); } statsAverage.ManaRestore *= fightLength; statsAverage.Healed *= fightLength; stats = statsBaseGear + statsBuffs + statsRace + statsAverage; ConvertRatings(stats, talents, calcOpts); } return(stats); }
protected override void LoadCalculationOptions() { _loadingCalculationOptions = true; if (Character.CalculationOptions == null) { Character.CalculationOptions = new CalculationOptionsProtPaladin(); } CalculationOptionsProtPaladin calcOpts = Character.CalculationOptions as CalculationOptionsProtPaladin; PaladinTalents Talents = Character.PaladinTalents; CK_PTRMode.Checked = calcOpts.PTRMode; // Attacker Stats comboBoxTargetType.SelectedItem = calcOpts.TargetType.ToString(); numericUpDownTargetLevel.Value = calcOpts.TargetLevel; trackBarTargetArmor.Value = calcOpts.TargetArmor; trackBarBossAttackValue.Value = calcOpts.BossAttackValue; trackBarBossAttackSpeed.Value = (int)(calcOpts.BossAttackSpeed / 0.25f); comboBoxMagicDamageType.SelectedItem = calcOpts.MagicDamageType.ToString(); trackBarBossAttackValueMagic.Value = calcOpts.BossAttackValueMagic; trackBarBossAttackSpeedMagic.Value = (int)(calcOpts.BossAttackSpeedMagic / 0.25f); checkBoxUseParryHaste.Checked = calcOpts.UseParryHaste; // Stupid hack since you can't put in newlines into the VS editor properties extendedToolTipUseParryHaste.ToolTipText = extendedToolTipUseParryHaste.ToolTipText.Replace("May not", Environment.NewLine + "May not"); extendedToolTipDamageTakenMode.ToolTipText = extendedToolTipDamageTakenMode.ToolTipText.Replace("10", Environment.NewLine + "10"); extendedToolTipMitigationScale.ToolTipText = extendedToolTipMitigationScale.ToolTipText.Replace("Mitigation", Environment.NewLine + "Mitigation"); // Ranking System if (calcOpts.ThreatScale > 30.0f) // Old scale value being saved, reset to default { calcOpts.ThreatScale = 10.0f; } trackBarThreatScale.Value = Convert.ToInt32(calcOpts.ThreatScale * 10.0f); if (calcOpts.MitigationScale > 51000.0f) // Old scale value being saved, reset to default { calcOpts.MitigationScale = 17000.0f; } trackBarMitigationScale.Value = Convert.ToInt32((calcOpts.MitigationScale / 170.0f)); radioButtonMitigationScale.Checked = (calcOpts.RankingMode == 1); radioButtonTankPoints.Checked = (calcOpts.RankingMode == 2); radioButtonBurstTime.Checked = (calcOpts.RankingMode == 3); radioButtonDamageOutput.Checked = (calcOpts.RankingMode == 4); radioButtonProtWarrMode.Checked = (calcOpts.RankingMode == 5); radioButtonDamageTakenMode.Checked = (calcOpts.RankingMode == 6); trackBarThreatScale.Enabled = labelThreatScale.Enabled = (calcOpts.RankingMode != 4); trackBarMitigationScale.Enabled = labelMitigationScale.Enabled = (calcOpts.RankingMode == 1) || (calcOpts.RankingMode == 5) || (calcOpts.RankingMode == 6); comboBoxTrinketOnUseHandling.SelectedItem = calcOpts.TrinketOnUseHandling.ToString(); numericUpDownSurvivalSoftCap.Value = calcOpts.SurvivalSoftCap; // Seal Choice radioButtonSoR.Checked = (calcOpts.SealChoice == "Seal of Righteousness"); radioButtonSoV.Checked = (calcOpts.SealChoice == "Seal of Vengeance"); calcOpts.UseHolyShield = checkBoxUseHolyShield.Checked; labelTargetArmorDescription.Text = trackBarTargetArmor.Value.ToString() + (armorBosses.ContainsKey(trackBarTargetArmor.Value) ? ": " + armorBosses[trackBarTargetArmor.Value] : ""); labelBossAttackValue.Text = trackBarBossAttackValue.Value.ToString(); labelBossAttackSpeed.Text = String.Format("{0:0.00}s", ((float)(trackBarBossAttackSpeed.Value) * 0.25f)); labelBossMagicalDamage.Text = trackBarBossAttackValueMagic.Value.ToString();; labelBossMagicSpeed.Text = String.Format("{0:0.00}s", ((float)(trackBarBossAttackSpeedMagic.Value) * 0.25f)); labelThreatScale.Text = String.Format("{0:0.00}", ((float)(trackBarThreatScale.Value) * 0.01f)); labelMitigationScale.Text = String.Format("{0:0.00}", ((float)(trackBarMitigationScale.Value) * 0.01f)); switch (numericUpDownSurvivalSoftCap.Value.ToString()) { case "90000": comboBoxSurvivalSoftCap.SelectedIndex = 0; break; //Normal Dungeons case "110000": comboBoxSurvivalSoftCap.SelectedIndex = 1; break; //Heroic Dungeons case "120000": comboBoxSurvivalSoftCap.SelectedIndex = 2; break; //T7 Raids (10) case "140000": comboBoxSurvivalSoftCap.SelectedIndex = 3; break; //T7 Raids (25) case "170000": comboBoxSurvivalSoftCap.SelectedIndex = 4; break; //T8 Raids (10) case "195000": comboBoxSurvivalSoftCap.SelectedIndex = 5; break; //T8 Raids (10, Hard) case "185000": comboBoxSurvivalSoftCap.SelectedIndex = 6; break; //T8 Raids (25) case "215000": comboBoxSurvivalSoftCap.SelectedIndex = 7; break; //T8 Raids (25, Hard) case "180000": comboBoxSurvivalSoftCap.SelectedIndex = 8; break; //T9 Raids (10) case "210000": comboBoxSurvivalSoftCap.SelectedIndex = 9; break; //T9 Raids (10, Heroic) case "190000": comboBoxSurvivalSoftCap.SelectedIndex = 10; break; //T9 Raids (25) case "225000": comboBoxSurvivalSoftCap.SelectedIndex = 11; break; //T9 Raids (25, Heroic) case "300000": comboBoxSurvivalSoftCap.SelectedIndex = 12; break; //T10 Raids (10) case "355000": comboBoxSurvivalSoftCap.SelectedIndex = 13; break; //T10 Raids (10, Heroic) case "350000": comboBoxSurvivalSoftCap.SelectedIndex = 14; break; //T10 Raids (25) case "400000": comboBoxSurvivalSoftCap.SelectedIndex = 15; break; //T10 Raids (25, Heroic) case "360000": comboBoxSurvivalSoftCap.SelectedIndex = 16; break; //Lich King (10) case "410000": comboBoxSurvivalSoftCap.SelectedIndex = 17; break; //Lich King (10, Heroic) case "405000": comboBoxSurvivalSoftCap.SelectedIndex = 18; break; //Lich King (25) case "500000": comboBoxSurvivalSoftCap.SelectedIndex = 19; break; //Lich King (25, Heroic) default: comboBoxSurvivalSoftCap.SelectedIndex = 20; break; } numericUpDownSurvivalSoftCap.Enabled = comboBoxSurvivalSoftCap.SelectedIndex == 20; _loadingCalculationOptions = false; }
public Stats GetCharacterStats(Character character, Item additionalItem, bool computeAverageStats, CharacterCalculationsHealadin calc) { CalculationOptionsHealadin calcOpts = character.CalculationOptions as CalculationOptionsHealadin; BossOptions bossOpts = character.BossOptions; PaladinTalents talents = character.PaladinTalents; float fightLength = bossOpts.BerserkTimer; Stats statsRace = BaseStats.GetBaseStats(character.Level, CharacterClass.Paladin, character.Race); Stats statsBaseGear = GetItemStats(character, additionalItem); Stats statsBuffs = GetBuffsStats(character, calcOpts); Stats stats = statsBaseGear + statsBuffs + statsRace; ConvertRatings(stats, talents, calcOpts); if (computeAverageStats) { Stats statsAverage = new Stats(); foreach (SpecialEffect effect in stats.SpecialEffects()) { float trigger = 0f; if (calc == null) { trigger = 1.5f / calcOpts.Activity / (1f + stats.SpellHaste); if (effect.Trigger == Trigger.HealingSpellCrit || effect.Trigger == Trigger.SpellCrit) { trigger *= stats.SpellCrit; } } else { if (effect.Trigger == Trigger.HealingSpellCast || effect.Trigger == Trigger.HealingSpellHit) { trigger = 1f / Rotation.GetHealingCastsPerSec(calc); } else if (effect.Trigger == Trigger.HealingSpellCrit || effect.Trigger == Trigger.SpellCrit) { trigger = 1f / Rotation.GetHealingCritsPerSec(calc); } else if (effect.Trigger == Trigger.SpellCast || effect.Trigger == Trigger.SpellHit) { trigger = 1f / Rotation.GetSpellCastsPerSec(calc); } else if (effect.Trigger == Trigger.DamageOrHealingDone) { trigger = 1f / Rotation.GetHealingCastsPerSec(calc); } else if (effect.Trigger == Trigger.Use) { trigger = 0f; foreach (SpecialEffect childEffect in effect.Stats.SpecialEffects()) { float childTrigger = 0f; if (effect.Trigger == Trigger.HealingSpellCast || effect.Trigger == Trigger.HealingSpellHit) { childTrigger = 1f / Rotation.GetHealingCastsPerSec(calc); } else if (effect.Trigger == Trigger.HealingSpellCrit || effect.Trigger == Trigger.SpellCrit) { childTrigger = 1f / Rotation.GetHealingCritsPerSec(calc); } else if (effect.Trigger == Trigger.SpellCast || effect.Trigger == Trigger.SpellHit) { childTrigger = 1f / Rotation.GetSpellCastsPerSec(calc); } statsAverage.Accumulate(childEffect.Stats, effect.GetAverageUptime(0.0f, 1.0f) * childEffect.GetAverageStackSize(childTrigger, 1f, 1.5f, effect.Duration)); } } else { continue; } } statsAverage.Accumulate(effect.GetAverageStats(trigger, 1f, 1.5f, fightLength)); } statsAverage.ManaRestore *= fightLength; statsAverage.Healed *= fightLength; statsAverage.HealedPerSP *= fightLength; stats = statsBaseGear + statsBuffs + statsRace + statsAverage; ConvertRatings(stats, talents, calcOpts); } #region Set Bonuses int T11Count; character.SetBonusCount.TryGetValue("Reinforced Sapphirium Regalia", out T11Count); stats.BonusCritChanceDeathCoil = 0; // using this for Holy Light crit bonus, for now stats.BonusCritChanceFrostStrike = 0; // yes, I'm pure evil, using this to track 4T11 if (T11Count >= 2) { // T11 Pally 2 piece bonus: add 5% crit to HL stats.BonusCritChanceDeathCoil = 0.05f; } if (T11Count >= 4) { // T11 Pally 4 piece bonus: 540 spirit buff for 6 secs after HS cast stats.BonusCritChanceFrostStrike = 1; } #endregion Set Bonuses return(stats); }
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; }