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)); }
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); } }
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); }