adds the ability to "mix" solutions (reactions caused by using an item on a solution holder) (#13015)
* everything for mixing aside from yaml changes * add recipe and canmix to bottles and the holy mixer tag to the bible * fixes as a result of testing * remove unused usings * remove emptylines that are not required Co-authored-by: 0x6273 <0x40@keemail.me> * more empty line removal! Co-authored-by: 0x6273 <0x40@keemail.me> * add single space between if statement and condition Co-authored-by: 0x6273 <0x40@keemail.me> * fixes indentation on TryGetMixableSolution * raise new AfterMixingEvent after attempting to mix a solution * before mixing event and attempt get mixable solution event * update reaction tests to be a beaker that can be mixed, and then pass a mixer component in to simulate mixing * make two more beaker types mixable, add attribute for mixing feedback * bible mix message * mixing feedback on success * updates test to use SpawnEntity over new as per feedback Co-authored-by: 0x6273 <0x40@keemail.me>
This commit is contained in:
committed by
GitHub
parent
a497167e45
commit
c046666578
@@ -14,6 +14,13 @@ namespace Content.Shared.Chemistry.Components
|
||||
[DataField("canReact")]
|
||||
public bool CanReact { get; set; } = true;
|
||||
|
||||
/// <summary>
|
||||
/// If reactions can occur via mixing.
|
||||
/// </summary>
|
||||
[ViewVariables(VVAccess.ReadWrite)]
|
||||
[DataField("canMix")]
|
||||
public bool CanMix { get; set; } = false;
|
||||
|
||||
/// <summary>
|
||||
/// Volume needed to fill this container.
|
||||
/// </summary>
|
||||
|
||||
29
Content.Shared/Chemistry/Reaction/ReactionMixerComponent.cs
Normal file
29
Content.Shared/Chemistry/Reaction/ReactionMixerComponent.cs
Normal file
@@ -0,0 +1,29 @@
|
||||
using Content.Shared.Chemistry.Components;
|
||||
|
||||
namespace Content.Shared.Chemistry.Reaction;
|
||||
|
||||
[RegisterComponent]
|
||||
public sealed class ReactionMixerComponent : Component
|
||||
{
|
||||
/// <summary>
|
||||
/// A list of IDs for categories of reactions that can be mixed (i.e. HOLY for a bible, DRINK for a spoon)
|
||||
/// </summary>
|
||||
[ViewVariables]
|
||||
[DataField("reactionTypes")]
|
||||
public List<string> ReactionTypes = default!;
|
||||
|
||||
/// <summary>
|
||||
/// A string which identifies the string to be sent when successfully mixing a solution
|
||||
/// </summary>
|
||||
[ViewVariables]
|
||||
[DataField("mixMessage")]
|
||||
public string MixMessage = "default-mixing-success";
|
||||
}
|
||||
|
||||
[ByRefEvent]
|
||||
public record struct MixingAttemptEvent(EntityUid Mixed, bool Cancelled = false);
|
||||
|
||||
public readonly record struct AfterMixingEvent(EntityUid Mixed, EntityUid Mixer);
|
||||
|
||||
[ByRefEvent]
|
||||
public record struct GetMixableSolutionAttemptEvent(EntityUid Mixed, Solution? MixedSolution = null);
|
||||
@@ -38,6 +38,12 @@ namespace Content.Shared.Chemistry.Reaction
|
||||
[DataField("maxTemp")]
|
||||
public float MaximumTemperature = float.PositiveInfinity;
|
||||
|
||||
/// <summary>
|
||||
/// The required mixing categories for an entity to mix the solution with for the reaction to occur
|
||||
/// </summary>
|
||||
[DataField("requiredMixerCategories")]
|
||||
public List<string>? MixingCategories = null;
|
||||
|
||||
/// <summary>
|
||||
/// Reagents created when the reaction occurs.
|
||||
/// </summary>
|
||||
|
||||
@@ -5,6 +5,7 @@ using Content.Shared.Chemistry.Components;
|
||||
using Content.Shared.Chemistry.Reagent;
|
||||
using Content.Shared.Database;
|
||||
using Content.Shared.FixedPoint;
|
||||
using Content.Shared.Interaction.Events;
|
||||
using Robust.Shared.Prototypes;
|
||||
using Robust.Shared.Random;
|
||||
|
||||
@@ -102,7 +103,7 @@ namespace Content.Shared.Chemistry.Reaction
|
||||
/// <param name="reaction">The reaction to check.</param>
|
||||
/// <param name="lowestUnitReactions">How many times this reaction can occur.</param>
|
||||
/// <returns></returns>
|
||||
private bool CanReact(Solution solution, ReactionPrototype reaction, EntityUid owner, out FixedPoint2 lowestUnitReactions)
|
||||
private bool CanReact(Solution solution, ReactionPrototype reaction, EntityUid owner, ReactionMixerComponent? mixerComponent, out FixedPoint2 lowestUnitReactions)
|
||||
{
|
||||
lowestUnitReactions = FixedPoint2.MaxValue;
|
||||
if (solution.Temperature < reaction.MinimumTemperature)
|
||||
@@ -115,6 +116,13 @@ namespace Content.Shared.Chemistry.Reaction
|
||||
return false;
|
||||
}
|
||||
|
||||
if((mixerComponent == null && reaction.MixingCategories != null) ||
|
||||
mixerComponent != null && reaction.MixingCategories != null && reaction.MixingCategories.Except(mixerComponent.ReactionTypes).Any())
|
||||
{
|
||||
lowestUnitReactions = FixedPoint2.Zero;
|
||||
return false;
|
||||
}
|
||||
|
||||
var attempt = new ReactionAttemptEvent(reaction, solution);
|
||||
RaiseLocalEvent(owner, attempt, false);
|
||||
if (attempt.Cancelled)
|
||||
@@ -215,7 +223,7 @@ namespace Content.Shared.Chemistry.Reaction
|
||||
/// Removes the reactants from the solution, then returns a solution with all products.
|
||||
/// WARNING: Does not trigger reactions between solution and new products.
|
||||
/// </summary>
|
||||
private bool ProcessReactions(Solution solution, EntityUid owner, FixedPoint2 maxVolume, SortedSet<ReactionPrototype> reactions)
|
||||
private bool ProcessReactions(Solution solution, EntityUid owner, FixedPoint2 maxVolume, SortedSet<ReactionPrototype> reactions, ReactionMixerComponent? mixerComponent)
|
||||
{
|
||||
HashSet<ReactionPrototype> toRemove = new();
|
||||
Solution? products = null;
|
||||
@@ -223,7 +231,7 @@ namespace Content.Shared.Chemistry.Reaction
|
||||
// attempt to perform any applicable reaction
|
||||
foreach (var reaction in reactions)
|
||||
{
|
||||
if (!CanReact(solution, reaction, owner, out var unitReactions))
|
||||
if (!CanReact(solution, reaction, owner, mixerComponent, out var unitReactions))
|
||||
{
|
||||
toRemove.Add(reaction);
|
||||
continue;
|
||||
@@ -264,13 +272,13 @@ namespace Content.Shared.Chemistry.Reaction
|
||||
/// <summary>
|
||||
/// Continually react a solution until no more reactions occur.
|
||||
/// </summary>
|
||||
public void FullyReactSolution(Solution solution, EntityUid owner) => FullyReactSolution(solution, owner, FixedPoint2.MaxValue);
|
||||
public void FullyReactSolution(Solution solution, EntityUid owner) => FullyReactSolution(solution, owner, FixedPoint2.MaxValue, null);
|
||||
|
||||
/// <summary>
|
||||
/// Continually react a solution until no more reactions occur, with a volume constraint.
|
||||
/// If a reaction's products would exceed the max volume, some product is deleted.
|
||||
/// </summary>
|
||||
public void FullyReactSolution(Solution solution, EntityUid owner, FixedPoint2 maxVolume)
|
||||
public void FullyReactSolution(Solution solution, EntityUid owner, FixedPoint2 maxVolume, ReactionMixerComponent? mixerComponent)
|
||||
{
|
||||
// construct the initial set of reactions to check.
|
||||
SortedSet<ReactionPrototype> reactions = new();
|
||||
@@ -284,7 +292,7 @@ namespace Content.Shared.Chemistry.Reaction
|
||||
// exceed the iteration limit.
|
||||
for (var i = 0; i < MaxReactionIterations; i++)
|
||||
{
|
||||
if (!ProcessReactions(solution, owner, maxVolume, reactions))
|
||||
if (!ProcessReactions(solution, owner, maxVolume, reactions, mixerComponent))
|
||||
return;
|
||||
}
|
||||
|
||||
|
||||
Reference in New Issue
Block a user