using Content.Shared.Chemistry.Components.SolutionManager;
using Content.Shared.Chemistry.EntitySystems;
using Content.Shared.Chemistry.Reagent;
using Content.Shared.Destructible.Thresholds;
using Content.Shared.Nutrition.Components;
using Content.Shared.Tag;
using JetBrains.Annotations;
using Robust.Shared.Prototypes;
using Robust.Shared.Serialization;
namespace Content.Shared.Nutrition.FoodMetamorphRules;
///
/// abstract rules that are used to verify the correct foodSequence for recipe
///
[ImplicitDataDefinitionForInheritors]
[Serializable, NetSerializable]
public abstract partial class FoodMetamorphRule
{
public abstract bool Check(IPrototypeManager protoMan, EntityManager entMan, EntityUid food, List ingredients);
}
///
/// The requirement that the sequence be within the specified size limit
///
[UsedImplicitly]
[Serializable, NetSerializable]
public sealed partial class SequenceLength : FoodMetamorphRule
{
[DataField(required: true)]
public MinMax Range;
public override bool Check(IPrototypeManager protoMan, EntityManager entMan, EntityUid food, List ingredients)
{
return ingredients.Count <= Range.Max && ingredients.Count >= Range.Min;
}
}
///
/// A requirement that the last element of the sequence have one or all of the required tags
///
[UsedImplicitly]
[Serializable, NetSerializable]
public sealed partial class LastElementHasTags : FoodMetamorphRule
{
[DataField(required: true)]
public List> Tags = new ();
[DataField]
public bool NeedAll = true;
public override bool Check(IPrototypeManager protoMan, EntityManager entMan, EntityUid food, List ingredients)
{
var lastIngredient = ingredients[ingredients.Count - 1];
if (!protoMan.TryIndex(lastIngredient.Proto, out var protoIndexed))
return false;
foreach (var tag in Tags)
{
var containsTag = protoIndexed.Tags.Contains(tag);
if (NeedAll && !containsTag)
{
return false;
}
if (!NeedAll && containsTag)
{
return true;
}
}
return NeedAll;
}
}
///
/// A requirement that the specified sequence element have one or all of the required tags
///
[UsedImplicitly]
[Serializable, NetSerializable]
public sealed partial class ElementHasTags : FoodMetamorphRule
{
[DataField(required: true)]
public int ElementNumber = 0;
[DataField(required: true)]
public List> Tags = new ();
[DataField]
public bool NeedAll = true;
public override bool Check(IPrototypeManager protoMan, EntityManager entMan, EntityUid food, List ingredients)
{
if (ingredients.Count < ElementNumber + 1)
return false;
if (!protoMan.TryIndex(ingredients[ElementNumber].Proto, out var protoIndexed))
return false;
foreach (var tag in Tags)
{
var containsTag = protoIndexed.Tags.Contains(tag);
if (NeedAll && !containsTag)
{
return false;
}
if (!NeedAll && containsTag)
{
return true;
}
}
return NeedAll;
}
}
///
/// requirement that the food contains certain reagents (e.g. sauces)
///
[UsedImplicitly]
[Serializable, NetSerializable]
public sealed partial class FoodHasReagent : FoodMetamorphRule
{
[DataField(required: true)]
public ProtoId Reagent = new();
[DataField(required: true)]
public MinMax Count;
[DataField]
public string Solution = "food";
public override bool Check(IPrototypeManager protoMan, EntityManager entMan, EntityUid food, List ingredients)
{
if (!entMan.TryGetComponent(food, out var solMan))
return false;
var solutionMan = entMan.System();
if (!solutionMan.TryGetSolution(food, Solution, out var foodSoln, out var foodSolution))
return false;
foreach (var (id, quantity) in foodSoln.Value.Comp.Solution.Contents)
{
if (id.Prototype != Reagent.Id)
continue;
if (quantity < Count.Min || quantity > Count.Max)
break;
return true;
}
return false;
}
}
///
/// A requirement that there be X ingredients in the sequence that have one or all of the specified tags.
///
[UsedImplicitly]
[Serializable, NetSerializable]
public sealed partial class IngredientsWithTags : FoodMetamorphRule
{
[DataField(required: true)]
public List> Tags = new ();
[DataField(required: true)]
public MinMax Count = new();
[DataField]
public bool NeedAll = true;
public override bool Check(IPrototypeManager protoMan, EntityManager entMan, EntityUid food, List ingredients)
{
var count = 0;
foreach (var ingredient in ingredients)
{
if (!protoMan.TryIndex(ingredient.Proto, out var protoIndexed))
continue;
var allowed = false;
if (NeedAll)
{
allowed = true;
foreach (var tag in Tags)
{
if (!protoIndexed.Tags.Contains(tag))
{
allowed = false;
break;
}
}
}
else
{
allowed = false;
foreach (var tag in Tags)
{
if (protoIndexed.Tags.Contains(tag))
{
allowed = true;
break;
}
}
}
if (allowed)
count++;
}
return count >= Count.Min && count <= Count.Max;
}
}