protected override void FinalizeModifiers() { base.FinalizeModifiers(); WarlockTalents talents = Mommy.Talents; // multipliers go into SpecialModifiers SpecialModifiers.AddMultiplicativeMultiplier( Stats.BonusShadowDamageMultiplier); if (Mommy.CastSpells.ContainsKey("Corruption")) { SpecialModifiers.AddAdditiveMultiplier(.15f); } if (Mommy.CastSpells.ContainsKey("Curse Of Agony")) { SpecialModifiers.AddAdditiveMultiplier(.15f); } if (Mommy.CastSpells.ContainsKey("Immolate")) { SpecialModifiers.AddAdditiveMultiplier(.15f); } if (Mommy.CastSpells.ContainsKey("Unstable Affliction")) { SpecialModifiers.AddAdditiveMultiplier(.15f); } }
protected override void FinalizeModifiers() { base.FinalizeModifiers(); WarlockTalents talents = Mommy.Talents; float demonologist = talents.MasterDemonologist * .01f; // crit goes into the stats object Stats.SpellCrit += demonologist; if (talents.DemonicEmpowerment > 0) { Stats.SpellCrit += .2f * 30f / GetEmpowermentCooldown(); } // multipliers go into SpecialModifiers SpecialModifiers.AddMultiplicativeMultiplier( Stats.BonusFireDamageMultiplier); SpecialModifiers.AddAdditiveMultiplier(.1f * talents.ImprovedImp); SpecialModifiers.AddAdditiveMultiplier(.04f * talents.UnholyPower); SpecialModifiers.AddMultiplicativeMultiplier(demonologist); SpecialModifiers.AddAdditiveMultiplier(.1f * talents.EmpoweredImp); SpecialModifiers.AddCritBonusMultiplier(.2f * talents.Ruin); if (talents.GlyphImp) { SpecialModifiers.AddAdditiveMultiplier(.2f); } }
protected override void FinalizeModifiers() { base.FinalizeModifiers(); WarlockTalents talents = Mommy.Talents; float apBonus = 1.5f + talents.DemonicBrutality * .1f; if (Mommy.Talents.GlyphFelguard) { apBonus *= 1.2f; } Stats.BonusAttackPowerMultiplier = (1f + Stats.BonusAttackPowerMultiplier) * apBonus - 1f; TotalModifiers.AddMultiplicativeMultiplier( talents.MasterDemonologist * .01f); if (talents.DemonicEmpowerment > 0) { Stats.AddSpecialEffect( new SpecialEffect( Trigger.Use, new Stats() { PhysicalHaste = .2f }, 15f, GetEmpowermentCooldown())); } }
private void ApplyPetsRaidBuff( Stats stats, string pet, WarlockTalents talents, List <Buff> activeBuffs) { stats.Health += CalcPetHealthBuff(pet, talents, activeBuffs); stats.Intellect += CalcPetIntBuff(pet, talents, activeBuffs); stats.Spirit += CalcPetSpiBuff(pet, talents, activeBuffs); }
public static float CalcPetHealthBuff(string pet, WarlockTalents talents, List <Buff> activeBuffs, CalculationOptionsWarlock options) { if (!pet.Equals("Imp")) { return(0f); } //spell ID 6307, effect ID 2190 float SCALE = 1.3200000525f; return(StatUtils.GetBuffEffect(activeBuffs, SCALE * buffBaseValues[options.PlayerLevel - 80], "Health", s => s.Health)); }
public static float CalcPetMP5Buff(string pet, WarlockTalents talents, List <Buff> activeBuffs, CalculationOptionsWarlock options) { if (!pet.Equals("Felhunter")) { return(0f); } //spell ID 54424, effect ID 47203 float SCALE = 0.7360000014f; return(StatUtils.GetBuffEffect(activeBuffs, SCALE * buffBaseValues[options.PlayerLevel - 80], "Mana Regeneration", s => s.Mp5)); }
public static float CalcPetSpiBuff( string pet, WarlockTalents talents, List <Buff> activeBuffs) { if (!pet.Equals("Felhunter")) { return(0f); } return(StatUtils.GetBuffEffect( activeBuffs, 64f * (1 + talents.ImprovedFelhunter * .05f), "Spirit", s => s.Spirit)); }
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); }
public static float CalcPetHealthBuff( string pet, WarlockTalents talents, List <Buff> activeBuffs) { if (!pet.Equals("Imp")) { return(0f); } return(StatUtils.GetBuffEffect( activeBuffs, 1330f * (1 + talents.ImprovedImp * .1f), "Health", s => s.Health)); }
protected override void FinalizeModifiers() { base.FinalizeModifiers(); WarlockTalents talents = Mommy.Talents; float demonologist = talents.MasterDemonologist * .01f; // crit goes into the stats object Stats.SpellCrit += demonologist; // multipliers go into SpecialModifiers SpecialModifiers.AddMultiplicativeMultiplier( Stats.BonusShadowDamageMultiplier); SpecialModifiers.AddAdditiveMultiplier(demonologist); }
/// <summary> /// Gets a modified version of the user's spell priorities, for internal /// purposes. /// </summary> /// <param name="spellPriority"></param> /// <returns></returns> public List<string> GetPrioritiesForCalcs(WarlockTalents talents, bool execute) { List<string> forCalcs = new List<string>(SpellPriority); if (talents.Backdraft > 0 && !SpellPriority.Contains("Incinerate (Under Backdraft)")) { forCalcs.Insert(forCalcs.Count, "Incinerate (Under Backdraft)"); } if (!execute && Filler.Equals("Shadow Bolt") && !forCalcs.Contains("Shadow Bolt (Instant)") && ShadowBolt_Instant.IsCastable(talents, forCalcs)) { forCalcs.Insert(forCalcs.Count, "Shadow Bolt (Instant)"); } return forCalcs; }
/// <summary> /// Gets a modified version of the user's spell priorities, for internal /// purposes. /// </summary> /// <param name="spellPriority"></param> /// <returns></returns> public List <string> GetPrioritiesForCalcs(WarlockTalents talents, bool execute) { List <string> forCalcs = new List <string>(SpellPriority); if (talents.Backdraft > 0 && !SpellPriority.Contains("Incinerate (Under Backdraft)")) { forCalcs.Insert(forCalcs.Count, "Incinerate (Under Backdraft)"); } if (!execute && Filler.Equals("Shadow Bolt") && !forCalcs.Contains("Shadow Bolt (Instant)") && ShadowBolt_Instant.IsCastable(talents, forCalcs)) { forCalcs.Insert(forCalcs.Count, "Shadow Bolt (Instant)"); } return(forCalcs); }
public void CalcStats1() { WarlockTalents talents = Mommy.Talents; //Stats.Strength = 453f; //Stats.Agility = 883f; Stats.SpellPower = CalcSpellPower(); Stats.AttackPower = CalcAttackPower(); Stats.PhysicalCrit = .0328f; Stats.Accumulate(Mommy.PetBuffs); FinalizeModifiers(); SpecialModifiers.Accumulate(TotalModifiers); MeleeModifiers.Accumulate(TotalModifiers); Stats.SpellHaste = GetHasteWithProcs(s => s.SpellHaste); Stats.PhysicalHaste = GetHasteWithProcs(s => s.PhysicalHaste); }
public void CalcStats1() { // Stam & Int have to happen in this stage, so that Demonic // Knowledge is in effect when calculating the benefit of a // Demonic Pact proc. // Crit has to happen in this stage, so that Empowered Imp gives // the warlocks the right amount of crit. WarlockTalents talents = Mommy.Talents; float vitality = talents.FelVitality * .05f; float tacticsCrit = .02f * talents.DemonicTactics + .1f * talents.ImprovedDemonicTactics * (Mommy.CalcSpellCrit() - Mommy.Stats.SpellCritOnTarget); Stats = new Stats() { Stamina = BaseStamina + StaminaCoef * Mommy.CalcStamina(), Intellect = BaseIntellect + IntellectCoef * Mommy.CalcIntellect(), Strength = 297f, Agility = 90f, BonusStaminaMultiplier = vitality, BonusIntellectMultiplier = vitality, SpellCrit = BaseSpellCrit + tacticsCrit + Mommy.Stats.Warlock2T9, SpellPower = BaseSpellPower, AttackPower = BaseAttackPower, PhysicalCrit = .0329f + tacticsCrit + Mommy.Stats.Warlock2T9, }; Stats.Accumulate(Mommy.PetBuffs); Mommy.Add4pT10(TotalModifiers); FinalizeModifiers(); SpecialModifiers.Accumulate(TotalModifiers); MeleeModifiers.Accumulate(TotalModifiers); Stats.SpellHaste = GetHasteWithProcs(s => s.SpellHaste); Stats.PhysicalHaste = GetHasteWithProcs(s => s.PhysicalHaste); }
public override Stats GetCharacterStats(Character character, Item additionalItem) { WarlockTalents talents = character.WarlockTalents; CalculationOptionsWarlock calcOpts = character.CalculationOptions as CalculationOptionsWarlock; BossOptions bossOpts = character.BossOptions; Stats stats = BaseStats.GetBaseStats(character); AccumulateItemStats(stats, character, additionalItem); AccumulateBuffsStats(stats, character.ActiveBuffs); AccumulateSetBonusStats(stats, character.SetBonusCount); ApplyPetsRaidBuff(stats, calcOpts.Pet, talents, character.ActiveBuffs, calcOpts); float[] demonicEmbraceValues = { 0f, .04f, .07f, .1f }; Stats statsTalents = new Stats { BonusStaminaMultiplier = demonicEmbraceValues[talents.DemonicEmbrace] //Demonic Embrace }; if (talents.Eradication > 0) { float[] eradicationValues = { 0f, .06f, .12f, .20f }; statsTalents.AddSpecialEffect( new SpecialEffect( Trigger.CorruptionTick, new Stats() { SpellHaste = eradicationValues[talents.Eradication] }, 10f, //duration 0f, //cooldown .06f)); //chance } stats.Accumulate(statsTalents); stats.ManaRestoreFromMaxManaPerSecond = Math.Max( stats.ManaRestoreFromMaxManaPerSecond, .001f * Spell.CalcUprate(talents.SoulLeech > 0 ? 1f : 0f, 15f, bossOpts.BerserkTimer * 1.1f)); 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); }
private void ApplyPetsRaidBuff(Stats stats, string pet, WarlockTalents talents, List <Buff> activeBuffs, CalculationOptionsWarlock options) { stats.Health += CalcPetHealthBuff(pet, talents, activeBuffs, options); stats.Mana += CalcPetManaBuff(pet, talents, activeBuffs, options); stats.Mp5 += CalcPetMP5Buff(pet, talents, activeBuffs, options); }
public static float CalcPetMP5Buff(string pet, WarlockTalents talents, List<Buff> activeBuffs, CalculationOptionsWarlock options) { if (!pet.Equals("Felhunter")) { return 0f; } //spell ID 54424, effect ID 47203 float SCALE = 0.7360000014f; return StatUtils.GetBuffEffect(activeBuffs, SCALE * buffBaseValues[options.PlayerLevel - 80], "Mana Regeneration", s => s.Mp5); }
public static float CalcPetHealthBuff(string pet, WarlockTalents talents, List<Buff> activeBuffs, CalculationOptionsWarlock options) { if (!pet.Equals("Imp")) { return 0f; } //spell ID 6307, effect ID 2190 float SCALE = 1.3200000525f; return StatUtils.GetBuffEffect(activeBuffs, SCALE * buffBaseValues[options.PlayerLevel - 80], "Health", s => s.Health); }
private void ApplyPetsRaidBuff(Stats stats, string pet, WarlockTalents talents, List<Buff> activeBuffs, CalculationOptionsWarlock options) { stats.Health += CalcPetHealthBuff(pet, talents, activeBuffs, options); stats.Mana += CalcPetManaBuff(pet, talents, activeBuffs, options); stats.Mp5 += CalcPetMP5Buff(pet, talents, activeBuffs, options); }
public static bool IsCastable(WarlockTalents talents, List<string> priorities) { return priorities.Contains("Corruption") && (talents.GlyphOfCorruption || talents.Nightfall > 0); }
/// <summary>Gets the total Stats of the Character</summary> /// <param name="character"> /// The Character to get the total Stats of /// </param> /// <param name="additionalItem"> /// An additional item to grant the Character the stats of (as if it /// were worn) /// </param> /// <returns>The total stats for the Character</returns> public override Stats GetCharacterStats( Character character, Item additionalItem) { WarlockTalents talents = character.WarlockTalents; CalculationOptionsWarlock options = character.CalculationOptions as CalculationOptionsWarlock; Stats stats = BaseStats.GetBaseStats(character); // Items AccumulateItemStats(stats, character, additionalItem); // Buffs AccumulateBuffsStats(stats, character.ActiveBuffs); if (options.Imbue.Equals("Grand Spellstone")) { stats.HasteRating += 60f * (1f + talents.MasterConjuror * 1.5f); } else { Debug.Assert(options.Imbue.Equals("Grand Firestone")); stats.CritRating += 49f * (1f + talents.MasterConjuror * 1.5f); } ApplyPetsRaidBuff( stats, options.Pet, talents, character.ActiveBuffs); float aegis = 1f + talents.DemonicAegis * 0.10f; stats.SpellPower += 180f * aegis; // fel armor stats.SpellDamageFromSpiritPercentage += .3f * aegis; // fel armor // Talents float[] talentValues = { 0f, .04f, .07f, .1f }; Stats statsTalents = new Stats { //Demonic Embrace: increases your stamina by 4/7/10% BonusStaminaMultiplier = talentValues[talents.DemonicEmbrace], //Fel Vitality: increases your maximum Health & Mana by 1/2/3% BonusHealthMultiplier = talents.FelVitality * 0.01f, BonusManaMultiplier = talents.FelVitality * 0.01f, //Suppression: increases your chance to hit with spells by //1/2/3% SpellHit = (talents.Suppression * 0.01f), //Demonic Tactics: increases your spell crit chance by //2/4/6/8/10% //Backlash: increases your spell crit chance by 1/2/3% BonusCritChance = talents.DemonicTactics * 0.02f + talents.Backlash * 0.01f }; if (talents.Eradication > 0) { talentValues = new float[] { 0f, .06f, .12f, .20f }; statsTalents.AddSpecialEffect( new SpecialEffect( Trigger.CorruptionTick, new Stats() { SpellHaste = talentValues[talents.Eradication] }, 6f, 0f, .06f)); } stats.Accumulate(statsTalents); stats.ManaRestoreFromMaxManaPerSecond = Math.Max( stats.ManaRestoreFromMaxManaPerSecond, .002f * Spell.CalcUprate( talents.ImprovedSoulLeech * .5f, 15f, options.Duration * 1.1f)); return(stats); }
public static bool HasTalent(WarlockTalents 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; }