using System.Collections.Generic; using System.Linq; using Revitalize.Framework.Utilities; using StardewValley; namespace Revitalize.Framework.Crafting { /// /// A crafting recipe. /// public class Recipe { /// /// The ingredients necessary to craft this recipe. /// public List ingredients; /// /// The items produced by this recipe. /// public List outputs; public Item DisplayItem { get => this.outputs.ElementAt(0).item; } /// /// The description for the crafting recipe. /// public string outputDescription; /// /// The name for the crafting recipe. /// public string outputName; /// /// The stats that this recipe costs. Magic, HP, stamina, gold, etc. /// public StatCost statCost; /// /// The number of in-game minutes it takes to craft this item. /// public int timeToCraft; public Recipe() { } /// Constructor for single item output. /// All the ingredients required to make the output. /// The item given as output with how many public Recipe(List inputs, CraftingRecipeComponent output, StatCost StatCost = null,int TimeToCraft=0) { this.ingredients = inputs; this.outputDescription = output.item.getDescription(); this.outputName = output.item.DisplayName; this.outputs = new List() { output }; this.statCost = StatCost ?? new StatCost(); this.timeToCraft = TimeToCraft; } public Recipe(List inputs, List outputs, string OutputName, string OutputDescription, Item DisplayItem = null, StatCost StatCost = null,int TimeToCraft=0) { this.ingredients = inputs; this.outputs = outputs; this.outputName = OutputName; this.outputDescription = OutputDescription; this.statCost = StatCost ?? new StatCost(); this.timeToCraft = TimeToCraft; } /// Checks if a player contains all recipe ingredients. public bool PlayerContainsAllIngredients() { return this.InventoryContainsAllIngredient(Game1.player.Items.ToList()); } /// Checks if a player contains a recipe ingredient. public bool PlayerContainsIngredient(CraftingRecipeComponent pair) { return this.InventoryContainsIngredient(Game1.player.Items.ToList(), pair); } /// Checks if an inventory contains all items. public bool InventoryContainsAllIngredient(IList items) { foreach (CraftingRecipeComponent pair in this.ingredients) if (!this.InventoryContainsIngredient(items, pair)) return false; return true; } /// Checks if an inventory contains an ingredient. public bool InventoryContainsIngredient(IList items, CraftingRecipeComponent pair) { foreach (Item i in items) { if (i != null && this.ItemEqualsOther(i, pair.item) && pair.requiredAmount <= i.Stack) return true; } return false; } /// Checks roughly if two items equal each other. public bool ItemEqualsOther(Item self, Item other) { return self.Name == other.Name && self.getCategoryName() == other.getCategoryName() && self.GetType() == other.GetType(); } /// /// Consumes all of the ingredients for the recipe. /// /// public void consume(ref IList from) { if (this.InventoryContainsAllIngredient(from) == false) return; InventoryManager manager = new InventoryManager(from); List removalList = new List(); foreach (CraftingRecipeComponent pair in this.ingredients) { foreach (Item item in manager.items) { if (item == null) continue; if (this.ItemEqualsOther(item, pair.item)) { if (item.Stack == pair.requiredAmount) removalList.Add(item); //remove the item else item.Stack -= pair.requiredAmount; //or reduce the stack size. } } } foreach (var v in removalList) manager.items.Remove(v); removalList.Clear(); from = manager.items; } /// /// Produces outputs for the crafting recipe. /// /// /// /// public void produce(ref IList to, bool dropToGround = false, bool isPlayerInventory = false) { var manager = isPlayerInventory ? new InventoryManager(new List()) : new InventoryManager(to); foreach (CraftingRecipeComponent pair in this.outputs) { Item item = pair.item.getOne(); item.addToStack(pair.requiredAmount - 1); bool added = manager.addItem(item); if (!added && dropToGround) Game1.createItemDebris(item, Game1.player.getStandingPosition(), Game1.player.getDirection()); } to = manager.items; } /// /// Consumes all ingredients in given inventory and adds in outputs to the other given inventory. /// /// The inventory to take ingredients from. /// The inventory to put outputs into. /// Should this item be dropped to the ground when crafted? /// Checks to see if the invventory is the player's public void craft(ref IList from, ref IList to, bool dropToGround = false, bool isPlayerInventory = false) { InventoryManager manager = new InventoryManager(to); if (manager.ItemCount + this.outputs.Count >= manager.capacity) { if (isPlayerInventory) Game1.showRedMessage("Inventory Full"); else return; } this.consume(ref from); this.produce(ref to, dropToGround, isPlayerInventory); } /// /// Actually crafts the recipe. /// public void craft() { IList playerItems = Game1.player.Items; IList outPutItems = new List(); this.craft(ref playerItems, ref outPutItems, true, true); Game1.player.Items = playerItems; //Set the items to be post consumption. foreach (Item I in outPutItems) Game1.player.addItemToInventory(I); //Add all items produced. this.statCost.payCost(); } public bool PlayerCanCraft() { return this.PlayerContainsAllIngredients() && this.statCost.canSafelyAffordCost(); } public bool CanCraft(IList items) { return this.InventoryContainsAllIngredient(items); } } }