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