public CombatFactors(Character character, StatsHunter stats, CalculationOptionsHunter calcOpts, BossOptions bossOpts) { Char = character; if (Char != null) { if (Char.Ranged != null) { RW = Char.Ranged.Item; } else { RW = new Knuckles(); } if (Char.HunterTalents != null) { Talents = Char.HunterTalents; } else { Talents = new HunterTalents(); } } CalcOpts = (calcOpts == null ? new CalculationOptionsHunter() : calcOpts); BossOpts = (bossOpts == null ? new BossOptions() : bossOpts); StatS = stats; InvalidateCache(); // Optimizations //Set_c_values(); }
public HunterBase (Character charac, StatsHunter stats, HunterTalents talents, Specialization spec, int targetLvL) { character = charac; Stats = stats; Talents = talents; Tree = spec; TargetLevel = targetLvL; }
public HunterBase(Character charac, StatsHunter stats, HunterTalents talents, Specialization spec, int targetLvL) { character = charac; Stats = stats; Talents = talents; Tree = spec; TargetLevel = targetLvL; }
public Rotation(CombatFactors CF, HunterTalents t) { Char = null; StatS = null; Talents = t; CombatFactors = CF; CalcOpts = null; BossOpts = null; AbilityList = new Dictionary <Type, AbilWrapper>(); InvalidateCache(); }
public PetCalculations(Character character, CharacterCalculationsHunter calculatedStats, CalculationOptionsHunter calcopts, BossOptions bossOpts, StatsHunter hunterStats) { this.character = character; this.calculatedStats = calculatedStats; this.CalcOpts = calcopts; this.BossOpts = bossOpts; this.PetTalents = calcopts.PetTalents; this.Talents = character.HunterTalents; this.HunterStats = hunterStats; PetStats = new StatsHunter(); }
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 CombatFactors(Character character, StatsHunter stats, CalculationOptionsHunter calcOpts, BossOptions bossOpts) { Char = character; if (Char != null) { if (Char.Ranged != null) RW = Char.Ranged.Item; else RW = new Knuckles(); if (Char.HunterTalents != null) Talents = Char.HunterTalents; else Talents = new HunterTalents(); } CalcOpts = (calcOpts == null ? new CalculationOptionsHunter() : calcOpts); BossOpts = (bossOpts == null ? new BossOptions() : bossOpts); StatS = stats; InvalidateCache(); // Optimizations //Set_c_values(); }
public RotationType GetRotationType(HunterTalents t) { RotationType curRotationType = RotationType.Custom; if (t != null) { if (t.HighestTree == (int)Specialization.BeastMastery) { // Beast Mastery curRotationType = Rotation.RotationType.BeastMastery; } else if (t.HighestTree == (int)Specialization.Marksmanship) { // Marksmanship curRotationType = Rotation.RotationType.Marksmanship; } if (t.HighestTree == (int)Specialization.Survival) { // Survival curRotationType = Rotation.RotationType.Survival; } } return(curRotationType); }
public void validateShots(HunterTalents Talents) { // check each shot in the priority is allowed to be there. // this means removing dupes and anything after steady shot. // it also means removing shots which have already had their cooldowns used bool removeAll = false; bool used_arcane_explosive = false; bool used_aimed_multi = false; bool used_black_immo = false; for (int i = 0; i < priorities.Length; i++) { // we've already seen steadyShot - remove everything else if (priorities[i] != null && removeAll) { priorities[i].FailReason_SteadyBefore = true; priorities[i] = null; } // this shot has been used aleady if (priorities[i] != null && priorities[i].FailReason_AlreadyUsed) { priorities[i] = null; } // we've already used a shot which shares cooldown with this one if (priorities[i] != null && (priorities[i].Type == Shots.ArcaneShot && used_arcane_explosive)) { priorities[i].FailReason_SharedCooldownUsed = true; priorities[i] = null; } if (priorities[i] != null && (priorities[i].Type == Shots.ExplosiveShot && used_arcane_explosive)) { priorities[i].FailReason_SharedCooldownUsed = true; priorities[i] = null; } if (priorities[i] != null && (priorities[i].Type == Shots.AimedShot && used_aimed_multi)) { priorities[i].FailReason_SharedCooldownUsed = true; priorities[i] = null; } if (priorities[i] != null && (priorities[i].Type == Shots.MultiShot && used_aimed_multi)) { priorities[i].FailReason_SharedCooldownUsed = true; priorities[i] = null; } if (priorities[i] != null && (priorities[i].Type == Shots.BlackArrow && used_black_immo)) { priorities[i].FailReason_SharedCooldownUsed = true; priorities[i] = null; } if (priorities[i] != null && (priorities[i].Type == Shots.ImmolationTrap && used_black_immo)) { priorities[i].FailReason_SharedCooldownUsed = true; priorities[i] = null; } if (priorities[i] != null && (priorities[i].Type == Shots.ExplosiveTrap && used_black_immo)) { priorities[i].FailReason_SharedCooldownUsed = true; priorities[i] = null; } if (priorities[i] != null && (priorities[i].Type == Shots.FreezingTrap && used_black_immo)) { priorities[i].FailReason_SharedCooldownUsed = true; priorities[i] = null; } if (priorities[i] != null && (priorities[i].Type == Shots.FrostTrap && used_black_immo)) { priorities[i].FailReason_SharedCooldownUsed = true; priorities[i] = null; } //if (priorities[i] != null && (priorities[i].Type == Shots.Volley && used_black_immo)) { priorities[i].FailReason_SharedCooldownUsed = true; priorities[i] = null; } // Requires Multiple Targets #if RAWR3 || SILVERLIGHT if (priorities[i] != null && (priorities[i].Type == Shots.Volley && (!BossOpts.MultiTargs || (BossOpts.MultiTargs && BossOpts.MultiTargsTime == 0)))) { priorities[i].FailReason_RequiresMultiTargs = true; priorities[i] = null; } #else if (priorities[i] != null && (priorities[i].Type == Shots.Volley && (!CalcOpts.MultipleTargets || (CalcOpts.MultipleTargets && CalcOpts.MultipleTargetsPerc == 0)))) { priorities[i].FailReason_RequiresMultiTargs = true; priorities[i] = null; } #endif // shots which require talents if (priorities[i] != null && priorities[i].Type == Shots.BlackArrow && Talents.BlackArrow == 0) { priorities[i].FailReason_LackTalent = true; priorities[i] = null; } if (priorities[i] != null && priorities[i].Type == Shots.ChimearaShot && Talents.ChimeraShot == 0) { priorities[i].FailReason_LackTalent = true; priorities[i] = null; } if (priorities[i] != null && priorities[i].Type == Shots.AimedShot && Talents.AimedShot == 0) { priorities[i].FailReason_LackTalent = true; priorities[i] = null; } if (priorities[i] != null && priorities[i].Type == Shots.ExplosiveShot && Talents.ExplosiveShot == 0) { priorities[i].FailReason_LackTalent = true; priorities[i] = null; } if (priorities[i] != null && priorities[i].Type == Shots.BestialWrath && Talents.BestialWrath == 0) { priorities[i].FailReason_LackTalent = true; priorities[i] = null; } if (priorities[i] != null && priorities[i].Type == Shots.SilencingShot && Talents.SilencingShot == 0) { priorities[i].FailReason_LackTalent = true; priorities[i] = null; } if (priorities[i] != null) { priorities[i].FailReason_AlreadyUsed = true; if (priorities[i].Type == Shots.SteadyShot) { removeAll = true; } if (priorities[i].Type == Shots.ArcaneShot) { used_arcane_explosive = true; } if (priorities[i].Type == Shots.ExplosiveShot) { used_arcane_explosive = true; } if (priorities[i].Type == Shots.AimedShot) { used_aimed_multi = true; } if (priorities[i].Type == Shots.MultiShot) { used_aimed_multi = true; } if (priorities[i].Type == Shots.BlackArrow) { used_black_immo = true; } if (priorities[i].Type == Shots.ImmolationTrap) { used_black_immo = true; } if (priorities[i].Type == Shots.ExplosiveTrap) { used_black_immo = true; } if (priorities[i].Type == Shots.FreezingTrap) { used_black_immo = true; } if (priorities[i].Type == Shots.FrostTrap) { used_black_immo = true; } //if (priorities[i].Type == Shots.Volley) used_black_immo = true; } } // store some derived facts about the rotation for later use chimeraRefreshesSerpent = false; chimeraRefreshesViper = false; if (containsShot(Shots.ChimearaShot)) { if (containsShot(Shots.SerpentSting)) { chimeraRefreshesSerpent = true; } if (containsShot(Shots.ViperSting)) { chimeraRefreshesViper = true; } } }
private static bool HasTalent(HunterTalents 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); }
private Specialization GetSpecialization(HunterTalents t) { Specialization curSpecialization = Specialization.BeastMastery; if (t.HighestTree < EnumHelper.GetCount(typeof(Specialization))) curSpecialization = (Specialization)t.HighestTree; return curSpecialization; }
private StatsHunter GetTalentStats(HunterTalents talents) { StatsHunter s = new StatsHunter(); #region Specializations : Abilities/Bonuses from picking a tree. switch ((Specialization)talents.HighestTree) { // BM case Specialization.BeastMastery: { // Initimitation // TODO: Implemented in Shots/Abilities // Animal Handler s.BonusAttackPowerMultiplier += 0.25f; // Mastery: Master of Beasts // TODO: s.BonusPetDamageMultiplier += .13 + 0.0167 * Mastery break; } // MM case Specialization.Marksmanship: { // Aimed Shot // TODO: Implemented in Shots/Abilities // Artisan Quiver // TODO: Auto-attack damage + 15% // Mastery: Wild Quiver // TODO: Additional Auto-Shot 16.8% + 2.1% per Mastery break; } // SV case Specialization.Survival: { // Explosive Shot // TODO: Implemented in Shots/Abilities // Intothe Wilderness s.BonusAgilityMultiplier += .1f; // Mastery: Essence of the Viper // Bonus magic damage 8% + 1% per mastery break; } } #endregion #region Beast Master // Talent: Ferocious Inspiration s.BonusDamageMultiplier += talents.FerociousInspiration * 0.03f; #endregion #region Marksman // Talent: Trueshot Aura (Always on and part of the paperdoll numbers) s.BonusAttackPowerMultiplier += talents.TrueshotAura * 0.1f; #endregion #region Survival s.BonusStaminaMultiplier += talents.HunterVsWild * 0.05f; s.BonusHasteMultiplier += talents.Pathing * 0.01f; s.BonusAgilityMultiplier += talents.HuntingParty * 0.02f; // This conflics w/ IcyTalons and other similar buffs. s.PhysicalHaste += talents.HuntingParty * .1f; #endregion return s; }
public void validateShots(HunterTalents Talents) { // check each shot in the priority is allowed to be there. // this means removing dupes and anything after steady shot. // it also means removing shots which have already had their cooldowns used bool removeAll = false; bool used_arcane_explosive = false; bool used_aimed_multi = false; bool used_black_immo = false; for (int i = 0; i < priorities.Length; i++) { // we've already seen steadyShot - remove everything else if (priorities[i] != null && removeAll) { priorities[i].FailReason_SteadyBefore = true; priorities[i] = null; } // this shot has been used aleady if (priorities[i] != null && priorities[i].FailReason_AlreadyUsed) priorities[i] = null; // we've already used a shot which shares cooldown with this one if (priorities[i] != null && (priorities[i].Type == Shots.ArcaneShot && used_arcane_explosive)) { priorities[i].FailReason_SharedCooldownUsed = true; priorities[i] = null; } if (priorities[i] != null && (priorities[i].Type == Shots.ExplosiveShot && used_arcane_explosive)){ priorities[i].FailReason_SharedCooldownUsed = true; priorities[i] = null;} if (priorities[i] != null && (priorities[i].Type == Shots.AimedShot && used_aimed_multi)){ priorities[i].FailReason_SharedCooldownUsed = true; priorities[i] = null;} if (priorities[i] != null && (priorities[i].Type == Shots.MultiShot && used_aimed_multi)){ priorities[i].FailReason_SharedCooldownUsed = true; priorities[i] = null;} if (priorities[i] != null && (priorities[i].Type == Shots.BlackArrow && used_black_immo)){ priorities[i].FailReason_SharedCooldownUsed = true; priorities[i] = null;} if (priorities[i] != null && (priorities[i].Type == Shots.ImmolationTrap && used_black_immo)){ priorities[i].FailReason_SharedCooldownUsed = true; priorities[i] = null;} if (priorities[i] != null && (priorities[i].Type == Shots.ExplosiveTrap && used_black_immo)) { priorities[i].FailReason_SharedCooldownUsed = true; priorities[i] = null; } if (priorities[i] != null && (priorities[i].Type == Shots.FreezingTrap && used_black_immo)) { priorities[i].FailReason_SharedCooldownUsed = true; priorities[i] = null; } if (priorities[i] != null && (priorities[i].Type == Shots.IceTrap && used_black_immo)) { priorities[i].FailReason_SharedCooldownUsed = true; priorities[i] = null; } //if (priorities[i] != null && (priorities[i].Type == Shots.Volley && used_black_immo)) { priorities[i].FailReason_SharedCooldownUsed = true; priorities[i] = null; } // Requires Multiple Targets ... TODO Zhok: Rly use multi here? #if RAWR3 || RAWR4 || SILVERLIGHT if (priorities[i] != null && (priorities[i].Type == Shots.MultiShot && (!BossOpts.MultiTargs || (BossOpts.MultiTargs && BossOpts.MultiTargsTime == 0)))) { priorities[i].FailReason_RequiresMultiTargs = true; priorities[i] = null; } #else if (priorities[i] != null && (priorities[i].Type == Shots.Volley && (!CalcOpts.MultipleTargets || (CalcOpts.MultipleTargets && CalcOpts.MultipleTargetsPerc == 0)))) { priorities[i].FailReason_RequiresMultiTargs = true; priorities[i] = null; } #endif // shots which require talents if (priorities[i] != null && priorities[i].Type == Shots.BlackArrow && Talents.BlackArrow == 0){ priorities[i].FailReason_LackTalent = true; priorities[i] = null; } if (priorities[i] != null && priorities[i].Type == Shots.ChimeraShot && Talents.ChimeraShot == 0) { priorities[i].FailReason_LackTalent = true; priorities[i] = null; } #if !RAWR4 if (priorities[i] != null && priorities[i].Type == Shots.AimedShot && Talents.AimedShot == 0) { priorities[i].FailReason_LackTalent = true; priorities[i] = null; } if (priorities[i] != null && priorities[i].Type == Shots.ExplosiveShot && Talents.ExplosiveShot == 0){priorities[i].FailReason_LackTalent = true; priorities[i] = null;} #endif if (priorities[i] != null && priorities[i].Type == Shots.BestialWrath && Talents.BestialWrath == 0) { priorities[i].FailReason_LackTalent = true; priorities[i] = null; } if (priorities[i] != null && priorities[i].Type == Shots.SilencingShot && Talents.SilencingShot == 0) { priorities[i].FailReason_LackTalent = true; priorities[i] = null; } if (priorities[i] != null) { priorities[i].FailReason_AlreadyUsed = true; if (priorities[i].Type == Shots.SteadyShot) removeAll = true; if (priorities[i].Type == Shots.ArcaneShot) used_arcane_explosive = true; if (priorities[i].Type == Shots.ExplosiveShot) used_arcane_explosive = true; if (priorities[i].Type == Shots.AimedShot) used_aimed_multi = true; if (priorities[i].Type == Shots.MultiShot) used_aimed_multi = true; if (priorities[i].Type == Shots.BlackArrow) used_black_immo = true; if (priorities[i].Type == Shots.ImmolationTrap) used_black_immo = true; if (priorities[i].Type == Shots.ExplosiveTrap) used_black_immo = true; if (priorities[i].Type == Shots.FreezingTrap) used_black_immo = true; if (priorities[i].Type == Shots.IceTrap) used_black_immo = true; //if (priorities[i].Type == Shots.Volley) used_black_immo = true; } } // store some derived facts about the rotation for later use chimeraRefreshesSerpent = false; chimeraRefreshesViper = false; if (containsShot(Shots.ChimeraShot)) { if (containsShot(Shots.SerpentSting)) chimeraRefreshesSerpent = true; } }
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; }