using System.Linq; using Content.Shared.Kitchen.Components; using JetBrains.Annotations; using Robust.Shared.Utility; namespace Content.Shared.Kitchen.EntitySystems; public abstract partial class MicrowaveSystem { /// /// Helper function to get if an entity is an active microwave. /// /// The microwave entity. /// Whether or not this entity is an active microwave. [PublicAPI] public bool IsActiveMicrowave(Entity microwave) { return MicrowaveQuery.Resolve(microwave.Owner, ref microwave.Comp) && ActiveMicrowaveQuery.HasComp(microwave.Owner); } /// /// Helper function to get the contents of a microwave. /// /// The microwave entity. /// A list of microwave contents. [PublicAPI] public IReadOnlyList GetMicrowaveContents(Entity microwave) { if (!MicrowaveQuery.Resolve(microwave.Owner, ref microwave.Comp)) return new List(); return microwave.Comp.Storage.ContainedEntities; } /// /// Helper function to check if a microwave has ingredient contents. /// /// The microwave entity. /// Whether or not this microwave contains anything. [PublicAPI] public bool HasContents(Entity microwave) { return GetMicrowaveContents(microwave).Any(); } /// /// Gets a complete ordered list of usable recipes for this appliance. /// /// /// Note that the order of recipes is meaningful. When a valid recipe is chosen, the first item /// in the list that satisfies the conditions of the recipe is selected. /// /// Recipe prototypes in the recipe manager are pre-sorted based on complexity, so more "specific" /// recipes will be selected first. Secret recipes come before all non-secret prototype recipes. /// Do not sort the result of this function! /// /// The appliance to get recipes for. /// A complete list of usable recipe prototypes. [PublicAPI] public IReadOnlyList GetAvailableRecipes(EntityUid uid) { var getRecipesEv = new GetSecretRecipesEvent(); RaiseLocalEvent(uid, ref getRecipesEv); var recipes = getRecipesEv.Recipes .OrderByDescending(recipe => recipe.Priority) .ThenByDescending(recipe => recipe.Ingredients.Count()) .ToList(); recipes.AddRange(_recipes.Recipes); return recipes; } /// /// Given a recipe, a list of available ingredients, and a cooking time, this functions /// gets how many times we can make this given recipe. /// /// A cooking recipe. /// The ingredients we have available. /// How long we are cooking for. /// How many portions of the recipe can be made. [PublicAPI] public static uint GetRecipePortions(MicrowaveMealRecipePrototype recipe, CookingIngredients ingredients, uint cookTime) { // Our cooking time must be a multiple of the recipe's cooking time. // For example: If a recipe takes 10 seconds to cook, then you can't make it with a 15 second timer. // However, if you use a 30 second timer, you could make three of that recipe on one timer. if (cookTime % recipe.Time != 0) return 0; // TODO: there's actually a kind of nasty edge case microwave economics issue here, // all reagents / stacks / solids will be included, but when the recipe is actually made, // solids are used first, then stacks, then reagents. // thus, recipe detection might thing you have "more" ingredients than you actually do. // // moral of the story: I hate microwaves var portionCount = cookTime / recipe.Time; var ingredientPortions = ingredients.PortionForRecipe(recipe.Ingredients); portionCount = Math.Min(portionCount, ingredientPortions); return portionCount; } /// /// Given an appliance entity and a list of available ingredients, this function gets the first valid /// usable recipe for cooking. /// /// /// The appliance entity itself is used to get secret recipes. /// /// An appliance to fetch a recipe for. /// A list of available ingredients. /// How long we plan to cook for. /// /// The first valid recipe we can use. If there is none, this is (null, 0). /// [PublicAPI] public PortionedRecipe? GetRecipe(EntityUid uid, CookingIngredients ingredients, uint cookTime) { var recipes = GetAvailableRecipes(uid); var recipePortions = recipes.Select(recipe => { var portions = GetRecipePortions(recipe, ingredients, cookTime); return new PortionedRecipe(recipe.ID, portions); }); return recipePortions.FirstOrNull(r => r.Count > 0) ?? null; } /// /// Gets a complete list of recipe-usable ingredients from a list of items, including solids, /// stacks, and reagents. /// /// The list of items to use as ingredients. /// Cooking ingredient quantities representing the total usable ingredient list. [PublicAPI] public CookingIngredients GetTotalIngredients(List items) { var ingredients = new CookingIngredients(); foreach (var item in items) { AddItemIngredients(item, ref ingredients); } return ingredients; } }