mirror of
https://github.com/space-syndicate/space-station-14.git
synced 2026-10-09 18:31:17 +03:00
* adjust fields of meal recipe prototype * document microwave recipe datafields * use file scoped namespace for microwave recipes * more of this * localize every microwave recipe * make microwave system shared * refactor recipe reagent contents * refactor recipe solids + add material ingredient datafield * im making this a bit less silly * awa * move this shit out * move this shit out also * refactor Wzhzhzh * im gonna shorten this parameter by 1 actually * move this into recipes * make processcontents a little better(?) * clean imports * rename a struct * use cooking ingredients struct * comment * use whitelist for this * unused dependency * rearranged the parameters of get recipe portions * rearrange some stuff * clean up more imports * move container related functions into separate file * move this function out of ProcessContents * prevent microwaves from having items inserted while active * use IsPowered in microwave system * use byref syntax and Entity<> * moving the override up sorry i like it being up here * refactor microwave updating * clean up recipe finish logic * im renaming this function actually * move some functions around * move more stuff around * some comments * fix compiler error * fix the yml of all microwave recipes * use materials instead of solids for this stuff * oops * fix this * turn microwave sparks into datafield * move activelymicrowaved events into separate folder * make UpdateUserInterfaceState use entity only * rearrange some functions * move UI functions out * comment microwave UI stuff * more comments * comment recipe functions * refactor GetTotalIngredients to use an operator * give CookingIngredients addition methods * comment the rest of CookingIngredients * make subtraction functions clearer? * remove redundant comment * handle zero/negative ingredient cases * simplify subtract contents logic * fix these comments * typo * add microwave recipe test * move active microwave methods * comment active microwave methods * comment cooking methods * comment microwave methods * change setappearance to use entity<> * add some public api decorators * comment all of MicrowaveComponent * use file-scoped namespace for MicrowaveComponent * comment * fix baguette sword * maybe...? * oh oops * document the rest of the owl * kill the massive YML breaking change * fix protoman dependency * move shared microwave stuff to SharedMicrowaveSystem * fix usings * move microwave components to shared * fix up microwave datafields * move APIs to shared * move activemicrowave methods to shared * initialize on shared * move ui functions to shared * add actor here * stuff * predict microwave update loop * make clientside microwave system * adjust the update loop for microwaves * clean up * add field deltas to microwaves * dirty fields instead of whole component * move this to the partial * move GetRecipesForMicrowave to shared * comments * predict microwave BUI * oops * refactor microwave bui update * move UI messages to shared * move messages to UI file * move init to shared * move container methosd to shared * oops my using * move cooking functions into partial * move cooking methods to shared * move microwave recipe methods to shared * move the rest of the microwave events to shared * update imports * remove custom type serializer * better (?) microwave UI prediction * fix list notations * OK IT WAS THE DATAFIELDS * add IOC inject * dont use IOC for htis * sealed * prediction fixes pt1 * make microwave cooking updates more consistent * datafield tweaks * test for multiple portions in microwave recipes * test for multiple recipe portions * better(?) prediction for malfunctions * remove redundant comment * prevent solution reactions in microwave * cleanup some microwave stuff * eh i think this should be container actually * this can be API i think * reduce system redundancy * this has to be public * use resolve pattern for explode * use GetMicrowaveContents in microwave system * this can be an API too * add conversion script for unlocalized recipes * use EnsureComp instead of AddComp * suffering * fix recipe prediction * fix the audio * reduce redundant networking * i think this should be autopaused? * nevermind we use dynamic portions in the test * oops i wrote the test wrong * make lemoon cake take 2 lemoons again sorry test fail * rename "materials" to "stacks" realized theyre different * add stack guidebook quantities * Kill audio * fix lemoon cake recipe for real? * mark PortionedRecipe as a datadefinition * fix the microwave timer * review * cleanup * Update SharedMicrowaveSystem.Recipes.cs * update * add audio params * review: inject microwavesystem * review: named variable * review: move dependencies * review: use gametest for recipe test * review: make access attributes standalone * rename prototypes and datafields * review: rename this var * review: move this function down * review: remove these scripts * actually this should stay * refactor cook time buttons * review: use a color name for this * fix timer reset * Dirty * review: make ActivelyMicrowavedComponent networked * review: slarti comments part 1 * review: remove serializable attribute from CookingIngredients * rename file * review: more microwave audio boilerplate. yippee! * review: use resolve pattern for TryGetStackId i dont like the way this makes the rest of the code look but we ball maybe. i dont know what else to do here * review: move ui update to constructor * review: kill LastCookUpdated * actually i do this instead * fixed up the PR * cleanup * /// * Update microwave.yml --------- Co-authored-by: Princess Cheeseballs <66055347+Princess-Cheeseballs@users.noreply.github.com> Co-authored-by: Pok245 <113675512+Pok27@users.noreply.github.com>
282 lines
12 KiB
C#
282 lines
12 KiB
C#
using System.Diagnostics.CodeAnalysis;
|
|
using System.Linq;
|
|
using Content.Shared.Chemistry.Components;
|
|
using Content.Shared.Chemistry.Reagent;
|
|
using Content.Shared.FixedPoint;
|
|
using Content.Shared.Kitchen.Components;
|
|
using Content.Shared.Stacks;
|
|
using Robust.Shared.Containers;
|
|
using Robust.Shared.Prototypes;
|
|
|
|
namespace Content.Shared.Kitchen.EntitySystems;
|
|
|
|
public abstract partial class MicrowaveSystem
|
|
{
|
|
/// <summary>
|
|
/// This event tries to get secret recipes that the microwave might be capable of.
|
|
/// Currently, we only check the microwave itself, but in the future, the user might be able to learn recipes.
|
|
/// </summary>
|
|
[SubscribeLocalEvent]
|
|
private void OnGetSecretRecipes(Entity<FoodRecipeProviderComponent> ent, ref GetSecretRecipesEvent args)
|
|
{
|
|
foreach (var recipeId in ent.Comp.ProvidedRecipes)
|
|
{
|
|
if (ProtoMan.Resolve(recipeId, out var recipeProto))
|
|
args.Recipes.Add(recipeProto);
|
|
}
|
|
}
|
|
|
|
/// <summary>
|
|
/// Adds all usable ingredients from a given entity to an ingredient list.
|
|
/// </summary>
|
|
/// <remarks>
|
|
/// The entity itself is a "solid".
|
|
/// If it's a stack, then that stack is its "stacks".
|
|
/// If it has a usable ingredient solution, then the solution's contents are "reagents".
|
|
/// </remarks>
|
|
/// <param name="item">The entity to use as ingredients.</param>
|
|
/// <param name="ingredients">A dictionary of available ingredients to add to.</param>
|
|
private void AddItemIngredients(EntityUid item, ref CookingIngredients ingredients)
|
|
{
|
|
if (TryGetSolidId(item, out var solidId))
|
|
ingredients.AddSolid(solidId.Value);
|
|
|
|
if (StackQuery.TryComp(item, out var stack) && TryGetStackId(item, out var stackId))
|
|
ingredients.AddStack(stackId.Value, stack.Count);
|
|
|
|
if (TryGetUsableIngredientSolution(item, out _, out var solution))
|
|
{
|
|
foreach (var (reagent, quantity) in solution.Contents)
|
|
{
|
|
ingredients.AddReagent(reagent.Prototype, quantity);
|
|
}
|
|
}
|
|
}
|
|
|
|
/// <summary>
|
|
/// Attempts to get a solution from an entity that can be used as viable ingredients in a recipe.
|
|
/// </summary>
|
|
/// <remarks>
|
|
/// For example, a beaker's contents will work, but not the contents of an uncracked egg.
|
|
/// </remarks>
|
|
/// <param name="uid">The entity to attempt to get a usable ingredient solution for.</param>
|
|
/// <param name="solutionEntity">A usable solution entity, if available.</param>
|
|
/// <param name="solution">A usable solution, if available.</param>
|
|
/// <returns>Whether or not a usable ingredient solution was successfully retrieved.</returns>
|
|
private bool TryGetUsableIngredientSolution(EntityUid uid,
|
|
[NotNullWhen(true)] out Entity<SolutionComponent>? solutionEntity,
|
|
[NotNullWhen(true)] out Solution? solution)
|
|
{
|
|
return Solution.TryGetDrainableSolution(uid, out solutionEntity, out solution);
|
|
}
|
|
|
|
/// <summary>
|
|
/// Given a dictionary of stacks that need to be spent in a recipe, and the amount of stacks
|
|
/// of a stack we have available, this function gets the number of stacks we need to remove
|
|
/// from the stack entity. It also removes this amount from the remaining stacks dictionary.
|
|
/// </summary>
|
|
/// <param name="availableStacks">How many stacks we have available.</param>
|
|
/// <param name="stackId">The stack ID associated with the stack.</param>
|
|
/// <param name="ingredientsToSpend">How many stacks still need to be spent in the recipe.</param>
|
|
/// <returns>How many stacks we should remove from the available stack entity.</returns>
|
|
private static int SpendStackQuantity(int availableStacks,
|
|
ProtoId<StackPrototype> stackId,
|
|
CookingIngredients ingredientsToSpend)
|
|
{
|
|
if (!ingredientsToSpend.Stacks.TryGetValue(stackId, out var remaining))
|
|
return 0;
|
|
|
|
var spent = Math.Min(availableStacks, remaining);
|
|
ingredientsToSpend.AddStack(stackId, -spent);
|
|
|
|
return spent;
|
|
}
|
|
|
|
/// <summary>
|
|
/// Given a dictionary of reagents that need to be spent in a recipe, and a quantity of a reagent
|
|
/// that we have available in a solution, this function gets the amount of reagents we need to
|
|
/// remove from the solution. This also removes that amount from the "reagents to spend" dictionary.
|
|
/// </summary>
|
|
/// <param name="availableQuantity">How much reagent we have available.</param>
|
|
/// <param name="reagent">The ID of the reagent we are spending.</param>
|
|
/// <param name="ingredientsToSpend">A dictionary of reagents that still need to be spent.</param>
|
|
/// <returns>How much we should reduce the available reagent volume by.</returns>
|
|
private static FixedPoint2 SpendReagentQuantity(FixedPoint2 availableQuantity,
|
|
ProtoId<ReagentPrototype> reagent,
|
|
CookingIngredients ingredientsToSpend)
|
|
{
|
|
if (!ingredientsToSpend.Reagents.TryGetValue(reagent, out var remaining))
|
|
return 0;
|
|
|
|
var spent = FixedPoint2.Min(availableQuantity, remaining);
|
|
ingredientsToSpend.AddReagent(reagent, -spent);
|
|
|
|
return spent;
|
|
}
|
|
|
|
/// <summary>
|
|
/// Removes a solid ingredient that is used in a recipe, removing it from the dictionary of
|
|
/// remaining solids that still need to be spent in the recipe.
|
|
/// </summary>
|
|
/// <param name="item">The entity to remove.</param>
|
|
/// <param name="itemProto">The solid ID of the ingredient.</param>
|
|
/// <param name="container">The microwave's ingredient storage container.</param>
|
|
/// <param name="ingredientsToSpend">The struct representing ingredients we still need to spend.</param>
|
|
private void SubtractSolidContents(EntityUid item,
|
|
EntProtoId itemProto,
|
|
Container container,
|
|
CookingIngredients ingredientsToSpend)
|
|
{
|
|
if (!ingredientsToSpend.Solids.ContainsKey(itemProto))
|
|
return;
|
|
|
|
ingredientsToSpend.AddSolid(itemProto, -1);
|
|
Container.Remove(item, container);
|
|
PredictedQueueDel(item);
|
|
}
|
|
|
|
/// <summary>
|
|
/// Given a dictionary of remaining stacks that need to be spent in a recipe, this function
|
|
/// reduces a stack entity's count by however many stacks need to be spent. This also removes the
|
|
/// stack count from our remaining ingredients.
|
|
/// </summary>
|
|
/// <remarks>
|
|
/// If a recipe calls for two stacks of plasma sheets, and you put 5 sheets in the microwave, then
|
|
/// the plasma sheet stack would reduce by 2 (leaving you with 3 remaining), and plasma will
|
|
/// be removed from the remaining stacks dictionary.
|
|
/// </remarks>
|
|
/// <param name="ent">The stack entity.</param>
|
|
/// <param name="ingredientsToSpend">The struct representing ingredients we still need to spend.</param>
|
|
private void SubtractStackContents(Entity<StackComponent?> ent,
|
|
CookingIngredients ingredientsToSpend)
|
|
{
|
|
if (!Resolve(ent.Owner, ref ent.Comp))
|
|
return;
|
|
|
|
var stack = ent.Comp;
|
|
var stackId = stack.StackTypeId;
|
|
var startingQuantity = stack.Count;
|
|
var quantityToRemove = SpendStackQuantity(startingQuantity, stackId, ingredientsToSpend);
|
|
|
|
_stack.ReduceCount(ent.AsNullable(), quantityToRemove);
|
|
}
|
|
|
|
/// <summary>
|
|
/// Given a dictionary of remaining reagents that still need to be spent in a recipe, this function iterates
|
|
/// over a solution's contents and subtracts reagents according to the reagents to spend. This also removes
|
|
/// it from our remaining ingredients.
|
|
/// </summary>
|
|
/// <remarks>
|
|
/// Say you still have 6u mayonnaise remaining, and the solution has 10u mayonnaise, then 6u of
|
|
/// mayonnaise would be removed from the solution, leaving you with 4u left over. Then, mayonnaise
|
|
/// is removed from the dictionary of remaining reagents.
|
|
/// </remarks>
|
|
/// <param name="solutionEntity">The solution entity.</param>
|
|
/// <param name="solution">The solution itself.</param>
|
|
/// <param name="ingredientsToSpend">The struct representing ingredients we still need to spend.</param>
|
|
private void SubtractReagentContents(Entity<SolutionComponent> solutionEntity,
|
|
Solution solution,
|
|
CookingIngredients ingredientsToSpend)
|
|
{
|
|
var reagentsToProcess = ingredientsToSpend.Reagents.Keys.ToList();
|
|
|
|
foreach (var reagent in reagentsToProcess)
|
|
{
|
|
var availableQuantity = solution.GetTotalPrototypeQuantity(reagent);
|
|
if (availableQuantity == 0)
|
|
continue;
|
|
|
|
var quantityToRemove = SpendReagentQuantity(availableQuantity, reagent, ingredientsToSpend);
|
|
Solution.RemoveReagent(solutionEntity, reagent, quantityToRemove);
|
|
}
|
|
}
|
|
|
|
/// <summary>
|
|
/// Attempt to get the solid ID of a given entity.
|
|
/// </summary>
|
|
/// <param name="item">The entity to retrieve a solid ID for.</param>
|
|
/// <param name="solidId">The solid ID of the entity, if any.</param>
|
|
/// <returns>
|
|
/// Whether or not the solid ID was successfully retrieved. False if entity lacks an entity prototype ID.
|
|
/// </returns>
|
|
// TODO: Solids should be tag-based, or something like that. Not prototype-based.
|
|
private bool TryGetSolidId(EntityUid item,
|
|
[NotNullWhen(true)] out EntProtoId? solidId)
|
|
{
|
|
solidId = MetaData(item).EntityPrototype?.ID;
|
|
return solidId != null;
|
|
}
|
|
|
|
/// <summary>
|
|
/// Attempt to get the stack ID of a given entity.
|
|
/// </summary>
|
|
/// <param name="ent">The stack entity.</param>
|
|
/// <param name="stack">The stack prototype associated with this entity, if any.</param>
|
|
/// <returns>
|
|
/// Whether or not a stack ID is successfully retrieved. False if this entity is not a stack.
|
|
/// </returns>
|
|
private bool TryGetStackId(Entity<StackComponent?> ent,
|
|
[NotNullWhen(true)] out ProtoId<StackPrototype>? stack)
|
|
{
|
|
stack = null;
|
|
|
|
if (!Resolve(ent.Owner, ref ent.Comp, logMissing: false))
|
|
return false;
|
|
|
|
stack = ent.Comp.StackTypeId;
|
|
return true;
|
|
}
|
|
|
|
/// <summary>
|
|
/// Spend ingredients in the microwave based on a given recipe. This deletes ingredient entities (solids),
|
|
/// subtracts respective stack counts, and removes reagents from ingredient containers (reagents).
|
|
/// </summary>
|
|
/// <remarks>
|
|
/// This function does not check whether or not the contents have *enough* ingredients to
|
|
/// subtract - it simply performs the subtraction.
|
|
/// </remarks>
|
|
/// <param name="ent">The microwave entity.</param>
|
|
/// <param name="portionedRecipe">The recipe used to spend ingredients.</param>
|
|
private void SubtractContents(Entity<MicrowaveComponent> ent, PortionedRecipe portionedRecipe)
|
|
{
|
|
if (!ProtoMan.Resolve(portionedRecipe.Recipe, out var recipe))
|
|
return;
|
|
|
|
var ingredientsToSpend = recipe.Ingredients * portionedRecipe.Count;
|
|
var solidsToSpend = ingredientsToSpend.Solids;
|
|
var stacksToSpend = ingredientsToSpend.Stacks;
|
|
var reagentsToSpend = ingredientsToSpend.Reagents;
|
|
var microwave = ent.Comp;
|
|
var microwaveItems = GetMicrowaveContents(ent.AsNullable()).ToArray();
|
|
|
|
foreach (var item in microwaveItems)
|
|
{
|
|
if (solidsToSpend.Count > 0
|
|
&& TryGetSolidId(item, out var solidId)
|
|
&& solidsToSpend.ContainsKey(solidId.Value))
|
|
{
|
|
SubtractSolidContents(item, solidId.Value, microwave.Storage, ingredientsToSpend);
|
|
continue;
|
|
// We're exiting early here; if the solid ingredient is removed from the container,
|
|
// then we shouldn't be attempting to use its stack or reagents.
|
|
}
|
|
|
|
if (stacksToSpend.Count > 0
|
|
&& StackQuery.TryComp(item, out var stack)
|
|
&& TryGetStackId((item, stack), out var stackId)
|
|
&& stacksToSpend.ContainsKey(stackId.Value))
|
|
{
|
|
SubtractStackContents((item, stack), ingredientsToSpend);
|
|
if (Deleted(item) || stack.Count <= 0)
|
|
continue;
|
|
// We're exiting early here - if the stack is empty, then the stack entity
|
|
// is gonna be deleted. Which means we shouldn't be using its reagents.
|
|
}
|
|
|
|
if (reagentsToSpend.Count > 0
|
|
&& TryGetUsableIngredientSolution(item, out var solutionEntity, out var solution)
|
|
&& solution.Volume > 0)
|
|
SubtractReagentContents(solutionEntity.Value, solution, ingredientsToSpend);
|
|
}
|
|
}
|
|
}
|