Generalizes solution overflow & slightly increases space lube yield (#21094)
* generalize SolutionSpikeOverflowEvent * let reactions overflow * spacelube: 3 -> 5 * restore TryMixAndOverflow threshold cap
This commit is contained in:
@@ -61,35 +61,11 @@ public sealed class SolutionSpikableSystem : EntitySystem
|
|||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
if (_solutionSystem.TryMixAndOverflow(target,
|
if (!_solutionSystem.ForceAddSolution(target, targetSolution, sourceSolution))
|
||||||
targetSolution,
|
return;
|
||||||
sourceSolution,
|
|
||||||
targetSolution.MaxVolume,
|
|
||||||
out var overflow))
|
|
||||||
{
|
|
||||||
if (overflow.Volume > 0)
|
|
||||||
{
|
|
||||||
RaiseLocalEvent(target, new SolutionSpikeOverflowEvent(overflow));
|
|
||||||
}
|
|
||||||
|
|
||||||
_popupSystem.PopupEntity(Loc.GetString(spikableSource.Popup, ("spiked-entity", target), ("spike-entity", source)), user, user);
|
_popupSystem.PopupEntity(Loc.GetString(spikableSource.Popup, ("spiked-entity", target), ("spike-entity", source)), user, user);
|
||||||
|
|
||||||
sourceSolution.RemoveAllSolution();
|
sourceSolution.RemoveAllSolution();
|
||||||
|
|
||||||
_triggerSystem.Trigger(source, user);
|
_triggerSystem.Trigger(source, user);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
|
||||||
|
|
||||||
public sealed class SolutionSpikeOverflowEvent : HandledEntityEventArgs
|
|
||||||
{
|
|
||||||
/// <summary>
|
|
||||||
/// The solution that's been overflowed from the spike.
|
|
||||||
/// </summary>
|
|
||||||
public Solution Overflow { get; }
|
|
||||||
|
|
||||||
public SolutionSpikeOverflowEvent(Solution overflow)
|
|
||||||
{
|
|
||||||
Overflow = overflow;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|||||||
@@ -34,7 +34,7 @@ public sealed partial class PuddleSystem
|
|||||||
SubscribeLocalEvent<SpillableComponent, MeleeHitEvent>(SplashOnMeleeHit, after: new[] { typeof(OpenableSystem) });
|
SubscribeLocalEvent<SpillableComponent, MeleeHitEvent>(SplashOnMeleeHit, after: new[] { typeof(OpenableSystem) });
|
||||||
SubscribeLocalEvent<SpillableComponent, GetVerbsEvent<Verb>>(AddSpillVerb);
|
SubscribeLocalEvent<SpillableComponent, GetVerbsEvent<Verb>>(AddSpillVerb);
|
||||||
SubscribeLocalEvent<SpillableComponent, GotEquippedEvent>(OnGotEquipped);
|
SubscribeLocalEvent<SpillableComponent, GotEquippedEvent>(OnGotEquipped);
|
||||||
SubscribeLocalEvent<SpillableComponent, SolutionSpikeOverflowEvent>(OnSpikeOverflow);
|
SubscribeLocalEvent<SpillableComponent, SolutionOverflowEvent>(OnOverflow);
|
||||||
SubscribeLocalEvent<SpillableComponent, SpillDoAfterEvent>(OnDoAfter);
|
SubscribeLocalEvent<SpillableComponent, SpillDoAfterEvent>(OnDoAfter);
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -46,13 +46,12 @@ public sealed partial class PuddleSystem
|
|||||||
args.PushMarkup(Loc.GetString("spill-examine-spillable-weapon"));
|
args.PushMarkup(Loc.GetString("spill-examine-spillable-weapon"));
|
||||||
}
|
}
|
||||||
|
|
||||||
private void OnSpikeOverflow(EntityUid uid, SpillableComponent component, SolutionSpikeOverflowEvent args)
|
private void OnOverflow(EntityUid uid, SpillableComponent component, ref SolutionOverflowEvent args)
|
||||||
{
|
{
|
||||||
if (!args.Handled)
|
if (args.Handled)
|
||||||
{
|
return;
|
||||||
TrySpillAt(Transform(uid).Coordinates, args.Overflow, out _);
|
|
||||||
}
|
|
||||||
|
|
||||||
|
TrySpillAt(Transform(uid).Coordinates, args.Overflow, out _);
|
||||||
args.Handled = true;
|
args.Handled = true;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|||||||
@@ -30,6 +30,24 @@ public sealed class SolutionChangedEvent : EntityEventArgs
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// An event raised when more reagents are added to a (managed) solution than it can hold.
|
||||||
|
/// </summary>
|
||||||
|
[ByRefEvent]
|
||||||
|
public record struct SolutionOverflowEvent(EntityUid SolutionEnt, Solution SolutionHolder, Solution Overflow)
|
||||||
|
{
|
||||||
|
/// <summary>The entity which contains the solution that has overflowed.</summary>
|
||||||
|
public readonly EntityUid SolutionEnt = SolutionEnt;
|
||||||
|
/// <summary>The solution that has overflowed.</summary>
|
||||||
|
public readonly Solution SolutionHolder = SolutionHolder;
|
||||||
|
/// <summary>The reagents that have overflowed the solution.</summary>
|
||||||
|
public readonly Solution Overflow = Overflow;
|
||||||
|
/// <summary>The volume by which the solution has overflowed.</summary>
|
||||||
|
public readonly FixedPoint2 OverflowVol = Overflow.Volume;
|
||||||
|
/// <summary>Whether some subscriber has taken care of the effects of the overflow.</summary>
|
||||||
|
public bool Handled = false;
|
||||||
|
}
|
||||||
|
|
||||||
/// <summary>
|
/// <summary>
|
||||||
/// Part of Chemistry system deal with SolutionContainers
|
/// Part of Chemistry system deal with SolutionContainers
|
||||||
/// </summary>
|
/// </summary>
|
||||||
@@ -265,6 +283,14 @@ public sealed partial class SolutionContainerSystem : EntitySystem
|
|||||||
_chemistrySystem.FullyReactSolution(solutionHolder, uid, solutionHolder.MaxVolume, mixerComponent);
|
_chemistrySystem.FullyReactSolution(solutionHolder, uid, solutionHolder.MaxVolume, mixerComponent);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
var overflowVol = solutionHolder.Volume - solutionHolder.MaxVolume;
|
||||||
|
if (overflowVol > FixedPoint2.Zero)
|
||||||
|
{
|
||||||
|
var overflow = solutionHolder.SplitSolution(overflowVol);
|
||||||
|
var overflowEv = new SolutionOverflowEvent(uid, solutionHolder, overflow);
|
||||||
|
RaiseLocalEvent(uid, ref overflowEv);
|
||||||
|
}
|
||||||
|
|
||||||
UpdateAppearance(uid, solutionHolder);
|
UpdateAppearance(uid, solutionHolder);
|
||||||
RaiseLocalEvent(uid, new SolutionChangedEvent(solutionHolder, solutionHolder.Name));
|
RaiseLocalEvent(uid, new SolutionChangedEvent(solutionHolder, solutionHolder.Name));
|
||||||
}
|
}
|
||||||
@@ -417,24 +443,6 @@ public sealed partial class SolutionContainerSystem : EntitySystem
|
|||||||
return RemoveReagent(targetUid, container, new ReagentQuantity(reagentId, quantity));
|
return RemoveReagent(targetUid, container, new ReagentQuantity(reagentId, quantity));
|
||||||
}
|
}
|
||||||
|
|
||||||
/// <summary>
|
|
||||||
/// Adds a solution to the container, if it can fully fit.
|
|
||||||
/// </summary>
|
|
||||||
/// <param name="targetUid">entity holding targetSolution</param>
|
|
||||||
/// <param name="targetSolution">entity holding targetSolution</param>
|
|
||||||
/// <param name="addedSolution">solution being added</param>
|
|
||||||
/// <returns>If the solution could be added.</returns>
|
|
||||||
public bool TryAddSolution(EntityUid targetUid, Solution? targetSolution, Solution addedSolution)
|
|
||||||
{
|
|
||||||
if (targetSolution == null
|
|
||||||
|| !targetSolution.CanAddSolution(addedSolution) || addedSolution.Volume == 0)
|
|
||||||
return false;
|
|
||||||
|
|
||||||
targetSolution.AddSolution(addedSolution, _prototypeManager);
|
|
||||||
UpdateChemicals(targetUid, targetSolution, true);
|
|
||||||
return true;
|
|
||||||
}
|
|
||||||
|
|
||||||
/// <summary>
|
/// <summary>
|
||||||
/// Moves some quantity of a solution from one solution to another.
|
/// Moves some quantity of a solution from one solution to another.
|
||||||
/// </summary>
|
/// </summary>
|
||||||
@@ -497,32 +505,86 @@ public sealed partial class SolutionContainerSystem : EntitySystem
|
|||||||
}
|
}
|
||||||
|
|
||||||
/// <summary>
|
/// <summary>
|
||||||
/// Adds a solution to the container, overflowing the rest.
|
/// Adds a solution to the container, if it can fully fit.
|
||||||
/// It will
|
|
||||||
/// Unlike <see cref="TryAddSolution"/> it will ignore size limits.
|
|
||||||
/// </summary>
|
/// </summary>
|
||||||
/// <param name="targetUid">entity holding targetSolution</param>
|
/// <param name="targetUid">entity holding targetSolution</param>
|
||||||
/// <param name="targetSolution">The container to which we try to add.</param>
|
/// <param name="targetSolution">entity holding targetSolution</param>
|
||||||
/// <param name="addedSolution">solution being added</param>
|
/// <param name="toAdd">solution being added</param>
|
||||||
/// <param name="overflowThreshold">After addition this much will be left in targetSolution. Should be less
|
/// <returns>If the solution could be added.</returns>
|
||||||
/// than targetSolution.TotalVolume</param>
|
public bool TryAddSolution(EntityUid targetUid, Solution targetSolution, Solution toAdd)
|
||||||
|
{
|
||||||
|
if (toAdd.Volume == FixedPoint2.Zero)
|
||||||
|
return true;
|
||||||
|
if (toAdd.Volume > targetSolution.AvailableVolume)
|
||||||
|
return false;
|
||||||
|
|
||||||
|
ForceAddSolution(targetUid, targetSolution, toAdd);
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// Adds as much of a solution to a container as can fit.
|
||||||
|
/// </summary>
|
||||||
|
/// <param name="targetUid">The entity containing <paramref cref="targetSolution"/></param>
|
||||||
|
/// <param name="targetSolution">The solution being added to.</param>
|
||||||
|
/// <param name="toAdd">The solution being added to <paramref cref="targetSolution"/></param>
|
||||||
|
/// <returns>The quantity of the solution actually added.</returns>
|
||||||
|
public FixedPoint2 AddSolution(EntityUid targetUid, Solution targetSolution, Solution toAdd)
|
||||||
|
{
|
||||||
|
if (toAdd.Volume == FixedPoint2.Zero)
|
||||||
|
return FixedPoint2.Zero;
|
||||||
|
|
||||||
|
var quantity = FixedPoint2.Max(FixedPoint2.Zero, FixedPoint2.Min(toAdd.Volume, targetSolution.AvailableVolume));
|
||||||
|
if (quantity < toAdd.Volume)
|
||||||
|
TryTransferSolution(targetUid, targetSolution, toAdd, quantity);
|
||||||
|
else
|
||||||
|
ForceAddSolution(targetUid, targetSolution, toAdd);
|
||||||
|
|
||||||
|
return quantity;
|
||||||
|
}
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// Adds a solution to a container and updates the container.
|
||||||
|
/// </summary>
|
||||||
|
/// <param name="targetUid">The entity containing <paramref cref="targetSolution"/></param>
|
||||||
|
/// <param name="targetSolution">The solution being added to.</param>
|
||||||
|
/// <param name="toAdd">The solution being added to <paramref cref="targetSolution"/></param>
|
||||||
|
/// <returns>Whether any reagents were added to the solution.</returns>
|
||||||
|
public bool ForceAddSolution(EntityUid targetUid, Solution targetSolution, Solution toAdd)
|
||||||
|
{
|
||||||
|
if (toAdd.Volume == FixedPoint2.Zero)
|
||||||
|
return false;
|
||||||
|
|
||||||
|
targetSolution.AddSolution(toAdd, _prototypeManager);
|
||||||
|
UpdateChemicals(targetUid, targetSolution, needsReactionsProcessing: true);
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// Adds a solution to the container, removing the overflow.
|
||||||
|
/// Unlike <see cref="TryAddSolution"/> it will ignore size limits.
|
||||||
|
/// </summary>
|
||||||
|
/// <param name="targetUid">The entity containing <paramref cref="targetSolution"/></param>
|
||||||
|
/// <param name="targetSolution">The solution being added to.</param>
|
||||||
|
/// <param name="toAdd">The solution being added to <paramref cref="targetSolution"/></param>
|
||||||
|
/// <param name="overflowThreshold">The combined volume above which the overflow will be returned.
|
||||||
|
/// If the combined volume is below this an empty solution is returned.</param>
|
||||||
/// <param name="overflowingSolution">Solution that exceeded overflowThreshold</param>
|
/// <param name="overflowingSolution">Solution that exceeded overflowThreshold</param>
|
||||||
/// <returns></returns>
|
/// <returns>Whether any reagents were added to <paramref cref="targetSolution"/>.</returns>
|
||||||
public bool TryMixAndOverflow(EntityUid targetUid, Solution targetSolution,
|
public bool TryMixAndOverflow(EntityUid targetUid, Solution targetSolution,
|
||||||
Solution addedSolution,
|
Solution toAdd,
|
||||||
FixedPoint2 overflowThreshold,
|
FixedPoint2 overflowThreshold,
|
||||||
[NotNullWhen(true)] out Solution? overflowingSolution)
|
[NotNullWhen(true)] out Solution? overflowingSolution)
|
||||||
{
|
{
|
||||||
if (addedSolution.Volume == 0 || overflowThreshold > targetSolution.MaxVolume)
|
if (toAdd.Volume == 0 || overflowThreshold > targetSolution.MaxVolume)
|
||||||
{
|
{
|
||||||
overflowingSolution = null;
|
overflowingSolution = null;
|
||||||
return false;
|
return false;
|
||||||
}
|
}
|
||||||
|
|
||||||
targetSolution.AddSolution(addedSolution, _prototypeManager);
|
targetSolution.AddSolution(toAdd, _prototypeManager);
|
||||||
|
overflowingSolution = targetSolution.SplitSolution(FixedPoint2.Max(FixedPoint2.Zero, targetSolution.Volume - overflowThreshold));
|
||||||
UpdateChemicals(targetUid, targetSolution, true);
|
UpdateChemicals(targetUid, targetSolution, true);
|
||||||
overflowingSolution = targetSolution.SplitSolution(FixedPoint2.Max(FixedPoint2.Zero,
|
|
||||||
targetSolution.Volume - overflowThreshold));
|
|
||||||
return true;
|
return true;
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -778,4 +840,8 @@ public sealed partial class SolutionContainerSystem : EntitySystem
|
|||||||
}
|
}
|
||||||
|
|
||||||
#endregion Thermal Energy and Temperature
|
#endregion Thermal Energy and Temperature
|
||||||
|
|
||||||
|
#region Event Handlers
|
||||||
|
|
||||||
|
#endregion Event Handlers
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -262,12 +262,6 @@ namespace Content.Shared.Chemistry.Reaction
|
|||||||
if (products.Count == 0)
|
if (products.Count == 0)
|
||||||
return true;
|
return true;
|
||||||
|
|
||||||
// remove excess product
|
|
||||||
// TODO spill excess?
|
|
||||||
var excessVolume = solution.Volume - maxVolume;
|
|
||||||
if (excessVolume > 0)
|
|
||||||
solution.RemoveSolution(excessVolume);
|
|
||||||
|
|
||||||
// Add any reactions associated with the new products. This may re-add reactions that were already iterated
|
// Add any reactions associated with the new products. This may re-add reactions that were already iterated
|
||||||
// over previously. The new product may mean the reactions are applicable again and need to be processed.
|
// over previously. The new product may mean the reactions are applicable again and need to be processed.
|
||||||
foreach (var product in products)
|
foreach (var product in products)
|
||||||
@@ -279,16 +273,10 @@ namespace Content.Shared.Chemistry.Reaction
|
|||||||
return true;
|
return true;
|
||||||
}
|
}
|
||||||
|
|
||||||
/// <summary>
|
|
||||||
/// Continually react a solution until no more reactions occur.
|
|
||||||
/// </summary>
|
|
||||||
public void FullyReactSolution(Solution solution, EntityUid owner) => FullyReactSolution(solution, owner, FixedPoint2.MaxValue, null);
|
|
||||||
|
|
||||||
/// <summary>
|
/// <summary>
|
||||||
/// Continually react a solution until no more reactions occur, with a volume constraint.
|
/// 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>
|
/// </summary>
|
||||||
public void FullyReactSolution(Solution solution, EntityUid owner, FixedPoint2 maxVolume, ReactionMixerComponent? mixerComponent)
|
public void FullyReactSolution(Solution solution, EntityUid owner, FixedPoint2 maxVolume, ReactionMixerComponent? mixerComponent = null)
|
||||||
{
|
{
|
||||||
// construct the initial set of reactions to check.
|
// construct the initial set of reactions to check.
|
||||||
SortedSet<ReactionPrototype> reactions = new();
|
SortedSet<ReactionPrototype> reactions = new();
|
||||||
|
|||||||
@@ -31,4 +31,4 @@
|
|||||||
Oxygen:
|
Oxygen:
|
||||||
amount: 1
|
amount: 1
|
||||||
products:
|
products:
|
||||||
SpaceLube: 3
|
SpaceLube: 5
|
||||||
|
|||||||
Reference in New Issue
Block a user