Beispiel #1
0
        Tuple <Saint.Items.Equipment, int> Match(Saint.EquipSlot slot, Saint.Quad key)
        {
            if (!_equipmentBySlotByModelKey.ContainsKey(slot))
            {
                Console.WriteLine(_equipmentBySlotByModelKey.Keys.ToString());
            }
            var equipmentByModelKey = _equipmentBySlotByModelKey[slot];

            // Check for an exact match.
            if (equipmentByModelKey.TryGetValue(key, out var equipment))
            {
                return(Tuple.Create(equipment, 0));
            }

            // Search for the closest-matching equipment with this key.
            var matchComplexity  = int.MaxValue;
            var matchUncertainty = int.MaxValue;

            Saint.Items.Equipment matchEquipment = null;
            foreach (var pair in equipmentByModelKey)
            {
                // The first value must always match.
                if (pair.Key.Value1 != key.Value1)
                {
                    continue;
                }

                // If the equipment is a weapon or shield, the second value must always match too.
                if ((pair.Value is Saint.Items.Weapon || pair.Value is Saint.Items.Shield) &&
                    pair.Key.Value2 != key.Value2)
                {
                    continue;
                }

                // For every 10 levels of variance in the second value, match uncertainty increases.
                var uncertainty = 1 + Math.Abs(pair.Key.Value2 - key.Value2) / 10;
                if (uncertainty > matchUncertainty)
                {
                    continue;
                }

                // Now find the least complicated match on the lowest uncertainty level.
                var complexity = _complexity.GetNqComplexity(pair.Value.Key);
                if (complexity < matchComplexity)
                {
                    matchUncertainty = uncertainty;
                    matchEquipment   = pair.Value;
                }
            }

            return(Tuple.Create(matchEquipment, matchUncertainty));
        }
Beispiel #2
0
        public static void SetMaxValue(SC.Items.Equipment equipment, SC.BaseParam baseParam, dynamic attr_max)
        {
            if (equipment.FreeMateriaSlots == 0)
            {
                return;
            }

            var meldCap = equipment.GetMateriaMeldCap(baseParam, true);

            if (meldCap > 0)
            {
                var paramMax = equipment.GetMaximumParamValue(baseParam);
                SetValue(baseParam, attr_max, paramMax, 0, false);
            }
        }
Beispiel #3
0
        EquipmentRank Rank(Saint.Items.Equipment equipment, JobData jobData, SW[] weights, bool isCombatJob)
        {
            if (isCombatJob && equipment.EquipmentLevel >= jobData.MaxLevel)
            {
                return(null); // Optimization: Stat ranks at cap are obsolete for combat jobs.
            }
            var rank = new EquipmentRank()
            {
                Equipment = equipment
            };
            var melds           = 0;
            var maxMeldsAllowed = equipment.IsAdvancedMeldingPermitted ? 5 : equipment.FreeMateriaSlots;
            var ranksByWeight   = new Dictionary <SW, EquipmentStatRank>();

            // First calculate rankings with base weights.
            foreach (var weight in weights)
            {
                var value = equipment.GetParameterValue(weight.BaseParam, equipment.CanBeHq);

                var statRank = new EquipmentStatRank();
                statRank.Param     = weight.BaseParam.Name;
                statRank.Score     = value * weight.Value;
                statRank.BaseScore = (weight.ExcludeFromBaseValue ? 0 : value * weight.Value);
                statRank.MaxValue  = equipment.GetMaximumParamValue(weight.BaseParam);
                statRank.Value     = value;
                rank.StatRanks.Add(statRank);
                ranksByWeight[weight] = statRank;

                rank.Score     += statRank.Score;
                rank.BaseScore += statRank.BaseScore;
            }

            // Kick out PVP equipment now.
            if (equipment.IsPvP)
            {
                return(rank);
            }

            // Next calculate optimal melds, one at a time.
            while (melds < maxMeldsAllowed)
            {
                EquipmentStatRank currentBestStatRank = null;
                int    currentBestNewValue            = 0;
                double currentBestWeightedIncrease    = 0;
                double currentOvermeldPenalty         = 0;

                // Check each meldable stat.
                foreach (var weight in weights.Where(w => w.Materia != null))
                {
                    var statRank = ranksByWeight[weight];

                    // Check each meld tier.
                    foreach (var sMateria in weight.Materia)
                    {
                        var newValue         = Math.Min(statRank.MaxValue, statRank.Value + sMateria.Value);
                        var weightedIncrease = (newValue - statRank.Value) * weight.Value;

                        // Don't count advanced melds that can't overcome their overmeld penalty.
                        double penalty = 0;
                        if (melds >= equipment.FreeMateriaSlots)
                        {
                            if (!sMateria.Item.IsAdvancedMeldingPermitted)
                            {
                                continue;
                            }

                            var slot = melds - equipment.FreeMateriaSlots;
                            if (sMateria.Tier == 5 && slot > 0)
                            {
                                continue; // Can't overmeld VI past the first slot.
                            }
                            if (slot >= 4)
                            {
                                continue; // Hotfix, somehow we might end up working on this slot that doesn't exist in weights.;
                            }
                            penalty = OvermeldPenalties[slot, sMateria.Tier];
                            if (weightedIncrease < penalty)
                            {
                                continue;
                            }
                        }

                        // Check for a new best meld choice.
                        if (currentBestWeightedIncrease < weightedIncrease)
                        {
                            currentBestWeightedIncrease = weightedIncrease;
                            currentBestNewValue         = newValue;
                            currentBestStatRank         = statRank;
                            currentOvermeldPenalty      = penalty;
                        }
                    }
                }

                // Stop when no good melds are left.
                if (currentBestNewValue == 0)
                {
                    break;
                }

                // Apply a good meld.
                currentBestStatRank.Value  = currentBestNewValue;
                currentBestStatRank.Score += currentBestWeightedIncrease;
                rank.Score           += currentBestWeightedIncrease;
                rank.OvermeldPenalty -= currentOvermeldPenalty;
                melds++;
            }

            // Apply overmeld penalty if applicable.
            if (melds > equipment.FreeMateriaSlots && rank.OvermeldPenalty < 0)
            {
                var overmeldPenalty = new EquipmentStatRank();
                overmeldPenalty.Param     = "Overmeld Penalty";
                overmeldPenalty.Score     = rank.OvermeldPenalty;
                overmeldPenalty.BaseScore = 0;
                rank.StatRanks.Add(overmeldPenalty);

                rank.Score += overmeldPenalty.Score;
            }

            return(rank);
        }