/// <summary> /// Reports all the reasons a given recipe for a givne player will fail with a given set of ingredients (defaults to /// the player's inventory). /// </summary> /// <param name="player"></param> /// <param name="recipe"></param> /// <param name="missingTile">Returns the tile IDs (crafting stations) needed for the recipe.</param> /// <param name="missingItemTypesStacks">Returns the missing item ids and amounts for the recipe.</param> /// <param name="availableIngredients"></param> /// <returns></returns> public static RecipeCraftFailReason GetRecipeFailReasons( Player player, Recipe recipe, out int[] missingTile, out IDictionary <int, int> missingItemTypesStacks, IEnumerable <Item> availableIngredients = null) { RecipeCraftFailReason reason = 0; var missingTileList = new List <int>(); missingItemTypesStacks = new Dictionary <int, int>(); // Get available item ingredients if (availableIngredients == null) { availableIngredients = player.inventory .Take(58) .Where(item => !item.IsAir); bool? _; Item[] chest = PlayerItemLibraries.GetCurrentlyOpenChest(player, out _); if (chest != null) { availableIngredients = availableIngredients.Concat(chest); } } // Process ingredients list into id + stack map IDictionary <int, int> availIngredientInfo = new Dictionary <int, int>(availableIngredients.Count()); foreach (Item item in availableIngredients) { if (availIngredientInfo.ContainsKey(item.netID)) { availIngredientInfo[item.netID] += item.stack; } else { availIngredientInfo[item.netID] = item.stack; } } // Tiles for (int i = 0; i < recipe.requiredTile.Length; i++) { int reqTileType = recipe.requiredTile[i]; if (reqTileType == -1) { break; } if (!player.adjTile[reqTileType]) { missingTileList.Add(reqTileType); reason |= RecipeCraftFailReason.MissingTile; } } // Items for (int i = 0; i < recipe.requiredItem.Length; i++) { Item reqItem = recipe.requiredItem[i]; if (reqItem == null || reqItem.type == ItemID.None) { break; } int reqStack = reqItem.stack; bool hasCheckedGroups = false; foreach (var kv in availIngredientInfo) { int itemType = kv.Key; int itemStack = kv.Value; if (recipe.useWood(itemType, reqItem.type) || recipe.useSand(itemType, reqItem.type) || recipe.useIronBar(itemType, reqItem.type) || recipe.useFragment(itemType, reqItem.type) || recipe.usePressurePlate(itemType, reqItem.type) || recipe.AcceptedByItemGroups(itemType, reqItem.type)) { reqStack -= itemStack; hasCheckedGroups = true; } } if (!hasCheckedGroups && availIngredientInfo.ContainsKey(reqItem.netID)) { reqStack -= availIngredientInfo[reqItem.netID]; } // Account for missing ingredients: if (reqStack > 0) { missingItemTypesStacks[reqItem.netID] = reqStack; reason |= RecipeCraftFailReason.MissingItem; } } if (recipe.needWater && !player.adjWater && !player.adjTile[172]) { reason |= RecipeCraftFailReason.NeedsNearbyWater; } if (recipe.needHoney && !player.adjHoney) { reason |= RecipeCraftFailReason.NeedsNearbyHoney; } if (recipe.needLava && !player.adjLava) { reason |= RecipeCraftFailReason.NeedsNearbyLava; } if (recipe.needSnowBiome && !player.ZoneSnow) { reason |= RecipeCraftFailReason.NeedsNearbySnowBiome; } missingTile = missingTileList.ToArray(); return(reason); }