using System; using System.Collections.Generic; using System.Globalization; using Mag.Shared.Constants; namespace Mag.Shared { /// /// This is a user defiend object to represent a Decal.Adapter.WorldObject. /// All properties will return -1 if the property isn't supported. /// [Serializable] public class MyWorldObject { public bool HasIdData; public int Id; public int LastIdTime; public int ObjectClass; public SerializableDictionary BoolValues = new SerializableDictionary(); public SerializableDictionary DoubleValues = new SerializableDictionary(); public SerializableDictionary IntValues = new SerializableDictionary(); public SerializableDictionary StringValues = new SerializableDictionary(); public List ActiveSpells = new List(); public List Spells = new List(); public void Init(bool hasIdData, int id, int lastIdTime, int objectClass, IDictionary boolValues, IDictionary doubleValues, IDictionary intValues, IDictionary stringValues, IList activeSpells, IList spells) { HasIdData = hasIdData; Id = id; LastIdTime = lastIdTime; ObjectClass = objectClass; AddTo(boolValues, doubleValues, intValues, stringValues); ActiveSpells.Clear(); foreach (var i in activeSpells) ActiveSpells.Add(i); Spells.Clear(); foreach (var i in spells) Spells.Add(i); } public void AddTo(IDictionary boolValues, IDictionary doubleValues, IDictionary intValues, IDictionary stringValues) { foreach (var kvp in boolValues) { if (boolValues.ContainsKey(kvp.Key)) BoolValues[kvp.Key] = kvp.Value; else BoolValues.Add(kvp.Key, kvp.Value); } foreach (var kvp in doubleValues) { if (doubleValues.ContainsKey(kvp.Key)) DoubleValues[kvp.Key] = kvp.Value; else DoubleValues.Add(kvp.Key, kvp.Value); } foreach (var kvp in intValues) { if (intValues.ContainsKey(kvp.Key)) IntValues[kvp.Key] = kvp.Value; else IntValues.Add(kvp.Key, kvp.Value); } foreach (var kvp in stringValues) { if (stringValues.ContainsKey(kvp.Key)) StringValues[kvp.Key] = kvp.Value; else StringValues.Add(kvp.Key, kvp.Value); } } public bool Values(BoolValueKey key, bool defaultValue = false) { if (BoolValues.ContainsKey((int)key)) return BoolValues[(int)key]; return defaultValue; } public double Values(DoubleValueKey key, double defaultValue = 0) { if (DoubleValues.ContainsKey((int)key)) return DoubleValues[(int)key]; return defaultValue; } public int Values(IntValueKey key, int defaultValue = 0) { if (IntValues.ContainsKey((int)key)) return IntValues[(int)key]; return defaultValue; } public string Values(StringValueKey key, string defaultValue = null) { if (StringValues.ContainsKey((int)key)) return StringValues[(int)key]; return defaultValue; } public string Material { get { if (IntValues.ContainsKey(131)) return Dictionaries.MaterialInfo.ContainsKey(IntValues[131]) ? Dictionaries.MaterialInfo[IntValues[131]] : IntValues[131].ToString(CultureInfo.InvariantCulture); return null; } } public string Name { get { return StringValues.ContainsKey(1) ? StringValues[1] : null; } } public string EquipSkill { get { if (IntValues.ContainsKey(218103840)) return Dictionaries.SkillInfo.ContainsKey(IntValues[218103840]) ? Dictionaries.SkillInfo[IntValues[218103840]] : IntValues[218103840].ToString(CultureInfo.InvariantCulture); return null; } } public string Mastery { get { if (IntValues.ContainsKey(353)) return Dictionaries.MasteryInfo.ContainsKey(IntValues[353]) ? Dictionaries.MasteryInfo[IntValues[353]] : IntValues[353].ToString(CultureInfo.InvariantCulture); return null; } } public string ItemSet { get { if (IntValues.ContainsKey(265)) return Dictionaries.AttributeSetInfo.ContainsKey(IntValues[265]) ? Dictionaries.AttributeSetInfo[IntValues[265]] : IntValues[265].ToString(CultureInfo.InvariantCulture); return null; } } public int ArmorLevel { get { return IntValues.ContainsKey(28) ? IntValues[28] : -1; } } public string Imbue { get { if (!IntValues.ContainsKey(179) || IntValues[179] == 0) return null; string retVal = String.Empty; if ((IntValues[179] & 1) == 1) retVal += " CS"; if ((IntValues[179] & 2) == 2) retVal += " CB"; if ((IntValues[179] & 4) == 4) retVal += " AR"; if ((IntValues[179] & 8) == 8) retVal += " SlashRend"; if ((IntValues[179] & 16) == 16) retVal += " PierceRend"; if ((IntValues[179] & 32) == 32) retVal += " BludgeRend"; if ((IntValues[179] & 64) == 64) retVal += " AcidRend"; if ((IntValues[179] & 128) == 128) retVal += " FrostRend"; if ((IntValues[179] & 256) == 256) retVal += " LightRend"; if ((IntValues[179] & 512) == 512) retVal += " FireRend"; if ((IntValues[179] & 1024) == 1024) retVal += " MeleeImbue"; if ((IntValues[179] & 4096) == 4096) retVal += " MagicImbue"; if ((IntValues[179] & 8192) == 8192) retVal += " Hematited"; if ((IntValues[179] & 536870912) == 536870912) retVal += " MagicAbsorb"; retVal = retVal.Trim(); return retVal; } } public int Tinks { get { return IntValues.ContainsKey(171) ? IntValues[171] : -1; } } public int MaxDamage { get { return IntValues.ContainsKey(218103842) ? IntValues[218103842] : -1; } } public int ElementalDmgBonus { get { return IntValues.ContainsKey(204) ? IntValues[204] : -1; } } public Double Variance { get { return DoubleValues.ContainsKey(167772171) ? DoubleValues[167772171] : -1; } } public Double DamageBonus { get { return DoubleValues.ContainsKey(167772174) ? DoubleValues[167772174] : -1; } } public Double ElementalDamageVersusMonsters { get { return DoubleValues.ContainsKey(152) ? DoubleValues[152] : -1; } } public Double AttackBonus { get { return DoubleValues.ContainsKey(167772172) ? DoubleValues[167772172] : -1; } } public Double MeleeDefenseBonus { get { return DoubleValues.ContainsKey(29) ? DoubleValues[29] : -1; } } public Double MagicDBonus { get { return DoubleValues.ContainsKey(150) ? DoubleValues[150] : -1; } } public Double MissileDBonus { get { return DoubleValues.ContainsKey(149) ? DoubleValues[149] : -1; } } public Double ManaCBonus { get { return DoubleValues.ContainsKey(144) ? DoubleValues[144] : -1; } } public int WieldLevel { get { if (IntValues.ContainsKey(160) && IntValues[160] > 0 && IntValues.ContainsKey(158) && IntValues[158] == 7 && IntValues.ContainsKey(159) && IntValues[159] == 1) return IntValues[160]; return -1; } } public int SkillLevel { get { if (IntValues.ContainsKey(160) && IntValues[160] > 0 && (!IntValues.ContainsKey(158) || IntValues[158] != 7) && IntValues.ContainsKey(159)) return IntValues[160]; return -1; } } public int LoreRequirement { get { return IntValues.ContainsKey(109) ? IntValues[109] : -1; } } public Double SalvageWorkmanship { get { return DoubleValues.ContainsKey(167772169) ? DoubleValues[167772169] : -1; } } public int Workmanship { get { return IntValues.ContainsKey(105) ? IntValues[105] : -1; } } public int Value { get { return IntValues.ContainsKey(19) ? IntValues[19] : -1; } } public int Burden { get { return IntValues.ContainsKey(5) ? IntValues[5] : -1; } } public int DamRating { get { return IntValues.ContainsKey(370) ? IntValues[370] : -1; } } public int DamResistRating { get { return IntValues.ContainsKey(371) ? IntValues[371] : -1; } } public int CritRating { get { return IntValues.ContainsKey(372) ? IntValues[372] : -1; } } public int CritResistRating { get { return IntValues.ContainsKey(373) ? IntValues[373] : -1; } } public int CritDamRating { get { return IntValues.ContainsKey(374) ? IntValues[374] : -1; } } public int CritDamResistRating { get { return IntValues.ContainsKey(375) ? IntValues[375] : -1; } } public int HealBoostRating { get { return IntValues.ContainsKey(376) ? IntValues[376] : -1; } } public int VitalityRating { get { return IntValues.ContainsKey(379) ? IntValues[379] : -1; } } /// /// Returns the sum of all the ratings found on this item, or -1 if no ratings exist. /// public int TotalRating { get { if (DamRating == -1 && DamResistRating == -1 && CritRating == -1 && CritResistRating == -1 && CritDamRating == -1 && CritDamResistRating == -1 && HealBoostRating == -1 && VitalityRating == -1) return -1; return Math.Max(DamRating, 0) + Math.Max(DamResistRating, 0) + Math.Max(CritRating, 0) + Math.Max(CritResistRating, 0) + Math.Max(CritDamRating, 0) + Math.Max(CritDamResistRating, 0) + Math.Max(HealBoostRating, 0) + Math.Max(VitalityRating, 0); } } /// /// This will take the current AmorLevel of the item, subtract any buffs, subtract tinks as 20 AL each (not including imbue), and add any impen cantrips. /// public int CalcedStartingArmorLevel { get { int armorFromTinks = 0; int armorFromBuffs = 0; if (Tinks > 0 && ArmorLevel > 0) armorFromTinks = (Imbue != null) ? (Tinks - 1) * 20 : Tinks * 20; // This assumes each tink adds an amor level of 20 if ((!IntValues.ContainsKey(131) || IntValues[131] == 0) && ArmorLevel > 0) // If this item has no material, its not a loot gen, assume its a quest item and subtract 200 al armorFromTinks = 200; foreach (int spell in ActiveSpells) { foreach (var effect in Dictionaries.LongValueKeySpellEffects) { if (spell == effect.Key && effect.Value.Key == 28) armorFromBuffs += effect.Value.Change; } } foreach (int spell in Spells) { foreach (var effect in Dictionaries.LongValueKeySpellEffects) { if (spell == effect.Key && effect.Value.Key == 28) armorFromBuffs -= effect.Value.Bonus; } } return ArmorLevel - armorFromTinks - armorFromBuffs; } } /// /// This will take into account Variance, MaxDamage and Tinks of a melee weapon and determine what its optimal 10 tinked DamageOverTime is. /// public double CalcedBuffedTinkedDoT { get { if (!DoubleValues.ContainsKey(167772171) || !IntValues.ContainsKey(218103842)) return -1; double variance = DoubleValues.ContainsKey(167772171) ? DoubleValues[167772171] : 0; int maxDamage = GetBuffedIntValueKey(218103842); int numberOfTinksLeft = Math.Max(10 - Math.Max(Tinks, 0), 0); if (!IntValues.ContainsKey(179) || IntValues[179] == 0) numberOfTinksLeft--; // Factor in an imbue tink // If this is not a loot generated item, it can't be tinked if (!IntValues.ContainsKey(131) || IntValues[131] == 0) numberOfTinksLeft = 0; for (int i = 1; i <= numberOfTinksLeft; i++) { double ironTinkDoT = CalculateDamageOverTime(maxDamage + 24 + 1, variance); double graniteTinkDoT = CalculateDamageOverTime(maxDamage + 24, variance * .8); if (ironTinkDoT >= graniteTinkDoT) maxDamage++; else variance *= .8; } return CalculateDamageOverTime(maxDamage + 24, variance); } } /// /// GetBuffedIntValueKey(LongValueKey.MaxDamage) + (((GetBuffedDoubleValueKey(DoubleValueKey.DamageBonus) - 1) * 100) / 3) + GetBuffedIntValueKey(LongValueKey.ElementalDmgBonus); /// public double CalcedBuffedMissileDamage { get { if (!IntValues.ContainsKey(218103842) || !DoubleValues.ContainsKey(167772174) || !IntValues.ContainsKey(204)) return -1; return GetBuffedIntValueKey(218103842) + (((GetBuffedDoubleValueKey(167772174) - 1) * 100) / 3) + GetBuffedIntValueKey(204); } } public double BuffedElementalDamageVersusMonsters { get { return GetBuffedDoubleValueKey(152, -1); } } public double BuffedAttackBonus { get { return GetBuffedDoubleValueKey(167772172, -1); } } public double BuffedMeleeDefenseBonus { get { return GetBuffedDoubleValueKey(29, -1); } } public double BuffedManaCBonus { get { return GetBuffedDoubleValueKey(144, -1); } } public int GetBuffedIntValueKey(int key, int defaultValue = 0) { if (!IntValues.ContainsKey(key)) return defaultValue; int value = IntValues[key]; foreach (int spell in ActiveSpells) { if (Dictionaries.LongValueKeySpellEffects.ContainsKey(spell) && Dictionaries.LongValueKeySpellEffects[spell].Key == key) value -= Dictionaries.LongValueKeySpellEffects[spell].Change; } foreach (int spell in Spells) { if (Dictionaries.LongValueKeySpellEffects.ContainsKey(spell) && Dictionaries.LongValueKeySpellEffects[spell].Key == key) value += Dictionaries.LongValueKeySpellEffects[spell].Bonus; } return value; } public double GetBuffedDoubleValueKey(int key, double defaultValue = 0) { if (!DoubleValues.ContainsKey(key)) return defaultValue; double value = DoubleValues[key]; foreach (int spell in ActiveSpells) { if (Dictionaries.DoubleValueKeySpellEffects.ContainsKey(spell) && Dictionaries.DoubleValueKeySpellEffects[spell].Key == key) { if (Math.Abs(Dictionaries.DoubleValueKeySpellEffects[spell].Change - 1) < Double.Epsilon) value /= Dictionaries.DoubleValueKeySpellEffects[spell].Change; else value -= Dictionaries.DoubleValueKeySpellEffects[spell].Change; } } foreach (int spell in Spells) { if (Dictionaries.DoubleValueKeySpellEffects.ContainsKey(spell) && Dictionaries.DoubleValueKeySpellEffects[spell].Key == key && Math.Abs(Dictionaries.DoubleValueKeySpellEffects[spell].Bonus - 0) > Double.Epsilon) { if (Math.Abs(Dictionaries.DoubleValueKeySpellEffects[spell].Change - 1) < Double.Epsilon) value *= Dictionaries.DoubleValueKeySpellEffects[spell].Bonus; else value += Dictionaries.DoubleValueKeySpellEffects[spell].Bonus; } } return value; } /// /// maxDamage * ((1 - critChance) * (2 - variance) / 2 + (critChance * critMultiplier)); /// /// /// /// /// /// public static double CalculateDamageOverTime(int maxDamage, double variance, double critChance = .1, double critMultiplier = 2) { return maxDamage * ((1 - critChance) * (2 - variance) / 2 + (critChance * critMultiplier)); } public override string ToString() { return Name; } } }