Allow solutions to store extra reagent data (#19323)
This commit is contained in:
@@ -1,4 +1,5 @@
|
|||||||
using Content.Shared.Chemistry.Components;
|
using Content.Shared.Chemistry.Components;
|
||||||
|
using Content.Shared.Chemistry.Reagent;
|
||||||
using Robust.Client.AutoGenerated;
|
using Robust.Client.AutoGenerated;
|
||||||
using Robust.Client.Console;
|
using Robust.Client.Console;
|
||||||
using Robust.Client.UserInterface.Controls;
|
using Robust.Client.UserInterface.Controls;
|
||||||
@@ -176,16 +177,16 @@ namespace Content.Client.Administration.UI.ManageSolutions
|
|||||||
/// <summary>
|
/// <summary>
|
||||||
/// Add a single reagent entry to the list
|
/// Add a single reagent entry to the list
|
||||||
/// </summary>
|
/// </summary>
|
||||||
private void AddReagentEntry(Solution.ReagentQuantity reagent)
|
private void AddReagentEntry(ReagentQuantity reagentQuantity)
|
||||||
{
|
{
|
||||||
var box = new BoxContainer();
|
var box = new BoxContainer();
|
||||||
var spin = new FloatSpinBox(1, 2);
|
var spin = new FloatSpinBox(1, 2);
|
||||||
|
|
||||||
spin.Value = reagent.Quantity.Float();
|
spin.Value = reagentQuantity.Quantity.Float();
|
||||||
spin.OnValueChanged += (args) => SetReagent(args, reagent.ReagentId);
|
spin.OnValueChanged += (args) => SetReagent(args, reagentQuantity.Reagent.Prototype);
|
||||||
spin.HorizontalExpand = true;
|
spin.HorizontalExpand = true;
|
||||||
|
|
||||||
box.AddChild(new Label() { Text = reagent.ReagentId , HorizontalExpand = true});
|
box.AddChild(new Label() { Text = reagentQuantity.Reagent.Prototype , HorizontalExpand = true});
|
||||||
box.AddChild(spin);
|
box.AddChild(spin);
|
||||||
|
|
||||||
ReagentList.AddChild(box);
|
ReagentList.AddChild(box);
|
||||||
@@ -194,18 +195,18 @@ namespace Content.Client.Administration.UI.ManageSolutions
|
|||||||
/// <summary>
|
/// <summary>
|
||||||
/// Execute a command to modify the reagents in the solution.
|
/// Execute a command to modify the reagents in the solution.
|
||||||
/// </summary>
|
/// </summary>
|
||||||
private void SetReagent(FloatSpinBox.FloatSpinBoxEventArgs args, string reagentId)
|
private void SetReagent(FloatSpinBox.FloatSpinBoxEventArgs args, string prototype)
|
||||||
{
|
{
|
||||||
if (_solutions == null || _selectedSolution == null)
|
if (_solutions == null || _selectedSolution == null)
|
||||||
return;
|
return;
|
||||||
|
|
||||||
var current = _solutions[_selectedSolution].GetReagentQuantity(reagentId);
|
var current = _solutions[_selectedSolution].GetTotalPrototypeQuantity(prototype);
|
||||||
var delta = args.Value - current.Float();
|
var delta = args.Value - current.Float();
|
||||||
|
|
||||||
if (MathF.Abs(delta) < 0.01)
|
if (MathF.Abs(delta) < 0.01)
|
||||||
return;
|
return;
|
||||||
|
|
||||||
var command = $"addreagent {_target} {_selectedSolution} {reagentId} {delta}";
|
var command = $"addreagent {_target} {_selectedSolution} {prototype} {delta}";
|
||||||
_consoleHost.ExecuteCommand(command);
|
_consoleHost.ExecuteCommand(command);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|||||||
@@ -11,6 +11,7 @@ using Robust.Shared.Prototypes;
|
|||||||
using Robust.Shared.Utility;
|
using Robust.Shared.Utility;
|
||||||
using System.Linq;
|
using System.Linq;
|
||||||
using System.Numerics;
|
using System.Numerics;
|
||||||
|
using Content.Shared.FixedPoint;
|
||||||
using static Robust.Client.UserInterface.Controls.BoxContainer;
|
using static Robust.Client.UserInterface.Controls.BoxContainer;
|
||||||
|
|
||||||
namespace Content.Client.Chemistry.UI
|
namespace Content.Client.Chemistry.UI
|
||||||
@@ -87,7 +88,7 @@ namespace Content.Client.Chemistry.UI
|
|||||||
Tabs.SetTabTitle(1, Loc.GetString("chem-master-window-output-tab"));
|
Tabs.SetTabTitle(1, Loc.GetString("chem-master-window-output-tab"));
|
||||||
}
|
}
|
||||||
|
|
||||||
private ReagentButton MakeReagentButton(string text, ChemMasterReagentAmount amount, string id, bool isBuffer, string styleClass)
|
private ReagentButton MakeReagentButton(string text, ChemMasterReagentAmount amount, ReagentId id, bool isBuffer, string styleClass)
|
||||||
{
|
{
|
||||||
var button = new ReagentButton(text, amount, id, isBuffer, styleClass);
|
var button = new ReagentButton(text, amount, id, isBuffer, styleClass);
|
||||||
button.OnPressed += args
|
button.OnPressed += args
|
||||||
@@ -112,11 +113,11 @@ namespace Content.Client.Chemistry.UI
|
|||||||
|
|
||||||
InputEjectButton.Disabled = castState.InputContainerInfo is null;
|
InputEjectButton.Disabled = castState.InputContainerInfo is null;
|
||||||
OutputEjectButton.Disabled = output is null;
|
OutputEjectButton.Disabled = output is null;
|
||||||
CreateBottleButton.Disabled = output is null || !output.HoldsReagents;
|
CreateBottleButton.Disabled = output?.Reagents == null;
|
||||||
CreatePillButton.Disabled = output is null || output.HoldsReagents;
|
CreatePillButton.Disabled = output?.Entities == null;
|
||||||
|
|
||||||
var remainingCapacity = output is null ? 0 : (output.MaxVolume - output.CurrentVolume).Int();
|
var remainingCapacity = output is null ? 0 : (output.MaxVolume - output.CurrentVolume).Int();
|
||||||
var holdsReagents = output?.HoldsReagents ?? false;
|
var holdsReagents = output?.Reagents != null;
|
||||||
var pillNumberMax = holdsReagents ? 0 : remainingCapacity;
|
var pillNumberMax = holdsReagents ? 0 : remainingCapacity;
|
||||||
var bottleAmountMax = holdsReagents ? remainingCapacity : 0;
|
var bottleAmountMax = holdsReagents ? remainingCapacity : 0;
|
||||||
|
|
||||||
@@ -139,13 +140,10 @@ namespace Content.Client.Chemistry.UI
|
|||||||
{
|
{
|
||||||
if (state.BufferCurrentVolume == 0)
|
if (state.BufferCurrentVolume == 0)
|
||||||
return "";
|
return "";
|
||||||
else
|
|
||||||
{
|
|
||||||
var reagent = state.BufferReagents.OrderBy(r => r.Quantity).First();
|
|
||||||
_prototypeManager.TryIndex(reagent.ReagentId, out ReagentPrototype? proto);
|
|
||||||
return proto?.LocalizedName ?? "";
|
|
||||||
}
|
|
||||||
|
|
||||||
|
var reagent = state.BufferReagents.OrderBy(r => r.Quantity).First().Reagent;
|
||||||
|
_prototypeManager.TryIndex(reagent.Prototype, out ReagentPrototype? proto);
|
||||||
|
return proto?.LocalizedName ?? "";
|
||||||
}
|
}
|
||||||
|
|
||||||
/// <summary>
|
/// <summary>
|
||||||
@@ -184,10 +182,10 @@ namespace Content.Client.Chemistry.UI
|
|||||||
};
|
};
|
||||||
bufferHBox.AddChild(bufferVol);
|
bufferHBox.AddChild(bufferVol);
|
||||||
|
|
||||||
foreach (var reagent in state.BufferReagents)
|
foreach (var (reagent, quantity) in state.BufferReagents)
|
||||||
{
|
{
|
||||||
// Try to get the prototype for the given reagent. This gives us its name.
|
// Try to get the prototype for the given reagent. This gives us its name.
|
||||||
_prototypeManager.TryIndex(reagent.ReagentId, out ReagentPrototype? proto);
|
_prototypeManager.TryIndex(reagent.Prototype, out ReagentPrototype? proto);
|
||||||
var name = proto?.LocalizedName ?? Loc.GetString("chem-master-window-unknown-reagent-text");
|
var name = proto?.LocalizedName ?? Loc.GetString("chem-master-window-unknown-reagent-text");
|
||||||
|
|
||||||
if (proto != null)
|
if (proto != null)
|
||||||
@@ -200,20 +198,20 @@ namespace Content.Client.Chemistry.UI
|
|||||||
new Label {Text = $"{name}: "},
|
new Label {Text = $"{name}: "},
|
||||||
new Label
|
new Label
|
||||||
{
|
{
|
||||||
Text = $"{reagent.Quantity}u",
|
Text = $"{quantity}u",
|
||||||
StyleClasses = {StyleNano.StyleClassLabelSecondaryColor}
|
StyleClasses = {StyleNano.StyleClassLabelSecondaryColor}
|
||||||
},
|
},
|
||||||
|
|
||||||
// Padding
|
// Padding
|
||||||
new Control {HorizontalExpand = true},
|
new Control {HorizontalExpand = true},
|
||||||
|
|
||||||
MakeReagentButton("1", ChemMasterReagentAmount.U1, reagent.ReagentId, true, StyleBase.ButtonOpenRight),
|
MakeReagentButton("1", ChemMasterReagentAmount.U1, reagent, true, StyleBase.ButtonOpenRight),
|
||||||
MakeReagentButton("5", ChemMasterReagentAmount.U5, reagent.ReagentId, true, StyleBase.ButtonOpenBoth),
|
MakeReagentButton("5", ChemMasterReagentAmount.U5, reagent, true, StyleBase.ButtonOpenBoth),
|
||||||
MakeReagentButton("10", ChemMasterReagentAmount.U10, reagent.ReagentId, true, StyleBase.ButtonOpenBoth),
|
MakeReagentButton("10", ChemMasterReagentAmount.U10, reagent, true, StyleBase.ButtonOpenBoth),
|
||||||
MakeReagentButton("25", ChemMasterReagentAmount.U25, reagent.ReagentId, true, StyleBase.ButtonOpenBoth),
|
MakeReagentButton("25", ChemMasterReagentAmount.U25, reagent, true, StyleBase.ButtonOpenBoth),
|
||||||
MakeReagentButton("50", ChemMasterReagentAmount.U50, reagent.ReagentId, true, StyleBase.ButtonOpenBoth),
|
MakeReagentButton("50", ChemMasterReagentAmount.U50, reagent, true, StyleBase.ButtonOpenBoth),
|
||||||
MakeReagentButton("100", ChemMasterReagentAmount.U100, reagent.ReagentId, true, StyleBase.ButtonOpenBoth),
|
MakeReagentButton("100", ChemMasterReagentAmount.U100, reagent, true, StyleBase.ButtonOpenBoth),
|
||||||
MakeReagentButton(Loc.GetString("chem-master-window-buffer-all-amount"), ChemMasterReagentAmount.All, reagent.ReagentId, true, StyleBase.ButtonOpenLeft),
|
MakeReagentButton(Loc.GetString("chem-master-window-buffer-all-amount"), ChemMasterReagentAmount.All, reagent, true, StyleBase.ButtonOpenLeft),
|
||||||
}
|
}
|
||||||
});
|
});
|
||||||
}
|
}
|
||||||
@@ -248,20 +246,29 @@ namespace Content.Client.Chemistry.UI
|
|||||||
}
|
}
|
||||||
});
|
});
|
||||||
|
|
||||||
var contents = info.Contents
|
IEnumerable<(string Name, ReagentId Id, FixedPoint2 Quantity)> contents;
|
||||||
.Select(lineItem =>
|
|
||||||
{
|
|
||||||
if (!info.HoldsReagents)
|
|
||||||
return (lineItem.Id, lineItem.Id, lineItem.Quantity);
|
|
||||||
|
|
||||||
// Try to get the prototype for the given reagent. This gives us its name.
|
if (info.Entities != null)
|
||||||
_prototypeManager.TryIndex(lineItem.Id, out ReagentPrototype? proto);
|
{
|
||||||
var name = proto?.LocalizedName
|
contents = info.Entities.Select(x => (x.Id, default(ReagentId), x.Quantity));
|
||||||
?? Loc.GetString("chem-master-window-unknown-reagent-text");
|
}
|
||||||
|
else if (info.Reagents != null)
|
||||||
|
{
|
||||||
|
contents = info.Reagents.Select(x =>
|
||||||
|
{
|
||||||
|
_prototypeManager.TryIndex(x.Reagent.Prototype, out ReagentPrototype? proto);
|
||||||
|
var name = proto?.LocalizedName
|
||||||
|
?? Loc.GetString("chem-master-window-unknown-reagent-text");
|
||||||
|
|
||||||
|
return (name, Id: x.Reagent, x.Quantity);
|
||||||
|
})
|
||||||
|
.OrderBy(r => r.Item1);
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
return (name, lineItem.Id, lineItem.Quantity);
|
|
||||||
})
|
|
||||||
.OrderBy(r => r.Item1);
|
|
||||||
|
|
||||||
foreach (var (name, id, quantity) in contents)
|
foreach (var (name, id, quantity) in contents)
|
||||||
{
|
{
|
||||||
@@ -326,8 +333,8 @@ namespace Content.Client.Chemistry.UI
|
|||||||
{
|
{
|
||||||
public ChemMasterReagentAmount Amount { get; set; }
|
public ChemMasterReagentAmount Amount { get; set; }
|
||||||
public bool IsBuffer = true;
|
public bool IsBuffer = true;
|
||||||
public string Id { get; set; }
|
public ReagentId Id { get; set; }
|
||||||
public ReagentButton(string text, ChemMasterReagentAmount amount, string id, bool isBuffer, string styleClass)
|
public ReagentButton(string text, ChemMasterReagentAmount amount, ReagentId id, bool isBuffer, string styleClass)
|
||||||
{
|
{
|
||||||
AddStyleClass(styleClass);
|
AddStyleClass(styleClass);
|
||||||
Text = text;
|
Text = text;
|
||||||
|
|||||||
@@ -48,17 +48,17 @@ namespace Content.Client.Chemistry.UI
|
|||||||
/// Update the button grid of reagents which can be dispensed.
|
/// Update the button grid of reagents which can be dispensed.
|
||||||
/// </summary>
|
/// </summary>
|
||||||
/// <param name="inventory">Reagents which can be dispensed by this dispenser</param>
|
/// <param name="inventory">Reagents which can be dispensed by this dispenser</param>
|
||||||
public void UpdateReagentsList(List<string> inventory)
|
public void UpdateReagentsList(List<ReagentId> inventory)
|
||||||
{
|
{
|
||||||
if (ChemicalList == null) return;
|
if (ChemicalList == null)
|
||||||
if (inventory == null) return;
|
return;
|
||||||
|
|
||||||
ChemicalList.Children.Clear();
|
ChemicalList.Children.Clear();
|
||||||
|
|
||||||
foreach (var entry in inventory
|
foreach (var entry in inventory
|
||||||
.OrderBy(r => {_prototypeManager.TryIndex(r, out ReagentPrototype? p); return p?.LocalizedName;}))
|
.OrderBy(r => {_prototypeManager.TryIndex(r.Prototype, out ReagentPrototype? p); return p?.LocalizedName;}))
|
||||||
{
|
{
|
||||||
var localizedName = _prototypeManager.TryIndex(entry, out ReagentPrototype? p)
|
var localizedName = _prototypeManager.TryIndex(entry.Prototype, out ReagentPrototype? p)
|
||||||
? p.LocalizedName
|
? p.LocalizedName
|
||||||
: Loc.GetString("reagent-dispenser-window-reagent-name-not-found-text");
|
: Loc.GetString("reagent-dispenser-window-reagent-name-not-found-text");
|
||||||
|
|
||||||
@@ -123,7 +123,7 @@ namespace Content.Client.Chemistry.UI
|
|||||||
/// <param name="state">State data for the dispenser.</param>
|
/// <param name="state">State data for the dispenser.</param>
|
||||||
/// <param name="highlightedReagentId">Prototype ID of the reagent whose dispense button is currently being mouse hovered,
|
/// <param name="highlightedReagentId">Prototype ID of the reagent whose dispense button is currently being mouse hovered,
|
||||||
/// or null if no button is being hovered.</param>
|
/// or null if no button is being hovered.</param>
|
||||||
public void UpdateContainerInfo(ReagentDispenserBoundUserInterfaceState state, string? highlightedReagentId = null)
|
public void UpdateContainerInfo(ReagentDispenserBoundUserInterfaceState state, ReagentId? highlightedReagentId = null)
|
||||||
{
|
{
|
||||||
ContainerInfo.Children.Clear();
|
ContainerInfo.Children.Clear();
|
||||||
|
|
||||||
@@ -147,22 +147,22 @@ namespace Content.Client.Chemistry.UI
|
|||||||
}
|
}
|
||||||
});
|
});
|
||||||
|
|
||||||
foreach (var reagent in state.OutputContainer.Contents)
|
foreach (var (reagent, quantity) in state.OutputContainer.Reagents!)
|
||||||
{
|
{
|
||||||
// Try get to the prototype for the given reagent. This gives us its name.
|
// Try get to the prototype for the given reagent. This gives us its name.
|
||||||
var localizedName = _prototypeManager.TryIndex(reagent.Id, out ReagentPrototype? p)
|
var localizedName = _prototypeManager.TryIndex(reagent.Prototype, out ReagentPrototype? p)
|
||||||
? p.LocalizedName
|
? p.LocalizedName
|
||||||
: Loc.GetString("reagent-dispenser-window-reagent-name-not-found-text");
|
: Loc.GetString("reagent-dispenser-window-reagent-name-not-found-text");
|
||||||
|
|
||||||
var nameLabel = new Label {Text = $"{localizedName}: "};
|
var nameLabel = new Label {Text = $"{localizedName}: "};
|
||||||
var quantityLabel = new Label
|
var quantityLabel = new Label
|
||||||
{
|
{
|
||||||
Text = Loc.GetString("reagent-dispenser-window-quantity-label-text", ("quantity", reagent.Quantity)),
|
Text = Loc.GetString("reagent-dispenser-window-quantity-label-text", ("quantity", quantity)),
|
||||||
StyleClasses = {StyleNano.StyleClassLabelSecondaryColor},
|
StyleClasses = {StyleNano.StyleClassLabelSecondaryColor},
|
||||||
};
|
};
|
||||||
|
|
||||||
// Check if the reagent is being moused over. If so, color it green.
|
// Check if the reagent is being moused over. If so, color it green.
|
||||||
if (reagent.Id == highlightedReagentId) {
|
if (reagent == highlightedReagentId) {
|
||||||
nameLabel.SetOnlyStyleClass(StyleNano.StyleClassPowerStateGood);
|
nameLabel.SetOnlyStyleClass(StyleNano.StyleClassPowerStateGood);
|
||||||
quantityLabel.SetOnlyStyleClass(StyleNano.StyleClassPowerStateGood);
|
quantityLabel.SetOnlyStyleClass(StyleNano.StyleClassPowerStateGood);
|
||||||
}
|
}
|
||||||
@@ -181,9 +181,9 @@ namespace Content.Client.Chemistry.UI
|
|||||||
}
|
}
|
||||||
|
|
||||||
public sealed class DispenseReagentButton : Button {
|
public sealed class DispenseReagentButton : Button {
|
||||||
public string ReagentId { get; }
|
public ReagentId ReagentId { get; }
|
||||||
|
|
||||||
public DispenseReagentButton(string reagentId, string text)
|
public DispenseReagentButton(ReagentId reagentId, string text)
|
||||||
{
|
{
|
||||||
ReagentId = reagentId;
|
ReagentId = reagentId;
|
||||||
Text = text;
|
Text = text;
|
||||||
|
|||||||
@@ -83,7 +83,7 @@ namespace Content.Client.Kitchen.UI
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
private void RefreshContentsDisplay(IList<Solution.ReagentQuantity>? reagents, IReadOnlyList<EntityUid> containedSolids, bool isBeakerAttached)
|
private void RefreshContentsDisplay(IList<ReagentQuantity>? reagents, IReadOnlyList<EntityUid> containedSolids, bool isBeakerAttached)
|
||||||
{
|
{
|
||||||
//Refresh chamber contents
|
//Refresh chamber contents
|
||||||
_chamberVisualContents.Clear();
|
_chamberVisualContents.Clear();
|
||||||
@@ -118,9 +118,11 @@ namespace Content.Client.Kitchen.UI
|
|||||||
}
|
}
|
||||||
else
|
else
|
||||||
{
|
{
|
||||||
foreach (var reagent in reagents)
|
foreach (var (reagent, quantity) in reagents)
|
||||||
{
|
{
|
||||||
var reagentName = _prototypeManager.TryIndex(reagent.ReagentId, out ReagentPrototype? proto) ? Loc.GetString($"{reagent.Quantity} {proto.LocalizedName}") : "???";
|
var reagentName = _prototypeManager.TryIndex(reagent.Prototype, out ReagentPrototype? proto)
|
||||||
|
? Loc.GetString($"{quantity} {proto.LocalizedName}")
|
||||||
|
: "???";
|
||||||
BeakerContentBox.BoxContents.AddItem(reagentName);
|
BeakerContentBox.BoxContents.AddItem(reagentName);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -1,4 +1,5 @@
|
|||||||
using Content.Shared.Chemistry.Components;
|
using Content.Shared.Chemistry.Components;
|
||||||
|
using Content.Shared.Chemistry.Reagent;
|
||||||
using Content.Shared.Kitchen.Components;
|
using Content.Shared.Kitchen.Components;
|
||||||
using JetBrains.Annotations;
|
using JetBrains.Annotations;
|
||||||
using Robust.Client.GameObjects;
|
using Robust.Client.GameObjects;
|
||||||
@@ -17,7 +18,7 @@ namespace Content.Client.Kitchen.UI
|
|||||||
private readonly Dictionary<int, EntityUid> _solids = new();
|
private readonly Dictionary<int, EntityUid> _solids = new();
|
||||||
|
|
||||||
[ViewVariables]
|
[ViewVariables]
|
||||||
private readonly Dictionary<int, Solution.ReagentQuantity> _reagents = new();
|
private readonly Dictionary<int, ReagentQuantity> _reagents = new();
|
||||||
|
|
||||||
public MicrowaveBoundUserInterface(EntityUid owner, Enum uiKey) : base(owner, uiKey)
|
public MicrowaveBoundUserInterface(EntityUid owner, Enum uiKey) : base(owner, uiKey)
|
||||||
{
|
{
|
||||||
|
|||||||
30
Content.IntegrationTests/Tests/Chemistry/ReagentDataTest.cs
Normal file
30
Content.IntegrationTests/Tests/Chemistry/ReagentDataTest.cs
Normal file
@@ -0,0 +1,30 @@
|
|||||||
|
using Content.IntegrationTests.Tests.Interaction;
|
||||||
|
using Content.Shared.Chemistry.Reagent;
|
||||||
|
using Robust.Shared.Reflection;
|
||||||
|
using Robust.Shared.Serialization;
|
||||||
|
using Robust.Shared.Utility;
|
||||||
|
|
||||||
|
namespace Content.IntegrationTests.Tests.Chemistry;
|
||||||
|
|
||||||
|
[TestFixture]
|
||||||
|
[TestOf(typeof(ReagentData))]
|
||||||
|
public sealed class ReagentDataTest : InteractionTest
|
||||||
|
{
|
||||||
|
[Test]
|
||||||
|
public async Task ReagentDataIsSerializable()
|
||||||
|
{
|
||||||
|
await using var pair = await PoolManager.GetServerClient();
|
||||||
|
var reflection = pair.Server.ResolveDependency<IReflectionManager>();
|
||||||
|
|
||||||
|
Assert.Multiple(() =>
|
||||||
|
{
|
||||||
|
foreach (var instance in reflection.GetAllChildren(typeof(ReagentData)))
|
||||||
|
{
|
||||||
|
Assert.That(instance.HasCustomAttribute<NetSerializableAttribute>(), $"{instance} must have the NetSerializable attribute.");
|
||||||
|
Assert.That(instance.HasCustomAttribute<SerializableAttribute>(), $"{instance} must have the serializable attribute.");
|
||||||
|
}
|
||||||
|
});
|
||||||
|
|
||||||
|
await pair.CleanReturnAsync();
|
||||||
|
}
|
||||||
|
}
|
||||||
@@ -73,8 +73,8 @@ public sealed class SolutionSystemTests
|
|||||||
Assert.That(containerSystem
|
Assert.That(containerSystem
|
||||||
.TryAddSolution(beaker, solution, oilAdded));
|
.TryAddSolution(beaker, solution, oilAdded));
|
||||||
|
|
||||||
solution.TryGetReagent("Water", out var water);
|
var water = solution.GetTotalPrototypeQuantity("Water");
|
||||||
solution.TryGetReagent("Oil", out var oil);
|
var oil = solution.GetTotalPrototypeQuantity("Oil");
|
||||||
Assert.Multiple(() =>
|
Assert.Multiple(() =>
|
||||||
{
|
{
|
||||||
Assert.That(water, Is.EqualTo(waterQuantity));
|
Assert.That(water, Is.EqualTo(waterQuantity));
|
||||||
@@ -118,8 +118,8 @@ public sealed class SolutionSystemTests
|
|||||||
Assert.That(containerSystem
|
Assert.That(containerSystem
|
||||||
.TryAddSolution(beaker, solution, oilAdded), Is.False);
|
.TryAddSolution(beaker, solution, oilAdded), Is.False);
|
||||||
|
|
||||||
solution.TryGetReagent("Water", out var water);
|
var water = solution.GetTotalPrototypeQuantity("Water");
|
||||||
solution.TryGetReagent("Oil", out var oil);
|
var oil = solution.GetTotalPrototypeQuantity("Oil");
|
||||||
Assert.Multiple(() =>
|
Assert.Multiple(() =>
|
||||||
{
|
{
|
||||||
Assert.That(water, Is.EqualTo(waterQuantity));
|
Assert.That(water, Is.EqualTo(waterQuantity));
|
||||||
@@ -168,15 +168,15 @@ public sealed class SolutionSystemTests
|
|||||||
{
|
{
|
||||||
Assert.That(solution.Volume, Is.EqualTo(FixedPoint2.New(threshold)));
|
Assert.That(solution.Volume, Is.EqualTo(FixedPoint2.New(threshold)));
|
||||||
|
|
||||||
solution.TryGetReagent("Water", out var waterMix);
|
var waterMix = solution.GetTotalPrototypeQuantity("Water");
|
||||||
solution.TryGetReagent("Oil", out var oilMix);
|
var oilMix = solution.GetTotalPrototypeQuantity("Oil");
|
||||||
Assert.That(waterMix, Is.EqualTo(FixedPoint2.New(threshold / (ratio + 1))));
|
Assert.That(waterMix, Is.EqualTo(FixedPoint2.New(threshold / (ratio + 1))));
|
||||||
Assert.That(oilMix, Is.EqualTo(FixedPoint2.New(threshold / (ratio + 1) * ratio)));
|
Assert.That(oilMix, Is.EqualTo(FixedPoint2.New(threshold / (ratio + 1) * ratio)));
|
||||||
|
|
||||||
Assert.That(overflowingSolution.Volume, Is.EqualTo(FixedPoint2.New(80)));
|
Assert.That(overflowingSolution.Volume, Is.EqualTo(FixedPoint2.New(80)));
|
||||||
|
|
||||||
overflowingSolution.TryGetReagent("Water", out var waterOverflow);
|
var waterOverflow = overflowingSolution.GetTotalPrototypeQuantity("Water");
|
||||||
overflowingSolution.TryGetReagent("Oil", out var oilOverFlow);
|
var oilOverFlow = overflowingSolution.GetTotalPrototypeQuantity("Oil");
|
||||||
Assert.That(waterOverflow, Is.EqualTo(waterQuantity - waterMix));
|
Assert.That(waterOverflow, Is.EqualTo(waterQuantity - waterMix));
|
||||||
Assert.That(oilOverFlow, Is.EqualTo(oilQuantity - oilMix));
|
Assert.That(oilOverFlow, Is.EqualTo(oilQuantity - oilMix));
|
||||||
});
|
});
|
||||||
|
|||||||
@@ -79,9 +79,9 @@ namespace Content.IntegrationTests.Tests.Chemistry
|
|||||||
var foundProductsMap = reactionPrototype.Products
|
var foundProductsMap = reactionPrototype.Products
|
||||||
.Concat(reactionPrototype.Reactants.Where(x => x.Value.Catalyst).ToDictionary(x => x.Key, x => x.Value.Amount))
|
.Concat(reactionPrototype.Reactants.Where(x => x.Value.Catalyst).ToDictionary(x => x.Key, x => x.Value.Amount))
|
||||||
.ToDictionary(x => x, _ => false);
|
.ToDictionary(x => x, _ => false);
|
||||||
foreach (var reagent in component.Contents)
|
foreach (var (reagent, quantity) in component.Contents)
|
||||||
{
|
{
|
||||||
Assert.That(foundProductsMap.TryFirstOrNull(x => x.Key.Key == reagent.ReagentId && x.Key.Value == reagent.Quantity, out var foundProduct));
|
Assert.That(foundProductsMap.TryFirstOrNull(x => x.Key.Key == reagent.Prototype && x.Key.Value == quantity, out var foundProduct));
|
||||||
foundProductsMap[foundProduct.Value.Key] = true;
|
foundProductsMap[foundProduct.Value.Key] = true;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|||||||
@@ -62,7 +62,7 @@ namespace Content.Server.Administration.Commands
|
|||||||
if (quantityFloat > 0)
|
if (quantityFloat > 0)
|
||||||
EntitySystem.Get<SolutionContainerSystem>().TryAddReagent(uid, solution, args[2], quantity, out var _);
|
EntitySystem.Get<SolutionContainerSystem>().TryAddReagent(uid, solution, args[2], quantity, out var _);
|
||||||
else
|
else
|
||||||
EntitySystem.Get<SolutionContainerSystem>().TryRemoveReagent(uid, solution, args[2], quantity);
|
EntitySystem.Get<SolutionContainerSystem>().RemoveReagent(uid, solution, args[2], quantity);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -59,7 +59,7 @@ public sealed class SolutionCommand : ToolshedCommand
|
|||||||
}
|
}
|
||||||
else if (amount < 0)
|
else if (amount < 0)
|
||||||
{
|
{
|
||||||
_solutionContainer.TryRemoveReagent(input.Owner, input.Solution, name.Value.ID, -amount);
|
_solutionContainer.RemoveReagent(input.Owner, input.Solution, name.Value.ID, -amount);
|
||||||
}
|
}
|
||||||
|
|
||||||
return input;
|
return input;
|
||||||
|
|||||||
@@ -1,5 +1,7 @@
|
|||||||
using Content.Server.Body.Systems;
|
using Content.Server.Body.Systems;
|
||||||
using Content.Server.Nutrition.EntitySystems;
|
using Content.Server.Nutrition.EntitySystems;
|
||||||
|
using Content.Shared.Chemistry.Components;
|
||||||
|
using Content.Shared.Chemistry.Reagent;
|
||||||
using Content.Shared.FixedPoint;
|
using Content.Shared.FixedPoint;
|
||||||
using Content.Shared.Whitelist;
|
using Content.Shared.Whitelist;
|
||||||
|
|
||||||
@@ -46,14 +48,12 @@ namespace Content.Server.Body.Components
|
|||||||
/// </summary>
|
/// </summary>
|
||||||
public sealed class ReagentDelta
|
public sealed class ReagentDelta
|
||||||
{
|
{
|
||||||
public readonly string ReagentId;
|
public readonly ReagentQuantity ReagentQuantity;
|
||||||
public readonly FixedPoint2 Quantity;
|
|
||||||
public float Lifetime { get; private set; }
|
public float Lifetime { get; private set; }
|
||||||
|
|
||||||
public ReagentDelta(string reagentId, FixedPoint2 quantity)
|
public ReagentDelta(ReagentQuantity reagentQuantity)
|
||||||
{
|
{
|
||||||
ReagentId = reagentId;
|
ReagentQuantity = reagentQuantity;
|
||||||
Quantity = quantity;
|
|
||||||
Lifetime = 0.0f;
|
Lifetime = 0.0f;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|||||||
@@ -274,9 +274,9 @@ public sealed class BloodstreamSystem : EntitySystem
|
|||||||
for (var i = component.ChemicalSolution.Contents.Count - 1; i >= 0; i--)
|
for (var i = component.ChemicalSolution.Contents.Count - 1; i >= 0; i--)
|
||||||
{
|
{
|
||||||
var (reagentId, _) = component.ChemicalSolution.Contents[i];
|
var (reagentId, _) = component.ChemicalSolution.Contents[i];
|
||||||
if (reagentId != excludedReagentID)
|
if (reagentId.Prototype != excludedReagentID)
|
||||||
{
|
{
|
||||||
_solutionContainerSystem.TryRemoveReagent(uid, component.ChemicalSolution, reagentId, quantity);
|
_solutionContainerSystem.RemoveReagent(uid, component.ChemicalSolution, reagentId, quantity);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|||||||
@@ -128,9 +128,9 @@ namespace Content.Server.Body.Systems
|
|||||||
_random.Shuffle(list);
|
_random.Shuffle(list);
|
||||||
|
|
||||||
int reagents = 0;
|
int reagents = 0;
|
||||||
foreach (var reagent in list)
|
foreach (var (reagent, quantity) in list)
|
||||||
{
|
{
|
||||||
if (!_prototypeManager.TryIndex<ReagentPrototype>(reagent.ReagentId, out var proto))
|
if (!_prototypeManager.TryIndex<ReagentPrototype>(reagent.Prototype, out var proto))
|
||||||
continue;
|
continue;
|
||||||
|
|
||||||
var mostToRemove = FixedPoint2.Zero;
|
var mostToRemove = FixedPoint2.Zero;
|
||||||
@@ -138,7 +138,7 @@ namespace Content.Server.Body.Systems
|
|||||||
{
|
{
|
||||||
if (meta.RemoveEmpty)
|
if (meta.RemoveEmpty)
|
||||||
{
|
{
|
||||||
_solutionContainerSystem.TryRemoveReagent(solutionEntityUid.Value, solution, reagent.ReagentId,
|
_solutionContainerSystem.RemoveReagent(solutionEntityUid.Value, solution, reagent,
|
||||||
FixedPoint2.New(1));
|
FixedPoint2.New(1));
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -168,7 +168,7 @@ namespace Content.Server.Body.Systems
|
|||||||
|
|
||||||
mostToRemove *= group.MetabolismRateModifier;
|
mostToRemove *= group.MetabolismRateModifier;
|
||||||
|
|
||||||
mostToRemove = FixedPoint2.Clamp(mostToRemove, 0, reagent.Quantity);
|
mostToRemove = FixedPoint2.Clamp(mostToRemove, 0, quantity);
|
||||||
|
|
||||||
float scale = (float) mostToRemove / (float) entry.MetabolismRate;
|
float scale = (float) mostToRemove / (float) entry.MetabolismRate;
|
||||||
|
|
||||||
@@ -204,8 +204,7 @@ namespace Content.Server.Body.Systems
|
|||||||
// remove a certain amount of reagent
|
// remove a certain amount of reagent
|
||||||
if (mostToRemove > FixedPoint2.Zero)
|
if (mostToRemove > FixedPoint2.Zero)
|
||||||
{
|
{
|
||||||
_solutionContainerSystem.TryRemoveReagent(solutionEntityUid.Value, solution, reagent.ReagentId,
|
_solutionContainerSystem.RemoveReagent(solutionEntityUid.Value, solution, reagent, mostToRemove);
|
||||||
mostToRemove);
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -45,14 +45,13 @@ namespace Content.Server.Body.Systems
|
|||||||
delta.Increment(stomach.UpdateInterval);
|
delta.Increment(stomach.UpdateInterval);
|
||||||
if (delta.Lifetime > stomach.DigestionDelay)
|
if (delta.Lifetime > stomach.DigestionDelay)
|
||||||
{
|
{
|
||||||
if (stomachSolution.TryGetReagent(delta.ReagentId, out var quant))
|
if (stomachSolution.TryGetReagent(delta.ReagentQuantity.Reagent, out var reagent))
|
||||||
{
|
{
|
||||||
if (quant > delta.Quantity)
|
if (reagent.Quantity > delta.ReagentQuantity.Quantity)
|
||||||
quant = delta.Quantity;
|
reagent = new(reagent.Reagent, delta.ReagentQuantity.Quantity);
|
||||||
|
|
||||||
_solutionContainerSystem.TryRemoveReagent((stomach).Owner, stomachSolution,
|
_solutionContainerSystem.RemoveReagent((stomach).Owner, stomachSolution, reagent);
|
||||||
delta.ReagentId, quant);
|
transferSolution.AddReagent(reagent);
|
||||||
transferSolution.AddReagent(delta.ReagentId, quant);
|
|
||||||
}
|
}
|
||||||
|
|
||||||
queue.Add(delta);
|
queue.Add(delta);
|
||||||
@@ -116,7 +115,7 @@ namespace Content.Server.Body.Systems
|
|||||||
// Add each reagent to ReagentDeltas. Used to track how long each reagent has been in the stomach
|
// Add each reagent to ReagentDeltas. Used to track how long each reagent has been in the stomach
|
||||||
foreach (var reagent in solution.Contents)
|
foreach (var reagent in solution.Contents)
|
||||||
{
|
{
|
||||||
stomach.ReagentDeltas.Add(new StomachComponent.ReagentDelta(reagent.ReagentId, reagent.Quantity));
|
stomach.ReagentDeltas.Add(new StomachComponent.ReagentDelta(reagent));
|
||||||
}
|
}
|
||||||
|
|
||||||
return true;
|
return true;
|
||||||
|
|||||||
@@ -824,10 +824,10 @@ namespace Content.Server.Botany.Systems
|
|||||||
if (solution.Volume > 0 && component.MutationLevel < 25)
|
if (solution.Volume > 0 && component.MutationLevel < 25)
|
||||||
{
|
{
|
||||||
var amt = FixedPoint2.New(1);
|
var amt = FixedPoint2.New(1);
|
||||||
foreach (var (reagentId, quantity) in _solutionSystem.RemoveEachReagent(uid, solution, amt))
|
foreach (var entry in _solutionSystem.RemoveEachReagent(uid, solution, amt))
|
||||||
{
|
{
|
||||||
var reagentProto = _prototype.Index<ReagentPrototype>(reagentId);
|
var reagentProto = _prototype.Index<ReagentPrototype>(entry.Reagent.Prototype);
|
||||||
reagentProto.ReactionPlant(uid, new Solution.ReagentQuantity(reagentId, quantity), solution);
|
reagentProto.ReactionPlant(uid, entry, solution);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|||||||
@@ -110,11 +110,13 @@ public sealed class PricingSystem : EntitySystem
|
|||||||
|
|
||||||
foreach (var solution in component.Solutions.Values)
|
foreach (var solution in component.Solutions.Values)
|
||||||
{
|
{
|
||||||
foreach (var reagent in solution.Contents)
|
foreach (var (reagent, quantity) in solution.Contents)
|
||||||
{
|
{
|
||||||
if (!_prototypeManager.TryIndex<ReagentPrototype>(reagent.ReagentId, out var reagentProto))
|
if (!_prototypeManager.TryIndex<ReagentPrototype>(reagent.Prototype, out var reagentProto))
|
||||||
continue;
|
continue;
|
||||||
price += (float) reagent.Quantity * reagentProto.PricePerUnit;
|
|
||||||
|
// TODO check ReagentData for price information?
|
||||||
|
price += (float) quantity * reagentProto.PricePerUnit;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|||||||
@@ -8,6 +8,7 @@ using Content.Server.Storage.EntitySystems;
|
|||||||
using Content.Shared.Administration.Logs;
|
using Content.Shared.Administration.Logs;
|
||||||
using Content.Shared.Chemistry;
|
using Content.Shared.Chemistry;
|
||||||
using Content.Shared.Chemistry.Components;
|
using Content.Shared.Chemistry.Components;
|
||||||
|
using Content.Shared.Chemistry.Reagent;
|
||||||
using Content.Shared.Containers.ItemSlots;
|
using Content.Shared.Containers.ItemSlots;
|
||||||
using Content.Shared.Database;
|
using Content.Shared.Database;
|
||||||
using Content.Shared.FixedPoint;
|
using Content.Shared.FixedPoint;
|
||||||
@@ -117,7 +118,7 @@ namespace Content.Server.Chemistry.EntitySystems
|
|||||||
ClickSound(chemMaster);
|
ClickSound(chemMaster);
|
||||||
}
|
}
|
||||||
|
|
||||||
private void TransferReagents(ChemMasterComponent chemMaster, string reagentId, FixedPoint2 amount, bool fromBuffer)
|
private void TransferReagents(ChemMasterComponent chemMaster, ReagentId id, FixedPoint2 amount, bool fromBuffer)
|
||||||
{
|
{
|
||||||
var container = _itemSlotsSystem.GetItemOrNull(chemMaster.Owner, SharedChemMaster.InputSlotName);
|
var container = _itemSlotsSystem.GetItemOrNull(chemMaster.Owner, SharedChemMaster.InputSlotName);
|
||||||
if (container is null ||
|
if (container is null ||
|
||||||
@@ -130,26 +131,26 @@ namespace Content.Server.Chemistry.EntitySystems
|
|||||||
if (fromBuffer) // Buffer to container
|
if (fromBuffer) // Buffer to container
|
||||||
{
|
{
|
||||||
amount = FixedPoint2.Min(amount, containerSolution.AvailableVolume);
|
amount = FixedPoint2.Min(amount, containerSolution.AvailableVolume);
|
||||||
amount = bufferSolution.RemoveReagent(reagentId, amount);
|
amount = bufferSolution.RemoveReagent(id, amount);
|
||||||
_solutionContainerSystem.TryAddReagent(container.Value, containerSolution, reagentId, amount, out var _);
|
_solutionContainerSystem.TryAddReagent(container.Value, containerSolution, id, amount, out var _);
|
||||||
}
|
}
|
||||||
else // Container to buffer
|
else // Container to buffer
|
||||||
{
|
{
|
||||||
amount = FixedPoint2.Min(amount, containerSolution.GetReagentQuantity(reagentId));
|
amount = FixedPoint2.Min(amount, containerSolution.GetReagentQuantity(id));
|
||||||
_solutionContainerSystem.TryRemoveReagent(container.Value, containerSolution, reagentId, amount);
|
_solutionContainerSystem.RemoveReagent(container.Value, containerSolution, id, amount);
|
||||||
bufferSolution.AddReagent(reagentId, amount);
|
bufferSolution.AddReagent(id, amount);
|
||||||
}
|
}
|
||||||
|
|
||||||
UpdateUiState(chemMaster, updateLabel: true);
|
UpdateUiState(chemMaster, updateLabel: true);
|
||||||
}
|
}
|
||||||
|
|
||||||
private void DiscardReagents(ChemMasterComponent chemMaster, string reagentId, FixedPoint2 amount, bool fromBuffer)
|
private void DiscardReagents(ChemMasterComponent chemMaster, ReagentId id, FixedPoint2 amount, bool fromBuffer)
|
||||||
{
|
{
|
||||||
|
|
||||||
if (fromBuffer)
|
if (fromBuffer)
|
||||||
{
|
{
|
||||||
if (_solutionContainerSystem.TryGetSolution(chemMaster.Owner, SharedChemMaster.BufferSolutionName, out var bufferSolution))
|
if (_solutionContainerSystem.TryGetSolution(chemMaster.Owner, SharedChemMaster.BufferSolutionName, out var bufferSolution))
|
||||||
bufferSolution.RemoveReagent(reagentId, amount);
|
bufferSolution.RemoveReagent(id, amount);
|
||||||
else
|
else
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
@@ -159,7 +160,7 @@ namespace Content.Server.Chemistry.EntitySystems
|
|||||||
if (container is not null &&
|
if (container is not null &&
|
||||||
_solutionContainerSystem.TryGetFitsInDispenser(container.Value, out var containerSolution))
|
_solutionContainerSystem.TryGetFitsInDispenser(container.Value, out var containerSolution))
|
||||||
{
|
{
|
||||||
_solutionContainerSystem.TryRemoveReagent(container.Value, containerSolution, reagentId, amount);
|
_solutionContainerSystem.RemoveReagent(container.Value, containerSolution, id, amount);
|
||||||
}
|
}
|
||||||
else
|
else
|
||||||
return;
|
return;
|
||||||
@@ -349,17 +350,21 @@ namespace Content.Server.Chemistry.EntitySystems
|
|||||||
return (Name(pill), quantity);
|
return (Name(pill), quantity);
|
||||||
})).ToList();
|
})).ToList();
|
||||||
|
|
||||||
return pills is null
|
if (pills == null)
|
||||||
? null
|
return null;
|
||||||
: new ContainerInfo(name, false, storage.StorageUsed, storage.StorageCapacityMax, pills);
|
|
||||||
|
return new ContainerInfo(name, storage.StorageUsed, storage.StorageCapacityMax)
|
||||||
|
{
|
||||||
|
Entities = pills
|
||||||
|
};
|
||||||
}
|
}
|
||||||
|
|
||||||
private static ContainerInfo BuildContainerInfo(string name, Solution solution)
|
private static ContainerInfo BuildContainerInfo(string name, Solution solution)
|
||||||
{
|
{
|
||||||
var reagents = solution.Contents
|
return new ContainerInfo(name, solution.Volume, solution.MaxVolume)
|
||||||
.Select(reagent => (reagent.ReagentId, reagent.Quantity)).ToList();
|
{
|
||||||
|
Reagents = solution.Contents
|
||||||
return new ContainerInfo(name, true, solution.Volume, solution.MaxVolume, reagents);
|
};
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -3,6 +3,7 @@ using Content.Server.Administration.Logs;
|
|||||||
using Content.Server.Chemistry.Components;
|
using Content.Server.Chemistry.Components;
|
||||||
using Content.Shared.Chemistry;
|
using Content.Shared.Chemistry;
|
||||||
using Content.Shared.Chemistry.Dispenser;
|
using Content.Shared.Chemistry.Dispenser;
|
||||||
|
using Content.Shared.Chemistry.Reagent;
|
||||||
using Content.Shared.Containers.ItemSlots;
|
using Content.Shared.Containers.ItemSlots;
|
||||||
using Content.Shared.Database;
|
using Content.Shared.Database;
|
||||||
using Content.Shared.Emag.Components;
|
using Content.Shared.Emag.Components;
|
||||||
@@ -63,28 +64,30 @@ namespace Content.Server.Chemistry.EntitySystems
|
|||||||
|
|
||||||
if (_solutionContainerSystem.TryGetFitsInDispenser(container.Value, out var solution))
|
if (_solutionContainerSystem.TryGetFitsInDispenser(container.Value, out var solution))
|
||||||
{
|
{
|
||||||
var reagents = solution.Contents.Select(reagent => (reagent.ReagentId, reagent.Quantity)).ToList();
|
return new ContainerInfo(Name(container.Value), solution.Volume, solution.MaxVolume)
|
||||||
return new ContainerInfo(Name(container.Value), true, solution.Volume, solution.MaxVolume, reagents);
|
{
|
||||||
|
Reagents = solution.Contents
|
||||||
|
};
|
||||||
}
|
}
|
||||||
|
|
||||||
return null;
|
return null;
|
||||||
}
|
}
|
||||||
|
|
||||||
private List<string> GetInventory(ReagentDispenserComponent reagentDispenser)
|
private List<ReagentId> GetInventory(ReagentDispenserComponent reagentDispenser)
|
||||||
{
|
{
|
||||||
var inventory = new List<string>();
|
var inventory = new List<ReagentId>();
|
||||||
|
|
||||||
if (reagentDispenser.PackPrototypeId is not null
|
if (reagentDispenser.PackPrototypeId is not null
|
||||||
&& _prototypeManager.TryIndex(reagentDispenser.PackPrototypeId, out ReagentDispenserInventoryPrototype? packPrototype))
|
&& _prototypeManager.TryIndex(reagentDispenser.PackPrototypeId, out ReagentDispenserInventoryPrototype? packPrototype))
|
||||||
{
|
{
|
||||||
inventory.AddRange(packPrototype.Inventory);
|
inventory.AddRange(packPrototype.Inventory.Select(x => new ReagentId(x, null)));
|
||||||
}
|
}
|
||||||
|
|
||||||
if (HasComp<EmaggedComponent>(reagentDispenser.Owner)
|
if (HasComp<EmaggedComponent>(reagentDispenser.Owner)
|
||||||
&& reagentDispenser.EmagPackPrototypeId is not null
|
&& reagentDispenser.EmagPackPrototypeId is not null
|
||||||
&& _prototypeManager.TryIndex(reagentDispenser.EmagPackPrototypeId, out ReagentDispenserInventoryPrototype? emagPackPrototype))
|
&& _prototypeManager.TryIndex(reagentDispenser.EmagPackPrototypeId, out ReagentDispenserInventoryPrototype? emagPackPrototype))
|
||||||
{
|
{
|
||||||
inventory.AddRange(emagPackPrototype.Inventory);
|
inventory.AddRange(emagPackPrototype.Inventory.Select(x => new ReagentId(x, null)));
|
||||||
}
|
}
|
||||||
|
|
||||||
return inventory;
|
return inventory;
|
||||||
|
|||||||
@@ -20,7 +20,7 @@ public sealed class RehydratableSystem : EntitySystem
|
|||||||
|
|
||||||
private void OnSolutionChange(EntityUid uid, RehydratableComponent comp, SolutionChangedEvent args)
|
private void OnSolutionChange(EntityUid uid, RehydratableComponent comp, SolutionChangedEvent args)
|
||||||
{
|
{
|
||||||
var quantity = _solutions.GetReagentQuantity(uid, comp.CatalystPrototype);
|
var quantity = _solutions.GetTotalPrototypeQuantity(uid, comp.CatalystPrototype);
|
||||||
if (quantity != FixedPoint2.Zero && quantity >= comp.CatalystMinimum)
|
if (quantity != FixedPoint2.Zero && quantity >= comp.CatalystMinimum)
|
||||||
{
|
{
|
||||||
Expand(uid, comp);
|
Expand(uid, comp);
|
||||||
|
|||||||
@@ -23,9 +23,11 @@ namespace Content.Server.Chemistry.EntitySystems;
|
|||||||
public sealed class SolutionChangedEvent : EntityEventArgs
|
public sealed class SolutionChangedEvent : EntityEventArgs
|
||||||
{
|
{
|
||||||
public readonly Solution Solution;
|
public readonly Solution Solution;
|
||||||
|
public readonly string SolutionId;
|
||||||
|
|
||||||
public SolutionChangedEvent(Solution solution)
|
public SolutionChangedEvent(Solution solution, string solutionId)
|
||||||
{
|
{
|
||||||
|
SolutionId = solutionId;
|
||||||
Solution = solution;
|
Solution = solution;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@@ -103,7 +105,7 @@ public sealed partial class SolutionContainerSystem : EntitySystem
|
|||||||
{
|
{
|
||||||
var msg = new FormattedMessage();
|
var msg = new FormattedMessage();
|
||||||
|
|
||||||
if (solution.Contents.Count == 0) //TODO: better way to see if empty?
|
if (solution.Volume == 0)
|
||||||
{
|
{
|
||||||
msg.AddMarkup(Loc.GetString("scannable-solution-empty-container"));
|
msg.AddMarkup(Loc.GetString("scannable-solution-empty-container"));
|
||||||
return msg;
|
return msg;
|
||||||
@@ -111,17 +113,13 @@ public sealed partial class SolutionContainerSystem : EntitySystem
|
|||||||
|
|
||||||
msg.AddMarkup(Loc.GetString("scannable-solution-main-text"));
|
msg.AddMarkup(Loc.GetString("scannable-solution-main-text"));
|
||||||
|
|
||||||
foreach (var reagent in solution)
|
foreach (var (proto, quantity) in solution.GetReagentPrototypes(_prototypeManager))
|
||||||
{
|
{
|
||||||
if (!_prototypeManager.TryIndex<ReagentPrototype>(reagent.ReagentId, out var proto))
|
|
||||||
{
|
|
||||||
continue;
|
|
||||||
}
|
|
||||||
msg.PushNewline();
|
msg.PushNewline();
|
||||||
msg.AddMarkup(Loc.GetString("scannable-solution-chemical"
|
msg.AddMarkup(Loc.GetString("scannable-solution-chemical"
|
||||||
, ("type", proto.LocalizedName)
|
, ("type", proto.LocalizedName)
|
||||||
, ("color", proto.SubstanceColor.ToHexNoAlpha())
|
, ("color", proto.SubstanceColor.ToHexNoAlpha())
|
||||||
, ("amount", reagent.Quantity)));
|
, ("amount", quantity)));
|
||||||
}
|
}
|
||||||
|
|
||||||
return msg;
|
return msg;
|
||||||
@@ -132,46 +130,41 @@ public sealed partial class SolutionContainerSystem : EntitySystem
|
|||||||
{
|
{
|
||||||
SolutionContainerManagerComponent? solutionsManager = null;
|
SolutionContainerManagerComponent? solutionsManager = null;
|
||||||
if (!Resolve(args.Examined, ref solutionsManager)
|
if (!Resolve(args.Examined, ref solutionsManager)
|
||||||
|| !solutionsManager.Solutions.TryGetValue(examinableComponent.Solution, out var solutionHolder))
|
|| !solutionsManager.Solutions.TryGetValue(examinableComponent.Solution, out var solution))
|
||||||
{
|
{
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
var primaryReagent = solutionHolder.GetPrimaryReagentId();
|
var primaryReagent = solution.GetPrimaryReagentId();
|
||||||
|
|
||||||
if (string.IsNullOrEmpty(primaryReagent))
|
if (string.IsNullOrEmpty(primaryReagent?.Prototype))
|
||||||
{
|
{
|
||||||
args.PushText(Loc.GetString("shared-solution-container-component-on-examine-empty-container"));
|
args.PushText(Loc.GetString("shared-solution-container-component-on-examine-empty-container"));
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
if (!_prototypeManager.TryIndex(primaryReagent, out ReagentPrototype? primary))
|
if (!_prototypeManager.TryIndex(primaryReagent.Value.Prototype, out ReagentPrototype? primary))
|
||||||
{
|
{
|
||||||
Logger.Error(
|
Logger.Error(
|
||||||
$"{nameof(Solution)} could not find the prototype associated with {primaryReagent}.");
|
$"{nameof(Solution)} could not find the prototype associated with {primaryReagent}.");
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
var colorHex = solutionHolder.GetColor(_prototypeManager)
|
var colorHex = solution.GetColor(_prototypeManager)
|
||||||
.ToHexNoAlpha(); //TODO: If the chem has a dark color, the examine text becomes black on a black background, which is unreadable.
|
.ToHexNoAlpha(); //TODO: If the chem has a dark color, the examine text becomes black on a black background, which is unreadable.
|
||||||
var messageString = "shared-solution-container-component-on-examine-main-text";
|
var messageString = "shared-solution-container-component-on-examine-main-text";
|
||||||
|
|
||||||
args.PushMarkup(Loc.GetString(messageString,
|
args.PushMarkup(Loc.GetString(messageString,
|
||||||
("color", colorHex),
|
("color", colorHex),
|
||||||
("wordedAmount", Loc.GetString(solutionHolder.Contents.Count == 1
|
("wordedAmount", Loc.GetString(solution.Contents.Count == 1
|
||||||
? "shared-solution-container-component-on-examine-worded-amount-one-reagent"
|
? "shared-solution-container-component-on-examine-worded-amount-one-reagent"
|
||||||
: "shared-solution-container-component-on-examine-worded-amount-multiple-reagents")),
|
: "shared-solution-container-component-on-examine-worded-amount-multiple-reagents")),
|
||||||
("desc", primary.LocalizedPhysicalDescription)));
|
("desc", primary.LocalizedPhysicalDescription)));
|
||||||
|
|
||||||
// Add descriptions of immediately recognizable reagents, like water or beer
|
// Add descriptions of immediately recognizable reagents, like water or beer
|
||||||
var recognized = new List<ReagentPrototype>();
|
var recognized = new List<ReagentPrototype>();
|
||||||
foreach (var (id, _) in solutionHolder)
|
foreach (var proto in solution.GetReagentPrototypes(_prototypeManager).Keys)
|
||||||
{
|
{
|
||||||
if (!_prototypeManager.TryIndex<ReagentPrototype>(id, out var proto))
|
|
||||||
{
|
|
||||||
continue;
|
|
||||||
}
|
|
||||||
|
|
||||||
if (!proto.Recognizable)
|
if (!proto.Recognizable)
|
||||||
{
|
{
|
||||||
continue;
|
continue;
|
||||||
@@ -278,7 +271,7 @@ public sealed partial class SolutionContainerSystem : EntitySystem
|
|||||||
}
|
}
|
||||||
|
|
||||||
UpdateAppearance(uid, solutionHolder);
|
UpdateAppearance(uid, solutionHolder);
|
||||||
RaiseLocalEvent(uid, new SolutionChangedEvent(solutionHolder));
|
RaiseLocalEvent(uid, new SolutionChangedEvent(solutionHolder, solutionHolder.Name));
|
||||||
}
|
}
|
||||||
|
|
||||||
public void RemoveAllSolution(EntityUid uid, Solution solutionHolder)
|
public void RemoveAllSolution(EntityUid uid, Solution solutionHolder)
|
||||||
@@ -324,46 +317,111 @@ public sealed partial class SolutionContainerSystem : EntitySystem
|
|||||||
/// </summary>
|
/// </summary>
|
||||||
/// <param name="targetUid"></param>
|
/// <param name="targetUid"></param>
|
||||||
/// <param name="targetSolution">Container to which we are adding reagent</param>
|
/// <param name="targetSolution">Container to which we are adding reagent</param>
|
||||||
/// <param name="reagentId">The Id of the reagent to add.</param>
|
/// <param name="reagentQuantity">The reagent to add.</param>
|
||||||
|
/// <param name="acceptedQuantity">The amount of reagent successfully added.</param>
|
||||||
|
/// <returns>If all the reagent could be added.</returns>
|
||||||
|
public bool TryAddReagent(EntityUid targetUid, Solution targetSolution, ReagentQuantity reagentQuantity,
|
||||||
|
out FixedPoint2 acceptedQuantity, float? temperature = null)
|
||||||
|
{
|
||||||
|
acceptedQuantity = targetSolution.AvailableVolume > reagentQuantity.Quantity
|
||||||
|
? reagentQuantity.Quantity
|
||||||
|
: targetSolution.AvailableVolume;
|
||||||
|
|
||||||
|
if (acceptedQuantity <= 0)
|
||||||
|
return reagentQuantity.Quantity == 0;
|
||||||
|
|
||||||
|
if (temperature == null)
|
||||||
|
{
|
||||||
|
targetSolution.AddReagent(reagentQuantity.Reagent, acceptedQuantity);
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
var proto = _prototypeManager.Index<ReagentPrototype>(reagentQuantity.Reagent.Prototype);
|
||||||
|
targetSolution.AddReagent(proto, acceptedQuantity, temperature.Value, _prototypeManager);
|
||||||
|
}
|
||||||
|
|
||||||
|
UpdateChemicals(targetUid, targetSolution, true);
|
||||||
|
return acceptedQuantity == reagentQuantity.Quantity;
|
||||||
|
}
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// Adds reagent of an Id to the container.
|
||||||
|
/// </summary>
|
||||||
|
/// <param name="targetUid"></param>
|
||||||
|
/// <param name="targetSolution">Container to which we are adding reagent</param>
|
||||||
|
/// <param name="prototype">The Id of the reagent to add.</param>
|
||||||
/// <param name="quantity">The amount of reagent to add.</param>
|
/// <param name="quantity">The amount of reagent to add.</param>
|
||||||
/// <param name="acceptedQuantity">The amount of reagent successfully added.</param>
|
/// <param name="acceptedQuantity">The amount of reagent successfully added.</param>
|
||||||
/// <returns>If all the reagent could be added.</returns>
|
/// <returns>If all the reagent could be added.</returns>
|
||||||
public bool TryAddReagent(EntityUid targetUid, Solution targetSolution, string reagentId, FixedPoint2 quantity,
|
public bool TryAddReagent(EntityUid targetUid, Solution targetSolution, string prototype, FixedPoint2 quantity,
|
||||||
out FixedPoint2 acceptedQuantity, float? temperature = null)
|
out FixedPoint2 acceptedQuantity, float? temperature = null, ReagentData? data = null)
|
||||||
{
|
{
|
||||||
acceptedQuantity = targetSolution.AvailableVolume > quantity ? quantity : targetSolution.AvailableVolume;
|
var reagent = new ReagentQuantity(prototype, quantity, data);
|
||||||
|
return TryAddReagent(targetUid, targetSolution, reagent, out acceptedQuantity, temperature);
|
||||||
if (acceptedQuantity <= 0)
|
|
||||||
return quantity == 0;
|
|
||||||
|
|
||||||
if (temperature == null)
|
|
||||||
targetSolution.AddReagent(reagentId, acceptedQuantity);
|
|
||||||
else
|
|
||||||
targetSolution.AddReagent(_prototypeManager.Index<ReagentPrototype>(reagentId), acceptedQuantity, temperature.Value, _prototypeManager);
|
|
||||||
|
|
||||||
UpdateChemicals(targetUid, targetSolution, true);
|
|
||||||
return acceptedQuantity == quantity;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// Adds reagent of an Id to the container.
|
||||||
|
/// </summary>
|
||||||
|
/// <param name="targetUid"></param>
|
||||||
|
/// <param name="targetSolution">Container to which we are adding reagent</param>
|
||||||
|
/// <param name="reagentId">The reagent to add.</param>
|
||||||
|
/// <param name="quantity">The amount of reagent to add.</param>
|
||||||
|
/// <param name="acceptedQuantity">The amount of reagent successfully added.</param>
|
||||||
|
/// <returns>If all the reagent could be added.</returns>
|
||||||
|
public bool TryAddReagent(EntityUid targetUid, Solution targetSolution, ReagentId reagentId, FixedPoint2 quantity,
|
||||||
|
out FixedPoint2 acceptedQuantity, float? temperature = null)
|
||||||
|
{
|
||||||
|
var quant = new ReagentQuantity(reagentId, quantity);
|
||||||
|
return TryAddReagent(targetUid, targetSolution, quant, out acceptedQuantity, temperature);
|
||||||
|
}
|
||||||
|
|
||||||
/// <summary>
|
/// <summary>
|
||||||
/// Removes reagent of an Id to the container.
|
/// Removes reagent from a container.
|
||||||
/// </summary>
|
/// </summary>
|
||||||
/// <param name="targetUid"></param>
|
/// <param name="targetUid"></param>
|
||||||
/// <param name="container">Solution container from which we are removing reagent</param>
|
/// <param name="container">Solution container from which we are removing reagent</param>
|
||||||
/// <param name="reagentId">The Id of the reagent to remove.</param>
|
/// <param name="reagentQuantity">The reagent to remove.</param>
|
||||||
/// <param name="quantity">The amount of reagent to remove.</param>
|
|
||||||
/// <returns>If the reagent to remove was found in the container.</returns>
|
/// <returns>If the reagent to remove was found in the container.</returns>
|
||||||
public bool TryRemoveReagent(EntityUid targetUid, Solution? container, string reagentId, FixedPoint2 quantity)
|
public bool RemoveReagent(EntityUid targetUid, Solution? container, ReagentQuantity reagentQuantity)
|
||||||
{
|
{
|
||||||
if (container == null || !container.ContainsReagent(reagentId))
|
if (container == null)
|
||||||
|
return false;
|
||||||
|
|
||||||
|
var quant = container.RemoveReagent(reagentQuantity);
|
||||||
|
if (quant <= FixedPoint2.Zero)
|
||||||
return false;
|
return false;
|
||||||
|
|
||||||
container.RemoveReagent(reagentId, quantity);
|
|
||||||
UpdateChemicals(targetUid, container);
|
UpdateChemicals(targetUid, container);
|
||||||
return true;
|
return true;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// Removes reagent from a container.
|
||||||
|
/// </summary>
|
||||||
|
/// <param name="targetUid"></param>
|
||||||
|
/// <param name="container">Solution container from which we are removing reagent</param>
|
||||||
|
/// <param name="prototype">The Id of the reagent to remove.</param>
|
||||||
|
/// <param name="quantity">The amount of reagent to remove.</param>
|
||||||
|
/// <returns>If the reagent to remove was found in the container.</returns>
|
||||||
|
public bool RemoveReagent(EntityUid targetUid, Solution? container, string prototype, FixedPoint2 quantity, ReagentData? data = null)
|
||||||
|
{
|
||||||
|
return RemoveReagent(targetUid, container, new ReagentQuantity(prototype, quantity, data));
|
||||||
|
}
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// Removes reagent from a container.
|
||||||
|
/// </summary>
|
||||||
|
/// <param name="targetUid"></param>
|
||||||
|
/// <param name="container">Solution container from which we are removing reagent</param>
|
||||||
|
/// <param name="reagentId">The reagent to remove.</param>
|
||||||
|
/// <param name="quantity">The amount of reagent to remove.</param>
|
||||||
|
/// <returns>If the reagent to remove was found in the container.</returns>
|
||||||
|
public bool RemoveReagent(EntityUid targetUid, Solution? container, ReagentId reagentId, FixedPoint2 quantity)
|
||||||
|
{
|
||||||
|
return RemoveReagent(targetUid, container, new ReagentQuantity(reagentId, quantity));
|
||||||
|
}
|
||||||
|
|
||||||
/// <summary>
|
/// <summary>
|
||||||
/// Adds a solution to the container, if it can fully fit.
|
/// Adds a solution to the container, if it can fully fit.
|
||||||
/// </summary>
|
/// </summary>
|
||||||
@@ -391,19 +449,35 @@ public sealed partial class SolutionContainerSystem : EntitySystem
|
|||||||
/// <param name="target">target solution</param>
|
/// <param name="target">target solution</param>
|
||||||
/// <param name="quantity">quantity of solution to move from source to target. If this is a negative number, the source & target roles are reversed.</param>
|
/// <param name="quantity">quantity of solution to move from source to target. If this is a negative number, the source & target roles are reversed.</param>
|
||||||
public bool TryTransferSolution(EntityUid sourceUid, EntityUid targetUid, Solution source, Solution target, FixedPoint2 quantity)
|
public bool TryTransferSolution(EntityUid sourceUid, EntityUid targetUid, Solution source, Solution target, FixedPoint2 quantity)
|
||||||
|
{
|
||||||
|
if (!TryTransferSolution(targetUid, target, source, quantity))
|
||||||
|
return false;
|
||||||
|
|
||||||
|
UpdateChemicals(sourceUid, source, false);
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// Moves some quantity of a solution from one solution to another.
|
||||||
|
/// </summary>
|
||||||
|
/// <param name="sourceUid">entity holding the source solution</param>
|
||||||
|
/// <param name="targetUid">entity holding the target solution</param>
|
||||||
|
/// <param name="source">source solution</param>
|
||||||
|
/// <param name="target">target solution</param>
|
||||||
|
/// <param name="quantity">quantity of solution to move from source to target. If this is a negative number, the source & target roles are reversed.</param>
|
||||||
|
public bool TryTransferSolution(EntityUid targetUid, Solution target, Solution source, FixedPoint2 quantity)
|
||||||
{
|
{
|
||||||
if (quantity < 0)
|
if (quantity < 0)
|
||||||
return TryTransferSolution(targetUid, sourceUid, target, source, -quantity);
|
throw new InvalidOperationException("Quantity must be positive");
|
||||||
|
|
||||||
quantity = FixedPoint2.Min(quantity, target.AvailableVolume, source.Volume);
|
quantity = FixedPoint2.Min(quantity, target.AvailableVolume, source.Volume);
|
||||||
if (quantity == 0)
|
if (quantity == 0)
|
||||||
return false;
|
return false;
|
||||||
|
|
||||||
// TODO This should be made into a function that directly transfers reagents. currently this is quite
|
// TODO This should be made into a function that directly transfers reagents.
|
||||||
// inefficient.
|
// Currently this is quite inefficient.
|
||||||
target.AddSolution(source.SplitSolution(quantity), _prototypeManager);
|
target.AddSolution(source.SplitSolution(quantity), _prototypeManager);
|
||||||
|
|
||||||
UpdateChemicals(sourceUid, source, false);
|
|
||||||
UpdateChemicals(targetUid, target, true);
|
UpdateChemicals(targetUid, target, true);
|
||||||
return true;
|
return true;
|
||||||
}
|
}
|
||||||
@@ -540,7 +614,7 @@ public sealed partial class SolutionContainerSystem : EntitySystem
|
|||||||
}
|
}
|
||||||
|
|
||||||
public Solution EnsureSolution(EntityUid uid, string name,
|
public Solution EnsureSolution(EntityUid uid, string name,
|
||||||
IEnumerable<Solution.ReagentQuantity> reagents,
|
IEnumerable<ReagentQuantity> reagents,
|
||||||
bool setMaxVol = true,
|
bool setMaxVol = true,
|
||||||
SolutionContainerManagerComponent? solutionsMgr = null)
|
SolutionContainerManagerComponent? solutionsMgr = null)
|
||||||
{
|
{
|
||||||
@@ -574,19 +648,16 @@ public sealed partial class SolutionContainerSystem : EntitySystem
|
|||||||
// RemoveReagent does a RemoveSwap, meaning we don't have to copy the list if we iterate it backwards.
|
// RemoveReagent does a RemoveSwap, meaning we don't have to copy the list if we iterate it backwards.
|
||||||
for (var i = solution.Contents.Count-1; i >= 0; i--)
|
for (var i = solution.Contents.Count-1; i >= 0; i--)
|
||||||
{
|
{
|
||||||
var (reagentId, _) = solution.Contents[i];
|
var (reagent, _) = solution.Contents[i];
|
||||||
|
var removedQuantity = solution.RemoveReagent(reagent, quantity);
|
||||||
var removedQuantity = solution.RemoveReagent(reagentId, quantity);
|
removedSolution.AddReagent(reagent, removedQuantity);
|
||||||
|
|
||||||
if(removedQuantity > 0)
|
|
||||||
removedSolution.AddReagent(reagentId, removedQuantity);
|
|
||||||
}
|
}
|
||||||
|
|
||||||
UpdateChemicals(uid, solution);
|
UpdateChemicals(uid, solution);
|
||||||
return removedSolution;
|
return removedSolution;
|
||||||
}
|
}
|
||||||
|
|
||||||
public FixedPoint2 GetReagentQuantity(EntityUid owner, string reagentId)
|
public FixedPoint2 GetTotalPrototypeQuantity(EntityUid owner, string reagentId)
|
||||||
{
|
{
|
||||||
var reagentQuantity = FixedPoint2.New(0);
|
var reagentQuantity = FixedPoint2.New(0);
|
||||||
if (EntityManager.EntityExists(owner)
|
if (EntityManager.EntityExists(owner)
|
||||||
@@ -594,7 +665,7 @@ public sealed partial class SolutionContainerSystem : EntitySystem
|
|||||||
{
|
{
|
||||||
foreach (var solution in managerComponent.Solutions.Values)
|
foreach (var solution in managerComponent.Solutions.Values)
|
||||||
{
|
{
|
||||||
reagentQuantity += solution.GetReagentQuantity(reagentId);
|
reagentQuantity += solution.GetTotalPrototypeQuantity(reagentId);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -640,21 +711,21 @@ public sealed partial class SolutionContainerSystem : EntitySystem
|
|||||||
if (component.Solutions.Count == 0)
|
if (component.Solutions.Count == 0)
|
||||||
return null;
|
return null;
|
||||||
|
|
||||||
var reagentCounts = new Dictionary<string, FixedPoint2>();
|
var reagentCounts = new Dictionary<ReagentId, FixedPoint2>();
|
||||||
|
|
||||||
foreach (var solution in component.Solutions.Values)
|
foreach (var solution in component.Solutions.Values)
|
||||||
{
|
{
|
||||||
foreach (var reagent in solution.Contents)
|
foreach (var (reagent, quantity) in solution.Contents)
|
||||||
{
|
{
|
||||||
reagentCounts.TryGetValue(reagent.ReagentId, out var existing);
|
reagentCounts.TryGetValue(reagent, out var existing);
|
||||||
existing += reagent.Quantity;
|
existing += quantity;
|
||||||
reagentCounts[reagent.ReagentId] = existing;
|
reagentCounts[reagent] = existing;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
var max = reagentCounts.Max();
|
var max = reagentCounts.Max();
|
||||||
|
|
||||||
return _prototypeManager.Index<ReagentPrototype>(max.Key);
|
return _prototypeManager.Index<ReagentPrototype>(max.Key.Prototype);
|
||||||
}
|
}
|
||||||
|
|
||||||
public SoundSpecifier? GetSound(SolutionContainerManagerComponent component)
|
public SoundSpecifier? GetSound(SolutionContainerManagerComponent component)
|
||||||
|
|||||||
@@ -47,14 +47,14 @@ public sealed class TransformableContainerSystem : EntitySystem
|
|||||||
var reagentId = solution.GetPrimaryReagentId();
|
var reagentId = solution.GetPrimaryReagentId();
|
||||||
|
|
||||||
//If biggest reagent didn't changed - don't change anything at all
|
//If biggest reagent didn't changed - don't change anything at all
|
||||||
if (component.CurrentReagent != null && component.CurrentReagent.ID == reagentId)
|
if (component.CurrentReagent != null && component.CurrentReagent.ID == reagentId?.Prototype)
|
||||||
{
|
{
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
//Only reagents with spritePath property can change appearance of transformable containers!
|
//Only reagents with spritePath property can change appearance of transformable containers!
|
||||||
if (!string.IsNullOrWhiteSpace(reagentId)
|
if (!string.IsNullOrWhiteSpace(reagentId?.Prototype)
|
||||||
&& _prototypeManager.TryIndex(reagentId, out ReagentPrototype? proto))
|
&& _prototypeManager.TryIndex(reagentId.Value.Prototype, out ReagentPrototype? proto))
|
||||||
{
|
{
|
||||||
var metadata = MetaData(owner);
|
var metadata = MetaData(owner);
|
||||||
var val = Loc.GetString("transformable-container-component-glass", ("name", proto.LocalizedName));
|
var val = Loc.GetString("transformable-container-component-glass", ("name", proto.LocalizedName));
|
||||||
|
|||||||
@@ -1,18 +1,17 @@
|
|||||||
using System.Numerics;
|
using System.Numerics;
|
||||||
using Content.Server.Chemistry.Components;
|
using Content.Server.Chemistry.Components;
|
||||||
using Content.Server.Chemistry.Components.SolutionManager;
|
using Content.Server.Chemistry.Components.SolutionManager;
|
||||||
|
using Content.Shared.Chemistry;
|
||||||
using Content.Shared.Chemistry.Components;
|
using Content.Shared.Chemistry.Components;
|
||||||
using Content.Shared.Chemistry.Reagent;
|
using Content.Shared.Chemistry.Reagent;
|
||||||
using Content.Shared.FixedPoint;
|
using Content.Shared.FixedPoint;
|
||||||
using Content.Shared.Physics;
|
using Content.Shared.Physics;
|
||||||
using Content.Shared.Spawners.Components;
|
using Content.Shared.Spawners.Components;
|
||||||
using Content.Shared.Throwing;
|
using Content.Shared.Throwing;
|
||||||
using Content.Shared.Vapor;
|
|
||||||
using JetBrains.Annotations;
|
using JetBrains.Annotations;
|
||||||
using Robust.Shared.Map;
|
using Robust.Shared.Map;
|
||||||
using Robust.Shared.Map.Components;
|
using Robust.Shared.Map.Components;
|
||||||
using Robust.Shared.Physics.Components;
|
using Robust.Shared.Physics.Components;
|
||||||
using Robust.Shared.Physics.Dynamics;
|
|
||||||
using Robust.Shared.Physics.Events;
|
using Robust.Shared.Physics.Events;
|
||||||
using Robust.Shared.Physics.Systems;
|
using Robust.Shared.Physics.Systems;
|
||||||
using Robust.Shared.Prototypes;
|
using Robust.Shared.Prototypes;
|
||||||
@@ -27,6 +26,7 @@ namespace Content.Server.Chemistry.EntitySystems
|
|||||||
[Dependency] private readonly SharedPhysicsSystem _physics = default!;
|
[Dependency] private readonly SharedPhysicsSystem _physics = default!;
|
||||||
[Dependency] private readonly SolutionContainerSystem _solutionContainerSystem = default!;
|
[Dependency] private readonly SolutionContainerSystem _solutionContainerSystem = default!;
|
||||||
[Dependency] private readonly ThrowingSystem _throwing = default!;
|
[Dependency] private readonly ThrowingSystem _throwing = default!;
|
||||||
|
[Dependency] private readonly ReactiveSystem _reactive = default!;
|
||||||
|
|
||||||
private const float ReactTime = 0.125f;
|
private const float ReactTime = 0.125f;
|
||||||
|
|
||||||
@@ -45,7 +45,7 @@ namespace Content.Server.Chemistry.EntitySystems
|
|||||||
|
|
||||||
foreach (var value in contents.Solutions.Values)
|
foreach (var value in contents.Solutions.Values)
|
||||||
{
|
{
|
||||||
value.DoEntityReaction(args.OtherEntity, ReactionMethod.Touch);
|
_reactive.DoEntityReaction(args.OtherEntity, value, ReactionMethod.Touch);
|
||||||
}
|
}
|
||||||
|
|
||||||
// Check for collision with a impassable object (e.g. wall) and stop
|
// Check for collision with a impassable object (e.g. wall) and stop
|
||||||
@@ -120,18 +120,18 @@ namespace Content.Server.Chemistry.EntitySystems
|
|||||||
foreach (var reagentQuantity in contents.Contents.ToArray())
|
foreach (var reagentQuantity in contents.Contents.ToArray())
|
||||||
{
|
{
|
||||||
if (reagentQuantity.Quantity == FixedPoint2.Zero) continue;
|
if (reagentQuantity.Quantity == FixedPoint2.Zero) continue;
|
||||||
var reagent = _protoManager.Index<ReagentPrototype>(reagentQuantity.ReagentId);
|
var reagent = _protoManager.Index<ReagentPrototype>(reagentQuantity.Reagent.Prototype);
|
||||||
|
|
||||||
var reaction =
|
var reaction =
|
||||||
reagent.ReactionTile(tile, (reagentQuantity.Quantity / vapor.TransferAmount) * 0.25f);
|
reagent.ReactionTile(tile, (reagentQuantity.Quantity / vapor.TransferAmount) * 0.25f);
|
||||||
|
|
||||||
if (reaction > reagentQuantity.Quantity)
|
if (reaction > reagentQuantity.Quantity)
|
||||||
{
|
{
|
||||||
_sawmill.Error($"Tried to tile react more than we have for reagent {reagentQuantity.ReagentId}. Found {reaction} and we only have {reagentQuantity.Quantity}");
|
_sawmill.Error($"Tried to tile react more than we have for reagent {reagentQuantity}. Found {reaction} and we only have {reagentQuantity.Quantity}");
|
||||||
reaction = reagentQuantity.Quantity;
|
reaction = reagentQuantity.Quantity;
|
||||||
}
|
}
|
||||||
|
|
||||||
_solutionContainerSystem.TryRemoveReagent(vapor.Owner, contents, reagentQuantity.ReagentId, reaction);
|
_solutionContainerSystem.RemoveReagent(vapor.Owner, contents, reagentQuantity.Reagent, reaction);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|||||||
@@ -19,6 +19,7 @@ namespace Content.Server.Chemistry.ReagentEffectConditions
|
|||||||
[DataField("max")]
|
[DataField("max")]
|
||||||
public FixedPoint2 Max = FixedPoint2.MaxValue;
|
public FixedPoint2 Max = FixedPoint2.MaxValue;
|
||||||
|
|
||||||
|
// TODO use ReagentId
|
||||||
[DataField("reagent")]
|
[DataField("reagent")]
|
||||||
public string? Reagent;
|
public string? Reagent;
|
||||||
|
|
||||||
@@ -29,10 +30,8 @@ namespace Content.Server.Chemistry.ReagentEffectConditions
|
|||||||
return true; // No condition to apply.
|
return true; // No condition to apply.
|
||||||
|
|
||||||
var quant = FixedPoint2.Zero;
|
var quant = FixedPoint2.Zero;
|
||||||
if (args.Source != null && args.Source.ContainsReagent(reagent))
|
if (args.Source != null)
|
||||||
{
|
quant = args.Source.GetTotalPrototypeQuantity(reagent);
|
||||||
quant = args.Source.GetReagentQuantity(reagent);
|
|
||||||
}
|
|
||||||
|
|
||||||
return quant >= Min && quant <= Max;
|
return quant >= Min && quant <= Max;
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -16,6 +16,7 @@ namespace Content.Server.Chemistry.ReagentEffects
|
|||||||
/// </summary>
|
/// </summary>
|
||||||
[DataField("reagent", customTypeSerializer:typeof(PrototypeIdSerializer<ReagentPrototype>))]
|
[DataField("reagent", customTypeSerializer:typeof(PrototypeIdSerializer<ReagentPrototype>))]
|
||||||
public string? Reagent = null;
|
public string? Reagent = null;
|
||||||
|
// TODO use ReagentId
|
||||||
|
|
||||||
/// <summary>
|
/// <summary>
|
||||||
/// The metabolism group to remove, if the reagent satisfies any.
|
/// The metabolism group to remove, if the reagent satisfies any.
|
||||||
@@ -38,8 +39,8 @@ namespace Content.Server.Chemistry.ReagentEffects
|
|||||||
|
|
||||||
if (Reagent != null)
|
if (Reagent != null)
|
||||||
{
|
{
|
||||||
if (amount < 0 && args.Source.ContainsReagent(Reagent))
|
if (amount < 0 && args.Source.ContainsPrototype(Reagent))
|
||||||
solutionSys.TryRemoveReagent(args.SolutionEntity, args.Source, Reagent, -amount);
|
solutionSys.RemoveReagent(args.SolutionEntity, args.Source, Reagent, -amount);
|
||||||
if (amount > 0)
|
if (amount > 0)
|
||||||
solutionSys.TryAddReagent(args.SolutionEntity, args.Source, Reagent, amount, out _);
|
solutionSys.TryAddReagent(args.SolutionEntity, args.Source, Reagent, amount, out _);
|
||||||
}
|
}
|
||||||
@@ -48,13 +49,13 @@ namespace Content.Server.Chemistry.ReagentEffects
|
|||||||
var prototypeMan = IoCManager.Resolve<IPrototypeManager>();
|
var prototypeMan = IoCManager.Resolve<IPrototypeManager>();
|
||||||
foreach (var quant in args.Source.Contents.ToArray())
|
foreach (var quant in args.Source.Contents.ToArray())
|
||||||
{
|
{
|
||||||
var proto = prototypeMan.Index<ReagentPrototype>(quant.ReagentId);
|
var proto = prototypeMan.Index<ReagentPrototype>(quant.Reagent.Prototype);
|
||||||
if (proto.Metabolisms != null && proto.Metabolisms.ContainsKey(Group))
|
if (proto.Metabolisms != null && proto.Metabolisms.ContainsKey(Group))
|
||||||
{
|
{
|
||||||
if (amount < 0)
|
if (amount < 0)
|
||||||
solutionSys.TryRemoveReagent(args.SolutionEntity, args.Source, quant.ReagentId, amount);
|
solutionSys.RemoveReagent(args.SolutionEntity, args.Source, quant.Reagent, amount);
|
||||||
if (amount > 0)
|
if (amount > 0)
|
||||||
solutionSys.TryAddReagent(args.SolutionEntity, args.Source, quant.ReagentId, amount, out _);
|
solutionSys.TryAddReagent(args.SolutionEntity, args.Source, quant.Reagent, amount, out _);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -55,7 +55,8 @@ public sealed class AbsorbentSystem : SharedAbsorbentSystem
|
|||||||
var oldProgress = component.Progress.ShallowClone();
|
var oldProgress = component.Progress.ShallowClone();
|
||||||
component.Progress.Clear();
|
component.Progress.Clear();
|
||||||
|
|
||||||
if (solution.TryGetReagent(PuddleSystem.EvaporationReagent, out var water))
|
var water = solution.GetTotalPrototypeQuantity(PuddleSystem.EvaporationReagent);
|
||||||
|
if (water > FixedPoint2.Zero)
|
||||||
{
|
{
|
||||||
component.Progress[_prototype.Index<ReagentPrototype>(PuddleSystem.EvaporationReagent).SubstanceColor] = water.Float();
|
component.Progress[_prototype.Index<ReagentPrototype>(PuddleSystem.EvaporationReagent).SubstanceColor] = water.Float();
|
||||||
}
|
}
|
||||||
@@ -230,7 +231,7 @@ public sealed class AbsorbentSystem : SharedAbsorbentSystem
|
|||||||
}
|
}
|
||||||
|
|
||||||
// Check if we have any evaporative reagents on our absorber to transfer
|
// Check if we have any evaporative reagents on our absorber to transfer
|
||||||
absorberSoln.TryGetReagent(PuddleSystem.EvaporationReagent, out var available);
|
var available = absorberSoln.GetTotalPrototypeQuantity(PuddleSystem.EvaporationReagent);
|
||||||
|
|
||||||
// No material
|
// No material
|
||||||
if (available == FixedPoint2.Zero)
|
if (available == FixedPoint2.Zero)
|
||||||
|
|||||||
@@ -25,7 +25,7 @@ public sealed partial class PuddleSystem
|
|||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
if (solution.ContainsReagent(EvaporationReagent))
|
if (solution.ContainsPrototype(EvaporationReagent))
|
||||||
{
|
{
|
||||||
var evaporation = AddComp<EvaporationComponent>(uid);
|
var evaporation = AddComp<EvaporationComponent>(uid);
|
||||||
evaporation.NextTick = _timing.CurTime + EvaporationCooldown;
|
evaporation.NextTick = _timing.CurTime + EvaporationCooldown;
|
||||||
@@ -51,7 +51,7 @@ public sealed partial class PuddleSystem
|
|||||||
continue;
|
continue;
|
||||||
|
|
||||||
var reagentTick = evaporation.EvaporationAmount * EvaporationCooldown.TotalSeconds;
|
var reagentTick = evaporation.EvaporationAmount * EvaporationCooldown.TotalSeconds;
|
||||||
_solutionContainerSystem.TryRemoveReagent(uid, puddleSolution, EvaporationReagent, reagentTick);
|
_solutionContainerSystem.RemoveReagent(uid, puddleSolution, EvaporationReagent, reagentTick);
|
||||||
|
|
||||||
// Despawn if we're done
|
// Despawn if we're done
|
||||||
if (puddleSolution.Volume == FixedPoint2.Zero)
|
if (puddleSolution.Volume == FixedPoint2.Zero)
|
||||||
@@ -65,6 +65,6 @@ public sealed partial class PuddleSystem
|
|||||||
|
|
||||||
public bool CanFullyEvaporate(Solution solution)
|
public bool CanFullyEvaporate(Solution solution)
|
||||||
{
|
{
|
||||||
return solution.Contents.Count == 1 && solution.ContainsReagent(EvaporationReagent);
|
return solution.Contents.Count == 1 && solution.ContainsPrototype(EvaporationReagent);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -56,6 +56,17 @@ public sealed partial class PuddleSystem : SharedPuddleSystem
|
|||||||
[Dependency] private readonly SlowContactsSystem _slowContacts = default!;
|
[Dependency] private readonly SlowContactsSystem _slowContacts = default!;
|
||||||
[Dependency] private readonly TileFrictionController _tile = default!;
|
[Dependency] private readonly TileFrictionController _tile = default!;
|
||||||
|
|
||||||
|
[ValidatePrototypeId<ReagentPrototype>]
|
||||||
|
private const string Blood = "Blood";
|
||||||
|
|
||||||
|
[ValidatePrototypeId<ReagentPrototype>]
|
||||||
|
private const string Slime = "Slime";
|
||||||
|
|
||||||
|
[ValidatePrototypeId<ReagentPrototype>]
|
||||||
|
private const string SpiderBlood = "SpiderBlood";
|
||||||
|
|
||||||
|
private static string[] _standoutReagents = new[] { Blood, Slime, SpiderBlood };
|
||||||
|
|
||||||
public static float PuddleVolume = 1000;
|
public static float PuddleVolume = 1000;
|
||||||
|
|
||||||
// Using local deletion queue instead of the standard queue so that we can easily "undelete" if a puddle
|
// Using local deletion queue instead of the standard queue so that we can easily "undelete" if a puddle
|
||||||
@@ -272,14 +283,14 @@ public sealed partial class PuddleSystem : SharedPuddleSystem
|
|||||||
// Make blood stand out more
|
// Make blood stand out more
|
||||||
// Kinda EH
|
// Kinda EH
|
||||||
// Could potentially do alpha per-solution but future problem.
|
// Could potentially do alpha per-solution but future problem.
|
||||||
var standoutReagents = new string[] { "Blood", "Slime", "SpiderBlood" };
|
|
||||||
|
|
||||||
color = solution.GetColorWithout(_prototypeManager, standoutReagents);
|
color = solution.GetColorWithout(_prototypeManager, _standoutReagents);
|
||||||
color = color.WithAlpha(0.7f);
|
color = color.WithAlpha(0.7f);
|
||||||
|
|
||||||
foreach (var standout in standoutReagents)
|
foreach (var standout in _standoutReagents)
|
||||||
{
|
{
|
||||||
if (!solution.TryGetReagent(standout, out var quantity))
|
var quantity = solution.GetTotalPrototypeQuantity(standout);
|
||||||
|
if (quantity <= FixedPoint2.Zero)
|
||||||
continue;
|
continue;
|
||||||
|
|
||||||
var interpolateValue = quantity.Float() / solution.Volume.Float();
|
var interpolateValue = quantity.Float() / solution.Volume.Float();
|
||||||
@@ -298,13 +309,13 @@ public sealed partial class PuddleSystem : SharedPuddleSystem
|
|||||||
var amountRequired = FixedPoint2.New(component.OverflowVolume.Float() * LowThreshold);
|
var amountRequired = FixedPoint2.New(component.OverflowVolume.Float() * LowThreshold);
|
||||||
var slipperyAmount = FixedPoint2.Zero;
|
var slipperyAmount = FixedPoint2.Zero;
|
||||||
|
|
||||||
foreach (var reagent in solution.Contents)
|
foreach (var (reagent, quantity) in solution.Contents)
|
||||||
{
|
{
|
||||||
var reagentProto = _prototypeManager.Index<ReagentPrototype>(reagent.ReagentId);
|
var reagentProto = _prototypeManager.Index<ReagentPrototype>(reagent.Prototype);
|
||||||
|
|
||||||
if (reagentProto.Slippery)
|
if (reagentProto.Slippery)
|
||||||
{
|
{
|
||||||
slipperyAmount += reagent.Quantity;
|
slipperyAmount += quantity;
|
||||||
|
|
||||||
if (slipperyAmount > amountRequired)
|
if (slipperyAmount > amountRequired)
|
||||||
{
|
{
|
||||||
@@ -331,9 +342,9 @@ public sealed partial class PuddleSystem : SharedPuddleSystem
|
|||||||
private void UpdateSlow(EntityUid uid, Solution solution)
|
private void UpdateSlow(EntityUid uid, Solution solution)
|
||||||
{
|
{
|
||||||
var maxViscosity = 0f;
|
var maxViscosity = 0f;
|
||||||
foreach (var reagent in solution.Contents)
|
foreach (var (reagent, _) in solution.Contents)
|
||||||
{
|
{
|
||||||
var reagentProto = _prototypeManager.Index<ReagentPrototype>(reagent.ReagentId);
|
var reagentProto = _prototypeManager.Index<ReagentPrototype>(reagent.Prototype);
|
||||||
maxViscosity = Math.Max(maxViscosity, reagentProto.Viscosity);
|
maxViscosity = Math.Max(maxViscosity, reagentProto.Viscosity);
|
||||||
}
|
}
|
||||||
if (maxViscosity > 0)
|
if (maxViscosity > 0)
|
||||||
@@ -362,7 +373,7 @@ public sealed partial class PuddleSystem : SharedPuddleSystem
|
|||||||
{
|
{
|
||||||
args.PushMarkup(Loc.GetString("puddle-component-examine-evaporating"));
|
args.PushMarkup(Loc.GetString("puddle-component-examine-evaporating"));
|
||||||
}
|
}
|
||||||
else if (solution?.ContainsReagent(EvaporationReagent) == true)
|
else if (solution?.ContainsPrototype(EvaporationReagent) == true)
|
||||||
{
|
{
|
||||||
args.PushMarkup(Loc.GetString("puddle-component-examine-evaporating-partial"));
|
args.PushMarkup(Loc.GetString("puddle-component-examine-evaporating-partial"));
|
||||||
}
|
}
|
||||||
@@ -588,15 +599,15 @@ public sealed partial class PuddleSystem : SharedPuddleSystem
|
|||||||
if (tileReact)
|
if (tileReact)
|
||||||
{
|
{
|
||||||
// First, do all tile reactions
|
// First, do all tile reactions
|
||||||
for (var i = 0; i < solution.Contents.Count; i++)
|
for (var i = solution.Contents.Count - 1; i >= 0; i--)
|
||||||
{
|
{
|
||||||
var (reagentId, quantity) = solution.Contents[i];
|
var (reagent, quantity) = solution.Contents[i];
|
||||||
var proto = _prototypeManager.Index<ReagentPrototype>(reagentId);
|
var proto = _prototypeManager.Index<ReagentPrototype>(reagent.Prototype);
|
||||||
var removed = proto.ReactionTile(tileRef, quantity);
|
var removed = proto.ReactionTile(tileRef, quantity);
|
||||||
if (removed <= FixedPoint2.Zero)
|
if (removed <= FixedPoint2.Zero)
|
||||||
continue;
|
continue;
|
||||||
|
|
||||||
solution.RemoveReagent(reagentId, removed);
|
solution.RemoveReagent(reagent, removed);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|||||||
@@ -113,6 +113,8 @@ namespace Content.Server.Kitchen.EntitySystems
|
|||||||
|
|
||||||
private void SubtractContents(MicrowaveComponent component, FoodRecipePrototype recipe)
|
private void SubtractContents(MicrowaveComponent component, FoodRecipePrototype recipe)
|
||||||
{
|
{
|
||||||
|
// TODO Turn recipe.IngredientsReagents into a ReagentQuantity[]
|
||||||
|
|
||||||
var totalReagentsToRemove = new Dictionary<string, FixedPoint2>(recipe.IngredientsReagents);
|
var totalReagentsToRemove = new Dictionary<string, FixedPoint2>(recipe.IngredientsReagents);
|
||||||
|
|
||||||
// this is spaghetti ngl
|
// this is spaghetti ngl
|
||||||
@@ -130,10 +132,7 @@ namespace Content.Server.Kitchen.EntitySystems
|
|||||||
if (!totalReagentsToRemove.ContainsKey(reagent))
|
if (!totalReagentsToRemove.ContainsKey(reagent))
|
||||||
continue;
|
continue;
|
||||||
|
|
||||||
if (!solution.ContainsReagent(reagent))
|
var quant = solution.GetTotalPrototypeQuantity(reagent);
|
||||||
continue;
|
|
||||||
|
|
||||||
var quant = solution.GetReagentQuantity(reagent);
|
|
||||||
|
|
||||||
if (quant >= totalReagentsToRemove[reagent])
|
if (quant >= totalReagentsToRemove[reagent])
|
||||||
{
|
{
|
||||||
@@ -145,7 +144,7 @@ namespace Content.Server.Kitchen.EntitySystems
|
|||||||
totalReagentsToRemove[reagent] -= quant;
|
totalReagentsToRemove[reagent] -= quant;
|
||||||
}
|
}
|
||||||
|
|
||||||
_solutionContainer.TryRemoveReagent(item, solution, reagent, quant);
|
_solutionContainer.RemoveReagent(item, solution, reagent, quant);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@@ -324,6 +323,8 @@ namespace Content.Server.Kitchen.EntitySystems
|
|||||||
|
|
||||||
var solidsDict = new Dictionary<string, int>();
|
var solidsDict = new Dictionary<string, int>();
|
||||||
var reagentDict = new Dictionary<string, FixedPoint2>();
|
var reagentDict = new Dictionary<string, FixedPoint2>();
|
||||||
|
// TODO use lists of Reagent quantities instead of reagent prototype ids.
|
||||||
|
|
||||||
foreach (var item in component.Storage.ContainedEntities)
|
foreach (var item in component.Storage.ContainedEntities)
|
||||||
{
|
{
|
||||||
// special behavior when being microwaved ;)
|
// special behavior when being microwaved ;)
|
||||||
@@ -370,12 +371,12 @@ namespace Content.Server.Kitchen.EntitySystems
|
|||||||
|
|
||||||
foreach (var (_, solution) in solMan.Solutions)
|
foreach (var (_, solution) in solMan.Solutions)
|
||||||
{
|
{
|
||||||
foreach (var reagent in solution.Contents)
|
foreach (var (reagent, quantity) in solution.Contents)
|
||||||
{
|
{
|
||||||
if (reagentDict.ContainsKey(reagent.ReagentId))
|
if (reagentDict.ContainsKey(reagent.Prototype))
|
||||||
reagentDict[reagent.ReagentId] += reagent.Quantity;
|
reagentDict[reagent.Prototype] += quantity;
|
||||||
else
|
else
|
||||||
reagentDict.Add(reagent.ReagentId, reagent.Quantity);
|
reagentDict.Add(reagent.Prototype, quantity);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@@ -417,6 +418,7 @@ namespace Content.Server.Kitchen.EntitySystems
|
|||||||
|
|
||||||
foreach (var reagent in recipe.IngredientsReagents)
|
foreach (var reagent in recipe.IngredientsReagents)
|
||||||
{
|
{
|
||||||
|
// TODO Turn recipe.IngredientsReagents into a ReagentQuantity[]
|
||||||
if (!reagents.ContainsKey(reagent.Key))
|
if (!reagents.ContainsKey(reagent.Key))
|
||||||
return (recipe, 0);
|
return (recipe, 0);
|
||||||
|
|
||||||
|
|||||||
@@ -220,14 +220,16 @@ public sealed class MaterialReclaimerSystem : SharedMaterialReclaimerSystem
|
|||||||
if (!Resolve(reclaimer, ref reclaimerComponent, ref xform))
|
if (!Resolve(reclaimer, ref reclaimerComponent, ref xform))
|
||||||
return;
|
return;
|
||||||
|
|
||||||
var overflow = new Solution();
|
efficiency *= reclaimerComponent.Efficiency;
|
||||||
var totalChemicals = new Dictionary<string, FixedPoint2>();
|
|
||||||
|
var totalChemicals = new Solution();
|
||||||
|
|
||||||
if (Resolve(item, ref composition, false))
|
if (Resolve(item, ref composition, false))
|
||||||
{
|
{
|
||||||
foreach (var (key, value) in composition.ChemicalComposition)
|
foreach (var (key, value) in composition.ChemicalComposition)
|
||||||
{
|
{
|
||||||
totalChemicals[key] = totalChemicals.GetValueOrDefault(key) + value;
|
// TODO use ReagentQuantity
|
||||||
|
totalChemicals.AddReagent(key, value * efficiency, false);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -238,27 +240,15 @@ public sealed class MaterialReclaimerSystem : SharedMaterialReclaimerSystem
|
|||||||
{
|
{
|
||||||
foreach (var quantity in solution.Contents)
|
foreach (var quantity in solution.Contents)
|
||||||
{
|
{
|
||||||
totalChemicals[quantity.ReagentId] =
|
totalChemicals.AddReagent(quantity.Reagent.Prototype, quantity.Quantity * efficiency, false);
|
||||||
totalChemicals.GetValueOrDefault(quantity.ReagentId) + quantity.Quantity;
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
foreach (var (reagent, amount) in totalChemicals)
|
_solutionContainer.TryTransferSolution(reclaimer, reclaimerComponent.OutputSolution, totalChemicals, totalChemicals.Volume);
|
||||||
|
if (totalChemicals.Volume > 0)
|
||||||
{
|
{
|
||||||
var outputAmount = amount * efficiency * reclaimerComponent.Efficiency;
|
_puddle.TrySpillAt(reclaimer, totalChemicals, out _, transformComponent: xform);
|
||||||
_solutionContainer.TryAddReagent(reclaimer, reclaimerComponent.OutputSolution, reagent, outputAmount,
|
|
||||||
out var accepted);
|
|
||||||
var overflowAmount = outputAmount - accepted;
|
|
||||||
if (overflowAmount > 0)
|
|
||||||
{
|
|
||||||
overflow.AddReagent(reagent, overflowAmount);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
if (overflow.Volume > 0)
|
|
||||||
{
|
|
||||||
_puddle.TrySpillAt(reclaimer, overflow, out _, transformComponent: xform);
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -1,12 +1,8 @@
|
|||||||
using System.Threading;
|
|
||||||
using Content.Server.Nutrition.EntitySystems;
|
using Content.Server.Nutrition.EntitySystems;
|
||||||
using Content.Shared.Damage;
|
using Content.Shared.Damage;
|
||||||
using Content.Shared.Atmos;
|
using Content.Shared.Atmos;
|
||||||
|
|
||||||
/// <summary>
|
namespace Content.Server.Nutrition.Components // Vapes are very nutritious.
|
||||||
/// Component for vapes
|
|
||||||
/// </summary>
|
|
||||||
namespace Content.Server.Nutrition.Components
|
|
||||||
{
|
{
|
||||||
[RegisterComponent, Access(typeof(SmokingSystem))]
|
[RegisterComponent, Access(typeof(SmokingSystem))]
|
||||||
public sealed partial class VapeComponent : Component
|
public sealed partial class VapeComponent : Component
|
||||||
@@ -23,6 +19,7 @@ namespace Content.Server.Nutrition.Components
|
|||||||
[ViewVariables(VVAccess.ReadWrite)]
|
[ViewVariables(VVAccess.ReadWrite)]
|
||||||
public float ExplosionIntensity { get; set; } = 2.5f;
|
public float ExplosionIntensity { get; set; } = 2.5f;
|
||||||
|
|
||||||
|
// TODO use RiggableComponent.
|
||||||
[DataField("explodeOnUse")]
|
[DataField("explodeOnUse")]
|
||||||
[ViewVariables(VVAccess.ReadWrite)]
|
[ViewVariables(VVAccess.ReadWrite)]
|
||||||
public bool ExplodeOnUse { get; set; } = false;
|
public bool ExplodeOnUse { get; set; } = false;
|
||||||
@@ -42,10 +39,9 @@ namespace Content.Server.Nutrition.Components
|
|||||||
[ViewVariables(VVAccess.ReadWrite)]
|
[ViewVariables(VVAccess.ReadWrite)]
|
||||||
public float ReductionFactor { get; set; } = 300f;
|
public float ReductionFactor { get; set; } = 300f;
|
||||||
|
|
||||||
|
// TODO when this gets fixed, use prototype serializers
|
||||||
[DataField("solutionNeeded")]
|
[DataField("solutionNeeded")]
|
||||||
[ViewVariables(VVAccess.ReadWrite)]
|
[ViewVariables(VVAccess.ReadWrite)]
|
||||||
public string SolutionNeeded = "Water";
|
public string SolutionNeeded = "Water";
|
||||||
|
|
||||||
public CancellationTokenSource? CancelToken;
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -101,7 +101,7 @@ public sealed class DrinkSystem : EntitySystem
|
|||||||
var total = 0f;
|
var total = 0f;
|
||||||
foreach (var quantity in solution.Contents)
|
foreach (var quantity in solution.Contents)
|
||||||
{
|
{
|
||||||
var reagent = _proto.Index<ReagentPrototype>(quantity.ReagentId);
|
var reagent = _proto.Index<ReagentPrototype>(quantity.Reagent.Prototype);
|
||||||
if (reagent.Metabolisms == null)
|
if (reagent.Metabolisms == null)
|
||||||
continue;
|
continue;
|
||||||
|
|
||||||
|
|||||||
@@ -84,9 +84,9 @@ public sealed class FlavorProfileSystem : EntitySystem
|
|||||||
private HashSet<string> GetFlavorsFromReagents(Solution solution, int desiredAmount, HashSet<string>? toIgnore = null)
|
private HashSet<string> GetFlavorsFromReagents(Solution solution, int desiredAmount, HashSet<string>? toIgnore = null)
|
||||||
{
|
{
|
||||||
var flavors = new HashSet<string>();
|
var flavors = new HashSet<string>();
|
||||||
foreach (var reagent in solution.Contents)
|
foreach (var (reagent, quantity) in solution.GetReagentPrototypes(_prototypeManager))
|
||||||
{
|
{
|
||||||
if (toIgnore != null && toIgnore.Contains(reagent.ReagentId))
|
if (toIgnore != null && toIgnore.Contains(reagent.ID))
|
||||||
{
|
{
|
||||||
continue;
|
continue;
|
||||||
}
|
}
|
||||||
@@ -96,15 +96,14 @@ public sealed class FlavorProfileSystem : EntitySystem
|
|||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
|
|
||||||
var proto = _prototypeManager.Index<ReagentPrototype>(reagent.ReagentId);
|
|
||||||
// don't care if the quantity is negligible
|
// don't care if the quantity is negligible
|
||||||
if (reagent.Quantity < proto.FlavorMinimum)
|
if (quantity < reagent.FlavorMinimum)
|
||||||
{
|
{
|
||||||
continue;
|
continue;
|
||||||
}
|
}
|
||||||
|
|
||||||
if (proto.Flavor != null)
|
if (reagent.Flavor != null)
|
||||||
flavors.Add(proto.Flavor);
|
flavors.Add(reagent.Flavor);
|
||||||
}
|
}
|
||||||
|
|
||||||
return flavors;
|
return flavors;
|
||||||
|
|||||||
@@ -35,7 +35,7 @@ namespace Content.Server.Nutrition.EntitySystems
|
|||||||
SubscribeLocalEvent<VapeComponent, GotEmaggedEvent>(OnEmagged);
|
SubscribeLocalEvent<VapeComponent, GotEmaggedEvent>(OnEmagged);
|
||||||
}
|
}
|
||||||
|
|
||||||
private void OnVapeInteraction(EntityUid uid, VapeComponent comp, AfterInteractEvent args)
|
private void OnVapeInteraction(EntityUid uid, VapeComponent comp, AfterInteractEvent args)
|
||||||
{
|
{
|
||||||
_solutionContainerSystem.TryGetRefillableSolution(uid, out var solution);
|
_solutionContainerSystem.TryGetRefillableSolution(uid, out var solution);
|
||||||
|
|
||||||
@@ -44,11 +44,12 @@ namespace Content.Server.Nutrition.EntitySystems
|
|||||||
var exploded = false;
|
var exploded = false;
|
||||||
|
|
||||||
if (!args.CanReach
|
if (!args.CanReach
|
||||||
|| solution == null
|
|| solution == null
|
||||||
|| comp.CancelToken != null
|
|| !HasComp<BloodstreamComponent>(args.Target)
|
||||||
|| !TryComp<BloodstreamComponent>(args.Target, out var _)
|
|| _foodSystem.IsMouthBlocked(args.Target.Value, args.User))
|
||||||
|| _foodSystem.IsMouthBlocked(args.Target.Value, args.User))
|
{
|
||||||
return;
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
if (solution.Contents.Count == 0)
|
if (solution.Contents.Count == 0)
|
||||||
{
|
{
|
||||||
@@ -72,9 +73,14 @@ namespace Content.Server.Nutrition.EntitySystems
|
|||||||
}
|
}
|
||||||
else
|
else
|
||||||
{
|
{
|
||||||
|
// All vapes explode if they contain anything other than pure water???
|
||||||
|
// WTF is this? Why is this? Am I going insane?
|
||||||
|
// Who the fuck vapes pure water?
|
||||||
|
// If this isn't how this is meant to work and this is meant to be for vapes with plasma or something,
|
||||||
|
// just re-use the existing RiggableSystem.
|
||||||
foreach (var name in solution.Contents)
|
foreach (var name in solution.Contents)
|
||||||
{
|
{
|
||||||
if (name.ReagentId != comp.SolutionNeeded)
|
if (name.Reagent.Prototype != comp.SolutionNeeded)
|
||||||
{
|
{
|
||||||
exploded = true;
|
exploded = true;
|
||||||
_explosionSystem.QueueExplosion(uid, "Default", comp.ExplosionIntensity, 0.5f, 3, canCreateVacuum: false);
|
_explosionSystem.QueueExplosion(uid, "Default", comp.ExplosionIntensity, 0.5f, 3, canCreateVacuum: false);
|
||||||
@@ -92,7 +98,7 @@ namespace Content.Server.Nutrition.EntitySystems
|
|||||||
_popupSystem.PopupEntity(
|
_popupSystem.PopupEntity(
|
||||||
Loc.GetString("vape-component-try-use-vape-forced", ("user", userName)), args.Target.Value,
|
Loc.GetString("vape-component-try-use-vape-forced", ("user", userName)), args.Target.Value,
|
||||||
args.Target.Value);
|
args.Target.Value);
|
||||||
|
|
||||||
_popupSystem.PopupEntity(
|
_popupSystem.PopupEntity(
|
||||||
Loc.GetString("vape-component-try-use-vape-forced-user", ("target", targetName)), args.User,
|
Loc.GetString("vape-component-try-use-vape-forced-user", ("target", targetName)), args.User,
|
||||||
args.User);
|
args.User);
|
||||||
@@ -106,8 +112,6 @@ namespace Content.Server.Nutrition.EntitySystems
|
|||||||
|
|
||||||
if (!exploded)
|
if (!exploded)
|
||||||
{
|
{
|
||||||
comp.CancelToken = new CancellationTokenSource();
|
|
||||||
|
|
||||||
var vapeDoAfterEvent = new VapeDoAfterEvent(solution, forced);
|
var vapeDoAfterEvent = new VapeDoAfterEvent(solution, forced);
|
||||||
_doAfterSystem.TryStartDoAfter(new DoAfterArgs(args.User, delay, vapeDoAfterEvent, uid, target: args.Target, used: uid)
|
_doAfterSystem.TryStartDoAfter(new DoAfterArgs(args.User, delay, vapeDoAfterEvent, uid, target: args.Target, used: uid)
|
||||||
{
|
{
|
||||||
@@ -121,14 +125,6 @@ namespace Content.Server.Nutrition.EntitySystems
|
|||||||
|
|
||||||
private void OnVapeDoAfter(EntityUid uid, VapeComponent comp, VapeDoAfterEvent args)
|
private void OnVapeDoAfter(EntityUid uid, VapeComponent comp, VapeDoAfterEvent args)
|
||||||
{
|
{
|
||||||
if (args.Cancelled)
|
|
||||||
{
|
|
||||||
comp.CancelToken = null;
|
|
||||||
return;
|
|
||||||
}
|
|
||||||
|
|
||||||
comp.CancelToken = null;
|
|
||||||
|
|
||||||
if (args.Handled
|
if (args.Handled
|
||||||
|| args.Args.Target == null)
|
|| args.Args.Target == null)
|
||||||
return;
|
return;
|
||||||
@@ -148,7 +144,7 @@ namespace Content.Server.Nutrition.EntitySystems
|
|||||||
_atmosphereSystem.Merge(environment, merger);
|
_atmosphereSystem.Merge(environment, merger);
|
||||||
|
|
||||||
args.Solution.RemoveAllSolution();
|
args.Solution.RemoveAllSolution();
|
||||||
|
|
||||||
if (args.Forced)
|
if (args.Forced)
|
||||||
{
|
{
|
||||||
var targetName = Identity.Entity(args.Args.Target.Value, EntityManager);
|
var targetName = Identity.Entity(args.Args.Target.Value, EntityManager);
|
||||||
@@ -157,7 +153,7 @@ namespace Content.Server.Nutrition.EntitySystems
|
|||||||
_popupSystem.PopupEntity(
|
_popupSystem.PopupEntity(
|
||||||
Loc.GetString("vape-component-vape-success-forced", ("user", userName)), args.Args.Target.Value,
|
Loc.GetString("vape-component-vape-success-forced", ("user", userName)), args.Args.Target.Value,
|
||||||
args.Args.Target.Value);
|
args.Args.Target.Value);
|
||||||
|
|
||||||
_popupSystem.PopupEntity(
|
_popupSystem.PopupEntity(
|
||||||
Loc.GetString("vape-component-vape-success-user-forced", ("target", targetName)), args.Args.User,
|
Loc.GetString("vape-component-vape-success-user-forced", ("target", targetName)), args.Args.User,
|
||||||
args.Args.Target.Value);
|
args.Args.Target.Value);
|
||||||
|
|||||||
@@ -1,11 +1,20 @@
|
|||||||
|
using Content.Shared.Chemistry.Reagent;
|
||||||
|
using Content.Shared.FixedPoint;
|
||||||
|
|
||||||
namespace Content.Server.Power.Components;
|
namespace Content.Server.Power.Components;
|
||||||
|
|
||||||
[RegisterComponent]
|
[RegisterComponent]
|
||||||
public sealed partial class RiggableComponent : Component
|
public sealed partial class RiggableComponent : Component
|
||||||
{
|
{
|
||||||
public const string SolutionName = "battery";
|
|
||||||
|
|
||||||
[ViewVariables(VVAccess.ReadWrite)]
|
[ViewVariables(VVAccess.ReadWrite)]
|
||||||
[DataField("isRigged")]
|
[DataField("isRigged")]
|
||||||
public bool IsRigged;
|
public bool IsRigged;
|
||||||
|
|
||||||
|
[ViewVariables(VVAccess.ReadWrite)]
|
||||||
|
[DataField("solution")]
|
||||||
|
public string Solution = "battery";
|
||||||
|
|
||||||
|
[ViewVariables(VVAccess.ReadWrite)]
|
||||||
|
[DataField("reagent")]
|
||||||
|
public ReagentQuantity RequiredQuantity = new("Plasma", FixedPoint2.New(5), null);
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -4,6 +4,7 @@ using Content.Server.Explosion.EntitySystems;
|
|||||||
using Content.Server.Kitchen.Components;
|
using Content.Server.Kitchen.Components;
|
||||||
using Content.Server.Power.Components;
|
using Content.Server.Power.Components;
|
||||||
using Content.Server.Stunnable.Components;
|
using Content.Server.Stunnable.Components;
|
||||||
|
using Content.Shared.Chemistry.Components;
|
||||||
using Content.Shared.Database;
|
using Content.Shared.Database;
|
||||||
using Content.Shared.Rejuvenate;
|
using Content.Shared.Rejuvenate;
|
||||||
|
|
||||||
@@ -47,27 +48,19 @@ public sealed class RiggableSystem : EntitySystem
|
|||||||
|
|
||||||
private void OnSolutionChanged(EntityUid uid, RiggableComponent component, SolutionChangedEvent args)
|
private void OnSolutionChanged(EntityUid uid, RiggableComponent component, SolutionChangedEvent args)
|
||||||
{
|
{
|
||||||
if (TryComp<BatteryComponent>(uid, out var battery))
|
if (args.SolutionId != component.Solution)
|
||||||
{
|
return;
|
||||||
IsRigged(uid, args);
|
|
||||||
}
|
|
||||||
|
|
||||||
if (component.IsRigged)
|
var wasRigged = component.IsRigged;
|
||||||
|
var quantity = args.Solution.GetReagentQuantity(component.RequiredQuantity.Reagent);
|
||||||
|
component.IsRigged = quantity >= component.RequiredQuantity.Quantity;
|
||||||
|
|
||||||
|
if (component.IsRigged && !wasRigged)
|
||||||
{
|
{
|
||||||
_adminLogger.Add(LogType.Explosion, LogImpact.Medium, $"{ToPrettyString(uid)} has been rigged up to explode when used.");
|
_adminLogger.Add(LogType.Explosion, LogImpact.Medium, $"{ToPrettyString(uid)} has been rigged up to explode when used.");
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
public void IsRigged(EntityUid uid, SolutionChangedEvent args)
|
|
||||||
{
|
|
||||||
if (TryComp<RiggableComponent>(uid, out var riggableComp))
|
|
||||||
{
|
|
||||||
riggableComp.IsRigged = _solutionsSystem.TryGetSolution(uid, RiggableComponent.SolutionName, out var solution)
|
|
||||||
&& solution.TryGetReagent("Plasma", out var plasma)
|
|
||||||
&& plasma >= 5;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
public void Explode(EntityUid uid, BatteryComponent? battery = null, EntityUid? cause = null)
|
public void Explode(EntityUid uid, BatteryComponent? battery = null, EntityUid? cause = null)
|
||||||
{
|
{
|
||||||
if (!Resolve(uid, ref battery))
|
if (!Resolve(uid, ref battery))
|
||||||
|
|||||||
@@ -81,7 +81,7 @@ public sealed class GeneratorSystem : SharedGeneratorSystem
|
|||||||
|
|
||||||
foreach (var reagentQuantity in solution)
|
foreach (var reagentQuantity in solution)
|
||||||
{
|
{
|
||||||
if (reagentQuantity.ReagentId != component.Reagent)
|
if (reagentQuantity.Reagent.Prototype != component.Reagent)
|
||||||
{
|
{
|
||||||
args.Clogged = true;
|
args.Clogged = true;
|
||||||
return;
|
return;
|
||||||
@@ -94,7 +94,7 @@ public sealed class GeneratorSystem : SharedGeneratorSystem
|
|||||||
if (!_solutionContainer.TryGetSolution(uid, component.Solution, out var solution))
|
if (!_solutionContainer.TryGetSolution(uid, component.Solution, out var solution))
|
||||||
return;
|
return;
|
||||||
|
|
||||||
var availableReagent = solution.GetReagentQuantity(component.Reagent).Value;
|
var availableReagent = solution.GetTotalPrototypeQuantity(component.Reagent).Value;
|
||||||
var toRemove = RemoveFractionalFuel(
|
var toRemove = RemoveFractionalFuel(
|
||||||
ref component.FractionalReagent,
|
ref component.FractionalReagent,
|
||||||
args.FuelUsed,
|
args.FuelUsed,
|
||||||
@@ -112,8 +112,8 @@ public sealed class GeneratorSystem : SharedGeneratorSystem
|
|||||||
if (!_solutionContainer.TryGetSolution(uid, component.Solution, out var solution))
|
if (!_solutionContainer.TryGetSolution(uid, component.Solution, out var solution))
|
||||||
return;
|
return;
|
||||||
|
|
||||||
var reagent = component.FractionalReagent * FixedPoint2.Epsilon.Float()
|
var availableReagent = solution.GetTotalPrototypeQuantity(component.Reagent).Float();
|
||||||
+ solution.GetReagentQuantity(component.Reagent).Float();
|
var reagent = component.FractionalReagent * FixedPoint2.Epsilon.Float() + availableReagent;
|
||||||
args.Fuel = reagent * component.Multiplier;
|
args.Fuel = reagent * component.Multiplier;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|||||||
@@ -58,7 +58,7 @@ namespace Content.Server.Tools
|
|||||||
|| !_solutionContainerSystem.TryGetSolution(uid, welder.FuelSolution, out var fuelSolution, solutionContainer))
|
|| !_solutionContainerSystem.TryGetSolution(uid, welder.FuelSolution, out var fuelSolution, solutionContainer))
|
||||||
return (FixedPoint2.Zero, FixedPoint2.Zero);
|
return (FixedPoint2.Zero, FixedPoint2.Zero);
|
||||||
|
|
||||||
return (_solutionContainerSystem.GetReagentQuantity(uid, welder.FuelReagent), fuelSolution.MaxVolume);
|
return (_solutionContainerSystem.GetTotalPrototypeQuantity(uid, welder.FuelReagent), fuelSolution.MaxVolume);
|
||||||
}
|
}
|
||||||
|
|
||||||
public bool TryToggleWelder(EntityUid uid, EntityUid? user,
|
public bool TryToggleWelder(EntityUid uid, EntityUid? user,
|
||||||
@@ -95,7 +95,7 @@ namespace Content.Server.Tools
|
|||||||
if (!_solutionContainerSystem.TryGetSolution(uid, welder.FuelSolution, out var solution, solutionContainer))
|
if (!_solutionContainerSystem.TryGetSolution(uid, welder.FuelSolution, out var solution, solutionContainer))
|
||||||
return false;
|
return false;
|
||||||
|
|
||||||
var fuel = solution.GetReagentQuantity(welder.FuelReagent);
|
var fuel = solution.GetTotalPrototypeQuantity(welder.FuelReagent);
|
||||||
|
|
||||||
// Not enough fuel to lit welder.
|
// Not enough fuel to lit welder.
|
||||||
if (fuel == FixedPoint2.Zero || fuel < welder.FuelLitCost)
|
if (fuel == FixedPoint2.Zero || fuel < welder.FuelLitCost)
|
||||||
@@ -307,7 +307,7 @@ namespace Content.Server.Tools
|
|||||||
|
|
||||||
solution.RemoveReagent(welder.FuelReagent, welder.FuelConsumption * _welderTimer);
|
solution.RemoveReagent(welder.FuelReagent, welder.FuelConsumption * _welderTimer);
|
||||||
|
|
||||||
if (solution.GetReagentQuantity(welder.FuelReagent) <= FixedPoint2.Zero)
|
if (solution.GetTotalPrototypeQuantity(welder.FuelReagent) <= FixedPoint2.Zero)
|
||||||
TryTurnWelderOff(tool, null, welder);
|
TryTurnWelderOff(tool, null, welder);
|
||||||
|
|
||||||
_entityManager.Dirty(welder);
|
_entityManager.Dirty(welder);
|
||||||
|
|||||||
@@ -3,10 +3,8 @@ using Content.Shared.FixedPoint;
|
|||||||
using JetBrains.Annotations;
|
using JetBrains.Annotations;
|
||||||
using Robust.Shared.Prototypes;
|
using Robust.Shared.Prototypes;
|
||||||
using Robust.Shared.Serialization;
|
using Robust.Shared.Serialization;
|
||||||
using Robust.Shared.Serialization.TypeSerializers.Implementations.Custom.Prototype;
|
|
||||||
using Robust.Shared.Utility;
|
using Robust.Shared.Utility;
|
||||||
using System.Collections;
|
using System.Collections;
|
||||||
using System.Diagnostics.CodeAnalysis;
|
|
||||||
using System.Linq;
|
using System.Linq;
|
||||||
|
|
||||||
namespace Content.Shared.Chemistry.Components
|
namespace Content.Shared.Chemistry.Components
|
||||||
@@ -16,12 +14,12 @@ namespace Content.Shared.Chemistry.Components
|
|||||||
/// </summary>
|
/// </summary>
|
||||||
[Serializable, NetSerializable]
|
[Serializable, NetSerializable]
|
||||||
[DataDefinition]
|
[DataDefinition]
|
||||||
public sealed partial class Solution : IEnumerable<Solution.ReagentQuantity>, ISerializationHooks
|
public sealed partial class Solution : IEnumerable<ReagentQuantity>, ISerializationHooks
|
||||||
{
|
{
|
||||||
// This is a list because it is actually faster to add and remove reagents from
|
// This is a list because it is actually faster to add and remove reagents from
|
||||||
// a list than a dictionary, though contains-reagent checks are slightly slower,
|
// a list than a dictionary, though contains-reagent checks are slightly slower,
|
||||||
[DataField("reagents")]
|
[DataField("reagents")]
|
||||||
public List<ReagentQuantity> Contents = new(2);
|
public List<ReagentQuantity> Contents;
|
||||||
|
|
||||||
/// <summary>
|
/// <summary>
|
||||||
/// The calculated total volume of all reagents in the solution (ex. Total volume of liquid in beaker).
|
/// The calculated total volume of all reagents in the solution (ex. Total volume of liquid in beaker).
|
||||||
@@ -86,14 +84,12 @@ namespace Content.Shared.Chemistry.Components
|
|||||||
/// <summary>
|
/// <summary>
|
||||||
/// The total heat capacity of all reagents in the solution.
|
/// The total heat capacity of all reagents in the solution.
|
||||||
/// </summary>
|
/// </summary>
|
||||||
[ViewVariables]
|
[ViewVariables] private float _heatCapacity;
|
||||||
private float _heatCapacity;
|
|
||||||
|
|
||||||
/// <summary>
|
/// <summary>
|
||||||
/// If true, then <see cref="_heatCapacity"/> needs to be recomputed.
|
/// If true, then <see cref="_heatCapacity"/> needs to be recomputed.
|
||||||
/// </summary>
|
/// </summary>
|
||||||
[ViewVariables]
|
[ViewVariables] private bool _heatCapacityDirty = true;
|
||||||
private bool _heatCapacityDirty = true;
|
|
||||||
|
|
||||||
public void UpdateHeatCapacity(IPrototypeManager? protoMan)
|
public void UpdateHeatCapacity(IPrototypeManager? protoMan)
|
||||||
{
|
{
|
||||||
@@ -101,9 +97,10 @@ namespace Content.Shared.Chemistry.Components
|
|||||||
DebugTools.Assert(_heatCapacityDirty);
|
DebugTools.Assert(_heatCapacityDirty);
|
||||||
_heatCapacityDirty = false;
|
_heatCapacityDirty = false;
|
||||||
_heatCapacity = 0;
|
_heatCapacity = 0;
|
||||||
foreach (var reagent in Contents)
|
foreach (var (reagent, quantity) in Contents)
|
||||||
{
|
{
|
||||||
_heatCapacity += (float) reagent.Quantity * protoMan.Index<ReagentPrototype>(reagent.ReagentId).SpecificHeat;
|
_heatCapacity += (float) quantity *
|
||||||
|
protoMan.Index<ReagentPrototype>(reagent.Prototype).SpecificHeat;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -137,11 +134,11 @@ namespace Content.Shared.Chemistry.Components
|
|||||||
/// <summary>
|
/// <summary>
|
||||||
/// Constructs a solution containing 100% of a reagent (ex. A beaker of pure water).
|
/// Constructs a solution containing 100% of a reagent (ex. A beaker of pure water).
|
||||||
/// </summary>
|
/// </summary>
|
||||||
/// <param name="reagentId">The prototype ID of the reagent to add.</param>
|
/// <param name="prototype">The prototype ID of the reagent to add.</param>
|
||||||
/// <param name="quantity">The quantity in milli-units.</param>
|
/// <param name="quantity">The quantity in milli-units.</param>
|
||||||
public Solution(string reagentId, FixedPoint2 quantity) : this()
|
public Solution(string prototype, FixedPoint2 quantity, ReagentData? data = null) : this()
|
||||||
{
|
{
|
||||||
AddReagent(reagentId, quantity);
|
AddReagent(new ReagentId(prototype, data), quantity);
|
||||||
}
|
}
|
||||||
|
|
||||||
public Solution(IEnumerable<ReagentQuantity> reagents, bool setMaxVol = true)
|
public Solution(IEnumerable<ReagentQuantity> reagents, bool setMaxVol = true)
|
||||||
@@ -173,7 +170,6 @@ namespace Content.Shared.Chemistry.Components
|
|||||||
return new Solution(this);
|
return new Solution(this);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
[AssertionMethod]
|
[AssertionMethod]
|
||||||
public void ValidateSolution()
|
public void ValidateSolution()
|
||||||
{
|
{
|
||||||
@@ -185,8 +181,8 @@ namespace Content.Shared.Chemistry.Components
|
|||||||
// All reagents have at least some reagent present.
|
// All reagents have at least some reagent present.
|
||||||
DebugTools.Assert(!Contents.Any(x => x.Quantity <= FixedPoint2.Zero));
|
DebugTools.Assert(!Contents.Any(x => x.Quantity <= FixedPoint2.Zero));
|
||||||
|
|
||||||
// No duplicate reagent iDs
|
// No duplicate reagents iDs
|
||||||
DebugTools.Assert(Contents.Select(x => x.ReagentId).ToHashSet().Count() == Contents.Count);
|
DebugTools.Assert(Contents.Select(x => x.Reagent).ToHashSet().Count == Contents.Count);
|
||||||
|
|
||||||
// If it isn't flagged as dirty, check heat capacity is correct.
|
// If it isn't flagged as dirty, check heat capacity is correct.
|
||||||
if (!_heatCapacityDirty)
|
if (!_heatCapacityDirty)
|
||||||
@@ -211,33 +207,101 @@ namespace Content.Shared.Chemistry.Components
|
|||||||
MaxVolume = Volume;
|
MaxVolume = Volume;
|
||||||
}
|
}
|
||||||
|
|
||||||
public bool ContainsReagent(string reagentId)
|
public bool ContainsPrototype(string prototype)
|
||||||
{
|
{
|
||||||
foreach (var reagent in Contents)
|
foreach (var (reagent, _) in Contents)
|
||||||
{
|
{
|
||||||
if (reagent.ReagentId == reagentId)
|
if (reagent.Prototype == prototype)
|
||||||
return true;
|
return true;
|
||||||
}
|
}
|
||||||
|
|
||||||
return false;
|
return false;
|
||||||
}
|
}
|
||||||
|
|
||||||
public bool TryGetReagent(string reagentId, out FixedPoint2 quantity)
|
public bool ContainsReagent(ReagentId id)
|
||||||
{
|
{
|
||||||
foreach (var reagent in Contents)
|
foreach (var (reagent, _) in Contents)
|
||||||
{
|
{
|
||||||
if (reagent.ReagentId == reagentId)
|
if (reagent == id)
|
||||||
{
|
|
||||||
quantity = reagent.Quantity;
|
|
||||||
return true;
|
return true;
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|
||||||
quantity = FixedPoint2.New(0);
|
|
||||||
return false;
|
return false;
|
||||||
}
|
}
|
||||||
|
|
||||||
public string? GetPrimaryReagentId()
|
public bool ContainsReagent(string reagentId, ReagentData? data)
|
||||||
|
=> ContainsReagent(new(reagentId, data));
|
||||||
|
|
||||||
|
public bool TryGetReagent(ReagentId id, out ReagentQuantity quantity)
|
||||||
|
{
|
||||||
|
foreach (var tuple in Contents)
|
||||||
|
{
|
||||||
|
if (tuple.Reagent != id)
|
||||||
|
continue;
|
||||||
|
|
||||||
|
DebugTools.Assert(tuple.Quantity > FixedPoint2.Zero);
|
||||||
|
quantity = tuple;
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
|
||||||
|
quantity = new ReagentQuantity(id, FixedPoint2.Zero);
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
|
||||||
|
public bool TryGetReagentQuantity(ReagentId id, out FixedPoint2 volume)
|
||||||
|
{
|
||||||
|
volume = FixedPoint2.Zero;
|
||||||
|
if (!TryGetReagent(id, out var quant))
|
||||||
|
return false;
|
||||||
|
|
||||||
|
volume = quant.Quantity;
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
|
||||||
|
[Pure]
|
||||||
|
public ReagentQuantity GetReagent(ReagentId id)
|
||||||
|
{
|
||||||
|
TryGetReagent(id, out var quantity);
|
||||||
|
return quantity;
|
||||||
|
}
|
||||||
|
|
||||||
|
public ReagentQuantity this[ReagentId id]
|
||||||
|
{
|
||||||
|
get
|
||||||
|
{
|
||||||
|
if (!TryGetReagent(id, out var quantity))
|
||||||
|
throw new KeyNotFoundException(id.ToString());
|
||||||
|
return quantity;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// Get the volume/quantity of a single reagent in the solution.
|
||||||
|
/// </summary>
|
||||||
|
[Pure]
|
||||||
|
public FixedPoint2 GetReagentQuantity(ReagentId id)
|
||||||
|
{
|
||||||
|
return GetReagent(id).Quantity;
|
||||||
|
}
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// Gets the total volume of all reagents in the solution with the given prototype Id.
|
||||||
|
/// If you only want the volume of a single reagent, use <see cref="GetReagentQuantity"/>
|
||||||
|
/// </summary>
|
||||||
|
[Pure]
|
||||||
|
public FixedPoint2 GetTotalPrototypeQuantity(string prototype)
|
||||||
|
{
|
||||||
|
var total = FixedPoint2.Zero;
|
||||||
|
foreach (var (reagent, quantity) in Contents)
|
||||||
|
{
|
||||||
|
if (reagent.Prototype == prototype)
|
||||||
|
total += quantity;
|
||||||
|
}
|
||||||
|
|
||||||
|
return total;
|
||||||
|
}
|
||||||
|
|
||||||
|
public ReagentId? GetPrimaryReagentId()
|
||||||
{
|
{
|
||||||
if (Contents.Count == 0)
|
if (Contents.Count == 0)
|
||||||
return null;
|
return null;
|
||||||
@@ -252,15 +316,23 @@ namespace Content.Shared.Chemistry.Components
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
return max.ReagentId!;
|
return max.Reagent;
|
||||||
}
|
}
|
||||||
|
|
||||||
/// <summary>
|
/// <summary>
|
||||||
/// Adds a given quantity of a reagent directly into the solution.
|
/// Adds a given quantity of a reagent directly into the solution.
|
||||||
/// </summary>
|
/// </summary>
|
||||||
/// <param name="reagentId">The prototype ID of the reagent to add.</param>
|
/// <param name="prototype">The prototype ID of the reagent to add.</param>
|
||||||
/// <param name="quantity">The quantity in milli-units.</param>
|
/// <param name="quantity">The quantity in milli-units.</param>
|
||||||
public void AddReagent(string reagentId, FixedPoint2 quantity, bool dirtyHeatCap = true)
|
public void AddReagent(string prototype, FixedPoint2 quantity, bool dirtyHeatCap = true)
|
||||||
|
=> AddReagent(new ReagentId(prototype, null), quantity, dirtyHeatCap);
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// Adds a given quantity of a reagent directly into the solution.
|
||||||
|
/// </summary>
|
||||||
|
/// <param name="id">The reagent to add.</param>
|
||||||
|
/// <param name="quantity">The quantity in milli-units.</param>
|
||||||
|
public void AddReagent(ReagentId id, FixedPoint2 quantity, bool dirtyHeatCap = true)
|
||||||
{
|
{
|
||||||
if (quantity <= 0)
|
if (quantity <= 0)
|
||||||
{
|
{
|
||||||
@@ -272,42 +344,45 @@ namespace Content.Shared.Chemistry.Components
|
|||||||
_heatCapacityDirty |= dirtyHeatCap;
|
_heatCapacityDirty |= dirtyHeatCap;
|
||||||
for (var i = 0; i < Contents.Count; i++)
|
for (var i = 0; i < Contents.Count; i++)
|
||||||
{
|
{
|
||||||
var reagent = Contents[i];
|
var (reagent, existingQuantity) = Contents[i];
|
||||||
if (reagent.ReagentId != reagentId)
|
if (reagent != id)
|
||||||
continue;
|
continue;
|
||||||
|
|
||||||
Contents[i] = new ReagentQuantity(reagentId, reagent.Quantity + quantity);
|
Contents[i] = new ReagentQuantity(id, existingQuantity + quantity);
|
||||||
ValidateSolution();
|
ValidateSolution();
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
Contents.Add(new ReagentQuantity(reagentId, quantity));
|
Contents.Add(new ReagentQuantity(id, quantity));
|
||||||
ValidateSolution();
|
ValidateSolution();
|
||||||
}
|
}
|
||||||
|
|
||||||
/// <summary>
|
/// <summary>
|
||||||
/// Adds a given quantity of a reagent directly into the solution.
|
/// Adds a given quantity of a reagent directly into the solution.
|
||||||
/// </summary>
|
/// </summary>
|
||||||
/// <param name="proto">The prototype of the reagent to add.</param>
|
/// <param name="reagentId">The reagent to add.</param>
|
||||||
/// <param name="quantity">The quantity in milli-units.</param>
|
/// <param name="quantity">The quantity in milli-units.</param>
|
||||||
public void AddReagent(ReagentPrototype proto, FixedPoint2 quantity)
|
public void AddReagent(ReagentPrototype proto, ReagentId reagentId, FixedPoint2 quantity)
|
||||||
{
|
{
|
||||||
AddReagent(proto.ID, quantity, false);
|
AddReagent(reagentId, quantity, false);
|
||||||
_heatCapacity += quantity.Float() * proto.SpecificHeat;
|
_heatCapacity += quantity.Float() * proto.SpecificHeat;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
public void AddReagent(ReagentQuantity reagentQuantity)
|
||||||
|
=> AddReagent(reagentQuantity.Reagent, reagentQuantity.Quantity);
|
||||||
|
|
||||||
/// <summary>
|
/// <summary>
|
||||||
/// Adds a given quantity of a reagent directly into the solution.
|
/// Adds a given quantity of a reagent directly into the solution.
|
||||||
/// </summary>
|
/// </summary>
|
||||||
/// <param name="proto">The prototype of the reagent to add.</param>
|
/// <param name="proto">The prototype of the reagent to add.</param>
|
||||||
/// <param name="quantity">The quantity in milli-units.</param>
|
/// <param name="quantity">The quantity in milli-units.</param>
|
||||||
public void AddReagent(ReagentPrototype proto, FixedPoint2 quantity, float temperature, IPrototypeManager? protoMan)
|
public void AddReagent(ReagentPrototype proto, FixedPoint2 quantity, float temperature, IPrototypeManager? protoMan, ReagentData? data = null)
|
||||||
{
|
{
|
||||||
if (_heatCapacityDirty)
|
if (_heatCapacityDirty)
|
||||||
UpdateHeatCapacity(protoMan);
|
UpdateHeatCapacity(protoMan);
|
||||||
|
|
||||||
var totalThermalEnergy = Temperature * _heatCapacity + temperature * proto.SpecificHeat;
|
var totalThermalEnergy = Temperature * _heatCapacity + temperature * proto.SpecificHeat;
|
||||||
AddReagent(proto, quantity);
|
AddReagent(new ReagentId(proto.ID, data), quantity);
|
||||||
Temperature = _heatCapacity == 0 ? 0 : totalThermalEnergy / _heatCapacity;
|
Temperature = _heatCapacity == 0 ? 0 : totalThermalEnergy / _heatCapacity;
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -333,7 +408,7 @@ namespace Content.Shared.Chemistry.Components
|
|||||||
for (int i = 0; i < Contents.Count; i++)
|
for (int i = 0; i < Contents.Count; i++)
|
||||||
{
|
{
|
||||||
var old = Contents[i];
|
var old = Contents[i];
|
||||||
Contents[i] = new ReagentQuantity(old.ReagentId, old.Quantity * scale);
|
Contents[i] = new ReagentQuantity(old.Reagent, old.Quantity * scale);
|
||||||
}
|
}
|
||||||
ValidateSolution();
|
ValidateSolution();
|
||||||
}
|
}
|
||||||
@@ -362,7 +437,7 @@ namespace Content.Shared.Chemistry.Components
|
|||||||
Contents.RemoveSwap(i);
|
Contents.RemoveSwap(i);
|
||||||
else
|
else
|
||||||
{
|
{
|
||||||
Contents[i] = new ReagentQuantity(old.ReagentId, newQuantity);
|
Contents[i] = new ReagentQuantity(old.Reagent, newQuantity);
|
||||||
Volume += newQuantity;
|
Volume += newQuantity;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@@ -371,43 +446,24 @@ namespace Content.Shared.Chemistry.Components
|
|||||||
ValidateSolution();
|
ValidateSolution();
|
||||||
}
|
}
|
||||||
|
|
||||||
/// <summary>
|
|
||||||
/// Returns the amount of a single reagent inside the solution.
|
|
||||||
/// </summary>
|
|
||||||
/// <param name="reagentId">The prototype ID of the reagent to add.</param>
|
|
||||||
/// <returns>The quantity in milli-units.</returns>
|
|
||||||
public FixedPoint2 GetReagentQuantity(string reagentId)
|
|
||||||
{
|
|
||||||
for (var i = 0; i < Contents.Count; i++)
|
|
||||||
{
|
|
||||||
var reagent = Contents[i];
|
|
||||||
if (reagent.ReagentId == reagentId)
|
|
||||||
return reagent.Quantity;
|
|
||||||
}
|
|
||||||
|
|
||||||
return FixedPoint2.Zero;
|
|
||||||
}
|
|
||||||
|
|
||||||
/// <summary>
|
/// <summary>
|
||||||
/// Attempts to remove an amount of reagent from the solution.
|
/// Attempts to remove an amount of reagent from the solution.
|
||||||
/// </summary>
|
/// </summary>
|
||||||
/// <param name="reagentId">The reagent to be removed.</param>
|
/// <param name="toRemove">The reagent to be removed.</param>
|
||||||
/// <param name="quantity">The amount of reagent to remove.</param>
|
|
||||||
/// <returns>How much reagent was actually removed. Zero if the reagent is not present on the solution.</returns>
|
/// <returns>How much reagent was actually removed. Zero if the reagent is not present on the solution.</returns>
|
||||||
public FixedPoint2 RemoveReagent(string reagentId, FixedPoint2 quantity)
|
public FixedPoint2 RemoveReagent(ReagentQuantity toRemove)
|
||||||
{
|
{
|
||||||
if (quantity <= FixedPoint2.Zero)
|
if (toRemove.Quantity <= FixedPoint2.Zero)
|
||||||
return FixedPoint2.Zero;
|
return FixedPoint2.Zero;
|
||||||
|
|
||||||
for (var i = 0; i < Contents.Count; i++)
|
for (var i = 0; i < Contents.Count; i++)
|
||||||
{
|
{
|
||||||
var reagent = Contents[i];
|
var (reagent, curQuantity) = Contents[i];
|
||||||
|
|
||||||
if(reagent.ReagentId != reagentId)
|
if(reagent != toRemove.Reagent)
|
||||||
continue;
|
continue;
|
||||||
|
|
||||||
var curQuantity = reagent.Quantity;
|
var newQuantity = curQuantity - toRemove.Quantity;
|
||||||
var newQuantity = curQuantity - quantity;
|
|
||||||
_heatCapacityDirty = true;
|
_heatCapacityDirty = true;
|
||||||
|
|
||||||
if (newQuantity <= 0)
|
if (newQuantity <= 0)
|
||||||
@@ -418,16 +474,38 @@ namespace Content.Shared.Chemistry.Components
|
|||||||
return curQuantity;
|
return curQuantity;
|
||||||
}
|
}
|
||||||
|
|
||||||
Contents[i] = new ReagentQuantity(reagentId, newQuantity);
|
Contents[i] = new ReagentQuantity(reagent, newQuantity);
|
||||||
Volume -= quantity;
|
Volume -= toRemove.Quantity;
|
||||||
ValidateSolution();
|
ValidateSolution();
|
||||||
return quantity;
|
return toRemove.Quantity;
|
||||||
}
|
}
|
||||||
|
|
||||||
// Reagent is not on the solution...
|
// Reagent is not on the solution...
|
||||||
return FixedPoint2.Zero;
|
return FixedPoint2.Zero;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// Attempts to remove an amount of reagent from the solution.
|
||||||
|
/// </summary>
|
||||||
|
/// <param name="prototype">The prototype of the reagent to be removed.</param>
|
||||||
|
/// <param name="quantity">The amount of reagent to remove.</param>
|
||||||
|
/// <returns>How much reagent was actually removed. Zero if the reagent is not present on the solution.</returns>
|
||||||
|
public FixedPoint2 RemoveReagent(string prototype, FixedPoint2 quantity, ReagentData? data = null)
|
||||||
|
{
|
||||||
|
return RemoveReagent(new ReagentQuantity(prototype, quantity, data));
|
||||||
|
}
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// Attempts to remove an amount of reagent from the solution.
|
||||||
|
/// </summary>
|
||||||
|
/// <param name="reagentId">The reagent to be removed.</param>
|
||||||
|
/// <param name="quantity">The amount of reagent to remove.</param>
|
||||||
|
/// <returns>How much reagent was actually removed. Zero if the reagent is not present on the solution.</returns>
|
||||||
|
public FixedPoint2 RemoveReagent(ReagentId reagentId, FixedPoint2 quantity)
|
||||||
|
{
|
||||||
|
return RemoveReagent(new ReagentQuantity(reagentId, quantity));
|
||||||
|
}
|
||||||
|
|
||||||
public void RemoveAllSolution()
|
public void RemoveAllSolution()
|
||||||
{
|
{
|
||||||
Contents.Clear();
|
Contents.Clear();
|
||||||
@@ -437,21 +515,33 @@ namespace Content.Shared.Chemistry.Components
|
|||||||
}
|
}
|
||||||
|
|
||||||
/// <summary>
|
/// <summary>
|
||||||
/// Splits a solution without the specified reagent.
|
/// Splits a solution without the specified reagent prototypes.
|
||||||
/// </summary>
|
/// </summary>
|
||||||
public Solution SplitSolutionWithout(FixedPoint2 toTake, params string[] without)
|
public Solution SplitSolutionWithout(FixedPoint2 toTake, params string[] excludedPrototypes)
|
||||||
{
|
{
|
||||||
var existing = new FixedPoint2[without.Length];
|
// First remove the blacklisted prototypes
|
||||||
for (var i = 0; i < without.Length; i++)
|
List<ReagentQuantity> excluded = new();
|
||||||
|
foreach (var id in excludedPrototypes)
|
||||||
{
|
{
|
||||||
TryGetReagent(without[i], out existing[i]);
|
foreach (var tuple in Contents)
|
||||||
RemoveReagent(without[i], existing[i]);
|
{
|
||||||
|
if (tuple.Reagent.Prototype != id)
|
||||||
|
continue;
|
||||||
|
|
||||||
|
excluded.Add(tuple);
|
||||||
|
RemoveReagent(tuple);
|
||||||
|
break;
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// Then split the solution
|
||||||
var sol = SplitSolution(toTake);
|
var sol = SplitSolution(toTake);
|
||||||
|
|
||||||
for (var i = 0; i < without.Length; i++)
|
// Then re-add the excluded reagents to the original solution.
|
||||||
AddReagent(without[i], existing[i]);
|
foreach (var reagent in excluded)
|
||||||
|
{
|
||||||
|
AddReagent(reagent);
|
||||||
|
}
|
||||||
|
|
||||||
return sol;
|
return sol;
|
||||||
}
|
}
|
||||||
@@ -477,32 +567,32 @@ namespace Content.Shared.Chemistry.Components
|
|||||||
|
|
||||||
for (var i = Contents.Count - 1; i >= 0; i--) // iterate backwards because of remove swap.
|
for (var i = Contents.Count - 1; i >= 0; i--) // iterate backwards because of remove swap.
|
||||||
{
|
{
|
||||||
var reagent = Contents[i];
|
var (reagent, quantity) = Contents[i];
|
||||||
|
|
||||||
// This is set up such that integer rounding will tend to take more reagents.
|
// This is set up such that integer rounding will tend to take more reagents.
|
||||||
var split = remaining * reagent.Quantity.Value / effVol;
|
var split = remaining * quantity.Value / effVol;
|
||||||
|
|
||||||
if (split <= 0)
|
if (split <= 0)
|
||||||
{
|
{
|
||||||
effVol -= reagent.Quantity.Value;
|
effVol -= quantity.Value;
|
||||||
DebugTools.Assert(split == 0, "Negative solution quantity while splitting? Long/int overflow?");
|
DebugTools.Assert(split == 0, "Negative solution quantity while splitting? Long/int overflow?");
|
||||||
continue;
|
continue;
|
||||||
}
|
}
|
||||||
|
|
||||||
var splitQuantity = FixedPoint2.FromCents((int) split);
|
var splitQuantity = FixedPoint2.FromCents((int) split);
|
||||||
var newQuantity = reagent.Quantity - splitQuantity;
|
var newQuantity = quantity - splitQuantity;
|
||||||
|
|
||||||
DebugTools.Assert(newQuantity >= 0);
|
DebugTools.Assert(newQuantity >= 0);
|
||||||
|
|
||||||
if (newQuantity > FixedPoint2.Zero)
|
if (newQuantity > FixedPoint2.Zero)
|
||||||
Contents[i] = new ReagentQuantity(reagent.ReagentId, newQuantity);
|
Contents[i] = new ReagentQuantity(reagent, newQuantity);
|
||||||
else
|
else
|
||||||
Contents.RemoveSwap(i);
|
Contents.RemoveSwap(i);
|
||||||
|
|
||||||
newSolution.Contents.Add(new ReagentQuantity(reagent.ReagentId, splitQuantity));
|
newSolution.Contents.Add(new ReagentQuantity(reagent, splitQuantity));
|
||||||
Volume -= splitQuantity;
|
Volume -= splitQuantity;
|
||||||
remaining -= split;
|
remaining -= split;
|
||||||
effVol -= reagent.Quantity.Value;
|
effVol -= quantity.Value;
|
||||||
}
|
}
|
||||||
|
|
||||||
newSolution.Volume = origVol - Volume;
|
newSolution.Volume = origVol - Volume;
|
||||||
@@ -539,28 +629,28 @@ namespace Content.Shared.Chemistry.Components
|
|||||||
var remaining = (long) toTake.Value;
|
var remaining = (long) toTake.Value;
|
||||||
for (var i = Contents.Count - 1; i >= 0; i--)// iterate backwards because of remove swap.
|
for (var i = Contents.Count - 1; i >= 0; i--)// iterate backwards because of remove swap.
|
||||||
{
|
{
|
||||||
var reagent = Contents[i];
|
var (reagent, quantity) = Contents[i];
|
||||||
|
|
||||||
// This is set up such that integer rounding will tend to take more reagents.
|
// This is set up such that integer rounding will tend to take more reagents.
|
||||||
var split = remaining * reagent.Quantity.Value / effVol;
|
var split = remaining * quantity.Value / effVol;
|
||||||
|
|
||||||
if (split <= 0)
|
if (split <= 0)
|
||||||
{
|
{
|
||||||
effVol -= reagent.Quantity.Value;
|
effVol -= quantity.Value;
|
||||||
DebugTools.Assert(split == 0, "Negative solution quantity while splitting? Long/int overflow?");
|
DebugTools.Assert(split == 0, "Negative solution quantity while splitting? Long/int overflow?");
|
||||||
continue;
|
continue;
|
||||||
}
|
}
|
||||||
|
|
||||||
var splitQuantity = FixedPoint2.FromCents((int) split);
|
var splitQuantity = FixedPoint2.FromCents((int) split);
|
||||||
var newQuantity = reagent.Quantity - splitQuantity;
|
var newQuantity = quantity - splitQuantity;
|
||||||
|
|
||||||
if (newQuantity > FixedPoint2.Zero)
|
if (newQuantity > FixedPoint2.Zero)
|
||||||
Contents[i] = new ReagentQuantity(reagent.ReagentId, newQuantity);
|
Contents[i] = new ReagentQuantity(reagent, newQuantity);
|
||||||
else
|
else
|
||||||
Contents.RemoveSwap(i);
|
Contents.RemoveSwap(i);
|
||||||
|
|
||||||
remaining -= split;
|
remaining -= split;
|
||||||
effVol -= reagent.Quantity.Value;
|
effVol -= quantity.Value;
|
||||||
}
|
}
|
||||||
|
|
||||||
DebugTools.Assert(remaining >= 0);
|
DebugTools.Assert(remaining >= 0);
|
||||||
@@ -594,23 +684,23 @@ namespace Content.Shared.Chemistry.Components
|
|||||||
|
|
||||||
for (var i = 0; i < otherSolution.Contents.Count; i++)
|
for (var i = 0; i < otherSolution.Contents.Count; i++)
|
||||||
{
|
{
|
||||||
var otherReagent = otherSolution.Contents[i];
|
var (otherReagent, otherQuantity) = otherSolution.Contents[i];
|
||||||
|
|
||||||
var found = false;
|
var found = false;
|
||||||
for (var j = 0; j < Contents.Count; j++)
|
for (var j = 0; j < Contents.Count; j++)
|
||||||
{
|
{
|
||||||
var reagent = Contents[j];
|
var (reagent, quantity) = Contents[j];
|
||||||
if (reagent.ReagentId == otherReagent.ReagentId)
|
if (reagent == otherReagent)
|
||||||
{
|
{
|
||||||
found = true;
|
found = true;
|
||||||
Contents[j] = new ReagentQuantity(reagent.ReagentId, reagent.Quantity + otherReagent.Quantity);
|
Contents[j] = new ReagentQuantity(reagent, quantity + otherQuantity);
|
||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
if (!found)
|
if (!found)
|
||||||
{
|
{
|
||||||
Contents.Add(new ReagentQuantity(otherReagent.ReagentId, otherReagent.Quantity));
|
Contents.Add(new ReagentQuantity(otherReagent, otherQuantity));
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -636,14 +726,14 @@ namespace Content.Shared.Chemistry.Components
|
|||||||
var runningTotalQuantity = FixedPoint2.New(0);
|
var runningTotalQuantity = FixedPoint2.New(0);
|
||||||
bool first = true;
|
bool first = true;
|
||||||
|
|
||||||
foreach (var reagent in Contents)
|
foreach (var (reagent, quantity) in Contents)
|
||||||
{
|
{
|
||||||
if (without.Contains(reagent.ReagentId))
|
if (without.Contains(reagent.Prototype))
|
||||||
continue;
|
continue;
|
||||||
|
|
||||||
runningTotalQuantity += reagent.Quantity;
|
runningTotalQuantity += quantity;
|
||||||
|
|
||||||
if (!protoMan.TryIndex(reagent.ReagentId, out ReagentPrototype? proto))
|
if (!protoMan.TryIndex(reagent.Prototype, out ReagentPrototype? proto))
|
||||||
{
|
{
|
||||||
continue;
|
continue;
|
||||||
}
|
}
|
||||||
@@ -655,7 +745,7 @@ namespace Content.Shared.Chemistry.Components
|
|||||||
continue;
|
continue;
|
||||||
}
|
}
|
||||||
|
|
||||||
var interpolateValue = reagent.Quantity.Float() / runningTotalQuantity.Float();
|
var interpolateValue = quantity.Float() / runningTotalQuantity.Float();
|
||||||
mixColor = Color.InterpolateBetween(mixColor, proto.SubstanceColor, interpolateValue);
|
mixColor = Color.InterpolateBetween(mixColor, proto.SubstanceColor, interpolateValue);
|
||||||
}
|
}
|
||||||
return mixColor;
|
return mixColor;
|
||||||
@@ -666,46 +756,6 @@ namespace Content.Shared.Chemistry.Components
|
|||||||
return GetColorWithout(protoMan);
|
return GetColorWithout(protoMan);
|
||||||
}
|
}
|
||||||
|
|
||||||
[Obsolete("Use ReactiveSystem.DoEntityReaction")]
|
|
||||||
public void DoEntityReaction(EntityUid uid, ReactionMethod method)
|
|
||||||
{
|
|
||||||
IoCManager.Resolve<IEntitySystemManager>().GetEntitySystem<ReactiveSystem>().DoEntityReaction(uid, this, method);
|
|
||||||
}
|
|
||||||
|
|
||||||
[Serializable, NetSerializable]
|
|
||||||
[DataDefinition]
|
|
||||||
public readonly partial struct ReagentQuantity: IComparable<ReagentQuantity>
|
|
||||||
{
|
|
||||||
[DataField("ReagentId", customTypeSerializer:typeof(PrototypeIdSerializer<ReagentPrototype>), required:true)]
|
|
||||||
public string ReagentId { get; init; }
|
|
||||||
[DataField("Quantity", required:true)]
|
|
||||||
public FixedPoint2 Quantity { get; init; }
|
|
||||||
|
|
||||||
public ReagentQuantity(string reagentId, FixedPoint2 quantity)
|
|
||||||
{
|
|
||||||
ReagentId = reagentId;
|
|
||||||
Quantity = quantity;
|
|
||||||
}
|
|
||||||
|
|
||||||
public ReagentQuantity() : this(string.Empty, default)
|
|
||||||
{
|
|
||||||
}
|
|
||||||
|
|
||||||
[ExcludeFromCodeCoverage]
|
|
||||||
public override string ToString()
|
|
||||||
{
|
|
||||||
return $"{ReagentId}:{Quantity}";
|
|
||||||
}
|
|
||||||
|
|
||||||
public int CompareTo(ReagentQuantity other) { return Quantity.Float().CompareTo(other.Quantity.Float()); }
|
|
||||||
|
|
||||||
public void Deconstruct(out string reagentId, out FixedPoint2 quantity)
|
|
||||||
{
|
|
||||||
reagentId = ReagentId;
|
|
||||||
quantity = Quantity;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
#region Enumeration
|
#region Enumeration
|
||||||
|
|
||||||
public IEnumerator<ReagentQuantity> GetEnumerator()
|
public IEnumerator<ReagentQuantity> GetEnumerator()
|
||||||
@@ -721,6 +771,7 @@ namespace Content.Shared.Chemistry.Components
|
|||||||
|
|
||||||
public void SetContents(IEnumerable<ReagentQuantity> reagents, bool setMaxVol = false)
|
public void SetContents(IEnumerable<ReagentQuantity> reagents, bool setMaxVol = false)
|
||||||
{
|
{
|
||||||
|
Volume = 0;
|
||||||
RemoveAllSolution();
|
RemoveAllSolution();
|
||||||
_heatCapacityDirty = true;
|
_heatCapacityDirty = true;
|
||||||
Contents = new(reagents);
|
Contents = new(reagents);
|
||||||
@@ -735,5 +786,15 @@ namespace Content.Shared.Chemistry.Components
|
|||||||
ValidateSolution();
|
ValidateSolution();
|
||||||
}
|
}
|
||||||
|
|
||||||
|
public Dictionary<ReagentPrototype, FixedPoint2> GetReagentPrototypes(IPrototypeManager protoMan)
|
||||||
|
{
|
||||||
|
var dict = new Dictionary<ReagentPrototype, FixedPoint2>(Contents.Count);
|
||||||
|
foreach (var (reagent, quantity) in Contents)
|
||||||
|
{
|
||||||
|
var proto = protoMan.Index<ReagentPrototype>(reagent.Prototype);
|
||||||
|
dict[proto] = quantity + dict.GetValueOrDefault(proto);
|
||||||
|
}
|
||||||
|
return dict;
|
||||||
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -14,13 +14,11 @@ namespace Content.Shared.Chemistry.Dispenser
|
|||||||
[Serializable, NetSerializable, Prototype("reagentDispenserInventory")]
|
[Serializable, NetSerializable, Prototype("reagentDispenserInventory")]
|
||||||
public sealed class ReagentDispenserInventoryPrototype : IPrototype
|
public sealed class ReagentDispenserInventoryPrototype : IPrototype
|
||||||
{
|
{
|
||||||
|
// TODO use ReagentId
|
||||||
[DataField("inventory", customTypeSerializer: typeof(PrototypeIdListSerializer<ReagentPrototype>))]
|
[DataField("inventory", customTypeSerializer: typeof(PrototypeIdListSerializer<ReagentPrototype>))]
|
||||||
private List<string> _inventory = new();
|
public List<string> Inventory = new();
|
||||||
|
|
||||||
[ViewVariables]
|
[ViewVariables, IdDataField]
|
||||||
[IdDataField]
|
public string ID { get; } = default!;
|
||||||
public string ID { get; private set; } = default!;
|
|
||||||
|
|
||||||
public List<string> Inventory => _inventory;
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -136,7 +136,9 @@ namespace Content.Shared.Chemistry.Reaction
|
|||||||
var reactantName = reactantData.Key;
|
var reactantName = reactantData.Key;
|
||||||
var reactantCoefficient = reactantData.Value.Amount;
|
var reactantCoefficient = reactantData.Value.Amount;
|
||||||
|
|
||||||
if (!solution.TryGetReagent(reactantName, out var reactantQuantity))
|
var reactantQuantity = solution.GetTotalPrototypeQuantity(reactantName);
|
||||||
|
|
||||||
|
if (reactantQuantity <= FixedPoint2.Zero)
|
||||||
return false;
|
return false;
|
||||||
|
|
||||||
if (reactantData.Value.Catalyst)
|
if (reactantData.Value.Catalyst)
|
||||||
@@ -292,7 +294,7 @@ namespace Content.Shared.Chemistry.Reaction
|
|||||||
SortedSet<ReactionPrototype> reactions = new();
|
SortedSet<ReactionPrototype> reactions = new();
|
||||||
foreach (var reactant in solution.Contents)
|
foreach (var reactant in solution.Contents)
|
||||||
{
|
{
|
||||||
if (_reactions.TryGetValue(reactant.ReagentId, out var reactantReactions))
|
if (_reactions.TryGetValue(reactant.Reagent.Prototype, out var reactantReactions))
|
||||||
reactions.UnionWith(reactantReactions);
|
reactions.UnionWith(reactantReactions);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|||||||
@@ -19,32 +19,33 @@ namespace Content.Shared.Chemistry
|
|||||||
|
|
||||||
public void DoEntityReaction(EntityUid uid, Solution solution, ReactionMethod method)
|
public void DoEntityReaction(EntityUid uid, Solution solution, ReactionMethod method)
|
||||||
{
|
{
|
||||||
foreach (var (reagentId, quantity) in solution.Contents.ToArray())
|
foreach (var reagent in solution.Contents.ToArray())
|
||||||
{
|
{
|
||||||
ReactionEntity(uid, method, reagentId, quantity, solution);
|
ReactionEntity(uid, method, reagent, solution);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
public void ReactionEntity(EntityUid uid, ReactionMethod method, string reagentId, FixedPoint2 reactVolume, Solution? source)
|
public void ReactionEntity(EntityUid uid, ReactionMethod method, ReagentQuantity reagentQuantity, Solution? source)
|
||||||
{
|
{
|
||||||
// We throw if the reagent specified doesn't exist.
|
// We throw if the reagent specified doesn't exist.
|
||||||
ReactionEntity(uid, method, _prototypeManager.Index<ReagentPrototype>(reagentId), reactVolume, source);
|
var proto = _prototypeManager.Index<ReagentPrototype>(reagentQuantity.Reagent.Prototype);
|
||||||
|
ReactionEntity(uid, method, proto, reagentQuantity, source);
|
||||||
}
|
}
|
||||||
|
|
||||||
public void ReactionEntity(EntityUid uid, ReactionMethod method, ReagentPrototype reagent,
|
public void ReactionEntity(EntityUid uid, ReactionMethod method, ReagentPrototype proto,
|
||||||
FixedPoint2 reactVolume, Solution? source)
|
ReagentQuantity reagentQuantity, Solution? source)
|
||||||
{
|
{
|
||||||
if (!EntityManager.TryGetComponent(uid, out ReactiveComponent? reactive))
|
if (!TryComp(uid, out ReactiveComponent? reactive))
|
||||||
return;
|
return;
|
||||||
|
|
||||||
// If we have a source solution, use the reagent quantity we have left. Otherwise, use the reaction volume specified.
|
// If we have a source solution, use the reagent quantity we have left. Otherwise, use the reaction volume specified.
|
||||||
var args = new ReagentEffectArgs(uid, null, source, reagent,
|
var args = new ReagentEffectArgs(uid, null, source, proto,
|
||||||
source?.GetReagentQuantity(reagent.ID) ?? reactVolume, EntityManager, method, 1f);
|
source?.GetReagentQuantity(reagentQuantity.Reagent) ?? reagentQuantity.Quantity, EntityManager, method, 1f);
|
||||||
|
|
||||||
// First, check if the reagent wants to apply any effects.
|
// First, check if the reagent wants to apply any effects.
|
||||||
if (reagent.ReactiveEffects != null && reactive.ReactiveGroups != null)
|
if (proto.ReactiveEffects != null && reactive.ReactiveGroups != null)
|
||||||
{
|
{
|
||||||
foreach (var (key, val) in reagent.ReactiveEffects)
|
foreach (var (key, val) in proto.ReactiveEffects)
|
||||||
{
|
{
|
||||||
if (!val.Methods.Contains(method))
|
if (!val.Methods.Contains(method))
|
||||||
continue;
|
continue;
|
||||||
@@ -64,7 +65,7 @@ namespace Content.Shared.Chemistry
|
|||||||
{
|
{
|
||||||
var entity = args.SolutionEntity;
|
var entity = args.SolutionEntity;
|
||||||
_adminLogger.Add(LogType.ReagentEffect, effect.LogImpact,
|
_adminLogger.Add(LogType.ReagentEffect, effect.LogImpact,
|
||||||
$"Reactive effect {effect.GetType().Name:effect} of reagent {reagent.ID:reagent} with method {method} applied on entity {ToPrettyString(entity):entity} at {Transform(entity).Coordinates:coordinates}");
|
$"Reactive effect {effect.GetType().Name:effect} of reagent {proto.ID:reagent} with method {method} applied on entity {ToPrettyString(entity):entity} at {Transform(entity).Coordinates:coordinates}");
|
||||||
}
|
}
|
||||||
|
|
||||||
effect.Effect(args);
|
effect.Effect(args);
|
||||||
@@ -80,7 +81,7 @@ namespace Content.Shared.Chemistry
|
|||||||
if (!entry.Methods.Contains(method))
|
if (!entry.Methods.Contains(method))
|
||||||
continue;
|
continue;
|
||||||
|
|
||||||
if (entry.Reagents != null && !entry.Reagents.Contains(reagent.ID))
|
if (entry.Reagents != null && !entry.Reagents.Contains(proto.ID))
|
||||||
continue;
|
continue;
|
||||||
|
|
||||||
foreach (var effect in entry.Effects)
|
foreach (var effect in entry.Effects)
|
||||||
@@ -92,7 +93,7 @@ namespace Content.Shared.Chemistry
|
|||||||
{
|
{
|
||||||
var entity = args.SolutionEntity;
|
var entity = args.SolutionEntity;
|
||||||
_adminLogger.Add(LogType.ReagentEffect, effect.LogImpact,
|
_adminLogger.Add(LogType.ReagentEffect, effect.LogImpact,
|
||||||
$"Reactive effect {effect.GetType().Name:effect} of {ToPrettyString(entity):entity} using reagent {reagent.ID:reagent} with method {method} at {Transform(entity).Coordinates:coordinates}");
|
$"Reactive effect {effect.GetType().Name:effect} of {ToPrettyString(entity):entity} using reagent {proto.ID:reagent} with method {method} at {Transform(entity).Coordinates:coordinates}");
|
||||||
}
|
}
|
||||||
|
|
||||||
effect.Effect(args);
|
effect.Effect(args);
|
||||||
|
|||||||
44
Content.Shared/Chemistry/Reagent/ReagentData.cs
Normal file
44
Content.Shared/Chemistry/Reagent/ReagentData.cs
Normal file
@@ -0,0 +1,44 @@
|
|||||||
|
using Content.Shared.FixedPoint;
|
||||||
|
using Robust.Shared.Serialization;
|
||||||
|
|
||||||
|
namespace Content.Shared.Chemistry.Reagent;
|
||||||
|
|
||||||
|
[ImplicitDataDefinitionForInheritors, Serializable, NetSerializable]
|
||||||
|
public abstract partial class ReagentData : IEquatable<ReagentData>
|
||||||
|
{
|
||||||
|
/// <summary>
|
||||||
|
/// Convert to a string representation. This if for logging & debugging. This is not localized and should not be
|
||||||
|
/// shown to players.
|
||||||
|
/// </summary>
|
||||||
|
public virtual string ToString(string prototype, FixedPoint2 quantity)
|
||||||
|
{
|
||||||
|
return $"{prototype}:{GetType().Name}:{quantity}";
|
||||||
|
}
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// Convert to a string representation. This if for logging & debugging. This is not localized and should not be
|
||||||
|
/// shown to players.
|
||||||
|
/// </summary>
|
||||||
|
public virtual string ToString(string prototype)
|
||||||
|
{
|
||||||
|
return $"{prototype}:{GetType().Name}";
|
||||||
|
}
|
||||||
|
|
||||||
|
public abstract bool Equals(ReagentData? other);
|
||||||
|
|
||||||
|
public override bool Equals(object? obj)
|
||||||
|
{
|
||||||
|
if (ReferenceEquals(null, obj))
|
||||||
|
return false;
|
||||||
|
if (ReferenceEquals(this, obj))
|
||||||
|
return true;
|
||||||
|
if (obj.GetType() != GetType())
|
||||||
|
return false;
|
||||||
|
|
||||||
|
return Equals((ReagentData) obj);
|
||||||
|
}
|
||||||
|
|
||||||
|
public abstract override int GetHashCode();
|
||||||
|
|
||||||
|
public abstract ReagentData Clone();
|
||||||
|
}
|
||||||
93
Content.Shared/Chemistry/Reagent/ReagentId.cs
Normal file
93
Content.Shared/Chemistry/Reagent/ReagentId.cs
Normal file
@@ -0,0 +1,93 @@
|
|||||||
|
using Content.Shared.FixedPoint;
|
||||||
|
using Robust.Shared.Serialization;
|
||||||
|
using Robust.Shared.Serialization.TypeSerializers.Implementations.Custom.Prototype;
|
||||||
|
|
||||||
|
namespace Content.Shared.Chemistry.Reagent;
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// Struct used to uniquely identify a reagent. This is usually just a ReagentPrototype id string, however some reagents
|
||||||
|
/// contain additional data (e.g., blood could store DNA data).
|
||||||
|
/// </summary>
|
||||||
|
[Serializable, NetSerializable]
|
||||||
|
[DataDefinition]
|
||||||
|
public partial struct ReagentId : IEquatable<ReagentId>
|
||||||
|
{
|
||||||
|
// TODO rename data field.
|
||||||
|
[DataField("ReagentId", customTypeSerializer: typeof(PrototypeIdSerializer<ReagentPrototype>), required: true)]
|
||||||
|
public string Prototype { get; private set; }
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// Any additional data that is unique to this reagent type. E.g., for blood this could be DNA data.
|
||||||
|
/// </summary>
|
||||||
|
[DataField("data")]
|
||||||
|
public ReagentData? Data { get; private set; }
|
||||||
|
|
||||||
|
public ReagentId(string prototype, ReagentData? data)
|
||||||
|
{
|
||||||
|
Prototype = prototype;
|
||||||
|
Data = data;
|
||||||
|
}
|
||||||
|
|
||||||
|
public ReagentId()
|
||||||
|
{
|
||||||
|
Prototype = default!;
|
||||||
|
}
|
||||||
|
|
||||||
|
public bool Equals(ReagentId other)
|
||||||
|
{
|
||||||
|
if (Prototype != other.Prototype)
|
||||||
|
return false;
|
||||||
|
|
||||||
|
if (Data == null)
|
||||||
|
return other.Data == null;
|
||||||
|
|
||||||
|
if (other.Data == null)
|
||||||
|
return false;
|
||||||
|
|
||||||
|
if (Data.GetType() != other.Data.GetType())
|
||||||
|
return false;
|
||||||
|
|
||||||
|
return Data.Equals(other.Data);
|
||||||
|
}
|
||||||
|
|
||||||
|
public bool Equals(string prototype, ReagentData? otherData = null)
|
||||||
|
{
|
||||||
|
if (Prototype != prototype)
|
||||||
|
return false;
|
||||||
|
|
||||||
|
if (Data == null)
|
||||||
|
return otherData == null;
|
||||||
|
|
||||||
|
return Data.Equals(otherData);
|
||||||
|
}
|
||||||
|
|
||||||
|
public override bool Equals(object? obj)
|
||||||
|
{
|
||||||
|
return obj is ReagentId other && Equals(other);
|
||||||
|
}
|
||||||
|
|
||||||
|
public override int GetHashCode()
|
||||||
|
{
|
||||||
|
return HashCode.Combine(Prototype, Data);
|
||||||
|
}
|
||||||
|
|
||||||
|
public string ToString(FixedPoint2 quantity)
|
||||||
|
{
|
||||||
|
return Data?.ToString(Prototype, quantity) ?? $"{Prototype}:{quantity}";
|
||||||
|
}
|
||||||
|
|
||||||
|
public override string ToString()
|
||||||
|
{
|
||||||
|
return Data?.ToString(Prototype) ?? Prototype;
|
||||||
|
}
|
||||||
|
|
||||||
|
public static bool operator ==(ReagentId left, ReagentId right)
|
||||||
|
{
|
||||||
|
return left.Equals(right);
|
||||||
|
}
|
||||||
|
|
||||||
|
public static bool operator !=(ReagentId left, ReagentId right)
|
||||||
|
{
|
||||||
|
return !(left == right);
|
||||||
|
}
|
||||||
|
}
|
||||||
@@ -141,7 +141,7 @@ namespace Content.Shared.Chemistry.Reagent
|
|||||||
return removed;
|
return removed;
|
||||||
}
|
}
|
||||||
|
|
||||||
public void ReactionPlant(EntityUid? plantHolder, Solution.ReagentQuantity amount, Solution solution)
|
public void ReactionPlant(EntityUid? plantHolder, ReagentQuantity amount, Solution solution)
|
||||||
{
|
{
|
||||||
if (plantHolder == null)
|
if (plantHolder == null)
|
||||||
return;
|
return;
|
||||||
|
|||||||
77
Content.Shared/Chemistry/Reagent/ReagentQuantity.cs
Normal file
77
Content.Shared/Chemistry/Reagent/ReagentQuantity.cs
Normal file
@@ -0,0 +1,77 @@
|
|||||||
|
using Content.Shared.FixedPoint;
|
||||||
|
using Robust.Shared.Serialization;
|
||||||
|
|
||||||
|
namespace Content.Shared.Chemistry.Reagent;
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// Simple struct for storing a <see cref="ReagentId"/> & quantity tuple.
|
||||||
|
/// </summary>
|
||||||
|
[Serializable, NetSerializable]
|
||||||
|
[DataDefinition]
|
||||||
|
public partial struct ReagentQuantity : IEquatable<ReagentQuantity>
|
||||||
|
{
|
||||||
|
[DataField("Quantity", required:true)]
|
||||||
|
public FixedPoint2 Quantity { get; private set; }
|
||||||
|
|
||||||
|
[IncludeDataField]
|
||||||
|
[ViewVariables]
|
||||||
|
public ReagentId Reagent { get; private set; }
|
||||||
|
|
||||||
|
public ReagentQuantity(string reagentId, FixedPoint2 quantity, ReagentData? data)
|
||||||
|
: this(new ReagentId(reagentId, data), quantity)
|
||||||
|
{
|
||||||
|
}
|
||||||
|
|
||||||
|
public ReagentQuantity(ReagentId reagent, FixedPoint2 quantity)
|
||||||
|
{
|
||||||
|
Reagent = reagent;
|
||||||
|
Quantity = quantity;
|
||||||
|
}
|
||||||
|
|
||||||
|
public ReagentQuantity() : this(default, default)
|
||||||
|
{
|
||||||
|
}
|
||||||
|
|
||||||
|
public override string ToString()
|
||||||
|
{
|
||||||
|
return Reagent.ToString(Quantity);
|
||||||
|
}
|
||||||
|
|
||||||
|
public void Deconstruct(out string prototype, out FixedPoint2 quantity, out ReagentData? data)
|
||||||
|
{
|
||||||
|
prototype = Reagent.Prototype;
|
||||||
|
quantity = Quantity;
|
||||||
|
data = Reagent.Data;
|
||||||
|
}
|
||||||
|
|
||||||
|
public void Deconstruct(out ReagentId id, out FixedPoint2 quantity)
|
||||||
|
{
|
||||||
|
id = Reagent;
|
||||||
|
quantity = Quantity;
|
||||||
|
}
|
||||||
|
|
||||||
|
public bool Equals(ReagentQuantity other)
|
||||||
|
{
|
||||||
|
return Quantity != other.Quantity && Reagent.Equals(other.Reagent);
|
||||||
|
}
|
||||||
|
|
||||||
|
public override bool Equals(object? obj)
|
||||||
|
{
|
||||||
|
return obj is ReagentQuantity other && Equals(other);
|
||||||
|
}
|
||||||
|
|
||||||
|
public override int GetHashCode()
|
||||||
|
{
|
||||||
|
return HashCode.Combine(Reagent.GetHashCode(), Quantity);
|
||||||
|
}
|
||||||
|
|
||||||
|
public static bool operator ==(ReagentQuantity left, ReagentQuantity right)
|
||||||
|
{
|
||||||
|
return left.Equals(right);
|
||||||
|
}
|
||||||
|
|
||||||
|
public static bool operator !=(ReagentQuantity left, ReagentQuantity right)
|
||||||
|
{
|
||||||
|
return !(left == right);
|
||||||
|
}
|
||||||
|
}
|
||||||
@@ -1,4 +1,5 @@
|
|||||||
using Content.Shared.Chemistry.Components;
|
using Content.Shared.Chemistry.Components;
|
||||||
|
using Content.Shared.Chemistry.Reagent;
|
||||||
using Content.Shared.FixedPoint;
|
using Content.Shared.FixedPoint;
|
||||||
using Robust.Shared.Serialization;
|
using Robust.Shared.Serialization;
|
||||||
|
|
||||||
@@ -43,11 +44,11 @@ namespace Content.Shared.Chemistry
|
|||||||
[Serializable, NetSerializable]
|
[Serializable, NetSerializable]
|
||||||
public sealed class ChemMasterReagentAmountButtonMessage : BoundUserInterfaceMessage
|
public sealed class ChemMasterReagentAmountButtonMessage : BoundUserInterfaceMessage
|
||||||
{
|
{
|
||||||
public readonly string ReagentId;
|
public readonly ReagentId ReagentId;
|
||||||
public readonly ChemMasterReagentAmount Amount;
|
public readonly ChemMasterReagentAmount Amount;
|
||||||
public readonly bool FromBuffer;
|
public readonly bool FromBuffer;
|
||||||
|
|
||||||
public ChemMasterReagentAmountButtonMessage(string reagentId, ChemMasterReagentAmount amount, bool fromBuffer)
|
public ChemMasterReagentAmountButtonMessage(ReagentId reagentId, ChemMasterReagentAmount amount, bool fromBuffer)
|
||||||
{
|
{
|
||||||
ReagentId = reagentId;
|
ReagentId = reagentId;
|
||||||
Amount = amount;
|
Amount = amount;
|
||||||
@@ -121,34 +122,29 @@ namespace Content.Shared.Chemistry
|
|||||||
/// The container name to show to the player
|
/// The container name to show to the player
|
||||||
/// </summary>
|
/// </summary>
|
||||||
public readonly string DisplayName;
|
public readonly string DisplayName;
|
||||||
/// <summary>
|
|
||||||
/// Whether the container holds reagents or entities
|
|
||||||
/// </summary>
|
|
||||||
public readonly bool HoldsReagents;
|
|
||||||
/// <summary>
|
/// <summary>
|
||||||
/// The currently used volume of the container
|
/// The currently used volume of the container
|
||||||
/// </summary>
|
/// </summary>
|
||||||
public readonly FixedPoint2 CurrentVolume;
|
public readonly FixedPoint2 CurrentVolume;
|
||||||
|
|
||||||
/// <summary>
|
/// <summary>
|
||||||
/// The maximum volume of the container
|
/// The maximum volume of the container
|
||||||
/// </summary>
|
/// </summary>
|
||||||
public readonly FixedPoint2 MaxVolume;
|
public readonly FixedPoint2 MaxVolume;
|
||||||
/// <summary>
|
|
||||||
/// A list of the reagents/entities and their sizes within the container
|
|
||||||
/// </summary>
|
|
||||||
// todo: this causes NetSerializer exceptions if it's an IReadOnlyList (which would be preferred)
|
|
||||||
public readonly List<(string Id, FixedPoint2 Quantity)> Contents;
|
|
||||||
|
|
||||||
public ContainerInfo(
|
/// <summary>
|
||||||
string displayName, bool holdsReagents,
|
/// A list of the entities and their sizes within the container
|
||||||
FixedPoint2 currentVolume, FixedPoint2 maxVolume,
|
/// </summary>
|
||||||
List<(string, FixedPoint2)> contents)
|
public List<(string Id, FixedPoint2 Quantity)>? Entities { get; init; }
|
||||||
|
|
||||||
|
public List<ReagentQuantity>? Reagents { get; init; }
|
||||||
|
|
||||||
|
public ContainerInfo(string displayName, FixedPoint2 currentVolume, FixedPoint2 maxVolume)
|
||||||
{
|
{
|
||||||
DisplayName = displayName;
|
DisplayName = displayName;
|
||||||
HoldsReagents = holdsReagents;
|
|
||||||
CurrentVolume = currentVolume;
|
CurrentVolume = currentVolume;
|
||||||
MaxVolume = maxVolume;
|
MaxVolume = maxVolume;
|
||||||
Contents = contents;
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -161,7 +157,7 @@ namespace Content.Shared.Chemistry
|
|||||||
/// <summary>
|
/// <summary>
|
||||||
/// A list of the reagents and their amounts within the buffer, if applicable.
|
/// A list of the reagents and their amounts within the buffer, if applicable.
|
||||||
/// </summary>
|
/// </summary>
|
||||||
public readonly IReadOnlyList<Solution.ReagentQuantity> BufferReagents;
|
public readonly IReadOnlyList<ReagentQuantity> BufferReagents;
|
||||||
|
|
||||||
public readonly ChemMasterMode Mode;
|
public readonly ChemMasterMode Mode;
|
||||||
|
|
||||||
@@ -174,7 +170,7 @@ namespace Content.Shared.Chemistry
|
|||||||
|
|
||||||
public ChemMasterBoundUserInterfaceState(
|
public ChemMasterBoundUserInterfaceState(
|
||||||
ChemMasterMode mode, ContainerInfo? inputContainerInfo, ContainerInfo? outputContainerInfo,
|
ChemMasterMode mode, ContainerInfo? inputContainerInfo, ContainerInfo? outputContainerInfo,
|
||||||
IReadOnlyList<Solution.ReagentQuantity> bufferReagents, FixedPoint2 bufferCurrentVolume,
|
IReadOnlyList<ReagentQuantity> bufferReagents, FixedPoint2 bufferCurrentVolume,
|
||||||
uint selectedPillType, uint pillDosageLimit, bool updateLabel)
|
uint selectedPillType, uint pillDosageLimit, bool updateLabel)
|
||||||
{
|
{
|
||||||
InputContainerInfo = inputContainerInfo;
|
InputContainerInfo = inputContainerInfo;
|
||||||
|
|||||||
@@ -1,3 +1,4 @@
|
|||||||
|
using Content.Shared.Chemistry.Reagent;
|
||||||
using Robust.Shared.Serialization;
|
using Robust.Shared.Serialization;
|
||||||
|
|
||||||
namespace Content.Shared.Chemistry
|
namespace Content.Shared.Chemistry
|
||||||
@@ -24,9 +25,9 @@ namespace Content.Shared.Chemistry
|
|||||||
[Serializable, NetSerializable]
|
[Serializable, NetSerializable]
|
||||||
public sealed class ReagentDispenserDispenseReagentMessage : BoundUserInterfaceMessage
|
public sealed class ReagentDispenserDispenseReagentMessage : BoundUserInterfaceMessage
|
||||||
{
|
{
|
||||||
public readonly string ReagentId;
|
public readonly ReagentId ReagentId;
|
||||||
|
|
||||||
public ReagentDispenserDispenseReagentMessage(string reagentId)
|
public ReagentDispenserDispenseReagentMessage(ReagentId reagentId)
|
||||||
{
|
{
|
||||||
ReagentId = reagentId;
|
ReagentId = reagentId;
|
||||||
}
|
}
|
||||||
@@ -58,11 +59,11 @@ namespace Content.Shared.Chemistry
|
|||||||
/// <summary>
|
/// <summary>
|
||||||
/// A list of the reagents which this dispenser can dispense.
|
/// A list of the reagents which this dispenser can dispense.
|
||||||
/// </summary>
|
/// </summary>
|
||||||
public readonly List<string> Inventory;
|
public readonly List<ReagentId> Inventory;
|
||||||
|
|
||||||
public readonly ReagentDispenserDispenseAmount SelectedDispenseAmount;
|
public readonly ReagentDispenserDispenseAmount SelectedDispenseAmount;
|
||||||
|
|
||||||
public ReagentDispenserBoundUserInterfaceState(ContainerInfo? outputContainer, List<string> inventory, ReagentDispenserDispenseAmount selectedDispenseAmount)
|
public ReagentDispenserBoundUserInterfaceState(ContainerInfo? outputContainer, List<ReagentId> inventory, ReagentDispenserDispenseAmount selectedDispenseAmount)
|
||||||
{
|
{
|
||||||
OutputContainer = outputContainer;
|
OutputContainer = outputContainer;
|
||||||
Inventory = inventory;
|
Inventory = inventory;
|
||||||
|
|||||||
@@ -1,4 +1,5 @@
|
|||||||
using Content.Shared.Chemistry.Components;
|
using Content.Shared.Chemistry.Components;
|
||||||
|
using Content.Shared.Chemistry.Reagent;
|
||||||
using Robust.Shared.Serialization;
|
using Robust.Shared.Serialization;
|
||||||
|
|
||||||
namespace Content.Shared.Kitchen.Components
|
namespace Content.Shared.Kitchen.Components
|
||||||
@@ -27,8 +28,8 @@ namespace Content.Shared.Kitchen.Components
|
|||||||
[Serializable, NetSerializable]
|
[Serializable, NetSerializable]
|
||||||
public sealed class MicrowaveVaporizeReagentIndexedMessage : BoundUserInterfaceMessage
|
public sealed class MicrowaveVaporizeReagentIndexedMessage : BoundUserInterfaceMessage
|
||||||
{
|
{
|
||||||
public Solution.ReagentQuantity ReagentQuantity;
|
public ReagentQuantity ReagentQuantity;
|
||||||
public MicrowaveVaporizeReagentIndexedMessage(Solution.ReagentQuantity reagentQuantity)
|
public MicrowaveVaporizeReagentIndexedMessage(ReagentQuantity reagentQuantity)
|
||||||
{
|
{
|
||||||
ReagentQuantity = reagentQuantity;
|
ReagentQuantity = reagentQuantity;
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -33,6 +33,7 @@ namespace Content.Shared.Kitchen
|
|||||||
|
|
||||||
public string Name => Loc.GetString(_name);
|
public string Name => Loc.GetString(_name);
|
||||||
|
|
||||||
|
// TODO Turn this into a ReagentQuantity[]
|
||||||
public IReadOnlyDictionary<string, FixedPoint2> IngredientsReagents => _ingsReagents;
|
public IReadOnlyDictionary<string, FixedPoint2> IngredientsReagents => _ingsReagents;
|
||||||
public IReadOnlyDictionary<string, FixedPoint2> IngredientsSolids => _ingsSolids;
|
public IReadOnlyDictionary<string, FixedPoint2> IngredientsSolids => _ingsSolids;
|
||||||
|
|
||||||
|
|||||||
@@ -1,4 +1,5 @@
|
|||||||
using Content.Shared.Chemistry.Components;
|
using Content.Shared.Chemistry.Components;
|
||||||
|
using Content.Shared.Chemistry.Reagent;
|
||||||
using Robust.Shared.Serialization;
|
using Robust.Shared.Serialization;
|
||||||
|
|
||||||
namespace Content.Shared.Kitchen
|
namespace Content.Shared.Kitchen
|
||||||
@@ -84,8 +85,8 @@ namespace Content.Shared.Kitchen
|
|||||||
public bool CanJuice;
|
public bool CanJuice;
|
||||||
public bool CanGrind;
|
public bool CanGrind;
|
||||||
public EntityUid[] ChamberContents;
|
public EntityUid[] ChamberContents;
|
||||||
public Solution.ReagentQuantity[]? ReagentQuantities;
|
public ReagentQuantity[]? ReagentQuantities;
|
||||||
public ReagentGrinderInterfaceState(bool isBusy, bool hasBeaker, bool powered, bool canJuice, bool canGrind, EntityUid[] chamberContents, Solution.ReagentQuantity[]? heldBeakerContents)
|
public ReagentGrinderInterfaceState(bool isBusy, bool hasBeaker, bool powered, bool canJuice, bool canGrind, EntityUid[] chamberContents, ReagentQuantity[]? heldBeakerContents)
|
||||||
{
|
{
|
||||||
IsBusy = isBusy;
|
IsBusy = isBusy;
|
||||||
HasBeakerIn = hasBeaker;
|
HasBeakerIn = hasBeaker;
|
||||||
|
|||||||
@@ -27,4 +27,5 @@ public sealed partial class PhysicalCompositionComponent : Component
|
|||||||
/// </summary>
|
/// </summary>
|
||||||
[DataField("chemicalComposition", customTypeSerializer: typeof(PrototypeIdDictionarySerializer<FixedPoint2, ReagentPrototype>))]
|
[DataField("chemicalComposition", customTypeSerializer: typeof(PrototypeIdDictionarySerializer<FixedPoint2, ReagentPrototype>))]
|
||||||
public Dictionary<string, FixedPoint2> ChemicalComposition = new();
|
public Dictionary<string, FixedPoint2> ChemicalComposition = new();
|
||||||
|
// TODO use ReagentQuantity[]
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -8,7 +8,7 @@ using Robust.Shared.Utility;
|
|||||||
namespace Content.Tests.Shared.Chemistry;
|
namespace Content.Tests.Shared.Chemistry;
|
||||||
|
|
||||||
[TestFixture, Parallelizable, TestOf(typeof(Solution))]
|
[TestFixture, Parallelizable, TestOf(typeof(Solution))]
|
||||||
public sealed class Solution_Tests : ContentUnitTest
|
public sealed class SolutionTests : ContentUnitTest
|
||||||
{
|
{
|
||||||
[OneTimeSetUp]
|
[OneTimeSetUp]
|
||||||
public void Setup()
|
public void Setup()
|
||||||
@@ -21,7 +21,7 @@ public sealed class Solution_Tests : ContentUnitTest
|
|||||||
{
|
{
|
||||||
var solution = new Solution();
|
var solution = new Solution();
|
||||||
solution.AddReagent("water", FixedPoint2.New(1000));
|
solution.AddReagent("water", FixedPoint2.New(1000));
|
||||||
var quantity = solution.GetReagentQuantity("water");
|
var quantity = solution.GetTotalPrototypeQuantity("water");
|
||||||
|
|
||||||
Assert.That(quantity.Int(), Is.EqualTo(1000));
|
Assert.That(quantity.Int(), Is.EqualTo(1000));
|
||||||
}
|
}
|
||||||
@@ -44,8 +44,8 @@ public sealed class Solution_Tests : ContentUnitTest
|
|||||||
tmp.ScaleSolution(2);
|
tmp.ScaleSolution(2);
|
||||||
Assert.That(tmp.Contents.Count, Is.EqualTo(2));
|
Assert.That(tmp.Contents.Count, Is.EqualTo(2));
|
||||||
Assert.That(tmp.Volume, Is.EqualTo(FixedPoint2.New(100)));
|
Assert.That(tmp.Volume, Is.EqualTo(FixedPoint2.New(100)));
|
||||||
Assert.That(tmp.GetReagentQuantity("water"), Is.EqualTo(FixedPoint2.New(40)));
|
Assert.That(tmp.GetTotalPrototypeQuantity("water"), Is.EqualTo(FixedPoint2.New(40)));
|
||||||
Assert.That(tmp.GetReagentQuantity("fire"), Is.EqualTo(FixedPoint2.New(60)));
|
Assert.That(tmp.GetTotalPrototypeQuantity("fire"), Is.EqualTo(FixedPoint2.New(60)));
|
||||||
}
|
}
|
||||||
|
|
||||||
// Test float scaling
|
// Test float scaling
|
||||||
@@ -59,15 +59,15 @@ public sealed class Solution_Tests : ContentUnitTest
|
|||||||
tmp.ScaleSolution(2f);
|
tmp.ScaleSolution(2f);
|
||||||
Assert.That(tmp.Contents.Count, Is.EqualTo(2));
|
Assert.That(tmp.Contents.Count, Is.EqualTo(2));
|
||||||
Assert.That(tmp.Volume, Is.EqualTo(FixedPoint2.New(100)));
|
Assert.That(tmp.Volume, Is.EqualTo(FixedPoint2.New(100)));
|
||||||
Assert.That(tmp.GetReagentQuantity("water"), Is.EqualTo(FixedPoint2.New(40)));
|
Assert.That(tmp.GetTotalPrototypeQuantity("water"), Is.EqualTo(FixedPoint2.New(40)));
|
||||||
Assert.That(tmp.GetReagentQuantity("fire"), Is.EqualTo(FixedPoint2.New(60)));
|
Assert.That(tmp.GetTotalPrototypeQuantity("fire"), Is.EqualTo(FixedPoint2.New(60)));
|
||||||
|
|
||||||
tmp = solution.Clone();
|
tmp = solution.Clone();
|
||||||
tmp.ScaleSolution(0.3f);
|
tmp.ScaleSolution(0.3f);
|
||||||
Assert.That(tmp.Contents.Count, Is.EqualTo(2));
|
Assert.That(tmp.Contents.Count, Is.EqualTo(2));
|
||||||
Assert.That(tmp.Volume, Is.EqualTo(FixedPoint2.New(15)));
|
Assert.That(tmp.Volume, Is.EqualTo(FixedPoint2.New(15)));
|
||||||
Assert.That(tmp.GetReagentQuantity("water"), Is.EqualTo(FixedPoint2.New(6)));
|
Assert.That(tmp.GetTotalPrototypeQuantity("water"), Is.EqualTo(FixedPoint2.New(6)));
|
||||||
Assert.That(tmp.GetReagentQuantity("fire"), Is.EqualTo(FixedPoint2.New(9)));
|
Assert.That(tmp.GetTotalPrototypeQuantity("fire"), Is.EqualTo(FixedPoint2.New(9)));
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -75,7 +75,7 @@ public sealed class Solution_Tests : ContentUnitTest
|
|||||||
public void ConstructorAddReagent()
|
public void ConstructorAddReagent()
|
||||||
{
|
{
|
||||||
var solution = new Solution("water", FixedPoint2.New(1000));
|
var solution = new Solution("water", FixedPoint2.New(1000));
|
||||||
var quantity = solution.GetReagentQuantity("water");
|
var quantity = solution.GetTotalPrototypeQuantity("water");
|
||||||
|
|
||||||
Assert.That(quantity.Int(), Is.EqualTo(1000));
|
Assert.That(quantity.Int(), Is.EqualTo(1000));
|
||||||
}
|
}
|
||||||
@@ -84,7 +84,7 @@ public sealed class Solution_Tests : ContentUnitTest
|
|||||||
public void NonExistingReagentReturnsZero()
|
public void NonExistingReagentReturnsZero()
|
||||||
{
|
{
|
||||||
var solution = new Solution();
|
var solution = new Solution();
|
||||||
var quantity = solution.GetReagentQuantity("water");
|
var quantity = solution.GetTotalPrototypeQuantity("water");
|
||||||
|
|
||||||
Assert.That(quantity.Int(), Is.EqualTo(0));
|
Assert.That(quantity.Int(), Is.EqualTo(0));
|
||||||
}
|
}
|
||||||
@@ -94,7 +94,7 @@ public sealed class Solution_Tests : ContentUnitTest
|
|||||||
public void AddLessThanZeroReagentReturnsZero()
|
public void AddLessThanZeroReagentReturnsZero()
|
||||||
{
|
{
|
||||||
var solution = new Solution("water", FixedPoint2.New(-1000));
|
var solution = new Solution("water", FixedPoint2.New(-1000));
|
||||||
var quantity = solution.GetReagentQuantity("water");
|
var quantity = solution.GetTotalPrototypeQuantity("water");
|
||||||
|
|
||||||
Assert.That(quantity.Int(), Is.EqualTo(0));
|
Assert.That(quantity.Int(), Is.EqualTo(0));
|
||||||
}
|
}
|
||||||
@@ -106,7 +106,7 @@ public sealed class Solution_Tests : ContentUnitTest
|
|||||||
var solution = new Solution();
|
var solution = new Solution();
|
||||||
solution.AddReagent("water", FixedPoint2.New(1000));
|
solution.AddReagent("water", FixedPoint2.New(1000));
|
||||||
solution.AddReagent("water", FixedPoint2.New(2000));
|
solution.AddReagent("water", FixedPoint2.New(2000));
|
||||||
var quantity = solution.GetReagentQuantity("water");
|
var quantity = solution.GetTotalPrototypeQuantity("water");
|
||||||
|
|
||||||
Assert.That(quantity.Int(), Is.EqualTo(3000));
|
Assert.That(quantity.Int(), Is.EqualTo(3000));
|
||||||
}
|
}
|
||||||
@@ -118,8 +118,8 @@ public sealed class Solution_Tests : ContentUnitTest
|
|||||||
solution.AddReagent("water", FixedPoint2.New(1000));
|
solution.AddReagent("water", FixedPoint2.New(1000));
|
||||||
solution.AddReagent("fire", FixedPoint2.New(2000));
|
solution.AddReagent("fire", FixedPoint2.New(2000));
|
||||||
|
|
||||||
Assert.That(solution.GetReagentQuantity("water").Int(), Is.EqualTo(1000));
|
Assert.That(solution.GetTotalPrototypeQuantity("water").Int(), Is.EqualTo(1000));
|
||||||
Assert.That(solution.GetReagentQuantity("fire").Int(), Is.EqualTo(2000));
|
Assert.That(solution.GetTotalPrototypeQuantity("fire").Int(), Is.EqualTo(2000));
|
||||||
}
|
}
|
||||||
|
|
||||||
[Test]
|
[Test]
|
||||||
@@ -141,8 +141,8 @@ public sealed class Solution_Tests : ContentUnitTest
|
|||||||
|
|
||||||
var newSolution = solution.Clone();
|
var newSolution = solution.Clone();
|
||||||
|
|
||||||
Assert.That(newSolution.GetReagentQuantity("water").Int(), Is.EqualTo(1000));
|
Assert.That(newSolution.GetTotalPrototypeQuantity("water").Int(), Is.EqualTo(1000));
|
||||||
Assert.That(newSolution.GetReagentQuantity("fire").Int(), Is.EqualTo(2000));
|
Assert.That(newSolution.GetTotalPrototypeQuantity("fire").Int(), Is.EqualTo(2000));
|
||||||
Assert.That(newSolution.Volume.Int(), Is.EqualTo(3000));
|
Assert.That(newSolution.Volume.Int(), Is.EqualTo(3000));
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -155,8 +155,8 @@ public sealed class Solution_Tests : ContentUnitTest
|
|||||||
|
|
||||||
solution.RemoveReagent("water", FixedPoint2.New(500));
|
solution.RemoveReagent("water", FixedPoint2.New(500));
|
||||||
|
|
||||||
Assert.That(solution.GetReagentQuantity("water").Int(), Is.EqualTo(500));
|
Assert.That(solution.GetTotalPrototypeQuantity("water").Int(), Is.EqualTo(500));
|
||||||
Assert.That(solution.GetReagentQuantity("fire").Int(), Is.EqualTo(2000));
|
Assert.That(solution.GetTotalPrototypeQuantity("fire").Int(), Is.EqualTo(2000));
|
||||||
Assert.That(solution.Volume.Int(), Is.EqualTo(2500));
|
Assert.That(solution.Volume.Int(), Is.EqualTo(2500));
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -167,7 +167,7 @@ public sealed class Solution_Tests : ContentUnitTest
|
|||||||
|
|
||||||
solution.RemoveReagent("water", FixedPoint2.New(-100));
|
solution.RemoveReagent("water", FixedPoint2.New(-100));
|
||||||
|
|
||||||
Assert.That(solution.GetReagentQuantity("water").Int(), Is.EqualTo(100));
|
Assert.That(solution.GetTotalPrototypeQuantity("water").Int(), Is.EqualTo(100));
|
||||||
Assert.That(solution.Volume.Int(), Is.EqualTo(100));
|
Assert.That(solution.Volume.Int(), Is.EqualTo(100));
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -178,7 +178,7 @@ public sealed class Solution_Tests : ContentUnitTest
|
|||||||
|
|
||||||
solution.RemoveReagent("water", FixedPoint2.New(1000));
|
solution.RemoveReagent("water", FixedPoint2.New(1000));
|
||||||
|
|
||||||
Assert.That(solution.GetReagentQuantity("water").Int(), Is.EqualTo(0));
|
Assert.That(solution.GetTotalPrototypeQuantity("water").Int(), Is.EqualTo(0));
|
||||||
Assert.That(solution.Volume.Int(), Is.EqualTo(0));
|
Assert.That(solution.Volume.Int(), Is.EqualTo(0));
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -189,7 +189,7 @@ public sealed class Solution_Tests : ContentUnitTest
|
|||||||
|
|
||||||
solution.RemoveReagent("fire", FixedPoint2.New(1000));
|
solution.RemoveReagent("fire", FixedPoint2.New(1000));
|
||||||
|
|
||||||
Assert.That(solution.GetReagentQuantity("water").Int(), Is.EqualTo(100));
|
Assert.That(solution.GetTotalPrototypeQuantity("water").Int(), Is.EqualTo(100));
|
||||||
Assert.That(solution.Volume.Int(), Is.EqualTo(100));
|
Assert.That(solution.Volume.Int(), Is.EqualTo(100));
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -201,7 +201,7 @@ public sealed class Solution_Tests : ContentUnitTest
|
|||||||
solution.RemoveSolution(FixedPoint2.New(500));
|
solution.RemoveSolution(FixedPoint2.New(500));
|
||||||
|
|
||||||
//Check that edited solution is correct
|
//Check that edited solution is correct
|
||||||
Assert.That(solution.GetReagentQuantity("water").Int(), Is.EqualTo(200));
|
Assert.That(solution.GetTotalPrototypeQuantity("water").Int(), Is.EqualTo(200));
|
||||||
Assert.That(solution.Volume.Int(), Is.EqualTo(200));
|
Assert.That(solution.Volume.Int(), Is.EqualTo(200));
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -213,7 +213,7 @@ public sealed class Solution_Tests : ContentUnitTest
|
|||||||
solution.RemoveSolution(FixedPoint2.New(1000));
|
solution.RemoveSolution(FixedPoint2.New(1000));
|
||||||
|
|
||||||
//Check that edited solution is correct
|
//Check that edited solution is correct
|
||||||
Assert.That(solution.GetReagentQuantity("water").Int(), Is.EqualTo(0));
|
Assert.That(solution.GetTotalPrototypeQuantity("water").Int(), Is.EqualTo(0));
|
||||||
Assert.That(solution.Volume.Int(), Is.EqualTo(0));
|
Assert.That(solution.Volume.Int(), Is.EqualTo(0));
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -226,8 +226,8 @@ public sealed class Solution_Tests : ContentUnitTest
|
|||||||
|
|
||||||
solution.RemoveSolution(FixedPoint2.New(1500));
|
solution.RemoveSolution(FixedPoint2.New(1500));
|
||||||
|
|
||||||
Assert.That(solution.GetReagentQuantity("water").Int(), Is.EqualTo(500));
|
Assert.That(solution.GetTotalPrototypeQuantity("water").Int(), Is.EqualTo(500));
|
||||||
Assert.That(solution.GetReagentQuantity("fire").Int(), Is.EqualTo(1000));
|
Assert.That(solution.GetTotalPrototypeQuantity("fire").Int(), Is.EqualTo(1000));
|
||||||
Assert.That(solution.Volume.Int(), Is.EqualTo(1500));
|
Assert.That(solution.Volume.Int(), Is.EqualTo(1500));
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -238,7 +238,7 @@ public sealed class Solution_Tests : ContentUnitTest
|
|||||||
|
|
||||||
solution.RemoveSolution(FixedPoint2.New(-200));
|
solution.RemoveSolution(FixedPoint2.New(-200));
|
||||||
|
|
||||||
Assert.That(solution.GetReagentQuantity("water").Int(), Is.EqualTo(800));
|
Assert.That(solution.GetTotalPrototypeQuantity("water").Int(), Is.EqualTo(800));
|
||||||
Assert.That(solution.Volume.Int(), Is.EqualTo(800));
|
Assert.That(solution.Volume.Int(), Is.EqualTo(800));
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -251,12 +251,12 @@ public sealed class Solution_Tests : ContentUnitTest
|
|||||||
|
|
||||||
var splitSolution = solution.SplitSolution(FixedPoint2.New(750));
|
var splitSolution = solution.SplitSolution(FixedPoint2.New(750));
|
||||||
|
|
||||||
Assert.That(solution.GetReagentQuantity("water").Int(), Is.EqualTo(750));
|
Assert.That(solution.GetTotalPrototypeQuantity("water").Int(), Is.EqualTo(750));
|
||||||
Assert.That(solution.GetReagentQuantity("fire").Int(), Is.EqualTo(1500));
|
Assert.That(solution.GetTotalPrototypeQuantity("fire").Int(), Is.EqualTo(1500));
|
||||||
Assert.That(solution.Volume.Int(), Is.EqualTo(2250));
|
Assert.That(solution.Volume.Int(), Is.EqualTo(2250));
|
||||||
|
|
||||||
Assert.That(splitSolution.GetReagentQuantity("water").Int(), Is.EqualTo(250));
|
Assert.That(splitSolution.GetTotalPrototypeQuantity("water").Int(), Is.EqualTo(250));
|
||||||
Assert.That(splitSolution.GetReagentQuantity("fire").Int(), Is.EqualTo(500));
|
Assert.That(splitSolution.GetTotalPrototypeQuantity("fire").Int(), Is.EqualTo(500));
|
||||||
Assert.That(splitSolution.Volume.Int(), Is.EqualTo(750));
|
Assert.That(splitSolution.Volume.Int(), Is.EqualTo(750));
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -269,12 +269,12 @@ public sealed class Solution_Tests : ContentUnitTest
|
|||||||
|
|
||||||
var splitSolution = solution.SplitSolution(FixedPoint2.New(1));
|
var splitSolution = solution.SplitSolution(FixedPoint2.New(1));
|
||||||
|
|
||||||
Assert.That(solution.GetReagentQuantity("water").Float(), Is.EqualTo(0.66f));
|
Assert.That(solution.GetTotalPrototypeQuantity("water").Float(), Is.EqualTo(0.66f));
|
||||||
Assert.That(solution.GetReagentQuantity("fire").Float(), Is.EqualTo(1.34f));
|
Assert.That(solution.GetTotalPrototypeQuantity("fire").Float(), Is.EqualTo(1.34f));
|
||||||
Assert.That(solution.Volume.Int(), Is.EqualTo(2));
|
Assert.That(solution.Volume.Int(), Is.EqualTo(2));
|
||||||
|
|
||||||
Assert.That(splitSolution.GetReagentQuantity("water").Float(), Is.EqualTo(0.34f));
|
Assert.That(splitSolution.GetTotalPrototypeQuantity("water").Float(), Is.EqualTo(0.34f));
|
||||||
Assert.That(splitSolution.GetReagentQuantity("fire").Float(), Is.EqualTo(0.66f));
|
Assert.That(splitSolution.GetTotalPrototypeQuantity("fire").Float(), Is.EqualTo(0.66f));
|
||||||
Assert.That(splitSolution.Volume.Int(), Is.EqualTo(1));
|
Assert.That(splitSolution.Volume.Int(), Is.EqualTo(1));
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -287,12 +287,12 @@ public sealed class Solution_Tests : ContentUnitTest
|
|||||||
|
|
||||||
var splitSolution = solution.SplitSolution(FixedPoint2.New(2));
|
var splitSolution = solution.SplitSolution(FixedPoint2.New(2));
|
||||||
|
|
||||||
Assert.That(solution.GetReagentQuantity("water").Float(), Is.EqualTo(0.33f));
|
Assert.That(solution.GetTotalPrototypeQuantity("water").Float(), Is.EqualTo(0.33f));
|
||||||
Assert.That(solution.GetReagentQuantity("fire").Float(), Is.EqualTo(0.67f));
|
Assert.That(solution.GetTotalPrototypeQuantity("fire").Float(), Is.EqualTo(0.67f));
|
||||||
Assert.That(solution.Volume.Int(), Is.EqualTo(1));
|
Assert.That(solution.Volume.Int(), Is.EqualTo(1));
|
||||||
|
|
||||||
Assert.That(splitSolution.GetReagentQuantity("water").Float(), Is.EqualTo(0.67f));
|
Assert.That(splitSolution.GetTotalPrototypeQuantity("water").Float(), Is.EqualTo(0.67f));
|
||||||
Assert.That(splitSolution.GetReagentQuantity("fire").Float(), Is.EqualTo(1.33f));
|
Assert.That(splitSolution.GetTotalPrototypeQuantity("fire").Float(), Is.EqualTo(1.33f));
|
||||||
Assert.That(splitSolution.Volume.Int(), Is.EqualTo(2));
|
Assert.That(splitSolution.Volume.Int(), Is.EqualTo(2));
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -306,10 +306,10 @@ public sealed class Solution_Tests : ContentUnitTest
|
|||||||
|
|
||||||
var splitSolution = solution.SplitSolution(FixedPoint2.New(reduce));
|
var splitSolution = solution.SplitSolution(FixedPoint2.New(reduce));
|
||||||
|
|
||||||
Assert.That(solution.GetReagentQuantity("water").Float(), Is.EqualTo(remainder));
|
Assert.That(solution.GetTotalPrototypeQuantity("water").Float(), Is.EqualTo(remainder));
|
||||||
Assert.That(solution.Volume.Float(), Is.EqualTo(remainder));
|
Assert.That(solution.Volume.Float(), Is.EqualTo(remainder));
|
||||||
|
|
||||||
Assert.That(splitSolution.GetReagentQuantity("water").Float(), Is.EqualTo(reduce));
|
Assert.That(splitSolution.GetTotalPrototypeQuantity("water").Float(), Is.EqualTo(reduce));
|
||||||
Assert.That(splitSolution.Volume.Float(), Is.EqualTo(reduce));
|
Assert.That(splitSolution.Volume.Float(), Is.EqualTo(reduce));
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -338,10 +338,10 @@ public sealed class Solution_Tests : ContentUnitTest
|
|||||||
|
|
||||||
var splitSolution = solution.SplitSolution(FixedPoint2.New(1000));
|
var splitSolution = solution.SplitSolution(FixedPoint2.New(1000));
|
||||||
|
|
||||||
Assert.That(solution.GetReagentQuantity("water").Int(), Is.EqualTo(0));
|
Assert.That(solution.GetTotalPrototypeQuantity("water").Int(), Is.EqualTo(0));
|
||||||
Assert.That(solution.Volume.Int(), Is.EqualTo(0));
|
Assert.That(solution.Volume.Int(), Is.EqualTo(0));
|
||||||
|
|
||||||
Assert.That(splitSolution.GetReagentQuantity("water").Int(), Is.EqualTo(800));
|
Assert.That(splitSolution.GetTotalPrototypeQuantity("water").Int(), Is.EqualTo(800));
|
||||||
Assert.That(splitSolution.Volume.Int(), Is.EqualTo(800));
|
Assert.That(splitSolution.Volume.Int(), Is.EqualTo(800));
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -352,10 +352,10 @@ public sealed class Solution_Tests : ContentUnitTest
|
|||||||
|
|
||||||
var splitSolution = solution.SplitSolution(FixedPoint2.New(-200));
|
var splitSolution = solution.SplitSolution(FixedPoint2.New(-200));
|
||||||
|
|
||||||
Assert.That(solution.GetReagentQuantity("water").Int(), Is.EqualTo(800));
|
Assert.That(solution.GetTotalPrototypeQuantity("water").Int(), Is.EqualTo(800));
|
||||||
Assert.That(solution.Volume.Int(), Is.EqualTo(800));
|
Assert.That(solution.Volume.Int(), Is.EqualTo(800));
|
||||||
|
|
||||||
Assert.That(splitSolution.GetReagentQuantity("water").Int(), Is.EqualTo(0));
|
Assert.That(splitSolution.GetTotalPrototypeQuantity("water").Int(), Is.EqualTo(0));
|
||||||
Assert.That(splitSolution.Volume.Int(), Is.EqualTo(0));
|
Assert.That(splitSolution.Volume.Int(), Is.EqualTo(0));
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -393,9 +393,9 @@ public sealed class Solution_Tests : ContentUnitTest
|
|||||||
|
|
||||||
solutionOne.AddSolution(solutionTwo, null);
|
solutionOne.AddSolution(solutionTwo, null);
|
||||||
|
|
||||||
Assert.That(solutionOne.GetReagentQuantity("water").Int(), Is.EqualTo(1500));
|
Assert.That(solutionOne.GetTotalPrototypeQuantity("water").Int(), Is.EqualTo(1500));
|
||||||
Assert.That(solutionOne.GetReagentQuantity("fire").Int(), Is.EqualTo(2000));
|
Assert.That(solutionOne.GetTotalPrototypeQuantity("fire").Int(), Is.EqualTo(2000));
|
||||||
Assert.That(solutionOne.GetReagentQuantity("earth").Int(), Is.EqualTo(1000));
|
Assert.That(solutionOne.GetTotalPrototypeQuantity("earth").Int(), Is.EqualTo(1000));
|
||||||
Assert.That(solutionOne.Volume.Int(), Is.EqualTo(4500));
|
Assert.That(solutionOne.Volume.Int(), Is.EqualTo(4500));
|
||||||
}
|
}
|
||||||
|
|
||||||
Reference in New Issue
Block a user