public override int GetHashCode()
 {
     unchecked
     {
         return(((EquipmentModifiers != null ? EquipmentModifiers.GetHashCode() : 0) * 397) ^
                (CurrencyModifiers != null ? CurrencyModifiers.GetHashCode() : 0));
     }
 }
        private AffixPool GenerateAffixPool(EquipmentModifiers equipmentModifiers, CurrencyModifiers currencyModifiers)
        {
            var tags         = new HashSet <string>(_baseTags.Union(equipmentModifiers.AddedTags));
            var masterModSet = new HashSet <string>(equipmentModifiers.MasterMods);


            var addedAffixes = currencyModifiers.AddedExplicits
                               .Union(equipmentModifiers.Influence.SelectMany(x => _influenceAffixes[x]))
                               .Where(x => x.RequiredLevel <= equipmentModifiers.ItemLevel)
                               .ToList();

            var affixesToEvaluate = _itemAffixes.Union(addedAffixes).ToList();

            if (currencyModifiers.ItemLevelRestriction != null && currencyModifiers.ItemLevelRestriction < equipmentModifiers.ItemLevel)
            {
                affixesToEvaluate = affixesToEvaluate
                                    .Where(x => x.RequiredLevel <= currencyModifiers.ItemLevelRestriction)
                                    .ToList();
            }

            List <KeyValuePair <string, double> > qualityWeightModifiers = new List <KeyValuePair <string, double> >();

            if (currencyModifiers.QualityAffectsExplicitOdds)
            {
                qualityWeightModifiers.Add(equipmentModifiers.QualityGenerationWeight);
            }

            var weightModifiers = equipmentModifiers.GenerationWeights
                                  .Union(currencyModifiers.ExplicitWeightModifiers)
                                  .Union(qualityWeightModifiers)
                                  .GroupBy(x => x.Key)
                                  .ToDictionary(x => x.Key, x => x.Aggregate(1d, (y, z) => y * z.Value / 100d));

            AffixPool pool = new AffixPool();

            pool.PrefixGroupToAffixWeights = GroupToAffixWeights(affixesToEvaluate.Where(x => x.GenerationType == "prefix").ToList(), tags, weightModifiers, masterModSet);
            pool.SuffixGroupToAffixWeights = GroupToAffixWeights(affixesToEvaluate.Where(x => x.GenerationType == "suffix").ToList(), tags, weightModifiers, masterModSet);

            pool.PrefixGroupWeights = pool.PrefixGroupToAffixWeights.ToDictionary(x => x.Key, x => x.Value.Sum(y => y.Weight));
            pool.SuffixGroupWeights = pool.SuffixGroupToAffixWeights.ToDictionary(x => x.Key, x => x.Value.Sum(y => y.Weight));

            pool.PrefixWeight = pool.PrefixGroupWeights.Sum(x => x.Value);
            pool.SuffixWeight = pool.SuffixGroupWeights.Sum(x => x.Value);

            pool.TotalWeight = pool.PrefixWeight + pool.SuffixWeight;

            pool.AffixCount = pool.PrefixGroupToAffixWeights.Sum(x => x.Value.Count) + pool.SuffixGroupToAffixWeights.Sum(x => x.Value.Count);

            return(pool);
        }
        public static bool AddExplicit(IRandom random, Equipment item, AffixManager affixManager, CurrencyModifiers currencyModifiers)
        {
            var equipmentModifiers = new EquipmentModifiers(item);
            var affix = affixManager.GetAffix(equipmentModifiers, currencyModifiers, item.Stats.Select(x => x.Affix).ToList(), item.Rarity, random);

            if (affix == null)
            {
                return(false);
            }

            var stat = AffixToStat(random, item, affix);

            item.Stats.Add(stat);

            return(true);
        }
        protected bool Equals(EquipmentModifiers other)
        {
            for (int i = 0; i < Influence.Count; i++)
            {
                if (Influence[i] != other.Influence[i])
                {
                    return(false);
                }
            }

            for (int i = 0; i < AddedTags.Count; i++)
            {
                if (AddedTags[i] != other.AddedTags[i])
                {
                    return(false);
                }
            }

            for (int i = 0; i < MasterMods.Count; i++)
            {
                if (MasterMods[i] != other.MasterMods[i])
                {
                    return(false);
                }
            }

            foreach (var weightModifier in GenerationWeights)
            {
                if (!other.GenerationWeights.ContainsKey(weightModifier.Key))
                {
                    return(false);
                }
                if (Math.Abs(other.GenerationWeights[weightModifier.Key] - weightModifier.Value) > double.Epsilon)
                {
                    return(false);
                }
            }

            bool qualityGenAreEqual = Math.Abs(QualityGenerationWeight.Value - other.QualityGenerationWeight.Value) < double.Epsilon &&
                                      QualityGenerationWeight.Key == other.QualityGenerationWeight.Key;

            return(ItemLevel == other.ItemLevel && qualityGenAreEqual);
        }
        public Affix GetInfluenceAffix(Influence influence, EquipmentModifiers equipmentModifiers, List <Affix> affixes, EquipmentRarity rarity, IRandom random)
        {
            var existingGroups = new HashSet <string>(affixes.Select(x => x.Group));

            int affixesCount = rarity == EquipmentRarity.Normal ? 0 :
                               rarity == EquipmentRarity.Magic ? 1 :
                               rarity == EquipmentRarity.Rare ? 3 : 0;

            HashSet <string> fullGenTypes = new HashSet <string>();

            if (affixes.Count(x => x.GenerationType == "suffix") >= affixesCount)
            {
                fullGenTypes.Add("suffix");
            }
            if (affixes.Count(x => x.GenerationType == "prefix") >= affixesCount)
            {
                fullGenTypes.Add("prefix");
            }

            var pool = _influenceAffixes[influence]
                       .Where(x => x.RequiredLevel <= equipmentModifiers.ItemLevel)
                       .Where(x => !existingGroups.Contains(x.Group))
                       .Where(x => !fullGenTypes.Contains(x.GenerationType))
                       .ToList();

            var tag = _influenceTags[influence];

            var currentWeight = pool.Sum(x => x.SpawnWeights[tag]);
            var randomValue   = random.Next(currentWeight);

            foreach (var affix in pool)
            {
                currentWeight -= affix.Weight;
                if (randomValue < currentWeight)
                {
                    return(affix);
                }
            }
            throw new InvalidOperationException("An affix should have been selected");
        }
        public Affix GetAffix(EquipmentModifiers equipmentModifiers, CurrencyModifiers currencyModifiers, List <Affix> affixes, EquipmentRarity rarity, IRandom random)
        {
            PoolKey key = new PoolKey(equipmentModifiers, currencyModifiers);

            if (!_poolDic.ContainsKey(key))
            {
                _poolDic.Add(key, GenerateAffixPool(equipmentModifiers, currencyModifiers));
            }

            AffixPool pool           = _poolDic[key];
            var       existingGroups = new HashSet <string>(affixes.Select(x => x.Group));

            int affixesCount = rarity == EquipmentRarity.Normal ? 0 :
                               rarity == EquipmentRarity.Magic ? 1 :
                               rarity == EquipmentRarity.Rare ? 3 : 0;

            double prefixSkipAmount = CalculateSkipAmount("prefix", pool.PrefixWeight, pool.PrefixGroupWeights, affixes, affixesCount);
            double suffixSkipAmount = CalculateSkipAmount("suffix", pool.SuffixWeight, pool.SuffixGroupWeights, affixes, affixesCount);

            var targetWeight = random.NextDouble() * (pool.TotalWeight - prefixSkipAmount - suffixSkipAmount);

            return(GetRandomAffixFromPool(pool, targetWeight, existingGroups, prefixSkipAmount, suffixSkipAmount));
        }
 public PoolKey(EquipmentModifiers equipmentModifiers, CurrencyModifiers currencyModifiers)
 {
     this.EquipmentModifiers = equipmentModifiers;
     this.CurrencyModifiers  = currencyModifiers;
 }
 protected bool Equals(PoolKey other)
 {
     return(EquipmentModifiers.Equals(other.EquipmentModifiers) && CurrencyModifiers.Equals(other.CurrencyModifiers));
 }