Files
wwdpublic/Content.Server/Nutrition/EntitySystems/FoodSequenceSystem.cs
sleepyyapril 885ee5a831 Wizmerge for Station AI (#1351)
<!--
This is a semi-strict format, you can add/remove sections as needed but
the order/format should be kept the same
Remove these comments before submitting
-->

# Description

the adding AI is now up to y'all because i'm not touching loadout code
for name datasets, but it shouldn't be too bad from here

---------

Signed-off-by: sleepyyapril <123355664+sleepyyapril@users.noreply.github.com>
Signed-off-by: SolStar <44028047+ewokswagger@users.noreply.github.com>
Signed-off-by: deltanedas <39013340+deltanedas@users.noreply.github.com>
Co-authored-by: themias <89101928+themias@users.noreply.github.com>
Co-authored-by: Verm <32827189+Vermidia@users.noreply.github.com>
Co-authored-by: DrSmugleaf <10968691+DrSmugleaf@users.noreply.github.com>
Co-authored-by: Sphiral <145869023+SphiraI@users.noreply.github.com>
Co-authored-by: Ed <96445749+TheShuEd@users.noreply.github.com>
Co-authored-by: Mr. 27 <45323883+Dutch-VanDerLinde@users.noreply.github.com>
Co-authored-by: metalgearsloth <comedian_vs_clown@hotmail.com>
Co-authored-by: Alzore <140123969+Blackern5000@users.noreply.github.com>
Co-authored-by: ravage <142820619+ravage123321@users.noreply.github.com>
Co-authored-by: slarticodefast <161409025+slarticodefast@users.noreply.github.com>
Co-authored-by: Intoxicating-Innocence <188202277+Intoxicating-Innocence@users.noreply.github.com>
Co-authored-by: Saphire <lattice@saphi.re>
Co-authored-by: metalgearsloth <31366439+metalgearsloth@users.noreply.github.com>
Co-authored-by: Errant <35878406+Errant-4@users.noreply.github.com>
Co-authored-by: Tayrtahn <tayrtahn@gmail.com>
Co-authored-by: CaasGit <87243814+CaasGit@users.noreply.github.com>
Co-authored-by: BramvanZijp <56019239+BramvanZijp@users.noreply.github.com>
Co-authored-by: Boaz1111 <149967078+Boaz1111@users.noreply.github.com>
Co-authored-by: NakataRin <45946146+NakataRin@users.noreply.github.com>
Co-authored-by: Kara <lunarautomaton6@gmail.com>
Co-authored-by: Plykiya <58439124+Plykiya@users.noreply.github.com>
Co-authored-by: SlamBamActionman <slambamactionman@gmail.com>
Co-authored-by: Doomsdrayk <robotdoughnut@comcast.net>
Co-authored-by: Brandon Hu <103440971+Brandon-Huu@users.noreply.github.com>
Co-authored-by: SlamBamActionman <83650252+SlamBamActionman@users.noreply.github.com>
Co-authored-by: ElectroJr <leonsfriedrich@gmail.com>
Co-authored-by: Pieter-Jan Briers <pieterjan.briers+git@gmail.com>
Co-authored-by: DrSmugleaf <DrSmugleaf@users.noreply.github.com>
Co-authored-by: Julian Giebel <juliangiebel@live.de>
Co-authored-by: nikthechampiongr <32041239+nikthechampiongr@users.noreply.github.com>
Co-authored-by: Repo <47093363+Titian3@users.noreply.github.com>
Co-authored-by: Chief-Engineer <119664036+Chief-Engineer@users.noreply.github.com>
Co-authored-by: icekot8 <93311212+icekot8@users.noreply.github.com>
Co-authored-by: AJCM-git <60196617+AJCM-git@users.noreply.github.com>
Co-authored-by: Leon Friedrich <60421075+ElectroJr@users.noreply.github.com>
Co-authored-by: no <165581243+pissdemon@users.noreply.github.com>
Co-authored-by: Tornado Tech <54727692+Tornado-Technology@users.noreply.github.com>
Co-authored-by: osjarw <62134478+osjarw@users.noreply.github.com>
Co-authored-by: Simon <63975668+Simyon264@users.noreply.github.com>
Co-authored-by: TGRCDev <tgrc@tgrc.dev>
Co-authored-by: Milon <milonpl.git@proton.me>
Co-authored-by: deltanedas <39013340+deltanedas@users.noreply.github.com>
Co-authored-by: ShadowCommander <10494922+ShadowCommander@users.noreply.github.com>
Co-authored-by: Fildrance <fildrance@gmail.com>
Co-authored-by: pa.pecherskij <pa.pecherskij@interfax.ru>
Co-authored-by: chavonadelal <156101927+chavonadelal@users.noreply.github.com>
Co-authored-by: SolStar <44028047+ewokswagger@users.noreply.github.com>
Co-authored-by: K-Dynamic <20566341+K-Dynamic@users.noreply.github.com>
Co-authored-by: lzk <124214523+lzk228@users.noreply.github.com>
Co-authored-by: ArchRBX <5040911+ArchRBX@users.noreply.github.com>
Co-authored-by: archrbx <punk.gear5260@fastmail.com>
Co-authored-by: Radezolid <snappednexus@gmail.com>
Co-authored-by: Nemanja <98561806+EmoGarbage404@users.noreply.github.com>
Co-authored-by: EmoGarbage404 <retron404@gmail.com>
Co-authored-by: MilenVolf <63782763+MilenVolf@users.noreply.github.com>
Co-authored-by: Velcroboy <107660393+IamVelcroboy@users.noreply.github.com>
Co-authored-by: Velcroboy <velcroboy333@hotmail.com>
Co-authored-by: neuPanda <chriseparton@gmail.com>
Co-authored-by: neuPanda <spainman0@yahoo.com>
Co-authored-by: Dvir <39403717+dvir001@users.noreply.github.com>
Co-authored-by: Whatstone <whatston3@gmail.com>
Co-authored-by: VideoKompany <135313844+VlaDOS1408@users.noreply.github.com>

(cherry picked from commit 93ed70acfeda357133a701f637d3faeec02749bb)
2025-01-14 00:13:42 +03:00

264 lines
9.4 KiB
C#

using System.Numerics;
using System.Text;
using Content.Server.Nutrition.Components;
using Content.Shared.Chemistry.EntitySystems;
using Content.Shared.Interaction;
using Content.Shared.Mobs.Systems;
using Content.Shared.Nutrition;
using Content.Shared.Nutrition.Components;
using Content.Shared.Nutrition.EntitySystems;
using Content.Shared.Nutrition.Prototypes;
using Content.Shared.Popups;
using Content.Shared.Tag;
using Robust.Server.GameObjects;
using Robust.Shared.Prototypes;
using Robust.Shared.Random;
namespace Content.Server.Nutrition.EntitySystems;
public sealed class FoodSequenceSystem : SharedFoodSequenceSystem
{
[Dependency] private readonly SharedSolutionContainerSystem _solutionContainer = default!;
[Dependency] private readonly SharedPopupSystem _popup = default!;
[Dependency] private readonly MetaDataSystem _metaData = default!;
[Dependency] private readonly MobStateSystem _mobState = default!;
[Dependency] private readonly TagSystem _tag = default!;
[Dependency] private readonly IRobustRandom _random = default!;
[Dependency] private readonly IPrototypeManager _proto = default!;
[Dependency] private readonly TransformSystem _transform = default!;
public override void Initialize()
{
base.Initialize();
SubscribeLocalEvent<FoodSequenceStartPointComponent, InteractUsingEvent>(OnInteractUsing);
SubscribeLocalEvent<FoodMetamorphableByAddingComponent, FoodSequenceIngredientAddedEvent>(OnIngredientAdded);
}
private void OnInteractUsing(Entity<FoodSequenceStartPointComponent> ent, ref InteractUsingEvent args)
{
if (TryComp<FoodSequenceElementComponent>(args.Used, out var sequenceElement))
TryAddFoodElement(ent, (args.Used, sequenceElement), args.User);
}
private void OnIngredientAdded(Entity<FoodMetamorphableByAddingComponent> ent, ref FoodSequenceIngredientAddedEvent args)
{
if (!TryComp<FoodSequenceStartPointComponent>(args.Start, out var start))
return;
if (!_proto.TryIndex(args.Proto, out var elementProto))
return;
if (!ent.Comp.OnlyFinal || elementProto.Final || start.FoodLayers.Count == start.MaxLayers)
{
TryMetamorph((ent, start));
}
}
private bool TryMetamorph(Entity<FoodSequenceStartPointComponent> start)
{
List<MetamorphRecipePrototype> availableRecipes = new();
foreach (var recipe in _proto.EnumeratePrototypes<MetamorphRecipePrototype>())
{
if (recipe.Key != start.Comp.Key)
continue;
bool allowed = true;
foreach (var rule in recipe.Rules)
{
if (!rule.Check(_proto, EntityManager, start, start.Comp.FoodLayers))
{
allowed = false;
break;
}
}
if (allowed)
availableRecipes.Add(recipe);
}
if (availableRecipes.Count <= 0)
return true;
Metamorf(start, _random.Pick(availableRecipes)); //In general, if there's more than one recipe, the yml-guys screwed up. Maybe some kind of unit test is needed.
QueueDel(start);
return true;
}
private void Metamorf(Entity<FoodSequenceStartPointComponent> start, MetamorphRecipePrototype recipe)
{
var result = SpawnAtPosition(recipe.Result, Transform(start).Coordinates);
//Try putting in container
_transform.DropNextTo(result, (start, Transform(start)));
if (!_solutionContainer.TryGetSolution(result, start.Comp.Solution, out var resultSoln, out var resultSolution))
return;
if (!_solutionContainer.TryGetSolution(start.Owner, start.Comp.Solution, out var startSoln, out var startSolution))
return;
_solutionContainer.RemoveAllSolution(resultSoln.Value); //Remove all YML reagents
resultSoln.Value.Comp.Solution.MaxVolume = startSoln.Value.Comp.Solution.MaxVolume;
_solutionContainer.TryAddSolution(resultSoln.Value, startSolution);
MergeFlavorProfiles(start, result);
MergeTrash(start, result);
MergeTags(start, result);
}
private bool TryAddFoodElement(Entity<FoodSequenceStartPointComponent> start, Entity<FoodSequenceElementComponent> element, EntityUid? user = null)
{
// we can't add a live mouse to a burger.
if (!TryComp<FoodComponent>(element, out var elementFood))
return false;
if (elementFood.RequireDead && _mobState.IsAlive(element))
return false;
//looking for a suitable FoodSequence prototype
ProtoId<FoodSequenceElementPrototype> elementProto = string.Empty;
foreach (var pair in element.Comp.Entries)
{
if (pair.Key == start.Comp.Key)
{
elementProto = pair.Value;
}
}
if (!_proto.TryIndex(elementProto, out var elementIndexed))
return false;
//if we run out of space, we can still put in one last, final finishing element.
if (start.Comp.FoodLayers.Count >= start.Comp.MaxLayers && !elementIndexed.Final || start.Comp.Finished)
{
if (user is not null)
_popup.PopupEntity(Loc.GetString("food-sequence-no-space"), start, user.Value);
return false;
}
//Generate new visual layer
var flip = start.Comp.AllowHorizontalFlip && _random.Prob(0.5f);
var layer = new FoodSequenceVisualLayer(elementIndexed,
_random.Pick(elementIndexed.Sprites),
new Vector2(flip ? -1 : 1, 1),
new Vector2(
_random.NextFloat(start.Comp.MinLayerOffset.X, start.Comp.MaxLayerOffset.X),
_random.NextFloat(start.Comp.MinLayerOffset.Y, start.Comp.MaxLayerOffset.Y))
);
start.Comp.FoodLayers.Add(layer);
Dirty(start);
if (elementIndexed.Final)
start.Comp.Finished = true;
UpdateFoodName(start);
MergeFoodSolutions(start, element);
MergeFlavorProfiles(start, element);
MergeTrash(start, element);
MergeTags(start, element);
var ev = new FoodSequenceIngredientAddedEvent(start, element, elementProto, user);
RaiseLocalEvent(start, ev);
QueueDel(element);
return true;
}
private void UpdateFoodName(Entity<FoodSequenceStartPointComponent> start)
{
if (start.Comp.NameGeneration is null)
return;
var content = new StringBuilder();
var separator = "";
if (start.Comp.ContentSeparator is not null)
separator = Loc.GetString(start.Comp.ContentSeparator);
HashSet<ProtoId<FoodSequenceElementPrototype>> existedContentNames = new();
foreach (var layer in start.Comp.FoodLayers)
{
if (!existedContentNames.Contains(layer.Proto))
existedContentNames.Add(layer.Proto);
}
var nameCounter = 1;
foreach (var proto in existedContentNames)
{
if (!_proto.TryIndex(proto, out var protoIndexed))
continue;
if (protoIndexed.Name is null)
continue;
content.Append(Loc.GetString(protoIndexed.Name.Value));
if (nameCounter < existedContentNames.Count)
content.Append(separator);
nameCounter++;
}
var newName = Loc.GetString(start.Comp.NameGeneration.Value,
("prefix", start.Comp.NamePrefix is not null ? Loc.GetString(start.Comp.NamePrefix) : ""),
("content", content),
("suffix", start.Comp.NameSuffix is not null ? Loc.GetString(start.Comp.NameSuffix) : ""));
_metaData.SetEntityName(start, newName);
}
private void MergeFoodSolutions(EntityUid start, EntityUid element)
{
if (!TryComp<FoodComponent>(start, out var startFood))
return;
if (!TryComp<FoodComponent>(element, out var elementFood))
return;
if (!_solutionContainer.TryGetSolution(start, startFood.Solution, out var startSolutionEntity, out var startSolution))
return;
if (!_solutionContainer.TryGetSolution(element, elementFood.Solution, out _, out var elementSolution))
return;
startSolution.MaxVolume += elementSolution.MaxVolume;
_solutionContainer.TryAddSolution(startSolutionEntity.Value, elementSolution);
}
private void MergeFlavorProfiles(EntityUid start, EntityUid element)
{
if (!TryComp<FlavorProfileComponent>(start, out var startProfile))
return;
if (!TryComp<FlavorProfileComponent>(element, out var elementProfile))
return;
foreach (var flavor in elementProfile.Flavors)
{
if (startProfile != null && !startProfile.Flavors.Contains(flavor))
startProfile.Flavors.Add(flavor);
}
}
private void MergeTrash(EntityUid start, EntityUid element)
{
if (!TryComp<FoodComponent>(start, out var startFood))
return;
if (!TryComp<FoodComponent>(element, out var elementFood))
return;
foreach (var trash in elementFood.Trash)
{
startFood.Trash.Add(trash);
}
}
private void MergeTags(EntityUid start, EntityUid element)
{
if (!TryComp<TagComponent>(element, out var elementTags))
return;
EnsureComp<TagComponent>(start);
_tag.TryAddTags(start, elementTags.Tags);
}
}