private static void ApplyIngredientsDepthWise(ComponentCost recipe, Dictionary <string, int> owned, int remainingDepth) { if (remainingDepth == 0) { if (owned.ContainsKey(recipe.Record)) { var numSpent = Math.Min(owned[recipe.Record], recipe.NumRequired); owned[recipe.Record] -= numSpent; recipe.NumOwned = numSpent; if (numSpent > 0) { ReduceChildrenTotals(recipe, recipe.NumRequired, recipe.NumRequired - numSpent); } } } else if (remainingDepth > 0) { if (recipe.NumOwned >= recipe.NumRequired) { MarkComplete(recipe); } else { foreach (var child in recipe.Cost) { ApplyIngredientsDepthWise(child, owned, remainingDepth - 1); } } } }
public void Populate(ComponentCost recipe) { if (recipe != null) { ISet <string> recipeRecords = new HashSet <string>(); GetRecords(recipe, recipeRecords); // Fetch player held items Dictionary <string, int> storedItems = _playerItemDao.GetCountByRecord(_mod); var stashItems = _stashManager.UnlootedItems .Where(item => recipeRecords.Contains(item.BaseRecord)) .Where(item => item.MateriaCombines == 0 || item.MateriaCombines >= 3) // "Good enough" for now, TODO: Check the DB for the real amount .ToList(); // Merge the two lists foreach (var item in stashItems) { if (storedItems.ContainsKey(item.BaseRecord)) { storedItems[item.BaseRecord] += Math.Max(1, (int)item.StackCount); } else { storedItems[item.BaseRecord] = Math.Max(1, (int)item.StackCount); } } // Apply "already have" items for (int depth = 0; depth < 10; depth++) { ApplyIngredientsDepthWise(recipe, storedItems, depth); } } }
/// <summary> /// /// </summary> /// <param name="formulas">Every formula in the database</param> /// <param name="components">Every component craftable by a formula</param> /// <param name="record"></param> /// <param name="numRequired"></param> /// <param name="depth">Max search depth to prevent stack overflows etc</param> /// <returns>A tree showing the construction costs for the given record</returns> private ComponentCost CreateComponent(IList <DatabaseItemDto> formulas, IList <DatabaseItemDto> components, string record, int numRequired, int depth = 0) { // Obs: if 'item' is null, search the database for it, some items are components without being craftable var item = components.FirstOrDefault(m => m.Record == record); if (item == null) { item = _itemDao.FindDtoByRecord(record); Logger.Warn($"Component {record} was not preloaded, this may be a performance issue"); components.Add(item); } var result = new ComponentCost { NumRequired = numRequired, Name = item?.Name, Bitmap = GetBitmap(item?.Stats), Cost = new List <ComponentCost>(), Record = record }; if (_looped.Contains(record) || depth >= 10) { return(result); } var recipeStat = formulas.SelectMany(m => m.Stats).FirstOrDefault(m => m.Stat == "artifactName" && m.TextValue == record); // For stuff like claws we only crate 1/4, so need the real number required // Only do this if this is not the last item in the chain. (makes no sense to list 4x when you obviously need a complete) int costMultiplier = numRequired; var relicLevel = item?.Stats.FirstOrDefault(m => m.Stat == "completedRelicLevel"); bool nonPartialCraft = recipeStat?.Parent.Stats.Any(m => m.Stat == "forcedRelicCompletion") ?? false; if (relicLevel != null && !nonPartialCraft) { costMultiplier *= (int)relicLevel.Value; } // Calculate costs for this item/component var recipe = recipeStat?.Parent; foreach (var reagent in _reagents) { var rcd = (recipe?.Stats)?.FirstOrDefault(m => m.Stat == $"{reagent}BaseName")?.TextValue; var qtd = (recipe?.Stats)?.FirstOrDefault(m => m.Stat == $"{reagent}Quantity")?.Value; if (rcd != null && qtd.HasValue) { result.Cost.Add(CreateComponent(formulas, components, rcd, (int)qtd.Value * costMultiplier, depth + 1)); } } return(result); }
private static void ReduceChildrenTotals(ComponentCost recipe, int original, int newValue) { foreach (var child in recipe.Cost) { child.NumRequired = child.NumRequired / original * newValue; ReduceChildrenTotals(child, original, newValue); } }
private static void GetRecords(ComponentCost recipe, ISet <string> records) { records.Add(recipe.Record); foreach (var cost in recipe.Cost) { GetRecords(cost, records); } }
private static void MarkComplete(ComponentCost recipe) { recipe.IsComplete = true; foreach (var child in recipe.Cost) { MarkComplete(child); } }