Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Metamorphosis - FoodSequence 3 #31012

Merged
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
Show all changes
44 commits
Select commit Hold shift + click to select a range
48b5299
setup some data
TheShuEd Aug 14, 2024
90a18ca
cheeseburger recipe
TheShuEd Aug 14, 2024
b2120ce
Update FoodSequenceSystem.cs
TheShuEd Aug 14, 2024
fd0fa09
Merge remote-tracking branch 'upstream/master' into ed-14-08-2024-met…
TheShuEd Aug 14, 2024
b7ec0f4
finalize cheseburger recipe
TheShuEd Aug 14, 2024
1a285d7
remove fun
TheShuEd Aug 18, 2024
07e9a55
return old taco sprites
TheShuEd Aug 18, 2024
86e2933
full foodsequence data refactor
TheShuEd Aug 18, 2024
753eb4e
return tacos
TheShuEd Aug 18, 2024
aa92ae6
well done
TheShuEd Aug 18, 2024
6b363ff
Merge branch 'master' into ed-14-08-2024-metamorph-food
TheShuEd Aug 18, 2024
74bff9a
add cutlets to burger
TheShuEd Aug 18, 2024
37a7749
chickenburger recipe
TheShuEd Aug 18, 2024
8cd74e4
+2 burger recipes
TheShuEd Aug 18, 2024
427bf13
more fun
TheShuEd Aug 18, 2024
5cdaaf8
Update brain.png
TheShuEd Aug 18, 2024
f840c12
some slice produce added
TheShuEd Aug 18, 2024
4edc681
documentation
TheShuEd Aug 18, 2024
355eb46
watermelon
TheShuEd Aug 18, 2024
bee53b0
skewer work
TheShuEd Aug 18, 2024
f900753
flipping
TheShuEd Aug 18, 2024
d0e40d9
tomato
TheShuEd Aug 18, 2024
0a0a115
skewer watermelon
TheShuEd Aug 18, 2024
0a7b1dd
Update skewer.yml
TheShuEd Aug 18, 2024
03e8918
oopsie, ok, im go to sleep
TheShuEd Aug 18, 2024
95cc33e
fix checks
TheShuEd Aug 18, 2024
82b926c
Update produce.yml
TheShuEd Aug 18, 2024
5de39e1
screwed
TheShuEd Aug 19, 2024
32f0559
cheeeeeeeese
TheShuEd Aug 19, 2024
775e815
Merge remote-tracking branch 'upstream/master' into ed-14-08-2024-met…
TheShuEd Aug 22, 2024
ccfb348
Merge remote-tracking branch 'upstream/master' into ed-14-08-2024-met…
TheShuEd Sep 3, 2024
0e0f6e3
Merge remote-tracking branch 'upstream/master' into ed-14-08-2024-met…
TheShuEd Sep 3, 2024
abf7061
all cooked meat added
TheShuEd Sep 3, 2024
0060f01
produce added
TheShuEd Sep 3, 2024
18ceaec
aaaaand suppermatter
TheShuEd Sep 3, 2024
b52c655
key to Tag
TheShuEd Sep 3, 2024
5ad4440
More
TheShuEd Sep 3, 2024
a1e63f2
proto string remove
TheShuEd Sep 3, 2024
2143857
raw snail
TheShuEd Sep 3, 2024
9bf36b7
fix
TheShuEd Sep 3, 2024
bd89f4e
Update FoodMetamorphableByAddingComponent.cs
TheShuEd Sep 3, 2024
3c58764
fixes
TheShuEd Sep 3, 2024
fa36533
fix3
TheShuEd Sep 3, 2024
39285a1
fififififx
TheShuEd Sep 3, 2024
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
Original file line number Diff line number Diff line change
@@ -1,7 +1,6 @@
using Content.Shared.Nutrition.Components;
using Content.Shared.Nutrition.EntitySystems;
using Robust.Client.GameObjects;
using Robust.Shared.Utility;

namespace Content.Client.Nutrition.EntitySystems;

Expand Down Expand Up @@ -50,6 +49,7 @@ private void UpdateFoodVisuals(Entity<FoodSequenceStartPointComponent> start, Sp
sprite.AddBlankLayer(index);
sprite.LayerMapSet(keyCode, index);
sprite.LayerSetSprite(index, state.Sprite);
sprite.LayerSetScale(index, state.Scale);

//Offset the layer
var layerPos = start.Comp.StartPosition;
Expand Down
158 changes: 124 additions & 34 deletions Content.Server/Nutrition/EntitySystems/FoodSequenceSystem.cs
Original file line number Diff line number Diff line change
Expand Up @@ -4,10 +4,14 @@
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;
Expand All @@ -20,12 +24,16 @@ public sealed class FoodSequenceSystem : SharedFoodSequenceSystem
[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)
Expand All @@ -34,54 +42,124 @@ private void OnInteractUsing(Entity<FoodSequenceStartPointComponent> ent, ref In
TryAddFoodElement(ent, (args.Used, sequenceElement), args.User);
}

private bool TryAddFoodElement(Entity<FoodSequenceStartPointComponent> start, Entity<FoodSequenceElementComponent> element, EntityUid? user = null)
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)
{
FoodSequenceElementEntry? elementData = null;
foreach (var entry in element.Comp.Entries)
List<MetamorphRecipePrototype> availableRecipes = new();
foreach (var recipe in _proto.EnumeratePrototypes<MetamorphRecipePrototype>())
{
if (entry.Key == start.Comp.Key)
if (recipe.Key != start.Comp.Key)
continue;

bool allowed = true;
foreach (var rule in recipe.Rules)
{
elementData = entry.Value;
break;
if (!rule.Check(_proto, EntityManager, start, start.Comp.FoodLayers))
{
allowed = false;
break;
}
}
if (allowed)
availableRecipes.Add(recipe);
}

if (elementData is null)
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;

if (TryComp<FoodComponent>(element, out var elementFood) && elementFood.RequireDead)
//looking for a suitable FoodSequence prototype
ProtoId<FoodSequenceElementPrototype> elementProto = string.Empty;
foreach (var pair in element.Comp.Entries)
{
if (_mobState.IsAlive(element))
return false;
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 && !elementData.Final || start.Comp.Finished)
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;
}

//If no specific sprites are specified, standard sprites will be used.
if (elementData.Sprite is null && element.Comp.Sprite is not null)
elementData.Sprite = element.Comp.Sprite;

elementData.LocalOffset = 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(elementData);
//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 (elementData.Final)
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;
}
Expand All @@ -96,17 +174,23 @@ private void UpdateFoodName(Entity<FoodSequenceStartPointComponent> start)
if (start.Comp.ContentSeparator is not null)
separator = Loc.GetString(start.Comp.ContentSeparator);

HashSet<LocId> existedContentNames = new();
HashSet<ProtoId<FoodSequenceElementPrototype>> existedContentNames = new();
foreach (var layer in start.Comp.FoodLayers)
{
if (layer.Name is not null && !existedContentNames.Contains(layer.Name.Value))
existedContentNames.Add(layer.Name.Value);
if (!existedContentNames.Contains(layer.Proto))
existedContentNames.Add(layer.Proto);
}

var nameCounter = 1;
foreach (var name in existedContentNames)
foreach (var proto in existedContentNames)
{
content.Append(Loc.GetString(name));
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);
Expand All @@ -121,19 +205,25 @@ private void UpdateFoodName(Entity<FoodSequenceStartPointComponent> start)
_metaData.SetEntityName(start, newName);
}

private void MergeFoodSolutions(Entity<FoodSequenceStartPointComponent> start, Entity<FoodSequenceElementComponent> element)
private void MergeFoodSolutions(EntityUid start, EntityUid element)
{
if (!_solutionContainer.TryGetSolution(start.Owner, start.Comp.Solution, out var startSolutionEntity, out var startSolution))
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.Owner, element.Comp.Solution, out _, out var elementSolution))
if (!_solutionContainer.TryGetSolution(element, elementFood.Solution, out _, out var elementSolution))
return;

startSolution.MaxVolume += elementSolution.MaxVolume;
_solutionContainer.TryAddSolution(startSolutionEntity.Value, elementSolution);
}

private void MergeFlavorProfiles(Entity<FoodSequenceStartPointComponent> start, Entity<FoodSequenceElementComponent> element)
private void MergeFlavorProfiles(EntityUid start, EntityUid element)
{
if (!TryComp<FlavorProfileComponent>(start, out var startProfile))
return;
Expand All @@ -148,7 +238,7 @@ private void MergeFlavorProfiles(Entity<FoodSequenceStartPointComponent> start,
}
}

private void MergeTrash(Entity<FoodSequenceStartPointComponent> start, Entity<FoodSequenceElementComponent> element)
private void MergeTrash(EntityUid start, EntityUid element)
{
if (!TryComp<FoodComponent>(start, out var startFood))
return;
Expand All @@ -162,13 +252,13 @@ private void MergeTrash(Entity<FoodSequenceStartPointComponent> start, Entity<Fo
}
}

private void MergeTags(Entity<FoodSequenceStartPointComponent> start, Entity<FoodSequenceElementComponent> element)
private void MergeTags(EntityUid start, EntityUid element)
{
if (!TryComp<TagComponent>(element, out var elementTags))
return;

EnsureComp<TagComponent>(start.Owner);
EnsureComp<TagComponent>(start);

_tag.TryAddTags(start.Owner, elementTags.Tags);
_tag.TryAddTags(start, elementTags.Tags);
}
}
Original file line number Diff line number Diff line change
@@ -0,0 +1,17 @@
using Content.Shared.Nutrition.EntitySystems;
using Robust.Shared.GameStates;

namespace Content.Shared.Nutrition.Components;

/// <summary>
/// Attempts to metamorphose a modular food when a new ingredient is added.
/// </summary>
[RegisterComponent, NetworkedComponent, Access(typeof(SharedFoodSequenceSystem))]
public sealed partial class FoodMetamorphableByAddingComponent : Component
{
/// <summary>
/// if true, the metamorphosis will only be attempted when the sequence ends, not when each element is added.
/// </summary>
[DataField]
public bool OnlyFinal = true;
}
Original file line number Diff line number Diff line change
@@ -1,55 +1,25 @@
using System.Numerics;
using Content.Shared.Nutrition.EntitySystems;
using Robust.Shared.Serialization;
using Robust.Shared.Utility;
using Content.Shared.Nutrition.Prototypes;
using Content.Shared.Tag;
using Robust.Shared.Prototypes;

namespace Content.Shared.Nutrition.Components;

/// <summary>
/// Tndicates that this entity can be inserted into FoodSequence, which will transfer all reagents to the target.
/// Indicates that this entity can be inserted into FoodSequence, which will transfer all reagents to the target.
/// </summary>
[RegisterComponent, Access(typeof(SharedFoodSequenceSystem))]
public sealed partial class FoodSequenceElementComponent : Component
{
/// <summary>
/// the same object can be used in different sequences, and it will have a different sprite in different sequences.
/// The same object can be used in different sequences, and it will have a different data in then.
/// </summary>
[DataField(required: true)]
public Dictionary<string, FoodSequenceElementEntry> Entries = new();
public Dictionary<ProtoId<TagPrototype>, ProtoId<FoodSequenceElementPrototype>> Entries = new();

/// <summary>
/// which solution we will add to the main dish
/// Which solution we will add to the main dish
/// </summary>
[DataField]
public string Solution = "food";

/// <summary>
/// state used to generate the appearance of the added layer
/// </summary>
[DataField]
public SpriteSpecifier? Sprite;
}

[DataRecord, Serializable, NetSerializable]
public sealed class FoodSequenceElementEntry
{
/// <summary>
/// A localized name piece to build into the item name generator.
/// </summary>
public LocId? Name { get; set; } = null;

/// <summary>
/// overriding default sprite
/// </summary>
public SpriteSpecifier? Sprite { get; set; } = null;

/// <summary>
/// If the layer is the final one, it can be added over the limit, but no other layers can be added after it.
/// </summary>
public bool Final { get; set; } = false;

/// <summary>
/// the shear of a particular layer. Allows a little "randomization" of each layer.
/// </summary>
public Vector2 LocalOffset { get; set; } = Vector2.Zero;
}
Loading
Loading