using System.Text;
using Content.Server.Atmos.Components;
using Content.Server.Body.Components;
using Content.Server.Ghost.Roles.Components;
using Content.Server.Nutrition.Components;
using Content.Server.Nyanotrasen.Kitchen.Components;
using Content.Shared.Atmos.Rotting;
using Content.Shared.Body.Components;
using Content.Shared.Buckle.Components;
using Content.Shared.Chemistry.Components;
using Content.Shared.FixedPoint;
using Content.Shared.Mobs.Components;
using Content.Shared.NPC;
using Content.Shared.Nutrition.Components;
using Content.Shared.Nyanotrasen.Kitchen.Prototypes;
using Content.Shared.Paper;
using Robust.Shared.Prototypes;
using Robust.Shared.Random;
namespace Content.Server.Nyanotrasen.Kitchen.EntitySystems;
public sealed partial class DeepFryerSystem
{
///
/// Make an item look deep-fried.
///
public void MakeCrispy(EntityUid item, ProtoId crispiness) // Frontier: add CrispinessLevelSetPrototype
{
EnsureComp(item);
// Frontier: apply the fryer-appropriate shader
var deepFried = EnsureComp(item);
var oldCrispinessProto = deepFried.CrispinessLevelSet;
SetDeepFriedCrispinessLevelSet(item, deepFried, crispiness);
if (_prototypeManager.TryIndex(oldCrispinessProto, out var oldCrispiness))
{
_appearanceSystem.SetData(item, oldCrispiness.Visual, false);
}
if (_prototypeManager.TryIndex(crispiness, out var newCrispiness))
{
_appearanceSystem.SetData(item, newCrispiness.Visual, true);
}
// End Frontier
}
///
/// Turn a dead mob into food.
///
///
/// This is meant to be an irreversible process, similar to gibbing.
///
public bool TryMakeMobIntoFood(EntityUid mob, MobStateComponent mobStateComponent, bool force = false)
{
// Don't do anything to mobs until they're dead.
if (force || _mobStateSystem.IsDead(mob, mobStateComponent))
{
RemComp(mob);
RemComp(mob);
RemComp(mob);
RemComp(mob);
RemComp(mob);
RemComp(mob);
RemComp(mob);
RemComp(mob);
RemComp(mob);
// Ensure it's Food here, so it passes the whitelist.
var mobFoodComponent = EnsureComp(mob);
if (!_solutionContainerSystem.EnsureSolutionEntity(mob, mobFoodComponent.Solution, out var alreadyHadFood, out var mobFood))
return false;
var mobFoodSolution = mobFood.Value.Comp.Solution;
// This line here is mainly for mice, because they have a food
// component that mirrors how much blood they have, which is
// used for the reagent grinder.
if (alreadyHadFood)
mobFoodSolution.RemoveAllSolution();
if (TryComp(mob, out var bloodstreamComponent) && bloodstreamComponent.ChemicalSolution != null)
{
// Fry off any blood into protein.
var bloodSolution = bloodstreamComponent.BloodSolution;
var solPresent = bloodSolution!.Value.Comp.Solution.Volume;
mobFoodSolution.RemoveReagent("Blood", FixedPoint2.MaxValue);
var bloodRemoved = solPresent - bloodSolution.Value.Comp.Solution.Volume;
var proteinQuantity = bloodRemoved * BloodToProteinRatio;
mobFoodSolution.MaxVolume += proteinQuantity;
mobFoodSolution.AddReagent("Protein", proteinQuantity);
// This is a heuristic. If you had blood, you might just taste meaty.
if (bloodRemoved > FixedPoint2.Zero)
EnsureComp(mob).Flavors.Add(MobFlavorMeat);
// Bring in whatever chemicals they had in them too.
mobFoodSolution.MaxVolume +=
bloodstreamComponent.ChemicalSolution.Value.Comp.Solution.Volume;
mobFoodSolution.AddSolution(bloodstreamComponent.ChemicalSolution.Value.Comp.Solution, _prototypeManager);
}
_solutionContainerSystem.UpdateChemicals(mobFood.Value);
return true;
}
return false;
}
///
/// Make an item actually edible.
///
private void MakeEdible(EntityUid uid, DeepFryerComponent component, EntityUid item, FixedPoint2 solutionQuantity)
{
if (!TryComp(item, out var deepFriedComponent))
{
_sawmill.Error($"{ToPrettyString(item)} is missing the DeepFriedComponent before being made Edible.");
return;
}
// Remove any components that wouldn't make sense anymore.
RemComp(item);
if (TryComp(item, out var paperComponent))
{
var stringBuilder = new StringBuilder();
for (var i = 0; i < paperComponent.Content.Length; ++i)
{
var uchar = paperComponent.Content.Substring(i, 1);
if (uchar == "\n" || _random.Prob(0.4f))
stringBuilder.Append(uchar);
else
stringBuilder.Append("x");
}
paperComponent.Content = stringBuilder.ToString();
}
var foodComponent = EnsureComp(item);
var extraSolution = new Solution();
if (TryComp(item, out FlavorProfileComponent? flavorProfileComponent))
{
HashSet goodFlavors = new(flavorProfileComponent.Flavors);
goodFlavors.IntersectWith(component.GoodFlavors);
HashSet badFlavors = new(flavorProfileComponent.Flavors);
badFlavors.IntersectWith(component.BadFlavors);
deepFriedComponent.PriceCoefficient = Math.Max(0.01f,
1.0f
+ goodFlavors.Count * component.GoodFlavorPriceBonus
- badFlavors.Count * component.BadFlavorPriceMalus);
if (goodFlavors.Count > 0)
{
foreach (var reagent in component.GoodReagents)
{
extraSolution.AddReagent(reagent.Reagent.ToString(), reagent.Quantity * goodFlavors.Count);
// Mask the taste of "medicine."
flavorProfileComponent.IgnoreReagents.Add(reagent.Reagent.ToString());
}
}
if (badFlavors.Count > 0)
{
foreach (var reagent in component.BadReagents)
{
extraSolution.AddReagent(reagent.Reagent.ToString(), reagent.Quantity * badFlavors.Count);
}
}
}
else
{
flavorProfileComponent = EnsureComp(item);
// TODO: Default flavor?
}
// Make sure there's enough room for the fryer solution.
if (!_solutionContainerSystem.EnsureSolutionEntity(item, foodComponent.Solution, out var foodEnt))
return;
var foodSolution = foodEnt.Value.Comp.Solution;
// The solution quantity is used to give the fried food an extra
// buffer too, to support injectables or condiments.
foodSolution.MaxVolume = 2 * solutionQuantity + foodSolution.Volume + extraSolution.Volume;
foodSolution.AddSolution(component.Solution.SplitSolution(solutionQuantity), _prototypeManager);
foodSolution.AddSolution(extraSolution, _prototypeManager);
_solutionContainerSystem.UpdateChemicals(foodEnt.Value);
}
}