Beispiel #1
0
        public FuryGenerator(Character c, Stats s, CombatFactors cf, Skills.WhiteAttacks wa, CalculationOptionsDPSWarr co, BossOptions bo)
        {
            WarriorTalents Talents = c.WarriorTalents;

            //WarriorTalentsCata TalentsCata = c.WarriorTalentsCata;
            //
            Rot = new FuryRotation(c, s, cf, wa, co, bo);
            Rot.Initialize();
            LatentGCD = Math.Round(1.5 + co.FullLatency, NUM_DEC);
            HastedGCD = Math.Round(1.0 + co.FullLatency, NUM_DEC);

            HSPerc = .8;

            BS1Proc = c.WarriorTalents.Bloodsurge / 15f; // 7/13/20%
            BS2Proc = 0f;

            if (s.BonusWarrior_T10_4P_BSSDProcChange > 0)
            {
                BS2Proc = 0.2;
            }

            BT            = Rot.GetWrapper <Skills.BloodThirst>().ability;
            WW            = Rot.GetWrapper <Skills.WhirlWind>().ability;
            BS            = Rot.GetWrapper <Skills.BloodSurge>().ability;
            HS            = Rot.GetWrapper <Skills.HeroicStrike>().ability;
            WhiteInterval = wa.MhEffectiveSpeed;

            SetChances();
        }
Beispiel #2
0
        public AttackModel(Character character, Stats stats, CalculationOptionsProtWarr options, AttackModelMode attackModelMode, RageModelMode rageModelMode)
        {
            Character        = character;
            Stats            = stats;
            Options          = options;
            Talents          = Character.WarriorTalents;
            DefendTable      = new DefendTable(character, stats, options);
            ParryModel       = new ParryModel(character, stats, options);
            _attackModelMode = attackModelMode;
            _rageModelMode   = rageModelMode;

            Abilities.Add(Ability.None, character, stats, options);
            Abilities.Add(Ability.Cleave, character, stats, options);
            Abilities.Add(Ability.ConcussionBlow, character, stats, options);
            Abilities.Add(Ability.DamageShield, character, stats, options);
            Abilities.Add(Ability.DeepWounds, character, stats, options);
            Abilities.Add(Ability.Devastate, character, stats, options);
            Abilities.Add(Ability.HeroicStrike, character, stats, options);
            Abilities.Add(Ability.HeroicThrow, character, stats, options);
            Abilities.Add(Ability.MockingBlow, character, stats, options);
            Abilities.Add(Ability.Rend, character, stats, options);
            Abilities.Add(Ability.Revenge, character, stats, options);
            Abilities.Add(Ability.ShieldSlam, character, stats, options);
            Abilities.Add(Ability.Shockwave, character, stats, options);
            Abilities.Add(Ability.Slam, character, stats, options);
            Abilities.Add(Ability.SunderArmor, character, stats, options);
            Abilities.Add(Ability.ThunderClap, character, stats, options);
            Abilities.Add(Ability.Vigilance, character, stats, options);

            Calculate();
        }
        private static Composite CreateProtectionDiagnosticOutput()
        {
            if (!SingularSettings.Debug)
            {
                return(new ActionAlwaysFail());
            }

            return(new ThrottlePasses(
                       1, TimeSpan.FromMilliseconds(1500), RunStatus.Failure,
                       new Action(ret =>
            {
                string log =
                    $"... [prot] h={Me.HealthPercent:F1}%/r={Me.CurrentRage:F1}%, stnc={(WarriorStance)Me.Shapeshift}, Ultim={HasUltimatum}";

                WarriorTalents tier6 = Common.GetTierTalent(6);
                string tier6spell = "";
                if (tier6 == WarriorTalents.Avatar)
                {
                    tier6spell = "Avatar";
                }
                else if (tier6 == WarriorTalents.Bloodbath)
                {
                    tier6spell = "Bloodbath";
                }
                else if (tier6 == WarriorTalents.Bladestorm)
                {
                    tier6spell = "Bladestorm";
                }

                if (tier6 != WarriorTalents.None)
                {
                    TimeSpan tsbs = Me.GetAuraTimeLeft(tier6spell);
                    log += string.Format(", {0}={1:F0} ms", tier6spell, tsbs.TotalMilliseconds);
                }

                if (!Me.GotTarget())
                {
                    log += ", Targ=(null)";
                }
                else
                {
                    log += string.Format(", Targ={0} {1:F1}% @ {2:F1} yds, Melee={3}, Facing={4}, LoSS={5}, DeepWounds={6}",
                                         Me.CurrentTarget.SafeName(),
                                         Me.CurrentTarget.HealthPercent,
                                         Me.CurrentTarget.Distance,
                                         Me.CurrentTarget.IsWithinMeleeRange,
                                         Me.IsSafelyFacing(Me.CurrentTarget),
                                         Me.CurrentTarget.InLineOfSpellSight,
                                         (long)Me.CurrentTarget.GetAuraTimeLeft("Deep Wounds").TotalMilliseconds
                                         );
                }
                Logger.WriteDebug(Color.AntiqueWhite, log);
                return RunStatus.Failure;
            })
                       ));
        }
 public Player(Character character)
 {
     this.Character = character;
     this.Stats = new Base.StatsWarrior();
     this.Talents = this.Character.WarriorTalents;
     this.CalcOpts = this.Character.CalculationOptions as CalculationOptionsProtWarr;
     this.BossOpts = this.Character.BossOptions;
     this.DefendModel = null;
     this.AttackModel = null;
 }
Beispiel #5
0
        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);
        }
Beispiel #6
0
        public AbilityModel(Character character, Stats stats, Ability ability)
        {
            Character   = character;
            Stats       = stats;
            Ability     = ability;
            Options     = Character.CalculationOptions as CalculationOptionsProtWarr;
            Talents     = Character.WarriorTalents;
            AttackTable = new AttackTable(character, stats, ability);

            Name             = Lookup.Name(Ability);
            ArmorReduction   = Lookup.TargetArmorReduction(Character, Stats);
            DamageMultiplier = Lookup.StanceDamageMultipler(Character, Stats);

            CalculateDamage();
            CalculateThreat();
        }
Beispiel #7
0
 public static bool HasTalent(WarriorTalents tal)
 {
     return TalentManager.IsSelected((int)tal);
 }
Beispiel #8
0
 private static bool HasTalent(WarriorTalents tal)
 {
     return(TalentManager.IsSelected((int)tal));
 }
Beispiel #9
0
 public void AddValidatedSpecialEffects(Stats statsTotal, WarriorTalents talents)
 {
     /*Ability ST = GetWrapper<ShatteringThrow>().ability,
      *      BTS = GetWrapper<BattleShout>().ability,
      *      CS = GetWrapper<CommandingShout>().ability,
      *      DS = GetWrapper<DemoralizingShout>().ability,
      *      TH = GetWrapper<ThunderClap>().ability,
      *      SN = GetWrapper<SunderArmor>().ability,
      *      SW = GetWrapper<SweepingStrikes>().ability,
      *      RK = GetWrapper<Recklessness>().ability;
      * if (ST.Validated)
      * {
      *  SpecialEffect shatt = new SpecialEffect(Trigger.Use,
      *      new Stats() { ArmorPenetration = 0.20f, },
      *      ST.Duration, ST.Cd,
      *      ST.RWAtkTable.AnyLand);
      *  statsTotal.AddSpecialEffect(shatt);
      * }
      * if (BTS.Validated)
      * {
      *  SpecialEffect bs = new SpecialEffect(Trigger.Use,
      *      new Stats() { AttackPower = (548f * (1f + talents.CommandingPresence * 0.05f)), },
      *      BTS.Duration, BTS.Cd);
      *  statsTotal.AddSpecialEffect(bs);
      * }
      * if (CS.Validated)
      * {
      *  //float value = (2255f * (1f + talents.CommandingPresence * 0.05f));
      *  SpecialEffect cs = new SpecialEffect(Trigger.Use,
      *      new Stats() { Health = 2255f * (1f + talents.CommandingPresence * 0.05f), },
      *      CS.Duration, CS.Cd);
      *  statsTotal.AddSpecialEffect(cs);
      * }
      * if (DS.Validated)
      * {
      *  //float value = (410f * (1f + talents.ImprovedDemoralizingShout * 0.08f));
      *  SpecialEffect ds = new SpecialEffect(Trigger.Use,
      *      new Stats() { BossAttackPower = 410f * (1f + talents.ImprovedDemoralizingShout * 0.08f) * -1f, },
      *      DS.Duration, DS.Cd);
      *  statsTotal.AddSpecialEffect(ds);
      * }
      * if (TH.Validated)
      * {
      *  //float value = (0.10f * (1f + (float)Math.Ceiling(talents.ImprovedThunderClap * 10f / 3f) / 100f));
      *  SpecialEffect tc = new SpecialEffect(Trigger.Use,
      *      new Stats() { BossAttackSpeedMultiplier = (-0.10f * (1f + talents.ImprovedThunderClap / 30f)), },
      *      TH.Duration, TH.Cd, TH.RWAtkTable.AnyLand);
      *  statsTotal.AddSpecialEffect(tc);
      * }
      * if (SN.Validated)
      * {
      *  //float value = 0.04f;
      *  SpecialEffect sn = new SpecialEffect(Trigger.Use,
      *      new Stats() { ArmorPenetration = 0.04f, },
      *      SN.Duration, SN.Cd, SN.RWAtkTable.AnyLand, 5);
      *  statsTotal.AddSpecialEffect(sn);
      * }
      * float landedAtksInterval = LandedAtksOverDur / CalcOpts.Duration;
      * float critRate = CriticalAtksOverDur / AttemptedAtksOverDur;
      * if (SW.Validated)
      * {
      *  SpecialEffect sweep = new SpecialEffect(Trigger.Use,
      *      new Stats() { BonusTargets = 1f, },
      *      landedAtksInterval * 5f, SW.Cd);
      *  statsTotal.AddSpecialEffect(sweep);
      * }
      * /*if (RK.Validated && CalcOpts.FuryStance)
      * {
      *  SpecialEffect reck = new SpecialEffect(Trigger.Use,
      *      new Stats() { PhysicalCrit = 1f - critRate },
      *      landedAtksInterval * 3f, RK.Cd);
      *  statsTotal.AddSpecialEffect(reck);
      * }*/
     /*if (talents.Flurry > 0 && CalcOpts.FuryStance)
      * {
      *  //float value = talents.Flurry * 0.05f;
      *  SpecialEffect flurry = new SpecialEffect(Trigger.MeleeCrit,
      *      new Stats() { PhysicalHaste = talents.Flurry * 0.05f, }, landedAtksInterval * 3f, 0f);
      *  statsTotal.AddSpecialEffect(flurry);
      * }*/
 }
Beispiel #10
0
        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;
        }