public Pet(StatsDK dkstats, DeathKnightTalents t, BossOptions bo, Presence p) { m_BO = bo; m_DKStats = dkstats; m_Talents = t; m_Presence = p; AccumulateStats(); }
/// <summary> /// Use the Talent spec to determine which type of rotation we should be looking towards. /// </summary> /// <param name="t">DeathKnightTalents</param> /// <returns>Enum "Type" [Custom, Blood, Frost, Unholy, Unknown]</returns> public Type GetRotationType(DeathKnightTalents t) { curRotationType = Type.Custom; if (t.HighestTree == (int)TalentTrees.Blood) { // Blood curRotationType = Rotation.Type.Blood; } else if (t.HighestTree == (int)TalentTrees.Frost) { // Frost curRotationType = Rotation.Type.Frost; } if (t.HighestTree == (int)TalentTrees.Unholy) { // Unholy curRotationType = Rotation.Type.Unholy; } return curRotationType; }
/// <summary> /// Get the type of rotation we should be using based on talents. /// </summary> /// <param name="t">DeathKnight Talents to evaluate.</param> public void GetRotationByTalents(DeathKnightTalents t) { if (curRotationType == Type.Custom) { managedRP = false; // if talents are all 0, then setup a basic rotation: curRotationType = Type.Custom; // we're going to just spam a very basic rotation. // IT-PS-BS-BS-DS-DS-RP // Need to find a way to actually implement this properly. numDisease = 2f; diseaseUptime = 100f; IcyTouch = 2f; PlagueStrike = 2f; BloodStrike = 2f; Obliterate = 0f; DeathStrike = 2f; RuneStrike = 3f; Pestilence = 0f; DeathCoil = 2f; ScourgeStrike = 0f; FrostStrike = 0f; HowlingBlast = 0f; HeartStrike = 0f; curRotationDuration = 15f; } const int indexBlood = 0; // start index of Blood Talents. const int indexFrost = 28; // start index of Frost Talents. const int indexUnholy = indexFrost + 29; // start index of Unholy Talents. int[] TalentCounter = new int[4]; int index = indexBlood; foreach (int i in t.Data) { if (i > 0) { // Blood if (index < indexFrost) { TalentCounter[(int)Type.Blood]++; } // Frost else if ((indexFrost <= index) && (index < indexUnholy)) { TalentCounter[(int)Type.Frost]++; } // Unholy else if (index >= indexUnholy) { TalentCounter[(int)Type.Unholy]++; } } index++; } if ((TalentCounter[(int)Type.Blood] > TalentCounter[(int)Type.Frost]) && (TalentCounter[(int)Type.Blood] > TalentCounter[(int)Type.Unholy])) { // Blood curRotationType = Type.Blood; } else if ((TalentCounter[(int)Type.Frost] > TalentCounter[(int)Type.Blood]) && (TalentCounter[(int)Type.Frost] > TalentCounter[(int)Type.Unholy])) { // Frost curRotationType = Type.Frost; } else if ((TalentCounter[(int)Type.Unholy] > TalentCounter[(int)Type.Frost]) && (TalentCounter[(int)Type.Unholy] > TalentCounter[(int)Type.Blood])) { // Unholy curRotationType = Type.Unholy; } managedRP = true; #region Frost Rotations if (curRotationType == Type.Frost) { numDisease = 2f; diseaseUptime = 100f; IcyTouch = 2f; PlagueStrike = 2f; ScourgeStrike = 0f; FrostStrike = 0f; if (t.FrostStrike > 0) { DeathCoil = 0f; FrostStrike = 2f; } else { DeathCoil = 2f; FrostStrike = 0f; } HowlingBlast = 0f; Obliterate = 3f; BloodStrike = 2f; HeartStrike = 0f; DeathStrike = 0f; RuneStrike = 3f; Pestilence = 0f; curRotationDuration = 15f; if (t.GlyphofHowlingBlast && t.HowlingBlast > 0) { // Single Disease Glyphed HB rotation // Means that we start w/ HB for the FF hit, and factor in PS later, while HB is on CD. numDisease = 1f; IcyTouch = 1f; PlagueStrike = 1f; HowlingBlast = 1f; } if (t.Rime > 0 && t.HowlingBlast > 0) { // Additional HB proc based on Rime. HowlingBlast += .5f; } } #endregion #region Blood Rotations else if (curRotationType == Type.Blood) { numDisease = 2f; diseaseUptime = 100f; DeathCoil = 2f; IcyTouch = 1f; PlagueStrike = 1f; ScourgeStrike = 0f; FrostStrike = 0f; HowlingBlast = 0f; Obliterate = 0f; DeathStrike = 2f; if (HeartStrike > 0) { HeartStrike = 6f; BloodStrike = 0f; } else { HeartStrike = 0f; BloodStrike = 6f; } Pestilence = 0f; RuneStrike = 2f; curRotationDuration = 15f; } #endregion #region Unholy Rotations else if (curRotationType == Type.Unholy) // UnHoly { numDisease = 3f; diseaseUptime = 100f; DeathCoil = 2f; IcyTouch = 1f; PlagueStrike = 1f; ScourgeStrike = 0f; if (t.ScourgeStrike > 0) { ScourgeStrike = 4f; } else { DeathStrike = 4f; } FrostStrike = 0f; HowlingBlast = 0f; Obliterate = 0f; BloodStrike = 2f; HeartStrike = 0f; curRotationDuration = 20f; RuneStrike = 2f; Pestilence = 0f; } #endregion }
public DRW(CombatTable combatTable, CharacterCalculationsDPSDK calcs, CalculationOptionsDPSDK calcOpts, Stats stats, Character character, DeathKnightTalents talents) { bool DW = false; float dpsWhite = 0f; float dpsBCB = 0f; float dpsNecrosis = 0f; float dpsDeathCoil = 0f; float dpsIcyTouch = 0f; float dpsPlagueStrike = 0f; float dpsFrostFever = 0f; float dpsBloodPlague = 0f; float dpsDeathStrike = 0f; float dpsHeartStrike = 0f; float dpsWPFromFF = 0f; float dpsWPFromBP = 0f; float dpsWhiteMinusGlancing = 0f; float dpsWhiteBeforeArmor = 0f; float IcyTouchAPMult = 0.1f; float FrostFeverAPMult = 0.055f; float BloodPlagueAPMult = 0.055f; float DeathCoilAPMult = 0.15f; float OHMult = 0.5f; int targetLevel = calcOpts.TargetLevel; float arpBuffs = talents.BloodGorged * 2f / 100; float mitigation = StatConversion.GetArmorDamageReduction(character.Level, calcOpts.BossArmor, stats.ArmorPenetration, arpBuffs, stats.ArmorPenetrationRating); mitigation = 1 - mitigation; float MHDPS = 0f, OHDPS = 0f; #region White Dmg { #region Main Hand { float dpsMHglancing = (StatConversion.WHITE_GLANCE_CHANCE_CAP[targetLevel - 80] * combatTable.MH.DPS) * 0.7f; float dpsMHBeforeArmor = ((combatTable.MH.DPS * (1f - calcs.AvoidedAttacks - StatConversion.WHITE_GLANCE_CHANCE_CAP[targetLevel - 80])) * (1f + combatTable.physCrits)) + dpsMHglancing; dpsWhiteMinusGlancing = dpsMHBeforeArmor - dpsMHglancing; dpsWhiteBeforeArmor = dpsMHBeforeArmor; MHDPS = dpsMHBeforeArmor * mitigation; } #endregion #region Off Hand if (DW || (character.MainHand == null && character.OffHand != null)) { float dpsOHglancing = (StatConversion.WHITE_GLANCE_CHANCE_CAP[targetLevel - 80] * combatTable.OH.DPS) * 0.7f; float dpsOHBeforeArmor = ((combatTable.OH.DPS * (1f - calcs.AvoidedAttacks - StatConversion.WHITE_GLANCE_CHANCE_CAP[targetLevel - 80])) * (1f + combatTable.physCrits)) + dpsOHglancing; dpsOHBeforeArmor *= OHMult; dpsWhiteMinusGlancing += dpsOHBeforeArmor - dpsOHglancing; dpsWhiteBeforeArmor += dpsOHBeforeArmor; OHDPS = dpsOHBeforeArmor * mitigation; } #endregion dpsWhite = MHDPS + OHDPS; } #endregion #region Necrosis { dpsNecrosis = dpsWhiteMinusGlancing * (.04f * (float)talents.Necrosis); // doesn't proc off Glancings } #endregion #region Blood Caked Blade { float dpsMHBCB = 0f; if (combatTable.MH.damage != 0) { float MHBCBDmg = (float)(combatTable.MH.damage * (.25f + .125f * calcOpts.rotation.AvgDiseaseMult)); dpsMHBCB = MHBCBDmg / combatTable.MH.hastedSpeed; } dpsBCB = dpsMHBCB; dpsBCB *= .1f * (float)talents.BloodCakedBlade; } #endregion #region Death Coil { if (calcOpts.rotation.DeathCoil > 0f) { float DCCD = 1; float DCDmg = 443f + (DeathCoilAPMult * stats.AttackPower); dpsDeathCoil = DCDmg / DCCD; float DCCritDmgMult = .5f * (2f + stats.BonusCritMultiplier); float DCCrit = 1f + ((combatTable.spellCrits + stats.BonusDeathCoilCrit) * DCCritDmgMult); dpsDeathCoil *= DCCrit; dpsDeathCoil *= 1f + (.05f * (float)talents.Morbidity); } } #endregion #region Icy Touch { if (calcOpts.rotation.IcyTouch > 0f) { float ITCD = 1; float ITDmg = 236f + (IcyTouchAPMult * stats.AttackPower) + stats.BonusIcyTouchDamage; ITDmg *= 1f + .1f * (float)talents.ImprovedIcyTouch; dpsIcyTouch = ITDmg / ITCD; float ITCritDmgMult = .5f * (2f + stats.CritBonusDamage + stats.BonusCritMultiplier); float ITCrit = 1f + (Math.Min((combatTable.spellCrits + (.05f * (float)talents.Rime)), 1f) * ITCritDmgMult); dpsIcyTouch *= ITCrit; } } #endregion #region Plague Strike { if (calcOpts.rotation.PlagueStrike > 0f) { float PSCD = 1; float PSDmg = (combatTable.MH.baseDamage + ((stats.AttackPower / 14f) * combatTable.normalizationFactor)) * 0.5f + 189f; dpsPlagueStrike = PSDmg / PSCD; float PSCritDmgMult = 1f + (.15f * (float)talents.ViciousStrikes) + stats.BonusCritMultiplier; float PSCrit = 1f + ((combatTable.physCrits + (.03f * (float)talents.ViciousStrikes) + stats.BonusPlagueStrikeCrit) * PSCritDmgMult); dpsPlagueStrike *= PSCrit; dpsPlagueStrike *= 1f + (.1f * (float)talents.Outbreak); } } #endregion #region Frost Fever { if (calcOpts.rotation.IcyTouch > 0f || (talents.GlyphofHowlingBlast && calcOpts.rotation.HowlingBlast > 0f) || (talents.GlyphofDisease && calcOpts.rotation.Pestilence > 0f)) { float FFDmg = FrostFeverAPMult * stats.AttackPower + 25.6f; dpsFrostFever = FFDmg; dpsFrostFever *= 1.15f; // Patch 3.2: Diseases hit 15% harder. dpsWPFromFF = dpsFrostFever * combatTable.physCrits; } } #endregion #region Blood Plague { if (calcOpts.rotation.PlagueStrike > 0f || talents.GlyphofDisease) { float BPDmg = BloodPlagueAPMult * stats.AttackPower + 31.1f; dpsBloodPlague = BPDmg; dpsBloodPlague *= 1.15f; // Patch 3.2: Diseases hit 15% harder. dpsWPFromBP = dpsBloodPlague * combatTable.physCrits; } } #endregion #region Death Strike { if (calcOpts.rotation.DeathStrike > 0f) { float DSCD = 1; // TODO: This should be changed to make use of the new glyph stats: float DSDmg = ((combatTable.MH.baseDamage + ((stats.AttackPower / 14f) * combatTable.normalizationFactor)) * 0.75f) + 222.75f; DSDmg *= 1f + 0.15f * (float)talents.ImprovedDeathStrike; dpsDeathStrike = DSDmg / DSCD; float DSCritDmgMult = 1f + (.15f * (float)talents.MightOfMograine) + stats.BonusCritMultiplier; float DSCrit = 1f + ((combatTable.physCrits + (.03f * (float)talents.ImprovedDeathStrike) + stats.BonusDeathStrikeCrit) * DSCritDmgMult); dpsDeathStrike *= DSCrit; } } #endregion #region Heart Strike { if (talents.HeartStrike > 0 && calcOpts.rotation.HeartStrike > 0f) { float HSCD = 1; float HSDmg = ((combatTable.MH.baseDamage + ((stats.AttackPower / 14f) * combatTable.normalizationFactor)) * 0.5f) + 368f; HSDmg *= 1f + 0.1f * (float)calcOpts.rotation.AvgDiseaseMult * (1f + stats.BonusPerDiseaseHeartStrikeDamage); dpsHeartStrike = HSDmg / HSCD; //float HSCrit = 1f + combatTable.physCrits + ( .03f * (float)talents.Subversion ); float HSCritDmgMult = 1f + (.15f * (float)talents.MightOfMograine) + stats.BonusCritMultiplier; float HSCrit = 1f + ((combatTable.physCrits + (.03f * (float)talents.Subversion)) * HSCritDmgMult); dpsHeartStrike = (dpsHeartStrike) * HSCrit; dpsHeartStrike *= 1f + (.15f * (float)talents.BloodyStrikes); } } #endregion float BCBMult = 1f; float BloodPlagueMult = 1f; float DeathCoilMult = 1f; float FrostFeverMult = 1f; float HeartStrikeMult = 1f; float IcyTouchMult = 1f; float NecrosisMult = 1f; float DeathStrikeMult = 1f; float PlagueStrikeMult = 1f; float WhiteMult = 1f; float spellPowerMult = 1f + stats.BonusSpellPowerMultiplier; float frostSpellPowerMult = 1f + stats.BonusSpellPowerMultiplier + Math.Max((stats.BonusFrostDamageMultiplier - stats.BonusShadowDamageMultiplier), 0f); float partialResist = 0.94f; float physPowerMult = 1f; #region Apply Physical Mitigation { float physMit = mitigation; physMit *= 1f + (!DW ? .02f * talents.TwoHandedWeaponSpecialization : 0f); dpsBCB *= physMit; dpsHeartStrike *= physMit; dpsDeathStrike *= physMit; dpsPlagueStrike *= physMit; WhiteMult += physPowerMult - 1f; BCBMult += physPowerMult - 1f; HeartStrikeMult += physPowerMult - 1f; DeathStrikeMult += physPowerMult - 1f; PlagueStrikeMult += physPowerMult - 1f; } #endregion #region Apply Magical Mitigation { // some of this applies to necrosis, I wonder if it is ever accounted for float magicMit = partialResist /** combatTable.spellResist*/; // magicMit = 1f - magicMit; dpsNecrosis *= magicMit; dpsBloodPlague *= magicMit; dpsDeathCoil *= magicMit * (1f - combatTable.spellResist); dpsFrostFever *= magicMit; dpsIcyTouch *= magicMit; NecrosisMult += spellPowerMult - 1f; BloodPlagueMult += spellPowerMult - 1f; DeathCoilMult += spellPowerMult - 1f; FrostFeverMult += frostSpellPowerMult - 1f; IcyTouchMult += frostSpellPowerMult - 1f; } #endregion #region Apply Multi-Ability Talent Multipliers { float BloodyVengeanceMult = .03f * (float)talents.BloodyVengeance; BCBMult *= 1 + BloodyVengeanceMult; HeartStrikeMult *= 1 + BloodyVengeanceMult; DeathStrikeMult *= 1 + BloodyVengeanceMult; PlagueStrikeMult *= 1 + BloodyVengeanceMult; WhiteMult *= 1 + BloodyVengeanceMult; float HysteriaCoeff = .2f / 2f; // current uptime is 50% for now float HysteriaMult = HysteriaCoeff * (float)talents.Hysteria; BCBMult *= 1 + HysteriaMult; HeartStrikeMult *= 1 + HysteriaMult; DeathStrikeMult *= 1 + HysteriaMult; PlagueStrikeMult *= 1 + HysteriaMult; WhiteMult *= 1 + HysteriaMult; float BlackIceMult = .02f * (float)talents.BlackIce; FrostFeverMult *= 1 + BlackIceMult; IcyTouchMult *= 1 + BlackIceMult; DeathCoilMult *= 1 + BlackIceMult; BloodPlagueMult *= 1 + BlackIceMult; float CryptFeverMult = .1f * (float)talents.CryptFever; float CryptFeverBuff = stats.BonusDiseaseDamageMultiplier; CryptFeverMult = Math.Max(CryptFeverMult, CryptFeverBuff); FrostFeverMult *= 1 + CryptFeverMult; BloodPlagueMult *= 1 + CryptFeverMult; } #endregion dpsDancingRuneWeapon = dpsWhite * WhiteMult * 17f + dpsBCB * BCBMult * 17f + dpsNecrosis * NecrosisMult * 17f + dpsDeathCoil * DeathCoilMult + dpsIcyTouch * IcyTouchMult + dpsPlagueStrike * PlagueStrikeMult + dpsFrostFever * (5f + talents.Epidemic) * FrostFeverMult + dpsBloodPlague * (5f + talents.Epidemic) * BloodPlagueMult + dpsDeathStrike * DeathStrikeMult * (talents.GlyphofDancingRuneWeapon ? 1f : 0f) + dpsHeartStrike * HeartStrikeMult * (5f + (talents.GlyphofDancingRuneWeapon ? 2f : 0f)); dpsDancingRuneWeapon *= 0.5f; }
public Disease(Character c, Stats s, CalculationOptionsDPSDK Calcopts, CombatTable table, DeathKnightTalents Talents) { character = c; stats = s; calcOpts = Calcopts; combatTable = table; talents = Talents; GcdType = GCDType.None; Runes = RunesUsed.None; Name = "A Disease"; }
public BloodBoil(Character c, Stats s, CalculationOptionsDPSDK CalcOpts, CombatTable table, DeathKnightTalents Talents) { character = c; stats = s; calcOpts = CalcOpts; combatTable = table; talents = Talents; GcdType = GCDType.Spell; Runes = RunesUsed.Blood; Name = "Blood Boil"; }
private void AccumulateGlyphStats(Stats s, DeathKnightTalents t) { if (t.GlyphofBoneShield) s.MovementSpeed = (float)Math.Max(s.MovementSpeed, 1.15f); }
public HowlingBlast(Character c, Stats s, CalculationOptionsDPSDK CalcOpts, CombatTable table, DeathKnightTalents Talents) { character = c; stats = s; calcOpts = CalcOpts; combatTable = table; talents = Talents; GcdType = GCDType.Spell; Runes = RunesUsed.UnholyFrost; Name = "Howling Blast"; }
public RotationGene(int availableBlood, int availableFrost, int availableUnholy, DeathKnightTalents talents) { Rotation = new Rotation(); Rotation.curRotationType = Rotation.Type.Custom; Rotation.ManagedRP = true; Random rand = new Random((int)(CalculationsDPSDK.hawut + 0.5d)); CalculationsDPSDK.hawut -= rand.NextDouble() * DateTime.Now.ToOADate() / 1000000; double nextRand; Rotation.presence = (rand.NextDouble() > .5 ? CalculationOptionsDPSDK.Presence.Blood : CalculationOptionsDPSDK.Presence.Unholy); nextRand = rand.NextDouble(); #region blood runes if (nextRand > 0.5d && availableBlood > 0d) { Rotation.Pestilence = 1; availableBlood--; } nextRand = rand.NextDouble(); if (nextRand < 1d / 3d) { Rotation.BloodStrike = availableBlood; Rotation.HeartStrike = 0; Rotation.BloodBoil = 0; } else if (nextRand < 2d / 3d) { Rotation.BloodStrike = 0; Rotation.HeartStrike = availableBlood; Rotation.BloodBoil = 0; } else { Rotation.BloodStrike = 0; Rotation.HeartStrike = 0; Rotation.BloodBoil = availableBlood; } #endregion #region frost and unholy runes nextRand = rand.NextDouble(); if (nextRand > 0.5d && availableFrost > 0d) { Rotation.IcyTouch = 1; availableFrost--; } else { Rotation.IcyTouch = 0; } nextRand = rand.NextDouble(); if (nextRand > 0.5d && availableUnholy > 0d) { Rotation.PlagueStrike = 1; availableUnholy--; } else { Rotation.PlagueStrike = 0; } nextRand = rand.NextDouble(); if (nextRand < .25d) { Rotation.DeathStrike = (availableUnholy + availableFrost) / 2f; Rotation.ScourgeStrike = 0; Rotation.Obliterate = 0; } else if (nextRand < .5d) { Rotation.DeathStrike = 0; Rotation.ScourgeStrike = (availableFrost + availableUnholy) / 2f; Rotation.Obliterate = 0; } else if (nextRand < .75d) { Rotation.DeathStrike = 0; Rotation.ScourgeStrike = 0; Rotation.Obliterate = (availableUnholy + availableFrost) / 2f; } else { Rotation.DeathStrike = 0; Rotation.ScourgeStrike = 0; Rotation.Obliterate = 0; Rotation.PlagueStrike += availableUnholy; Rotation.IcyTouch += availableFrost; } #endregion Rotation.AvgDiseaseMult = (Rotation.IcyTouch > 0 ? 1 : 0) + (Rotation.PlagueStrike > 0 ? 1 : 0); if (talents.CryptFever > 0 && (Rotation.IcyTouch > 0 || Rotation.PlagueStrike > 0)) { Rotation.AvgDiseaseMult++; } double minDuration = availableBlood + availableFrost + availableUnholy; minDuration /= 6; minDuration *= 10 - (Rotation.presence == CalculationOptionsDPSDK.Presence.Unholy ? talents.ImprovedUnholyPresence * .5 : 0); }
public IcyTouch(Character c, Stats s, CalculationOptionsDPSDK CalcOpts, CombatTable table, DeathKnightTalents Talents) { character = c; stats = s; calcOpts = CalcOpts; combatTable = table; GcdType = GCDType.Spell; Runes = RunesUsed.Frost; talents = Talents; Name = "Icy Touch"; }
public Weapon (Item i, Stats stats, CalculationOptionsDPSDK calcOpts, BossOptions bossOpts, DeathKnightTalents talents, float expertise, CharacterSlot hand) { if (stats == null || calcOpts == null || !(hand == CharacterSlot.MainHand || hand == CharacterSlot.OffHand )) { return; } if (i == null) { i = new Item(); i.Speed = 2.0f; i.MinDamage = 0; i.MaxDamage = 0; } else { twohander = (i.Slot == ItemSlot.TwoHand); } effectiveExpertise = expertise; if (i == null) { return; } baseSpeed = i.Speed; baseDamage = (float)(i.MinDamage + i.MaxDamage) / 2f + stats.WeaponDamage; #region Attack Speed { hastedSpeed = baseSpeed / (1 + stats.PhysicalHaste); } #endregion #region Dodge { float baseDodged = StatConversion.WHITE_DODGE_CHANCE_CAP[bossOpts.Level - 85]; chanceDodged = baseDodged - StatConversion.GetDodgeParryReducFromExpertise(effectiveExpertise); chanceDodged = Math.Min(Math.Max(chanceDodged, 0f), baseDodged); } #endregion #region Parry { float baseParried = StatConversion.WHITE_PARRY_CHANCE_CAP[bossOpts.Level - 85]; chanceParried = baseParried - StatConversion.GetDodgeParryReducFromExpertise(effectiveExpertise); chanceParried = Math.Min(Math.Max(chanceParried, 0f), baseParried); } #endregion #region Miss { float baseMissed = StatConversion.WHITE_MISS_CHANCE_CAP[bossOpts.Level - 85]; if (!twohander) baseMissed = StatConversion.WHITE_MISS_CHANCE_CAP_DW[bossOpts.Level - 85]; chanceMissed = baseMissed - stats.PhysicalHit; chanceMissed = Math.Min(Math.Max(chanceMissed, 0f), baseMissed); } #endregion #if DEBUG if (chanceDodged < 0 || chanceParried < 0 || chanceMissed < 0) throw new Exception("Chance to hit out of range."); #endif #region White Damage { // White damage per hit. Basic white hits are use elsewhere. float baseDPS = baseDamage / baseSpeed; damage = (baseDPS + (stats.AttackPower / 14.0f)) * baseSpeed; DPS = damage / hastedSpeed; if (hand == CharacterSlot.OffHand) { damage /= 2; DPS /= 2; if (talents.NervesOfColdSteel > 0) { damage *= 1f + (.25f * (talents.NervesOfColdSteel / 3f)); DPS *= 1f + (.25f * (talents.NervesOfColdSteel / 3f)); ; } } } #endregion }
TalentsBase parse_talents_wowhead(CharacterClass characterclass, string talent_string) { // wowhead format: [tree_1]Z[tree_2]Z[tree_3] where the trees are character encodings // each character expands to a pair of numbers [0-5][0-5] // unused deeper talents are simply left blank instead of filling up the string with zero-zero encodings bool hasGlyphs = talent_string.Contains(":"); int[] talent_trees = new int[] { 0, 0, 0 }; int[] glyph_trees = new int[] { 3, 3, 3 }; switch (characterclass) { case CharacterClass.Warrior: { WarriorTalents talents = new WarriorTalents(); talent_trees = talents.TreeLengths; break; } case CharacterClass.Paladin: { PaladinTalents talents = new PaladinTalents(); talent_trees = talents.TreeLengths; break; } case CharacterClass.Hunter: { HunterTalents talents = new HunterTalents(); talent_trees = talents.TreeLengths; break; } case CharacterClass.Rogue: { RogueTalents talents = new RogueTalents(); talent_trees = talents.TreeLengths; break; } case CharacterClass.Priest: { PriestTalents talents = new PriestTalents(); talent_trees = talents.TreeLengths; break; } case CharacterClass.DeathKnight: { DeathKnightTalents talents = new DeathKnightTalents(); talent_trees = talents.TreeLengths; break; } case CharacterClass.Shaman: { ShamanTalents talents = new ShamanTalents(); talent_trees = talents.TreeLengths; break; } case CharacterClass.Mage: { MageTalents talents = new MageTalents(); talent_trees = talents.TreeLengths; break; } case CharacterClass.Warlock: { WarlockTalents talents = new WarlockTalents(); talent_trees = talents.TreeLengths; break; } case CharacterClass.Druid: { DruidTalents talents = new DruidTalents(); talent_trees = talents.TreeLengths; break; } } int[] encoding = new int[talent_trees[0] + talent_trees[1] + talent_trees[2]]; int[][] glyphEncoding = new int[][] { new int[3], new int[3], new int[3], }; int[] tree_count = new int[] { 0, 0, 0 }; int[] glyph_count = new int[] { 0, 0, 0 }; int tree = 0; int count = 0; #region Talents parsing for (int i=1; i < talent_string.Length; i++) { if (tree >= 3) { //sim -> errorf( "Player %s has malformed wowhead talent string. Too many talent trees specified.\n", name() ); return null; } char c = talent_string[i]; if (c == ':') break; // glyph encoding follows if (c == 'Z') { count = 0; for (int j = 0; j <= tree; j++) { count += talent_trees[tree]; } tree++; continue; } decode_t decode = null; for (int j=0; decoding[j].key != '\0' && decode==null; j++) { if (decoding[j].key == c) { decode = decoding[j]; } } if (decode == null) { //sim -> errorf( "Player %s has malformed wowhead talent string. Translation for '%c' unknown.\n", name(), c ); return null; } encoding[count++] += decode.first - '0'; tree_count[tree] += 1; if (tree_count[tree] < talent_trees[tree]) { encoding[count++] += decode.second - '0'; tree_count[tree] += 1; } if (tree_count[tree] >= talent_trees[tree]) { tree++; } } #endregion #region Glyphs Parsing #region Notes /* This is totally crappy.... * Glyphs do not follow the same parsing rules. If you apply what was there for talents directly * to glyphs you get 1202032213120011050000000000000000. Which should only have 1's and 0's * * * Warriors: As I'm checking glyphs, here's what I get: * == PRIMES == * Link decode id Name * * http://www.wowhead.com/talent#L:0 00 43415 58388 Devastate * * http://www.wowhead.com/talent#L:z 01 43416 58367 Bloodthirst * * http://www.wowhead.com/talent#L:M 02 43421 58368 Mortal Strike * * http://www.wowhead.com/talent#L:c 03 43422 58386 Overpower * * http://www.wowhead.com/talent#L:m 04 43423 58385 Slam * * http://www.wowhead.com/talent#L:V 05 43424 58364 Revenge * * http://www.wowhead.com/talent#L:o 10 43425 58375 Shield Slam * * http://www.wowhead.com/talent#L:k 11 43432 58370 Raging Blow * * http://www.wowhead.com/talent#L:R 12 45790 63324 Bladestorm * == MAJORS == * * http://www.wowhead.com/talent#L:0 00 43397 Long Charge * * http://www.wowhead.com/talent#L:z 01 43399 Thunder Clap * * http://www.wowhead.com/talent#L:M 02 43413 Rapid Charge * * http://www.wowhead.com/talent#L:c 03 43414 Cleaving * * http://www.wowhead.com/talent#L:m 04 43417 Piercing Howl * * http://www.wowhead.com/talent#L:V 05 43418 Heroic Throw * * http://www.wowhead.com/talent#L:o 10 43419 Intervene * * http://www.wowhead.com/talent#L:k 11 43427 Sunder Armor * * http://www.wowhead.com/talent#L:R 12 43428 Sweeping Strikes * * http://www.wowhead.com/talent#L:s 13 43430 Resonating Power * * http://www.wowhead.com/talent#L:a 14 43431 Victory Rush * * http://www.wowhead.com/talent#L:q 15 45792 Shockwave * * http://www.wowhead.com/talent#L:b 20 45795 Spell Reflection * * http://www.wowhead.com/talent#L:d 21 45797 Shield Wall * * http://www.wowhead.com/talent#L:r 22 63481 Colossus Smash * * http://www.wowhead.com/talent#L:f 23 67482 Intercept * * http://www.wowhead.com/talent#L:w 24 67483 Death Wish * == MINORS == * * http://www.wowhead.com/talent#L:0 00 43395 Battle * * http://www.wowhead.com/talent#L:z 01 43396 Berserker Rage * * http://www.wowhead.com/talent#L:M 02 43398 Demoralizing Shout * * http://www.wowhead.com/talent#L:c 03 43400 Enduring Victory * * http://www.wowhead.com/talent#L:m 04 43412 Bloody Healing * * http://www.wowhead.com/talent#L:V 05 45793 Furious Sundering * * http://www.wowhead.com/talent#L:o 10 45794 Intimidating Shout * * http://www.wowhead.com/talent#L:k 11 49084 Command * * So http://www.wowhead.com/talent#LubcfRMRurkcrZ0b:RMcrsR0kV would mean: * Prime: Bladestorm, Mortal Strike, Overpower * Major: Colossus Smash, Resonating Power, Sweeping Strikes * Minor: Battle, Command, Furious Sundering * Which is correct, that's what we come out to */ #endregion tree = 0; count = 0; if (hasGlyphs) { for (int i=talent_string.IndexOf(":")+1; i < talent_string.Length; i++) { if (tree >= 3) { //sim -> errorf( "Player %s has malformed wowhead talent string. Too many talent trees specified.\n", name() ); return null; } char c = talent_string[i]; if (c == 'Z') { count = 0; /*for (int j = 0; j <= tree; j++) { count += glyph_trees[tree]; }*/ tree++; continue; } decode_t decode = null; for (int j=0; decoding[j].key != '\0' && decode==null; j++) { if (decoding[j].key == c) { decode = decoding[j]; } } if (decode == null) { //sim -> errorf( "Player %s has malformed wowhead talent string. Translation for '%c' unknown.\n", name(), c ); return null; } glyphEncoding[tree][count++] += (decode.first - '0') * 10 + decode.second - '0'; glyph_count[tree] += 1; if (glyph_count[tree] >= (glyph_trees[tree])) { tree++; count = 0; } } } #endregion string newtalentstring = ""; foreach (int i in encoding) { newtalentstring += i.ToString(); } if (hasGlyphs) { //newtalentstring += "."; //for (int t = 0; t < 3; t++) { // foreach (int i in glyphEncoding[t]) { newtalentstring += i.ToString(); } //} } switch (characterclass) { case CharacterClass.Warrior: { return new WarriorTalents(newtalentstring, hasGlyphs ? glyphEncoding : null); } case CharacterClass.Paladin: { return new PaladinTalents(newtalentstring, hasGlyphs ? glyphEncoding : null); } case CharacterClass.Hunter: { return new HunterTalents(newtalentstring, hasGlyphs ? glyphEncoding : null); } case CharacterClass.Rogue: { return new RogueTalents(newtalentstring, hasGlyphs ? glyphEncoding : null); } case CharacterClass.Priest: { return new PriestTalents(newtalentstring, hasGlyphs ? glyphEncoding : null); } case CharacterClass.DeathKnight: { return new DeathKnightTalents(newtalentstring, hasGlyphs ? glyphEncoding : null); } case CharacterClass.Shaman: { return new ShamanTalents(newtalentstring, hasGlyphs ? glyphEncoding : null); } case CharacterClass.Mage: { return new MageTalents(newtalentstring, hasGlyphs ? glyphEncoding : null); } case CharacterClass.Warlock: { return new WarlockTalents(newtalentstring, hasGlyphs ? glyphEncoding : null); } case CharacterClass.Druid: { return new DruidTalents(newtalentstring, hasGlyphs ? glyphEncoding : null); } } return null; }
public static Rotation.Type GetSpec(DeathKnightTalents t) { return (Rotation.Type)t.HighestTree + 1; }
public Gargoyle(StatsDK dkstats, DeathKnightTalents t, BossOptions bo, Presence p) { m_BO = bo; m_DKStats = dkstats; m_Talents = t; m_Presence = p; AccumulateStats(); DamageType = ItemDamageType.Physical; }
public Obliterate(Character c, Stats s, CalculationOptionsDPSDK CalcOpts, CombatTable table, DeathKnightTalents Talents) { character = c; stats = s; calcOpts = CalcOpts; combatTable = table; talents = Talents; GcdType = GCDType.Melee; Runes = RunesUsed.UnholyFrost; Name = "Obliterate"; }
public FrostCycle(Character c, CombatTable t, Stats s, CalculationOptionsDPSDK opts, AbilityHandler a) { BP = 0; FF = 0; currentTime = 0; GCDTime = 0; occurence = new Rotation(); //occurence.presence = calcOpts.rotation.presence; occurence.setRotation(Rotation.Type.Custom); occurence.NumDisease = 0f; occurence.DiseaseUptime = 100f; occurence.DeathCoil = 0f; occurence.IcyTouch = 0f; occurence.PlagueStrike = 0f; occurence.ScourgeStrike = 0f; occurence.ManagedRP = false; occurence.FrostStrike = 0f; occurence.HowlingBlast = 0f; occurence.Obliterate = 0f; occurence.BloodStrike = 0f; occurence.HeartStrike = 0f; occurence.DancingRuneWeapon = 0f; occurence.Horn = 0f; occurence.GargoyleDuration = 30f; occurence.DeathStrike = 0f; occurence.GhoulFrenzy = 0f; occurence.Pestilence = 0f; occurence.CurRotationDuration = 60f; KMApplicationProbability = 0; RP = 0; FrostRune1 = 0; FrostRune2 = 0; UnholyRune1 = 0; UnholyRune2 = 0; BloodRune1 = 0; BloodRune2 = 0; DeathRune1 = 100 * 60 * 1000 + 1; DeathRune2 = 100 * 60 * 1000 + 1; horn = 0; abilities = a; character = c; combatTable = t; stats = s; talents = c.DeathKnightTalents; KMChance = (1 / (60 / t.MH.baseSpeed)) * talents.KillingMachine * (1 - combatTable.totalMHMiss); calcOpts = opts; if (opts.CurrentPresence == CalculationOptionsDPSDK.Presence.Unholy) { meleeGCD = 1000; spellGCD = 1000; } else { meleeGCD = 1500; spellGCD = (int)(1500 / ((1 + (StatConversion.GetHasteFromRating(stats.HasteRating, CharacterClass.DeathKnight))) * (1d + stats.SpellHaste))); spellGCD = Math.Max(spellGCD, 1000); } PhysicalGCDMultiplier = (1 / (1 - (combatTable.dodgedSpecial + combatTable.missedSpecial))); SpellGCDMultiplier = (1 / (1 - (combatTable.spellResist))); MHFrequency = (int)(combatTable.MH.hastedSpeed * 1000); RimeChance = 0.05 * talents.Rime + (combatTable.DW ? (1 - talents.Rime * .05) * (talents.Rime * .05) : 0); }
public HeartStrike(Character c, Stats s, CalculationOptionsDPSDK CalcOpts, CombatTable table, DeathKnightTalents Talents) { character = c; stats = s; calcOpts = CalcOpts; combatTable = table; talents = Talents; GcdType = GCDType.Melee; Runes = RunesUsed.Blood; Name = "Heart Strike"; }
public static bool HasTalent(DeathKnightTalents tal) { return TalentManager.IsSelected((int)tal); }
public static void AccumulatePresenceStats(StatsDK PresenceStats, Presence p, DeathKnightTalents t) { switch(p) { case Presence.Blood: { if (t.ImprovedBloodPresence > 0) { PresenceStats.CritChanceReduction += 0.03f * t.ImprovedBloodPresence; PresenceStats.BonusRuneRegeneration += .1f * t.ImprovedBloodPresence; } else if (t.ImprovedFrostPresence > 0) PresenceStats.BonusRPMultiplier += .02f * t.ImprovedFrostPresence; else if (t.ImprovedUnholyPresence == 1) PresenceStats.MovementSpeed += .08f; else if (t.ImprovedUnholyPresence == 2) PresenceStats.MovementSpeed += .15f; PresenceStats.BonusStaminaMultiplier += .08125f; if (Rawr.Properties.GeneralSettings.Default.PTRMode) PresenceStats.BaseArmorMultiplier += 0.55f; else PresenceStats.BaseArmorMultiplier += 0.3f; PresenceStats.DamageTakenReductionMultiplier = 1f - (1f - PresenceStats.DamageTakenReductionMultiplier) * (1f - 0.08f); // Threat bonus. PresenceStats.ThreatIncreaseMultiplier += 1f; break; } case Presence.Frost: { if (t.ImprovedBloodPresence > 0) PresenceStats.DamageTakenReductionMultiplier = 1f - (1f - PresenceStats.DamageTakenReductionMultiplier) * (1f - 0.02f * t.ImprovedBloodPresence); else if (t.ImprovedUnholyPresence == 1) PresenceStats.MovementSpeed += .08f; else if (t.ImprovedUnholyPresence == 2) PresenceStats.MovementSpeed += .15f; PresenceStats.BonusDamageMultiplier += 0.1f; PresenceStats.BonusRPMultiplier += 0.1f; PresenceStats.ThreatReductionMultiplier += .20f; // Wowhead has this as effect #3 break; } case Presence.Unholy: { if (t.ImprovedBloodPresence > 0) PresenceStats.DamageTakenReductionMultiplier = 1f - (1f - PresenceStats.DamageTakenReductionMultiplier) * (1f - 0.02f * t.ImprovedBloodPresence); else if (t.ImprovedFrostPresence > 0) PresenceStats.BonusRPMultiplier += .02f * t.ImprovedFrostPresence; else if (t.ImprovedUnholyPresence > 0) PresenceStats.PhysicalHaste = AddStatMultiplierStat(PresenceStats.PhysicalHaste, (.025f * t.ImprovedUnholyPresence)); PresenceStats.PhysicalHaste = AddStatMultiplierStat(PresenceStats.PhysicalHaste, .1f); //PresenceStats.BonusRuneRegeneration += .1f; PresenceStats.MovementSpeed += .15f; PresenceStats.ThreatReductionMultiplier += .20f; // Wowhead has this as effect #3 break; } } }