using Robust.Client.UserInterface.Controls;
using Robust.Client.UserInterface.CustomControls;
using Robust.Client.UserInterface.XAML;
+using Robust.Shared.GameObjects;
+using Robust.Shared.IoC;
+using Robust.Shared.Localization;
using Robust.Shared.Prototypes;
namespace Content.Client.Administration.UI.ManageSolutions
private NetEntity _target = NetEntity.Invalid;
private string? _selectedSolution;
private AddReagentWindow? _addReagentWindow;
- private Dictionary<string, EntityUid>? _solutions;
+ private Dictionary<string, Solution>? _solutions;
public EditSolutionsWindow()
{
if (_selectedSolution == null || _solutions == null)
return;
- if (!_solutions.TryGetValue(_selectedSolution, out var solutionId) ||
- !_entityManager.TryGetComponent(solutionId, out SolutionComponent? solutionComp))
+ if (!_solutions.TryGetValue(_selectedSolution, out var solution))
return;
- var solution = solutionComp.Solution;
UpdateVolumeBox(solution);
UpdateThermalBox(solution);
/// </summary>
private void SetReagent(FloatSpinBox.FloatSpinBoxEventArgs args, string prototype)
{
- if (_solutions == null || _selectedSolution == null ||
- !_solutions.TryGetValue(_selectedSolution, out var solutionId) ||
- !_entityManager.TryGetComponent(solutionId, out SolutionComponent? solutionComp))
+ if (_solutions == null || _selectedSolution == null)
return;
- var solution = solutionComp.Solution;
- var current = solution.GetTotalPrototypeQuantity(prototype);
+ var current = _solutions[_selectedSolution].GetTotalPrototypeQuantity(prototype);
var delta = args.Value - current.Float();
if (MathF.Abs(delta) < 0.01)
/// <summary>
/// Update the solution options.
/// </summary>
- public void UpdateSolutions(List<(string, NetEntity)>? solutions)
+ public void UpdateSolutions(Dictionary<string, Solution>? solutions)
{
SolutionOption.Clear();
-
- if (solutions is { Count: > 0 })
- {
- if (_solutions is { Count: > 0 })
- _solutions.Clear();
- else
- _solutions = new(solutions.Count);
-
- foreach (var (name, netSolution) in solutions)
- {
- if (_entityManager.TryGetEntity(netSolution, out var solution))
- _solutions.Add(name, solution.Value);
- }
- }
- else
- _solutions = null;
+ _solutions = solutions;
if (_solutions == null)
return;
int i = 0;
- int selectedIndex = 0; // Default to the first solution if none are found.
- foreach (var (name, _) in _solutions)
+ foreach (var solution in _solutions.Keys)
{
- SolutionOption.AddItem(name, i);
- SolutionOption.SetItemMetadata(i, name);
+ SolutionOption.AddItem(solution, i);
+ SolutionOption.SetItemMetadata(i, solution);
- if (name == _selectedSolution)
- selectedIndex = i;
+ if (solution == _selectedSolution)
+ SolutionOption.Select(i);
i++;
}
// No applicable solutions
Close();
Dispose();
- return;
}
- SolutionOption.Select(selectedIndex);
- _selectedSolution = (string?) SolutionOption.SelectedMetadata;
+ if (_selectedSolution == null || !_solutions.ContainsKey(_selectedSolution))
+ {
+ // the previously selected solution is no longer valid.
+ SolutionOption.Select(0);
+ _selectedSolution = (string?) SolutionOption.SelectedMetadata;
+ }
}
}
}
+++ /dev/null
-using Content.Shared.Chemistry.EntitySystems;
-
-namespace Content.Client.Chemistry.Containers.EntitySystems;
-
-public sealed partial class SolutionContainerSystem : SharedSolutionContainerSystem
-{
-}
using Content.Client.UserInterface.Controls;
+using Content.Shared.Chemistry.Components;
using Content.Shared.Chemistry.Reagent;
using Content.Shared.Kitchen;
using Robust.Client.AutoGenerated;
using Robust.Client.GameObjects;
using Robust.Client.UserInterface.Controls;
+using Robust.Client.UserInterface.CustomControls;
using Robust.Client.UserInterface.XAML;
using Robust.Shared.Prototypes;
public sealed partial class GrinderMenu : FancyWindow
{
private readonly IEntityManager _entityManager;
- private readonly IPrototypeManager _prototypeManager;
+ private readonly IPrototypeManager _prototypeManager ;
private readonly ReagentGrinderBoundUserInterface _owner;
private readonly Dictionary<int, EntityUid> _chamberVisualContents = new();
{
foreach (var (reagent, quantity) in reagents)
{
- var reagentName = _prototypeManager.TryIndex(reagent.Prototype, out ReagentPrototype? proto)
- ? Loc.GetString($"{quantity} {proto.LocalizedName}")
+ var reagentName = _prototypeManager.TryIndex(reagent.Prototype, out ReagentPrototype? proto)
+ ? Loc.GetString($"{quantity} {proto.LocalizedName}")
: "???";
BeakerContentBox.BoxContents.AddItem(reagentName);
}
+using Content.Shared.Chemistry.Components;
using Content.Shared.Chemistry.Reagent;
using Content.Shared.Kitchen.Components;
using JetBrains.Annotations;
using Robust.Client.GameObjects;
using Robust.Client.Graphics;
using Robust.Client.UserInterface.Controls;
+using Robust.Shared.Graphics;
namespace Content.Client.Kitchen.UI
{
-using Content.Server.Chemistry.Containers.EntitySystems;
using Content.Shared.Chemistry.Components;
+using Content.Shared.Chemistry.EntitySystems;
using Content.Shared.FixedPoint;
using Robust.Shared.GameObjects;
using Robust.Shared.Prototypes;
var entityManager = server.ResolveDependency<IEntityManager>();
var protoMan = server.ResolveDependency<IPrototypeManager>();
- var containerSystem = entityManager.System<SolutionContainerSystem>();
+ var containerSystem = entityManager.EntitySysManager.GetEntitySystem<SolutionContainerSystem>();
var testMap = await pair.CreateTestMap();
var coordinates = testMap.GridCoords;
beaker = entityManager.SpawnEntity("SolutionTarget", coordinates);
Assert.That(containerSystem
- .TryGetSolution(beaker, "beaker", out var solutionEnt, out var solution));
+ .TryGetSolution(beaker, "beaker", out var solution));
solution.AddSolution(originalWater, protoMan);
Assert.That(containerSystem
- .TryAddSolution(solutionEnt.Value, oilAdded));
+ .TryAddSolution(beaker, solution, oilAdded));
var water = solution.GetTotalPrototypeQuantity("Water");
var oil = solution.GetTotalPrototypeQuantity("Oil");
var entityManager = server.ResolveDependency<IEntityManager>();
var protoMan = server.ResolveDependency<IPrototypeManager>();
- var containerSystem = entityManager.System<SolutionContainerSystem>();
+ var containerSystem = entityManager.EntitySysManager.GetEntitySystem<SolutionContainerSystem>();
var coordinates = testMap.GridCoords;
EntityUid beaker;
beaker = entityManager.SpawnEntity("SolutionTarget", coordinates);
Assert.That(containerSystem
- .TryGetSolution(beaker, "beaker", out var solutionEnt, out var solution));
+ .TryGetSolution(beaker, "beaker", out var solution));
solution.AddSolution(originalWater, protoMan);
Assert.That(containerSystem
- .TryAddSolution(solutionEnt.Value, oilAdded), Is.False);
+ .TryAddSolution(beaker, solution, oilAdded), Is.False);
var water = solution.GetTotalPrototypeQuantity("Water");
var oil = solution.GetTotalPrototypeQuantity("Oil");
var entityManager = server.ResolveDependency<IEntityManager>();
var protoMan = server.ResolveDependency<IPrototypeManager>();
var testMap = await pair.CreateTestMap();
- var containerSystem = entityManager.System<SolutionContainerSystem>();
+ var containerSystem = entityManager.EntitySysManager.GetEntitySystem<SolutionContainerSystem>();
var coordinates = testMap.GridCoords;
EntityUid beaker;
beaker = entityManager.SpawnEntity("SolutionTarget", coordinates);
Assert.That(containerSystem
- .TryGetSolution(beaker, "beaker", out var solutionEnt, out var solution));
+ .TryGetSolution(beaker, "beaker", out var solution));
solution.AddSolution(originalWater, protoMan);
Assert.That(containerSystem
- .TryMixAndOverflow(solutionEnt.Value, oilAdded, threshold, out var overflowingSolution));
+ .TryMixAndOverflow(beaker, solution, oilAdded, threshold, out var overflowingSolution));
Assert.Multiple(() =>
{
var entityManager = server.ResolveDependency<IEntityManager>();
var protoMan = server.ResolveDependency<IPrototypeManager>();
- var containerSystem = entityManager.System<SolutionContainerSystem>();
+ var containerSystem = entityManager.EntitySysManager.GetEntitySystem<SolutionContainerSystem>();
var testMap = await pair.CreateTestMap();
var coordinates = testMap.GridCoords;
beaker = entityManager.SpawnEntity("SolutionTarget", coordinates);
Assert.That(containerSystem
- .TryGetSolution(beaker, "beaker", out var solutionEnt, out var solution));
+ .TryGetSolution(beaker, "beaker", out var solution));
solution.AddSolution(originalWater, protoMan);
Assert.That(containerSystem
- .TryMixAndOverflow(solutionEnt.Value, oilAdded, threshold, out _),
+ .TryMixAndOverflow(beaker, solution, oilAdded, threshold, out _),
Is.False);
});
-using Content.Server.Chemistry.Containers.EntitySystems;
-using Content.Shared.Chemistry.Reaction;
+using System.Linq;
using Content.Shared.Chemistry.Components;
+using Content.Shared.Chemistry.EntitySystems;
+using Content.Shared.Chemistry.Reaction;
using Robust.Shared.GameObjects;
using Robust.Shared.Map;
using Robust.Shared.Prototypes;
using Robust.Shared.Utility;
-using System.Linq;
namespace Content.IntegrationTests.Tests.Chemistry
{
var prototypeManager = server.ResolveDependency<IPrototypeManager>();
var testMap = await pair.CreateTestMap();
var coordinates = testMap.GridCoords;
- var solutionContainerSystem = entityManager.System<SolutionContainerSystem>();
+ var solutionSystem = server.ResolveDependency<IEntitySystemManager>()
+ .GetEntitySystem<SolutionContainerSystem>();
foreach (var reactionPrototype in prototypeManager.EnumeratePrototypes<ReactionPrototype>())
{
Console.WriteLine($"Testing {reactionPrototype.ID}");
EntityUid beaker = default;
- Entity<SolutionComponent>? solutionEnt = default!;
- Solution solution = null;
+ Solution component = null;
await server.WaitAssertion(() =>
{
beaker = entityManager.SpawnEntity("TestSolutionContainer", coordinates);
- Assert.That(solutionContainerSystem
- .TryGetSolution(beaker, "beaker", out solutionEnt, out solution));
+ Assert.That(solutionSystem
+ .TryGetSolution(beaker, "beaker", out component));
foreach (var (id, reactant) in reactionPrototype.Reactants)
{
#pragma warning disable NUnit2045
- Assert.That(solutionContainerSystem
- .TryAddReagent(solutionEnt.Value, id, reactant.Amount, out var quantity));
+ Assert.That(solutionSystem
+ .TryAddReagent(beaker, component, id, reactant.Amount, out var quantity));
Assert.That(reactant.Amount, Is.EqualTo(quantity));
#pragma warning restore NUnit2045
}
- solutionContainerSystem.SetTemperature(solutionEnt.Value, reactionPrototype.MinimumTemperature);
+ solutionSystem.SetTemperature(beaker, component, reactionPrototype.MinimumTemperature);
if (reactionPrototype.MixingCategories != null)
{
var dummyEntity = entityManager.SpawnEntity(null, MapCoordinates.Nullspace);
var mixerComponent = entityManager.AddComponent<ReactionMixerComponent>(dummyEntity);
mixerComponent.ReactionTypes = reactionPrototype.MixingCategories;
- solutionContainerSystem.UpdateChemicals(solutionEnt.Value, true, mixerComponent);
+ solutionSystem.UpdateChemicals(beaker, component, true, mixerComponent);
}
});
var foundProductsMap = reactionPrototype.Products
.Concat(reactionPrototype.Reactants.Where(x => x.Value.Catalyst).ToDictionary(x => x.Key, x => x.Value.Amount))
.ToDictionary(x => x, _ => false);
- foreach (var (reagent, quantity) in solution.Contents)
+ foreach (var (reagent, quantity) in component.Contents)
{
Assert.That(foundProductsMap.TryFirstOrNull(x => x.Key.Key == reagent.Prototype && x.Key.Value == quantity, out var foundProduct));
foundProductsMap[foundProduct.Value.Key] = true;
var entityManager = server.ResolveDependency<IEntityManager>();
var absorbentSystem = entityManager.System<AbsorbentSystem>();
- var solutionContainerSystem = entityManager.System<SharedSolutionContainerSystem>();
+ var solutionContainerSystem = entityManager.System<SolutionContainerSystem>();
var prototypeManager = server.ResolveDependency<IPrototypeManager>();
EntityUid user = default;
refillable = entityManager.SpawnEntity(RefillableDummyId, coordinates);
entityManager.TryGetComponent(absorbent, out component);
- solutionContainerSystem.TryGetSolution(absorbent, AbsorbentComponent.SolutionName, out var absorbentSoln, out var absorbentSolution);
- solutionContainerSystem.TryGetRefillableSolution(refillable, out var refillableSoln, out var refillableSolution);
+ solutionContainerSystem.TryGetSolution(absorbent, AbsorbentComponent.SolutionName, out var absorbentSolution);
+ solutionContainerSystem.TryGetRefillableSolution(refillable, out var refillableSolution);
// Arrange
if (testCase.InitialAbsorbentSolution.VolumeOfEvaporable > FixedPoint2.Zero)
- solutionContainerSystem.AddSolution(absorbentSoln.Value, new Solution(EvaporablePrototypeId, testCase.InitialAbsorbentSolution.VolumeOfEvaporable));
+ solutionContainerSystem.AddSolution(absorbent, absorbentSolution, new Solution(EvaporablePrototypeId, testCase.InitialAbsorbentSolution.VolumeOfEvaporable));
if (testCase.InitialAbsorbentSolution.VolumeOfNonEvaporable > FixedPoint2.Zero)
- solutionContainerSystem.AddSolution(absorbentSoln.Value, new Solution(NonEvaporablePrototypeId, testCase.InitialAbsorbentSolution.VolumeOfNonEvaporable));
+ solutionContainerSystem.AddSolution(absorbent, absorbentSolution, new Solution(NonEvaporablePrototypeId, testCase.InitialAbsorbentSolution.VolumeOfNonEvaporable));
if (testCase.InitialRefillableSolution.VolumeOfEvaporable > FixedPoint2.Zero)
- solutionContainerSystem.AddSolution(refillableSoln.Value, new Solution(EvaporablePrototypeId, testCase.InitialRefillableSolution.VolumeOfEvaporable));
+ solutionContainerSystem.AddSolution(refillable, refillableSolution, new Solution(EvaporablePrototypeId, testCase.InitialRefillableSolution.VolumeOfEvaporable));
if (testCase.InitialRefillableSolution.VolumeOfNonEvaporable > FixedPoint2.Zero)
- solutionContainerSystem.AddSolution(refillableSoln.Value, new Solution(NonEvaporablePrototypeId, testCase.InitialRefillableSolution.VolumeOfNonEvaporable));
+ solutionContainerSystem.AddSolution(refillable, refillableSolution, new Solution(NonEvaporablePrototypeId, testCase.InitialRefillableSolution.VolumeOfNonEvaporable));
// Act
absorbentSystem.Mop(user, refillable, absorbent, component);
var entityManager = server.ResolveDependency<IEntityManager>();
var absorbentSystem = entityManager.System<AbsorbentSystem>();
- var solutionContainerSystem = entityManager.System<SharedSolutionContainerSystem>();
+ var solutionContainerSystem = entityManager.System<SolutionContainerSystem>();
var prototypeManager = server.ResolveDependency<IPrototypeManager>();
EntityUid user = default;
refillable = entityManager.SpawnEntity(SmallRefillableDummyId, coordinates);
entityManager.TryGetComponent(absorbent, out component);
- solutionContainerSystem.TryGetSolution(absorbent, AbsorbentComponent.SolutionName, out var absorbentSoln, out var absorbentSolution);
- solutionContainerSystem.TryGetRefillableSolution(refillable, out var refillableSoln, out var refillableSolution);
+ solutionContainerSystem.TryGetSolution(absorbent, AbsorbentComponent.SolutionName, out var absorbentSolution);
+ solutionContainerSystem.TryGetRefillableSolution(refillable, out var refillableSolution);
// Arrange
- solutionContainerSystem.AddSolution(absorbentSoln.Value, new Solution(EvaporablePrototypeId, testCase.InitialAbsorbentSolution.VolumeOfEvaporable));
+ solutionContainerSystem.AddSolution(absorbent, absorbentSolution, new Solution(EvaporablePrototypeId, testCase.InitialAbsorbentSolution.VolumeOfEvaporable));
if (testCase.InitialAbsorbentSolution.VolumeOfNonEvaporable > FixedPoint2.Zero)
- solutionContainerSystem.AddSolution(absorbentSoln.Value, new Solution(NonEvaporablePrototypeId, testCase.InitialAbsorbentSolution.VolumeOfNonEvaporable));
+ solutionContainerSystem.AddSolution(absorbent, absorbentSolution, new Solution(NonEvaporablePrototypeId, testCase.InitialAbsorbentSolution.VolumeOfNonEvaporable));
if (testCase.InitialRefillableSolution.VolumeOfEvaporable > FixedPoint2.Zero)
- solutionContainerSystem.AddSolution(refillableSoln.Value, new Solution(EvaporablePrototypeId, testCase.InitialRefillableSolution.VolumeOfEvaporable));
+ solutionContainerSystem.AddSolution(refillable, refillableSolution, new Solution(EvaporablePrototypeId, testCase.InitialRefillableSolution.VolumeOfEvaporable));
if (testCase.InitialRefillableSolution.VolumeOfNonEvaporable > FixedPoint2.Zero)
- solutionContainerSystem.AddSolution(refillableSoln.Value, new Solution(NonEvaporablePrototypeId, testCase.InitialRefillableSolution.VolumeOfNonEvaporable));
+ solutionContainerSystem.AddSolution(refillable, refillableSolution, new Solution(NonEvaporablePrototypeId, testCase.InitialRefillableSolution.VolumeOfNonEvaporable));
// Act
absorbentSystem.Mop(user, refillable, absorbent, component);
-using Content.Server.Chemistry.Containers.EntitySystems;
using Content.Shared.Administration;
using Content.Shared.Chemistry.Components.SolutionManager;
+using Content.Shared.Chemistry.EntitySystems;
using Content.Shared.Chemistry.Reagent;
using Content.Shared.FixedPoint;
using Robust.Shared.Console;
using Robust.Shared.Prototypes;
-using System.Linq;
namespace Content.Server.Administration.Commands
{
return;
}
- var solutionContainerSystem = _entManager.System<SolutionContainerSystem>();
- if (!solutionContainerSystem.TryGetSolution((uid.Value, man), args[1], out var solution))
+ if (!man.Solutions.ContainsKey(args[1]))
{
- var validSolutions = string.Join(", ", solutionContainerSystem.EnumerateSolutions((uid.Value, man)).Select(s => s.Name));
+ var validSolutions = string.Join(", ", man.Solutions.Keys);
shell.WriteLine($"Entity does not have a \"{args[1]}\" solution. Valid solutions are:\n{validSolutions}");
return;
}
+ var solution = man.Solutions[args[1]];
if (!_protomanager.HasIndex<ReagentPrototype>(args[2]))
{
var quantity = FixedPoint2.New(MathF.Abs(quantityFloat));
if (quantityFloat > 0)
- solutionContainerSystem.TryAddReagent(solution.Value, args[2], quantity, out _);
+ _entManager.System<SolutionContainerSystem>().TryAddReagent(uid.Value, solution, args[2], quantity, out _);
else
- solutionContainerSystem.RemoveReagent(solution.Value, args[2], quantity);
+ _entManager.System<SolutionContainerSystem>().RemoveReagent(uid.Value, solution, args[2], quantity);
}
}
}
-using Content.Server.Chemistry.Containers.EntitySystems;
using Content.Shared.Administration;
using Content.Shared.Chemistry.Components.SolutionManager;
+using Content.Shared.Chemistry.EntitySystems;
using Content.Shared.FixedPoint;
using Robust.Shared.Console;
-using System.Linq;
namespace Content.Server.Administration.Commands
{
return;
}
- var solutionContainerSystem = _entManager.System<SolutionContainerSystem>();
- if (!solutionContainerSystem.TryGetSolution((uid.Value, man), args[1], out var solution))
+ if (!man.Solutions.ContainsKey(args[1]))
{
- var validSolutions = string.Join(", ", solutionContainerSystem.EnumerateSolutions((uid.Value, man)).Select(s => s.Name));
+ var validSolutions = string.Join(", ", man.Solutions.Keys);
shell.WriteLine($"Entity does not have a \"{args[1]}\" solution. Valid solutions are:\n{validSolutions}");
return;
}
+ var solution = man.Solutions[args[1]];
if (!float.TryParse(args[2], out var quantityFloat))
{
return;
}
- if (quantityFloat < 0.0f)
+ if(quantityFloat < 0.0f)
{
shell.WriteLine($"Cannot set the maximum volume of a solution to a negative number.");
return;
}
var quantity = FixedPoint2.New(quantityFloat);
- solutionContainerSystem.SetCapacity(solution.Value, quantity);
+ _entManager.System<SolutionContainerSystem>().SetCapacity(uid.Value, solution, quantity);
}
}
}
-using Content.Server.Chemistry.Containers.EntitySystems;
using Content.Shared.Administration;
using Content.Shared.Chemistry.Components.SolutionManager;
+using Content.Shared.Chemistry.EntitySystems;
using Robust.Shared.Console;
-using System.Linq;
namespace Content.Server.Administration.Commands
{
return;
}
- var solutionContainerSystem = _entManager.System<SolutionContainerSystem>();
- if (!solutionContainerSystem.TryGetSolution((uid.Value, man), args[1], out var solution))
+ if (!man.Solutions.ContainsKey(args[1]))
{
- var validSolutions = string.Join(", ", solutionContainerSystem.EnumerateSolutions((uid.Value, man)).Select(s => s.Name));
+ var validSolutions = string.Join(", ", man.Solutions.Keys);
shell.WriteLine($"Entity does not have a \"{args[1]}\" solution. Valid solutions are:\n{validSolutions}");
return;
}
+ var solution = man.Solutions[args[1]];
if (!float.TryParse(args[2], out var quantity))
{
return;
}
- solutionContainerSystem.SetTemperature(solution.Value, quantity);
+ _entManager.System<SolutionContainerSystem>().SetTemperature(uid.Value, solution, quantity);
}
}
}
-using Content.Server.Chemistry.Containers.EntitySystems;
using Content.Shared.Administration;
using Content.Shared.Chemistry.Components.SolutionManager;
+using Content.Shared.Chemistry.EntitySystems;
using Robust.Shared.Console;
-using System.Linq;
namespace Content.Server.Administration.Commands
{
return;
}
- var solutionContainerSystem = _entManager.System<SolutionContainerSystem>();
- if (!solutionContainerSystem.TryGetSolution((uid.Value, man), args[1], out var solutionEnt, out var solution))
+ if (!man.Solutions.ContainsKey(args[1]))
{
- var validSolutions = string.Join(", ", solutionContainerSystem.EnumerateSolutions((uid.Value, man)).Select(s => s.Name));
+ var validSolutions = string.Join(", ", man.Solutions.Keys);
shell.WriteLine($"Entity does not have a \"{args[1]}\" solution. Valid solutions are:\n{validSolutions}");
return;
}
+ var solution = man.Solutions[args[1]];
if (!float.TryParse(args[2], out var quantity))
{
if (solution.GetHeatCapacity(null) <= 0.0f)
{
- if (quantity != 0.0f)
+ if(quantity != 0.0f)
{
shell.WriteLine($"Cannot set the thermal energy of a solution with 0 heat capacity to a non-zero number.");
return;
}
}
- else if (quantity <= 0.0f)
+ else if(quantity <= 0.0f)
{
shell.WriteLine($"Cannot set the thermal energy of a solution with heat capacity to a non-positive number.");
return;
}
- solutionContainerSystem.SetThermalEnergy(solutionEnt.Value, quantity);
+ _entManager.System<SolutionContainerSystem>().SetThermalEnergy(uid.Value, solution, quantity);
}
}
}
+using System.Linq;
using Content.Server.Administration.Logs;
using Content.Server.Administration.Managers;
using Content.Server.Administration.UI;
using Robust.Shared.Timing;
using Robust.Shared.Toolshed;
using Robust.Shared.Utility;
-using System.Linq;
using static Content.Shared.Configurable.ConfigurationComponent;
namespace Content.Server.Administration.Systems
{
SubscribeLocalEvent<GetVerbsEvent<Verb>>(GetVerbs);
SubscribeLocalEvent<RoundRestartCleanupEvent>(Reset);
- SubscribeLocalEvent<SolutionContainerManagerComponent, SolutionContainerChangedEvent>(OnSolutionChanged);
+ SubscribeLocalEvent<SolutionContainerManagerComponent, SolutionChangedEvent>(OnSolutionChanged);
}
private void GetVerbs(GetVerbsEvent<Verb> ev)
}
#region SolutionsEui
- private void OnSolutionChanged(Entity<SolutionContainerManagerComponent> entity, ref SolutionContainerChangedEvent args)
+ private void OnSolutionChanged(EntityUid uid, SolutionContainerManagerComponent component, SolutionChangedEvent args)
{
foreach (var eui in _openSolutionUis.Values)
{
- if (eui.Target == entity.Owner)
+ if (eui.Target == uid)
eui.StateDirty();
}
}
-using Content.Server.Chemistry.Containers.EntitySystems;
+using System.Linq;
using Content.Shared.Administration;
using Content.Shared.Chemistry.Components;
+using Content.Shared.Chemistry.EntitySystems;
using Content.Shared.Chemistry.Reagent;
using Content.Shared.FixedPoint;
using Robust.Shared.Toolshed;
using Robust.Shared.Toolshed.Syntax;
using Robust.Shared.Toolshed.TypeParsers;
-using System.Linq;
namespace Content.Server.Administration.Toolshed;
{
_solutionContainer ??= GetSys<SolutionContainerSystem>();
- if (_solutionContainer.TryGetSolution(input, name.Evaluate(ctx)!, out var solution))
- return new SolutionRef(solution.Value);
+ _solutionContainer.TryGetSolution(input, name.Evaluate(ctx)!, out var solution);
+
+ if (solution is not null)
+ return new SolutionRef(input, solution);
return null;
}
var amount = amountRef.Evaluate(ctx);
if (amount > 0)
{
- _solutionContainer.TryAddReagent(input.Solution, name.Value.ID, amount, out _);
+ _solutionContainer.TryAddReagent(input.Owner, input.Solution, name.Value.ID, amount, out _);
}
else if (amount < 0)
{
- _solutionContainer.RemoveReagent(input.Solution, name.Value.ID, -amount);
+ _solutionContainer.RemoveReagent(input.Owner, input.Solution, name.Value.ID, -amount);
}
return input;
=> input.Select(x => AdjReagent(ctx, x, name, amountRef));
}
-public readonly record struct SolutionRef(Entity<SolutionComponent> Solution)
+public readonly record struct SolutionRef(EntityUid Owner, Solution Solution)
{
public override string ToString()
{
- return $"{Solution.Owner} {Solution.Comp.Solution}";
+ return $"{Owner} {Solution}";
}
}
using Content.Server.Administration.Systems;
-using Content.Server.Chemistry.Containers.EntitySystems;
using Content.Server.EUI;
using Content.Shared.Administration;
using Content.Shared.Chemistry.Components.SolutionManager;
public sealed class EditSolutionsEui : BaseEui
{
[Dependency] private readonly IEntityManager _entityManager = default!;
- private readonly SolutionContainerSystem _solutionContainerSystem = default!;
public readonly EntityUid Target;
public EditSolutionsEui(EntityUid entity)
{
IoCManager.InjectDependencies(this);
- _solutionContainerSystem = _entityManager.System<SolutionContainerSystem>();
Target = entity;
}
public override EuiStateBase GetNewState()
{
- List<(string Name, NetEntity Solution)>? netSolutions;
-
- if (_entityManager.TryGetComponent(Target, out SolutionContainerManagerComponent? container) && container.Containers.Count > 0)
- {
- netSolutions = new();
- foreach (var (name, solution) in _solutionContainerSystem.EnumerateSolutions((Target, container)))
- {
- if (name is null || !_entityManager.TryGetNetEntity(solution, out var netSolution))
- continue;
-
- netSolutions.Add((name, netSolution.Value));
- }
- }
- else
- netSolutions = null;
-
- return new EditSolutionsEuiState(_entityManager.GetNetEntity(Target), netSolutions);
+ var solutions = _entityManager.GetComponentOrNull<SolutionContainerManagerComponent>(Target)?.Solutions;
+ return new EditSolutionsEuiState(_entityManager.GetNetEntity(Target), solutions);
}
}
}
using Content.Server.Animals.Systems;
-using Content.Shared.Chemistry.Components;
using Content.Shared.Chemistry.Reagent;
using Content.Shared.FixedPoint;
using Robust.Shared.Prototypes;
using Robust.Shared.Serialization.TypeSerializers.Implementations.Custom;
+
namespace Content.Server.Animals.Components
/// <summary>
[DataField, ViewVariables(VVAccess.ReadOnly)]
public ProtoId<ReagentPrototype> ReagentId = "Milk";
- /// <summary>
- /// The name of <see cref="Solution"/>.
- /// </summary>
- [DataField, ViewVariables(VVAccess.ReadOnly)]
- public string SolutionName = "udder";
-
/// <summary>
/// The solution to add reagent to.
/// </summary>
- [DataField]
- public Entity<SolutionComponent>? Solution = null;
+ [DataField, ViewVariables(VVAccess.ReadOnly)]
+ public string Solution = "udder";
/// <summary>
/// The amount of reagent to be generated on update.
using Content.Server.Animals.Systems;
-using Content.Shared.Chemistry.Components;
using Content.Shared.Chemistry.Reagent;
using Content.Shared.FixedPoint;
using Robust.Shared.Prototypes;
[DataField, ViewVariables(VVAccess.ReadOnly)]
public ProtoId<ReagentPrototype> ReagentId = "Fiber";
- /// <summary>
- /// The name of <see cref="Solution"/>.
- /// </summary>
- [DataField, ViewVariables(VVAccess.ReadOnly)]
- public string SolutionName = "wool";
-
/// <summary>
/// The solution to add reagent to.
/// </summary>
- [DataField]
- public Entity<SolutionComponent>? Solution;
+ [DataField, ViewVariables(VVAccess.ReadOnly)]
+ public string Solution = "wool";
/// <summary>
/// The amount of reagent to be generated on update.
using Content.Server.Animals.Components;
-using Content.Server.Chemistry.Containers.EntitySystems;
using Content.Server.Popups;
using Content.Shared.Chemistry.Components;
+using Content.Shared.Chemistry.EntitySystems;
using Content.Shared.DoAfter;
using Content.Shared.IdentityManagement;
using Content.Shared.Mobs.Systems;
_hunger.ModifyHunger(uid, -udder.HungerUsage, hunger);
}
- if (!_solutionContainerSystem.ResolveSolution(uid, udder.SolutionName, ref udder.Solution))
+ if (!_solutionContainerSystem.TryGetSolution(uid, udder.Solution, out var solution))
continue;
//TODO: toxins from bloodstream !?
- _solutionContainerSystem.TryAddReagent(udder.Solution.Value, udder.ReagentId, udder.QuantityPerUpdate, out _);
+ _solutionContainerSystem.TryAddReagent(uid, solution, udder.ReagentId, udder.QuantityPerUpdate, out _);
}
}
_doAfterSystem.TryStartDoAfter(doargs);
}
- private void OnDoAfter(Entity<UdderComponent> entity, ref MilkingDoAfterEvent args)
+ private void OnDoAfter(EntityUid uid, UdderComponent component, MilkingDoAfterEvent args)
{
if (args.Cancelled || args.Handled || args.Args.Used == null)
return;
- if (!_solutionContainerSystem.ResolveSolution(entity.Owner, entity.Comp.SolutionName, ref entity.Comp.Solution, out var solution))
+ if (!_solutionContainerSystem.TryGetSolution(uid, component.Solution, out var solution))
return;
- if (!_solutionContainerSystem.TryGetRefillableSolution(args.Args.Used.Value, out var targetSoln, out var targetSolution))
+ if (!_solutionContainerSystem.TryGetRefillableSolution(args.Args.Used.Value, out var targetSolution))
return;
args.Handled = true;
var quantity = solution.Volume;
if (quantity == 0)
{
- _popupSystem.PopupEntity(Loc.GetString("udder-system-dry"), entity.Owner, args.Args.User);
+ _popupSystem.PopupEntity(Loc.GetString("udder-system-dry"), uid, args.Args.User);
return;
}
if (quantity > targetSolution.AvailableVolume)
quantity = targetSolution.AvailableVolume;
- var split = _solutionContainerSystem.SplitSolution(entity.Comp.Solution.Value, quantity);
- _solutionContainerSystem.TryAddSolution(targetSoln.Value, split);
+ var split = _solutionContainerSystem.SplitSolution(uid, solution, quantity);
+ _solutionContainerSystem.TryAddSolution(args.Args.Used.Value, targetSolution, split);
- _popupSystem.PopupEntity(Loc.GetString("udder-system-success", ("amount", quantity), ("target", Identity.Entity(args.Args.Used.Value, EntityManager))), entity.Owner,
+ _popupSystem.PopupEntity(Loc.GetString("udder-system-success", ("amount", quantity), ("target", Identity.Entity(args.Args.Used.Value, EntityManager))), uid,
args.Args.User, PopupType.Medium);
}
- private void AddMilkVerb(Entity<UdderComponent> entity, ref GetVerbsEvent<AlternativeVerb> args)
+ private void AddMilkVerb(EntityUid uid, UdderComponent component, GetVerbsEvent<AlternativeVerb> args)
{
if (args.Using == null ||
!args.CanInteract ||
!EntityManager.HasComponent<RefillableSolutionComponent>(args.Using.Value))
return;
- var uid = entity.Owner;
- var user = args.User;
- var used = args.Using.Value;
AlternativeVerb verb = new()
{
Act = () =>
{
- AttemptMilk(uid, user, used);
+ AttemptMilk(uid, args.User, args.Using.Value);
},
Text = Loc.GetString("udder-system-verb-milk"),
Priority = 2
using Content.Server.Animals.Components;
-using Content.Server.Chemistry.Containers.EntitySystems;
using Content.Server.Nutrition;
+using Content.Shared.Chemistry.EntitySystems;
using Content.Shared.Mobs.Systems;
using Content.Shared.Nutrition.Components;
using Content.Shared.Nutrition.EntitySystems;
_hunger.ModifyHunger(uid, -wooly.HungerUsage, hunger);
}
- if (!_solutionContainer.ResolveSolution(uid, wooly.SolutionName, ref wooly.Solution))
+ if (!_solutionContainer.TryGetSolution(uid, wooly.Solution, out var solution))
continue;
- _solutionContainer.TryAddReagent(wooly.Solution.Value, wooly.ReagentId, wooly.Quantity, out _);
+ _solutionContainer.TryAddReagent(uid, solution, wooly.ReagentId, wooly.Quantity, out _);
}
}
using Content.Server.Anomaly.Effects;
-using Content.Shared.Chemistry.Components;
using Content.Shared.Chemistry.Reagent;
using Robust.Shared.Audio;
using Robust.Shared.Prototypes;
/// </summary>
[DataField, ViewVariables(VVAccess.ReadWrite)]
public ProtoId<ReagentPrototype> ProducingReagent = "Water";
-
/// <summary>
/// Solution name where the substance is generated
/// </summary>
[ViewVariables(VVAccess.ReadWrite)]
[DataField("solution")]
- public string SolutionName = "default";
-
- /// <summary>
- /// Solution where the substance is generated
- /// </summary>
- [DataField("solutionRef")]
- public Entity<SolutionComponent>? Solution = null;
+ public string Solution = "default";
}
+using System.Linq;
using Content.Server.Anomaly.Components;
-using Content.Server.Chemistry.Containers.EntitySystems;
using Content.Shared.Anomaly.Components;
using Content.Shared.Chemistry.Components.SolutionManager;
-using System.Linq;
+using Content.Shared.Chemistry.EntitySystems;
namespace Content.Server.Anomaly.Effects;
/// <summary>
_injectableQuery = GetEntityQuery<InjectableSolutionComponent>();
}
- private void OnPulse(Entity<InjectionAnomalyComponent> entity, ref AnomalyPulseEvent args)
+ private void OnPulse(EntityUid uid, InjectionAnomalyComponent component, ref AnomalyPulseEvent args)
{
- PulseScalableEffect(entity, entity.Comp.InjectRadius, entity.Comp.MaxSolutionInjection * args.Severity);
+ PulseScalableEffect(uid, component, component.InjectRadius, component.MaxSolutionInjection * args.Severity);
}
- private void OnSupercritical(Entity<InjectionAnomalyComponent> entity, ref AnomalySupercriticalEvent args)
+ private void OnSupercritical(EntityUid uid, InjectionAnomalyComponent component, ref AnomalySupercriticalEvent args)
{
- PulseScalableEffect(entity, entity.Comp.SuperCriticalInjectRadius, entity.Comp.SuperCriticalSolutionInjection);
+ PulseScalableEffect(uid, component, component.SuperCriticalInjectRadius, component.SuperCriticalSolutionInjection);
}
- private void PulseScalableEffect(Entity<InjectionAnomalyComponent> entity, float injectRadius, float maxInject)
+ private void PulseScalableEffect(EntityUid uid, InjectionAnomalyComponent component, float injectRadius, float maxInject)
{
- if (!_solutionContainer.TryGetSolution(entity.Owner, entity.Comp.Solution, out _, out var sol))
+ if (!_solutionContainer.TryGetSolution(uid, component.Solution, out var sol))
return;
-
//We get all the entity in the radius into which the reagent will be injected.
var xformQuery = GetEntityQuery<TransformComponent>();
- var xform = xformQuery.GetComponent(entity);
+ var xform = xformQuery.GetComponent(uid);
var allEnts = _lookup.GetEntitiesInRange<InjectableSolutionComponent>(xform.MapPosition, injectRadius)
.Select(x => x.Owner).ToList();
//for each matching entity found
foreach (var ent in allEnts)
{
- if (!_solutionContainer.TryGetInjectableSolution(ent, out var injectable, out _))
+ if (!_solutionContainer.TryGetInjectableSolution(ent, out var injectable))
continue;
if (_injectableQuery.TryGetComponent(ent, out var injEnt))
{
- _solutionContainer.TryTransferSolution(injectable.Value, sol, maxInject);
+ var buffer = sol;
+ _solutionContainer.TryTransferSolution(ent, injectable, buffer, maxInject);
//Spawn Effect
var uidXform = Transform(ent);
- Spawn(entity.Comp.VisualEffectPrototype, uidXform.Coordinates);
+ Spawn(component.VisualEffectPrototype, uidXform.Coordinates);
}
}
}
+
}
using Content.Server.Anomaly.Components;
-using Content.Server.Chemistry.Containers.EntitySystems;
-using Content.Server.Fluids.EntitySystems;
using Content.Shared.Anomaly.Components;
+using Content.Shared.Chemistry.EntitySystems;
+using Content.Server.Fluids.EntitySystems;
namespace Content.Server.Anomaly.Effects;
SubscribeLocalEvent<PuddleCreateAnomalyComponent, AnomalySupercriticalEvent>(OnSupercritical, before: new[] { typeof(InjectionAnomalySystem) });
}
- private void OnPulse(Entity<PuddleCreateAnomalyComponent> entity, ref AnomalyPulseEvent args)
+ private void OnPulse(EntityUid uid, PuddleCreateAnomalyComponent component, ref AnomalyPulseEvent args)
{
- if (!_solutionContainer.TryGetSolution(entity.Owner, entity.Comp.Solution, out var sol, out _))
+ if (!_solutionContainer.TryGetSolution(uid, component.Solution, out var sol))
return;
- var xform = Transform(entity.Owner);
- var puddleSol = _solutionContainer.SplitSolution(sol.Value, entity.Comp.MaxPuddleSize * args.Severity);
- _puddle.TrySplashSpillAt(entity.Owner, xform.Coordinates, puddleSol, out _);
+ var xform = Transform(uid);
+ var puddleSol = _solutionContainer.SplitSolution(uid, sol, component.MaxPuddleSize * args.Severity);
+ _puddle.TrySplashSpillAt(uid, xform.Coordinates, puddleSol, out _);
}
- private void OnSupercritical(Entity<PuddleCreateAnomalyComponent> entity, ref AnomalySupercriticalEvent args)
+ private void OnSupercritical(EntityUid uid, PuddleCreateAnomalyComponent component, ref AnomalySupercriticalEvent args)
{
- if (!_solutionContainer.TryGetSolution(entity.Owner, entity.Comp.Solution, out _, out var sol))
+ if (!_solutionContainer.TryGetSolution(uid, component.Solution, out var sol))
return;
-
- var xform = Transform(entity.Owner);
- _puddle.TrySpillAt(xform.Coordinates, sol, out _);
+ var buffer = sol;
+ var xform = Transform(uid);
+ _puddle.TrySpillAt(xform.Coordinates, buffer, out _);
}
}
using Content.Server.Anomaly.Components;
-using Content.Server.Chemistry.Containers.EntitySystems;
using Content.Shared.Anomaly.Components;
+using Robust.Shared.Random;
using Content.Shared.Chemistry.Components;
+using Content.Shared.Chemistry.EntitySystems;
+using Robust.Shared.Prototypes;
using Content.Shared.Sprite;
using Robust.Server.GameObjects;
using Robust.Shared.Audio.Systems;
-using Robust.Shared.Prototypes;
-using Robust.Shared.Random;
namespace Content.Server.Anomaly.Effects;
SubscribeLocalEvent<ReagentProducerAnomalyComponent, MapInitEvent>(OnMapInit);
}
- private void OnPulse(Entity<ReagentProducerAnomalyComponent> entity, ref AnomalyPulseEvent args)
+ private void OnPulse(EntityUid uid, ReagentProducerAnomalyComponent component, ref AnomalyPulseEvent args)
{
if (_random.NextFloat(0.0f, 1.0f) > args.Stability)
- ChangeReagent(entity, args.Severity);
+ ChangeReagent(uid, component, args.Severity);
}
- private void ChangeReagent(Entity<ReagentProducerAnomalyComponent> entity, float severity)
+ private void ChangeReagent(EntityUid uid, ReagentProducerAnomalyComponent component, float severity)
{
- var reagent = GetRandomReagentType(entity, severity);
- entity.Comp.ProducingReagent = reagent;
- _audio.PlayPvs(entity.Comp.ChangeSound, entity);
+ var reagent = GetRandomReagentType(uid, component, severity);
+ component.ProducingReagent = reagent;
+ _audio.PlayPvs(component.ChangeSound, uid);
}
//reagent realtime generation
if (component.AccumulatedFrametime < component.UpdateInterval)
continue;
- if (!_solutionContainer.ResolveSolution(uid, component.SolutionName, ref component.Solution, out var producerSolution))
+ if (!_solutionContainer.TryGetSolution(uid, component.Solution, out var producerSol))
continue;
Solution newSol = new();
if (anomaly.Severity >= 0.97) reagentProducingAmount *= component.SupercriticalReagentProducingModifier;
newSol.AddReagent(component.ProducingReagent, reagentProducingAmount);
- _solutionContainer.TryAddSolution(component.Solution.Value, newSol); //TO DO - the container is not fully filled.
+ _solutionContainer.TryAddSolution(uid, producerSol, newSol); //TO DO - the container is not fully filled.
component.AccumulatedFrametime = 0;
// and nothing worked out for me. So for now it will be like this.
if (component.NeedRecolor)
{
- var color = producerSolution.GetColor(_prototypeManager);
+ var color = producerSol.GetColor(_prototypeManager);
_light.SetColor(uid, color);
if (TryComp<RandomSpriteComponent>(uid, out var randomSprite))
{
}
}
- private void OnMapInit(Entity<ReagentProducerAnomalyComponent> entity, ref MapInitEvent args)
+ private void OnMapInit(EntityUid uid, ReagentProducerAnomalyComponent component, MapInitEvent args)
{
- ChangeReagent(entity, 0.1f); //MapInit Reagent 100% change
+ ChangeReagent(uid, component, 0.1f); //MapInit Reagent 100% change
}
// returns a random reagent based on a system of random weights.
// After that, a random reagent in the selected category is selected.
//
// Such a system is made to control the danger and interest of the anomaly more.
- private string GetRandomReagentType(Entity<ReagentProducerAnomalyComponent> entity, float severity)
+ private string GetRandomReagentType(EntityUid uid, ReagentProducerAnomalyComponent component, float severity)
{
//Category Weight Randomization
- var currentWeightDangerous = MathHelper.Lerp(entity.Comp.WeightSpreadDangerous.X, entity.Comp.WeightSpreadDangerous.Y, severity);
- var currentWeightFun = MathHelper.Lerp(entity.Comp.WeightSpreadFun.X, entity.Comp.WeightSpreadFun.Y, severity);
- var currentWeightUseful = MathHelper.Lerp(entity.Comp.WeightSpreadUseful.X, entity.Comp.WeightSpreadUseful.Y, severity);
+ var currentWeightDangerous = MathHelper.Lerp(component.WeightSpreadDangerous.X, component.WeightSpreadDangerous.Y, severity);
+ var currentWeightFun = MathHelper.Lerp(component.WeightSpreadFun.X, component.WeightSpreadFun.Y, severity);
+ var currentWeightUseful = MathHelper.Lerp(component.WeightSpreadUseful.X, component.WeightSpreadUseful.Y, severity);
var sumWeight = currentWeightDangerous + currentWeightFun + currentWeightUseful;
var rnd = _random.NextFloat(0f, sumWeight);
//Dangerous
- if (rnd <= currentWeightDangerous && entity.Comp.DangerousChemicals.Count > 0)
+ if (rnd <= currentWeightDangerous && component.DangerousChemicals.Count > 0)
{
- var reagent = _random.Pick(entity.Comp.DangerousChemicals);
+ var reagent = _random.Pick(component.DangerousChemicals);
return reagent;
}
else rnd -= currentWeightDangerous;
//Fun
- if (rnd <= currentWeightFun && entity.Comp.FunChemicals.Count > 0)
+ if (rnd <= currentWeightFun && component.FunChemicals.Count > 0)
{
- var reagent = _random.Pick(entity.Comp.FunChemicals);
+ var reagent = _random.Pick(component.FunChemicals);
return reagent;
}
else rnd -= currentWeightFun;
//Useful
- if (rnd <= currentWeightUseful && entity.Comp.UsefulChemicals.Count > 0)
+ if (rnd <= currentWeightUseful && component.UsefulChemicals.Count > 0)
{
- var reagent = _random.Pick(entity.Comp.UsefulChemicals);
+ var reagent = _random.Pick(component.UsefulChemicals);
return reagent;
}
//We should never end up here.
using Content.Server.Atmos.Piping.Unary.EntitySystems;
-using Content.Shared.Chemistry.Components;
namespace Content.Server.Atmos.Piping.Unary.Components;
[DataField]
public string SolutionId = "tank";
- /// <summary>
- /// The solution that gases are condensed into.
- /// </summary>
- [DataField]
- public Entity<SolutionComponent>? Solution = null;
-
/// <summary>
/// For a condenser, how many U of reagents are given per each mole of gas.
/// </summary>
using Content.Server.NodeContainer.EntitySystems;
using Content.Server.NodeContainer.Nodes;
using Content.Server.Power.Components;
-using Content.Server.Power.EntitySystems;
using Content.Shared.Atmos;
-using Content.Shared.Chemistry.EntitySystems;
-using Content.Shared.FixedPoint;
using JetBrains.Annotations;
+using Content.Server.Power.EntitySystems;
+using Content.Shared.Chemistry.EntitySystems;
namespace Content.Server.Atmos.Piping.Unary.EntitySystems;
[Dependency] private readonly AtmosphereSystem _atmosphereSystem = default!;
[Dependency] private readonly PowerReceiverSystem _power = default!;
[Dependency] private readonly NodeContainerSystem _nodeContainer = default!;
- [Dependency] private readonly SharedSolutionContainerSystem _solution = default!;
+ [Dependency] private readonly SolutionContainerSystem _solution = default!;
public override void Initialize()
{
SubscribeLocalEvent<GasCondenserComponent, AtmosDeviceUpdateEvent>(OnCondenserUpdated);
}
- private void OnCondenserUpdated(Entity<GasCondenserComponent> entity, ref AtmosDeviceUpdateEvent args)
+ private void OnCondenserUpdated(EntityUid uid, GasCondenserComponent component, ref AtmosDeviceUpdateEvent args)
{
- if (!(_power.IsPowered(entity) && TryComp<ApcPowerReceiverComponent>(entity, out var receiver))
- || !TryComp<NodeContainerComponent>(entity, out var nodeContainer)
- || !_nodeContainer.TryGetNode(nodeContainer, entity.Comp.Inlet, out PipeNode? inlet)
- || !_solution.ResolveSolution(entity.Owner, entity.Comp.SolutionId, ref entity.Comp.Solution, out var solution))
+ if (!(_power.IsPowered(uid) && TryComp<ApcPowerReceiverComponent>(uid, out var receiver))
+ || !TryComp<NodeContainerComponent>(uid, out var nodeContainer)
+ || !_nodeContainer.TryGetNode(nodeContainer, component.Inlet, out PipeNode? inlet)
+ || !_solution.TryGetSolution(uid, component.SolutionId, out var solution))
{
return;
}
if (moles <= 0)
continue;
- if (_atmosphereSystem.GetGas(i).Reagent is not { } gasReagent)
+ if (_atmosphereSystem.GetGas(i).Reagent is not {} gasReagent)
continue;
- var moleToReagentMultiplier = entity.Comp.MolesToReagentMultiplier;
- var amount = FixedPoint2.Min(FixedPoint2.New(moles * moleToReagentMultiplier), solution.AvailableVolume);
- if (amount <= 0)
- continue;
+ var moleToReagentMultiplier = component.MolesToReagentMultiplier;
+ var amount = moles * moleToReagentMultiplier;
- solution.AddReagent(gasReagent, amount);
+ if (_solution.TryAddReagent(uid, solution, gasReagent, amount, out var remaining))
+ continue;
// if we have leftover reagent, then convert it back to moles and put it back in the mixture.
- inlet.Air.AdjustMoles(i, moles - (amount.Float() / moleToReagentMultiplier));
+ inlet.Air.AdjustMoles(i, remaining.Float() / moleToReagentMultiplier);
}
-
- _solution.UpdateChemicals(entity.Comp.Solution.Value);
}
public float NumberOfMolesToConvert(ApcPowerReceiverComponent comp, GasMixture mix, float dt)
/// <summary>
/// How much should bleeding should be reduced every update interval?
/// </summary>
- [DataField]
+ [DataField("bleedReductionAmount")]
public float BleedReductionAmount = 1.0f;
/// <summary>
/// How high can <see cref="BleedAmount"/> go?
/// </summary>
- [DataField]
+ [DataField("maxBleedAmount")]
public float MaxBleedAmount = 10.0f;
/// <summary>
/// What percentage of current blood is necessary to avoid dealing blood loss damage?
/// </summary>
- [DataField]
+ [DataField("bloodlossThreshold")]
public float BloodlossThreshold = 0.9f;
/// <summary>
/// The base bloodloss damage to be incurred if below <see cref="BloodlossThreshold"/>
/// The default values are defined per mob/species in YML.
/// </summary>
- [DataField(required: true)]
+ [DataField("bloodlossDamage", required: true)]
public DamageSpecifier BloodlossDamage = new();
/// <summary>
/// The base bloodloss damage to be healed if above <see cref="BloodlossThreshold"/>
/// The default values are defined per mob/species in YML.
/// </summary>
- [DataField(required: true)]
+ [DataField("bloodlossHealDamage", required: true)]
public DamageSpecifier BloodlossHealDamage = new();
/// <summary>
/// How frequently should this bloodstream update, in seconds?
/// </summary>
- [DataField]
+ [DataField("updateInterval")]
public float UpdateInterval = 3.0f;
// TODO shouldn't be hardcoded, should just use some organ simulation like bone marrow or smth.
/// <summary>
/// How much reagent of blood should be restored each update interval?
/// </summary>
- [DataField]
+ [DataField("bloodRefreshAmount")]
public float BloodRefreshAmount = 1.0f;
/// <summary>
/// How much blood needs to be in the temporary solution in order to create a puddle?
/// </summary>
- [DataField]
+ [DataField("bleedPuddleThreshold")]
public FixedPoint2 BleedPuddleThreshold = 1.0f;
/// <summary>
/// <remarks>
/// For example, piercing damage is increased while poison damage is nullified entirely.
/// </remarks>
- [DataField(customTypeSerializer:typeof(PrototypeIdSerializer<DamageModifierSetPrototype>))]
+ [DataField("damageBleedModifiers", customTypeSerializer:typeof(PrototypeIdSerializer<DamageModifierSetPrototype>))]
public string DamageBleedModifiers = "BloodlossHuman";
/// <summary>
/// The sound to be played when a weapon instantly deals blood loss damage.
/// </summary>
- [DataField]
+ [DataField("instantBloodSound")]
public SoundSpecifier InstantBloodSound = new SoundCollectionSpecifier("blood");
/// <summary>
/// The sound to be played when some damage actually heals bleeding rather than starting it.
/// </summary>
- [DataField]
+ [DataField("bloodHealedSound")]
public SoundSpecifier BloodHealedSound = new SoundPathSpecifier("/Audio/Effects/lightburn.ogg");
// TODO probably damage bleed thresholds.
/// <summary>
/// Max volume of internal chemical solution storage
/// </summary>
- [DataField]
+ [DataField("chemicalMaxVolume")]
public FixedPoint2 ChemicalMaxVolume = FixedPoint2.New(250);
/// <summary>
/// Max volume of internal blood storage,
/// and starting level of blood.
/// </summary>
- [DataField]
+ [DataField("bloodMaxVolume")]
public FixedPoint2 BloodMaxVolume = FixedPoint2.New(300);
/// <summary>
/// <remarks>
/// Slime-people might use slime as their blood or something like that.
/// </remarks>
- [DataField]
+ [DataField("bloodReagent")]
public string BloodReagent = "Blood";
- /// <summary>Name/Key that <see cref="BloodSolution"/> is indexed by.</summary>
- [DataField]
- public string BloodSolutionName = DefaultBloodSolutionName;
-
- /// <summary>Name/Key that <see cref="ChemicalSolution"/> is indexed by.</summary>
- [DataField]
- public string ChemicalSolutionName = DefaultChemicalsSolutionName;
-
- /// <summary>Name/Key that <see cref="TemporarySolution"/> is indexed by.</summary>
- [DataField]
- public string BloodTemporarySolutionName = DefaultBloodTemporarySolutionName;
-
/// <summary>
- /// Internal solution for blood storage
+ /// Internal solution for reagent storage
/// </summary>
- [DataField]
- public Entity<SolutionComponent>? BloodSolution = null;
+ [ViewVariables(VVAccess.ReadWrite)]
+ [Access(typeof(BloodstreamSystem), Other = AccessPermissions.ReadExecute)] // FIXME Friends
+ public Solution ChemicalSolution = default!;
/// <summary>
- /// Internal solution for reagent storage
+ /// Internal solution for blood storage
/// </summary>
- [DataField]
- public Entity<SolutionComponent>? ChemicalSolution = null;
+ [ViewVariables(VVAccess.ReadWrite)]
+ public Solution BloodSolution = default!;
/// <summary>
/// Temporary blood solution.
/// When blood is lost, it goes to this solution, and when this
/// solution hits a certain cap, the blood is actually spilled as a puddle.
/// </summary>
- [DataField]
- public Entity<SolutionComponent>? TemporarySolution = null;
+ [ViewVariables(VVAccess.ReadWrite)]
+ public Solution BloodTemporarySolution = default!;
/// <summary>
/// Variable that stores the amount of status time added by having a low blood level.
[RegisterComponent, Access(typeof(LungSystem))]
public sealed partial class LungComponent : Component
{
- [DataField]
+ [DataField("air")]
[Access(typeof(LungSystem), Other = AccessPermissions.ReadExecute)] // FIXME Friends
public GasMixture Air { get; set; } = new()
{
Temperature = Atmospherics.NormalBodyTemperature
};
- /// <summary>
- /// The name/key of the solution on this entity which these lungs act on.
- /// </summary>
- [DataField]
- public string SolutionName = LungSystem.LungSolutionName;
-
- /// <summary>
- /// The solution on this entity that these lungs act on.
- /// </summary>
- [DataField]
- public Entity<SolutionComponent>? Solution = null;
+ [ViewVariables]
+ [Access(typeof(LungSystem), Other = AccessPermissions.ReadExecute)] // FIXME Friends
+ public Solution LungSolution = default!;
}
/// How often to metabolize reagents, in seconds.
/// </summary>
/// <returns></returns>
- [DataField]
+ [DataField("updateFrequency")]
public float UpdateFrequency = 1.0f;
/// <summary>
/// <remarks>
/// Most things will use the parent entity (bloodstream).
/// </remarks>
- [DataField]
+ [DataField("solutionOnBody")]
public bool SolutionOnBody = true;
/// <summary>
/// List of metabolizer types that this organ is. ex. Human, Slime, Felinid, w/e.
/// </summary>
- [DataField(customTypeSerializer:typeof(PrototypeIdHashSetSerializer<MetabolizerTypePrototype>))]
+ [DataField("metabolizerTypes", customTypeSerializer:typeof(PrototypeIdHashSetSerializer<MetabolizerTypePrototype>))]
[Access(typeof(MetabolizerSystem), Other = AccessPermissions.ReadExecute)] // FIXME Friends
public HashSet<string>? MetabolizerTypes = null;
/// Should this metabolizer remove chemicals that have no metabolisms defined?
/// As a stop-gap, basically.
/// </summary>
- [DataField]
+ [DataField("removeEmpty")]
public bool RemoveEmpty = false;
/// <summary>
[DataDefinition]
public sealed partial class MetabolismGroupEntry
{
- [DataField(required: true, customTypeSerializer:typeof(PrototypeIdSerializer<MetabolismGroupPrototype>))]
+ [DataField("id", required: true, customTypeSerializer:typeof(PrototypeIdSerializer<MetabolismGroupPrototype>))]
public string Id = default!;
[DataField("rateModifier")]
using Content.Server.Nutrition.EntitySystems;
using Content.Shared.Chemistry.Components;
using Content.Shared.Chemistry.Reagent;
+using Content.Shared.FixedPoint;
using Content.Shared.Whitelist;
namespace Content.Server.Body.Components
/// <summary>
/// How fast should this component update, in seconds?
/// </summary>
- [DataField]
+ [DataField("updateInterval")]
public float UpdateInterval = 1.0f;
- /// <summary>
- /// The solution inside of this stomach this transfers reagents to the body.
- /// </summary>
- [DataField]
- public Entity<SolutionComponent>? Solution = null;
-
/// <summary>
/// What solution should this stomach push reagents into, on the body?
/// </summary>
- [DataField]
+ [DataField("bodySolutionName")]
public string BodySolutionName = BloodstreamComponent.DefaultChemicalsSolutionName;
/// <summary>
/// Time in seconds between reagents being ingested and them being
/// transferred to <see cref="BloodstreamComponent"/>
/// </summary>
- [DataField]
+ [DataField("digestionDelay")]
public float DigestionDelay = 20;
/// <summary>
/// A whitelist for what special-digestible-required foods this stomach is capable of eating.
/// </summary>
- [DataField]
+ [DataField("specialDigestible")]
public EntityWhitelist? SpecialDigestible = null;
/// <summary>
using Content.Server.Body.Components;
-using Content.Server.Chemistry.Containers.EntitySystems;
using Content.Server.Chemistry.ReactionEffects;
using Content.Server.Fluids.EntitySystems;
-using Content.Server.Forensics;
using Content.Server.HealthExaminable;
using Content.Server.Popups;
using Content.Shared.Alert;
using Content.Shared.Popups;
using Content.Shared.Rejuvenate;
using Content.Shared.Speech.EntitySystems;
-using Robust.Server.Audio;
+using Robust.Server.GameObjects;
using Robust.Shared.Prototypes;
using Robust.Shared.Random;
+using Content.Shared.Speech.EntitySystems;
+using Robust.Server.Audio;
+using Robust.Shared.GameObjects;
+using Content.Server.Forensics;
namespace Content.Server.Body.Systems;
SubscribeLocalEvent<BloodstreamComponent, BeingGibbedEvent>(OnBeingGibbed);
SubscribeLocalEvent<BloodstreamComponent, ApplyMetabolicMultiplierEvent>(OnApplyMetabolicMultiplier);
SubscribeLocalEvent<BloodstreamComponent, ReactionAttemptEvent>(OnReactionAttempt);
- SubscribeLocalEvent<BloodstreamComponent, SolutionRelayEvent<ReactionAttemptEvent>>(OnReactionAttempt);
SubscribeLocalEvent<BloodstreamComponent, RejuvenateEvent>(OnRejuvenate);
}
- private void OnReactionAttempt(Entity<BloodstreamComponent> entity, ref ReactionAttemptEvent args)
+ private void OnReactionAttempt(EntityUid uid, BloodstreamComponent component, ReactionAttemptEvent args)
{
- if (args.Cancelled)
+ if (args.Solution.Name != BloodstreamComponent.DefaultBloodSolutionName
+ && args.Solution.Name != BloodstreamComponent.DefaultChemicalsSolutionName
+ && args.Solution.Name != BloodstreamComponent.DefaultBloodTemporarySolutionName)
return;
foreach (var effect in args.Reaction.Effects)
{
case CreateEntityReactionEffect: // Prevent entities from spawning in the bloodstream
case AreaReactionEffect: // No spontaneous smoke or foam leaking out of blood vessels.
- args.Cancelled = true;
+ args.Cancel();
return;
}
}
// Having cheese-clots form in your veins can't be good for you.
}
- private void OnReactionAttempt(Entity<BloodstreamComponent> entity, ref SolutionRelayEvent<ReactionAttemptEvent> args)
- {
- if (args.Name != entity.Comp.BloodSolutionName
- && args.Name != entity.Comp.ChemicalSolutionName
- && args.Name != entity.Comp.BloodTemporarySolutionName)
- return;
-
- OnReactionAttempt(entity, ref args.Event);
- }
-
public override void Update(float frameTime)
{
base.Update(frameTime);
bloodstream.AccumulatedFrametime -= bloodstream.UpdateInterval;
- if (!_solutionContainerSystem.ResolveSolution(uid, bloodstream.BloodSolutionName, ref bloodstream.BloodSolution, out var bloodSolution))
- continue;
-
// Adds blood to their blood level if it is below the maximum; Blood regeneration. Must be alive.
- if (bloodSolution.Volume < bloodSolution.MaxVolume && !_mobStateSystem.IsDead(uid))
+ if (bloodstream.BloodSolution.Volume < bloodstream.BloodSolution.MaxVolume && !_mobStateSystem.IsDead(uid))
{
TryModifyBloodLevel(uid, bloodstream.BloodRefreshAmount, bloodstream);
}
}
}
- private void OnComponentInit(Entity<BloodstreamComponent> entity, ref ComponentInit args)
+ private void OnComponentInit(EntityUid uid, BloodstreamComponent component, ComponentInit args)
{
- var chemicalSolution = _solutionContainerSystem.EnsureSolution(entity.Owner, entity.Comp.ChemicalSolutionName);
- var bloodSolution = _solutionContainerSystem.EnsureSolution(entity.Owner, entity.Comp.BloodSolutionName);
- var tempSolution = _solutionContainerSystem.EnsureSolution(entity.Owner, entity.Comp.BloodTemporarySolutionName);
+ component.ChemicalSolution = _solutionContainerSystem.EnsureSolution(uid, BloodstreamComponent.DefaultChemicalsSolutionName);
+ component.BloodSolution = _solutionContainerSystem.EnsureSolution(uid, BloodstreamComponent.DefaultBloodSolutionName);
+ component.BloodTemporarySolution = _solutionContainerSystem.EnsureSolution(uid, BloodstreamComponent.DefaultBloodTemporarySolutionName);
- chemicalSolution.MaxVolume = entity.Comp.ChemicalMaxVolume;
- bloodSolution.MaxVolume = entity.Comp.BloodMaxVolume;
- tempSolution.MaxVolume = entity.Comp.BleedPuddleThreshold * 4; // give some leeway, for chemstream as well
+ component.ChemicalSolution.MaxVolume = component.ChemicalMaxVolume;
+ component.BloodSolution.MaxVolume = component.BloodMaxVolume;
+ component.BloodTemporarySolution.MaxVolume = component.BleedPuddleThreshold * 4; // give some leeway, for chemstream as well
// Fill blood solution with BLOOD
- bloodSolution.AddReagent(entity.Comp.BloodReagent, entity.Comp.BloodMaxVolume - bloodSolution.Volume);
+ _solutionContainerSystem.TryAddReagent(uid, component.BloodSolution, component.BloodReagent,
+ component.BloodMaxVolume, out _);
}
private void OnDamageChanged(EntityUid uid, BloodstreamComponent component, DamageChangedEvent args)
component.AccumulatedFrametime = component.UpdateInterval;
}
- private void OnRejuvenate(Entity<BloodstreamComponent> entity, ref RejuvenateEvent args)
+ private void OnRejuvenate(EntityUid uid, BloodstreamComponent component, RejuvenateEvent args)
{
- TryModifyBleedAmount(entity.Owner, -entity.Comp.BleedAmount, entity.Comp);
-
- if (_solutionContainerSystem.ResolveSolution(entity.Owner, entity.Comp.BloodSolutionName, ref entity.Comp.BloodSolution, out var bloodSolution))
- TryModifyBloodLevel(entity.Owner, bloodSolution.AvailableVolume, entity.Comp);
-
- if (_solutionContainerSystem.ResolveSolution(entity.Owner, entity.Comp.ChemicalSolutionName, ref entity.Comp.ChemicalSolution))
- _solutionContainerSystem.RemoveAllSolution(entity.Comp.ChemicalSolution.Value);
+ TryModifyBleedAmount(uid, -component.BleedAmount, component);
+ TryModifyBloodLevel(uid, component.BloodSolution.AvailableVolume, component);
+ _solutionContainerSystem.RemoveAllSolution(uid, component.ChemicalSolution);
}
/// <summary>
/// Attempt to transfer provided solution to internal solution.
/// </summary>
- public bool TryAddToChemicals(EntityUid uid, Solution solution, BloodstreamComponent? component = null)
+ public bool TryAddToChemicals(EntityUid uid, Solution solution, BloodstreamComponent? component=null)
{
if (!Resolve(uid, ref component, false))
return false;
- if (!_solutionContainerSystem.ResolveSolution(uid, component.ChemicalSolutionName, ref component.ChemicalSolution))
- return false;
-
- return _solutionContainerSystem.TryAddSolution(component.ChemicalSolution.Value, solution);
+ return _solutionContainerSystem.TryAddSolution(uid, component.ChemicalSolution, solution);
}
- public bool FlushChemicals(EntityUid uid, string excludedReagentID, FixedPoint2 quantity, BloodstreamComponent? component = null)
- {
+ public bool FlushChemicals(EntityUid uid, string excludedReagentID, FixedPoint2 quantity, BloodstreamComponent? component = null) {
if (!Resolve(uid, ref component, false))
return false;
- if (!_solutionContainerSystem.ResolveSolution(uid, component.ChemicalSolutionName, ref component.ChemicalSolution, out var chemSolution))
- return false;
-
- for (var i = chemSolution.Contents.Count - 1; i >= 0; i--)
+ for (var i = component.ChemicalSolution.Contents.Count - 1; i >= 0; i--)
{
- var (reagentId, _) = chemSolution.Contents[i];
+ var (reagentId, _) = component.ChemicalSolution.Contents[i];
if (reagentId.Prototype != excludedReagentID)
{
- _solutionContainerSystem.RemoveReagent(component.ChemicalSolution.Value, reagentId, quantity);
+ _solutionContainerSystem.RemoveReagent(uid, component.ChemicalSolution, reagentId, quantity);
}
}
if (!Resolve(uid, ref component))
return 0.0f;
- if (!_solutionContainerSystem.ResolveSolution(uid, component.BloodSolutionName, ref component.BloodSolution, out var bloodSolution))
- return 0.0f;
-
- return bloodSolution.FillFraction;
+ return component.BloodSolution.FillFraction;
}
public void SetBloodLossThreshold(EntityUid uid, float threshold, BloodstreamComponent? comp = null)
if (!Resolve(uid, ref component, false))
return false;
- if (!_solutionContainerSystem.ResolveSolution(uid, component.BloodSolutionName, ref component.BloodSolution))
- return false;
-
if (amount >= 0)
- return _solutionContainerSystem.TryAddReagent(component.BloodSolution.Value, component.BloodReagent, amount, out _);
+ return _solutionContainerSystem.TryAddReagent(uid, component.BloodSolution, component.BloodReagent, amount, out _);
// Removal is more involved,
// since we also wanna handle moving it to the temporary solution
// and then spilling it if necessary.
- var newSol = _solutionContainerSystem.SplitSolution(component.BloodSolution.Value, -amount);
-
- if (!_solutionContainerSystem.ResolveSolution(uid, component.BloodTemporarySolutionName, ref component.TemporarySolution, out var tempSolution))
- return true;
+ var newSol = component.BloodSolution.SplitSolution(-amount);
+ component.BloodTemporarySolution.AddSolution(newSol, _prototypeManager);
- tempSolution.AddSolution(newSol, _prototypeManager);
-
- if (tempSolution.Volume > component.BleedPuddleThreshold)
+ if (component.BloodTemporarySolution.Volume > component.BleedPuddleThreshold)
{
// Pass some of the chemstream into the spilled blood.
- if (_solutionContainerSystem.ResolveSolution(uid, component.ChemicalSolutionName, ref component.ChemicalSolution))
- {
- var temp = _solutionContainerSystem.SplitSolution(component.ChemicalSolution.Value, tempSolution.Volume / 10);
- tempSolution.AddSolution(temp, _prototypeManager);
- }
-
- if (_puddleSystem.TrySpillAt(uid, tempSolution, out var puddleUid, false))
+ var temp = component.ChemicalSolution.SplitSolution(component.BloodTemporarySolution.Volume / 10);
+ component.BloodTemporarySolution.AddSolution(temp, _prototypeManager);
+ if (_puddleSystem.TrySpillAt(uid, component.BloodTemporarySolution, out var puddleUid, false))
{
_forensicsSystem.TransferDna(puddleUid, uid, false);
}
- tempSolution.RemoveAllSolution();
+ component.BloodTemporarySolution.RemoveAllSolution();
}
- _solutionContainerSystem.UpdateChemicals(component.TemporarySolution.Value);
-
return true;
}
if (!Resolve(uid, ref component))
return;
- var tempSol = new Solution();
+ var max = component.BloodSolution.MaxVolume + component.BloodTemporarySolution.MaxVolume +
+ component.ChemicalSolution.MaxVolume;
+ var tempSol = new Solution() { MaxVolume = max };
- if (_solutionContainerSystem.ResolveSolution(uid, component.BloodSolutionName, ref component.BloodSolution, out var bloodSolution))
- {
- tempSol.MaxVolume += bloodSolution.MaxVolume;
- tempSol.AddSolution(bloodSolution, _prototypeManager);
- _solutionContainerSystem.RemoveAllSolution(component.BloodSolution.Value);
- }
-
- if (_solutionContainerSystem.ResolveSolution(uid, component.ChemicalSolutionName, ref component.ChemicalSolution, out var chemSolution))
- {
- tempSol.MaxVolume += chemSolution.MaxVolume;
- tempSol.AddSolution(chemSolution, _prototypeManager);
- _solutionContainerSystem.RemoveAllSolution(component.ChemicalSolution.Value);
- }
-
- if (_solutionContainerSystem.ResolveSolution(uid, component.BloodTemporarySolutionName, ref component.TemporarySolution, out var tempSolution))
- {
- tempSol.MaxVolume += tempSolution.MaxVolume;
- tempSol.AddSolution(tempSolution, _prototypeManager);
- _solutionContainerSystem.RemoveAllSolution(component.TemporarySolution.Value);
- }
+ tempSol.AddSolution(component.BloodSolution, _prototypeManager);
+ component.BloodSolution.RemoveAllSolution();
+ tempSol.AddSolution(component.BloodTemporarySolution, _prototypeManager);
+ component.BloodTemporarySolution.RemoveAllSolution();
+ tempSol.AddSolution(component.ChemicalSolution, _prototypeManager);
+ component.ChemicalSolution.RemoveAllSolution();
if (_puddleSystem.TrySpillAt(uid, tempSol, out var puddleUid))
{
if (!Resolve(uid, ref component, false))
return;
- if (reagent == component.BloodReagent)
+ if(reagent == component.BloodReagent)
return;
- if (!_solutionContainerSystem.ResolveSolution(uid, component.BloodSolutionName, ref component.BloodSolution, out var bloodSolution))
- {
- component.BloodReagent = reagent;
- return;
- }
-
- var currentVolume = bloodSolution.RemoveReagent(component.BloodReagent, bloodSolution.Volume);
+ var currentVolume = component.BloodSolution.Volume;
component.BloodReagent = reagent;
-
- if (currentVolume > 0)
- _solutionContainerSystem.TryAddReagent(component.BloodSolution.Value, component.BloodReagent, currentVolume, out _);
+ component.BloodSolution.RemoveAllSolution();
+ _solutionContainerSystem.TryAddReagent(uid, component.BloodSolution, component.BloodReagent, currentVolume, out _);
}
}
using Content.Server.Atmos.Components;
using Content.Server.Atmos.EntitySystems;
using Content.Server.Body.Components;
-using Content.Server.Chemistry.Containers.EntitySystems;
using Content.Shared.Atmos;
+using Content.Shared.Chemistry.EntitySystems;
using Content.Shared.Clothing;
using Content.Shared.Inventory.Events;
}
}
- private void OnComponentInit(Entity<LungComponent> entity, ref ComponentInit args)
+ private void OnComponentInit(EntityUid uid, LungComponent component, ComponentInit args)
{
- var solution = _solutionContainerSystem.EnsureSolution(entity.Owner, entity.Comp.SolutionName);
- solution.MaxVolume = 100.0f;
- solution.CanReact = false; // No dexalin lungs
+ component.LungSolution = _solutionContainerSystem.EnsureSolution(uid, LungSolutionName);
+ component.LungSolution.MaxVolume = 100.0f;
+ component.LungSolution.CanReact = false; // No dexalin lungs
}
private void OnMaskToggled(Entity<BreathToolComponent> ent, ref ItemMaskToggledEvent args)
public void GasToReagent(EntityUid uid, LungComponent lung)
{
- if (!_solutionContainerSystem.ResolveSolution(uid, lung.SolutionName, ref lung.Solution, out var solution))
- return;
-
foreach (var gas in Enum.GetValues<Gas>())
{
var i = (int) gas;
if (reagent == null) continue;
var amount = moles * Atmospherics.BreathMolesToReagentMultiplier;
- solution.AddReagent(reagent, amount);
+ _solutionContainerSystem.TryAddReagent(uid, lung.LungSolution, reagent, amount, out _);
// We don't remove the gas from the lung mix,
// that's the responsibility of whatever gas is being metabolized.
// Most things will just want to exhale again.
}
-
- _solutionContainerSystem.UpdateChemicals(lung.Solution.Value);
}
}
using Content.Server.Body.Components;
-using Content.Server.Chemistry.Containers.EntitySystems;
using Content.Shared.Administration.Logs;
using Content.Shared.Body.Organ;
using Content.Shared.Chemistry.Components;
using Content.Shared.Chemistry.Components.SolutionManager;
+using Content.Shared.Chemistry.EntitySystems;
using Content.Shared.Chemistry.Reagent;
using Content.Shared.Database;
using Content.Shared.FixedPoint;
SubscribeLocalEvent<MetabolizerComponent, ApplyMetabolicMultiplierEvent>(OnApplyMetabolicMultiplier);
}
- private void OnMetabolizerInit(Entity<MetabolizerComponent> entity, ref ComponentInit args)
+ private void OnMetabolizerInit(EntityUid uid, MetabolizerComponent component, ComponentInit args)
{
- if (!entity.Comp.SolutionOnBody)
+ if (!component.SolutionOnBody)
{
- _solutionContainerSystem.EnsureSolution(entity.Owner, entity.Comp.SolutionName);
+ _solutionContainerSystem.EnsureSolution(uid, component.SolutionName);
}
- else if (_organQuery.CompOrNull(entity)?.Body is { } body)
+ else if (_organQuery.CompOrNull(uid)?.Body is { } body)
{
- _solutionContainerSystem.EnsureSolution(body, entity.Comp.SolutionName);
+ _solutionContainerSystem.EnsureSolution(body, component.SolutionName);
}
}
// First step is get the solution we actually care about
Solution? solution = null;
- Entity<SolutionComponent>? soln = default!;
EntityUid? solutionEntityUid = null;
SolutionContainerManagerComponent? manager = null;
if (!_solutionQuery.Resolve(body, ref manager, false))
return;
- _solutionContainerSystem.TryGetSolution((body, manager), meta.SolutionName, out soln, out solution);
+ _solutionContainerSystem.TryGetSolution(body, meta.SolutionName, out solution, manager);
solutionEntityUid = body;
}
}
if (!_solutionQuery.Resolve(uid, ref manager, false))
return;
- _solutionContainerSystem.TryGetSolution((uid, manager), meta.SolutionName, out soln, out solution);
+ _solutionContainerSystem.TryGetSolution(uid, meta.SolutionName, out solution, manager);
solutionEntityUid = uid;
}
- if (solutionEntityUid == null || soln is null || solution is null || solution.Contents.Count == 0)
+ if (solutionEntityUid == null || solution == null || solution.Contents.Count == 0)
return;
// randomize the reagent list so we don't have any weird quirks
{
if (meta.RemoveEmpty)
{
- solution.RemoveReagent(reagent, FixedPoint2.New(1));
+ _solutionContainerSystem.RemoveReagent(solutionEntityUid.Value, solution, reagent,
+ FixedPoint2.New(1));
}
continue;
// remove a certain amount of reagent
if (mostToRemove > FixedPoint2.Zero)
{
- solution.RemoveReagent(reagent, mostToRemove);
+ _solutionContainerSystem.RemoveReagent(solutionEntityUid.Value, solution, reagent, mostToRemove);
// We have processed a reagant, so count it towards the cap
reagents += 1;
}
}
-
- _solutionContainerSystem.UpdateChemicals(soln.Value);
}
}
using Content.Server.Atmos;
using Content.Server.Atmos.EntitySystems;
using Content.Server.Body.Components;
-using Content.Server.Chemistry.Containers.EntitySystems;
using Content.Server.Popups;
using Content.Shared.Alert;
using Content.Shared.Atmos;
[Dependency] private readonly LungSystem _lungSystem = default!;
[Dependency] private readonly PopupSystem _popupSystem = default!;
[Dependency] private readonly MobStateSystem _mobState = default!;
- [Dependency] private readonly SolutionContainerSystem _solutionContainerSystem = default!;
public override void Initialize()
{
{
_atmosSys.Merge(outGas, lung.Air);
lung.Air.Clear();
-
- if (_solutionContainerSystem.ResolveSolution(lung.Owner, lung.SolutionName, ref lung.Solution))
- _solutionContainerSystem.RemoveAllSolution(lung.Solution.Value);
+ lung.LungSolution.RemoveAllSolution();
}
_atmosSys.Merge(ev.Gas, outGas);
using Content.Server.Body.Components;
-using Content.Server.Chemistry.Containers.EntitySystems;
using Content.Shared.Body.Organ;
using Content.Shared.Chemistry.Components;
using Content.Shared.Chemistry.Components.SolutionManager;
+using Content.Shared.Chemistry.EntitySystems;
using Robust.Shared.Utility;
namespace Content.Server.Body.Systems
stomach.AccumulatedFrameTime -= stomach.UpdateInterval;
// Get our solutions
- if (!_solutionContainerSystem.ResolveSolution((uid, sol), DefaultSolutionName, ref stomach.Solution, out var stomachSolution))
+ if (!_solutionContainerSystem.TryGetSolution(uid, DefaultSolutionName,
+ out var stomachSolution, sol))
continue;
if (organ.Body is not { } body || !_solutionContainerSystem.TryGetSolution(body, stomach.BodySolutionName, out var bodySolution))
if (reagent.Quantity > delta.ReagentQuantity.Quantity)
reagent = new(reagent.Reagent, delta.ReagentQuantity.Quantity);
- stomachSolution.RemoveReagent(reagent);
+ _solutionContainerSystem.RemoveReagent(uid, stomachSolution, reagent);
transferSolution.AddReagent(reagent);
}
stomach.ReagentDeltas.Remove(item);
}
- _solutionContainerSystem.UpdateChemicals(stomach.Solution.Value);
-
// Transfer everything to the body solution!
- _solutionContainerSystem.TryAddSolution(bodySolution.Value, transferSolution);
+ _solutionContainerSystem.TryAddSolution(body, bodySolution, transferSolution);
}
}
}
public bool CanTransferSolution(EntityUid uid, Solution solution,
- StomachComponent? stomach = null,
SolutionContainerManagerComponent? solutions = null)
{
- if (!Resolve(uid, ref stomach, ref solutions, false))
+ if (!Resolve(uid, ref solutions, false))
return false;
- if (!_solutionContainerSystem.ResolveSolution((uid, solutions), DefaultSolutionName, ref stomach.Solution, out var stomachSolution))
+ if (!_solutionContainerSystem.TryGetSolution(uid, DefaultSolutionName, out var stomachSolution, solutions))
return false;
// TODO: For now no partial transfers. Potentially change by design
if (!Resolve(uid, ref stomach, ref solutions, false))
return false;
- if (!_solutionContainerSystem.ResolveSolution((uid, solutions), DefaultSolutionName, ref stomach.Solution)
- || !CanTransferSolution(uid, solution, stomach, solutions))
+ if (!_solutionContainerSystem.TryGetSolution(uid, DefaultSolutionName, out var stomachSolution, solutions)
+ || !CanTransferSolution(uid, solution, solutions))
return false;
- _solutionContainerSystem.TryAddSolution(stomach.Solution.Value, solution);
+ _solutionContainerSystem.TryAddSolution(uid, stomachSolution, solution);
// Add each reagent to ReagentDeltas. Used to track how long each reagent has been in the stomach
foreach (var reagent in solution.Contents)
{
-using Content.Shared.Chemistry.Components;
using Robust.Shared.Serialization.TypeSerializers.Implementations.Custom;
namespace Content.Server.Botany.Components;
[ViewVariables(VVAccess.ReadWrite), DataField("solution")]
public string SoilSolutionName = "soil";
-
- [DataField]
- public Entity<SolutionComponent>? SoilSolution = null;
}
using Content.Server.Botany.Components;
using Content.Shared.FixedPoint;
+using Robust.Server.GameObjects;
namespace Content.Server.Botany.Systems;
if (!TryGetSeed(produce, out var seed))
return;
- var solutionContainer = _solutionContainerSystem.EnsureSolution(uid, produce.SolutionName, FixedPoint2.Zero, out _);
+ var solutionContainer = _solutionContainerSystem.EnsureSolution(uid, produce.SolutionName);
solutionContainer.RemoveAllSolution();
foreach (var (chem, quantity) in seed.Chemicals)
+using System.Diagnostics.CodeAnalysis;
+using System.Linq;
using Content.Server.Botany.Components;
-using Content.Server.Chemistry.Containers.EntitySystems;
using Content.Server.Kitchen.Components;
using Content.Server.Popups;
using Content.Shared.Botany;
+using Content.Shared.Chemistry.EntitySystems;
using Content.Shared.Examine;
using Content.Shared.Hands.EntitySystems;
using Content.Shared.Physics;
using Robust.Shared.Physics.Systems;
using Robust.Shared.Prototypes;
using Robust.Shared.Random;
-using System.Diagnostics.CodeAnalysis;
-using System.Linq;
namespace Content.Server.Botany.Systems;
using Content.Server.Atmos;
using Content.Server.Atmos.EntitySystems;
using Content.Server.Botany.Components;
-using Content.Server.Chemistry.Containers.EntitySystems;
using Content.Server.Fluids.Components;
using Content.Server.Ghost.Roles.Components;
using Content.Server.Kitchen.Components;
using Content.Server.Popups;
using Content.Shared.Botany;
+using Content.Shared.Chemistry.EntitySystems;
using Content.Shared.Chemistry.Reagent;
using Content.Shared.Coordinates.Helpers;
using Content.Shared.Examine;
[Dependency] private readonly PopupSystem _popup = default!;
[Dependency] private readonly IGameTiming _gameTiming = default!;
[Dependency] private readonly SharedPointLightSystem _pointLight = default!;
- [Dependency] private readonly SolutionContainerSystem _solutionContainerSystem = default!;
+ [Dependency] private readonly SolutionContainerSystem _solutionSystem = default!;
[Dependency] private readonly TagSystem _tagSystem = default!;
[Dependency] private readonly RandomHelperSystem _randomHelper = default!;
[Dependency] private readonly IRobustRandom _random = default!;
}
}
- private void OnExamine(Entity<PlantHolderComponent> entity, ref ExaminedEvent args)
+ private void OnExamine(EntityUid uid, PlantHolderComponent component, ExaminedEvent args)
{
if (!args.IsInDetailsRange)
return;
- var (_, component) = entity;
-
if (component.Seed == null)
{
args.PushMarkup(Loc.GetString("plant-holder-component-nothing-planted-message"));
}
}
- private void OnInteractUsing(Entity<PlantHolderComponent> entity, ref InteractUsingEvent args)
+ private void OnInteractUsing(EntityUid uid, PlantHolderComponent component, InteractUsingEvent args)
{
- var (uid, component) = entity;
-
if (TryComp(args.Used, out SeedComponent? seeds))
{
if (component.Seed == null)
return;
}
- if (_solutionContainerSystem.TryGetDrainableSolution(args.Used, out var solution, out _)
- && _solutionContainerSystem.ResolveSolution(uid, component.SoilSolutionName, ref component.SoilSolution)
+ if (_solutionSystem.TryGetDrainableSolution(args.Used, out var solution)
+ && _solutionSystem.TryGetSolution(uid, component.SoilSolutionName, out var targetSolution)
&& TryComp(args.Used, out SprayComponent? spray))
{
var amount = FixedPoint2.New(1);
_audio.PlayPvs(spray.SpraySound, args.Used, AudioParams.Default.WithVariation(0.125f));
- var split = _solutionContainerSystem.Drain(solutionEntity, solution.Value, amount);
+ var split = _solutionSystem.Drain(solutionEntity, solution, amount);
if (split.Volume == 0)
{
("owner", uid),
("amount", split.Volume)), args.User, PopupType.Medium);
- _solutionContainerSystem.TryAddSolution(component.SoilSolution.Value, split);
+ _solutionSystem.TryAddSolution(targetEntity, targetSolution, split);
ForceUpdateByExternalCause(uid, component);
("usingItem", args.Used),
("owner", uid)), uid, Filter.PvsExcept(args.User), true);
- if (_solutionContainerSystem.TryGetSolution(args.Used, produce.SolutionName, out var soln2, out var solution2))
+ if (_solutionSystem.TryGetSolution(args.Used, produce.SolutionName, out var solution2))
{
- if (_solutionContainerSystem.ResolveSolution(uid, component.SoilSolutionName, ref component.SoilSolution, out var solution1))
+ if (_solutionSystem.TryGetSolution(uid, component.SoilSolutionName, out var solution1))
{
// We try to fit as much of the composted plant's contained solution into the hydroponics tray as we can,
// since the plant will be consumed anyway.
var fillAmount = FixedPoint2.Min(solution2.Volume, solution1.AvailableVolume);
- _solutionContainerSystem.TryAddSolution(component.SoilSolution.Value, _solutionContainerSystem.SplitSolution(soln2.Value, fillAmount));
+ _solutionSystem.TryAddSolution(uid, solution1,
+ _solutionSystem.SplitSolution(args.Used, solution2, fillAmount));
ForceUpdateByExternalCause(uid, component);
}
}
}
- private void OnInteractHand(Entity<PlantHolderComponent> entity, ref InteractHandEvent args)
+ private void OnInteractHand(EntityUid uid, PlantHolderComponent component, InteractHandEvent args)
{
- DoHarvest(entity, args.User, entity.Comp);
+ DoHarvest(uid, args.User, component);
}
public void WeedInvasion()
if (!Resolve(uid, ref component))
return;
- if (!_solutionContainerSystem.ResolveSolution(uid, component.SoilSolutionName, ref component.SoilSolution, out var solution))
+ if (!_solutionSystem.TryGetSolution(uid, component.SoilSolutionName, out var solution))
return;
if (solution.Volume > 0 && component.MutationLevel < 25)
{
var amt = FixedPoint2.New(1);
- foreach (var entry in _solutionContainerSystem.RemoveEachReagent(component.SoilSolution.Value, amt))
+ foreach (var entry in _solutionSystem.RemoveEachReagent(uid, solution, amt))
{
var reagentProto = _prototype.Index<ReagentPrototype>(entry.Reagent.Prototype);
reagentProto.ReactionPlant(uid, entry, solution);
-using Content.Server.Administration;
+using System.Linq;
+using Content.Server.Administration;
using Content.Server.Body.Systems;
using Content.Server.Cargo.Components;
-using Content.Server.Chemistry.Containers.EntitySystems;
using Content.Shared.Administration;
using Content.Shared.Body.Components;
using Content.Shared.Chemistry.Components.SolutionManager;
using Robust.Shared.Map.Components;
using Robust.Shared.Prototypes;
using Robust.Shared.Utility;
-using System.Linq;
namespace Content.Server.Cargo.Systems;
[Dependency] private readonly IPrototypeManager _prototypeManager = default!;
[Dependency] private readonly BodySystem _bodySystem = default!;
[Dependency] private readonly MobStateSystem _mobStateSystem = default!;
- [Dependency] private readonly SolutionContainerSystem _solutionContainerSystem = default!;
/// <inheritdoc/>
public override void Initialize()
args.Price += (component.Price - partPenalty) * (_mobStateSystem.IsAlive(uid, state) ? 1.0 : component.DeathPenalty);
}
- private double GetSolutionPrice(Entity<SolutionContainerManagerComponent> entity)
- {
- if (Comp<MetaDataComponent>(entity).EntityLifeStage < EntityLifeStage.MapInitialized)
- return GetSolutionPrice(entity.Comp);
-
- var price = 0.0;
-
- foreach (var (_, soln) in _solutionContainerSystem.EnumerateSolutions((entity.Owner, entity.Comp)))
- {
- var solution = soln.Comp.Solution;
- foreach (var (reagent, quantity) in solution.Contents)
- {
- if (!_prototypeManager.TryIndex<ReagentPrototype>(reagent.Prototype, out var reagentProto))
- continue;
-
- // TODO check ReagentData for price information?
- price += (float) quantity * reagentProto.PricePerUnit;
- }
- }
-
- return price;
- }
-
private double GetSolutionPrice(SolutionContainerManagerComponent component)
{
var price = 0.0;
- foreach (var (_, prototype) in _solutionContainerSystem.EnumerateSolutions(component))
+ foreach (var solution in component.Solutions.Values)
{
- foreach (var (reagent, quantity) in prototype.Contents)
+ foreach (var (reagent, quantity) in solution.Contents)
{
if (!_prototypeManager.TryIndex<ReagentPrototype>(reagent.Prototype, out var reagentProto))
continue;
if (TryComp<SolutionContainerManagerComponent>(uid, out var solComp))
{
- price += GetSolutionPrice((uid, solComp));
+ price += GetSolutionPrice(solComp);
}
return price;
+using Content.Server.Chemistry.EntitySystems;
using Content.Shared.Chemistry.Components;
using Content.Shared.FixedPoint;
using Robust.Shared.Audio;
using Content.Server.Chemistry.EntitySystems;
using Content.Shared.Chemistry.Components;
+using Content.Shared.FixedPoint;
using Robust.Shared.Serialization.TypeSerializers.Implementations.Custom;
+using Robust.Shared.Serialization.TypeSerializers.Implementations.Custom.Prototype;
namespace Content.Server.Chemistry.Components;
/// The name of the solution to add to.
/// </summary>
[DataField("solution", required: true), ViewVariables(VVAccess.ReadWrite)]
- public string SolutionName = string.Empty;
-
- /// <summary>
- /// The solution to add reagents to.
- /// </summary>
- [DataField("solutionRef")]
- public Entity<SolutionComponent>? Solution = null;
+ public string Solution = string.Empty;
/// <summary>
/// The reagent(s) to be regenerated in the solution.
+++ /dev/null
-using Content.Shared.Chemistry.Components;
-using Content.Shared.Chemistry.Components.SolutionManager;
-using Content.Shared.Chemistry.EntitySystems;
-using Content.Shared.FixedPoint;
-using Robust.Shared.Containers;
-using Robust.Shared.Map;
-using Robust.Shared.Network;
-using Robust.Shared.Utility;
-using System.Numerics;
-
-namespace Content.Server.Chemistry.Containers.EntitySystems;
-
-public sealed partial class SolutionContainerSystem : SharedSolutionContainerSystem
-{
- [Dependency] private readonly INetManager _netManager = default!;
-
- public override void Initialize()
- {
- base.Initialize();
-
- SubscribeLocalEvent<SolutionContainerManagerComponent, MapInitEvent>(OnMapInit);
- SubscribeLocalEvent<SolutionContainerManagerComponent, ComponentShutdown>(OnComponentShutdown);
- SubscribeLocalEvent<ContainedSolutionComponent, ComponentShutdown>(OnComponentShutdown);
- }
-
-
- public Solution EnsureSolution(Entity<MetaDataComponent?> entity, string name)
- => EnsureSolution(entity, name, out _);
-
- public Solution EnsureSolution(Entity<MetaDataComponent?> entity, string name, out bool existed)
- => EnsureSolution(entity, name, FixedPoint2.Zero, out existed);
-
- public Solution EnsureSolution(Entity<MetaDataComponent?> entity, string name, FixedPoint2 minVol, out bool existed)
- => EnsureSolution(entity, name, minVol, null, out existed);
-
- public Solution EnsureSolution(Entity<MetaDataComponent?> entity, string name, FixedPoint2 minVol, Solution? prototype, out bool existed)
- {
- var (uid, meta) = entity;
- DebugTools.Assert(Resolve(uid, ref meta), $"Attempted to ensure solution on invalid entity {ToPrettyString(entity.Owner)}");
-
- var manager = EnsureComp<SolutionContainerManagerComponent>(uid);
- if (meta.EntityLifeStage >= EntityLifeStage.MapInitialized)
- return EnsureSolutionEntity((uid, manager), name, minVol, prototype, out existed).Comp.Solution;
- else
- return EnsureSolutionPrototype((uid, manager), name, minVol, prototype, out existed);
- }
-
- public Entity<SolutionComponent> EnsureSolutionEntity(Entity<SolutionContainerManagerComponent?> entity, string name, FixedPoint2 minVol, Solution? prototype, out bool existed)
- {
- existed = true;
-
- var (uid, container) = entity;
-
- var solutionSlot = ContainerSystem.EnsureContainer<ContainerSlot>(uid, $"solution@{name}", out existed);
- if (!Resolve(uid, ref container, logMissing: false))
- {
- existed = false;
- container = AddComp<SolutionContainerManagerComponent>(uid);
- container.Containers.Add(name);
- }
- else if (!existed)
- {
- container.Containers.Add(name);
- Dirty(uid, container);
- }
-
- var needsInit = false;
- SolutionComponent solutionComp;
- if (solutionSlot.ContainedEntity is not { } solutionId)
- {
- prototype ??= new() { MaxVolume = minVol };
- prototype.Name = name;
- (solutionId, solutionComp, _) = SpawnSolutionUninitialized(solutionSlot, name, minVol, prototype);
- existed = false;
- needsInit = true;
- Dirty(uid, container);
- }
- else
- {
- solutionComp = Comp<SolutionComponent>(solutionId);
- DebugTools.Assert(TryComp(solutionId, out ContainedSolutionComponent? relation) && relation.Container == uid && relation.ContainerName == name);
- DebugTools.Assert(solutionComp.Solution.Name == name);
-
- var solution = solutionComp.Solution;
- solution.MaxVolume = FixedPoint2.Max(solution.MaxVolume, minVol);
-
- // Depending on MapInitEvent order some systems can ensure solution empty solutions and conflict with the prototype solutions.
- // We want the reagents from the prototype to exist even if something else already created the solution.
- if (prototype is { Volume.Value: > 0 })
- solution.AddSolution(prototype, PrototypeManager);
-
- Dirty(solutionId, solutionComp);
- }
-
- if (needsInit)
- EntityManager.InitializeAndStartEntity(solutionId, Transform(solutionId).MapID);
-
- return (solutionId, solutionComp);
- }
-
- private Solution EnsureSolutionPrototype(Entity<SolutionContainerManagerComponent?> entity, string name, FixedPoint2 minVol, Solution? prototype, out bool existed)
- {
- existed = true;
-
- var (uid, container) = entity;
- if (!Resolve(uid, ref container, logMissing: false))
- {
- container = AddComp<SolutionContainerManagerComponent>(uid);
- existed = false;
- }
-
- if (container.Solutions is null)
- container.Solutions = new(SolutionContainerManagerComponent.DefaultCapacity);
-
- if (!container.Solutions.TryGetValue(name, out var solution))
- {
- solution = prototype ?? new() { Name = name, MaxVolume = minVol };
- container.Solutions.Add(name, solution);
- existed = false;
- }
- else
- solution.MaxVolume = FixedPoint2.Max(solution.MaxVolume, minVol);
-
- Dirty(uid, container);
- return solution;
- }
-
-
- private Entity<SolutionComponent, ContainedSolutionComponent> SpawnSolutionUninitialized(ContainerSlot container, string name, FixedPoint2 minVol, Solution prototype)
- {
- var coords = new EntityCoordinates(container.Owner, Vector2.Zero);
- var uid = EntityManager.CreateEntityUninitialized(null, coords, null);
-
- var solution = new SolutionComponent() { Solution = prototype };
- AddComp(uid, solution);
-
- var relation = new ContainedSolutionComponent() { Container = container.Owner, ContainerName = name };
- AddComp(uid, relation);
-
- ContainerSystem.Insert(uid, container, force: true);
-
- return (uid, solution, relation);
- }
-
-
- #region Event Handlers
-
- private void OnMapInit(Entity<SolutionContainerManagerComponent> entity, ref MapInitEvent args)
- {
- if (entity.Comp.Solutions is not { } prototypes)
- return;
-
- foreach (var (name, prototype) in prototypes)
- {
- EnsureSolutionEntity((entity.Owner, entity.Comp), name, prototype.MaxVolume, prototype, out _);
- }
-
- entity.Comp.Solutions = null;
- Dirty(entity);
- }
-
- private void OnComponentShutdown(Entity<SolutionContainerManagerComponent> entity, ref ComponentShutdown args)
- {
- foreach (var name in entity.Comp.Containers)
- {
- if (ContainerSystem.TryGetContainer(entity, $"solution@{name}", out var solutionContainer))
- ContainerSystem.ShutdownContainer(solutionContainer);
- }
- entity.Comp.Containers.Clear();
- }
-
- private void OnComponentShutdown(Entity<ContainedSolutionComponent> entity, ref ComponentShutdown args)
- {
- if (TryComp(entity.Comp.Container, out SolutionContainerManagerComponent? container))
- {
- container.Containers.Remove(entity.Comp.ContainerName);
- Dirty(entity.Comp.Container, container);
- }
-
- if (ContainerSystem.TryGetContainer(entity, $"solution@{entity.Comp.ContainerName}", out var solutionContainer))
- ContainerSystem.ShutdownContainer(solutionContainer);
- }
-
- #endregion Event Handlers
-}
+using System.Diagnostics.CodeAnalysis;
+using System.Linq;
using Content.Server.Chemistry.Components;
-using Content.Server.Chemistry.Containers.EntitySystems;
using Content.Server.Labels;
using Content.Server.Popups;
using Content.Server.Storage.EntitySystems;
using Robust.Shared.Audio;
using Robust.Shared.Containers;
using Robust.Shared.Prototypes;
-using System.Diagnostics.CodeAnalysis;
-using System.Linq;
namespace Content.Server.Chemistry.EntitySystems
{
base.Initialize();
SubscribeLocalEvent<ChemMasterComponent, ComponentStartup>(SubscribeUpdateUiState);
- SubscribeLocalEvent<ChemMasterComponent, SolutionContainerChangedEvent>(SubscribeUpdateUiState);
+ SubscribeLocalEvent<ChemMasterComponent, SolutionChangedEvent>(SubscribeUpdateUiState);
SubscribeLocalEvent<ChemMasterComponent, EntInsertedIntoContainerMessage>(SubscribeUpdateUiState);
SubscribeLocalEvent<ChemMasterComponent, EntRemovedFromContainerMessage>(SubscribeUpdateUiState);
SubscribeLocalEvent<ChemMasterComponent, BoundUIOpenedEvent>(SubscribeUpdateUiState);
private void UpdateUiState(Entity<ChemMasterComponent> ent, bool updateLabel = false)
{
var (owner, chemMaster) = ent;
- if (!_solutionContainerSystem.TryGetSolution(owner, SharedChemMaster.BufferSolutionName, out _, out var bufferSolution))
+ if (!_solutionContainerSystem.TryGetSolution(owner, SharedChemMaster.BufferSolutionName, out var bufferSolution))
return;
var inputContainer = _itemSlotsSystem.GetItemOrNull(owner, SharedChemMaster.InputSlotName);
var outputContainer = _itemSlotsSystem.GetItemOrNull(owner, SharedChemMaster.OutputSlotName);
{
var container = _itemSlotsSystem.GetItemOrNull(chemMaster, SharedChemMaster.InputSlotName);
if (container is null ||
- !_solutionContainerSystem.TryGetFitsInDispenser(container.Value, out var containerSoln, out var containerSolution) ||
- !_solutionContainerSystem.TryGetSolution(chemMaster.Owner, SharedChemMaster.BufferSolutionName, out _, out var bufferSolution))
+ !_solutionContainerSystem.TryGetFitsInDispenser(container.Value, out var containerSolution) ||
+ !_solutionContainerSystem.TryGetSolution(chemMaster, SharedChemMaster.BufferSolutionName, out var bufferSolution))
{
return;
}
{
amount = FixedPoint2.Min(amount, containerSolution.AvailableVolume);
amount = bufferSolution.RemoveReagent(id, amount);
- _solutionContainerSystem.TryAddReagent(containerSoln.Value, id, amount, out var _);
+ _solutionContainerSystem.TryAddReagent(container.Value, containerSolution, id, amount, out var _);
}
else // Container to buffer
{
amount = FixedPoint2.Min(amount, containerSolution.GetReagentQuantity(id));
- _solutionContainerSystem.RemoveReagent(containerSoln.Value, id, amount);
+ _solutionContainerSystem.RemoveReagent(container.Value, containerSolution, id, amount);
bufferSolution.AddReagent(id, amount);
}
{
if (fromBuffer)
{
- if (_solutionContainerSystem.TryGetSolution(chemMaster.Owner, SharedChemMaster.BufferSolutionName, out _, out var bufferSolution))
+ if (_solutionContainerSystem.TryGetSolution(chemMaster, SharedChemMaster.BufferSolutionName, out var bufferSolution))
bufferSolution.RemoveReagent(id, amount);
else
return;
{
var container = _itemSlotsSystem.GetItemOrNull(chemMaster, SharedChemMaster.InputSlotName);
if (container is not null &&
- _solutionContainerSystem.TryGetFitsInDispenser(container.Value, out var containerSolution, out _))
+ _solutionContainerSystem.TryGetFitsInDispenser(container.Value, out var containerSolution))
{
- _solutionContainerSystem.RemoveReagent(containerSolution.Value, id, amount);
+ _solutionContainerSystem.RemoveReagent(container.Value, containerSolution, id, amount);
}
else
return;
_storageSystem.Insert(container, item, out _, user: user, storage);
_labelSystem.Label(item, message.Label);
- var itemSolution = _solutionContainerSystem.EnsureSolutionEntity(item, SharedChemMaster.PillSolutionName, message.Dosage, null, out _);
- _solutionContainerSystem.TryAddSolution(itemSolution, withdrawal.SplitSolution(message.Dosage));
+ var itemSolution = _solutionContainerSystem.EnsureSolution(item, SharedChemMaster.PillSolutionName);
+
+ _solutionContainerSystem.TryAddSolution(
+ item, itemSolution, withdrawal.SplitSolution(message.Dosage));
var pill = EnsureComp<PillComponent>(item);
pill.PillType = chemMaster.Comp.PillType;
{
// Log pill creation by a user
_adminLogger.Add(LogType.Action, LogImpact.Low,
- $"{ToPrettyString(user.Value):user} printed {ToPrettyString(item):pill} {SolutionContainerSystem.ToPrettyString(itemSolution.Comp.Solution)}");
+ $"{ToPrettyString(user.Value):user} printed {ToPrettyString(item):pill} {SolutionContainerSystem.ToPrettyString(itemSolution)}");
}
else
{
// Log pill creation by magic? This should never happen... right?
_adminLogger.Add(LogType.Action, LogImpact.Low,
- $"Unknown printed {ToPrettyString(item):pill} {SolutionContainerSystem.ToPrettyString(itemSolution.Comp.Solution)}");
+ $"Unknown printed {ToPrettyString(item):pill} {SolutionContainerSystem.ToPrettyString(itemSolution)}");
}
}
var user = message.Session.AttachedEntity;
var maybeContainer = _itemSlotsSystem.GetItemOrNull(chemMaster, SharedChemMaster.OutputSlotName);
if (maybeContainer is not { Valid: true } container
- || !_solutionContainerSystem.TryGetSolution(container, SharedChemMaster.BottleSolutionName, out var soln, out var solution))
+ || !_solutionContainerSystem.TryGetSolution(
+ container, SharedChemMaster.BottleSolutionName, out var solution))
{
return; // output can't fit reagents
}
return;
_labelSystem.Label(container, message.Label);
- _solutionContainerSystem.TryAddSolution(soln.Value, withdrawal);
+ _solutionContainerSystem.TryAddSolution(
+ container, solution, withdrawal);
if (user.HasValue)
{
{
outputSolution = null;
- if (!_solutionContainerSystem.TryGetSolution(chemMaster.Owner, SharedChemMaster.BufferSolutionName, out _, out var solution))
+ if (!_solutionContainerSystem.TryGetSolution(
+ chemMaster, SharedChemMaster.BufferSolutionName, out var solution))
{
return false;
}
return null;
if (!TryComp(container, out FitsInDispenserComponent? fits)
- || !_solutionContainerSystem.TryGetSolution(container.Value, fits.Solution, out _, out var solution))
+ || !_solutionContainerSystem.TryGetSolution(container.Value, fits.Solution, out var solution))
{
return null;
}
var name = Name(container.Value);
{
if (_solutionContainerSystem.TryGetSolution(
- container.Value, SharedChemMaster.BottleSolutionName, out _, out var solution))
+ container.Value, SharedChemMaster.BottleSolutionName, out var solution))
{
return BuildContainerInfo(name, solution);
}
var pills = storage.Container.ContainedEntities.Select((Func<EntityUid, (string, FixedPoint2 quantity)>) (pill =>
{
- _solutionContainerSystem.TryGetSolution(pill, SharedChemMaster.PillSolutionName, out _, out var solution);
+ _solutionContainerSystem.TryGetSolution(pill, SharedChemMaster.PillSolutionName, out var solution);
var quantity = solution?.Volume ?? FixedPoint2.Zero;
return (Name(pill), quantity);
})).ToList();
using Content.Server.Body.Components;
using Content.Server.Chemistry.Components;
-using Content.Server.Chemistry.Containers.EntitySystems;
using Content.Shared.Chemistry.Components;
using Content.Shared.Chemistry.Components.SolutionManager;
using Content.Shared.Chemistry.EntitySystems;
using Content.Shared.Chemistry.Reagent;
using Content.Shared.Database;
-using Content.Shared.DoAfter;
using Content.Shared.FixedPoint;
-using Content.Shared.Forensics;
using Content.Shared.IdentityManagement;
using Content.Shared.Interaction;
using Content.Shared.Interaction.Events;
+using Robust.Shared.GameStates;
+using Content.Shared.DoAfter;
using Content.Shared.Mobs.Components;
-using Content.Shared.Stacks;
using Content.Shared.Verbs;
-using Robust.Shared.GameStates;
+using Content.Shared.Stacks;
using Robust.Shared.Player;
+using Content.Shared.Forensics;
namespace Content.Server.Chemistry.EntitySystems;
/// <summary>
/// Default transfer amounts for the set-transfer verb.
/// </summary>
- public static readonly List<int> TransferAmounts = new() { 1, 5, 10, 15 };
+ public static readonly List<int> TransferAmounts = new() {1, 5, 10, 15};
private void InitializeInjector()
{
SubscribeLocalEvent<InjectorComponent, GetVerbsEvent<AlternativeVerb>>(AddSetTransferVerbs);
- SubscribeLocalEvent<InjectorComponent, SolutionContainerChangedEvent>(OnSolutionChange);
+ SubscribeLocalEvent<InjectorComponent, SolutionChangedEvent>(OnSolutionChange);
SubscribeLocalEvent<InjectorComponent, InjectorDoAfterEvent>(OnInjectDoAfter);
SubscribeLocalEvent<InjectorComponent, ComponentStartup>(OnInjectorStartup);
SubscribeLocalEvent<InjectorComponent, UseInHandEvent>(OnInjectorUse);
SubscribeLocalEvent<InjectorComponent, ComponentGetState>(OnInjectorGetState);
}
- private void AddSetTransferVerbs(Entity<InjectorComponent> entity, ref GetVerbsEvent<AlternativeVerb> args)
+ private void AddSetTransferVerbs(EntityUid uid, InjectorComponent component, GetVerbsEvent<AlternativeVerb> args)
{
if (!args.CanAccess || !args.CanInteract || args.Hands == null)
return;
if (!EntityManager.TryGetComponent(args.User, out ActorComponent? actor))
return;
- var (uid, component) = entity;
-
// Add specific transfer verbs according to the container's size
var priority = 0;
- var user = args.User;
foreach (var amount in TransferAmounts)
{
- if (amount < component.MinimumTransferAmount.Int() || amount > component.MaximumTransferAmount.Int())
+ if ( amount < component.MinimumTransferAmount.Int() || amount > component.MaximumTransferAmount.Int())
continue;
AlternativeVerb verb = new();
verb.Act = () =>
{
component.TransferAmount = FixedPoint2.New(amount);
- _popup.PopupEntity(Loc.GetString("comp-solution-transfer-set-amount", ("amount", amount)), user, user);
+ _popup.PopupEntity(Loc.GetString("comp-solution-transfer-set-amount", ("amount", amount)), args.User, args.User);
};
// we want to sort by size, not alphabetically by the verb text.
}
}
- private void UseInjector(Entity<InjectorComponent> injector, EntityUid target, EntityUid user)
+ private void UseInjector(EntityUid target, EntityUid user, EntityUid injector, InjectorComponent component)
{
// Handle injecting/drawing for solutions
- if (injector.Comp.ToggleState == SharedInjectorComponent.InjectorToggleMode.Inject)
+ if (component.ToggleState == SharedInjectorComponent.InjectorToggleMode.Inject)
{
- if (_solutionContainers.TryGetInjectableSolution(target, out var injectableSolution, out _))
+ if (_solutions.TryGetInjectableSolution(target, out var injectableSolution))
{
- TryInject(injector, target, injectableSolution.Value, user, false);
+ TryInject(component, injector, target, injectableSolution, user, false);
}
- else if (_solutionContainers.TryGetRefillableSolution(target, out var refillableSolution, out _))
+ else if (_solutions.TryGetRefillableSolution(target, out var refillableSolution))
{
- TryInject(injector, target, refillableSolution.Value, user, true);
+ TryInject(component, injector, target, refillableSolution, user, true);
}
else if (TryComp<BloodstreamComponent>(target, out var bloodstream))
{
- TryInjectIntoBloodstream(injector, (target, bloodstream), user);
+ TryInjectIntoBloodstream(component, injector, target, bloodstream, user);
}
else
{
("target", Identity.Entity(target, EntityManager))), injector, user);
}
}
- else if (injector.Comp.ToggleState == SharedInjectorComponent.InjectorToggleMode.Draw)
+ else if (component.ToggleState == SharedInjectorComponent.InjectorToggleMode.Draw)
{
// Draw from a bloodstream, if the target has that
- if (TryComp<BloodstreamComponent>(target, out var stream) &&
- _solutionContainers.ResolveSolution(target, stream.BloodSolutionName, ref stream.BloodSolution))
+ if (TryComp<BloodstreamComponent>(target, out var stream))
{
- TryDraw(injector, (target, stream), stream.BloodSolution.Value, user);
+ TryDraw(component, injector, target, stream.BloodSolution, user, stream);
return;
}
// Draw from an object (food, beaker, etc)
- if (_solutionContainers.TryGetDrawableSolution(target, out var drawableSolution, out _))
+ if (_solutions.TryGetDrawableSolution(target, out var drawableSolution))
{
- TryDraw(injector, target, drawableSolution.Value, user);
+ TryDraw(component, injector, target, drawableSolution, user);
}
else
{
_popup.PopupEntity(Loc.GetString("injector-component-cannot-draw-message",
- ("target", Identity.Entity(target, EntityManager))), injector.Owner, user);
+ ("target", Identity.Entity(target, EntityManager))), injector, user);
}
}
}
- private void OnSolutionChange(Entity<InjectorComponent> entity, ref SolutionContainerChangedEvent args)
+ private void OnSolutionChange(EntityUid uid, InjectorComponent component, SolutionChangedEvent args)
{
- Dirty(entity);
+ Dirty(component);
}
- private void OnInjectorGetState(Entity<InjectorComponent> entity, ref ComponentGetState args)
+ private void OnInjectorGetState(EntityUid uid, InjectorComponent component, ref ComponentGetState args)
{
- _solutionContainers.TryGetSolution(entity.Owner, InjectorComponent.SolutionName, out _, out var solution);
+ _solutions.TryGetSolution(uid, InjectorComponent.SolutionName, out var solution);
var currentVolume = solution?.Volume ?? FixedPoint2.Zero;
var maxVolume = solution?.MaxVolume ?? FixedPoint2.Zero;
- args.State = new SharedInjectorComponent.InjectorComponentState(currentVolume, maxVolume, entity.Comp.ToggleState);
+ args.State = new SharedInjectorComponent.InjectorComponentState(currentVolume, maxVolume, component.ToggleState);
}
- private void OnInjectDoAfter(Entity<InjectorComponent> entity, ref InjectorDoAfterEvent args)
+ private void OnInjectDoAfter(EntityUid uid, InjectorComponent component, DoAfterEvent args)
{
if (args.Cancelled || args.Handled || args.Args.Target == null)
return;
- UseInjector(entity, args.Args.Target.Value, args.Args.User);
+ UseInjector(args.Args.Target.Value, args.Args.User, uid, component);
args.Handled = true;
}
- private void OnInjectorAfterInteract(Entity<InjectorComponent> entity, ref AfterInteractEvent args)
+ private void OnInjectorAfterInteract(EntityUid uid, InjectorComponent component, AfterInteractEvent args)
{
if (args.Handled || !args.CanReach)
return;
//Make sure we have the attacking entity
- if (args.Target is not { Valid: true } target || !HasComp<SolutionContainerManagerComponent>(entity))
+ if (args.Target is not { Valid: true } target || !HasComp<SolutionContainerManagerComponent>(uid))
return;
// Is the target a mob? If yes, use a do-after to give them time to respond.
if (HasComp<MobStateComponent>(target) || HasComp<BloodstreamComponent>(target))
{
// Are use using an injector capible of targeting a mob?
- if (entity.Comp.IgnoreMobs)
+ if (component.IgnoreMobs)
return;
- InjectDoAfter(entity, target, args.User);
+ InjectDoAfter(component, args.User, target, uid);
args.Handled = true;
return;
}
- UseInjector(entity, target, args.User);
+ UseInjector(target, args.User, uid, component);
args.Handled = true;
}
- private void OnInjectorStartup(Entity<InjectorComponent> entity, ref ComponentStartup args)
+ private void OnInjectorStartup(EntityUid uid, InjectorComponent component, ComponentStartup args)
{
// ???? why ?????
- Dirty(entity);
+ Dirty(component);
}
- private void OnInjectorUse(Entity<InjectorComponent> entity, ref UseInHandEvent args)
+ private void OnInjectorUse(EntityUid uid, InjectorComponent component, UseInHandEvent args)
{
if (args.Handled)
return;
- Toggle(entity, args.User);
+ Toggle(component, args.User, uid);
args.Handled = true;
}
/// <summary>
/// Toggle between draw/inject state if applicable
/// </summary>
- private void Toggle(Entity<InjectorComponent> injector, EntityUid user)
+ private void Toggle(InjectorComponent component, EntityUid user, EntityUid injector)
{
- if (injector.Comp.InjectOnly)
+ if (component.InjectOnly)
{
return;
}
string msg;
- switch (injector.Comp.ToggleState)
+ switch (component.ToggleState)
{
case SharedInjectorComponent.InjectorToggleMode.Inject:
- injector.Comp.ToggleState = SharedInjectorComponent.InjectorToggleMode.Draw;
+ component.ToggleState = SharedInjectorComponent.InjectorToggleMode.Draw;
msg = "injector-component-drawing-text";
break;
case SharedInjectorComponent.InjectorToggleMode.Draw:
- injector.Comp.ToggleState = SharedInjectorComponent.InjectorToggleMode.Inject;
+ component.ToggleState = SharedInjectorComponent.InjectorToggleMode.Inject;
msg = "injector-component-injecting-text";
break;
default:
/// <summary>
/// Send informative pop-up messages and wait for a do-after to complete.
/// </summary>
- private void InjectDoAfter(Entity<InjectorComponent> injector, EntityUid target, EntityUid user)
+ private void InjectDoAfter(InjectorComponent component, EntityUid user, EntityUid target, EntityUid injector)
{
// Create a pop-up for the user
_popup.PopupEntity(Loc.GetString("injector-component-injecting-user"), target, user);
- if (!_solutionContainers.TryGetSolution(injector.Owner, InjectorComponent.SolutionName, out _, out var solution))
+ if (!_solutions.TryGetSolution(injector, InjectorComponent.SolutionName, out var solution))
return;
- var actualDelay = MathF.Max(injector.Comp.Delay, 1f);
+ var actualDelay = MathF.Max(component.Delay, 1f);
// Injections take 0.5 seconds longer per additional 5u
- actualDelay += (float) injector.Comp.TransferAmount / injector.Comp.Delay - 0.5f;
+ actualDelay += (float) component.TransferAmount / component.Delay - 0.5f;
var isTarget = user != target;
}
// Add an admin log, using the "force feed" log type. It's not quite feeding, but the effect is the same.
- if (injector.Comp.ToggleState == SharedInjectorComponent.InjectorToggleMode.Inject)
+ if (component.ToggleState == SharedInjectorComponent.InjectorToggleMode.Inject)
{
_adminLogger.Add(LogType.ForceFeed,
$"{EntityManager.ToPrettyString(user):user} is attempting to inject {EntityManager.ToPrettyString(target):target} with a solution {SolutionContainerSystem.ToPrettyString(solution):solution}");
// Self-injections take half as long.
actualDelay /= 2;
- if (injector.Comp.ToggleState == SharedInjectorComponent.InjectorToggleMode.Inject)
+ if (component.ToggleState == SharedInjectorComponent.InjectorToggleMode.Inject)
_adminLogger.Add(LogType.Ingestion, $"{EntityManager.ToPrettyString(user):user} is attempting to inject themselves with a solution {SolutionContainerSystem.ToPrettyString(solution):solution}.");
}
- _doAfter.TryStartDoAfter(new DoAfterArgs(EntityManager, user, actualDelay, new InjectorDoAfterEvent(), injector.Owner, target: target, used: injector.Owner)
+ _doAfter.TryStartDoAfter(new DoAfterArgs(EntityManager, user, actualDelay, new InjectorDoAfterEvent(), injector, target: target, used: injector)
{
BreakOnUserMove = true,
BreakOnDamage = true,
});
}
- private void TryInjectIntoBloodstream(Entity<InjectorComponent> injector, Entity<BloodstreamComponent> target, EntityUid user)
+ private void TryInjectIntoBloodstream(InjectorComponent component, EntityUid injector, EntityUid target, BloodstreamComponent targetBloodstream, EntityUid user)
{
// Get transfer amount. May be smaller than _transferAmount if not enough room
- if (!_solutionContainers.ResolveSolution(target.Owner, target.Comp.ChemicalSolutionName, ref target.Comp.ChemicalSolution, out var chemSolution))
- {
- _popup.PopupEntity(Loc.GetString("injector-component-cannot-inject-message", ("target", Identity.Entity(target, EntityManager))), injector.Owner, user);
- return;
- }
+ var realTransferAmount = FixedPoint2.Min(component.TransferAmount, targetBloodstream.ChemicalSolution.AvailableVolume);
- var realTransferAmount = FixedPoint2.Min(injector.Comp.TransferAmount, chemSolution.AvailableVolume);
if (realTransferAmount <= 0)
{
- _popup.PopupEntity(Loc.GetString("injector-component-cannot-inject-message", ("target", Identity.Entity(target, EntityManager))), injector.Owner, user);
+ _popup.PopupEntity(Loc.GetString("injector-component-cannot-inject-message", ("target", Identity.Entity(target, EntityManager))), injector, user);
return;
}
// Move units from attackSolution to targetSolution
- var removedSolution = _solutionContainers.SplitSolution(target.Comp.ChemicalSolution.Value, realTransferAmount);
+ var removedSolution = _solutions.SplitSolution(user, targetBloodstream.ChemicalSolution, realTransferAmount);
- _blood.TryAddToChemicals(target, removedSolution, target.Comp);
+ _blood.TryAddToChemicals(target, removedSolution, targetBloodstream);
_reactiveSystem.DoEntityReaction(target, removedSolution, ReactionMethod.Injection);
_popup.PopupEntity(Loc.GetString("injector-component-inject-success-message",
("amount", removedSolution.Volume),
- ("target", Identity.Entity(target, EntityManager))), injector.Owner, user);
+ ("target", Identity.Entity(target, EntityManager))), injector, user);
- Dirty(injector);
- AfterInject(injector, target);
+ Dirty(component);
+ AfterInject(component, injector, target);
}
- private void TryInject(Entity<InjectorComponent> injector, EntityUid targetEntity, Entity<SolutionComponent> targetSolution, EntityUid user, bool asRefill)
+ private void TryInject(InjectorComponent component, EntityUid injector, EntityUid targetEntity, Solution targetSolution, EntityUid user, bool asRefill)
{
- if (!_solutionContainers.TryGetSolution(injector.Owner, InjectorComponent.SolutionName, out var soln, out var solution) || solution.Volume == 0)
+ if (!_solutions.TryGetSolution(injector, InjectorComponent.SolutionName, out var solution)
+ || solution.Volume == 0)
return;
// Get transfer amount. May be smaller than _transferAmount if not enough room
- var realTransferAmount = FixedPoint2.Min(injector.Comp.TransferAmount, targetSolution.Comp.Solution.AvailableVolume);
+ var realTransferAmount = FixedPoint2.Min(component.TransferAmount, targetSolution.AvailableVolume);
if (realTransferAmount <= 0)
{
_popup.PopupEntity(Loc.GetString("injector-component-target-already-full-message", ("target", Identity.Entity(targetEntity, EntityManager))),
- injector.Owner, user);
+ injector, user);
return;
}
// Move units from attackSolution to targetSolution
Solution removedSolution;
if (TryComp<StackComponent>(targetEntity, out var stack))
- removedSolution = _solutionContainers.SplitStackSolution(soln.Value, realTransferAmount, stack.Count);
+ removedSolution = _solutions.SplitStackSolution(injector, solution, realTransferAmount, stack.Count);
else
- removedSolution = _solutionContainers.SplitSolution(soln.Value, realTransferAmount);
+ removedSolution = _solutions.SplitSolution(injector, solution, realTransferAmount);
_reactiveSystem.DoEntityReaction(targetEntity, removedSolution, ReactionMethod.Injection);
if (!asRefill)
- _solutionContainers.Inject(targetEntity, targetSolution, removedSolution);
+ _solutions.Inject(targetEntity, targetSolution, removedSolution);
else
- _solutionContainers.Refill(targetEntity, targetSolution, removedSolution);
+ _solutions.Refill(targetEntity, targetSolution, removedSolution);
_popup.PopupEntity(Loc.GetString("injector-component-transfer-success-message",
("amount", removedSolution.Volume),
- ("target", Identity.Entity(targetEntity, EntityManager))), injector.Owner, user);
+ ("target", Identity.Entity(targetEntity, EntityManager))), injector, user);
- Dirty(injector);
- AfterInject(injector, targetEntity);
+ Dirty(component);
+ AfterInject(component, injector, targetEntity);
}
- private void AfterInject(Entity<InjectorComponent> injector, EntityUid target)
+ private void AfterInject(InjectorComponent component, EntityUid injector, EntityUid target)
{
// Automatically set syringe to draw after completely draining it.
- if (_solutionContainers.TryGetSolution(injector.Owner, InjectorComponent.SolutionName, out _, out var solution) && solution.Volume == 0)
+ if (_solutions.TryGetSolution(injector, InjectorComponent.SolutionName, out var solution)
+ && solution.Volume == 0)
{
- injector.Comp.ToggleState = SharedInjectorComponent.InjectorToggleMode.Draw;
+ component.ToggleState = SharedInjectorComponent.InjectorToggleMode.Draw;
}
// Leave some DNA from the injectee on it
RaiseLocalEvent(target, ref ev);
}
- private void AfterDraw(Entity<InjectorComponent> injector, EntityUid target)
+ private void AfterDraw(InjectorComponent component, EntityUid injector, EntityUid target)
{
// Automatically set syringe to inject after completely filling it.
- if (_solutionContainers.TryGetSolution(injector.Owner, InjectorComponent.SolutionName, out _, out var solution) && solution.AvailableVolume == 0)
+ if (_solutions.TryGetSolution(injector, InjectorComponent.SolutionName, out var solution)
+ && solution.AvailableVolume == 0)
{
- injector.Comp.ToggleState = SharedInjectorComponent.InjectorToggleMode.Inject;
+ component.ToggleState = SharedInjectorComponent.InjectorToggleMode.Inject;
}
// Leave some DNA from the drawee on it
RaiseLocalEvent(target, ref ev);
}
- private void TryDraw(Entity<InjectorComponent> injector, Entity<BloodstreamComponent?> target, Entity<SolutionComponent> targetSolution, EntityUid user)
+ private void TryDraw(InjectorComponent component, EntityUid injector, EntityUid targetEntity, Solution targetSolution, EntityUid user, BloodstreamComponent? stream = null)
{
- if (!_solutionContainers.TryGetSolution(injector.Owner, InjectorComponent.SolutionName, out var soln, out var solution) || solution.AvailableVolume == 0)
+ if (!_solutions.TryGetSolution(injector, InjectorComponent.SolutionName, out var solution)
+ || solution.AvailableVolume == 0)
{
return;
}
// Get transfer amount. May be smaller than _transferAmount if not enough room, also make sure there's room in the injector
- var realTransferAmount = FixedPoint2.Min(injector.Comp.TransferAmount, targetSolution.Comp.Solution.Volume, solution.AvailableVolume);
+ var realTransferAmount = FixedPoint2.Min(component.TransferAmount, targetSolution.Volume, solution.AvailableVolume);
if (realTransferAmount <= 0)
{
- _popup.PopupEntity(Loc.GetString("injector-component-target-is-empty-message", ("target", Identity.Entity(target, EntityManager))),
- injector.Owner, user);
+ _popup.PopupEntity(Loc.GetString("injector-component-target-is-empty-message", ("target", Identity.Entity(targetEntity, EntityManager))),
+ injector, user);
return;
}
// We have some snowflaked behavior for streams.
- if (target.Comp != null)
+ if (stream != null)
{
- DrawFromBlood(injector, (target.Owner, target.Comp), soln.Value, realTransferAmount, user);
+ DrawFromBlood(user, injector, targetEntity, component, solution, stream, realTransferAmount);
return;
}
// Move units from attackSolution to targetSolution
- var removedSolution = _solutionContainers.Draw(target.Owner, targetSolution, realTransferAmount);
+ var removedSolution = _solutions.Draw(targetEntity, targetSolution, realTransferAmount);
- if (!_solutionContainers.TryAddSolution(soln.Value, removedSolution))
+ if (!_solutions.TryAddSolution(injector, solution, removedSolution))
{
return;
}
_popup.PopupEntity(Loc.GetString("injector-component-draw-success-message",
("amount", removedSolution.Volume),
- ("target", Identity.Entity(target, EntityManager))), injector.Owner, user);
+ ("target", Identity.Entity(targetEntity, EntityManager))), injector, user);
- Dirty(injector);
- AfterDraw(injector, target);
+ Dirty(component);
+ AfterDraw(component, injector, targetEntity);
}
- private void DrawFromBlood(Entity<InjectorComponent> injector, Entity<BloodstreamComponent> target, Entity<SolutionComponent> injectorSolution, FixedPoint2 transferAmount, EntityUid user)
+ private void DrawFromBlood(EntityUid user, EntityUid injector, EntityUid target, InjectorComponent component, Solution injectorSolution, BloodstreamComponent stream, FixedPoint2 transferAmount)
{
var drawAmount = (float) transferAmount;
-
- if (_solutionContainers.ResolveSolution(target.Owner, target.Comp.ChemicalSolutionName, ref target.Comp.ChemicalSolution))
+ var bloodAmount = drawAmount;
+ var chemAmount = 0f;
+ if (stream.ChemicalSolution.Volume > 0f) // If they have stuff in their chem stream, we'll draw some of that
{
- var chemTemp = _solutionContainers.SplitSolution(target.Comp.ChemicalSolution.Value, drawAmount * 0.15f);
- _solutionContainers.TryAddSolution(injectorSolution, chemTemp);
- drawAmount -= (float) chemTemp.Volume;
+ bloodAmount = drawAmount * 0.85f;
+ chemAmount = drawAmount * 0.15f;
}
- if (_solutionContainers.ResolveSolution(target.Owner, target.Comp.BloodSolutionName, ref target.Comp.BloodSolution))
- {
- var bloodTemp = _solutionContainers.SplitSolution(target.Comp.BloodSolution.Value, drawAmount);
- _solutionContainers.TryAddSolution(injectorSolution, bloodTemp);
- }
+ var bloodTemp = stream.BloodSolution.SplitSolution(bloodAmount);
+ var chemTemp = stream.ChemicalSolution.SplitSolution(chemAmount);
+
+ _solutions.TryAddSolution(injector, injectorSolution, bloodTemp);
+ _solutions.TryAddSolution(injector, injectorSolution, chemTemp);
_popup.PopupEntity(Loc.GetString("injector-component-draw-success-message",
("amount", transferAmount),
- ("target", Identity.Entity(target, EntityManager))), injector.Owner, user);
+ ("target", Identity.Entity(target, EntityManager))), injector, user);
- Dirty(injector);
- AfterDraw(injector, target);
+ Dirty(component);
+ AfterDraw(component, injector, target);
}
+
}
using Content.Server.Administration.Logs;
using Content.Server.Body.Systems;
-using Content.Server.Chemistry.Containers.EntitySystems;
using Content.Server.Interaction;
using Content.Server.Popups;
-using Content.Shared.Chemistry;
using Content.Shared.CombatMode;
+using Content.Shared.Chemistry;
+using Content.Shared.Chemistry.EntitySystems;
using Content.Shared.DoAfter;
using Content.Shared.Mobs.Systems;
+using Robust.Shared.Audio;
using Robust.Shared.Audio.Systems;
namespace Content.Server.Chemistry.EntitySystems;
[Dependency] private readonly SharedAudioSystem _audio = default!;
[Dependency] private readonly MobStateSystem _mobState = default!;
[Dependency] private readonly SharedCombatModeSystem _combat = default!;
- [Dependency] private readonly SolutionContainerSystem _solutionContainers = default!;
+ [Dependency] private readonly SolutionContainerSystem _solutions = default!;
public override void Initialize()
{
+using System.Linq;
+using System.Diagnostics.CodeAnalysis;
using Content.Server.Chemistry.Components;
-using Content.Server.Chemistry.Containers.EntitySystems;
using Content.Shared.Chemistry.Components;
using Content.Shared.Chemistry.Components.SolutionManager;
using Content.Shared.Chemistry.EntitySystems;
using Content.Shared.Chemistry.Reagent;
using Content.Shared.Database;
using Content.Shared.FixedPoint;
-using Content.Shared.Forensics;
using Content.Shared.IdentityManagement;
using Content.Shared.Interaction;
using Content.Shared.Interaction.Events;
using Content.Shared.Mobs.Components;
-using Content.Shared.Timing;
using Content.Shared.Weapons.Melee.Events;
+using Content.Shared.Timing;
using Robust.Shared.GameStates;
-using System.Diagnostics.CodeAnalysis;
-using System.Linq;
+using Content.Shared.Forensics;
namespace Content.Server.Chemistry.EntitySystems
{
{
SubscribeLocalEvent<HyposprayComponent, AfterInteractEvent>(OnAfterInteract);
SubscribeLocalEvent<HyposprayComponent, MeleeHitEvent>(OnAttack);
- SubscribeLocalEvent<HyposprayComponent, SolutionContainerChangedEvent>(OnSolutionChange);
+ SubscribeLocalEvent<HyposprayComponent, SolutionChangedEvent>(OnSolutionChange);
SubscribeLocalEvent<HyposprayComponent, UseInHandEvent>(OnUseInHand);
SubscribeLocalEvent<HyposprayComponent, ComponentGetState>(OnHypoGetState);
}
- private void OnHypoGetState(Entity<HyposprayComponent> entity, ref ComponentGetState args)
+ private void OnHypoGetState(EntityUid uid, HyposprayComponent component, ref ComponentGetState args)
{
- args.State = _solutionContainers.TryGetSolution(entity.Owner, entity.Comp.SolutionName, out _, out var solution)
+ args.State = _solutions.TryGetSolution(uid, component.SolutionName, out var solution)
? new HyposprayComponentState(solution.Volume, solution.MaxVolume)
: new HyposprayComponentState(FixedPoint2.Zero, FixedPoint2.Zero);
}
- private void OnUseInHand(Entity<HyposprayComponent> entity, ref UseInHandEvent args)
+ private void OnUseInHand(EntityUid uid, HyposprayComponent component, UseInHandEvent args)
{
if (args.Handled)
return;
- TryDoInject(entity, args.User, args.User);
+ TryDoInject(uid, args.User, args.User);
args.Handled = true;
}
- private void OnSolutionChange(Entity<HyposprayComponent> entity, ref SolutionContainerChangedEvent args)
+ private void OnSolutionChange(EntityUid uid, HyposprayComponent component, SolutionChangedEvent args)
{
- Dirty(entity);
+ Dirty(component);
}
- public void OnAfterInteract(Entity<HyposprayComponent> entity, ref AfterInteractEvent args)
+ public void OnAfterInteract(EntityUid uid, HyposprayComponent component, AfterInteractEvent args)
{
if (!args.CanReach)
return;
var target = args.Target;
var user = args.User;
- TryDoInject(entity, target, user);
+ TryDoInject(uid, target, user);
}
- public void OnAttack(Entity<HyposprayComponent> entity, ref MeleeHitEvent args)
+ public void OnAttack(EntityUid uid, HyposprayComponent component, MeleeHitEvent args)
{
if (!args.HitEntities.Any())
return;
- TryDoInject(entity, args.HitEntities.First(), args.User);
+ TryDoInject(uid, args.HitEntities.First(), args.User);
}
- public bool TryDoInject(Entity<HyposprayComponent> hypo, EntityUid? target, EntityUid user)
+ public bool TryDoInject(EntityUid uid, EntityUid? target, EntityUid user, HyposprayComponent? component=null)
{
- var (uid, component) = hypo;
+ if (!Resolve(uid, ref component))
+ return false;
if (!EligibleEntity(target, _entMan, component))
return false;
target = user;
}
- if (!_solutionContainers.TryGetSolution(uid, component.SolutionName, out var hypoSpraySoln, out var hypoSpraySolution) || hypoSpraySolution.Volume == 0)
+ _solutions.TryGetSolution(uid, component.SolutionName, out var hypoSpraySolution);
+
+ if (hypoSpraySolution == null || hypoSpraySolution.Volume == 0)
{
_popup.PopupCursor(Loc.GetString("hypospray-component-empty-message"), user);
return true;
}
- if (!_solutionContainers.TryGetInjectableSolution(target.Value, out var targetSoln, out var targetSolution))
+ if (!_solutions.TryGetInjectableSolution(target.Value, out var targetSolution))
{
_popup.PopupCursor(Loc.GetString("hypospray-cant-inject", ("target", Identity.Entity(target.Value, _entMan))), user);
return false;
if (realTransferAmount <= 0)
{
- _popup.PopupCursor(Loc.GetString("hypospray-component-transfer-already-full-message", ("owner", target)), user);
+ _popup.PopupCursor(Loc.GetString("hypospray-component-transfer-already-full-message",("owner", target)), user);
return true;
}
// Move units from attackSolution to targetSolution
- var removedSolution = _solutionContainers.SplitSolution(hypoSpraySoln.Value, realTransferAmount);
+ var removedSolution = _solutions.SplitSolution(uid, hypoSpraySolution, realTransferAmount);
if (!targetSolution.CanAddSolution(removedSolution))
return true;
_reactiveSystem.DoEntityReaction(target.Value, removedSolution, ReactionMethod.Injection);
- _solutionContainers.TryAddSolution(targetSoln.Value, removedSolution);
+ _solutions.TryAddSolution(target.Value, targetSolution, removedSolution);
var ev = new TransferDnaEvent { Donor = target.Value, Recipient = uid };
RaiseLocalEvent(target.Value, ref ev);
+using Content.Server.Xenoarchaeology.XenoArtifacts.Triggers.Components;
+using Content.Shared.Chemistry.Components;
using Content.Shared.Chemistry.Reaction;
using Content.Shared.IdentityManagement;
using Content.Shared.Interaction;
+using Content.Shared.Interaction.Events;
+using Robust.Shared.Player;
namespace Content.Server.Chemistry.EntitySystems;
SubscribeLocalEvent<ReactionMixerComponent, AfterInteractEvent>(OnAfterInteract);
}
- private void OnAfterInteract(Entity<ReactionMixerComponent> entity, ref AfterInteractEvent args)
+ private void OnAfterInteract(EntityUid uid, ReactionMixerComponent component, AfterInteractEvent args)
{
if (!args.Target.HasValue || !args.CanReach)
return;
- var mixAttemptEvent = new MixingAttemptEvent(entity);
- RaiseLocalEvent(entity, ref mixAttemptEvent);
- if (mixAttemptEvent.Cancelled)
+ var mixAttemptEvent = new MixingAttemptEvent(uid);
+ RaiseLocalEvent(uid, ref mixAttemptEvent);
+ if(mixAttemptEvent.Cancelled)
{
return;
}
- if (!_solutionContainers.TryGetMixableSolution(args.Target.Value, out var solution))
- return;
+ Solution? solution = null;
+ if (!_solutions.TryGetMixableSolution(args.Target.Value, out solution))
+ return;
- _popup.PopupEntity(Loc.GetString(entity.Comp.MixMessage, ("mixed", Identity.Entity(args.Target.Value, EntityManager)), ("mixer", Identity.Entity(entity.Owner, EntityManager))), args.User, args.User);
+ _popup.PopupEntity(Loc.GetString(component.MixMessage, ("mixed", Identity.Entity(args.Target.Value, EntityManager)), ("mixer", Identity.Entity(uid, EntityManager))), args.User, args.User);
- _solutionContainers.UpdateChemicals(solution.Value, true, entity.Comp);
+ _solutions.UpdateChemicals(args.Target.Value, solution, true, component);
- var afterMixingEvent = new AfterMixingEvent(entity, args.Target.Value);
- RaiseLocalEvent(entity, afterMixingEvent);
+ var afterMixingEvent = new AfterMixingEvent(uid, args.Target.Value);
+ RaiseLocalEvent(uid, afterMixingEvent);
}
}
using Content.Server.Chemistry.Components.DeleteOnSolutionEmptyComponent;
-using Content.Server.Chemistry.Containers.EntitySystems;
using Content.Shared.Chemistry.Components.SolutionManager;
using Content.Shared.Chemistry.EntitySystems;
{
base.Initialize();
SubscribeLocalEvent<DeleteOnSolutionEmptyComponent, ComponentStartup>(OnStartup);
- SubscribeLocalEvent<DeleteOnSolutionEmptyComponent, SolutionContainerChangedEvent>(OnSolutionChange);
+ SubscribeLocalEvent<DeleteOnSolutionEmptyComponent, SolutionChangedEvent>(OnSolutionChange);
}
- public void OnStartup(Entity<DeleteOnSolutionEmptyComponent> entity, ref ComponentStartup args)
+ public void OnStartup(EntityUid uid, DeleteOnSolutionEmptyComponent component, ComponentStartup args)
{
- CheckSolutions(entity);
+ CheckSolutions(uid, component);
}
- public void OnSolutionChange(Entity<DeleteOnSolutionEmptyComponent> entity, ref SolutionContainerChangedEvent args)
+ public void OnSolutionChange(EntityUid uid, DeleteOnSolutionEmptyComponent component, SolutionChangedEvent args)
{
- CheckSolutions(entity);
+ CheckSolutions(uid, component);
}
- public void CheckSolutions(Entity<DeleteOnSolutionEmptyComponent> entity)
+ public void CheckSolutions(EntityUid uid, DeleteOnSolutionEmptyComponent component)
{
- if (!TryComp(entity, out SolutionContainerManagerComponent? solutions))
+ if (!EntityManager.HasComponent<SolutionContainerManagerComponent>(uid))
return;
- if (_solutionContainerSystem.TryGetSolution((entity.Owner, solutions), entity.Comp.Solution, out _, out var solution))
+ if (_solutionContainerSystem.TryGetSolution(uid, component.Solution, out var solution))
if (solution.Volume <= 0)
- EntityManager.QueueDeleteEntity(entity);
+ EntityManager.QueueDeleteEntity(uid);
}
}
}
+using System.Linq;
using Content.Server.Administration.Logs;
using Content.Server.Chemistry.Components;
-using Content.Server.Chemistry.Containers.EntitySystems;
using Content.Shared.Chemistry;
using Content.Shared.Chemistry.Dispenser;
using Content.Shared.Chemistry.EntitySystems;
using Robust.Shared.Audio;
using Robust.Shared.Containers;
using Robust.Shared.Prototypes;
-using System.Linq;
namespace Content.Server.Chemistry.EntitySystems
{
base.Initialize();
SubscribeLocalEvent<ReagentDispenserComponent, ComponentStartup>(SubscribeUpdateUiState);
- SubscribeLocalEvent<ReagentDispenserComponent, SolutionContainerChangedEvent>(SubscribeUpdateUiState);
+ SubscribeLocalEvent<ReagentDispenserComponent, SolutionChangedEvent>(SubscribeUpdateUiState);
SubscribeLocalEvent<ReagentDispenserComponent, EntInsertedIntoContainerMessage>(SubscribeUpdateUiState);
SubscribeLocalEvent<ReagentDispenserComponent, EntRemovedFromContainerMessage>(SubscribeUpdateUiState);
SubscribeLocalEvent<ReagentDispenserComponent, BoundUIOpenedEvent>(SubscribeUpdateUiState);
if (container is not { Valid: true })
return null;
- if (_solutionContainerSystem.TryGetFitsInDispenser(container.Value, out _, out var solution))
+ if (_solutionContainerSystem.TryGetFitsInDispenser(container.Value, out var solution))
{
return new ContainerInfo(Name(container.Value), solution.Volume, solution.MaxVolume)
{
return;
var outputContainer = _itemSlotsSystem.GetItemOrNull(reagentDispenser, SharedReagentDispenser.OutputSlotName);
- if (outputContainer is not { Valid: true } || !_solutionContainerSystem.TryGetFitsInDispenser(outputContainer.Value, out var solution, out _))
+ if (outputContainer is not {Valid: true} || !_solutionContainerSystem.TryGetFitsInDispenser(outputContainer.Value, out var solution))
return;
- if (_solutionContainerSystem.TryAddReagent(solution.Value, message.ReagentId, (int) reagentDispenser.Comp.DispenseAmount, out var dispensedAmount)
+ if (_solutionContainerSystem.TryAddReagent(outputContainer.Value, solution, message.ReagentId, (int)reagentDispenser.Comp.DispenseAmount, out var dispensedAmount)
&& message.Session.AttachedEntity is not null)
{
_adminLogger.Add(LogType.ChemicalReaction, LogImpact.Medium,
private void OnClearContainerSolutionMessage(Entity<ReagentDispenserComponent> reagentDispenser, ref ReagentDispenserClearContainerSolutionMessage message)
{
var outputContainer = _itemSlotsSystem.GetItemOrNull(reagentDispenser, SharedReagentDispenser.OutputSlotName);
- if (outputContainer is not { Valid: true } || !_solutionContainerSystem.TryGetFitsInDispenser(outputContainer.Value, out var solution, out _))
+ if (outputContainer is not {Valid: true} || !_solutionContainerSystem.TryGetFitsInDispenser(outputContainer.Value, out var solution))
return;
- _solutionContainerSystem.RemoveAllSolution(solution.Value);
+ _solutionContainerSystem.RemoveAllSolution(outputContainer.Value, solution);
UpdateUiState(reagentDispenser);
ClickSound(reagentDispenser);
}
using Content.Server.Chemistry.Components;
-using Content.Server.Chemistry.Containers.EntitySystems;
using Content.Shared.Chemistry.EntitySystems;
using Content.Shared.FixedPoint;
using Content.Shared.Popups;
{
base.Initialize();
- SubscribeLocalEvent<RehydratableComponent, SolutionContainerChangedEvent>(OnSolutionChange);
+ SubscribeLocalEvent<RehydratableComponent, SolutionChangedEvent>(OnSolutionChange);
}
- private void OnSolutionChange(Entity<RehydratableComponent> entity, ref SolutionContainerChangedEvent args)
+ private void OnSolutionChange(EntityUid uid, RehydratableComponent comp, SolutionChangedEvent args)
{
- var quantity = _solutions.GetTotalPrototypeQuantity(entity, entity.Comp.CatalystPrototype);
- if (quantity != FixedPoint2.Zero && quantity >= entity.Comp.CatalystMinimum)
+ var quantity = _solutions.GetTotalPrototypeQuantity(uid, comp.CatalystPrototype);
+ if (quantity != FixedPoint2.Zero && quantity >= comp.CatalystMinimum)
{
- Expand(entity);
+ Expand(uid, comp);
}
}
// Try not to make this public if you can help it.
- private void Expand(Entity<RehydratableComponent> entity)
+ private void Expand(EntityUid uid, RehydratableComponent comp)
{
- var (uid, comp) = entity;
-
_popups.PopupEntity(Loc.GetString("rehydratable-component-expands-message", ("owner", uid)), uid);
var randomMob = _random.Pick(comp.PossibleSpawns);
using Content.Server.Chemistry.Components;
-using Content.Server.Chemistry.Containers.EntitySystems;
using Content.Server.Construction;
using Content.Server.Power.Components;
using Content.Server.Power.EntitySystems;
using Content.Shared.Chemistry;
using Content.Shared.Chemistry.Components.SolutionManager;
+using Content.Shared.Chemistry.EntitySystems;
using Content.Shared.Placeable;
namespace Content.Server.Chemistry.EntitySystems;
{
[Dependency] private readonly PowerReceiverSystem _powerReceiver = default!;
[Dependency] private readonly SharedAppearanceSystem _appearance = default!;
- [Dependency] private readonly SolutionContainerSystem _solutionContainer = default!;
+ [Dependency] private readonly SolutionContainerSystem _solution = default!;
/// <inheritdoc/>
public override void Initialize()
RemComp<ActiveSolutionHeaterComponent>(uid);
}
- private void OnPowerChanged(Entity<SolutionHeaterComponent> entity, ref PowerChangedEvent args)
+ private void OnPowerChanged(EntityUid uid, SolutionHeaterComponent component, ref PowerChangedEvent args)
{
- var placer = Comp<ItemPlacerComponent>(entity);
+ var placer = Comp<ItemPlacerComponent>(uid);
if (args.Powered && placer.PlacedEntities.Count > 0)
{
- TurnOn(entity);
+ TurnOn(uid);
}
else
{
- TurnOff(entity);
+ TurnOff(uid);
}
}
- private void OnRefreshParts(Entity<SolutionHeaterComponent> entity, ref RefreshPartsEvent args)
+ private void OnRefreshParts(EntityUid uid, SolutionHeaterComponent component, RefreshPartsEvent args)
{
- var heatRating = args.PartRatings[entity.Comp.MachinePartHeatMultiplier] - 1;
+ var heatRating = args.PartRatings[component.MachinePartHeatMultiplier] - 1;
- entity.Comp.HeatPerSecond = entity.Comp.BaseHeatPerSecond * MathF.Pow(entity.Comp.PartRatingHeatMultiplier, heatRating);
+ component.HeatPerSecond = component.BaseHeatPerSecond * MathF.Pow(component.PartRatingHeatMultiplier, heatRating);
}
- private void OnUpgradeExamine(Entity<SolutionHeaterComponent> entity, ref UpgradeExamineEvent args)
+ private void OnUpgradeExamine(EntityUid uid, SolutionHeaterComponent component, UpgradeExamineEvent args)
{
- args.AddPercentageUpgrade("solution-heater-upgrade-heat", entity.Comp.HeatPerSecond / entity.Comp.BaseHeatPerSecond);
+ args.AddPercentageUpgrade("solution-heater-upgrade-heat", component.HeatPerSecond / component.BaseHeatPerSecond);
}
- private void OnItemPlaced(Entity<SolutionHeaterComponent> entity, ref ItemPlacedEvent args)
+ private void OnItemPlaced(EntityUid uid, SolutionHeaterComponent comp, ref ItemPlacedEvent args)
{
- TryTurnOn(entity);
+ TryTurnOn(uid);
}
- private void OnItemRemoved(Entity<SolutionHeaterComponent> entity, ref ItemRemovedEvent args)
+ private void OnItemRemoved(EntityUid uid, SolutionHeaterComponent component, ref ItemRemovedEvent args)
{
- var placer = Comp<ItemPlacerComponent>(entity);
+ var placer = Comp<ItemPlacerComponent>(uid);
if (placer.PlacedEntities.Count == 0) // Last entity was removed
- TurnOff(entity);
+ TurnOff(uid);
}
public override void Update(float frameTime)
{
foreach (var heatingEntity in placer.PlacedEntities)
{
- if (!TryComp<SolutionContainerManagerComponent>(heatingEntity, out var container))
+ if (!TryComp<SolutionContainerManagerComponent>(heatingEntity, out var solution))
continue;
var energy = heater.HeatPerSecond * frameTime;
- foreach (var (_, soln) in _solutionContainer.EnumerateSolutions((heatingEntity, container)))
+ foreach (var s in solution.Solutions.Values)
{
- _solutionContainer.AddThermalEnergy(soln, energy);
+ _solution.AddThermalEnergy(heatingEntity, s, energy);
}
}
}
using Content.Server.Body.Components;
using Content.Server.Body.Systems;
using Content.Server.Chemistry.Components;
-using Content.Server.Chemistry.Containers.EntitySystems;
+using Content.Shared.Chemistry.EntitySystems;
using Content.Shared.Inventory;
using JetBrains.Annotations;
using Robust.Shared.Physics.Events;
+using Robust.Shared.Prototypes;
namespace Content.Server.Chemistry.EntitySystems
{
[UsedImplicitly]
internal sealed class SolutionInjectOnCollideSystem : EntitySystem
{
- [Dependency] private readonly SolutionContainerSystem _solutionContainersSystem = default!;
+ [Dependency] private readonly IPrototypeManager _protoManager = default!;
+ [Dependency] private readonly SolutionContainerSystem _solutionsSystem = default!;
[Dependency] private readonly BloodstreamSystem _bloodstreamSystem = default!;
[Dependency] private readonly InventorySystem _inventorySystem = default!;
if (!args.OtherBody.Hard ||
!EntityManager.TryGetComponent<BloodstreamComponent>(target, out var bloodstream) ||
- !_solutionContainersSystem.TryGetInjectableSolution(ent.Owner, out var solution, out _))
+ !_solutionsSystem.TryGetInjectableSolution(ent, out var solution))
{
return;
}
return;
}
- var solRemoved = _solutionContainersSystem.SplitSolution(solution.Value, component.TransferAmount);
+ var solRemoved = solution.SplitSolution(component.TransferAmount);
var solRemovedVol = solRemoved.Volume;
var solToInject = solRemoved.SplitSolution(solRemovedVol * component.TransferEfficiency);
using Content.Server.Chemistry.Components;
-using Content.Server.Chemistry.Containers.EntitySystems;
using Content.Shared.Chemistry.Components.SolutionManager;
+using Content.Shared.Chemistry.EntitySystems;
+using Content.Shared.FixedPoint;
using Robust.Shared.Timing;
namespace Content.Server.Chemistry.EntitySystems;
// timer ignores if it's empty, it's just a fixed cycle
purge.NextPurgeTime += purge.Duration;
- if (_solutionContainer.TryGetSolution((uid, manager), purge.Solution, out var solution))
- _solutionContainer.SplitSolutionWithout(solution.Value, purge.Quantity, purge.Preserve.ToArray());
+ if (_solutionContainer.TryGetSolution(uid, purge.Solution, out var solution, manager))
+ _solutionContainer.SplitSolutionWithout(uid, solution, purge.Quantity, purge.Preserve.ToArray());
}
}
- private void OnUnpaused(Entity<SolutionPurgeComponent> entity, ref EntityUnpausedEvent args)
+ private void OnUnpaused(EntityUid uid, SolutionPurgeComponent comp, ref EntityUnpausedEvent args)
{
- entity.Comp.NextPurgeTime += args.PausedTime;
+ comp.NextPurgeTime += args.PausedTime;
}
}
using Content.Server.Chemistry.Components;
-using Content.Server.Chemistry.Containers.EntitySystems;
+using Content.Shared.Chemistry.EntitySystems;
using Content.Shared.Chemistry.Reagent;
using Content.Shared.Random;
using Content.Shared.Random.Helpers;
SubscribeLocalEvent<RandomFillSolutionComponent, MapInitEvent>(OnRandomSolutionFillMapInit);
}
- private void OnRandomSolutionFillMapInit(Entity<RandomFillSolutionComponent> entity, ref MapInitEvent args)
+ private void OnRandomSolutionFillMapInit(EntityUid uid, RandomFillSolutionComponent component, MapInitEvent args)
{
- if (entity.Comp.WeightedRandomId == null)
+ if (component.WeightedRandomId == null)
return;
- var pick = _proto.Index<WeightedRandomFillSolutionPrototype>(entity.Comp.WeightedRandomId).Pick(_random);
+ var target = _solutionsSystem.EnsureSolution(uid, component.Solution);
+ var pick = _proto.Index<WeightedRandomFillSolutionPrototype>(component.WeightedRandomId).Pick(_random);
var reagent = pick.reagent;
var quantity = pick.quantity;
return;
}
- var target = _solutionsSystem.EnsureSolutionEntity(entity.Owner, entity.Comp.Solution, pick.quantity, null, out _);
- _solutionsSystem.TryAddReagent(target, reagent, quantity, out _);
+ target.AddReagent(reagent, quantity);
}
}
using Content.Server.Chemistry.Components;
-using Content.Server.Chemistry.Containers.EntitySystems;
using Content.Shared.Chemistry.Components;
using Content.Shared.Chemistry.Components.SolutionManager;
+using Content.Shared.Chemistry.EntitySystems;
using Content.Shared.FixedPoint;
using Robust.Shared.Timing;
// timer ignores if its full, it's just a fixed cycle
regen.NextRegenTime = _timing.CurTime + regen.Duration;
- if (_solutionContainer.ResolveSolution((uid, manager), regen.SolutionName, ref regen.Solution, out var solution))
+ if (_solutionContainer.TryGetSolution(uid, regen.Solution, out var solution, manager))
{
var amount = FixedPoint2.Min(solution.AvailableVolume, regen.Generated.Volume);
if (amount <= FixedPoint2.Zero)
generated = regen.Generated.Clone().SplitSolution(amount);
}
- _solutionContainer.TryAddSolution(regen.Solution.Value, generated);
+ _solutionContainer.TryAddSolution(uid, solution, generated);
}
}
}
- private void OnUnpaused(Entity<SolutionRegenerationComponent> entity, ref EntityUnpausedEvent args)
+ private void OnUnpaused(EntityUid uid, SolutionRegenerationComponent comp, ref EntityUnpausedEvent args)
{
- entity.Comp.NextRegenTime += args.PausedTime;
+ comp.NextRegenTime += args.PausedTime;
}
}
using Content.Server.Chemistry.Components;
-using Content.Server.Chemistry.Containers.EntitySystems;
using Content.Server.Explosion.EntitySystems;
using Content.Server.Popups;
using Content.Shared.Chemistry.Components;
using Content.Shared.Chemistry.Components.SolutionManager;
+using Content.Shared.Chemistry.EntitySystems;
+using Content.Shared.FixedPoint;
using Content.Shared.Interaction;
+using Robust.Shared.Player;
namespace Content.Server.Chemistry.EntitySystems;
/// </summary>
public sealed class SolutionSpikableSystem : EntitySystem
{
- [Dependency] private readonly SolutionContainerSystem _solutionContainerSystem = default!;
+ [Dependency] private readonly SolutionContainerSystem _solutionSystem = default!;
[Dependency] private readonly TriggerSystem _triggerSystem = default!;
[Dependency] private readonly PopupSystem _popupSystem = default!;
SubscribeLocalEvent<RefillableSolutionComponent, InteractUsingEvent>(OnInteractUsing);
}
- private void OnInteractUsing(Entity<RefillableSolutionComponent> entity, ref InteractUsingEvent args)
+ private void OnInteractUsing(EntityUid uid, RefillableSolutionComponent target, InteractUsingEvent args)
{
- TrySpike(args.Used, args.Target, args.User, entity.Comp);
+ TrySpike(args.Used, args.Target, args.User, target);
}
/// <summary>
{
if (!Resolve(source, ref spikableSource, ref managerSource, false)
|| !Resolve(target, ref spikableTarget, ref managerTarget, false)
- || !_solutionContainerSystem.TryGetRefillableSolution((target, spikableTarget, managerTarget), out var targetSoln, out var targetSolution)
- || !_solutionContainerSystem.TryGetSolution((source, managerSource), spikableSource.SourceSolution, out _, out var sourceSolution))
+ || !_solutionSystem.TryGetRefillableSolution(target, out var targetSolution, managerTarget, spikableTarget)
+ || !managerSource.Solutions.TryGetValue(spikableSource.SourceSolution, out var sourceSolution))
{
return;
}
return;
}
- if (!_solutionContainerSystem.ForceAddSolution(targetSoln.Value, sourceSolution))
+ if (!_solutionSystem.ForceAddSolution(target, targetSolution, sourceSolution))
return;
_popupSystem.PopupEntity(Loc.GetString(spikableSource.Popup, ("spiked-entity", target), ("spike-entity", source)), user, user);
using Content.Server.Administration.Logs;
-using Content.Server.Chemistry.Containers.EntitySystems;
+using Content.Shared.Verbs;
+using JetBrains.Annotations;
+using Robust.Server.GameObjects;
using Content.Shared.Chemistry;
using Content.Shared.Chemistry.Components;
+using Content.Shared.Chemistry.EntitySystems;
using Content.Shared.Database;
using Content.Shared.FixedPoint;
using Content.Shared.Interaction;
using Content.Shared.Popups;
-using Content.Shared.Verbs;
-using JetBrains.Annotations;
-using Robust.Server.GameObjects;
using Robust.Shared.Player;
namespace Content.Server.Chemistry.EntitySystems
/// <summary>
/// Default transfer amounts for the set-transfer verb.
/// </summary>
- public static readonly List<int> DefaultTransferAmounts = new() { 1, 5, 10, 25, 50, 100, 250, 500, 1000 };
+ public static readonly List<int> DefaultTransferAmounts = new() { 1, 5, 10, 25, 50, 100, 250, 500, 1000};
public override void Initialize()
{
SubscribeLocalEvent<SolutionTransferComponent, TransferAmountSetValueMessage>(OnTransferAmountSetValueMessage);
}
- private void OnTransferAmountSetValueMessage(Entity<SolutionTransferComponent> entity, ref TransferAmountSetValueMessage message)
+ private void OnTransferAmountSetValueMessage(EntityUid uid, SolutionTransferComponent solutionTransfer, TransferAmountSetValueMessage message)
{
- var newTransferAmount = FixedPoint2.Clamp(message.Value, entity.Comp.MinimumTransferAmount, entity.Comp.MaximumTransferAmount);
- entity.Comp.TransferAmount = newTransferAmount;
+ var newTransferAmount = FixedPoint2.Clamp(message.Value, solutionTransfer.MinimumTransferAmount, solutionTransfer.MaximumTransferAmount);
+ solutionTransfer.TransferAmount = newTransferAmount;
- if (message.Session.AttachedEntity is { Valid: true } user)
- _popupSystem.PopupEntity(Loc.GetString("comp-solution-transfer-set-amount", ("amount", newTransferAmount)), entity.Owner, user);
+ if (message.Session.AttachedEntity is {Valid: true} user)
+ _popupSystem.PopupEntity(Loc.GetString("comp-solution-transfer-set-amount", ("amount", newTransferAmount)), uid, user);
}
- private void AddSetTransferVerbs(Entity<SolutionTransferComponent> entity, ref GetVerbsEvent<AlternativeVerb> args)
+ private void AddSetTransferVerbs(EntityUid uid, SolutionTransferComponent component, GetVerbsEvent<AlternativeVerb> args)
{
- var (uid, component) = entity;
-
if (!args.CanAccess || !args.CanInteract || !component.CanChangeTransferAmount || args.Hands == null)
return;
AlternativeVerb custom = new();
custom.Text = Loc.GetString("comp-solution-transfer-verb-custom-amount");
custom.Category = VerbCategory.SetTransferAmount;
- custom.Act = () => _userInterfaceSystem.TryOpen(uid, TransferAmountUiKey.Key, actor.PlayerSession);
+ custom.Act = () => _userInterfaceSystem.TryOpen(args.Target, TransferAmountUiKey.Key, actor.PlayerSession);
custom.Priority = 1;
args.Verbs.Add(custom);
// Add specific transfer verbs according to the container's size
var priority = 0;
- var user = args.User;
foreach (var amount in DefaultTransferAmounts)
{
- if (amount < component.MinimumTransferAmount.Int() || amount > component.MaximumTransferAmount.Int())
+ if ( amount < component.MinimumTransferAmount.Int() || amount > component.MaximumTransferAmount.Int())
continue;
AlternativeVerb verb = new();
verb.Act = () =>
{
component.TransferAmount = FixedPoint2.New(amount);
- _popupSystem.PopupEntity(Loc.GetString("comp-solution-transfer-set-amount", ("amount", amount)), uid, user);
+ _popupSystem.PopupEntity(Loc.GetString("comp-solution-transfer-set-amount", ("amount", amount)), uid, args.User);
};
// we want to sort by size, not alphabetically by the verb text.
}
}
- private void OnAfterInteract(Entity<SolutionTransferComponent> entity, ref AfterInteractEvent args)
+ private void OnAfterInteract(EntityUid uid, SolutionTransferComponent component, AfterInteractEvent args)
{
if (!args.CanReach || args.Target == null)
return;
var target = args.Target!.Value;
- var (uid, component) = entity;
//Special case for reagent tanks, because normally clicking another container will give solution, not take it.
- if (component.CanReceive && !EntityManager.HasComponent<RefillableSolutionComponent>(target) // target must not be refillable (e.g. Reagent Tanks)
- && _solutionContainerSystem.TryGetDrainableSolution(target, out var targetSoln, out _) // target must be drainable
- && EntityManager.TryGetComponent(uid, out RefillableSolutionComponent? refillComp)
- && _solutionContainerSystem.TryGetRefillableSolution((uid, refillComp, null), out var ownerSoln, out var ownerRefill))
+ if (component.CanReceive && !EntityManager.HasComponent<RefillableSolutionComponent>(target) // target must not be refillable (e.g. Reagent Tanks)
+ && _solutionContainerSystem.TryGetDrainableSolution(target, out var targetDrain) // target must be drainable
+ && EntityManager.TryGetComponent(uid, out RefillableSolutionComponent? refillComp)
+ && _solutionContainerSystem.TryGetRefillableSolution(uid, out var ownerRefill, refillable: refillComp))
{
transferAmount = FixedPoint2.Min(transferAmount, (FixedPoint2) refill.MaxRefill); // if the receiver has a smaller transfer limit, use that instead
}
- var transferred = Transfer(args.User, target, targetSoln.Value, uid, ownerSoln.Value, transferAmount);
+ var transferred = Transfer(args.User, target, targetDrain, uid, ownerRefill, transferAmount);
if (transferred > 0)
{
var toTheBrim = ownerRefill.AvailableVolume == 0;
}
// if target is refillable, and owner is drainable
- if (component.CanSend && _solutionContainerSystem.TryGetRefillableSolution(target, out targetSoln, out var targetRefill)
- && _solutionContainerSystem.TryGetDrainableSolution(uid, out ownerSoln, out var ownerDrain))
+ if (component.CanSend && _solutionContainerSystem.TryGetRefillableSolution(target, out var targetRefill)
+ && _solutionContainerSystem.TryGetDrainableSolution(uid, out var ownerDrain))
{
var transferAmount = component.TransferAmount;
transferAmount = FixedPoint2.Min(transferAmount, (FixedPoint2) refill.MaxRefill);
}
- var transferred = Transfer(args.User, uid, ownerSoln.Value, target, targetSoln.Value, transferAmount);
+ var transferred = Transfer(args.User, uid, ownerDrain, target, targetRefill, transferAmount);
if (transferred > 0)
{
/// <returns>The actual amount transferred.</returns>
public FixedPoint2 Transfer(EntityUid user,
EntityUid sourceEntity,
- Entity<SolutionComponent> source,
+ Solution source,
EntityUid targetEntity,
- Entity<SolutionComponent> target,
+ Solution target,
FixedPoint2 amount)
{
var transferAttempt = new SolutionTransferAttemptEvent(sourceEntity, targetEntity);
return FixedPoint2.Zero;
}
- var sourceSolution = source.Comp.Solution;
- if (sourceSolution.Volume == 0)
+ if (source.Volume == 0)
{
_popupSystem.PopupEntity(Loc.GetString("comp-solution-transfer-is-empty", ("target", sourceEntity)), sourceEntity, user);
return FixedPoint2.Zero;
return FixedPoint2.Zero;
}
- var targetSolution = target.Comp.Solution;
- if (targetSolution.AvailableVolume == 0)
+ if (target.AvailableVolume == 0)
{
_popupSystem.PopupEntity(Loc.GetString("comp-solution-transfer-is-full", ("target", targetEntity)), targetEntity, user);
return FixedPoint2.Zero;
}
- var actualAmount = FixedPoint2.Min(amount, FixedPoint2.Min(sourceSolution.Volume, targetSolution.AvailableVolume));
+ var actualAmount = FixedPoint2.Min(amount, FixedPoint2.Min(source.Volume, target.AvailableVolume));
var solution = _solutionContainerSystem.Drain(sourceEntity, source, actualAmount);
_solutionContainerSystem.Refill(targetEntity, target, solution);
_adminLogger.Add(LogType.Action, LogImpact.Medium,
- $"{EntityManager.ToPrettyString(user):player} transferred {string.Join(", ", solution.Contents)} to {EntityManager.ToPrettyString(targetEntity):entity}, which now contains {SolutionContainerSystem.ToPrettyString(targetSolution)}");
+ $"{EntityManager.ToPrettyString(user):player} transferred {string.Join(", ", solution.Contents)} to {EntityManager.ToPrettyString(targetEntity):entity}, which now contains {string.Join(", ", target.Contents)}");
return actualAmount;
}
using Content.Server.Chemistry.Components;
-using Content.Server.Chemistry.Containers.EntitySystems;
using Content.Shared.Chemistry.EntitySystems;
using Content.Shared.Chemistry.Reagent;
using Robust.Shared.Prototypes;
base.Initialize();
SubscribeLocalEvent<TransformableContainerComponent, MapInitEvent>(OnMapInit);
- SubscribeLocalEvent<TransformableContainerComponent, SolutionContainerChangedEvent>(OnSolutionChange);
+ SubscribeLocalEvent<TransformableContainerComponent, SolutionChangedEvent>(OnSolutionChange);
}
- private void OnMapInit(Entity<TransformableContainerComponent> entity, ref MapInitEvent args)
+ private void OnMapInit(EntityUid uid, TransformableContainerComponent component, MapInitEvent args)
{
- var meta = MetaData(entity.Owner);
- if (string.IsNullOrEmpty(entity.Comp.InitialName))
+ var meta = MetaData(uid);
+ if (string.IsNullOrEmpty(component.InitialName))
{
- entity.Comp.InitialName = meta.EntityName;
+ component.InitialName = meta.EntityName;
}
- if (string.IsNullOrEmpty(entity.Comp.InitialDescription))
+ if (string.IsNullOrEmpty(component.InitialDescription))
{
- entity.Comp.InitialDescription = meta.EntityDescription;
+ component.InitialDescription = meta.EntityDescription;
}
}
- private void OnSolutionChange(Entity<TransformableContainerComponent> entity, ref SolutionContainerChangedEvent args)
+ private void OnSolutionChange(EntityUid owner, TransformableContainerComponent component,
+ SolutionChangedEvent args)
{
- if (!_solutionsSystem.TryGetFitsInDispenser(entity.Owner, out _, out var solution))
+ if (!_solutionsSystem.TryGetFitsInDispenser(owner, out var solution))
return;
-
//Transform container into initial state when emptied
- if (entity.Comp.CurrentReagent != null && solution.Contents.Count == 0)
+ if (component.CurrentReagent != null && solution.Contents.Count == 0)
{
- CancelTransformation(entity);
+ CancelTransformation(owner, component);
}
//the biggest reagent in the solution decides the appearance
var reagentId = solution.GetPrimaryReagentId();
//If biggest reagent didn't changed - don't change anything at all
- if (entity.Comp.CurrentReagent != null && entity.Comp.CurrentReagent.ID == reagentId?.Prototype)
+ if (component.CurrentReagent != null && component.CurrentReagent.ID == reagentId?.Prototype)
{
return;
}
if (!string.IsNullOrWhiteSpace(reagentId?.Prototype)
&& _prototypeManager.TryIndex(reagentId.Value.Prototype, out ReagentPrototype? proto))
{
- var metadata = MetaData(entity.Owner);
+ var metadata = MetaData(owner);
var val = Loc.GetString("transformable-container-component-glass", ("name", proto.LocalizedName));
- _metadataSystem.SetEntityName(entity.Owner, val, metadata);
- _metadataSystem.SetEntityDescription(entity.Owner, proto.LocalizedDescription, metadata);
- entity.Comp.CurrentReagent = proto;
- entity.Comp.Transformed = true;
+ _metadataSystem.SetEntityName(owner, val, metadata);
+ _metadataSystem.SetEntityDescription(owner, proto.LocalizedDescription, metadata);
+ component.CurrentReagent = proto;
+ component.Transformed = true;
}
}
- private void CancelTransformation(Entity<TransformableContainerComponent> entity)
+ private void CancelTransformation(EntityUid owner, TransformableContainerComponent component)
{
- entity.Comp.CurrentReagent = null;
- entity.Comp.Transformed = false;
+ component.CurrentReagent = null;
+ component.Transformed = false;
- var metadata = MetaData(entity);
+ var metadata = MetaData(owner);
- if (!string.IsNullOrEmpty(entity.Comp.InitialName))
+ if (!string.IsNullOrEmpty(component.InitialName))
{
- _metadataSystem.SetEntityName(entity.Owner, entity.Comp.InitialName, metadata);
+ _metadataSystem.SetEntityName(owner, component.InitialName, metadata);
}
- if (!string.IsNullOrEmpty(entity.Comp.InitialDescription))
+ if (!string.IsNullOrEmpty(component.InitialDescription))
{
- _metadataSystem.SetEntityDescription(entity.Owner, entity.Comp.InitialDescription, metadata);
+ _metadataSystem.SetEntityDescription(owner, component.InitialDescription, metadata);
}
}
}
+using System.Numerics;
using Content.Server.Chemistry.Components;
-using Content.Server.Chemistry.Containers.EntitySystems;
using Content.Shared.Chemistry;
using Content.Shared.Chemistry.Components;
using Content.Shared.Chemistry.Components.SolutionManager;
+using Content.Shared.Chemistry.EntitySystems;
using Content.Shared.Chemistry.Reagent;
using Content.Shared.FixedPoint;
using Content.Shared.Physics;
using Robust.Shared.Physics.Systems;
using Robust.Shared.Prototypes;
using Robust.Shared.Spawners;
-using System.Numerics;
namespace Content.Server.Chemistry.EntitySystems
{
SubscribeLocalEvent<VaporComponent, StartCollideEvent>(HandleCollide);
}
- private void HandleCollide(Entity<VaporComponent> entity, ref StartCollideEvent args)
+ private void HandleCollide(EntityUid uid, VaporComponent component, ref StartCollideEvent args)
{
- if (!EntityManager.TryGetComponent(entity.Owner, out SolutionContainerManagerComponent? contents)) return;
+ if (!EntityManager.TryGetComponent(uid, out SolutionContainerManagerComponent? contents)) return;
- foreach (var (_, soln) in _solutionContainerSystem.EnumerateSolutions((entity.Owner, contents)))
+ foreach (var value in contents.Solutions.Values)
{
- var solution = soln.Comp.Solution;
- _reactive.DoEntityReaction(args.OtherEntity, solution, ReactionMethod.Touch);
+ _reactive.DoEntityReaction(args.OtherEntity, value, ReactionMethod.Touch);
}
// Check for collision with a impassable object (e.g. wall) and stop
if ((args.OtherFixture.CollisionLayer & (int) CollisionGroup.Impassable) != 0 && args.OtherFixture.Hard)
{
- EntityManager.QueueDeleteEntity(entity);
+ EntityManager.QueueDeleteEntity(uid);
}
}
return false;
}
- if (!_solutionContainerSystem.TryGetSolution(vapor.Owner, VaporComponent.SolutionName, out var vaporSolution))
+ if (!_solutionContainerSystem.TryGetSolution(vapor, VaporComponent.SolutionName,
+ out var vaporSolution))
{
return false;
}
- return _solutionContainerSystem.TryAddSolution(vaporSolution.Value, solution);
+ return _solutionContainerSystem.TryAddSolution(vapor, vaporSolution, solution);
}
public override void Update(float frameTime)
{
var query = EntityQueryEnumerator<VaporComponent, SolutionContainerManagerComponent, TransformComponent>();
- while (query.MoveNext(out var uid, out var vaporComp, out var container, out var xform))
+ while (query.MoveNext(out var uid, out var vaporComp, out var solution, out var xform))
{
- foreach (var (_, soln) in _solutionContainerSystem.EnumerateSolutions((uid, container)))
+ foreach (var (_, value) in solution.Solutions)
{
- Update(frameTime, (uid, vaporComp), soln, xform);
+ Update(frameTime, (uid, vaporComp), value, xform);
}
}
}
- private void Update(float frameTime, Entity<VaporComponent> ent, Entity<SolutionComponent> soln, TransformComponent xform)
+ private void Update(float frameTime, Entity<VaporComponent> ent, Solution contents, TransformComponent xform)
{
var (entity, vapor) = ent;
if (!vapor.Active)
vapor.ReactTimer += frameTime;
- var contents = soln.Comp.Solution;
if (vapor.ReactTimer >= ReactTime && TryComp(xform.GridUid, out MapGridComponent? gridComp))
{
vapor.ReactTimer = 0;
reaction = reagentQuantity.Quantity;
}
- _solutionContainerSystem.RemoveReagent(soln, reagentQuantity.Reagent, reaction);
+ _solutionContainerSystem.RemoveReagent(entity, contents, reagentQuantity.Reagent, reaction);
}
}
using Content.Server.Fluids.EntitySystems;
using Content.Shared.Audio;
+using Content.Shared.Chemistry.EntitySystems;
using Content.Shared.Chemistry.Reagent;
using Content.Shared.Coordinates.Helpers;
using Content.Shared.Database;
/// <summary>
/// How many units of reaction for 1 smoke entity.
/// </summary>
- [DataField] public FixedPoint2 OverflowThreshold = FixedPoint2.New(2.5);
+ [DataField("overflowThreshold")] public FixedPoint2 OverflowThreshold = FixedPoint2.New(2.5);
/// <summary>
/// The entity prototype that will be spawned as the effect.
return;
var spreadAmount = (int) Math.Max(0, Math.Ceiling((args.Quantity / OverflowThreshold).Float()));
- var splitSolution = args.Source.SplitSolution(args.Source.Volume);
+ var splitSolution = args.EntityManager.System<SolutionContainerSystem>().SplitSolution(args.SolutionEntity, args.Source, args.Source.Volume);
var transform = args.EntityManager.GetComponent<TransformComponent>(args.SolutionEntity);
var mapManager = IoCManager.Resolve<IMapManager>();
/// <summary>
/// What entity to create.
/// </summary>
- [DataField(required: true, customTypeSerializer: typeof(PrototypeIdSerializer<EntityPrototype>))]
+ [DataField("entity", required: true, customTypeSerializer: typeof(PrototypeIdSerializer<EntityPrototype>))]
public string Entity = default!;
/// <summary>
/// How many entities to create per unit reaction.
/// </summary>
- [DataField]
+ [DataField("number")]
public uint Number = 1;
protected override string? ReagentEffectGuidebookText(IPrototypeManager prototype, IEntitySystemManager entSys)
/// <summary>
/// How much energy will be drain from sources
/// </summary>
- [DataField]
+ [DataField("energyConsumption")]
public float EnergyConsumption = 12500;
/// <summary>
+using System.Text.Json.Serialization;
using Content.Server.Explosion.EntitySystems;
using Content.Shared.Chemistry.Reagent;
using Content.Shared.Database;
using Content.Shared.Explosion;
using Robust.Shared.Prototypes;
using Robust.Shared.Serialization.TypeSerializers.Implementations.Custom.Prototype;
-using System.Text.Json.Serialization;
namespace Content.Server.Chemistry.ReactionEffects
{
/// <summary>
/// The type of explosion. Determines damage types and tile break chance scaling.
/// </summary>
- [DataField(required: true, customTypeSerializer: typeof(PrototypeIdSerializer<ExplosionPrototype>))]
+ [DataField("explosionType", required: true, customTypeSerializer: typeof(PrototypeIdSerializer<ExplosionPrototype>))]
[JsonIgnore]
public string ExplosionType = default!;
/// The max intensity the explosion can have at a given tile. Places an upper limit of damage and tile break
/// chance.
/// </summary>
- [DataField]
+ [DataField("maxIntensity")]
[JsonIgnore]
public float MaxIntensity = 5;
/// <summary>
/// How quickly intensity drops off as you move away from the epicenter
/// </summary>
- [DataField]
+ [DataField("intensitySlope")]
[JsonIgnore]
public float IntensitySlope = 1;
/// <remarks>
/// A slope of 1 and MaxTotalIntensity of 100 corresponds to a radius of around 4.5 tiles.
/// </remarks>
- [DataField]
+ [DataField("maxTotalIntensity")]
[JsonIgnore]
public float MaxTotalIntensity = 100;
/// <summary>
/// The intensity of the explosion per unit reaction.
/// </summary>
- [DataField]
+ [DataField("intensityPerUnit")]
[JsonIgnore]
public float IntensityPerUnit = 1;
--- /dev/null
+
\ No newline at end of file
+using Content.Shared.Chemistry.Components;
using Content.Shared.Chemistry.Reagent;
using Robust.Shared.Prototypes;
+using static Robust.Shared.Physics.DynamicTree;
namespace Content.Server.Chemistry.ReactionEffects
{
}
}
+
+
/// </summary>
public sealed partial class Temperature : ReagentEffectCondition
{
- [DataField]
+ [DataField("min")]
public float Min = 0;
- [DataField]
+ [DataField("max")]
public float Max = float.PositiveInfinity;
public override bool Condition(ReagentEffectArgs args)
{
[UsedImplicitly]
public sealed partial class HasTag : ReagentEffectCondition
{
- [DataField(customTypeSerializer: typeof(PrototypeIdSerializer<TagPrototype>))]
+ [DataField("tag", customTypeSerializer: typeof(PrototypeIdSerializer<TagPrototype>))]
public string Tag = default!;
- [DataField]
+ [DataField("invert")]
public bool Invert = false;
public override bool Condition(ReagentEffectArgs args)
{
public sealed partial class MobStateCondition : ReagentEffectCondition
{
- [DataField]
- public MobState Mobstate = MobState.Alive;
+
+
+ [DataField("mobstate")]
+ public MobState mobstate = MobState.Alive;
public override bool Condition(ReagentEffectArgs args)
{
if (args.EntityManager.TryGetComponent(args.SolutionEntity, out MobStateComponent? mobState))
{
- if (mobState.CurrentState == Mobstate)
+ if (mobState.CurrentState == mobstate)
return true;
}
public override string GuidebookExplanation(IPrototypeManager prototype)
{
- return Loc.GetString("reagent-effect-condition-guidebook-mob-state-condition", ("state", Mobstate));
+ return Loc.GetString("reagent-effect-condition-guidebook-mob-state-condition", ("state", mobstate));
}
}
}
/// </summary>
public sealed partial class OrganType : ReagentEffectCondition
{
- [DataField(required: true, customTypeSerializer: typeof(PrototypeIdSerializer<MetabolizerTypePrototype>))]
+ [DataField("type", required: true, customTypeSerializer: typeof(PrototypeIdSerializer<MetabolizerTypePrototype>))]
public string Type = default!;
/// <summary>
/// Does this condition pass when the organ has the type, or when it doesn't have the type?
/// </summary>
- [DataField]
+ [DataField("shouldHave")]
public bool ShouldHave = true;
public override bool Condition(ReagentEffectArgs args)
/// </summary>
public sealed partial class ReagentThreshold : ReagentEffectCondition
{
- [DataField]
+ [DataField("min")]
public FixedPoint2 Min = FixedPoint2.Zero;
- [DataField]
+ [DataField("max")]
public FixedPoint2 Max = FixedPoint2.MaxValue;
// TODO use ReagentId
- [DataField]
+ [DataField("reagent")]
public string? Reagent;
public override bool Condition(ReagentEffectArgs args)
/// </summary>
public sealed partial class SolutionTemperature : ReagentEffectCondition
{
- [DataField]
+ [DataField("min")]
public float Min = 0.0f;
- [DataField]
+ [DataField("max")]
public float Max = float.PositiveInfinity;
public override bool Condition(ReagentEffectArgs args)
{
{
public sealed partial class TotalDamage : ReagentEffectCondition
{
- [DataField]
+ [DataField("max")]
public FixedPoint2 Max = FixedPoint2.MaxValue;
- [DataField]
+ [DataField("min")]
public FixedPoint2 Min = FixedPoint2.Zero;
public override bool Condition(ReagentEffectArgs args)
-using Content.Server.Chemistry.Containers.EntitySystems;
+using Content.Shared.Chemistry.EntitySystems;
using Content.Shared.Chemistry.Reagent;
using JetBrains.Annotations;
using Robust.Shared.Prototypes;
return;
// TODO see if this is correct
- var solutionContainerSystem = args.EntityManager.System<SolutionContainerSystem>();
- if (!solutionContainerSystem.TryGetSolution(args.SolutionEntity, _solution, out var solutionContainer))
+ if (!EntitySystem.Get<SolutionContainerSystem>()
+ .TryGetSolution(args.SolutionEntity, _solution, out var solutionContainer))
return;
- if (solutionContainerSystem.TryAddReagent(solutionContainer.Value, args.Reagent.ID, args.Quantity, out var accepted))
+ if (EntitySystem.Get<SolutionContainerSystem>()
+ .TryAddReagent(args.SolutionEntity, solutionContainer, args.Reagent.ID, args.Quantity, out var accepted))
args.Source?.RemoveReagent(args.Reagent.ID, accepted);
}
[DataField("alertType", required: true)]
public AlertType Type;
- [DataField]
+ [DataField("clear")]
public bool Clear;
- [DataField]
+ [DataField("cooldown")]
public bool Cooldown;
- [DataField]
+ [DataField("time")]
public float Time;
//JUSTIFICATION: This just changes some visuals, doesn't need to be documented.
using Content.Shared.Body.Prototypes;
+using Content.Shared.Chemistry.EntitySystems;
using Content.Shared.Chemistry.Reagent;
using Content.Shared.FixedPoint;
using JetBrains.Annotations;
/// <summary>
/// The reagent ID to remove. Only one of this and <see cref="Group"/> should be active.
/// </summary>
- [DataField(customTypeSerializer: typeof(PrototypeIdSerializer<ReagentPrototype>))]
+ [DataField("reagent", customTypeSerializer:typeof(PrototypeIdSerializer<ReagentPrototype>))]
public string? Reagent = null;
// TODO use ReagentId
/// The metabolism group to remove, if the reagent satisfies any.
/// Only one of this and <see cref="Reagent"/> should be active.
/// </summary>
- [DataField(customTypeSerializer: typeof(PrototypeIdSerializer<MetabolismGroupPrototype>))]
+ [DataField("group", customTypeSerializer:typeof(PrototypeIdSerializer<MetabolismGroupPrototype>))]
public string? Group = null;
- [DataField(required: true)]
+ [DataField("amount", required: true)]
public FixedPoint2 Amount = default!;
public override void Effect(ReagentEffectArgs args)
{
- if (args.Source == null)
- return;
+ if (args.Source != null)
+ {
+ var solutionSys = args.EntityManager.EntitySysManager.GetEntitySystem<SolutionContainerSystem>();
+ var amount = Amount;
- var amount = Amount;
- amount *= args.Scale;
+ amount *= args.Scale;
- if (Reagent != null)
- {
- if (amount < 0 && args.Source.ContainsPrototype(Reagent))
- args.Source.RemoveReagent(Reagent, -amount);
- if (amount > 0)
- args.Source.AddReagent(Reagent, amount);
- }
- else if (Group != null)
- {
- var prototypeMan = IoCManager.Resolve<IPrototypeManager>();
- foreach (var quant in args.Source.Contents.ToArray())
+ if (Reagent != null)
+ {
+ if (amount < 0 && args.Source.ContainsPrototype(Reagent))
+ solutionSys.RemoveReagent(args.SolutionEntity, args.Source, Reagent, -amount);
+ if (amount > 0)
+ solutionSys.TryAddReagent(args.SolutionEntity, args.Source, Reagent, amount, out _);
+ }
+ else if (Group != null)
{
- var proto = prototypeMan.Index<ReagentPrototype>(quant.Reagent.Prototype);
- if (proto.Metabolisms != null && proto.Metabolisms.ContainsKey(Group))
+ var prototypeMan = IoCManager.Resolve<IPrototypeManager>();
+ foreach (var quant in args.Source.Contents.ToArray())
{
- if (amount < 0)
- args.Source.RemoveReagent(quant.Reagent, amount);
- if (amount > 0)
- args.Source.AddReagent(quant.Reagent, amount);
+ var proto = prototypeMan.Index<ReagentPrototype>(quant.Reagent.Prototype);
+ if (proto.Metabolisms != null && proto.Metabolisms.ContainsKey(Group))
+ {
+ if (amount < 0)
+ solutionSys.RemoveReagent(args.SolutionEntity, args.Source, quant.Reagent, amount);
+ if (amount > 0)
+ solutionSys.TryAddReagent(args.SolutionEntity, args.Source, quant.Reagent, amount, out _);
+ }
}
}
}
{
public sealed partial class AdjustTemperature : ReagentEffect
{
- [DataField]
+ [DataField("amount")]
public float Amount;
protected override string? ReagentEffectGuidebookText(IPrototypeManager prototype, IEntitySystemManager entSys)
-using Content.Server.Zombies;
using Content.Shared.Chemistry.Reagent;
-using Robust.Shared.Configuration;
using Robust.Shared.Prototypes;
+using Robust.Shared.Configuration;
+using Content.Server.Zombies;
+
+
namespace Content.Server.Chemistry.ReagentEffects;
public sealed partial class CauseZombieInfection : ReagentEffect
-using Content.Server.Body.Systems;
using Content.Shared.Chemistry.Reagent;
using JetBrains.Annotations;
+using Content.Server.Body.Systems;
using Robust.Shared.Prototypes;
namespace Content.Server.Chemistry.ReactionEffects
[UsedImplicitly]
public sealed partial class ChemCleanBloodstream : ReagentEffect
{
- [DataField]
+ [DataField("cleanseRate")]
public float CleanseRate = 3.0f;
protected override string? ReagentEffectGuidebookText(IPrototypeManager prototype, IEntitySystemManager entSys)
/// <summary>
/// How much eye damage to add.
/// </summary>
- [DataField]
+ [DataField("amount")]
public int Amount = -1;
protected override string? ReagentEffectGuidebookText(IPrototypeManager prototype, IEntitySystemManager entSys)
-using Content.Server.Medical;
using Content.Shared.Chemistry.Reagent;
+using Content.Server.Medical;
using JetBrains.Annotations;
using Robust.Shared.Prototypes;
public sealed partial class ChemVomit : ReagentEffect
{
/// How many units of thirst to add each time we vomit
- [DataField]
+ [DataField("thirstAmount")]
public float ThirstAmount = -8f;
/// How many units of hunger to add each time we vomit
- [DataField]
+ [DataField("hungerAmount")]
public float HungerAmount = -8f;
protected override string? ReagentEffectGuidebookText(IPrototypeManager prototype, IEntitySystemManager entSys)
public sealed partial class CreateGas : ReagentEffect
{
- [DataField(required: true)]
+ [DataField("gas", required: true)]
public Gas Gas = default!;
/// <summary>
/// For each unit consumed, how many moles of gas should be created?
/// </summary>
- [DataField]
+ [DataField("multiplier")]
public float Multiplier = 3f;
public override bool ShouldLog => true;
-using Content.Server.Zombies;
using Content.Shared.Chemistry.Reagent;
-using Robust.Shared.Configuration;
using Robust.Shared.Prototypes;
+using Robust.Shared.Configuration;
+using Content.Server.Zombies;
+
namespace Content.Server.Chemistry.ReagentEffects;
public sealed partial class CureZombieInfection : ReagentEffect
{
- [DataField]
+ [DataField("innoculate")]
public bool Innoculate;
protected override string? ReagentEffectGuidebookText(IPrototypeManager prototype, IEntitySystemManager entSys)
/// <summary>
/// BoozePower is how long each metabolism cycle will make the drunk effect last for.
/// </summary>
- [DataField]
+ [DataField("boozePower")]
public float BoozePower = 3f;
/// <summary>
/// Whether speech should be slurred.
/// </summary>
- [DataField]
+ [DataField("slurSpeech")]
public bool SlurSpeech = true;
protected override string? ReagentEffectGuidebookText(IPrototypeManager prototype, IEntitySystemManager entSys)
public sealed partial class Electrocute : ReagentEffect
{
- [DataField] public int ElectrocuteTime = 2;
+ [DataField("electrocuteTime")] public int ElectrocuteTime = 2;
- [DataField] public int ElectrocuteDamageScale = 5;
+ [DataField("electrocuteDamageScale")] public int ElectrocuteDamageScale = 5;
/// <remarks>
/// true - refresh electrocute time, false - accumulate electrocute time
/// </remarks>
- [DataField] public bool Refresh = true;
+ [DataField("refresh")] public bool Refresh = true;
protected override string? ReagentEffectGuidebookText(IPrototypeManager prototype, IEntitySystemManager entSys)
=> Loc.GetString("reagent-effect-guidebook-electrocute", ("chance", Probability), ("time", ElectrocuteTime));
[DataField("emote", customTypeSerializer: typeof(PrototypeIdSerializer<EmotePrototype>))]
public string? EmoteId;
- [DataField]
+ [DataField("showInChat")]
public bool ShowInChat;
// JUSTIFICATION: Emoting is flavor, so same reason popup messages are not in here.
[UsedImplicitly]
public sealed partial class FlammableReaction : ReagentEffect
{
- [DataField]
+ [DataField("multiplier")]
public float Multiplier = 0.05f;
public override bool ShouldLog => true;
+using System.Linq;
+using System.Text.Json.Serialization;
using Content.Shared.Chemistry.Reagent;
using Content.Shared.Damage;
using Content.Shared.Damage.Prototypes;
using Content.Shared.Localizations;
using JetBrains.Annotations;
using Robust.Shared.Prototypes;
-using System.Linq;
-using System.Text.Json.Serialization;
namespace Content.Server.Chemistry.ReagentEffects
{
/// <summary>
/// Damage to apply every metabolism cycle. Damage Ignores resistances.
/// </summary>
- [DataField(required: true)]
[JsonPropertyName("damage")]
+ [DataField("damage", required: true)]
public DamageSpecifier Damage = default!;
/// <summary>
/// Should this effect scale the damage by the amount of chemical in the solution?
/// Useful for touch reactions, like styptic powder or acid.
/// </summary>
- [DataField]
[JsonPropertyName("scaleByQuantity")]
+ [DataField("scaleByQuantity")]
public bool ScaleByQuantity;
- [DataField]
+ [DataField("ignoreResistances")]
[JsonPropertyName("ignoreResistances")]
public bool IgnoreResistances = true;
public sealed partial class ModifyBleedAmount : ReagentEffect
{
- [DataField]
+ [DataField("scaled")]
public bool Scaled = false;
- [DataField]
+ [DataField("amount")]
public float Amount = -1.0f;
protected override string? ReagentEffectGuidebookText(IPrototypeManager prototype, IEntitySystemManager entSys)
public sealed partial class ModifyBloodLevel : ReagentEffect
{
- [DataField]
+ [DataField("scaled")]
public bool Scaled = false;
- [DataField]
+ [DataField("amount")]
public FixedPoint2 Amount = 1.0f;
protected override string? ReagentEffectGuidebookText(IPrototypeManager prototype, IEntitySystemManager entSys)
/// <summary>
/// How much the entities' walk speed is multiplied by.
/// </summary>
- [DataField]
+ [DataField("walkSpeedModifier")]
public float WalkSpeedModifier { get; set; } = 1;
/// <summary>
/// How much the entities' run speed is multiplied by.
/// </summary>
- [DataField]
+ [DataField("sprintSpeedModifier")]
public float SprintSpeedModifier { get; set; } = 1;
/// <summary>
/// How long the modifier applies (in seconds) when metabolized.
/// </summary>
- [DataField]
+ [DataField("statusLifetime")]
public float StatusLifetime = 2f;
protected override string? ReagentEffectGuidebookText(IPrototypeManager prototype, IEntitySystemManager entSys)
public sealed partial class Oxygenate : ReagentEffect
{
- [DataField]
+ [DataField("factor")]
public float Factor = 1f;
// JUSTIFICATION: This is internal magic that players never directly interact with.
-using Content.Server.Stunnable;
using Content.Shared.Chemistry.Reagent;
+using Content.Server.Stunnable;
using Robust.Shared.Prototypes;
namespace Content.Server.Chemistry.ReagentEffects;
public sealed partial class Paralyze : ReagentEffect
{
- [DataField] public double ParalyzeTime = 2;
+ [DataField("paralyzeTime")] public double ParalyzeTime = 2;
/// <remarks>
/// true - refresh paralyze time, false - accumulate paralyze time
/// </remarks>
- [DataField] public bool Refresh = true;
+ [DataField("refresh")] public bool Refresh = true;
protected override string? ReagentEffectGuidebookText(IPrototypeManager prototype, IEntitySystemManager entSys)
=> Loc.GetString("reagent-effect-guidebook-paralyze",
-using Content.Server.Botany.Components;
+using System.Diagnostics.CodeAnalysis;
+using Content.Server.Botany.Components;
using Content.Shared.Chemistry.Reagent;
using Robust.Shared.Prototypes;
using Robust.Shared.Random;
-using System.Diagnostics.CodeAnalysis;
namespace Content.Server.Chemistry.ReagentEffects.PlantMetabolism
{
[ImplicitDataDefinitionForInheritors]
public abstract partial class PlantAdjustAttribute : ReagentEffect
{
- [DataField]
- public float Amount { get; protected set; } = 1;
-
- [DataField]
- public float Prob { get; protected set; } = 1; // = (80);
+ [DataField("amount")] public float Amount { get; protected set; } = 1;
+ [DataField("prob")] public float Prob { get; protected set; } = 1; // = (80);
/// <summary>
/// Checks if the plant holder can metabolize the reagent or not. Checks if it has an alive plant by default.
[DataDefinition]
public sealed partial class RobustHarvest : ReagentEffect
{
- [DataField]
+ [DataField("potencyLimit")]
public int PotencyLimit = 50;
- [DataField]
+ [DataField("potencyIncrease")]
public int PotencyIncrease = 3;
- [DataField]
+ [DataField("potencySeedlessThreshold")]
public int PotencySeedlessThreshold = 30;
public override void Effect(ReagentEffectArgs args)
{
public sealed partial class PopupMessage : ReagentEffect
{
- [DataField(required: true)]
+ [DataField("messages", required: true)]
public string[] Messages = default!;
- [DataField]
+ [DataField("type")]
public PopupRecipients Type = PopupRecipients.Local;
- [DataField]
+ [DataField("visualType")]
public PopupType VisualType = PopupType.Small;
// JUSTIFICATION: This is purely cosmetic.
[UsedImplicitly]
public sealed partial class GenericStatusEffect : ReagentEffect
{
- [DataField(required: true)]
+ [DataField("key", required: true)]
public string Key = default!;
- [DataField]
+ [DataField("component")]
public string Component = String.Empty;
- [DataField]
+ [DataField("time")]
public float Time = 2.0f;
/// <remarks>
/// true - refresh status effect time, false - accumulate status effect time
/// </remarks>
- [DataField]
+ [DataField("refresh")]
public bool Refresh = true;
/// <summary>
/// Should this effect add the status effect, remove time from it, or set its cooldown?
/// </summary>
- [DataField]
+ [DataField("type")]
public StatusEffectMetabolismType Type = StatusEffectMetabolismType.Add;
public override void Effect(ReagentEffectArgs args)
/// </summary>
public sealed partial class Jitter : ReagentEffect
{
- [DataField]
+ [DataField("amplitude")]
public float Amplitude = 10.0f;
- [DataField]
+ [DataField("frequency")]
public float Frequency = 4.0f;
- [DataField]
+ [DataField("time")]
public float Time = 2.0f;
/// <remarks>
/// true - refresh jitter time, false - accumulate jitter time
/// </remarks>
- [DataField]
+ [DataField("refresh")]
public bool Refresh = true;
public override void Effect(ReagentEffectArgs args)
+using System.Numerics;
using Content.Server.Decals;
using Content.Shared.Chemistry.Reaction;
using Content.Shared.Chemistry.Reagent;
using Content.Shared.FixedPoint;
using Robust.Shared.Map;
using Robust.Shared.Map.Components;
-using System.Numerics;
namespace Content.Server.Chemistry.TileReactions;
/// <summary>
/// For every cleaned decal we lose this much reagent.
/// </summary>
- [DataField]
+ [DataField("cleanCost")]
public FixedPoint2 CleanCost { get; private set; } = FixedPoint2.New(0.25f);
public FixedPoint2 TileReact(TileRef tile, ReagentPrototype reagent, FixedPoint2 reactVolume)
-using Content.Server.Chemistry.Containers.EntitySystems;
+using System.Linq;
using Content.Shared.Chemistry.Components;
+using Content.Shared.Chemistry.EntitySystems;
using Content.Shared.Chemistry.Reaction;
using Content.Shared.Chemistry.Reagent;
using Content.Shared.FixedPoint;
using Content.Shared.Fluids.Components;
using Robust.Shared.Map;
using Robust.Shared.Serialization.TypeSerializers.Implementations.Custom.Prototype;
-using System.Linq;
namespace Content.Server.Chemistry.TileReactions;
/// <summary>
/// What reagent to replace the tile conents with.
/// </summary>
- [DataField("reagent", customTypeSerializer: typeof(PrototypeIdSerializer<ReagentPrototype>))]
+ [DataField("reagent", customTypeSerializer:typeof(PrototypeIdSerializer<ReagentPrototype>))]
public string ReplacementReagent = "Water";
FixedPoint2 ITileReaction.TileReact(TileRef tile, ReagentPrototype reagent, FixedPoint2 reactVolume)
foreach (var entity in entities)
{
if (!puddleQuery.TryGetComponent(entity, out var puddle) ||
- !solutionContainerSystem.TryGetSolution(entity, puddle.SolutionName, out var puddleSolution, out _))
+ !solutionContainerSystem.TryGetSolution(entity, puddle.SolutionName, out var puddleSolution))
{
continue;
}
- var purgeable = solutionContainerSystem.SplitSolutionWithout(puddleSolution.Value, purgeAmount, ReplacementReagent, reagent.ID);
+ var purgeable =
+ solutionContainerSystem.SplitSolutionWithout(entity, puddleSolution, purgeAmount, ReplacementReagent, reagent.ID);
purgeAmount -= purgeable.Volume;
- solutionContainerSystem.TryAddSolution(puddleSolution.Value, new Solution(ReplacementReagent, purgeable.Volume));
+ solutionContainerSystem.TryAddSolution(entity, puddleSolution, new Solution(ReplacementReagent, purgeable.Volume));
if (purgeable.Volume <= FixedPoint2.Zero)
break;
-using Content.Shared.Chemistry.Reaction;
+using System.Numerics;
+using Content.Shared.Chemistry.Reaction;
using Content.Shared.Chemistry.Reagent;
using Content.Shared.FixedPoint;
using Content.Shared.Maps;
using Robust.Shared.Prototypes;
using Robust.Shared.Random;
using Robust.Shared.Serialization.TypeSerializers.Implementations.Custom.Prototype;
-using System.Numerics;
namespace Content.Server.Chemistry.TileReactions;
[DataDefinition]
public sealed partial class CreateEntityTileReaction : ITileReaction
{
- [DataField(required: true, customTypeSerializer: typeof(PrototypeIdSerializer<EntityPrototype>))]
+ [DataField("entity", required: true, customTypeSerializer:typeof(PrototypeIdSerializer<EntityPrototype>))]
public string Entity = default!;
- [DataField]
+ [DataField("usage")]
public FixedPoint2 Usage = FixedPoint2.New(1);
/// <summary>
/// How many of the whitelisted entity can fit on one tile?
/// </summary>
- [DataField]
+ [DataField("maxOnTile")]
public int MaxOnTile = 1;
/// <summary>
[DataField("maxOnTileWhitelist")]
public EntityWhitelist? Whitelist;
- [DataField]
+ [DataField("randomOffsetMax")]
public float RandomOffsetMax = 0.0f;
public FixedPoint2 TileReact(TileRef tile, ReagentPrototype reagent, FixedPoint2 reactVolume)
using Robust.Server.Containers;
using Robust.Server.GameObjects;
using Robust.Server.Player;
+using Robust.Shared.Audio;
using Robust.Shared.Audio.Systems;
using Robust.Shared.Configuration;
using Robust.Shared.Containers;
-using Content.Server.Chemistry.Containers.EntitySystems;
+using Content.Shared.Chemistry.EntitySystems;
using Content.Shared.Chemistry.Reagent;
using Content.Shared.Construction;
using Content.Shared.Examine;
public bool Condition(EntityUid uid, IEntityManager entMan)
{
var containerSys = entMan.System<SolutionContainerSystem>();
- if (!containerSys.TryGetSolution(uid, Solution, out _, out var solution))
+ if (!containerSys.TryGetSolution(uid, Solution, out var solution))
return false;
solution.TryGetReagentQuantity(Reagent, out var quantity);
var uid = args.Examined;
var containerSys = entMan.System<SolutionContainerSystem>();
- if (!containerSys.TryGetSolution(uid, Solution, out _, out var solution))
+ if (!containerSys.TryGetSolution(uid, Solution, out var solution))
return false;
solution.TryGetReagentQuantity(Reagent, out var quantity);
-using Content.Server.Chemistry.Containers.EntitySystems;
+using Content.Shared.Chemistry.EntitySystems;
using Content.Shared.Construction;
using Content.Shared.Examine;
public bool Condition(EntityUid uid, IEntityManager entMan)
{
var containerSys = entMan.System<SolutionContainerSystem>();
- if (!containerSys.TryGetSolution(uid, Solution, out _, out var solution))
+ if (!containerSys.TryGetSolution(uid, Solution, out var solution))
return false;
return solution.Volume == 0;
var uid = args.Examined;
var containerSys = entMan.System<SolutionContainerSystem>();
- if (!containerSys.TryGetSolution(uid, Solution, out _, out var solution))
+ if (!containerSys.TryGetSolution(uid, Solution, out var solution))
return false;
// already empty so dont show examine
+using System.Linq;
using Content.Server.Administration.Logs;
using Content.Server.Atmos.EntitySystems;
using Content.Server.Body.Systems;
-using Content.Server.Chemistry.Containers.EntitySystems;
using Content.Server.Construction;
using Content.Server.Destructible.Thresholds;
using Content.Server.Destructible.Thresholds.Behaviors;
using Content.Server.Explosion.EntitySystems;
using Content.Server.Fluids.EntitySystems;
using Content.Server.Stack;
+using Content.Shared.Chemistry.EntitySystems;
using Content.Shared.Damage;
using Content.Shared.Database;
using Content.Shared.Destructible;
using Robust.Shared.Containers;
using Robust.Shared.Prototypes;
using Robust.Shared.Random;
-using System.Linq;
namespace Content.Server.Destructible
{
[DataDefinition]
public sealed partial class SolutionExplosionBehavior : IThresholdBehavior
{
- [DataField(required: true)]
+ [DataField("solution", required: true)]
public string Solution = default!;
public void Execute(EntityUid owner, DestructibleSystem system, EntityUid? cause = null)
{
- if (system.SolutionContainerSystem.TryGetSolution(owner, Solution, out _, out var explodingSolution)
+ if (system.SolutionContainerSystem.TryGetSolution(owner, Solution, out var explodingSolution)
&& system.EntityManager.TryGetComponent(owner, out ExplosiveComponent? explosiveComponent))
{
// Don't explode if there's no solution
-using Content.Server.Chemistry.Containers.EntitySystems;
using Content.Server.Fluids.Components;
using Content.Server.Fluids.EntitySystems;
+using Content.Shared.Chemistry.EntitySystems;
using JetBrains.Annotations;
namespace Content.Server.Destructible.Thresholds.Behaviors
[DataDefinition]
public sealed partial class SpillBehavior : IThresholdBehavior
{
- [DataField]
+ [DataField("solution")]
public string? Solution;
/// <summary>
var coordinates = system.EntityManager.GetComponent<TransformComponent>(owner).Coordinates;
if (system.EntityManager.TryGetComponent(owner, out SpillableComponent? spillableComponent) &&
- solutionContainerSystem.TryGetSolution(owner, spillableComponent.SolutionName, out _, out var compSolution))
+ solutionContainerSystem.TryGetSolution(owner, spillableComponent.SolutionName,
+ out var compSolution))
{
spillableSystem.TrySplashSpillAt(owner, coordinates, compSolution, out _, false, user: cause);
}
else if (Solution != null &&
- solutionContainerSystem.TryGetSolution(owner, Solution, out _, out var behaviorSolution))
+ solutionContainerSystem.TryGetSolution(owner, Solution, out var behaviorSolution))
{
spillableSystem.TrySplashSpillAt(owner, coordinates, behaviorSolution, out _, user: cause);
}
+using System.Linq;
using Content.Server.Administration.Logs;
using Content.Server.Body.Systems;
-using Content.Server.Chemistry.Containers.EntitySystems;
using Content.Server.Explosion.Components;
using Content.Server.Flash;
using Content.Server.Flash.Components;
using Content.Server.Radio.EntitySystems;
-using Content.Shared.Chemistry.Components;
using Content.Shared.Chemistry.Components.SolutionManager;
+using Content.Shared.Chemistry.EntitySystems;
using Content.Shared.Database;
using Content.Shared.Implants.Components;
using Content.Shared.Interaction;
-using Content.Shared.Mobs;
-using Content.Shared.Mobs.Components;
using Content.Shared.Payload.Components;
+using Robust.Shared.Prototypes;
using Content.Shared.Radio;
using Content.Shared.Slippery;
using Content.Shared.StepTrigger.Systems;
using Content.Shared.Trigger;
-using Content.Shared.Weapons.Ranged.Events;
using JetBrains.Annotations;
using Robust.Shared.Audio;
-using Robust.Shared.Audio.Systems;
using Robust.Shared.Containers;
using Robust.Shared.Physics.Events;
using Robust.Shared.Physics.Systems;
-using Robust.Shared.Prototypes;
+using Content.Shared.Mobs;
+using Content.Shared.Mobs.Components;
+using Content.Shared.Weapons.Ranged.Events;
+using Robust.Shared.Audio.Systems;
using Robust.Shared.Random;
namespace Content.Server.Explosion.EntitySystems
[Dependency] private readonly RadioSystem _radioSystem = default!;
[Dependency] private readonly IRobustRandom _random = default!;
[Dependency] private readonly IPrototypeManager _prototypeManager = default!;
- [Dependency] private readonly SolutionContainerSystem _solutionContainerSystem = default!;
public override void Initialize()
{
comp.TimeRemaining += amount;
}
- public void HandleTimerTrigger(EntityUid uid, EntityUid? user, float delay, float beepInterval, float? initialBeepDelay, SoundSpecifier? beepSound)
+ public void HandleTimerTrigger(EntityUid uid, EntityUid? user, float delay , float beepInterval, float? initialBeepDelay, SoundSpecifier? beepSound)
{
if (delay <= 0)
{
TryComp(container.ContainedEntities[0], out ChemicalPayloadComponent? chemicalPayloadComponent))
{
// If a beaker is missing, the entity won't explode, so no reason to log it
- if (chemicalPayloadComponent?.BeakerSlotA.Item is not { } beakerA ||
- chemicalPayloadComponent?.BeakerSlotB.Item is not { } beakerB ||
- !TryComp(beakerA, out SolutionContainerManagerComponent? containerA) ||
- !TryComp(beakerB, out SolutionContainerManagerComponent? containerB) ||
- !TryComp(beakerA, out FitsInDispenserComponent? fitsA) ||
- !TryComp(beakerB, out FitsInDispenserComponent? fitsB) ||
- !_solutionContainerSystem.TryGetSolution((beakerA, containerA), fitsA.Solution, out _, out var solutionA) ||
- !_solutionContainerSystem.TryGetSolution((beakerB, containerB), fitsB.Solution, out _, out var solutionB))
+ if (!TryComp(chemicalPayloadComponent?.BeakerSlotA.Item, out SolutionContainerManagerComponent? beakerA) ||
+ !TryComp(chemicalPayloadComponent?.BeakerSlotB.Item, out SolutionContainerManagerComponent? beakerB))
return;
_adminLogger.Add(LogType.Trigger,
- $"{ToPrettyString(user.Value):user} started a {delay} second timer trigger on entity {ToPrettyString(uid):timer}, which contains {SolutionContainerSystem.ToPrettyString(solutionA)} in one beaker and {SolutionContainerSystem.ToPrettyString(solutionB)} in the other.");
+ $"{ToPrettyString(user.Value):user} started a {delay} second timer trigger on entity {ToPrettyString(uid):timer}, which contains [{string.Join(", ", beakerA.Solutions.Values.First())}] in one beaker and [{string.Join(", ", beakerB.Solutions.Values.First())}] in the other.");
}
else
{
-using Content.Server.Chemistry.Containers.EntitySystems;
using Content.Server.Fluids.EntitySystems;
using Content.Server.Popups;
+using Content.Shared.Audio;
using Content.Shared.Chemistry.Components;
+using Content.Shared.Chemistry.EntitySystems;
using Content.Shared.Extinguisher;
using Content.Shared.FixedPoint;
using Content.Shared.Interaction;
using Content.Shared.Verbs;
using Robust.Shared.Audio;
using Robust.Shared.Audio.Systems;
+using Robust.Shared.Player;
namespace Content.Server.Extinguisher;
SubscribeLocalEvent<FireExtinguisherComponent, SprayAttemptEvent>(OnSprayAttempt);
}
- private void OnFireExtinguisherInit(Entity<FireExtinguisherComponent> entity, ref ComponentInit args)
+ private void OnFireExtinguisherInit(EntityUid uid, FireExtinguisherComponent component, ComponentInit args)
{
- if (entity.Comp.HasSafety)
+ if (component.HasSafety)
{
- UpdateAppearance((entity.Owner, entity.Comp));
+ UpdateAppearance(uid, component);
}
}
- private void OnUseInHand(Entity<FireExtinguisherComponent> entity, ref UseInHandEvent args)
+ private void OnUseInHand(EntityUid uid, FireExtinguisherComponent component, UseInHandEvent args)
{
if (args.Handled)
return;
- ToggleSafety((entity.Owner, entity.Comp), args.User);
+ ToggleSafety(uid, args.User, component);
args.Handled = true;
}
- private void OnAfterInteract(Entity<FireExtinguisherComponent> entity, ref AfterInteractEvent args)
+ private void OnAfterInteract(EntityUid uid, FireExtinguisherComponent component, AfterInteractEvent args)
{
if (args.Target == null || !args.CanReach)
{
if (args.Handled)
return;
- if (entity.Comp.HasSafety && entity.Comp.Safety)
+ if (component.HasSafety && component.Safety)
{
- _popupSystem.PopupEntity(Loc.GetString("fire-extinguisher-component-safety-on-message"), entity.Owner, args.User);
+ _popupSystem.PopupEntity(Loc.GetString("fire-extinguisher-component-safety-on-message"), uid,
+ args.User);
return;
}
- if (args.Target is not { Valid: true } target ||
- !_solutionContainerSystem.TryGetDrainableSolution(target, out var targetSoln, out var targetSolution) ||
- !_solutionContainerSystem.TryGetRefillableSolution(entity.Owner, out var containerSoln, out var containerSolution))
+ if (args.Target is not {Valid: true} target ||
+ !_solutionContainerSystem.TryGetDrainableSolution(target, out var targetSolution) ||
+ !_solutionContainerSystem.TryGetRefillableSolution(uid, out var container))
{
return;
}
args.Handled = true;
- var transfer = containerSolution.AvailableVolume;
- if (TryComp<SolutionTransferComponent>(entity.Owner, out var solTrans))
+ var transfer = container.AvailableVolume;
+ if (TryComp<SolutionTransferComponent>(uid, out var solTrans))
{
transfer = solTrans.TransferAmount;
}
if (transfer > 0)
{
- var drained = _solutionContainerSystem.Drain(target, targetSoln.Value, transfer);
- _solutionContainerSystem.TryAddSolution(containerSoln.Value, drained);
+ var drained = _solutionContainerSystem.Drain(target, targetSolution, transfer);
+ _solutionContainerSystem.TryAddSolution(uid, container, drained);
- _audio.PlayPvs(entity.Comp.RefillSound, entity.Owner);
- _popupSystem.PopupEntity(Loc.GetString("fire-extinguisher-component-after-interact-refilled-message", ("owner", entity.Owner)),
- entity.Owner, args.Target.Value);
+ _audio.PlayPvs(component.RefillSound, uid);
+ _popupSystem.PopupEntity(Loc.GetString("fire-extinguisher-component-after-interact-refilled-message", ("owner", uid)),
+ uid, args.Target.Value);
}
}
- private void OnGetInteractionVerbs(Entity<FireExtinguisherComponent> entity, ref GetVerbsEvent<InteractionVerb> args)
+ private void OnGetInteractionVerbs(EntityUid uid, FireExtinguisherComponent component, GetVerbsEvent<InteractionVerb> args)
{
if (!args.CanInteract)
return;
- var user = args.User;
var verb = new InteractionVerb
{
- Act = () => ToggleSafety((entity.Owner, entity.Comp), user),
+ Act = () => ToggleSafety(uid, args.User, component),
Text = Loc.GetString("fire-extinguisher-component-verb-text"),
};
args.Verbs.Add(verb);
}
- private void OnSprayAttempt(Entity<FireExtinguisherComponent> entity, ref SprayAttemptEvent args)
+ private void OnSprayAttempt(EntityUid uid, FireExtinguisherComponent component, SprayAttemptEvent args)
{
- if (entity.Comp.HasSafety && entity.Comp.Safety)
+ if (component.HasSafety && component.Safety)
{
- _popupSystem.PopupEntity(Loc.GetString("fire-extinguisher-component-safety-on-message"), entity, args.User);
+ _popupSystem.PopupEntity(Loc.GetString("fire-extinguisher-component-safety-on-message"), uid,
+ args.User);
args.Cancel();
}
}
- private void UpdateAppearance(Entity<FireExtinguisherComponent, AppearanceComponent?> entity)
+ private void UpdateAppearance(EntityUid uid, FireExtinguisherComponent comp,
+ AppearanceComponent? appearance=null)
{
- if (!Resolve(entity, ref entity.Comp2, false))
+ if (!Resolve(uid, ref appearance, false))
return;
- if (entity.Comp1.HasSafety)
+ if (comp.HasSafety)
{
- _appearance.SetData(entity, FireExtinguisherVisuals.Safety, entity.Comp1.Safety, entity.Comp2);
+ _appearance.SetData(uid, FireExtinguisherVisuals.Safety, comp.Safety, appearance);
}
}
- public void ToggleSafety(Entity<FireExtinguisherComponent?> extinguisher, EntityUid user)
+ public void ToggleSafety(EntityUid uid, EntityUid user,
+ FireExtinguisherComponent? extinguisher = null)
{
- if (!Resolve(extinguisher, ref extinguisher.Comp))
+ if (!Resolve(uid, ref extinguisher))
return;
- extinguisher.Comp.Safety = !extinguisher.Comp.Safety;
- _audio.PlayPvs(extinguisher.Comp.SafetySound, extinguisher, AudioParams.Default.WithVariation(0.125f).WithVolume(-4f));
- UpdateAppearance((extinguisher.Owner, extinguisher.Comp));
+ extinguisher.Safety = !extinguisher.Safety;
+ _audio.PlayPvs(extinguisher.SafetySound, uid, AudioParams.Default.WithVariation(0.125f).WithVolume(-4f));
+ UpdateAppearance(uid, extinguisher);
}
}
-using Content.Server.Chemistry.Containers.EntitySystems;
using Content.Server.Popups;
using Content.Shared.Chemistry.Components;
using Content.Shared.Chemistry.EntitySystems;
[Dependency] private readonly PuddleSystem _puddleSystem = default!;
[Dependency] private readonly SharedMeleeWeaponSystem _melee = default!;
[Dependency] private readonly SharedTransformSystem _transform = default!;
- [Dependency] private readonly SolutionContainerSystem _solutionContainerSystem = default!;
+ [Dependency] private readonly SolutionContainerSystem _solutionSystem = default!;
[Dependency] private readonly UseDelaySystem _useDelay = default!;
public override void Initialize()
SubscribeLocalEvent<AbsorbentComponent, ComponentInit>(OnAbsorbentInit);
SubscribeLocalEvent<AbsorbentComponent, AfterInteractEvent>(OnAfterInteract);
SubscribeLocalEvent<AbsorbentComponent, InteractNoHandEvent>(OnInteractNoHand);
- SubscribeLocalEvent<AbsorbentComponent, SolutionContainerChangedEvent>(OnAbsorbentSolutionChange);
+ SubscribeLocalEvent<AbsorbentComponent, SolutionChangedEvent>(OnAbsorbentSolutionChange);
}
private void OnAbsorbentInit(EntityUid uid, AbsorbentComponent component, ComponentInit args)
UpdateAbsorbent(uid, component);
}
- private void OnAbsorbentSolutionChange(EntityUid uid, AbsorbentComponent component, ref SolutionContainerChangedEvent args)
+ private void OnAbsorbentSolutionChange(EntityUid uid, AbsorbentComponent component, SolutionChangedEvent args)
{
UpdateAbsorbent(uid, component);
}
private void UpdateAbsorbent(EntityUid uid, AbsorbentComponent component)
{
- if (!_solutionContainerSystem.TryGetSolution(uid, AbsorbentComponent.SolutionName, out _, out var solution))
+ if (!_solutionSystem.TryGetSolution(uid, AbsorbentComponent.SolutionName, out var solution))
return;
var oldProgress = component.Progress.ShallowClone();
public void Mop(EntityUid user, EntityUid target, EntityUid used, AbsorbentComponent component)
{
- if (!_solutionContainerSystem.TryGetSolution(used, AbsorbentComponent.SolutionName, out var absorberSoln))
+ if (!_solutionSystem.TryGetSolution(used, AbsorbentComponent.SolutionName, out var absorbentSolution))
return;
if (_useDelay.ActiveDelay(used))
return;
// If it's a puddle try to grab from
- if (!TryPuddleInteract(user, used, target, component, absorberSoln.Value))
+ if (!TryPuddleInteract(user, used, target, component, absorbentSolution))
{
// If it's refillable try to transfer
- if (!TryRefillableInteract(user, used, target, component, absorberSoln.Value))
+ if (!TryRefillableInteract(user, used, target, component, absorbentSolution))
return;
}
}
/// <summary>
/// Logic for an absorbing entity interacting with a refillable.
/// </summary>
- private bool TryRefillableInteract(EntityUid user, EntityUid used, EntityUid target, AbsorbentComponent component, Entity<SolutionComponent> absorbentSoln)
+ private bool TryRefillableInteract(EntityUid user, EntityUid used, EntityUid target, AbsorbentComponent component, Solution absorbentSolution)
{
if (!TryComp(target, out RefillableSolutionComponent? refillable))
return false;
- if (!_solutionContainerSystem.TryGetRefillableSolution((target, refillable, null), out var refillableSoln, out var refillableSolution))
+ if (!_solutionSystem.TryGetRefillableSolution(target, out var refillableSolution, refillable: refillable))
return false;
if (refillableSolution.Volume <= 0)
{
// Target empty - only transfer absorbent contents into refillable
- if (!TryTransferFromAbsorbentToRefillable(user, used, target, component, absorbentSoln, refillableSoln.Value))
+ if (!TryTransferFromAbsorbentToRefillable(user, used, target, component, absorbentSolution, refillableSolution))
return false;
}
else
{
// Target non-empty - do a two-way transfer
- if (!TryTwoWayAbsorbentRefillableTransfer(user, used, target, component, absorbentSoln, refillableSoln.Value))
+ if (!TryTwoWayAbsorbentRefillableTransfer(user, used, target, component, absorbentSolution, refillableSolution))
return false;
}
EntityUid used,
EntityUid target,
AbsorbentComponent component,
- Entity<SolutionComponent> absorbentSoln,
- Entity<SolutionComponent> refillableSoln)
+ Solution absorbentSolution,
+ Solution refillableSolution)
{
- var absorbentSolution = absorbentSoln.Comp.Solution;
if (absorbentSolution.Volume <= 0)
{
_popups.PopupEntity(Loc.GetString("mopping-system-target-container-empty", ("target", target)), user, user);
return false;
}
- var refillableSolution = refillableSoln.Comp.Solution;
var transferAmount = component.PickupAmount < refillableSolution.AvailableVolume ?
component.PickupAmount :
refillableSolution.AvailableVolume;
}
// Prioritize transferring non-evaporatives if absorbent has any
- var contaminants = _solutionContainerSystem.SplitSolutionWithout(absorbentSoln, transferAmount, PuddleSystem.EvaporationReagents);
+ var contaminants = absorbentSolution.SplitSolutionWithout(transferAmount, PuddleSystem.EvaporationReagents);
if (contaminants.Volume > 0)
{
- _solutionContainerSystem.TryAddSolution(refillableSoln, contaminants);
+ _solutionSystem.UpdateChemicals(used, absorbentSolution, true);
+ _solutionSystem.TryAddSolution(target, refillableSolution, contaminants);
}
else
{
- var evaporatives = _solutionContainerSystem.SplitSolution(absorbentSoln, transferAmount);
- _solutionContainerSystem.TryAddSolution(refillableSoln, evaporatives);
+ var evaporatives = absorbentSolution.SplitSolution(transferAmount);
+ _solutionSystem.UpdateChemicals(used, absorbentSolution, true);
+ _solutionSystem.TryAddSolution(target, refillableSolution, evaporatives);
}
return true;
EntityUid used,
EntityUid target,
AbsorbentComponent component,
- Entity<SolutionComponent> absorbentSoln,
- Entity<SolutionComponent> refillableSoln)
+ Solution absorbentSolution,
+ Solution refillableSolution)
{
- var contaminantsFromAbsorbent = _solutionContainerSystem.SplitSolutionWithout(absorbentSoln, component.PickupAmount, PuddleSystem.EvaporationReagents);
+ var contaminantsFromAbsorbent = absorbentSolution.SplitSolutionWithout(component.PickupAmount, PuddleSystem.EvaporationReagents);
+ _solutionSystem.UpdateChemicals(used, absorbentSolution, true);
- var absorbentSolution = absorbentSoln.Comp.Solution;
if (contaminantsFromAbsorbent.Volume == FixedPoint2.Zero && absorbentSolution.AvailableVolume == FixedPoint2.Zero)
{
// Nothing to transfer to refillable and no room to absorb anything extra
component.PickupAmount :
absorbentSolution.AvailableVolume;
- var refillableSolution = refillableSoln.Comp.Solution;
var waterFromRefillable = refillableSolution.SplitSolutionWithOnly(waterPulled, PuddleSystem.EvaporationReagents);
- _solutionContainerSystem.UpdateChemicals(refillableSoln);
+ _solutionSystem.UpdateChemicals(target, refillableSolution);
if (waterFromRefillable.Volume == FixedPoint2.Zero && contaminantsFromAbsorbent.Volume == FixedPoint2.Zero)
{
if (waterFromRefillable.Volume > FixedPoint2.Zero)
{
// transfer water to absorbent
- _solutionContainerSystem.TryAddSolution(absorbentSoln, waterFromRefillable);
+ _solutionSystem.TryAddSolution(used, absorbentSolution, waterFromRefillable);
anyTransferOccurred = true;
}
{
// transfer as much contaminants to refillable as will fit
var contaminantsForRefillable = contaminantsFromAbsorbent.SplitSolution(refillableSolution.AvailableVolume);
- _solutionContainerSystem.TryAddSolution(refillableSoln, contaminantsForRefillable);
+ _solutionSystem.TryAddSolution(target, refillableSolution, contaminantsForRefillable);
anyTransferOccurred = true;
}
// absorb everything that did not fit in the refillable back by the absorbent
- _solutionContainerSystem.TryAddSolution(absorbentSoln, contaminantsFromAbsorbent);
+ _solutionSystem.TryAddSolution(used, absorbentSolution, contaminantsFromAbsorbent);
}
return anyTransferOccurred;
/// <summary>
/// Logic for an absorbing entity interacting with a puddle.
/// </summary>
- private bool TryPuddleInteract(EntityUid user, EntityUid used, EntityUid target, AbsorbentComponent absorber, Entity<SolutionComponent> absorberSoln)
+ private bool TryPuddleInteract(EntityUid user, EntityUid used, EntityUid target, AbsorbentComponent absorber, Solution absorberSoln)
{
if (!TryComp(target, out PuddleComponent? puddle))
return false;
- if (!_solutionContainerSystem.ResolveSolution(target, puddle.SolutionName, ref puddle.Solution, out var puddleSolution) || puddleSolution.Volume <= 0)
+ if (!_solutionSystem.TryGetSolution(target, puddle.SolutionName, out var puddleSoln) || puddleSoln.Volume <= 0)
return false;
// Check if the puddle has any non-evaporative reagents
- if (_puddleSystem.CanFullyEvaporate(puddleSolution))
+ if (_puddleSystem.CanFullyEvaporate(puddleSoln))
{
_popups.PopupEntity(Loc.GetString("mopping-system-puddle-evaporate", ("target", target)), user, user);
return true;
}
// Check if we have any evaporative reagents on our absorber to transfer
- var absorberSolution = absorberSoln.Comp.Solution;
- var available = absorberSolution.GetTotalPrototypeQuantity(PuddleSystem.EvaporationReagents);
+ var available = absorberSoln.GetTotalPrototypeQuantity(PuddleSystem.EvaporationReagents);
// No material
if (available == FixedPoint2.Zero)
var transferMax = absorber.PickupAmount;
var transferAmount = available > transferMax ? transferMax : available;
- var puddleSplit = puddleSolution.SplitSolutionWithout(transferAmount, PuddleSystem.EvaporationReagents);
- var absorberSplit = absorberSolution.SplitSolutionWithOnly(puddleSplit.Volume, PuddleSystem.EvaporationReagents);
+ var puddleSplit = puddleSoln.SplitSolutionWithout(transferAmount, PuddleSystem.EvaporationReagents);
+ var absorberSplit = absorberSoln.SplitSolutionWithOnly(puddleSplit.Volume, PuddleSystem.EvaporationReagents);
// Do tile reactions first
var coordinates = Transform(target).Coordinates;
_puddleSystem.DoTileReactions(mapGrid.GetTileRef(coordinates), absorberSplit);
}
- _solutionContainerSystem.AddSolution(puddle.Solution.Value, absorberSplit);
- _solutionContainerSystem.AddSolution(absorberSoln, puddleSplit);
+ puddleSoln.AddSolution(absorberSplit, _prototype);
+ absorberSoln.AddSolution(puddleSplit, _prototype);
+ _solutionSystem.UpdateChemicals(used, absorberSoln);
+ _solutionSystem.UpdateChemicals(target, puddleSoln);
_audio.PlayPvs(absorber.PickupSound, target);
_useDelay.BeginDelay(used);
-using Content.Server.Chemistry.Containers.EntitySystems;
using Content.Server.DoAfter;
using Content.Server.Fluids.Components;
using Content.Server.Popups;
using Content.Shared.Audio;
using Content.Shared.Chemistry.Components.SolutionManager;
+using Content.Shared.Chemistry.EntitySystems;
using Content.Shared.Database;
using Content.Shared.DoAfter;
using Content.Shared.Examine;
using Content.Shared.Interaction;
using Content.Shared.Tag;
using Content.Shared.Verbs;
+using Content.Shared.Fluids.Components;
+using Robust.Shared.Audio;
using Robust.Shared.Audio.Systems;
using Robust.Shared.Collections;
-using Robust.Shared.Prototypes;
using Robust.Shared.Random;
using Robust.Shared.Utility;
public sealed class DrainSystem : SharedDrainSystem
{
[Dependency] private readonly EntityLookupSystem _lookup = default!;
- [Dependency] private readonly SolutionContainerSystem _solutionContainerSystem = default!;
+ [Dependency] private readonly SolutionContainerSystem _solutionSystem = default!;
[Dependency] private readonly SharedAmbientSoundSystem _ambientSoundSystem = default!;
[Dependency] private readonly SharedAudioSystem _audioSystem = default!;
[Dependency] private readonly PopupSystem _popupSystem = default!;
[Dependency] private readonly DoAfterSystem _doAfterSystem = default!;
[Dependency] private readonly PuddleSystem _puddleSystem = default!;
[Dependency] private readonly IRobustRandom _random = default!;
- [Dependency] private readonly IPrototypeManager _prototypeManager = default!;
public override void Initialize()
{
SubscribeLocalEvent<DrainComponent, DrainDoAfterEvent>(OnDoAfter);
}
- private void AddEmptyVerb(Entity<DrainComponent> entity, ref GetVerbsEvent<Verb> args)
+ private void AddEmptyVerb(EntityUid uid, DrainComponent component, GetVerbsEvent<Verb> args)
{
if (!args.CanAccess || !args.CanInteract || args.Using == null)
return;
!TryComp(args.Target, out DrainComponent? drain))
return;
- var used = args.Using.Value;
- var target = args.Target;
Verb verb = new()
{
- Text = Loc.GetString("drain-component-empty-verb-inhand", ("object", Name(used))),
+ Text = Loc.GetString("drain-component-empty-verb-inhand", ("object", Name(args.Using.Value))),
Act = () =>
{
- Empty(used, spillable, target, drain);
+ Empty(args.Using.Value, spillable, args.Target, drain);
},
Impact = LogImpact.Low,
Icon = new SpriteSpecifier.Texture(new ResPath("/Textures/Interface/VerbIcons/eject.svg.192dpi.png"))
private void Empty(EntityUid container, SpillableComponent spillable, EntityUid target, DrainComponent drain)
{
// Find the solution in the container that is emptied
- if (!_solutionContainerSystem.TryGetDrainableSolution(container, out var containerSoln, out var containerSolution) || containerSolution.Volume == FixedPoint2.Zero)
+ if (!_solutionSystem.TryGetDrainableSolution(container, out var containerSolution) ||
+ containerSolution.Volume == FixedPoint2.Zero)
{
_popupSystem.PopupEntity(
Loc.GetString("drain-component-empty-verb-using-is-empty-message", ("object", container)),
}
// try to find the drain's solution
- if (!_solutionContainerSystem.ResolveSolution(target, DrainComponent.SolutionName, ref drain.Solution, out var drainSolution))
+ if (!_solutionSystem.TryGetSolution(target, DrainComponent.SolutionName, out var drainSolution))
{
return;
}
// Try to transfer as much solution as possible to the drain
- var transferSolution = _solutionContainerSystem.SplitSolution(containerSoln.Value,
+ var transferSolution = _solutionSystem.SplitSolution(container, containerSolution,
FixedPoint2.Min(containerSolution.Volume, drainSolution.AvailableVolume));
- _solutionContainerSystem.TryAddSolution(drain.Solution.Value, transferSolution);
+ _solutionSystem.TryAddSolution(target, drainSolution, transferSolution);
_audioSystem.PlayPvs(drain.ManualDrainSound, target);
_ambientSoundSystem.SetAmbience(target, true);
var managerQuery = GetEntityQuery<SolutionContainerManagerComponent>();
var xformQuery = GetEntityQuery<TransformComponent>();
var puddleQuery = GetEntityQuery<PuddleComponent>();
- var puddles = new ValueList<(Entity<PuddleComponent> Entity, string Solution)>();
+ var puddles = new ValueList<(EntityUid Entity, string Solution)>();
var query = EntityQueryEnumerator<DrainComponent>();
while (query.MoveNext(out var uid, out var drain))
continue;
// Best to do this one every second rather than once every tick...
- if (!_solutionContainerSystem.ResolveSolution((uid, manager), DrainComponent.SolutionName, ref drain.Solution, out var drainSolution))
+ _solutionSystem.TryGetSolution(uid, DrainComponent.SolutionName, out var drainSolution, manager);
+
+ if (drainSolution is null)
continue;
if (drainSolution.AvailableVolume <= 0)
}
// Remove a bit from the buffer
- _solutionContainerSystem.SplitSolution(drain.Solution.Value, (drain.UnitsDestroyedPerSecond * drain.DrainFrequency));
+ _solutionSystem.SplitSolution(uid, drainSolution, (drain.UnitsDestroyedPerSecond * drain.DrainFrequency));
// This will ensure that UnitsPerSecond is per second...
var amount = drain.UnitsPerSecond * drain.DrainFrequency;
// and these are placed by mappers and not buildable/movable so shouldnt really be a problem...
if (puddleQuery.TryGetComponent(entity, out var puddle))
{
- puddles.Add(((entity, puddle), puddle.SolutionName));
+ puddles.Add((entity, puddle.SolutionName));
}
}
{
// Queue the solution deletion if it's empty. EvaporationSystem might also do this
// but queuedelete should be pretty safe.
- if (!_solutionContainerSystem.ResolveSolution(puddle.Owner, solution, ref puddle.Comp.Solution, out var puddleSolution))
+ if (!_solutionSystem.TryGetSolution(puddle, solution, out var puddleSolution))
{
EntityManager.QueueDeleteEntity(puddle);
continue;
// the drain component's units per second adjusted for # of puddles
// the puddle's remaining volume (making it cleanly zero)
// the drain's remaining volume in its buffer.
- var transferSolution = _solutionContainerSystem.SplitSolution(puddle.Comp.Solution.Value,
+ var transferSolution = _solutionSystem.SplitSolution(puddle, puddleSolution,
FixedPoint2.Min(FixedPoint2.New(amount), puddleSolution.Volume, drainSolution.AvailableVolume));
- drainSolution.AddSolution(transferSolution, _prototypeManager);
+ _solutionSystem.TryAddSolution(uid, drainSolution, transferSolution);
if (puddleSolution.Volume <= 0)
{
QueueDel(puddle);
}
}
-
- _solutionContainerSystem.UpdateChemicals(drain.Solution.Value);
}
}
- private void OnExamined(Entity<DrainComponent> entity, ref ExaminedEvent args)
+ private void OnExamined(EntityUid uid, DrainComponent component, ExaminedEvent args)
{
if (!args.IsInDetailsRange ||
- !HasComp<SolutionContainerManagerComponent>(entity) ||
- !_solutionContainerSystem.ResolveSolution(entity.Owner, DrainComponent.SolutionName, ref entity.Comp.Solution, out var drainSolution))
+ !HasComp<SolutionContainerManagerComponent>(uid) ||
+ !_solutionSystem.TryGetSolution(uid, DrainComponent.SolutionName, out var drainSolution))
{
return;
}
args.Message.AddMarkup($"\n\n{text}");
}
- private void OnInteract(Entity<DrainComponent> entity, ref AfterInteractUsingEvent args)
+ private void OnInteract(EntityUid uid, DrainComponent component, InteractEvent args)
{
if (!args.CanReach || args.Target == null ||
!_tagSystem.HasTag(args.Used, DrainComponent.PlungerTag) ||
- !_solutionContainerSystem.ResolveSolution(args.Target.Value, DrainComponent.SolutionName, ref entity.Comp.Solution, out var drainSolution))
+ !_solutionSystem.TryGetSolution(args.Target.Value, DrainComponent.SolutionName, out var drainSolution))
{
return;
}
return;
}
- _audioSystem.PlayPvs(entity.Comp.PlungerSound, entity);
+ _audioSystem.PlayPvs(component.PlungerSound, uid);
- var doAfterArgs = new DoAfterArgs(EntityManager, args.User, entity.Comp.UnclogDuration, new DrainDoAfterEvent(), entity, args.Target, args.Used)
+ var doAfterArgs = new DoAfterArgs(EntityManager, args.User, component.UnclogDuration, new DrainDoAfterEvent(),uid, args.Target, args.Used)
{
BreakOnTargetMove = true,
BreakOnUserMove = true,
_doAfterSystem.TryStartDoAfter(doAfterArgs);
}
- private void OnDoAfter(Entity<DrainComponent> entity, ref DrainDoAfterEvent args)
+ private void OnDoAfter(EntityUid uid, DrainComponent component, DoAfterEvent args)
{
if (args.Target == null)
return;
- if (!_random.Prob(entity.Comp.UnclogProbability))
+ if (!_random.Prob(component.UnclogProbability))
{
_popupSystem.PopupEntity(Loc.GetString("drain-component-unclog-fail", ("object", args.Target.Value)), args.Target.Value);
return;
}
- if (!_solutionContainerSystem.ResolveSolution(args.Target.Value, DrainComponent.SolutionName, ref entity.Comp.Solution))
+ if (!_solutionSystem.TryGetSolution(args.Target.Value, DrainComponent.SolutionName,
+ out var drainSolution))
{
return;
}
- _solutionContainerSystem.RemoveAllSolution(entity.Comp.Solution.Value);
- _audioSystem.PlayPvs(entity.Comp.UnclogSound, args.Target.Value);
+ _solutionSystem.RemoveAllSolution(args.Target.Value, drainSolution);
+ _audioSystem.PlayPvs(component.UnclogSound, args.Target.Value);
_popupSystem.PopupEntity(Loc.GetString("drain-component-unclog-success", ("object", args.Target.Value)), args.Target.Value);
}
}
public static string[] EvaporationReagents = new[] { Water, SoapyWater };
- private void OnEvaporationMapInit(Entity<EvaporationComponent> entity, ref MapInitEvent args)
+ private void OnEvaporationMapInit(EntityUid uid, EvaporationComponent component, MapInitEvent args)
{
- entity.Comp.NextTick = _timing.CurTime + EvaporationCooldown;
+ component.NextTick = _timing.CurTime + EvaporationCooldown;
}
private void UpdateEvaporation(EntityUid uid, Solution solution)
evaporation.NextTick += EvaporationCooldown;
- if (!_solutionContainerSystem.ResolveSolution(uid, puddle.SolutionName, ref puddle.Solution, out var puddleSolution))
+ if (!_solutionContainerSystem.TryGetSolution(uid, puddle.SolutionName, out var puddleSolution))
continue;
var reagentTick = evaporation.EvaporationAmount * EvaporationCooldown.TotalSeconds;
-using Content.Server.Chemistry.Containers.EntitySystems;
+using Content.Server.Chemistry.EntitySystems;
using Content.Server.Fluids.Components;
using Content.Server.Nutrition.EntitySystems;
using Content.Shared.Chemistry.Components;
SubscribeLocalEvent<SpillableComponent, MeleeHitEvent>(SplashOnMeleeHit, after: new[] { typeof(OpenableSystem) });
SubscribeLocalEvent<SpillableComponent, GetVerbsEvent<Verb>>(AddSpillVerb);
SubscribeLocalEvent<SpillableComponent, GotEquippedEvent>(OnGotEquipped);
- SubscribeLocalEvent<SpillableComponent, SolutionContainerOverflowEvent>(OnOverflow);
+ SubscribeLocalEvent<SpillableComponent, SolutionOverflowEvent>(OnOverflow);
SubscribeLocalEvent<SpillableComponent, SpillDoAfterEvent>(OnDoAfter);
SubscribeLocalEvent<SpillableComponent, AttemptPacifiedThrowEvent>(OnAttemptPacifiedThrow);
}
- private void OnExamined(Entity<SpillableComponent> entity, ref ExaminedEvent args)
+ private void OnExamined(EntityUid uid, SpillableComponent component, ExaminedEvent args)
{
args.PushMarkup(Loc.GetString("spill-examine-is-spillable"));
- if (HasComp<MeleeWeaponComponent>(entity))
+ if (HasComp<MeleeWeaponComponent>(uid))
args.PushMarkup(Loc.GetString("spill-examine-spillable-weapon"));
}
- private void OnOverflow(Entity<SpillableComponent> entity, ref SolutionContainerOverflowEvent args)
+ private void OnOverflow(EntityUid uid, SpillableComponent component, ref SolutionOverflowEvent args)
{
if (args.Handled)
return;
- TrySpillAt(Transform(entity).Coordinates, args.Overflow, out _);
+ TrySpillAt(Transform(uid).Coordinates, args.Overflow, out _);
args.Handled = true;
}
- private void SplashOnMeleeHit(Entity<SpillableComponent> entity, ref MeleeHitEvent args)
+ private void SplashOnMeleeHit(EntityUid uid, SpillableComponent component, MeleeHitEvent args)
{
if (args.Handled)
return;
// If this also has solution transfer, then assume the transfer amount is how much we want to spill.
// Otherwise let's say they want to spill a quarter of its max volume.
- if (!_solutionContainerSystem.TryGetDrainableSolution(entity.Owner, out var soln, out var solution))
+ if (!_solutionContainerSystem.TryGetDrainableSolution(uid, out var solution))
return;
var hitCount = args.HitEntities.Count;
var totalSplit = FixedPoint2.Min(solution.MaxVolume * 0.25, solution.Volume);
- if (TryComp<SolutionTransferComponent>(entity, out var transfer))
+ if (TryComp<SolutionTransferComponent>(uid, out var transfer))
{
totalSplit = FixedPoint2.Min(transfer.TransferAmount, solution.Volume);
}
// a little lame, but reagent quantity is not very balanced and we don't want people
// spilling like 100u of reagent on someone at once!
- totalSplit = FixedPoint2.Min(totalSplit, entity.Comp.MaxMeleeSpillAmount);
+ totalSplit = FixedPoint2.Min(totalSplit, component.MaxMeleeSpillAmount);
if (totalSplit == 0)
return;
continue;
}
- var splitSolution = _solutionContainerSystem.SplitSolution(soln.Value, totalSplit / hitCount);
+ var splitSolution = _solutionContainerSystem.SplitSolution(uid, solution, totalSplit / hitCount);
- _adminLogger.Add(LogType.MeleeHit, $"{ToPrettyString(args.User)} splashed {SolutionContainerSystem.ToPrettyString(splitSolution):solution} from {ToPrettyString(entity.Owner):entity} onto {ToPrettyString(hit):target}");
+ _adminLogger.Add(LogType.MeleeHit, $"{ToPrettyString(args.User)} splashed {SolutionContainerSystem.ToPrettyString(splitSolution):solution} from {ToPrettyString(uid):entity} onto {ToPrettyString(hit):target}");
_reactive.DoEntityReaction(hit, splitSolution, ReactionMethod.Touch);
_popups.PopupEntity(
- Loc.GetString("spill-melee-hit-attacker", ("amount", totalSplit / hitCount), ("spillable", entity.Owner),
+ Loc.GetString("spill-melee-hit-attacker", ("amount", totalSplit / hitCount), ("spillable", uid),
("target", Identity.Entity(hit, EntityManager))),
hit, args.User);
_popups.PopupEntity(
- Loc.GetString("spill-melee-hit-others", ("attacker", args.User), ("spillable", entity.Owner),
+ Loc.GetString("spill-melee-hit-others", ("attacker", args.User), ("spillable", uid),
("target", Identity.Entity(hit, EntityManager))),
hit, Filter.PvsExcept(args.User), true, PopupType.SmallCaution);
}
}
- private void OnGotEquipped(Entity<SpillableComponent> entity, ref GotEquippedEvent args)
+ private void OnGotEquipped(EntityUid uid, SpillableComponent component, GotEquippedEvent args)
{
- if (!entity.Comp.SpillWorn)
+ if (!component.SpillWorn)
return;
- if (!TryComp(entity, out ClothingComponent? clothing))
+ if (!TryComp(uid, out ClothingComponent? clothing))
return;
// check if entity was actually used as clothing
if (!isCorrectSlot)
return;
- if (!_solutionContainerSystem.TryGetSolution(entity.Owner, entity.Comp.SolutionName, out var soln, out var solution))
+ if (!_solutionContainerSystem.TryGetSolution(uid, component.SolutionName, out var solution))
return;
if (solution.Volume == 0)
return;
// spill all solution on the player
- var drainedSolution = _solutionContainerSystem.Drain(entity.Owner, soln.Value, solution.Volume);
- TrySplashSpillAt(entity.Owner, Transform(args.Equipee).Coordinates, drainedSolution, out _);
+ var drainedSolution = _solutionContainerSystem.Drain(uid, solution, solution.Volume);
+ TrySplashSpillAt(uid, Transform(args.Equipee).Coordinates, drainedSolution, out _);
}
- private void SpillOnLand(Entity<SpillableComponent> entity, ref LandEvent args)
+ private void SpillOnLand(EntityUid uid, SpillableComponent component, ref LandEvent args)
{
- if (!_solutionContainerSystem.TryGetSolution(entity.Owner, entity.Comp.SolutionName, out var soln, out var solution))
+ if (!_solutionContainerSystem.TryGetSolution(uid, component.SolutionName, out var solution))
return;
- if (_openable.IsClosed(entity.Owner))
+ if (_openable.IsClosed(uid))
return;
if (args.User != null)
{
_adminLogger.Add(LogType.Landed,
- $"{ToPrettyString(entity.Owner):entity} spilled a solution {SolutionContainerSystem.ToPrettyString(solution):solution} on landing");
+ $"{ToPrettyString(uid):entity} spilled a solution {SolutionContainerSystem.ToPrettyString(solution):solution} on landing");
}
- var drainedSolution = _solutionContainerSystem.Drain(entity.Owner, soln.Value, solution.Volume);
- TrySplashSpillAt(entity.Owner, Transform(entity).Coordinates, drainedSolution, out _);
+ var drainedSolution = _solutionContainerSystem.Drain(uid, solution, solution.Volume);
+ TrySplashSpillAt(uid, Transform(uid).Coordinates, drainedSolution, out _);
}
/// <summary>
return;
// Don’t care about empty containers.
- if (!_solutionContainerSystem.TryGetSolution(ent.Owner, ent.Comp.SolutionName, out _, out var solution) || solution.Volume <= 0)
+ if (!_solutionContainerSystem.TryGetSolution(ent, ent.Comp.SolutionName, out var solution))
return;
args.Cancel("pacified-cannot-throw-spill");
}
- private void AddSpillVerb(Entity<SpillableComponent> entity, ref GetVerbsEvent<Verb> args)
+ private void AddSpillVerb(EntityUid uid, SpillableComponent component, GetVerbsEvent<Verb> args)
{
if (!args.CanAccess || !args.CanInteract)
return;
- if (!_solutionContainerSystem.TryGetSolution(args.Target, entity.Comp.SolutionName, out var soln, out var solution))
+ if (!_solutionContainerSystem.TryGetSolution(args.Target, component.SolutionName, out var solution))
return;
if (_openable.IsClosed(args.Target))
};
// TODO VERB ICONS spill icon? pouring out a glass/beaker?
- if (entity.Comp.SpillDelay == null)
+ if (component.SpillDelay == null)
{
- var target = args.Target;
verb.Act = () =>
{
- var puddleSolution = _solutionContainerSystem.SplitSolution(soln.Value, solution.Volume);
- TrySpillAt(Transform(target).Coordinates, puddleSolution, out _);
+ var puddleSolution = _solutionContainerSystem.SplitSolution(args.Target,
+ solution, solution.Volume);
+ TrySpillAt(Transform(args.Target).Coordinates, puddleSolution, out _);
};
}
else
{
- var user = args.User;
verb.Act = () =>
{
- _doAfterSystem.TryStartDoAfter(new DoAfterArgs(EntityManager, user, entity.Comp.SpillDelay ?? 0, new SpillDoAfterEvent(), entity.Owner, target: entity.Owner)
+ _doAfterSystem.TryStartDoAfter(new DoAfterArgs(EntityManager, args.User, component.SpillDelay ?? 0, new SpillDoAfterEvent(), uid, target: uid)
{
BreakOnTargetMove = true,
BreakOnUserMove = true,
args.Verbs.Add(verb);
}
- private void OnDoAfter(Entity<SpillableComponent> entity, ref SpillDoAfterEvent args)
+ private void OnDoAfter(EntityUid uid, SpillableComponent component, DoAfterEvent args)
{
if (args.Handled || args.Cancelled || args.Args.Target == null)
return;
//solution gone by other means before doafter completes
- if (!_solutionContainerSystem.TryGetDrainableSolution(entity.Owner, out var soln, out var solution) || solution.Volume == 0)
+ if (!_solutionContainerSystem.TryGetDrainableSolution(uid, out var solution) || solution.Volume == 0)
return;
- var puddleSolution = _solutionContainerSystem.SplitSolution(soln.Value, solution.Volume);
- TrySpillAt(Transform(entity).Coordinates, puddleSolution, out _);
+ var puddleSolution = _solutionContainerSystem.SplitSolution(uid, solution, solution.Volume);
+ TrySpillAt(Transform(uid).Coordinates, puddleSolution, out _);
args.Handled = true;
}
}
+using Content.Server.Fluids.Components;
using Content.Shared.Chemistry.Components;
using Content.Shared.DragDrop;
using Content.Shared.FixedPoint;
using Content.Shared.Fluids;
+using Content.Shared.Fluids.Components;
namespace Content.Server.Fluids.EntitySystems;
SubscribeLocalEvent<RefillableSolutionComponent, DragDropDraggedEvent>(OnRefillableDragged);
}
- private void OnRefillableDragged(Entity<RefillableSolutionComponent> entity, ref DragDropDraggedEvent args)
+ private void OnRefillableDragged(EntityUid uid, RefillableSolutionComponent component, ref DragDropDraggedEvent args)
{
- if (!_solutionContainerSystem.TryGetSolution(entity.Owner, entity.Comp.Solution, out var soln, out var solution) || solution.Volume == FixedPoint2.Zero)
+ _solutionContainerSystem.TryGetSolution(uid, component.Solution, out var solution);
+
+ if (solution?.Volume == FixedPoint2.Zero)
{
- _popups.PopupEntity(Loc.GetString("mopping-system-empty", ("used", entity.Owner)), entity, args.User);
+ _popups.PopupEntity(Loc.GetString("mopping-system-empty", ("used", uid)), uid, args.User);
return;
}
// Dump reagents into DumpableSolution
if (TryComp<DumpableSolutionComponent>(args.Target, out var dump))
{
- if (!_solutionContainerSystem.TryGetDumpableSolution((args.Target, dump, null), out var dumpableSoln, out var dumpableSolution))
+ _solutionContainerSystem.TryGetDumpableSolution(args.Target, out var dumpableSolution, dump);
+ if (dumpableSolution == null || solution == null)
return;
bool success = true;
if (dump.Unlimited)
{
- var split = _solutionContainerSystem.SplitSolution(soln.Value, solution.Volume);
+ var split = _solutionContainerSystem.SplitSolution(uid, solution, solution.Volume);
dumpableSolution.AddSolution(split, _prototypeManager);
}
else
{
- var split = _solutionContainerSystem.SplitSolution(soln.Value, dumpableSolution.AvailableVolume);
- success = _solutionContainerSystem.TryAddSolution(dumpableSoln.Value, split);
+ var split = _solutionContainerSystem.SplitSolution(uid, solution, dumpableSolution.AvailableVolume);
+ success = _solutionContainerSystem.TryAddSolution(args.Target, dumpableSolution, split);
}
if (success)
return;
}
+ TryComp<DrainableSolutionComponent>(args.Target, out var drainable);
+
+ _solutionContainerSystem.TryGetDrainableSolution(args.Target, out var drainableSolution, drainable);
+
// Take reagents from target
- if (!TryComp<DrainableSolutionComponent>(args.Target, out var drainable))
+ if (drainable != null)
{
- if (!_solutionContainerSystem.TryGetDrainableSolution((args.Target, drainable, null), out var drainableSolution, out _))
+ if (drainableSolution == null || solution == null)
return;
- var split = _solutionContainerSystem.SplitSolution(drainableSolution.Value, solution.AvailableVolume);
+ var split = _solutionContainerSystem.SplitSolution(args.Target, drainableSolution, solution.AvailableVolume);
- if (_solutionContainerSystem.TryAddSolution(soln.Value, split))
+ if (_solutionContainerSystem.TryAddSolution(uid, solution, split))
{
- _audio.PlayPvs(AbsorbentComponent.DefaultTransferSound, entity);
+ _audio.PlayPvs(AbsorbentComponent.DefaultTransferSound, uid);
}
else
{
- _popups.PopupEntity(Loc.GetString("mopping-system-full", ("used", entity.Owner)), entity, args.User);
+ _popups.PopupEntity(Loc.GetString("mopping-system-full", ("used", uid)), uid, args.User);
}
}
}
using Content.Server.Administration.Logs;
-using Content.Server.Chemistry.Containers.EntitySystems;
using Content.Server.DoAfter;
using Content.Server.Fluids.Components;
using Content.Server.Spreader;
using Content.Shared.Slippery;
using Content.Shared.StepTrigger.Components;
using Content.Shared.StepTrigger.Systems;
-using Robust.Server.Audio;
+using Robust.Server.GameObjects;
+using Robust.Shared.Audio;
using Robust.Shared.Map;
using Robust.Shared.Map.Components;
using Robust.Shared.Player;
using Robust.Shared.Prototypes;
using Robust.Shared.Random;
using Robust.Shared.Timing;
+using Content.Shared.Movement.Components;
+using Content.Shared.Movement.Systems;
+using Content.Shared.Maps;
+using Content.Shared.Effects;
+using Robust.Server.Audio;
namespace Content.Server.Fluids.EntitySystems;
// Shouldn't need re-anchoring.
SubscribeLocalEvent<PuddleComponent, AnchorStateChangedEvent>(OnAnchorChanged);
SubscribeLocalEvent<PuddleComponent, ExaminedEvent>(HandlePuddleExamined);
- SubscribeLocalEvent<PuddleComponent, SolutionContainerChangedEvent>(OnSolutionUpdate);
+ SubscribeLocalEvent<PuddleComponent, SolutionChangedEvent>(OnSolutionUpdate);
SubscribeLocalEvent<PuddleComponent, ComponentInit>(OnPuddleInit);
SubscribeLocalEvent<PuddleComponent, SpreadNeighborsEvent>(OnPuddleSpread);
SubscribeLocalEvent<PuddleComponent, SlipEvent>(OnPuddleSlip);
InitializeTransfers();
}
- private void OnPuddleSpread(Entity<PuddleComponent> entity, ref SpreadNeighborsEvent args)
+ private void OnPuddleSpread(EntityUid uid, PuddleComponent component, ref SpreadNeighborsEvent args)
{
- var overflow = GetOverflowSolution(entity.Owner, entity.Comp);
+ var overflow = GetOverflowSolution(uid, component);
if (overflow.Volume == FixedPoint2.Zero)
{
- RemCompDeferred<ActiveEdgeSpreaderComponent>(entity);
+ RemCompDeferred<ActiveEdgeSpreaderComponent>(uid);
return;
}
foreach (var neighbor in args.Neighbors)
{
if (!puddleQuery.TryGetComponent(neighbor, out var puddle) ||
- !_solutionContainerSystem.ResolveSolution(neighbor, puddle.SolutionName, ref puddle.Solution, out var neighborSolution) ||
+ !_solutionContainerSystem.TryGetSolution(neighbor, puddle.SolutionName, out var neighborSolution) ||
CanFullyEvaporate(neighborSolution))
{
continue;
var split = overflow.SplitSolution(remaining);
- if (!_solutionContainerSystem.TryAddSolution(puddle.Solution.Value, split))
+ if (!_solutionContainerSystem.TryAddSolution(neighbor, neighborSolution, split))
continue;
args.Updates--;
if (overflow.Volume == FixedPoint2.Zero)
{
- RemCompDeferred<ActiveEdgeSpreaderComponent>(entity);
+ RemCompDeferred<ActiveEdgeSpreaderComponent>(uid);
return;
}
}
break;
}
- RemCompDeferred<ActiveEdgeSpreaderComponent>(entity);
+ RemCompDeferred<ActiveEdgeSpreaderComponent>(uid);
return;
}
{
// Overflow to neighbours (unless it's pure water)
if (!puddleQuery.TryGetComponent(neighbor, out var puddle) ||
- !_solutionContainerSystem.ResolveSolution(neighbor, puddle.SolutionName, ref puddle.Solution, out var neighborSolution) ||
+ !_solutionContainerSystem.TryGetSolution(neighbor, puddle.SolutionName, out var neighborSolution) ||
CanFullyEvaporate(neighborSolution))
{
continue;
var split = overflow.SplitSolution(spillPerNeighbor);
- if (!_solutionContainerSystem.TryAddSolution(puddle.Solution.Value, split))
+ if (!_solutionContainerSystem.TryAddSolution(neighbor, neighborSolution, split))
continue;
EnsureComp<ActiveEdgeSpreaderComponent>(neighbor);
}
// Add the remainder back
- if (_solutionContainerSystem.ResolveSolution(entity.Owner, entity.Comp.SolutionName, ref entity.Comp.Solution))
+ if (_solutionContainerSystem.TryGetSolution(uid, component.SolutionName, out var puddleSolution))
{
- _solutionContainerSystem.TryAddSolution(entity.Comp.Solution.Value, overflow);
+ _solutionContainerSystem.TryAddSolution(uid, puddleSolution, overflow);
}
}
- private void OnPuddleSlip(Entity<PuddleComponent> entity, ref SlipEvent args)
+ private void OnPuddleSlip(EntityUid uid, PuddleComponent component, ref SlipEvent args)
{
// Reactive entities have a chance to get a touch reaction from slipping on a puddle
// (i.e. it is implied they fell face first onto it or something)
if (!_random.Prob(0.5f))
return;
- if (!_solutionContainerSystem.ResolveSolution(entity.Owner, entity.Comp.SolutionName, ref entity.Comp.Solution, out var solution))
+ if (!_solutionContainerSystem.TryGetSolution(uid, component.SolutionName, out var solution))
return;
- _popups.PopupEntity(Loc.GetString("puddle-component-slipped-touch-reaction", ("puddle", entity.Owner)),
+ _popups.PopupEntity(Loc.GetString("puddle-component-slipped-touch-reaction", ("puddle", uid)),
args.Slipped, args.Slipped, PopupType.SmallCaution);
// Take 15% of the puddle solution
- var splitSol = _solutionContainerSystem.SplitSolution(entity.Comp.Solution.Value, solution.Volume * 0.15f);
+ var splitSol = _solutionContainerSystem.SplitSolution(uid, solution, solution.Volume * 0.15f);
_reactive.DoEntityReaction(args.Slipped, splitSol, ReactionMethod.Touch);
}
TickEvaporation();
}
- private void OnPuddleInit(Entity<PuddleComponent> entity, ref ComponentInit args)
+ private void OnPuddleInit(EntityUid uid, PuddleComponent component, ComponentInit args)
{
- _solutionContainerSystem.EnsureSolution(entity.Owner, entity.Comp.SolutionName, FixedPoint2.New(PuddleVolume), out _);
+ _solutionContainerSystem.EnsureSolution(uid, component.SolutionName, FixedPoint2.New(PuddleVolume), out _);
}
- private void OnSolutionUpdate(Entity<PuddleComponent> entity, ref SolutionContainerChangedEvent args)
+ private void OnSolutionUpdate(EntityUid uid, PuddleComponent component, SolutionChangedEvent args)
{
- if (args.SolutionId != entity.Comp.SolutionName)
+ if (args.Solution.Name != component.SolutionName)
return;
if (args.Solution.Volume <= 0)
{
- _deletionQueue.Add(entity);
+ _deletionQueue.Add(uid);
return;
}
- _deletionQueue.Remove(entity);
- UpdateSlip(entity, entity.Comp, args.Solution);
- UpdateSlow(entity, args.Solution);
- UpdateEvaporation(entity, args.Solution);
- UpdateAppearance(entity, entity.Comp);
+ _deletionQueue.Remove(uid);
+ UpdateSlip(uid, component, args.Solution);
+ UpdateSlow(uid, args.Solution);
+ UpdateEvaporation(uid, args.Solution);
+ UpdateAppearance(uid, component);
}
private void UpdateAppearance(EntityUid uid, PuddleComponent? puddleComponent = null, AppearanceComponent? appearance = null)
var volume = FixedPoint2.Zero;
Color color = Color.White;
- if (_solutionContainerSystem.ResolveSolution(uid, puddleComponent.SolutionName, ref puddleComponent.Solution, out var solution))
+ if (_solutionContainerSystem.TryGetSolution(uid, puddleComponent.SolutionName, out var solution))
{
volume = solution.Volume / puddleComponent.OverflowVolume;
}
}
- private void HandlePuddleExamined(Entity<PuddleComponent> entity, ref ExaminedEvent args)
+ private void HandlePuddleExamined(EntityUid uid, PuddleComponent component, ExaminedEvent args)
{
- if (TryComp<StepTriggerComponent>(entity, out var slippery) && slippery.Active)
+ if (TryComp<StepTriggerComponent>(uid, out var slippery) && slippery.Active)
{
args.PushMarkup(Loc.GetString("puddle-component-examine-is-slipper-text"));
}
- if (HasComp<EvaporationComponent>(entity) &&
- _solutionContainerSystem.ResolveSolution(entity.Owner, entity.Comp.SolutionName, ref entity.Comp.Solution, out var solution))
+ if (HasComp<EvaporationComponent>(uid))
{
- if (CanFullyEvaporate(solution))
+ if (_solutionContainerSystem.TryGetSolution(uid, component.SolutionName, out var solution) &&
+ CanFullyEvaporate(solution))
+ {
args.PushMarkup(Loc.GetString("puddle-component-examine-evaporating"));
- else if (solution.GetTotalPrototypeQuantity(EvaporationReagents) > FixedPoint2.Zero)
+ }
+ else if (solution?.GetTotalPrototypeQuantity(EvaporationReagents) > FixedPoint2.Zero)
+ {
args.PushMarkup(Loc.GetString("puddle-component-examine-evaporating-partial"));
+ }
else
+ {
args.PushMarkup(Loc.GetString("puddle-component-examine-evaporating-no"));
+ }
}
else
+ {
args.PushMarkup(Loc.GetString("puddle-component-examine-evaporating-no"));
+ }
}
- private void OnAnchorChanged(Entity<PuddleComponent> entity, ref AnchorStateChangedEvent args)
+ private void OnAnchorChanged(EntityUid uid, PuddleComponent puddle, ref AnchorStateChangedEvent args)
{
if (!args.Anchored)
- QueueDel(entity);
+ QueueDel(uid);
}
/// <summary>
if (!Resolve(uid, ref puddleComponent))
return FixedPoint2.Zero;
- return _solutionContainerSystem.ResolveSolution(uid, puddleComponent.SolutionName, ref puddleComponent.Solution, out var solution)
+ return _solutionContainerSystem.TryGetSolution(uid, puddleComponent.SolutionName,
+ out var solution)
? solution.Volume
: FixedPoint2.Zero;
}
return false;
if (addedSolution.Volume == 0 ||
- !_solutionContainerSystem.ResolveSolution(puddleUid, puddleComponent.SolutionName, ref puddleComponent.Solution))
+ !_solutionContainerSystem.TryGetSolution(puddleUid, puddleComponent.SolutionName,
+ out var solution))
{
return false;
}
- _solutionContainerSystem.AddSolution(puddleComponent.Solution.Value, addedSolution);
+ solution.AddSolution(addedSolution, _prototypeManager);
+ _solutionContainerSystem.UpdateChemicals(puddleUid, solution, true);
if (checkForOverflow && IsOverflowing(puddleUid, puddleComponent))
{
/// </summary>
public Solution GetOverflowSolution(EntityUid uid, PuddleComponent? puddle = null)
{
- if (!Resolve(uid, ref puddle) || !_solutionContainerSystem.ResolveSolution(uid, puddle.SolutionName, ref puddle.Solution))
+ if (!Resolve(uid, ref puddle) || !_solutionContainerSystem.TryGetSolution(uid, puddle.SolutionName,
+ out var solution))
{
return new Solution(0);
}
// TODO: This is going to fail with struct solutions.
var remaining = puddle.OverflowVolume;
- var split = _solutionContainerSystem.SplitSolution(puddle.Solution.Value, CurrentVolume(uid, puddle) - remaining);
+ var split = _solutionContainerSystem.SplitSolution(uid, solution, CurrentVolume(uid, puddle) - remaining);
return split;
}
+using System.Linq;
using Content.Server.Administration.Logs;
using Content.Server.Body.Components;
using Content.Server.Body.Systems;
-using Content.Server.Chemistry.Containers.EntitySystems;
using Content.Server.Chemistry.ReactionEffects;
using Content.Server.Spreader;
using Content.Shared.Chemistry;
using Robust.Shared.Prototypes;
using Robust.Shared.Random;
using Robust.Shared.Timing;
-using System.Linq;
-
using TimedDespawnComponent = Robust.Shared.Spawners.TimedDespawnComponent;
namespace Content.Server.Fluids.EntitySystems;
[Dependency] private readonly ReactiveSystem _reactive = default!;
[Dependency] private readonly SharedBroadphaseSystem _broadphase = default!;
[Dependency] private readonly SharedPhysicsSystem _physics = default!;
- [Dependency] private readonly SolutionContainerSystem _solutionContainerSystem = default!;
+ [Dependency] private readonly SolutionContainerSystem _solutionSystem = default!;
[Dependency] private readonly TransformSystem _transform = default!;
private EntityQuery<SmokeComponent> _smokeQuery;
SubscribeLocalEvent<SmokeComponent, StartCollideEvent>(OnStartCollide);
SubscribeLocalEvent<SmokeComponent, EndCollideEvent>(OnEndCollide);
SubscribeLocalEvent<SmokeComponent, ReactionAttemptEvent>(OnReactionAttempt);
- SubscribeLocalEvent<SmokeComponent, SolutionRelayEvent<ReactionAttemptEvent>>(OnReactionAttempt);
SubscribeLocalEvent<SmokeComponent, SpreadNeighborsEvent>(OnSmokeSpread);
SubscribeLocalEvent<SmokeAffectedComponent, EntityUnpausedEvent>(OnAffectedUnpaused);
}
}
}
- private void OnStartCollide(Entity<SmokeComponent> entity, ref StartCollideEvent args)
+ private void OnStartCollide(EntityUid uid, SmokeComponent component, ref StartCollideEvent args)
{
if (_smokeAffectedQuery.HasComponent(args.OtherEntity))
return;
var smokeAffected = AddComp<SmokeAffectedComponent>(args.OtherEntity);
- smokeAffected.SmokeEntity = entity;
+ smokeAffected.SmokeEntity = uid;
smokeAffected.NextSecond = _timing.CurTime + TimeSpan.FromSeconds(1);
}
- private void OnEndCollide(Entity<SmokeComponent> entity, ref EndCollideEvent args)
+ private void OnEndCollide(EntityUid uid, SmokeComponent component, ref EndCollideEvent args)
{
// if we are already in smoke, make sure the thing we are exiting is the current smoke we are in.
if (_smokeAffectedQuery.TryGetComponent(args.OtherEntity, out var smokeAffectedComponent))
{
- if (smokeAffectedComponent.SmokeEntity != entity.Owner)
+ if (smokeAffectedComponent.SmokeEntity != uid)
return;
}
- var exists = Exists(entity);
+ var exists = Exists(uid);
if (!TryComp<PhysicsComponent>(args.OtherEntity, out var body))
return;
foreach (var ent in _physics.GetContactingEntities(args.OtherEntity, body))
{
- if (exists && ent == entity.Owner)
+ if (exists && ent == uid)
continue;
if (!_smokeQuery.HasComponent(ent))
RemComp(args.OtherEntity, smokeAffectedComponent);
}
- private void OnAffectedUnpaused(Entity<SmokeAffectedComponent> entity, ref EntityUnpausedEvent args)
+ private void OnAffectedUnpaused(EntityUid uid, SmokeAffectedComponent component, ref EntityUnpausedEvent args)
{
- entity.Comp.NextSecond += args.PausedTime;
+ component.NextSecond += args.PausedTime;
}
- private void OnSmokeSpread(Entity<SmokeComponent> entity, ref SpreadNeighborsEvent args)
+ private void OnSmokeSpread(EntityUid uid, SmokeComponent component, ref SpreadNeighborsEvent args)
{
- if (entity.Comp.SpreadAmount == 0 || !_solutionContainerSystem.ResolveSolution(entity.Owner, SmokeComponent.SolutionName, ref entity.Comp.Solution, out var solution))
+ if (component.SpreadAmount == 0 || !_solutionSystem.TryGetSolution(uid, SmokeComponent.SolutionName, out var solution))
{
- RemCompDeferred<ActiveEdgeSpreaderComponent>(entity);
+ RemCompDeferred<ActiveEdgeSpreaderComponent>(uid);
return;
}
- if (Prototype(entity) is not { } prototype)
+ if (Prototype(uid) is not { } prototype)
{
- RemCompDeferred<ActiveEdgeSpreaderComponent>(entity);
+ RemCompDeferred<ActiveEdgeSpreaderComponent>(uid);
return;
}
if (!args.NeighborFreeTiles.Any())
return;
- TryComp<TimedDespawnComponent>(entity, out var timer);
+ TryComp<TimedDespawnComponent>(uid, out var timer);
// wtf is the logic behind any of this.
- var smokePerSpread = entity.Comp.SpreadAmount / Math.Max(1, args.NeighborFreeTiles.Count);
+ var smokePerSpread = component.SpreadAmount / Math.Max(1, args.NeighborFreeTiles.Count);
foreach (var neighbor in args.NeighborFreeTiles)
{
var coords = neighbor.Grid.GridTileToLocal(neighbor.Tile);
var ent = Spawn(prototype.ID, coords);
var spreadAmount = Math.Max(0, smokePerSpread);
- entity.Comp.SpreadAmount -= args.NeighborFreeTiles.Count();
+ component.SpreadAmount -= args.NeighborFreeTiles.Count();
- StartSmoke(ent, solution.Clone(), timer?.Lifetime ?? entity.Comp.Duration, spreadAmount);
+ StartSmoke(ent, solution.Clone(), timer?.Lifetime ?? component.Duration, spreadAmount);
- if (entity.Comp.SpreadAmount == 0)
+ if (component.SpreadAmount == 0)
{
- RemCompDeferred<ActiveEdgeSpreaderComponent>(entity);
+ RemCompDeferred<ActiveEdgeSpreaderComponent>(uid);
break;
}
}
args.Updates--;
- if (args.NeighborFreeTiles.Count > 0 || args.Neighbors.Count == 0 || entity.Comp.SpreadAmount < 1)
+ if (args.NeighborFreeTiles.Count > 0 || args.Neighbors.Count == 0 || component.SpreadAmount < 1)
return;
// We have no more neighbours to spread to. So instead we will randomly distribute our volume to neighbouring smoke tiles.
continue;
smoke.SpreadAmount++;
- entity.Comp.SpreadAmount--;
+ component.SpreadAmount--;
EnsureComp<ActiveEdgeSpreaderComponent>(neighbor);
- if (entity.Comp.SpreadAmount == 0)
+ if (component.SpreadAmount == 0)
{
- RemCompDeferred<ActiveEdgeSpreaderComponent>(entity);
+ RemCompDeferred<ActiveEdgeSpreaderComponent>(uid);
break;
}
}
}
- private void OnReactionAttempt(Entity<SmokeComponent> entity, ref ReactionAttemptEvent args)
+ private void OnReactionAttempt(EntityUid uid, SmokeComponent component, ReactionAttemptEvent args)
{
- if (args.Cancelled)
+ if (args.Solution.Name != SmokeComponent.SolutionName)
return;
// Prevent smoke/foam fork bombs (smoke creating more smoke).
{
if (effect is AreaReactionEffect)
{
- args.Cancelled = true;
+ args.Cancel();
return;
}
}
}
- private void OnReactionAttempt(Entity<SmokeComponent> entity, ref SolutionRelayEvent<ReactionAttemptEvent> args)
- {
- if (args.Name == SmokeComponent.SolutionName)
- OnReactionAttempt(entity, ref args.Event);
- }
-
/// <summary>
/// Sets up a smoke component for spreading.
/// </summary>
if (!Resolve(smokeUid, ref component))
return;
- if (!_solutionContainerSystem.ResolveSolution(smokeUid, SmokeComponent.SolutionName, ref component.Solution, out var solution) ||
+ if (!_solutionSystem.TryGetSolution(smokeUid, SmokeComponent.SolutionName, out var solution) ||
solution.Contents.Count == 0)
{
return;
}
ReactWithEntity(entity, smokeUid, solution, component);
- UpdateVisuals((smokeUid, component));
+ UpdateVisuals(smokeUid);
}
private void ReactWithEntity(EntityUid entity, EntityUid smokeUid, Solution solution, SmokeComponent? component = null)
if (!TryComp<BloodstreamComponent>(entity, out var bloodstream))
return;
- if (!_solutionContainerSystem.ResolveSolution(entity, bloodstream.ChemicalSolutionName, ref bloodstream.ChemicalSolution, out var chemSolution) || chemSolution.AvailableVolume <= 0)
- return;
-
- var blockIngestion = _internals.AreInternalsWorking(entity);
+ var blockIngestion = _internals.AreInternalsWorking(entity);
var cloneSolution = solution.Clone();
var availableTransfer = FixedPoint2.Min(cloneSolution.Volume, component.TransferRate);
- var transferAmount = FixedPoint2.Min(availableTransfer, chemSolution.AvailableVolume);
+ var transferAmount = FixedPoint2.Min(availableTransfer, bloodstream.ChemicalSolution.AvailableVolume);
var transferSolution = cloneSolution.SplitSolution(transferAmount);
foreach (var reagentQuantity in transferSolution.Contents.ToArray())
if (!Resolve(uid, ref component, ref xform))
return;
- if (!_solutionContainerSystem.ResolveSolution(uid, SmokeComponent.SolutionName, ref component.Solution, out var solution) || !solution.Any())
+ if (!_solutionSystem.TryGetSolution(uid, SmokeComponent.SolutionName, out var solution) || !solution.Any())
return;
if (!_mapManager.TryGetGrid(xform.GridUid, out var mapGrid))
/// <summary>
/// Adds the specified solution to the relevant smoke solution.
/// </summary>
- private void TryAddSolution(Entity<SmokeComponent?> smoke, Solution solution)
+ private void TryAddSolution(EntityUid uid, Solution solution)
{
if (solution.Volume == FixedPoint2.Zero)
return;
- if (!Resolve(smoke, ref smoke.Comp))
+ if (!_solutionSystem.TryGetSolution(uid, SmokeComponent.SolutionName, out var solutionArea))
return;
- if (!_solutionContainerSystem.ResolveSolution(smoke.Owner, SmokeComponent.SolutionName, ref smoke.Comp.Solution, out var solutionArea))
- return;
+ var addSolution =
+ solution.SplitSolution(FixedPoint2.Min(solution.Volume, solutionArea.AvailableVolume));
- var addSolution = solution.SplitSolution(FixedPoint2.Min(solution.Volume, solutionArea.AvailableVolume));
- _solutionContainerSystem.TryAddSolution(smoke.Comp.Solution.Value, addSolution);
+ _solutionSystem.TryAddSolution(uid, solutionArea, addSolution);
- UpdateVisuals(smoke);
+ UpdateVisuals(uid);
}
- private void UpdateVisuals(Entity<SmokeComponent?, AppearanceComponent?> smoke)
+ private void UpdateVisuals(EntityUid uid)
{
- if (!Resolve(smoke, ref smoke.Comp1, ref smoke.Comp2) ||
- !_solutionContainerSystem.ResolveSolution(smoke.Owner, SmokeComponent.SolutionName, ref smoke.Comp1.Solution, out var solution))
+ if (!TryComp(uid, out AppearanceComponent? appearance) ||
+ !_solutionSystem.TryGetSolution(uid, SmokeComponent.SolutionName, out var solution))
return;
var color = solution.GetColor(_prototype);
- _appearance.SetData(smoke.Owner, SmokeVisuals.Color, color, smoke.Comp2);
+ _appearance.SetData(uid, SmokeVisuals.Color, color, appearance);
}
}
+using System.Numerics;
using Content.Server.Chemistry.Components;
-using Content.Server.Chemistry.Containers.EntitySystems;
using Content.Server.Chemistry.EntitySystems;
using Content.Server.Cooldown;
using Content.Server.Extinguisher;
using Content.Server.Fluids.Components;
using Content.Server.Gravity;
using Content.Server.Popups;
+using Content.Shared.Chemistry.EntitySystems;
using Content.Shared.Cooldown;
using Content.Shared.FixedPoint;
using Content.Shared.Interaction;
using Content.Shared.Vapor;
using Robust.Server.GameObjects;
+using Robust.Shared.Audio;
using Robust.Shared.Audio.Systems;
using Robust.Shared.Physics.Components;
using Robust.Shared.Prototypes;
using Robust.Shared.Timing;
-using System.Numerics;
namespace Content.Server.Fluids.EntitySystems;
SubscribeLocalEvent<SprayComponent, AfterInteractEvent>(OnAfterInteract, after: new[] { typeof(FireExtinguisherSystem) });
}
- private void OnAfterInteract(Entity<SprayComponent> entity, ref AfterInteractEvent args)
+ private void OnAfterInteract(EntityUid uid, SprayComponent component, AfterInteractEvent args)
{
if (args.Handled)
return;
args.Handled = true;
- if (!_solutionContainer.TryGetSolution(entity.Owner, SprayComponent.SolutionName, out var soln, out var solution))
+ if (!_solutionContainer.TryGetSolution(uid, SprayComponent.SolutionName, out var solution))
return;
var ev = new SprayAttemptEvent(args.User);
- RaiseLocalEvent(entity, ev);
+ RaiseLocalEvent(uid, ev);
if (ev.Cancelled)
return;
var curTime = _gameTiming.CurTime;
- if (TryComp<ItemCooldownComponent>(entity, out var cooldown)
+ if (TryComp<ItemCooldownComponent>(uid, out var cooldown)
&& curTime < cooldown.CooldownEnd)
{
return;
if (solution.Volume <= 0)
{
- _popupSystem.PopupEntity(Loc.GetString("spray-component-is-empty-message"), entity.Owner, args.User);
+ _popupSystem.PopupEntity(Loc.GetString("spray-component-is-empty-message"), uid,
+ args.User);
return;
}
var diffNorm = diffPos.Normalized();
var diffLength = diffPos.Length();
- if (diffLength > entity.Comp.SprayDistance)
+ if (diffLength > component.SprayDistance)
{
- diffLength = entity.Comp.SprayDistance;
+ diffLength = component.SprayDistance;
}
var diffAngle = diffNorm.ToAngle();
var threeQuarters = diffNorm * 0.75f;
var quarter = diffNorm * 0.25f;
- var amount = Math.Max(Math.Min((solution.Volume / entity.Comp.TransferAmount).Int(), entity.Comp.VaporAmount), 1);
- var spread = entity.Comp.VaporSpread / amount;
+ var amount = Math.Max(Math.Min((solution.Volume / component.TransferAmount).Int(), component.VaporAmount), 1);
+ var spread = component.VaporSpread / amount;
// TODO: Just use usedelay homie.
var cooldownTime = 0f;
.Offset((diffNorm + rotation.ToVec()).Normalized() * diffLength + quarter);
var distance = (target.Position - userMapPos.Position).Length();
- if (distance > entity.Comp.SprayDistance)
- target = userMapPos.Offset(diffNorm * entity.Comp.SprayDistance);
+ if (distance > component.SprayDistance)
+ target = userMapPos.Offset(diffNorm * component.SprayDistance);
- var adjustedSolutionAmount = entity.Comp.TransferAmount / entity.Comp.VaporAmount;
- var newSolution = _solutionContainer.SplitSolution(soln.Value, adjustedSolutionAmount);
+ var adjustedSolutionAmount = component.TransferAmount / component.VaporAmount;
+ var newSolution = _solutionContainer.SplitSolution(uid, solution, adjustedSolutionAmount);
if (newSolution.Volume <= FixedPoint2.Zero)
break;
// Spawn the vapor cloud onto the grid/map the user is present on. Offset the start position based on how far the target destination is.
var vaporPos = userMapPos.Offset(distance < 1 ? quarter : threeQuarters);
- var vapor = Spawn(entity.Comp.SprayedPrototype, vaporPos);
+ var vapor = Spawn(component.SprayedPrototype, vaporPos);
var vaporXform = xformQuery.GetComponent(vapor);
_transform.SetWorldRotation(vaporXform, rotation);
// impulse direction is defined in world-coordinates, not local coordinates
var impulseDirection = rotation.ToVec();
- var time = diffLength / entity.Comp.SprayVelocity;
+ var time = diffLength / component.SprayVelocity;
cooldownTime = MathF.Max(time, cooldownTime);
- _vapor.Start(ent, vaporXform, impulseDirection * diffLength, entity.Comp.SprayVelocity, target, time, args.User);
+ _vapor.Start(ent, vaporXform, impulseDirection * diffLength, component.SprayVelocity, target, time, args.User);
if (TryComp<PhysicsComponent>(args.User, out var body))
{
if (_gravity.IsWeightless(args.User, body))
- _physics.ApplyLinearImpulse(args.User, -impulseDirection.Normalized() * entity.Comp.PushbackAmount, body: body);
+ _physics.ApplyLinearImpulse(args.User, -impulseDirection.Normalized() * component.PushbackAmount, body: body);
}
}
- _audio.PlayPvs(entity.Comp.SpraySound, entity, entity.Comp.SpraySound.Params.WithVariation(0.125f));
+ _audio.PlayPvs(component.SpraySound, uid, component.SpraySound.Params.WithVariation(0.125f));
- RaiseLocalEvent(entity, new RefreshItemCooldownEvent(curTime, curTime + TimeSpan.FromSeconds(cooldownTime)), true);
+ RaiseLocalEvent(uid,
+ new RefreshItemCooldownEvent(curTime, curTime + TimeSpan.FromSeconds(cooldownTime)), true);
}
}
using Content.Server.Administration.Logs;
-using Content.Server.Chemistry.Containers.EntitySystems;
+using Content.Shared.Popups;
+using Content.Shared.Item;
+using Content.Shared.Glue;
+using Content.Shared.Interaction;
using Content.Server.Nutrition.EntitySystems;
+using Content.Shared.Chemistry.EntitySystems;
using Content.Shared.Database;
-using Content.Shared.Glue;
using Content.Shared.Hands;
-using Content.Shared.Interaction;
+using Robust.Shared.Timing;
using Content.Shared.Interaction.Components;
-using Content.Shared.Item;
-using Content.Shared.Popups;
+using Robust.Shared.Audio;
using Robust.Shared.Audio.Systems;
-using Robust.Shared.Timing;
namespace Content.Server.Glue;
}
// When glue bottle is used on item it will apply the glued and unremoveable components.
- private void OnInteract(Entity<GlueComponent> entity, ref AfterInteractEvent args)
+ private void OnInteract(EntityUid uid, GlueComponent component, AfterInteractEvent args)
{
if (args.Handled)
return;
if (!args.CanReach || args.Target is not { Valid: true } target)
return;
- if (TryGlue(entity, target, args.User))
+ if (TryGlue(uid, component, target, args.User))
{
args.Handled = true;
- _audio.PlayPvs(entity.Comp.Squeeze, entity);
+ _audio.PlayPvs(component.Squeeze, uid);
_popup.PopupEntity(Loc.GetString("glue-success", ("target", target)), args.User, args.User, PopupType.Medium);
}
else
}
}
- private bool TryGlue(Entity<GlueComponent> glue, EntityUid target, EntityUid actor)
+ private bool TryGlue(EntityUid uid, GlueComponent component, EntityUid target, EntityUid actor)
{
// if item is glued then don't apply glue again so it can be removed for reasonable time
if (HasComp<GluedComponent>(target) || !HasComp<ItemComponent>(target))
return false;
}
- if (HasComp<ItemComponent>(target) && _solutionContainer.TryGetSolution(glue.Owner, glue.Comp.Solution, out _, out var solution))
+ if (HasComp<ItemComponent>(target) && _solutionContainer.TryGetSolution(uid, component.Solution, out var solution))
{
- var quantity = solution.RemoveReagent(glue.Comp.Reagent, glue.Comp.ConsumptionUnit);
+ var quantity = solution.RemoveReagent(component.Reagent, component.ConsumptionUnit);
if (quantity > 0)
{
- EnsureComp<GluedComponent>(target).Duration = quantity.Double() * glue.Comp.DurationPerUnit;
- _adminLogger.Add(LogType.Action, LogImpact.Medium, $"{ToPrettyString(actor):actor} glued {ToPrettyString(target):subject} with {ToPrettyString(glue.Owner):tool}");
+ EnsureComp<GluedComponent>(target).Duration = quantity.Double() * component.DurationPerUnit;
+ _adminLogger.Add(LogType.Action, LogImpact.Medium, $"{ToPrettyString(actor):actor} glued {ToPrettyString(target):subject} with {ToPrettyString(uid):tool}");
return true;
}
}
}
}
- private void OnGluedInit(Entity<GluedComponent> entity, ref ComponentInit args)
+ private void OnGluedInit(EntityUid uid, GluedComponent component, ComponentInit args)
{
- var meta = MetaData(entity);
+ var meta = MetaData(uid);
var name = meta.EntityName;
- entity.Comp.BeforeGluedEntityName = meta.EntityName;
- _metaData.SetEntityName(entity.Owner, Loc.GetString("glued-name-prefix", ("target", name)));
+ component.BeforeGluedEntityName = meta.EntityName;
+ _metaData.SetEntityName(uid, Loc.GetString("glued-name-prefix", ("target", name)));
}
- private void OnHandPickUp(Entity<GluedComponent> entity, ref GotEquippedHandEvent args)
+ private void OnHandPickUp(EntityUid uid, GluedComponent component, GotEquippedHandEvent args)
{
- EnsureComp<UnremoveableComponent>(entity);
- entity.Comp.Until = _timing.CurTime + entity.Comp.Duration;
+ EnsureComp<UnremoveableComponent>(uid);
+ component.Until = _timing.CurTime + component.Duration;
}
}
+using System.Linq;
using Content.Server.Body.Systems;
-using Content.Server.Chemistry.Containers.EntitySystems;
using Content.Server.Construction;
using Content.Server.DeviceLinking.Events;
using Content.Server.DeviceLinking.Systems;
+using Content.Server.DeviceNetwork;
using Content.Server.Hands.Systems;
using Content.Server.Kitchen.Components;
using Content.Server.Power.Components;
using Robust.Shared.Audio.Systems;
using Robust.Shared.Containers;
using Robust.Shared.Player;
-using System.Linq;
namespace Content.Server.Kitchen.EntitySystems
{
SubscribeLocalEvent<MicrowaveComponent, ComponentInit>(OnInit);
SubscribeLocalEvent<MicrowaveComponent, MapInitEvent>(OnMapInit);
- SubscribeLocalEvent<MicrowaveComponent, SolutionContainerChangedEvent>(OnSolutionChange);
+ SubscribeLocalEvent<MicrowaveComponent, SolutionChangedEvent>(OnSolutionChange);
SubscribeLocalEvent<MicrowaveComponent, InteractUsingEvent>(OnInteractUsing, after: new[] { typeof(AnchorableSystem) });
SubscribeLocalEvent<MicrowaveComponent, BreakageEventArgs>(OnBreak);
SubscribeLocalEvent<MicrowaveComponent, PowerChangedEvent>(OnPowerChanged);
SubscribeLocalEvent<ActiveMicrowaveComponent, ComponentShutdown>(OnCookStop);
}
- private void OnCookStart(Entity<ActiveMicrowaveComponent> ent, ref ComponentStartup args)
+ private void OnCookStart(EntityUid uid, ActiveMicrowaveComponent component, ComponentStartup args)
{
- if (!TryComp<MicrowaveComponent>(ent, out var microwaveComponent))
+ if (!TryComp<MicrowaveComponent>(uid, out var microwaveComponent))
return;
- SetAppearance(ent.Owner, MicrowaveVisualState.Cooking, microwaveComponent);
+ SetAppearance(uid, MicrowaveVisualState.Cooking, microwaveComponent);
microwaveComponent.PlayingStream =
- _audio.PlayPvs(microwaveComponent.LoopingSound, ent, AudioParams.Default.WithLoop(true).WithMaxDistance(5)).Value.Entity;
+ _audio.PlayPvs(microwaveComponent.LoopingSound, uid, AudioParams.Default.WithLoop(true).WithMaxDistance(5)).Value.Entity;
}
- private void OnCookStop(Entity<ActiveMicrowaveComponent> ent, ref ComponentShutdown args)
+ private void OnCookStop(EntityUid uid, ActiveMicrowaveComponent component, ComponentShutdown args)
{
- if (!TryComp<MicrowaveComponent>(ent, out var microwaveComponent))
+ if (!TryComp<MicrowaveComponent>(uid, out var microwaveComponent))
return;
- SetAppearance(ent.Owner, MicrowaveVisualState.Idle, microwaveComponent);
+ SetAppearance(uid, MicrowaveVisualState.Idle, microwaveComponent);
microwaveComponent.PlayingStream = _audio.Stop(microwaveComponent.PlayingStream);
}
if (!TryComp<SolutionContainerManagerComponent>(entity, out var solutions))
continue;
- foreach (var (_, soln) in _solutionContainer.EnumerateSolutions((entity, solutions)))
+ foreach (var (_, solution) in solutions.Solutions)
{
- var solution = soln.Comp.Solution;
if (solution.Temperature > component.TemperatureUpperThreshold)
continue;
- _solutionContainer.AddThermalEnergy(soln, heatToAdd);
+ _solutionContainer.AddThermalEnergy(entity, solution, heatToAdd);
}
}
}
continue;
// go over every solution
- foreach (var (_, soln) in _solutionContainer.EnumerateSolutions((item, solMan)))
+ foreach (var (_, solution) in solMan.Solutions)
{
- var solution = soln.Comp.Solution;
foreach (var (reagent, _) in recipe.IngredientsReagents)
{
// removed everything
totalReagentsToRemove[reagent] -= quant;
}
- _solutionContainer.RemoveReagent(soln, reagent, quant);
+ _solutionContainer.RemoveReagent(item, solution, reagent, quant);
}
}
}
_deviceLink.EnsureSinkPorts(ent, ent.Comp.OnPort);
}
- private void OnSuicide(Entity<MicrowaveComponent> ent, ref SuicideEvent args)
+ private void OnSuicide(EntityUid uid, MicrowaveComponent component, SuicideEvent args)
{
if (args.Handled)
return;
foreach (var part in headSlots)
{
- _container.Insert(part.Id, ent.Comp.Storage);
+ _container.Insert(part.Id, component.Storage);
headCount++;
}
}
_popupSystem.PopupEntity(othersMessage, victim, Filter.PvsExcept(victim), true);
_popupSystem.PopupEntity(selfMessage, victim, victim);
- _audio.PlayPvs(ent.Comp.ClickSound, ent.Owner, AudioParams.Default.WithVolume(-2));
- ent.Comp.CurrentCookTimerTime = 10;
- Wzhzhzh(ent.Owner, ent.Comp, args.Victim);
- UpdateUserInterfaceState(ent.Owner, ent.Comp);
+ _audio.PlayPvs(component.ClickSound, uid, AudioParams.Default.WithVolume(-2));
+ component.CurrentCookTimerTime = 10;
+ Wzhzhzh(uid, component, args.Victim);
+ UpdateUserInterfaceState(uid, component);
}
- private void OnSolutionChange(Entity<MicrowaveComponent> ent, ref SolutionContainerChangedEvent args)
+ private void OnSolutionChange(EntityUid uid, MicrowaveComponent component, SolutionChangedEvent args)
{
- UpdateUserInterfaceState(ent, ent.Comp);
+ UpdateUserInterfaceState(uid, component);
}
- private void OnInteractUsing(Entity<MicrowaveComponent> ent, ref InteractUsingEvent args)
+ private void OnInteractUsing(EntityUid uid, MicrowaveComponent component, InteractUsingEvent args)
{
if (args.Handled)
return;
- if (!(TryComp<ApcPowerReceiverComponent>(ent, out var apc) && apc.Powered))
+ if (!(TryComp<ApcPowerReceiverComponent>(uid, out var apc) && apc.Powered))
{
- _popupSystem.PopupEntity(Loc.GetString("microwave-component-interact-using-no-power"), ent, args.User);
+ _popupSystem.PopupEntity(Loc.GetString("microwave-component-interact-using-no-power"), uid, args.User);
return;
}
- if (ent.Comp.Broken)
+ if (component.Broken)
{
- _popupSystem.PopupEntity(Loc.GetString("microwave-component-interact-using-broken"), ent, args.User);
+ _popupSystem.PopupEntity(Loc.GetString("microwave-component-interact-using-broken"), uid, args.User);
return;
}
if (!HasComp<ItemComponent>(args.Used))
{
- _popupSystem.PopupEntity(Loc.GetString("microwave-component-interact-using-transfer-fail"), ent, args.User);
+ _popupSystem.PopupEntity(Loc.GetString("microwave-component-interact-using-transfer-fail"), uid, args.User);
return;
}
args.Handled = true;
- _handsSystem.TryDropIntoContainer(args.User, args.Used, ent.Comp.Storage);
- UpdateUserInterfaceState(ent, ent.Comp);
+ _handsSystem.TryDropIntoContainer(args.User, args.Used, component.Storage);
+ UpdateUserInterfaceState(uid, component);
}
- private void OnBreak(Entity<MicrowaveComponent> ent, ref BreakageEventArgs args)
+ private void OnBreak(EntityUid uid, MicrowaveComponent component, BreakageEventArgs args)
{
- ent.Comp.Broken = true;
- SetAppearance(ent, MicrowaveVisualState.Broken, ent.Comp);
- RemComp<ActiveMicrowaveComponent>(ent);
- _sharedContainer.EmptyContainer(ent.Comp.Storage);
- UpdateUserInterfaceState(ent, ent.Comp);
+ component.Broken = true;
+ SetAppearance(uid, MicrowaveVisualState.Broken, component);
+ RemComp<ActiveMicrowaveComponent>(uid);
+ _sharedContainer.EmptyContainer(component.Storage);
+ UpdateUserInterfaceState(uid, component);
}
- private void OnPowerChanged(Entity<MicrowaveComponent> ent, ref PowerChangedEvent args)
+ private void OnPowerChanged(EntityUid uid, MicrowaveComponent component, ref PowerChangedEvent args)
{
if (!args.Powered)
{
- SetAppearance(ent, MicrowaveVisualState.Idle, ent.Comp);
- RemComp<ActiveMicrowaveComponent>(ent);
- _sharedContainer.EmptyContainer(ent.Comp.Storage);
+ SetAppearance(uid, MicrowaveVisualState.Idle, component);
+ RemComp<ActiveMicrowaveComponent>(uid);
+ _sharedContainer.EmptyContainer(component.Storage);
}
- UpdateUserInterfaceState(ent, ent.Comp);
+ UpdateUserInterfaceState(uid, component);
}
- private void OnRefreshParts(Entity<MicrowaveComponent> ent, ref RefreshPartsEvent args)
+ private void OnRefreshParts(EntityUid uid, MicrowaveComponent component, RefreshPartsEvent args)
{
- var cookRating = args.PartRatings[ent.Comp.MachinePartCookTimeMultiplier];
- ent.Comp.CookTimeMultiplier = MathF.Pow(ent.Comp.CookTimeScalingConstant, cookRating - 1);
+ var cookRating = args.PartRatings[component.MachinePartCookTimeMultiplier];
+ component.CookTimeMultiplier = MathF.Pow(component.CookTimeScalingConstant, cookRating - 1);
}
- private void OnUpgradeExamine(Entity<MicrowaveComponent> ent, ref UpgradeExamineEvent args)
+ private void OnUpgradeExamine(EntityUid uid, MicrowaveComponent component, UpgradeExamineEvent args)
{
- args.AddPercentageUpgrade("microwave-component-upgrade-cook-time", ent.Comp.CookTimeMultiplier);
+ args.AddPercentageUpgrade("microwave-component-upgrade-cook-time", component.CookTimeMultiplier);
}
private void OnSignalReceived(Entity<MicrowaveComponent> ent, ref SignalReceivedEvent args)
if (!TryComp<SolutionContainerManagerComponent>(item, out var solMan))
continue;
- foreach (var (_, soln) in _solutionContainer.EnumerateSolutions((item, solMan)))
+ foreach (var (_, solution) in solMan.Solutions)
{
- var solution = soln.Comp.Solution;
foreach (var (reagent, quantity) in solution.Contents)
{
if (reagentDict.ContainsKey(reagent.Prototype))
}
#region ui
- private void OnEjectMessage(Entity<MicrowaveComponent> ent, ref MicrowaveEjectMessage args)
+ private void OnEjectMessage(EntityUid uid, MicrowaveComponent component, MicrowaveEjectMessage args)
{
- if (!HasContents(ent.Comp) || HasComp<ActiveMicrowaveComponent>(ent))
+ if (!HasContents(component) || HasComp<ActiveMicrowaveComponent>(uid))
return;
- _sharedContainer.EmptyContainer(ent.Comp.Storage);
- _audio.PlayPvs(ent.Comp.ClickSound, ent, AudioParams.Default.WithVolume(-2));
- UpdateUserInterfaceState(ent, ent.Comp);
+ _sharedContainer.EmptyContainer(component.Storage);
+ _audio.PlayPvs(component.ClickSound, uid, AudioParams.Default.WithVolume(-2));
+ UpdateUserInterfaceState(uid, component);
}
- private void OnEjectIndex(Entity<MicrowaveComponent> ent, ref MicrowaveEjectSolidIndexedMessage args)
+ private void OnEjectIndex(EntityUid uid, MicrowaveComponent component, MicrowaveEjectSolidIndexedMessage args)
{
- if (!HasContents(ent.Comp) || HasComp<ActiveMicrowaveComponent>(ent))
+ if (!HasContents(component) || HasComp<ActiveMicrowaveComponent>(uid))
return;
- _sharedContainer.Remove(EntityManager.GetEntity(args.EntityID), ent.Comp.Storage);
- UpdateUserInterfaceState(ent, ent.Comp);
+ _sharedContainer.Remove(EntityManager.GetEntity(args.EntityID), component.Storage);
+ UpdateUserInterfaceState(uid, component);
}
- private void OnSelectTime(Entity<MicrowaveComponent> ent, ref MicrowaveSelectCookTimeMessage args)
+ private void OnSelectTime(EntityUid uid, MicrowaveComponent comp, MicrowaveSelectCookTimeMessage args)
{
- if (!HasContents(ent.Comp) || HasComp<ActiveMicrowaveComponent>(ent) || !(TryComp<ApcPowerReceiverComponent>(ent, out var apc) && apc.Powered))
+ if (!HasContents(comp) || HasComp<ActiveMicrowaveComponent>(uid) || !(TryComp<ApcPowerReceiverComponent>(uid, out var apc) && apc.Powered))
return;
// some validation to prevent trollage
- if (args.NewCookTime % 5 != 0 || args.NewCookTime > ent.Comp.MaxCookTime)
+ if (args.NewCookTime % 5 != 0 || args.NewCookTime > comp.MaxCookTime)
return;
- ent.Comp.CurrentCookTimeButtonIndex = args.ButtonIndex;
- ent.Comp.CurrentCookTimerTime = args.NewCookTime;
- _audio.PlayPvs(ent.Comp.ClickSound, ent, AudioParams.Default.WithVolume(-2));
- UpdateUserInterfaceState(ent, ent.Comp);
+ comp.CurrentCookTimeButtonIndex = args.ButtonIndex;
+ comp.CurrentCookTimerTime = args.NewCookTime;
+ _audio.PlayPvs(comp.ClickSound, uid, AudioParams.Default.WithVolume(-2));
+ UpdateUserInterfaceState(uid, comp);
}
#endregion
}
-using Content.Server.Chemistry.Containers.EntitySystems;
+using System.Linq;
using Content.Server.Construction;
using Content.Server.Kitchen.Components;
using Content.Server.Power.Components;
using Content.Server.Power.EntitySystems;
using Content.Server.Stack;
using Content.Shared.Chemistry.Components;
+using Content.Shared.Chemistry.EntitySystems;
using Content.Shared.Containers.ItemSlots;
using Content.Shared.FixedPoint;
using Content.Shared.Interaction;
using Robust.Shared.Audio.Systems;
using Robust.Shared.Containers;
using Robust.Shared.Timing;
-using System.Linq;
namespace Content.Server.Kitchen.EntitySystems
{
internal sealed class ReagentGrinderSystem : EntitySystem
{
[Dependency] private readonly IGameTiming _timing = default!;
- [Dependency] private readonly SolutionContainerSystem _solutionContainersSystem = default!;
+ [Dependency] private readonly SolutionContainerSystem _solutionsSystem = default!;
[Dependency] private readonly ItemSlotsSystem _itemSlotsSystem = default!;
[Dependency] private readonly SharedPopupSystem _popupSystem = default!;
[Dependency] private readonly UserInterfaceSystem _userInterfaceSystem = default!;
var inputContainer = _containerSystem.EnsureContainer<Container>(uid, SharedReagentGrinder.InputContainerId);
var outputContainer = _itemSlotsSystem.GetItemOrNull(uid, SharedReagentGrinder.BeakerSlotId);
- if (outputContainer is null || !_solutionContainersSystem.TryGetFitsInDispenser(outputContainer.Value, out var containerSoln, out var containerSolution))
+ if (outputContainer is null || !_solutionsSystem.TryGetFitsInDispenser(outputContainer.Value, out var containerSolution))
continue;
foreach (var item in inputContainer.ContainedEntities.ToList())
QueueDel(item);
}
- _solutionContainersSystem.TryAddSolution(containerSoln.Value, solution);
+ _solutionsSystem.TryAddSolution(outputContainer.Value, containerSolution, solution);
}
_userInterfaceSystem.TrySendUiMessage(uid, ReagentGrinderUiKey.Key,
}
}
- private void OnEntRemoveAttempt(Entity<ReagentGrinderComponent> entity, ref ContainerIsRemovingAttemptEvent args)
+ private void OnEntRemoveAttempt(EntityUid uid, ReagentGrinderComponent reagentGrinder, ContainerIsRemovingAttemptEvent args)
{
- if (HasComp<ActiveReagentGrinderComponent>(entity))
+ if (HasComp<ActiveReagentGrinderComponent>(uid))
args.Cancel();
}
_appearanceSystem.SetData(uid, ReagentGrinderVisualState.BeakerAttached, outputContainer.HasValue);
}
- private void OnInteractUsing(Entity<ReagentGrinderComponent> entity, ref InteractUsingEvent args)
+ private void OnInteractUsing(EntityUid uid, ReagentGrinderComponent reagentGrinder, InteractUsingEvent args)
{
var heldEnt = args.Used;
- var inputContainer = _containerSystem.EnsureContainer<Container>(entity.Owner, SharedReagentGrinder.InputContainerId);
+ var inputContainer = _containerSystem.EnsureContainer<Container>(uid, SharedReagentGrinder.InputContainerId);
if (!HasComp<ExtractableComponent>(heldEnt))
{
if (!HasComp<FitsInDispenserComponent>(heldEnt))
{
// This is ugly but we can't use whitelistFailPopup because there are 2 containers with different whitelists.
- _popupSystem.PopupEntity(Loc.GetString("reagent-grinder-component-cannot-put-entity-message"), entity.Owner, args.User);
+ _popupSystem.PopupEntity(Loc.GetString("reagent-grinder-component-cannot-put-entity-message"), uid, args.User);
}
// Entity did NOT pass the whitelist for grind/juice.
// Cap the chamber. Don't want someone putting in 500 entities and ejecting them all at once.
// Maybe I should have done that for the microwave too?
- if (inputContainer.ContainedEntities.Count >= entity.Comp.StorageMaxEntities)
+ if (inputContainer.ContainedEntities.Count >= reagentGrinder.StorageMaxEntities)
return;
if (!_containerSystem.Insert(heldEnt, inputContainer))
/// <remarks>
/// Gotta be efficient, you know? you're saving a whole extra second here and everything.
/// </remarks>
- private void OnRefreshParts(Entity<ReagentGrinderComponent> entity, ref RefreshPartsEvent args)
+ private void OnRefreshParts(EntityUid uid, ReagentGrinderComponent component, RefreshPartsEvent args)
{
- var ratingWorkTime = args.PartRatings[entity.Comp.MachinePartWorkTime];
- var ratingStorage = args.PartRatings[entity.Comp.MachinePartStorageMax];
+ var ratingWorkTime = args.PartRatings[component.MachinePartWorkTime];
+ var ratingStorage = args.PartRatings[component.MachinePartStorageMax];
- entity.Comp.WorkTimeMultiplier = MathF.Pow(entity.Comp.PartRatingWorkTimerMulitplier, ratingWorkTime - 1);
- entity.Comp.StorageMaxEntities = entity.Comp.BaseStorageMaxEntities + (int) (entity.Comp.StoragePerPartRating * (ratingStorage - 1));
+ component.WorkTimeMultiplier = MathF.Pow(component.PartRatingWorkTimerMulitplier, ratingWorkTime - 1);
+ component.StorageMaxEntities = component.BaseStorageMaxEntities + (int) (component.StoragePerPartRating * (ratingStorage - 1));
}
- private void OnUpgradeExamine(Entity<ReagentGrinderComponent> entity, ref UpgradeExamineEvent args)
+ private void OnUpgradeExamine(EntityUid uid, ReagentGrinderComponent component, UpgradeExamineEvent args)
{
- args.AddPercentageUpgrade("reagent-grinder-component-upgrade-work-time", entity.Comp.WorkTimeMultiplier);
- args.AddNumberUpgrade("reagent-grinder-component-upgrade-storage", entity.Comp.StorageMaxEntities - entity.Comp.BaseStorageMaxEntities);
+ args.AddPercentageUpgrade("reagent-grinder-component-upgrade-work-time", component.WorkTimeMultiplier);
+ args.AddNumberUpgrade("reagent-grinder-component-upgrade-storage", component.StorageMaxEntities - component.BaseStorageMaxEntities);
}
private void UpdateUiState(EntityUid uid)
var canGrind = false;
if (outputContainer is not null
- && _solutionContainersSystem.TryGetFitsInDispenser(outputContainer.Value, out _, out containerSolution)
+ && _solutionsSystem.TryGetFitsInDispenser(outputContainer.Value, out containerSolution)
&& inputContainer.ContainedEntities.Count > 0)
{
canGrind = inputContainer.ContainedEntities.All(CanGrind);
_userInterfaceSystem.TrySetUiState(uid, ReagentGrinderUiKey.Key, state);
}
- private void OnStartMessage(Entity<ReagentGrinderComponent> entity, ref ReagentGrinderStartMessage message)
+ private void OnStartMessage(EntityUid uid, ReagentGrinderComponent reagentGrinder, ReagentGrinderStartMessage message)
{
- if (!this.IsPowered(entity.Owner, EntityManager) || HasComp<ActiveReagentGrinderComponent>(entity))
+ if (!this.IsPowered(uid, EntityManager) || HasComp<ActiveReagentGrinderComponent>(uid))
return;
- DoWork(entity.Owner, entity.Comp, message.Program);
+ DoWork(uid, reagentGrinder, message.Program);
}
- private void OnEjectChamberAllMessage(Entity<ReagentGrinderComponent> entity, ref ReagentGrinderEjectChamberAllMessage message)
+ private void OnEjectChamberAllMessage(EntityUid uid, ReagentGrinderComponent reagentGrinder, ReagentGrinderEjectChamberAllMessage message)
{
- var inputContainer = _containerSystem.EnsureContainer<Container>(entity.Owner, SharedReagentGrinder.InputContainerId);
+ var inputContainer = _containerSystem.EnsureContainer<Container>(uid, SharedReagentGrinder.InputContainerId);
- if (HasComp<ActiveReagentGrinderComponent>(entity) || inputContainer.ContainedEntities.Count <= 0)
+ if (HasComp<ActiveReagentGrinderComponent>(uid) || inputContainer.ContainedEntities.Count <= 0)
return;
- ClickSound(entity);
- foreach (var toEject in inputContainer.ContainedEntities.ToList())
+ ClickSound(uid, reagentGrinder);
+ foreach (var entity in inputContainer.ContainedEntities.ToList())
{
- _containerSystem.Remove(toEject, inputContainer);
- _randomHelper.RandomOffset(toEject, 0.4f);
+ _containerSystem.Remove(entity, inputContainer);
+ _randomHelper.RandomOffset(entity, 0.4f);
}
- UpdateUiState(entity);
+ UpdateUiState(uid);
}
- private void OnEjectChamberContentMessage(Entity<ReagentGrinderComponent> entity, ref ReagentGrinderEjectChamberContentMessage message)
+ private void OnEjectChamberContentMessage(EntityUid uid, ReagentGrinderComponent reagentGrinder, ReagentGrinderEjectChamberContentMessage message)
{
- if (HasComp<ActiveReagentGrinderComponent>(entity))
+ if (HasComp<ActiveReagentGrinderComponent>(uid))
return;
- var inputContainer = _containerSystem.EnsureContainer<Container>(entity.Owner, SharedReagentGrinder.InputContainerId);
+ var inputContainer = _containerSystem.EnsureContainer<Container>(uid, SharedReagentGrinder.InputContainerId);
var ent = GetEntity(message.EntityId);
if (_containerSystem.Remove(ent, inputContainer))
{
_randomHelper.RandomOffset(ent, 0.4f);
- ClickSound(entity);
- UpdateUiState(entity);
+ ClickSound(uid, reagentGrinder);
+ UpdateUiState(uid);
}
}
new ReagentGrinderWorkStartedMessage(program));
}
- private void ClickSound(Entity<ReagentGrinderComponent> reagentGrinder)
+ private void ClickSound(EntityUid uid, ReagentGrinderComponent reagentGrinder)
{
- _audioSystem.PlayPvs(reagentGrinder.Comp.ClickSound, reagentGrinder.Owner, AudioParams.Default.WithVolume(-2f));
+ _audioSystem.PlayPvs(reagentGrinder.ClickSound, uid, AudioParams.Default.WithVolume(-2f));
}
private Solution? GetGrindSolution(EntityUid uid)
{
if (TryComp<ExtractableComponent>(uid, out var extractable)
&& extractable.GrindableSolution is not null
- && _solutionContainersSystem.TryGetSolution(uid, extractable.GrindableSolution, out _, out var solution))
+ && _solutionsSystem.TryGetSolution(uid, extractable.GrindableSolution, out var solution))
{
return solution;
}
{
var solutionName = CompOrNull<ExtractableComponent>(uid)?.GrindableSolution;
- return solutionName is not null && _solutionContainersSystem.TryGetSolution(uid, solutionName, out _, out _);
+ return solutionName is not null && _solutionsSystem.TryGetSolution(uid, solutionName, out _);
}
private bool CanJuice(EntityUid uid)
using Content.Server.Administration.Logs;
-using Content.Server.Chemistry.Containers.EntitySystems;
using Content.Server.Nutrition.EntitySystems;
+using Content.Shared.Chemistry.EntitySystems;
using Content.Shared.Database;
using Content.Shared.IdentityManagement;
using Content.Shared.Interaction;
SubscribeLocalEvent<LubeComponent, AfterInteractEvent>(OnInteract, after: new[] { typeof(OpenableSystem) });
}
- private void OnInteract(Entity<LubeComponent> entity, ref AfterInteractEvent args)
+ private void OnInteract(EntityUid uid, LubeComponent component, AfterInteractEvent args)
{
if (args.Handled)
return;
if (!args.CanReach || args.Target is not { Valid: true } target)
return;
- if (TryLube(entity, target, args.User))
+ if (TryLube(uid, component, target, args.User))
{
args.Handled = true;
- _audio.PlayPvs(entity.Comp.Squeeze, entity);
+ _audio.PlayPvs(component.Squeeze, uid);
_popup.PopupEntity(Loc.GetString("lube-success", ("target", Identity.Entity(target, EntityManager))), args.User, args.User, PopupType.Medium);
}
else
}
}
- private bool TryLube(Entity<LubeComponent> lube, EntityUid target, EntityUid actor)
+ private bool TryLube(EntityUid uid, LubeComponent component, EntityUid target, EntityUid actor)
{
if (HasComp<LubedComponent>(target) || !HasComp<ItemComponent>(target))
{
return false;
}
- if (HasComp<ItemComponent>(target) && _solutionContainer.TryGetSolution(lube.Owner, lube.Comp.Solution, out _, out var solution))
+ if (HasComp<ItemComponent>(target) && _solutionContainer.TryGetSolution(uid, component.Solution, out var solution))
{
- var quantity = solution.RemoveReagent(lube.Comp.Reagent, lube.Comp.Consumption);
+ var quantity = solution.RemoveReagent(component.Reagent, component.Consumption);
if (quantity > 0)
{
var lubed = EnsureComp<LubedComponent>(target);
- lubed.SlipsLeft = _random.Next(lube.Comp.MinSlips * quantity.Int(), lube.Comp.MaxSlips * quantity.Int());
- lubed.SlipStrength = lube.Comp.SlipStrength;
- _adminLogger.Add(LogType.Action, LogImpact.Medium, $"{ToPrettyString(actor):actor} lubed {ToPrettyString(target):subject} with {ToPrettyString(lube.Owner):tool}");
+ lubed.SlipsLeft = _random.Next(component.MinSlips * quantity.Int(), component.MaxSlips * quantity.Int());
+ lubed.SlipStrength = component.SlipStrength;
+ _adminLogger.Add(LogType.Action, LogImpact.Medium, $"{ToPrettyString(actor):actor} lubed {ToPrettyString(target):subject} with {ToPrettyString(uid):tool}");
return true;
}
}
-using Content.Server.Chemistry.Containers.EntitySystems;
+using System.Linq;
using Content.Server.Chemistry.EntitySystems;
using Content.Server.Construction;
using Content.Server.Fluids.EntitySystems;
using Content.Shared.Body.Systems;
using Content.Shared.Chemistry.Components;
using Content.Shared.Chemistry.Components.SolutionManager;
+using Content.Shared.Chemistry.EntitySystems;
using Content.Shared.IdentityManagement;
using Content.Shared.Interaction;
using Content.Shared.Interaction.Events;
using Robust.Server.GameObjects;
using Robust.Shared.Player;
using Robust.Shared.Utility;
-using System.Linq;
namespace Content.Server.Materials;
SubscribeLocalEvent<MaterialReclaimerComponent, SuicideEvent>(OnSuicide);
SubscribeLocalEvent<ActiveMaterialReclaimerComponent, PowerChangedEvent>(OnActivePowerChanged);
}
- private void OnStartup(Entity<MaterialReclaimerComponent> entity, ref ComponentStartup args)
+ private void OnStartup(EntityUid uid, MaterialReclaimerComponent component, ComponentStartup args)
{
- _solutionContainer.EnsureSolution(entity.Owner, entity.Comp.SolutionContainerId);
+ component.OutputSolution = _solutionContainer.EnsureSolution(uid, component.SolutionContainerId);
}
- private void OnUpgradeExamine(Entity<MaterialReclaimerComponent> entity, ref UpgradeExamineEvent args)
+ private void OnUpgradeExamine(EntityUid uid, MaterialReclaimerComponent component, UpgradeExamineEvent args)
{
- args.AddPercentageUpgrade(Loc.GetString("material-reclaimer-upgrade-process-rate"), entity.Comp.MaterialProcessRate / entity.Comp.BaseMaterialProcessRate);
+ args.AddPercentageUpgrade(Loc.GetString("material-reclaimer-upgrade-process-rate"), component.MaterialProcessRate / component.BaseMaterialProcessRate);
}
- private void OnRefreshParts(Entity<MaterialReclaimerComponent> entity, ref RefreshPartsEvent args)
+ private void OnRefreshParts(EntityUid uid, MaterialReclaimerComponent component, RefreshPartsEvent args)
{
- var rating = args.PartRatings[entity.Comp.MachinePartProcessRate] - 1;
- entity.Comp.MaterialProcessRate = entity.Comp.BaseMaterialProcessRate * MathF.Pow(entity.Comp.PartRatingProcessRateMultiplier, rating);
- Dirty(entity);
+ var rating = args.PartRatings[component.MachinePartProcessRate] - 1;
+ component.MaterialProcessRate = component.BaseMaterialProcessRate * MathF.Pow(component.PartRatingProcessRateMultiplier, rating);
+ Dirty(component);
}
- private void OnPowerChanged(Entity<MaterialReclaimerComponent> entity, ref PowerChangedEvent args)
+ private void OnPowerChanged(EntityUid uid, MaterialReclaimerComponent component, ref PowerChangedEvent args)
{
- AmbientSound.SetAmbience(entity.Owner, entity.Comp.Enabled && args.Powered);
- entity.Comp.Powered = args.Powered;
- Dirty(entity);
+ AmbientSound.SetAmbience(uid, component.Enabled && args.Powered);
+ component.Powered = args.Powered;
+ Dirty(component);
}
- private void OnInteractUsing(Entity<MaterialReclaimerComponent> entity, ref InteractUsingEvent args)
+ private void OnInteractUsing(EntityUid uid, MaterialReclaimerComponent component, InteractUsingEvent args)
{
if (args.Handled)
return;
// if we're trying to get a solution out of the reclaimer, don't destroy it
- if (_solutionContainer.TryGetSolution(entity.Owner, entity.Comp.SolutionContainerId, out _, out var outputSolution) && outputSolution.Contents.Any())
+ if (component.OutputSolution.Contents.Any())
{
if (TryComp<SolutionContainerManagerComponent>(args.Used, out var managerComponent) &&
- _solutionContainer.EnumerateSolutions((args.Used, managerComponent)).Any(s => s.Solution.Comp.Solution.AvailableVolume > 0))
+ managerComponent.Solutions.Any(s => s.Value.AvailableVolume > 0))
{
if (_openable.IsClosed(args.Used))
return;
}
}
- args.Handled = TryStartProcessItem(entity.Owner, args.Used, entity.Comp, args.User);
+ args.Handled = TryStartProcessItem(uid, args.Used, component, args.User);
}
- private void OnSuicide(Entity<MaterialReclaimerComponent> entity, ref SuicideEvent args)
+ private void OnSuicide(EntityUid uid, MaterialReclaimerComponent component, SuicideEvent args)
{
if (args.Handled)
return;
_mind.TryGetMind(actor.PlayerSession, out var mindId, out var mind))
{
_ticker.OnGhostAttempt(mindId, false, mind: mind);
- if (mind.OwnedEntity is { Valid: true } suicider)
+ if (mind.OwnedEntity is { Valid: true } entity)
{
- _popup.PopupEntity(Loc.GetString("recycler-component-suicide-message"), suicider);
+ _popup.PopupEntity(Loc.GetString("recycler-component-suicide-message"), entity);
}
}
Filter.PvsExcept(victim, entityManager: EntityManager), true);
_body.GibBody(victim, true);
- _appearance.SetData(entity.Owner, RecyclerVisuals.Bloody, true);
+ _appearance.SetData(uid, RecyclerVisuals.Bloody, true);
}
- private void OnActivePowerChanged(Entity<ActiveMaterialReclaimerComponent> entity, ref PowerChangedEvent args)
+ private void OnActivePowerChanged(EntityUid uid, ActiveMaterialReclaimerComponent component, ref PowerChangedEvent args)
{
if (!args.Powered)
- TryFinishProcessItem(entity, null, entity.Comp);
+ TryFinishProcessItem(uid, null, component);
}
/// <inheritdoc/>
{
if (!Resolve(reclaimer, ref reclaimerComponent, ref xform))
return;
- if (!_solutionContainer.TryGetSolution(reclaimer, reclaimerComponent.SolutionContainerId, out var outputSolution))
- return;
efficiency *= reclaimerComponent.Efficiency;
// if the item we inserted has reagents, add it in.
if (TryComp<SolutionContainerManagerComponent>(item, out var solutionContainer))
{
- foreach (var (_, soln) in _solutionContainer.EnumerateSolutions((item, solutionContainer)))
+ foreach (var solution in solutionContainer.Solutions.Values)
{
- var solution = soln.Comp.Solution;
foreach (var quantity in solution.Contents)
{
totalChemicals.AddReagent(quantity.Reagent.Prototype, quantity.Quantity * efficiency, false);
}
}
- _solutionContainer.TryTransferSolution(outputSolution.Value, totalChemicals, totalChemicals.Volume);
+ _solutionContainer.TryTransferSolution(reclaimer, reclaimerComponent.OutputSolution, totalChemicals, totalChemicals.Volume);
if (totalChemicals.Volume > 0)
{
_puddle.TrySpillAt(reclaimer, totalChemicals, out _, sound, transformComponent: xform);
using Content.Server.Atmos.Piping.Unary.EntitySystems;
using Content.Server.Body.Components;
using Content.Server.Body.Systems;
-using Content.Server.Chemistry.Containers.EntitySystems;
using Content.Server.Medical.Components;
using Content.Server.NodeContainer;
using Content.Server.NodeContainer.EntitySystems;
using Content.Shared.Chemistry;
using Content.Shared.Chemistry.Components;
using Content.Shared.Chemistry.Components.SolutionManager;
+using Content.Shared.Chemistry.EntitySystems;
using Content.Shared.Chemistry.Reagent;
using Content.Shared.Climbing.Systems;
using Content.Shared.Containers.ItemSlots;
using Content.Shared.Interaction;
using Content.Shared.Medical.Cryogenics;
using Content.Shared.MedicalScanner;
+using Content.Shared.Tools;
using Content.Shared.Verbs;
using Robust.Server.GameObjects;
using Robust.Shared.Timing;
namespace Content.Server.Medical;
-public sealed partial class CryoPodSystem : SharedCryoPodSystem
+public sealed partial class CryoPodSystem: SharedCryoPodSystem
{
[Dependency] private readonly AtmosphereSystem _atmosphereSystem = default!;
[Dependency] private readonly GasCanisterSystem _gasCanisterSystem = default!;
&& fitsInDispenserQuery.TryGetComponent(container, out var fitsInDispenserComponent)
&& solutionContainerManagerQuery.TryGetComponent(container,
out var solutionContainerManagerComponent)
- && _solutionContainerSystem.TryGetFitsInDispenser((container.Value, fitsInDispenserComponent, solutionContainerManagerComponent),
- out var containerSolution, out _))
+ && _solutionContainerSystem.TryGetFitsInDispenser(container.Value, out var containerSolution, dispenserFits: fitsInDispenserComponent, solutionManager: solutionContainerManagerComponent))
{
if (!bloodStreamQuery.TryGetComponent(patient, out var bloodstream))
{
continue;
}
- var solutionToInject = _solutionContainerSystem.SplitSolution(containerSolution.Value, cryoPod.BeakerTransferAmount);
+ var solutionToInject = _solutionContainerSystem.SplitSolution(container.Value, containerSolution, cryoPod.BeakerTransferAmount);
_bloodstreamSystem.TryAddToChemicals(patient.Value, solutionToInject, bloodstream);
_reactiveSystem.DoEntityReaction(patient.Value, solutionToInject, ReactionMethod.Injection);
}
{
if (!Resolve(uid, ref cryoPodComponent))
return null;
- if (cryoPodComponent.BodyContainer.ContainedEntity is not { Valid: true } contained)
+ if (cryoPodComponent.BodyContainer.ContainedEntity is not {Valid: true} contained)
return null;
base.EjectBody(uid, cryoPodComponent);
_climbSystem.ForciblySetClimbing(contained, uid);
#region Interaction
- private void HandleDragDropOn(Entity<CryoPodComponent> entity, ref DragDropTargetEvent args)
+ private void HandleDragDropOn(EntityUid uid, CryoPodComponent cryoPodComponent, ref DragDropTargetEvent args)
{
- if (entity.Comp.BodyContainer.ContainedEntity != null)
+ if (cryoPodComponent.BodyContainer.ContainedEntity != null)
return;
- var doAfterArgs = new DoAfterArgs(EntityManager, args.User, entity.Comp.EntryDelay, new CryoPodDragFinished(), entity, target: args.Dragged, used: entity)
+ var doAfterArgs = new DoAfterArgs(EntityManager, args.User, cryoPodComponent.EntryDelay, new CryoPodDragFinished(), uid, target: args.Dragged, used: uid)
{
BreakOnDamage = true,
BreakOnTargetMove = true,
args.Handled = true;
}
- private void OnDragFinished(Entity<CryoPodComponent> entity, ref CryoPodDragFinished args)
+ private void OnDragFinished(EntityUid uid, CryoPodComponent component, CryoPodDragFinished args)
{
if (args.Cancelled || args.Handled || args.Args.Target == null)
return;
- if (InsertBody(entity.Owner, args.Args.Target.Value, entity.Comp))
+ if (InsertBody(uid, args.Args.Target.Value, component))
{
- if (!TryComp(entity.Owner, out CryoPodAirComponent? cryoPodAir))
+ if (!TryComp(uid, out CryoPodAirComponent? cryoPodAir))
_adminLogger.Add(LogType.Action, LogImpact.Medium,
- $"{ToPrettyString(args.User)} inserted {ToPrettyString(args.Args.Target.Value)} into {ToPrettyString(entity.Owner)}");
+ $"{ToPrettyString(args.User)} inserted {ToPrettyString(args.Args.Target.Value)} into {ToPrettyString(uid)}");
_adminLogger.Add(LogType.Action, LogImpact.Medium,
- $"{ToPrettyString(args.User)} inserted {ToPrettyString(args.Args.Target.Value)} into {ToPrettyString(entity.Owner)} which contains gas: {cryoPodAir!.Air.ToPrettyString():gasMix}");
+ $"{ToPrettyString(args.User)} inserted {ToPrettyString(args.Args.Target.Value)} into {ToPrettyString(uid)} which contains gas: {cryoPodAir!.Air.ToPrettyString():gasMix}");
}
args.Handled = true;
}
- private void OnActivateUIAttempt(Entity<CryoPodComponent> entity, ref ActivatableUIOpenAttemptEvent args)
+ private void OnActivateUIAttempt(EntityUid uid, CryoPodComponent cryoPodComponent, ActivatableUIOpenAttemptEvent args)
{
if (args.Cancelled)
{
return;
}
- var containedEntity = entity.Comp.BodyContainer.ContainedEntity;
- if (containedEntity == null || containedEntity == args.User || !HasComp<ActiveCryoPodComponent>(entity))
+ var containedEntity = cryoPodComponent.BodyContainer.ContainedEntity;
+ if (containedEntity == null || containedEntity == args.User || !HasComp<ActiveCryoPodComponent>(uid))
{
args.Cancel();
}
}
- private void OnActivateUI(Entity<CryoPodComponent> entity, ref AfterActivatableUIOpenEvent args)
+ private void OnActivateUI(EntityUid uid, CryoPodComponent cryoPodComponent, AfterActivatableUIOpenEvent args)
{
- TryComp<TemperatureComponent>(entity.Comp.BodyContainer.ContainedEntity, out var temp);
- TryComp<BloodstreamComponent>(entity.Comp.BodyContainer.ContainedEntity, out var bloodstream);
+ TryComp<TemperatureComponent>(cryoPodComponent.BodyContainer.ContainedEntity, out var temp);
+ TryComp<BloodstreamComponent>(cryoPodComponent.BodyContainer.ContainedEntity, out var bloodstream);
_userInterfaceSystem.TrySendUiMessage(
- entity.Owner,
+ uid,
HealthAnalyzerUiKey.Key,
- new HealthAnalyzerScannedUserMessage(GetNetEntity(entity.Comp.BodyContainer.ContainedEntity),
- temp?.CurrentTemperature ?? 0,
- (bloodstream != null && _solutionContainerSystem.ResolveSolution(entity.Owner, bloodstream.BloodSolutionName, ref bloodstream.BloodSolution, out var bloodSolution))
- ? bloodSolution.FillFraction
- : 0
- ));
+ new HealthAnalyzerScannedUserMessage(GetNetEntity(cryoPodComponent.BodyContainer.ContainedEntity),
+ temp?.CurrentTemperature ?? 0, bloodstream != null ? bloodstream.BloodSolution.FillFraction : 0));
}
- private void OnInteractUsing(Entity<CryoPodComponent> entity, ref InteractUsingEvent args)
+ private void OnInteractUsing(EntityUid uid, CryoPodComponent cryoPodComponent, InteractUsingEvent args)
{
- if (args.Handled || !entity.Comp.Locked || entity.Comp.BodyContainer.ContainedEntity == null)
+ if (args.Handled || !cryoPodComponent.Locked || cryoPodComponent.BodyContainer.ContainedEntity == null)
return;
- args.Handled = _toolSystem.UseTool(args.Used, args.User, entity.Owner, entity.Comp.PryDelay, "Prying", new CryoPodPryFinished());
+ args.Handled = _toolSystem.UseTool(args.Used, args.User, uid, cryoPodComponent.PryDelay, "Prying", new CryoPodPryFinished());
}
- private void OnExamined(Entity<CryoPodComponent> entity, ref ExaminedEvent args)
+ private void OnExamined(EntityUid uid, CryoPodComponent component, ExaminedEvent args)
{
- var container = _itemSlotsSystem.GetItemOrNull(entity.Owner, entity.Comp.SolutionContainerName);
- if (args.IsInDetailsRange && container != null && _solutionContainerSystem.TryGetFitsInDispenser(container.Value, out _, out var containerSolution))
+ var container = _itemSlotsSystem.GetItemOrNull(uid, component.SolutionContainerName);
+ if (args.IsInDetailsRange && container != null && _solutionContainerSystem.TryGetFitsInDispenser(container.Value, out var containerSolution))
{
args.PushMarkup(Loc.GetString("cryo-pod-examine", ("beaker", Name(container.Value))));
if (containerSolution.Volume == 0)
}
}
- private void OnPowerChanged(Entity<CryoPodComponent> entity, ref PowerChangedEvent args)
+ private void OnPowerChanged(EntityUid uid, CryoPodComponent component, ref PowerChangedEvent args)
{
// Needed to avoid adding/removing components on a deleted entity
- if (Terminating(entity))
+ if (Terminating(uid))
{
return;
}
if (args.Powered)
{
- EnsureComp<ActiveCryoPodComponent>(entity);
+ EnsureComp<ActiveCryoPodComponent>(uid);
}
else
{
- RemComp<ActiveCryoPodComponent>(entity);
- _uiSystem.TryCloseAll(entity.Owner, HealthAnalyzerUiKey.Key);
+ RemComp<ActiveCryoPodComponent>(uid);
+ _uiSystem.TryCloseAll(uid, HealthAnalyzerUiKey.Key);
}
- UpdateAppearance(entity.Owner, entity.Comp);
+ UpdateAppearance(uid, component);
}
#endregion
#region Atmos handler
- private void OnCryoPodUpdateAtmosphere(Entity<CryoPodComponent> entity, ref AtmosDeviceUpdateEvent args)
+ private void OnCryoPodUpdateAtmosphere(EntityUid uid, CryoPodComponent cryoPod, ref AtmosDeviceUpdateEvent args)
{
- if (!TryComp(entity, out NodeContainerComponent? nodeContainer))
+ if (!TryComp(uid, out NodeContainerComponent? nodeContainer))
return;
- if (!_nodeContainer.TryGetNode(nodeContainer, entity.Comp.PortName, out PortablePipeNode? portNode))
+ if (!_nodeContainer.TryGetNode(nodeContainer, cryoPod.PortName, out PortablePipeNode? portNode))
return;
- if (!TryComp(entity, out CryoPodAirComponent? cryoPodAir))
+ if (!TryComp(uid, out CryoPodAirComponent? cryoPodAir))
return;
_atmosphereSystem.React(cryoPodAir.Air, portNode);
- if (portNode.NodeGroup is PipeNet { NodeCount: > 1 } net)
+ if (portNode.NodeGroup is PipeNet {NodeCount: > 1} net)
{
_gasCanisterSystem.MixContainerWithPipeNet(cryoPodAir.Air, net.Air);
}
}
- private void OnGasAnalyzed(Entity<CryoPodComponent> entity, ref GasAnalyzerScanEvent args)
+ private void OnGasAnalyzed(EntityUid uid, CryoPodComponent component, GasAnalyzerScanEvent args)
{
- if (!TryComp(entity, out CryoPodAirComponent? cryoPodAir))
+ if (!TryComp(uid, out CryoPodAirComponent? cryoPodAir))
return;
- var gasMixDict = new Dictionary<string, GasMixture?> { { Name(entity.Owner), cryoPodAir.Air } };
+ var gasMixDict = new Dictionary<string, GasMixture?> { { Name(uid), cryoPodAir.Air } };
// If it's connected to a port, include the port side
- if (TryComp(entity, out NodeContainerComponent? nodeContainer))
+ if (TryComp(uid, out NodeContainerComponent? nodeContainer))
{
- if (_nodeContainer.TryGetNode(nodeContainer, entity.Comp.PortName, out PipeNode? port))
- gasMixDict.Add(entity.Comp.PortName, port.Air);
+ if (_nodeContainer.TryGetNode(nodeContainer, component.PortName, out PipeNode? port))
+ gasMixDict.Add(component.PortName, port.Air);
}
args.GasMixtures = gasMixDict;
}
+
#endregion
}
using Content.Server.Administration.Logs;
using Content.Server.Body.Components;
using Content.Server.Body.Systems;
-using Content.Server.Chemistry.Containers.EntitySystems;
using Content.Server.Medical.Components;
-using Content.Server.Popups;
using Content.Server.Stack;
using Content.Shared.Audio;
using Content.Shared.Damage;
using Content.Shared.Mobs.Components;
using Content.Shared.Mobs.Systems;
using Content.Shared.Stacks;
+using Content.Server.Popups;
+using Robust.Shared.Audio;
using Robust.Shared.Audio.Systems;
using Robust.Shared.Random;
[Dependency] private readonly SharedInteractionSystem _interactionSystem = default!;
[Dependency] private readonly MobThresholdSystem _mobThresholdSystem = default!;
[Dependency] private readonly PopupSystem _popupSystem = default!;
- [Dependency] private readonly SolutionContainerSystem _solutionContainerSystem = default!;
public override void Initialize()
{
SubscribeLocalEvent<DamageableComponent, HealingDoAfterEvent>(OnDoAfter);
}
- private void OnDoAfter(Entity<DamageableComponent> entity, ref HealingDoAfterEvent args)
+ private void OnDoAfter(EntityUid uid, DamageableComponent component, HealingDoAfterEvent args)
{
var dontRepeat = false;
return;
if (healing.DamageContainers is not null &&
- entity.Comp.DamageContainerID is not null &&
- !healing.DamageContainers.Contains(entity.Comp.DamageContainerID))
+ component.DamageContainerID is not null &&
+ !healing.DamageContainers.Contains(component.DamageContainerID))
{
return;
}
// Heal some bloodloss damage.
if (healing.BloodlossModifier != 0)
{
- if (!TryComp<BloodstreamComponent>(entity, out var bloodstream))
+ if (!TryComp<BloodstreamComponent>(uid, out var bloodstream))
return;
var isBleeding = bloodstream.BleedAmount > 0;
- _bloodstreamSystem.TryModifyBleedAmount(entity.Owner, healing.BloodlossModifier);
+ _bloodstreamSystem.TryModifyBleedAmount(uid, healing.BloodlossModifier);
if (isBleeding != bloodstream.BleedAmount > 0)
{
dontRepeat = true;
- _popupSystem.PopupEntity(Loc.GetString("medical-item-stop-bleeding"), entity, args.User);
+ _popupSystem.PopupEntity(Loc.GetString("medical-item-stop-bleeding"), uid, args.User);
}
}
// Restores missing blood
if (healing.ModifyBloodLevel != 0)
- _bloodstreamSystem.TryModifyBloodLevel(entity.Owner, healing.ModifyBloodLevel);
+ _bloodstreamSystem.TryModifyBloodLevel(uid, healing.ModifyBloodLevel);
- var healed = _damageable.TryChangeDamage(entity.Owner, healing.Damage, true, origin: args.Args.User);
+ var healed = _damageable.TryChangeDamage(uid, healing.Damage, true, origin: args.Args.User);
if (healed == null && healing.BloodlossModifier != 0)
return;
QueueDel(args.Used.Value);
}
- if (entity.Owner != args.User)
+ if (uid != args.User)
{
_adminLogger.Add(LogType.Healed,
- $"{EntityManager.ToPrettyString(args.User):user} healed {EntityManager.ToPrettyString(entity.Owner):target} for {total:damage} damage");
+ $"{EntityManager.ToPrettyString(args.User):user} healed {EntityManager.ToPrettyString(uid):target} for {total:damage} damage");
}
else
{
$"{EntityManager.ToPrettyString(args.User):user} healed themselves for {total:damage} damage");
}
- _audio.PlayPvs(healing.HealingEndSound, entity.Owner, AudioHelpers.WithVariation(0.125f, _random).WithVolume(-5f));
+ _audio.PlayPvs(healing.HealingEndSound, uid, AudioHelpers.WithVariation(0.125f, _random).WithVolume(-5f));
// Logic to determine the whether or not to repeat the healing action
- args.Repeat = (HasDamage(entity.Comp, healing) && !dontRepeat);
+ args.Repeat = (HasDamage(component, healing) && !dontRepeat);
if (!args.Repeat && !dontRepeat)
- _popupSystem.PopupEntity(Loc.GetString("medical-item-finished-using", ("item", args.Used)), entity.Owner, args.User);
+ _popupSystem.PopupEntity(Loc.GetString("medical-item-finished-using", ("item", args.Used)), uid, args.User);
args.Handled = true;
}
return false;
}
- private void OnHealingUse(Entity<HealingComponent> entity, ref UseInHandEvent args)
+ private void OnHealingUse(EntityUid uid, HealingComponent component, UseInHandEvent args)
{
if (args.Handled)
return;
- if (TryHeal(entity, args.User, args.User, entity.Comp))
+ if (TryHeal(uid, args.User, args.User, component))
args.Handled = true;
}
- private void OnHealingAfterInteract(Entity<HealingComponent> entity, ref AfterInteractEvent args)
+ private void OnHealingAfterInteract(EntityUid uid, HealingComponent component, AfterInteractEvent args)
{
if (args.Handled || !args.CanReach || args.Target == null)
return;
- if (TryHeal(entity, args.User, args.Target.Value, entity.Comp))
+ if (TryHeal(uid, args.User, args.Target.Value, component))
args.Handled = true;
}
if (TryComp<StackComponent>(uid, out var stack) && stack.Count < 1)
return false;
- var anythingToDo =
- HasDamage(targetDamage, component) ||
- component.ModifyBloodLevel > 0 // Special case if healing item can restore lost blood...
- && TryComp<BloodstreamComponent>(target, out var bloodstream)
- && _solutionContainerSystem.ResolveSolution(target, bloodstream.BloodSolutionName, ref bloodstream.BloodSolution, out var bloodSolution)
- && bloodSolution.Volume < bloodSolution.MaxVolume; // ...and there is lost blood to restore.
+ if (!TryComp<BloodstreamComponent>(target, out var bloodstream))
+ return false;
- if (!anythingToDo)
+ if (!HasDamage(targetDamage, component) && !(bloodstream.BloodSolution.Volume < bloodstream.BloodSolution.MaxVolume && component.ModifyBloodLevel > 0))
{
_popupSystem.PopupEntity(Loc.GetString("medical-item-cant-use", ("item", uid)), uid, user);
return false;
-using Content.Server.Body.Components;
-using Content.Server.Chemistry.Containers.EntitySystems;
using Content.Server.Medical.Components;
using Content.Server.PowerCell;
-using Content.Server.Temperature.Components;
using Content.Shared.Damage;
using Content.Shared.DoAfter;
using Content.Shared.Interaction;
using Content.Shared.MedicalScanner;
using Content.Shared.Mobs.Components;
using Robust.Server.GameObjects;
+using Content.Server.Temperature.Components;
+using Content.Server.Body.Components;
+using Robust.Shared.Audio;
using Robust.Shared.Audio.Systems;
using Robust.Shared.Player;
[Dependency] private readonly PowerCellSystem _cell = default!;
[Dependency] private readonly SharedAudioSystem _audio = default!;
[Dependency] private readonly SharedDoAfterSystem _doAfterSystem = default!;
- [Dependency] private readonly SolutionContainerSystem _solutionContainerSystem = default!;
[Dependency] private readonly UserInterfaceSystem _uiSystem = default!;
public override void Initialize()
SubscribeLocalEvent<HealthAnalyzerComponent, HealthAnalyzerDoAfterEvent>(OnDoAfter);
}
- private void OnAfterInteract(Entity<HealthAnalyzerComponent> entity, ref AfterInteractEvent args)
+ private void OnAfterInteract(EntityUid uid, HealthAnalyzerComponent healthAnalyzer, AfterInteractEvent args)
{
- if (args.Target == null || !args.CanReach || !HasComp<MobStateComponent>(args.Target) || !_cell.HasActivatableCharge(entity.Owner, user: args.User))
+ if (args.Target == null || !args.CanReach || !HasComp<MobStateComponent>(args.Target) || !_cell.HasActivatableCharge(uid, user: args.User))
return;
- _audio.PlayPvs(entity.Comp.ScanningBeginSound, entity);
+ _audio.PlayPvs(healthAnalyzer.ScanningBeginSound, uid);
- _doAfterSystem.TryStartDoAfter(new DoAfterArgs(EntityManager, args.User, TimeSpan.FromSeconds(entity.Comp.ScanDelay), new HealthAnalyzerDoAfterEvent(), entity.Owner, target: args.Target, used: entity.Owner)
+ _doAfterSystem.TryStartDoAfter(new DoAfterArgs(EntityManager, args.User, healthAnalyzer.ScanDelay, new HealthAnalyzerDoAfterEvent(), uid, target: args.Target, used: uid)
{
BreakOnTargetMove = true,
BreakOnUserMove = true,
});
}
- private void OnDoAfter(Entity<HealthAnalyzerComponent> entity, ref HealthAnalyzerDoAfterEvent args)
+ private void OnDoAfter(EntityUid uid, HealthAnalyzerComponent component, DoAfterEvent args)
{
- if (args.Handled || args.Cancelled || args.Target == null || !_cell.TryUseActivatableCharge(entity.Owner, user: args.User))
+ if (args.Handled || args.Cancelled || args.Args.Target == null || !_cell.TryUseActivatableCharge(uid, user: args.User))
return;
- _audio.PlayPvs(entity.Comp.ScanningEndSound, args.User);
+ _audio.PlayPvs(component.ScanningEndSound, args.Args.User);
- UpdateScannedUser(entity, args.User, args.Target.Value, entity.Comp);
+ UpdateScannedUser(uid, args.Args.User, args.Args.Target.Value, component);
args.Handled = true;
}
if (!HasComp<DamageableComponent>(target))
return;
- float bodyTemperature;
- if (TryComp<TemperatureComponent>(target, out var temp))
- bodyTemperature = temp.CurrentTemperature;
- else
- bodyTemperature = float.NaN;
-
- float bloodAmount;
- if (TryComp<BloodstreamComponent>(target, out var bloodstream) &&
- _solutionContainerSystem.ResolveSolution(target.Value, bloodstream.BloodSolutionName, ref bloodstream.BloodSolution, out var bloodSolution))
- bloodAmount = bloodSolution.FillFraction;
- else
- bloodAmount = float.NaN;
+ TryComp<TemperatureComponent>(target, out var temp);
+ TryComp<BloodstreamComponent>(target, out var bloodstream);
OpenUserInterface(user, uid);
- _uiSystem.SendUiMessage(ui, new HealthAnalyzerScannedUserMessage(
- GetNetEntity(target),
- bodyTemperature,
- bloodAmount
- ));
+ _uiSystem.SendUiMessage(ui, new HealthAnalyzerScannedUserMessage(GetNetEntity(target), temp != null ? temp.CurrentTemperature : float.NaN,
+ bloodstream != null ? bloodstream.BloodSolution.FillFraction : float.NaN));
}
}
}
using Content.Server.Body.Components;
using Content.Server.Body.Systems;
-using Content.Server.Chemistry.Containers.EntitySystems;
using Content.Server.Fluids.EntitySystems;
using Content.Server.Forensics;
using Content.Server.Popups;
using Content.Server.Stunnable;
using Content.Shared.Chemistry.Components;
+using Content.Shared.Chemistry.EntitySystems;
using Content.Shared.IdentityManagement;
using Content.Shared.Nutrition.Components;
using Content.Shared.Nutrition.EntitySystems;
using Content.Shared.StatusEffect;
using Robust.Server.Audio;
+using Robust.Server.GameObjects;
using Robust.Shared.Audio;
using Robust.Shared.Prototypes;
// Empty the stomach out into it
foreach (var stomach in stomachList)
{
- if (_solutionContainer.ResolveSolution(stomach.Comp.Owner, StomachSystem.DefaultSolutionName, ref stomach.Comp.Solution, out var sol))
+ if (_solutionContainer.TryGetSolution(stomach.Comp.Owner, StomachSystem.DefaultSolutionName,
+ out var sol))
{
solution.AddSolution(sol, _proto);
sol.RemoveAllSolution();
- _solutionContainer.UpdateChemicals(stomach.Comp.Solution.Value);
+ _solutionContainer.UpdateChemicals(stomach.Comp.Owner, sol);
}
}
// Adds a tiny amount of the chem stream from earlier along with vomit
if (TryComp<BloodstreamComponent>(uid, out var bloodStream))
{
- const float chemMultiplier = 0.1f;
+ var chemMultiplier = 0.1;
+ var vomitMultiplier = 0.9;
- var vomitAmount = solutionSize;
+ // Makes a vomit solution the size of 90% of the chemicals removed from the chemstream
+ var vomitAmount = new Solution("Vomit", solutionSize * vomitMultiplier);
// Takes 10% of the chemicals removed from the chem stream
- if (_solutionContainer.ResolveSolution(uid, bloodStream.ChemicalSolutionName, ref bloodStream.ChemicalSolution))
- {
- var vomitChemstreamAmount = _solutionContainer.SplitSolution(bloodStream.ChemicalSolution.Value, vomitAmount);
- vomitChemstreamAmount.ScaleSolution(chemMultiplier);
- solution.AddSolution(vomitChemstreamAmount, _proto);
+ var vomitChemstreamAmount = _solutionContainer.SplitSolution(uid, bloodStream.ChemicalSolution, solutionSize * chemMultiplier);
- vomitAmount -= (float) vomitChemstreamAmount.Volume;
- }
-
- // Makes a vomit solution the size of 90% of the chemicals removed from the chemstream
- solution.AddReagent("Vomit", vomitAmount); // TODO: Dehardcode vomit prototype
+ _solutionContainer.SplitSolution(uid, bloodStream.ChemicalSolution, solutionSize * vomitMultiplier);
+ solution.AddSolution(vomitAmount, _proto);
+ solution.AddSolution(vomitChemstreamAmount, _proto);
}
if (_puddle.TrySpillAt(uid, solution, out var puddle, false))
using Content.Server.Chat.Systems;
-using Content.Server.Chemistry.Containers.EntitySystems;
using Content.Server.NPC.Components;
+using Content.Shared.Chemistry.EntitySystems;
using Content.Shared.Damage;
using Content.Shared.Emag.Components;
using Content.Shared.Interaction;
using Content.Shared.Mobs.Components;
using Content.Shared.Popups;
using Content.Shared.Silicons.Bots;
+using Robust.Shared.Audio;
using Robust.Shared.Audio.Systems;
+using Robust.Shared.Player;
namespace Content.Server.NPC.HTN.PrimitiveTasks.Operators.Specific;
private SharedAudioSystem _audio = default!;
private SharedInteractionSystem _interaction = default!;
private SharedPopupSystem _popup = default!;
- private SolutionContainerSystem _solutionContainer = default!;
+ private SolutionContainerSystem _solution = default!;
/// <summary>
/// Target entity to inject.
_audio = sysManager.GetEntitySystem<SharedAudioSystem>();
_interaction = sysManager.GetEntitySystem<SharedInteractionSystem>();
_popup = sysManager.GetEntitySystem<SharedPopupSystem>();
- _solutionContainer = sysManager.GetEntitySystem<SolutionContainerSystem>();
+ _solution = sysManager.GetEntitySystem<SolutionContainerSystem>();
}
public override void TaskShutdown(NPCBlackboard blackboard, HTNOperatorStatus status)
if (!_entMan.TryGetComponent<DamageableComponent>(target, out var damage))
return HTNOperatorStatus.Failed;
- if (!_solutionContainer.TryGetInjectableSolution(target, out var injectable, out _))
+ if (!_solution.TryGetInjectableSolution(target, out var injectable))
return HTNOperatorStatus.Failed;
if (!_interaction.InRangeUnobstructed(owner, target))
return HTNOperatorStatus.Failed;
_entMan.EnsureComponent<NPCRecentlyInjectedComponent>(target);
- _solutionContainer.TryAddReagent(injectable.Value, treatment.Reagent, treatment.Quantity, out _);
+ _solution.TryAddReagent(target, injectable, treatment.Reagent, treatment.Quantity, out _);
_popup.PopupEntity(Loc.GetString("hypospray-component-feel-prick-message"), target, target);
_audio.PlayPvs(botComp.InjectSound, target);
_chat.TrySendInGameICMessage(owner, Loc.GetString("medibot-finish-inject"), InGameICChatType.Speak, hideChat: true, hideLog: true);
-using Content.Server.Chemistry.Containers.EntitySystems;
+using System.Linq;
using Content.Server.Fluids.EntitySystems;
using Content.Server.NPC.Queries;
using Content.Server.NPC.Queries.Considerations;
using Content.Server.Nutrition.Components;
using Content.Server.Nutrition.EntitySystems;
using Content.Server.Storage.Components;
+using Content.Shared.Chemistry.EntitySystems;
using Content.Shared.Examine;
using Content.Shared.Fluids.Components;
using Content.Shared.Hands.Components;
using Content.Shared.Weapons.Ranged.Events;
using Microsoft.Extensions.ObjectPool;
using Robust.Server.Containers;
+using Robust.Shared.Collections;
using Robust.Shared.Prototypes;
using Robust.Shared.Utility;
-using System.Linq;
namespace Content.Server.NPC.Systems;
foreach (var ent in entities)
{
if (!_puddleQuery.TryGetComponent(ent, out var puddleComp) ||
- !_solutions.TryGetSolution(ent, puddleComp.SolutionName, out _, out var sol) ||
+ !_solutions.TryGetSolution(ent, puddleComp.SolutionName, out var sol) ||
_puddle.CanFullyEvaporate(sol))
{
_entityList.Add(ent);
-using Content.Server.Chemistry.Containers.EntitySystems;
using Content.Server.Explosion.Components;
using Content.Server.Explosion.EntitySystems;
using Content.Server.Fluids.EntitySystems;
using Content.Server.Nutrition.Components;
using Content.Server.Popups;
+using Content.Shared.Chemistry.EntitySystems;
using Content.Shared.Containers.ItemSlots;
using Content.Shared.Interaction;
using Content.Shared.Nutrition.Components;
using Content.Shared.Rejuvenate;
using Content.Shared.Throwing;
using JetBrains.Annotations;
+using Robust.Server.GameObjects;
using Robust.Shared.Audio;
using Robust.Shared.Audio.Systems;
using Robust.Shared.Player;
if (EntityManager.TryGetComponent(uid, out FoodComponent? foodComp))
{
- if (_solutions.TryGetSolution(uid, foodComp.Solution, out _, out var solution))
+ if (_solutions.TryGetSolution(uid, foodComp.Solution, out var solution))
{
_puddle.TrySpillAt(uid, solution, out _, false);
}
EntityManager.QueueDeleteEntity(uid);
}
- private void OnInteractUsing(Entity<CreamPieComponent> entity, ref InteractUsingEvent args)
+ private void OnInteractUsing(EntityUid uid, CreamPieComponent component, InteractUsingEvent args)
{
- ActivatePayload(entity);
+ ActivatePayload(uid);
}
private void ActivatePayload(EntityUid uid)
{
otherPlayers.RemovePlayer(actor.PlayerSession);
}
- _popup.PopupEntity(Loc.GetString("cream-pied-component-on-hit-by-message-others", ("owner", uid), ("thrower", args.Thrown)), uid, otherPlayers, false);
+ _popup.PopupEntity(Loc.GetString("cream-pied-component-on-hit-by-message-others", ("owner", uid),("thrower", args.Thrown)), uid, otherPlayers, false);
}
- private void OnRejuvenate(Entity<CreamPiedComponent> entity, ref RejuvenateEvent args)
+ private void OnRejuvenate(EntityUid uid, CreamPiedComponent component, RejuvenateEvent args)
{
- SetCreamPied(entity, entity.Comp, false);
+ SetCreamPied(uid, component, false);
}
}
}
using Content.Server.Body.Components;
using Content.Server.Body.Systems;
-using Content.Server.Chemistry.Containers.EntitySystems;
+using Content.Server.Chemistry.EntitySystems;
using Content.Server.Chemistry.ReagentEffects;
using Content.Server.Fluids.EntitySystems;
using Content.Server.Forensics;
base.Initialize();
// TODO add InteractNoHandEvent for entities like mice.
- SubscribeLocalEvent<DrinkComponent, SolutionContainerChangedEvent>(OnSolutionChange);
+ SubscribeLocalEvent<DrinkComponent, SolutionChangedEvent>(OnSolutionChange);
SubscribeLocalEvent<DrinkComponent, ComponentInit>(OnDrinkInit);
// run before inventory so for bucket it always tries to drink before equipping (when empty)
// run after openable so its always open -> drink
if (!Resolve(uid, ref component))
return FixedPoint2.Zero;
- if (!_solutionContainer.TryGetSolution(uid, component.Solution, out _, out var sol))
+ if (!_solutionContainer.TryGetSolution(uid, component.Solution, out var sol))
return FixedPoint2.Zero;
return sol.Volume;
if (!Resolve(uid, ref comp))
return 0f;
- if (!_solutionContainer.TryGetSolution(uid, comp.Solution, out _, out var solution))
+ if (!_solutionContainer.TryGetSolution(uid, comp.Solution, out var solution))
return 0f;
var total = 0f;
return total;
}
- private void OnExamined(Entity<DrinkComponent> entity, ref ExaminedEvent args)
+ private void OnExamined(EntityUid uid, DrinkComponent component, ExaminedEvent args)
{
- var hasOpenable = TryComp<OpenableComponent>(entity, out var openable);
- if (_openable.IsClosed(entity.Owner, null, openable) || !args.IsInDetailsRange || !entity.Comp.Examinable)
+ var hasOpenable = TryComp<OpenableComponent>(uid, out var openable);
+ if (_openable.IsClosed(uid, null, openable) || !args.IsInDetailsRange || !component.Examinable)
return;
// put Empty / Xu after Opened, or start a new line
args.Message.AddMarkup(hasOpenable ? " - " : "\n");
- var empty = IsEmpty(entity, entity.Comp);
+ var empty = IsEmpty(uid, component);
if (empty)
{
args.Message.AddMarkup(Loc.GetString("drink-component-on-examine-is-empty"));
return;
}
- if (TryComp<ExaminableSolutionComponent>(entity, out var comp))
+ if (TryComp<ExaminableSolutionComponent>(uid, out var comp))
{
//provide exact measurement for beakers
- args.Message.AddMarkup(Loc.GetString("drink-component-on-examine-exact-volume", ("amount", DrinkVolume(entity, entity.Comp))));
+ args.Message.AddMarkup(Loc.GetString("drink-component-on-examine-exact-volume", ("amount", DrinkVolume(uid, component))));
}
else
{
//general approximation
- var remainingString = (int) _solutionContainer.PercentFull(entity) switch
+ var remainingString = (int) _solutionContainer.PercentFull(uid) switch
{
100 => "drink-component-on-examine-is-full",
> 66 => "drink-component-on-examine-is-mostly-full",
}
}
- private void AfterInteract(Entity<DrinkComponent> entity, ref AfterInteractEvent args)
+ private void AfterInteract(EntityUid uid, DrinkComponent component, AfterInteractEvent args)
{
if (args.Handled || args.Target == null || !args.CanReach)
return;
- args.Handled = TryDrink(args.User, args.Target.Value, entity.Comp, entity);
+ args.Handled = TryDrink(args.User, args.Target.Value, component, uid);
}
- private void OnUse(Entity<DrinkComponent> entity, ref UseInHandEvent args)
+ private void OnUse(EntityUid uid, DrinkComponent component, UseInHandEvent args)
{
if (args.Handled)
return;
- args.Handled = TryDrink(args.User, args.User, entity.Comp, entity);
+ args.Handled = TryDrink(args.User, args.User, component, uid);
}
- private void OnPressurizedDrinkLand(Entity<PressurizedDrinkComponent> entity, ref LandEvent args)
+ private void OnPressurizedDrinkLand(EntityUid uid, PressurizedDrinkComponent comp, ref LandEvent args)
{
- if (!TryComp<DrinkComponent>(entity, out var drink) || !TryComp<OpenableComponent>(entity, out var openable))
+ if (!TryComp<DrinkComponent>(uid, out var drink) || !TryComp<OpenableComponent>(uid, out var openable))
return;
if (!openable.Opened &&
- _random.Prob(entity.Comp.BurstChance) &&
- _solutionContainer.TryGetSolution(entity.Owner, drink.Solution, out var soln, out var interactions))
+ _random.Prob(comp.BurstChance) &&
+ _solutionContainer.TryGetSolution(uid, drink.Solution, out var interactions))
{
// using SetOpen instead of TryOpen to not play 2 sounds
- _openable.SetOpen(entity, true, openable);
+ _openable.SetOpen(uid, true, openable);
- var solution = _solutionContainer.SplitSolution(soln.Value, interactions.Volume);
- _puddle.TrySpillAt(entity, solution, out _);
+ var solution = _solutionContainer.SplitSolution(uid, interactions, interactions.Volume);
+ _puddle.TrySpillAt(uid, solution, out _);
- _audio.PlayPvs(entity.Comp.BurstSound, entity);
+ _audio.PlayPvs(comp.BurstSound, uid);
}
}
- private void OnDrinkInit(Entity<DrinkComponent> entity, ref ComponentInit args)
+ private void OnDrinkInit(EntityUid uid, DrinkComponent component, ComponentInit args)
{
- if (TryComp<DrainableSolutionComponent>(entity, out var existingDrainable))
+ if (TryComp<DrainableSolutionComponent>(uid, out var existingDrainable))
{
// Beakers have Drink component but they should use the existing Drainable
- entity.Comp.Solution = existingDrainable.Solution;
+ component.Solution = existingDrainable.Solution;
}
else
{
- _solutionContainer.EnsureSolution(entity.Owner, entity.Comp.Solution);
+ _solutionContainer.EnsureSolution(uid, component.Solution);
}
- UpdateAppearance(entity, entity.Comp);
+ UpdateAppearance(uid, component);
- if (TryComp(entity, out RefillableSolutionComponent? refillComp))
- refillComp.Solution = entity.Comp.Solution;
+ if (TryComp(uid, out RefillableSolutionComponent? refillComp))
+ refillComp.Solution = component.Solution;
- if (TryComp(entity, out DrainableSolutionComponent? drainComp))
- drainComp.Solution = entity.Comp.Solution;
+ if (TryComp(uid, out DrainableSolutionComponent? drainComp))
+ drainComp.Solution = component.Solution;
}
- private void OnSolutionChange(Entity<DrinkComponent> entity, ref SolutionContainerChangedEvent args)
+ private void OnSolutionChange(EntityUid uid, DrinkComponent component, SolutionChangedEvent args)
{
- UpdateAppearance(entity, entity.Comp);
+ UpdateAppearance(uid, component);
}
public void UpdateAppearance(EntityUid uid, DrinkComponent component)
if (_openable.IsClosed(item, user))
return true;
- if (!_solutionContainer.TryGetSolution(item, drink.Solution, out _, out var drinkSolution) || drinkSolution.Volume <= 0)
+ if (!_solutionContainer.TryGetSolution(item, drink.Solution, out var drinkSolution) ||
+ drinkSolution.Volume <= 0)
{
if (drink.IgnoreEmpty)
return false;
return true;
}
+ if (drinkSolution.Name == null)
+ return false;
+
if (_food.IsMouthBlocked(target, user))
return true;
var doAfterEventArgs = new DoAfterArgs(EntityManager,
user,
forceDrink ? drink.ForceFeedDelay : drink.Delay,
- new ConsumeDoAfterEvent(drink.Solution, flavors),
+ new ConsumeDoAfterEvent(drinkSolution.Name, flavors),
eventTarget: item,
target: target,
used: item)
/// <summary>
/// Raised directed at a victim when someone has force fed them a drink.
/// </summary>
- private void OnDoAfter(Entity<DrinkComponent> entity, ref ConsumeDoAfterEvent args)
+ private void OnDoAfter(EntityUid uid, DrinkComponent component, ConsumeDoAfterEvent args)
{
- if (args.Handled || args.Cancelled || entity.Comp.Deleted)
+ if (args.Handled || args.Cancelled || component.Deleted)
return;
if (!TryComp<BodyComponent>(args.Target, out var body))
return;
- if (args.Used is null || !_solutionContainer.TryGetSolution(args.Used.Value, args.Solution, out var soln, out var solution))
+ if (!_solutionContainer.TryGetSolution(args.Used, args.Solution, out var solution))
return;
// TODO this should really be checked every tick.
if (!_interaction.InRangeUnobstructed(args.User, args.Target.Value))
return;
- var transferAmount = FixedPoint2.Min(entity.Comp.TransferAmount, solution.Volume);
- var drained = _solutionContainer.SplitSolution(soln.Value, transferAmount);
+ var transferAmount = FixedPoint2.Min(component.TransferAmount, solution.Volume);
+ var drained = _solutionContainer.SplitSolution(uid, solution, transferAmount);
var forceDrink = args.User != args.Target;
args.Handled = true;
return;
}
- _solutionContainer.Refill(args.Target.Value, soln.Value, drained);
+ _solutionContainer.Refill(args.Target.Value, solution, drained);
return;
}
- var firstStomach = stomachs.FirstOrNull(stomach => _stomach.CanTransferSolution(stomach.Comp.Owner, drained, stomach.Comp));
+ var firstStomach = stomachs.FirstOrNull(stomach => _stomach.CanTransferSolution(stomach.Comp.Owner, drained));
//All stomachs are full or can't handle whatever solution we have.
if (firstStomach == null)
_puddle.TrySpillAt(args.Target.Value, drained, out _);
}
else
- _solutionContainer.TryAddSolution(soln.Value, drained);
+ _solutionContainer.TryAddSolution(uid, solution, drained);
return;
}
args.User, args.User);
// log successful forced drinking
- _adminLogger.Add(LogType.ForceFeed, LogImpact.Medium, $"{ToPrettyString(entity.Owner):user} forced {ToPrettyString(args.User):target} to drink {ToPrettyString(entity.Owner):drink}");
+ _adminLogger.Add(LogType.ForceFeed, LogImpact.Medium, $"{ToPrettyString(uid):user} forced {ToPrettyString(args.User):target} to drink {ToPrettyString(uid):drink}");
}
else
{
Loc.GetString("drink-component-try-use-drink-success-slurp"), args.User, Filter.PvsExcept(args.User), true);
// log successful voluntary drinking
- _adminLogger.Add(LogType.Ingestion, LogImpact.Low, $"{ToPrettyString(args.User):target} drank {ToPrettyString(entity.Owner):drink}");
+ _adminLogger.Add(LogType.Ingestion, LogImpact.Low, $"{ToPrettyString(args.User):target} drank {ToPrettyString(uid):drink}");
}
- _audio.PlayPvs(entity.Comp.UseSound, args.Target.Value, AudioParams.Default.WithVolume(-2f));
+ _audio.PlayPvs(component.UseSound, args.Target.Value, AudioParams.Default.WithVolume(-2f));
_reaction.DoEntityReaction(args.Target.Value, solution, ReactionMethod.Ingestion);
//TODO: Grab the stomach UIDs somehow without using Owner
_stomach.TryTransferSolution(firstStomach.Value.Comp.Owner, drained, firstStomach.Value.Comp);
- _forensics.TransferDna(entity, args.Target.Value);
+ _forensics.TransferDna(uid, args.Target.Value);
if (!forceDrink && solution.Volume > 0)
args.Repeat = true;
}
- private void AddDrinkVerb(Entity<DrinkComponent> entity, ref GetVerbsEvent<AlternativeVerb> ev)
+ private void AddDrinkVerb(EntityUid uid, DrinkComponent component, GetVerbsEvent<AlternativeVerb> ev)
{
- if (entity.Owner == ev.User ||
+ if (uid == ev.User ||
!ev.CanInteract ||
!ev.CanAccess ||
!TryComp<BodyComponent>(ev.User, out var body) ||
return;
// no drinking from living drinks, have to kill them first.
- if (_mobState.IsAlive(entity))
+ if (_mobState.IsAlive(uid))
return;
- var user = ev.User;
AlternativeVerb verb = new()
{
Act = () =>
{
- TryDrink(user, user, entity.Comp, entity);
+ TryDrink(ev.User, ev.User, component, uid);
},
- Icon = new SpriteSpecifier.Texture(new("/Textures/Interface/VerbIcons/drink.svg.192dpi.png")),
+ Icon = new SpriteSpecifier.Texture(new ("/Textures/Interface/VerbIcons/drink.svg.192dpi.png")),
Text = Loc.GetString("drink-system-verb-drink"),
Priority = 2
};
+using System.Linq;
+using System.Text;
using Content.Server.Nutrition.Components;
using Content.Shared.CCVar;
using Content.Shared.Chemistry.Components;
+using Content.Shared.Chemistry.Reagent;
using Content.Shared.Nutrition;
+using Microsoft.VisualBasic;
using Robust.Shared.Configuration;
using Robust.Shared.Prototypes;
-using System.Linq;
namespace Content.Server.Nutrition.EntitySystems;
+using System.Linq;
using Content.Server.Body.Components;
using Content.Server.Body.Systems;
-using Content.Server.Chemistry.Containers.EntitySystems;
using Content.Server.Inventory;
using Content.Server.Nutrition.Components;
using Content.Server.Popups;
using Content.Shared.Body.Components;
using Content.Shared.Body.Organ;
using Content.Shared.Chemistry;
+using Content.Shared.Chemistry.EntitySystems;
using Content.Shared.Chemistry.Reagent;
using Content.Shared.Database;
using Content.Shared.DoAfter;
using Content.Shared.Storage;
using Content.Shared.Verbs;
using Robust.Shared.Audio;
-using Robust.Shared.Audio.Systems;
+using Robust.Shared.Player;
using Robust.Shared.Utility;
-using System.Linq;
+using Content.Shared.Tag;
+using Content.Shared.Storage;
+using Robust.Shared.Audio.Systems;
namespace Content.Server.Nutrition.EntitySystems;
/// <summary>
/// Eat item
/// </summary>
- private void OnUseFoodInHand(Entity<FoodComponent> entity, ref UseInHandEvent ev)
+ private void OnUseFoodInHand(EntityUid uid, FoodComponent foodComponent, UseInHandEvent ev)
{
if (ev.Handled)
return;
- var result = TryFeed(ev.User, ev.User, entity, entity.Comp);
+ var result = TryFeed(ev.User, ev.User, uid, foodComponent);
ev.Handled = result.Handled;
}
/// <summary>
/// Feed someone else
/// </summary>
- private void OnFeedFood(Entity<FoodComponent> entity, ref AfterInteractEvent args)
+ private void OnFeedFood(EntityUid uid, FoodComponent foodComponent, AfterInteractEvent args)
{
if (args.Handled || args.Target == null || !args.CanReach)
return;
- var result = TryFeed(args.User, args.Target.Value, entity, entity.Comp);
+ var result = TryFeed(args.User, args.Target.Value, uid, foodComponent);
args.Handled = result.Handled;
}
if (_openable.IsClosed(food, user))
return (false, true);
- if (!_solutionContainer.TryGetSolution(food, foodComp.Solution, out _, out var foodSolution))
+ if (!_solutionContainer.TryGetSolution(food, foodComp.Solution, out var foodSolution) || foodSolution.Name == null)
return (false, false);
if (!_body.TryGetBodyOrganComponents<StomachComponent>(target, out var stomachs, body))
var doAfterArgs = new DoAfterArgs(EntityManager,
user,
forceFeed ? foodComp.ForceFeedDelay : foodComp.Delay,
- new ConsumeDoAfterEvent(foodComp.Solution, flavors),
+ new ConsumeDoAfterEvent(foodSolution.Name, flavors),
eventTarget: food,
target: target,
used: food)
return (true, true);
}
- private void OnDoAfter(Entity<FoodComponent> entity, ref ConsumeDoAfterEvent args)
+ private void OnDoAfter(EntityUid uid, FoodComponent component, ConsumeDoAfterEvent args)
{
- if (args.Cancelled || args.Handled || entity.Comp.Deleted || args.Target == null)
+ if (args.Cancelled || args.Handled || component.Deleted || args.Target == null)
return;
if (!TryComp<BodyComponent>(args.Target.Value, out var body))
if (!_body.TryGetBodyOrganComponents<StomachComponent>(args.Target.Value, out var stomachs, body))
return;
- if (args.Used is null || !_solutionContainer.TryGetSolution(args.Used.Value, args.Solution, out var soln, out var solution))
+ if (!_solutionContainer.TryGetSolution(args.Used, args.Solution, out var solution))
return;
- if (!TryGetRequiredUtensils(args.User, entity.Comp, out var utensils))
+ if (!TryGetRequiredUtensils(args.User, component, out var utensils))
return;
// TODO this should really be checked every tick.
var forceFeed = args.User != args.Target;
args.Handled = true;
- var transferAmount = entity.Comp.TransferAmount != null ? FixedPoint2.Min((FixedPoint2) entity.Comp.TransferAmount, solution.Volume) : solution.Volume;
+ var transferAmount = component.TransferAmount != null ? FixedPoint2.Min((FixedPoint2) component.TransferAmount, solution.Volume) : solution.Volume;
- var split = _solutionContainer.SplitSolution(soln.Value, transferAmount);
+ var split = _solutionContainer.SplitSolution(uid, solution, transferAmount);
//TODO: Get the stomach UID somehow without nabbing owner
// Get the stomach with the highest available solution volume
foreach (var (stomach, _) in stomachs)
{
var owner = stomach.Owner;
- if (!_stomach.CanTransferSolution(owner, split, stomach))
+ if (!_stomach.CanTransferSolution(owner, split))
continue;
- if (!_solutionContainer.ResolveSolution(owner, StomachSystem.DefaultSolutionName, ref stomach.Solution, out var stomachSol))
+ if (!_solutionContainer.TryGetSolution(owner, StomachSystem.DefaultSolutionName,
+ out var stomachSol))
continue;
if (stomachSol.AvailableVolume <= highestAvailable)
// No stomach so just popup a message that they can't eat.
if (stomachToUse == null)
{
- _solutionContainer.TryAddSolution(soln.Value, split);
+ _solutionContainer.TryAddSolution(uid, solution, split);
_popup.PopupEntity(forceFeed ? Loc.GetString("food-system-you-cannot-eat-any-more-other") : Loc.GetString("food-system-you-cannot-eat-any-more"), args.Target.Value, args.User);
return;
}
{
var targetName = Identity.Entity(args.Target.Value, EntityManager);
var userName = Identity.Entity(args.User, EntityManager);
- _popup.PopupEntity(Loc.GetString("food-system-force-feed-success", ("user", userName), ("flavors", flavors)), entity.Owner, entity.Owner);
+ _popup.PopupEntity(Loc.GetString("food-system-force-feed-success", ("user", userName), ("flavors", flavors)),
+ uid, uid);
_popup.PopupEntity(Loc.GetString("food-system-force-feed-success-user", ("target", targetName)), args.User, args.User);
// log successful force feed
- _adminLogger.Add(LogType.ForceFeed, LogImpact.Medium, $"{ToPrettyString(entity.Owner):user} forced {ToPrettyString(args.User):target} to eat {ToPrettyString(entity.Owner):food}");
+ _adminLogger.Add(LogType.ForceFeed, LogImpact.Medium, $"{ToPrettyString(uid):user} forced {ToPrettyString(args.User):target} to eat {ToPrettyString(uid):food}");
}
else
{
- _popup.PopupEntity(Loc.GetString(entity.Comp.EatMessage, ("food", entity.Owner), ("flavors", flavors)), args.User, args.User);
+ _popup.PopupEntity(Loc.GetString(component.EatMessage, ("food", uid), ("flavors", flavors)), args.User, args.User);
// log successful voluntary eating
- _adminLogger.Add(LogType.Ingestion, LogImpact.Low, $"{ToPrettyString(args.User):target} ate {ToPrettyString(entity.Owner):food}");
+ _adminLogger.Add(LogType.Ingestion, LogImpact.Low, $"{ToPrettyString(args.User):target} ate {ToPrettyString(uid):food}");
}
- _audio.PlayPvs(entity.Comp.UseSound, args.Target.Value, AudioParams.Default.WithVolume(-1f));
+ _audio.PlayPvs(component.UseSound, args.Target.Value, AudioParams.Default.WithVolume(-1f));
// Try to break all used utensils
foreach (var utensil in utensils)
args.Repeat = !forceFeed;
- if (TryComp<StackComponent>(entity, out var stack))
+ if (TryComp<StackComponent>(uid, out var stack))
{
//Not deleting whole stack piece will make troubles with grinding object
if (stack.Count > 1)
{
- _stack.SetCount(entity.Owner, stack.Count - 1);
- _solutionContainer.TryAddSolution(soln.Value, split);
+ _stack.SetCount(uid, stack.Count - 1);
+ _solutionContainer.TryAddSolution(uid, solution, split);
return;
}
}
- else if (GetUsesRemaining(entity.Owner, entity.Comp) > 0)
+ else if (GetUsesRemaining(uid, component) > 0)
{
return;
}
// don't try to repeat if its being deleted
args.Repeat = false;
- DeleteAndSpawnTrash(entity.Comp, entity.Owner, args.User);
+ DeleteAndSpawnTrash(component, uid, args.User);
}
public void DeleteAndSpawnTrash(FoodComponent component, EntityUid food, EntityUid user)
QueueDel(food);
}
- private void AddEatVerb(Entity<FoodComponent> entity, ref GetVerbsEvent<AlternativeVerb> ev)
+ private void AddEatVerb(EntityUid uid, FoodComponent component, GetVerbsEvent<AlternativeVerb> ev)
{
- if (entity.Owner == ev.User ||
+ if (uid == ev.User ||
!ev.CanInteract ||
!ev.CanAccess ||
!TryComp<BodyComponent>(ev.User, out var body) ||
return;
// have to kill mouse before eating it
- if (_mobState.IsAlive(entity) && entity.Comp.RequireDead)
+ if (_mobState.IsAlive(uid) && component.RequireDead)
return;
// only give moths eat verb for clothes since it would just fail otherwise
- if (!IsDigestibleBy(entity, entity.Comp, stomachs))
+ if (!IsDigestibleBy(uid, component, stomachs))
return;
- var user = ev.User;
AlternativeVerb verb = new()
{
Act = () =>
{
- TryFeed(user, user, entity, entity.Comp);
+ TryFeed(ev.User, ev.User, uid, component);
},
- Icon = new SpriteSpecifier.Texture(new("/Textures/Interface/VerbIcons/cutlery.svg.192dpi.png")),
+ Icon = new SpriteSpecifier.Texture(new ("/Textures/Interface/VerbIcons/cutlery.svg.192dpi.png")),
Text = Loc.GetString("food-system-verb-eat"),
Priority = -1
};
}
if (component.RequiresSpecialDigestion)
- return false;
+ return false;
return digestible;
}
/// <summary>
/// Block ingestion attempts based on the equipped mask or head-wear
/// </summary>
- private void OnInventoryIngestAttempt(Entity<InventoryComponent> entity, ref IngestionAttemptEvent args)
+ private void OnInventoryIngestAttempt(EntityUid uid, InventoryComponent component, IngestionAttemptEvent args)
{
if (args.Cancelled)
return;
IngestionBlockerComponent? blocker;
- if (_inventory.TryGetSlotEntity(entity.Owner, "mask", out var maskUid) &&
+ if (_inventory.TryGetSlotEntity(uid, "mask", out var maskUid) &&
TryComp(maskUid, out blocker) &&
blocker.Enabled)
{
return;
}
- if (_inventory.TryGetSlotEntity(entity.Owner, "head", out var headUid) &&
+ if (_inventory.TryGetSlotEntity(uid, "head", out var headUid) &&
TryComp(headUid, out blocker) &&
blocker.Enabled)
{
if (!Resolve(uid, ref comp))
return 0;
- if (!_solutionContainer.TryGetSolution(uid, comp.Solution, out _, out var solution) || solution.Volume == 0)
+ if (!_solutionContainer.TryGetSolution(uid, comp.Solution, out var solution) || solution.Volume == 0)
return 0;
// eat all in 1 go, so non empty is 1 bite
-using Content.Server.Chemistry.Containers.EntitySystems;
using Content.Server.Nutrition.Components;
using Content.Shared.Chemistry.Components;
+using Content.Shared.Chemistry.Components.SolutionManager;
+using Content.Shared.Chemistry.EntitySystems;
using Content.Shared.Examine;
using Content.Shared.FixedPoint;
using Content.Shared.Hands.EntitySystems;
using Robust.Shared.Audio;
using Robust.Shared.Audio.Systems;
using Robust.Shared.Containers;
+using Robust.Shared.Player;
namespace Content.Server.Nutrition.EntitySystems
{
SubscribeLocalEvent<SliceableFoodComponent, ComponentStartup>(OnComponentStartup);
}
- private void OnInteractUsing(Entity<SliceableFoodComponent> entity, ref InteractUsingEvent args)
+ private void OnInteractUsing(EntityUid uid, SliceableFoodComponent component, InteractUsingEvent args)
{
if (args.Handled)
return;
- if (TrySliceFood(entity, args.User, args.Used, entity.Comp))
+ if (TrySliceFood(uid, args.User, args.Used, component))
args.Handled = true;
}
return false;
}
- if (!_solutionContainerSystem.TryGetSolution(uid, food.Solution, out var soln, out var solution))
+ if (!_solutionContainerSystem.TryGetSolution(uid, food.Solution, out var solution))
{
return false;
}
var sliceUid = Slice(uid, user, component, transform);
- var lostSolution = _solutionContainerSystem.SplitSolution(soln.Value, solution.Volume / FixedPoint2.New(component.Count));
+ var lostSolution = _solutionContainerSystem.SplitSolution(uid, solution,
+ solution.Volume / FixedPoint2.New(component.Count));
// Fill new slice
FillSlice(sliceUid, lostSolution);
{
// Replace all reagents on prototype not just copying poisons (example: slices of eaten pizza should have less nutrition)
if (TryComp<FoodComponent>(sliceUid, out var sliceFoodComp) &&
- _solutionContainerSystem.TryGetSolution(sliceUid, sliceFoodComp.Solution, out var itsSoln, out var itsSolution))
+ _solutionContainerSystem.TryGetSolution(sliceUid, sliceFoodComp.Solution, out var itsSolution))
{
- _solutionContainerSystem.RemoveAllSolution(itsSoln.Value);
+ _solutionContainerSystem.RemoveAllSolution(sliceUid, itsSolution);
var lostSolutionPart = solution.SplitSolution(itsSolution.AvailableVolume);
- _solutionContainerSystem.TryAddSolution(itsSoln.Value, lostSolutionPart);
+ _solutionContainerSystem.TryAddSolution(sliceUid, itsSolution, lostSolutionPart);
}
}
- private void OnComponentStartup(Entity<SliceableFoodComponent> entity, ref ComponentStartup args)
+ private void OnComponentStartup(EntityUid uid, SliceableFoodComponent component, ComponentStartup args)
{
- entity.Comp.Count = entity.Comp.TotalCount;
+ component.Count = component.TotalCount;
+ var foodComp = EnsureComp<FoodComponent>(uid);
- var foodComp = EnsureComp<FoodComponent>(entity);
- _solutionContainerSystem.EnsureSolution(entity.Owner, foodComp.Solution);
+ EnsureComp<SolutionContainerManagerComponent>(uid);
+ _solutionContainerSystem.EnsureSolution(uid, foodComp.Solution);
}
- private void OnExamined(Entity<SliceableFoodComponent> entity, ref ExaminedEvent args)
+ private void OnExamined(EntityUid uid, SliceableFoodComponent component, ExaminedEvent args)
{
- args.PushMarkup(Loc.GetString("sliceable-food-component-on-examine-remaining-slices-text", ("remainingCount", entity.Comp.Count)));
+ args.PushMarkup(Loc.GetString("sliceable-food-component-on-examine-remaining-slices-text", ("remainingCount", component.Count)));
}
}
}
using Content.Server.Nutrition.Components;
-using Content.Shared.Interaction;
using Content.Shared.Nutrition.Components;
+using Content.Shared.Interaction;
using Content.Shared.Smoking;
using Content.Shared.Temperature;
SubscribeLocalEvent<CigarComponent, AfterInteractEvent>(OnCigarAfterInteract);
}
- private void OnCigarActivatedEvent(Entity<CigarComponent> entity, ref ActivateInWorldEvent args)
+ private void OnCigarActivatedEvent(EntityUid uid, CigarComponent component, ActivateInWorldEvent args)
{
if (args.Handled)
return;
- if (!EntityManager.TryGetComponent(entity, out SmokableComponent? smokable))
+ if (!EntityManager.TryGetComponent(uid, out SmokableComponent? smokable))
return;
if (smokable.State != SmokableState.Lit)
return;
- SetSmokableState(entity, SmokableState.Burnt, smokable);
+ SetSmokableState(uid, SmokableState.Burnt, smokable);
args.Handled = true;
}
- private void OnCigarInteractUsingEvent(Entity<CigarComponent> entity, ref InteractUsingEvent args)
+ private void OnCigarInteractUsingEvent(EntityUid uid, CigarComponent component, InteractUsingEvent args)
{
if (args.Handled)
return;
- if (!EntityManager.TryGetComponent(entity, out SmokableComponent? smokable))
+ if (!EntityManager.TryGetComponent(uid, out SmokableComponent? smokable))
return;
if (smokable.State != SmokableState.Unlit)
if (!isHotEvent.IsHot)
return;
- SetSmokableState(entity, SmokableState.Lit, smokable);
+ SetSmokableState(uid, SmokableState.Lit, smokable);
args.Handled = true;
}
- public void OnCigarAfterInteract(Entity<CigarComponent> entity, ref AfterInteractEvent args)
+ public void OnCigarAfterInteract(EntityUid uid, CigarComponent component, AfterInteractEvent args)
{
var targetEntity = args.Target;
if (targetEntity == null ||
!args.CanReach ||
- !EntityManager.TryGetComponent(entity, out SmokableComponent? smokable) ||
+ !EntityManager.TryGetComponent(uid, out SmokableComponent? smokable) ||
smokable.State == SmokableState.Lit)
return;
if (!isHotEvent.IsHot)
return;
- SetSmokableState(entity, SmokableState.Lit, smokable);
+ SetSmokableState(uid, SmokableState.Lit, smokable);
args.Handled = true;
}
- private void OnCigarSolutionEmptyEvent(Entity<CigarComponent> entity, ref SmokableSolutionEmptyEvent args)
+ private void OnCigarSolutionEmptyEvent(EntityUid uid, CigarComponent component, SmokableSolutionEmptyEvent args)
{
- SetSmokableState(entity, SmokableState.Burnt);
+ SetSmokableState(uid, SmokableState.Burnt);
}
}
}
using Content.Server.Nutrition.Components;
+using Content.Shared.Nutrition.Components;
using Content.Shared.Chemistry.Components.SolutionManager;
using Content.Shared.Containers.ItemSlots;
using Content.Shared.Interaction;
-using Content.Shared.Nutrition.Components;
using Content.Shared.Smoking;
using Content.Shared.Temperature;
SubscribeLocalEvent<SmokingPipeComponent, ComponentInit>(OnComponentInit);
}
- public void OnComponentInit(Entity<SmokingPipeComponent> entity, ref ComponentInit args)
+ public void OnComponentInit(EntityUid uid, SmokingPipeComponent pipe, ComponentInit args)
{
- _itemSlotsSystem.AddItemSlot(entity, SmokingPipeComponent.BowlSlotId, entity.Comp.BowlSlot);
+ _itemSlotsSystem.AddItemSlot(uid, SmokingPipeComponent.BowlSlotId, pipe.BowlSlot);
}
- private void OnPipeInteractUsingEvent(Entity<SmokingPipeComponent> entity, ref InteractUsingEvent args)
+ private void OnPipeInteractUsingEvent(EntityUid uid, SmokingPipeComponent component, InteractUsingEvent args)
{
if (args.Handled)
return;
- if (!EntityManager.TryGetComponent(entity, out SmokableComponent? smokable))
+ if (!EntityManager.TryGetComponent(uid, out SmokableComponent? smokable))
return;
if (smokable.State != SmokableState.Unlit)
if (!isHotEvent.IsHot)
return;
- if (TryTransferReagents(entity.Comp, smokable))
- SetSmokableState(entity, SmokableState.Lit, smokable);
+ if (TryTransferReagents(component, smokable))
+ SetSmokableState(uid, SmokableState.Lit, smokable);
args.Handled = true;
}
- public void OnPipeAfterInteract(Entity<SmokingPipeComponent> entity, ref AfterInteractEvent args)
+ public void OnPipeAfterInteract(EntityUid uid, SmokingPipeComponent component, AfterInteractEvent args)
{
var targetEntity = args.Target;
if (targetEntity == null ||
!args.CanReach ||
- !EntityManager.TryGetComponent(entity, out SmokableComponent? smokable) ||
+ !EntityManager.TryGetComponent(uid, out SmokableComponent? smokable) ||
smokable.State == SmokableState.Lit)
return;
if (!isHotEvent.IsHot)
return;
- if (TryTransferReagents(entity.Comp, smokable))
- SetSmokableState(entity, SmokableState.Lit, smokable);
+ if(TryTransferReagents(component, smokable))
+ SetSmokableState(uid, SmokableState.Lit, smokable);
args.Handled = true;
}
- private void OnPipeSolutionEmptyEvent(Entity<SmokingPipeComponent> entity, ref SmokableSolutionEmptyEvent args)
+ private void OnPipeSolutionEmptyEvent(EntityUid uid, SmokingPipeComponent component, SmokableSolutionEmptyEvent args)
{
- _itemSlotsSystem.SetLock(entity, entity.Comp.BowlSlot, false);
- SetSmokableState(entity, SmokableState.Unlit);
+ _itemSlotsSystem.SetLock(component.Owner, component.BowlSlot, false);
+ SetSmokableState(uid, SmokableState.Unlit);
}
// Convert smokable item into reagents to be smoked
EntityUid contents = component.BowlSlot.Item.Value;
if (!TryComp<SolutionContainerManagerComponent>(contents, out var reagents) ||
- !_solutionContainerSystem.TryGetSolution(smokable.Owner, smokable.Solution, out var pipeSolution, out _))
+ !_solutionContainerSystem.TryGetSolution(smokable.Owner, smokable.Solution, out var pipeSolution))
return false;
- foreach (var (_, soln) in _solutionContainerSystem.EnumerateSolutions((contents, reagents)))
+ foreach (var reagentSolution in reagents.Solutions)
{
- var reagentSolution = soln.Comp.Solution;
- _solutionContainerSystem.TryAddSolution(pipeSolution.Value, reagentSolution);
+ _solutionContainerSystem.TryAddSolution(smokable.Owner, pipeSolution, reagentSolution.Value);
}
EntityManager.DeleteEntity(contents);
-using Content.Server.Atmos;
-using Content.Server.Atmos.EntitySystems;
+using Content.Server.Nutrition.Components;
using Content.Server.Body.Components;
+using Content.Shared.Interaction;
using Content.Server.DoAfter;
+using System.Threading;
using Content.Server.Explosion.EntitySystems;
-using Content.Server.Nutrition.Components;
-using Content.Server.Popups;
using Content.Shared.Damage;
+using Content.Server.Popups;
+using Content.Shared.IdentityManagement;
using Content.Shared.DoAfter;
-using Content.Shared.Emag.Components;
using Content.Shared.Emag.Systems;
-using Content.Shared.IdentityManagement;
-using Content.Shared.Interaction;
+using Content.Shared.Emag.Components;
using Content.Shared.Nutrition;
-using System.Threading;
+using Content.Server.Atmos.EntitySystems;
+using Content.Server.Atmos;
/// <summary>
/// System for vapes
SubscribeLocalEvent<VapeComponent, GotEmaggedEvent>(OnEmagged);
}
- private void OnVapeInteraction(Entity<VapeComponent> entity, ref AfterInteractEvent args)
+ private void OnVapeInteraction(EntityUid uid, VapeComponent comp, AfterInteractEvent args)
{
- var delay = entity.Comp.Delay;
+ _solutionContainerSystem.TryGetRefillableSolution(uid, out var solution);
+
+ var delay = comp.Delay;
var forced = true;
var exploded = false;
if (!args.CanReach
- || !_solutionContainerSystem.TryGetRefillableSolution(entity.Owner, out _, out var solution)
+ || solution == null
|| !HasComp<BloodstreamComponent>(args.Target)
|| _foodSystem.IsMouthBlocked(args.Target.Value, args.User))
{
if (args.Target == args.User)
{
- delay = entity.Comp.UserDelay;
+ delay = comp.UserDelay;
forced = false;
}
- if (entity.Comp.ExplodeOnUse || HasComp<EmaggedComponent>(entity.Owner))
+ if (comp.ExplodeOnUse || HasComp<EmaggedComponent>(uid))
{
- _explosionSystem.QueueExplosion(entity.Owner, "Default", entity.Comp.ExplosionIntensity, 0.5f, 3, canCreateVacuum: false);
- EntityManager.DeleteEntity(entity);
+ _explosionSystem.QueueExplosion(uid, "Default", comp.ExplosionIntensity, 0.5f, 3, canCreateVacuum: false);
+ EntityManager.DeleteEntity(uid);
exploded = true;
}
else
// just re-use the existing RiggableSystem.
foreach (var name in solution.Contents)
{
- if (name.Reagent.Prototype != entity.Comp.SolutionNeeded)
+ if (name.Reagent.Prototype != comp.SolutionNeeded)
{
exploded = true;
- _explosionSystem.QueueExplosion(entity.Owner, "Default", entity.Comp.ExplosionIntensity, 0.5f, 3, canCreateVacuum: false);
- EntityManager.DeleteEntity(entity);
+ _explosionSystem.QueueExplosion(uid, "Default", comp.ExplosionIntensity, 0.5f, 3, canCreateVacuum: false);
+ EntityManager.DeleteEntity(uid);
break;
}
}
if (!exploded)
{
var vapeDoAfterEvent = new VapeDoAfterEvent(solution, forced);
- _doAfterSystem.TryStartDoAfter(new DoAfterArgs(EntityManager, args.User, delay, vapeDoAfterEvent, entity.Owner, target: args.Target, used: entity.Owner)
+ _doAfterSystem.TryStartDoAfter(new DoAfterArgs(EntityManager, args.User, delay, vapeDoAfterEvent, uid, target: args.Target, used: uid)
{
BreakOnTargetMove = true,
BreakOnUserMove = false,
});
}
args.Handled = true;
- }
+ }
- private void OnVapeDoAfter(Entity<VapeComponent> entity, ref VapeDoAfterEvent args)
+ private void OnVapeDoAfter(EntityUid uid, VapeComponent comp, VapeDoAfterEvent args)
{
if (args.Handled
|| args.Args.Target == null)
}
//Smoking kills(your lungs, but there is no organ damage yet)
- _damageableSystem.TryChangeDamage(args.Args.Target.Value, entity.Comp.Damage, true);
+ _damageableSystem.TryChangeDamage(args.Args.Target.Value, comp.Damage, true);
- var merger = new GasMixture(1) { Temperature = args.Solution.Temperature };
- merger.SetMoles(entity.Comp.GasType, args.Solution.Volume.Value / entity.Comp.ReductionFactor);
+ var merger = new GasMixture(1) { Temperature = args.Solution.Temperature};
+ merger.SetMoles(comp.GasType, args.Solution.Volume.Value / comp.ReductionFactor);
_atmosphereSystem.Merge(environment, merger);
args.Args.Target.Value);
}
}
- private void OnEmagged(Entity<VapeComponent> entity, ref GotEmaggedEvent args)
+ private void OnEmagged(EntityUid uid, VapeComponent component, ref GotEmaggedEvent args)
{
args.Handled = true;
}
- }
+ }
}
using Content.Server.Atmos.EntitySystems;
using Content.Server.Body.Components;
using Content.Server.Body.Systems;
-using Content.Server.Chemistry.Containers.EntitySystems;
-using Content.Server.Forensics;
+using Content.Shared.Nutrition.Components;
using Content.Shared.Chemistry;
+using Content.Shared.Chemistry.EntitySystems;
using Content.Shared.Chemistry.Reagent;
using Content.Shared.Clothing.Components;
using Content.Shared.Clothing.EntitySystems;
using Content.Shared.FixedPoint;
using Content.Shared.Inventory;
-using Content.Shared.Inventory.Events;
using Content.Shared.Item;
-using Content.Shared.Nutrition.Components;
using Content.Shared.Smoking;
using Content.Shared.Temperature;
using Robust.Server.GameObjects;
using Robust.Shared.Containers;
using System.Linq;
+using Content.Shared.Inventory.Events;
+using Content.Server.Forensics;
namespace Content.Server.Nutrition.EntitySystems
{
_active.Remove(uid);
}
- private void OnSmokableIsHotEvent(Entity<SmokableComponent> entity, ref IsHotEvent args)
+ private void OnSmokableIsHotEvent(EntityUid uid, SmokableComponent component, IsHotEvent args)
{
- args.IsHot = entity.Comp.State == SmokableState.Lit;
+ args.IsHot = component.State == SmokableState.Lit;
}
- private void OnSmokableShutdownEvent(Entity<SmokableComponent> entity, ref ComponentShutdown args)
+ private void OnSmokableShutdownEvent(EntityUid uid, SmokableComponent component, ComponentShutdown args)
{
- _active.Remove(entity);
+ _active.Remove(uid);
}
- private void OnSmokeableEquipEvent(Entity<SmokableComponent> entity, ref GotEquippedEvent args)
+ private void OnSmokeableEquipEvent(EntityUid uid, SmokableComponent component, GotEquippedEvent args)
{
if (args.Slot == "mask")
{
- _forensics.TransferDna(entity.Owner, args.Equipee, false);
+ _forensics.TransferDna(uid, args.Equipee, false);
}
}
continue;
}
- if (!_solutionContainerSystem.TryGetSolution(uid, smokable.Solution, out var soln, out var solution))
+ if (!_solutionContainerSystem.TryGetSolution(uid, smokable.Solution, out var solution))
{
_active.Remove(uid);
continue;
{
var transform = Transform(uid);
- if (transform.GridUid is { } gridUid)
+ if (transform.GridUid is {} gridUid)
{
var position = _transformSystem.GetGridOrMapTilePosition(uid, transform);
_atmos.HotspotExpose(gridUid, position, smokable.ExposeTemperature, smokable.ExposeVolume, uid, true);
}
}
- var inhaledSolution = _solutionContainerSystem.SplitSolution(soln.Value, smokable.InhaleAmount * _timer);
+ var inhaledSolution = _solutionContainerSystem.SplitSolution(uid, solution, smokable.InhaleAmount * _timer);
if (solution.Volume == FixedPoint2.Zero)
{
-using Content.Server.Chemistry.Containers.EntitySystems;
using Content.Server.Nutrition.Components;
using Content.Shared.Chemistry.Components;
using Content.Shared.Chemistry.Components.SolutionManager;
{
base.Initialize();
SubscribeLocalEvent<TrashOnSolutionEmptyComponent, ComponentStartup>(OnStartup);
- SubscribeLocalEvent<TrashOnSolutionEmptyComponent, SolutionContainerChangedEvent>(OnSolutionChange);
+ SubscribeLocalEvent<TrashOnSolutionEmptyComponent, SolutionChangedEvent>(OnSolutionChange);
}
- public void OnStartup(Entity<TrashOnSolutionEmptyComponent> entity, ref ComponentStartup args)
+ public void OnStartup(EntityUid uid, TrashOnSolutionEmptyComponent component, ComponentStartup args)
{
- CheckSolutions(entity);
+ CheckSolutions(component);
}
- public void OnSolutionChange(Entity<TrashOnSolutionEmptyComponent> entity, ref SolutionContainerChangedEvent args)
+ public void OnSolutionChange(EntityUid uid, TrashOnSolutionEmptyComponent component, SolutionChangedEvent args)
{
- CheckSolutions(entity);
+ CheckSolutions(component);
}
- public void CheckSolutions(Entity<TrashOnSolutionEmptyComponent> entity)
+ public void CheckSolutions(TrashOnSolutionEmptyComponent component)
{
- if (!EntityManager.HasComponent<SolutionContainerManagerComponent>(entity))
+ if (!EntityManager.HasComponent<SolutionContainerManagerComponent>((component).Owner))
return;
- if (_solutionContainerSystem.TryGetSolution(entity.Owner, entity.Comp.Solution, out _, out var solution))
- UpdateTags(entity, solution);
+ if (_solutionContainerSystem.TryGetSolution(component.Owner, component.Solution, out var solution))
+ UpdateTags(component, solution);
}
- public void UpdateTags(Entity<TrashOnSolutionEmptyComponent> entity, Solution solution)
+ public void UpdateTags(TrashOnSolutionEmptyComponent component, Solution solution)
{
if (solution.Volume <= 0)
{
- _tagSystem.AddTag(entity.Owner, "Trash");
+ _tagSystem.AddTag(component.Owner, "Trash");
return;
}
- if (_tagSystem.HasTag(entity.Owner, "Trash"))
- _tagSystem.RemoveTag(entity.Owner, "Trash");
+ if (_tagSystem.HasTag(component.Owner, "Trash"))
+ _tagSystem.RemoveTag(component.Owner, "Trash");
}
}
}
+using System.Linq;
using Content.Server.Administration.Logs;
-using Content.Server.Chemistry.Containers.EntitySystems;
using Content.Server.Explosion.EntitySystems;
using Content.Shared.Chemistry.Components;
+using Content.Shared.Chemistry.EntitySystems;
using Content.Shared.Database;
using Content.Shared.Examine;
using Content.Shared.Payload.Components;
using Robust.Shared.Containers;
using Robust.Shared.Serialization.Manager;
using Robust.Shared.Utility;
-using System.Linq;
namespace Content.Server.Payload.EntitySystems;
public sealed class PayloadSystem : EntitySystem
{
[Dependency] private readonly TagSystem _tagSystem = default!;
- [Dependency] private readonly SolutionContainerSystem _solutionContainerSystem = default!;
- [Dependency] private readonly IAdminLogManager _adminLogger = default!;
+ [Dependency] private readonly SolutionContainerSystem _solutionSystem = default!;
+ [Dependency] private readonly IAdminLogManager _adminLogger= default!;
[Dependency] private readonly IComponentFactory _componentFactory = default!;
[Dependency] private readonly ISerializationManager _serializationManager = default!;
SubscribeLocalEvent<ChemicalPayloadComponent, TriggerEvent>(HandleChemicalPayloadTrigger);
}
- public IEnumerable<EntityUid> GetAllPayloads(EntityUid uid, ContainerManagerComponent? contMan = null)
+ public IEnumerable<EntityUid> GetAllPayloads(EntityUid uid, ContainerManagerComponent? contMan=null)
{
if (!Resolve(uid, ref contMan, false))
yield break;
var temp = (object) component;
_serializationManager.CopyTo(data.Component, ref temp);
- EntityManager.AddComponent(uid, (Component) temp!);
+ EntityManager.AddComponent(uid, (Component)temp!);
trigger.GrantedComponents.Add(registration.Type);
}
}
}
- private void HandleChemicalPayloadTrigger(Entity<ChemicalPayloadComponent> entity, ref TriggerEvent args)
+ private void HandleChemicalPayloadTrigger(EntityUid uid, ChemicalPayloadComponent component, TriggerEvent args)
{
- if (entity.Comp.BeakerSlotA.Item is not EntityUid beakerA
- || entity.Comp.BeakerSlotB.Item is not EntityUid beakerB
+ if (component.BeakerSlotA.Item is not EntityUid beakerA
+ || component.BeakerSlotB.Item is not EntityUid beakerB
|| !TryComp(beakerA, out FitsInDispenserComponent? compA)
|| !TryComp(beakerB, out FitsInDispenserComponent? compB)
- || !_solutionContainerSystem.TryGetSolution(beakerA, compA.Solution, out var solnA, out var solutionA)
- || !_solutionContainerSystem.TryGetSolution(beakerB, compB.Solution, out var solnB, out var solutionB)
+ || !_solutionSystem.TryGetSolution(beakerA, compA.Solution, out var solutionA)
+ || !_solutionSystem.TryGetSolution(beakerB, compB.Solution, out var solutionB)
|| solutionA.Volume == 0
|| solutionB.Volume == 0)
{
var solStringB = SolutionContainerSystem.ToPrettyString(solutionB);
_adminLogger.Add(LogType.ChemicalReaction,
- $"Chemical bomb payload {ToPrettyString(entity.Owner):payload} at {Transform(entity.Owner).MapPosition:location} is combining two solutions: {solStringA:solutionA} and {solStringB:solutionB}");
+ $"Chemical bomb payload {ToPrettyString(uid):payload} at {Transform(uid).MapPosition:location} is combining two solutions: {solStringA:solutionA} and {solStringB:solutionB}");
solutionA.MaxVolume += solutionB.MaxVolume;
- _solutionContainerSystem.TryAddSolution(solnA.Value, solutionB);
- _solutionContainerSystem.RemoveAllSolution(solnB.Value);
+ _solutionSystem.TryAddSolution(beakerA, solutionA, solutionB);
+ _solutionSystem.RemoveAllSolution(beakerB, solutionB);
// The grenade might be a dud. Redistribute solution:
- var tmpSol = _solutionContainerSystem.SplitSolution(solnA.Value, solutionA.Volume * solutionB.MaxVolume / solutionA.MaxVolume);
- _solutionContainerSystem.TryAddSolution(solnB.Value, tmpSol);
+ var tmpSol = _solutionSystem.SplitSolution(beakerA, solutionA, solutionA.Volume * solutionB.MaxVolume / solutionA.MaxVolume);
+ _solutionSystem.TryAddSolution(beakerB, solutionB, tmpSol);
solutionA.MaxVolume -= solutionB.MaxVolume;
- _solutionContainerSystem.UpdateChemicals(solnA.Value);
+ _solutionSystem.UpdateChemicals(beakerA, solutionA, false);
args.Handled = true;
}
/// </summary>
public sealed class RiggableSystem : EntitySystem
{
+ [Dependency] private readonly SolutionContainerSystem _solutionsSystem = default!;
[Dependency] private readonly ExplosionSystem _explosionSystem = default!;
[Dependency] private readonly IAdminLogManager _adminLogger = default!;
base.Initialize();
SubscribeLocalEvent<RiggableComponent, RejuvenateEvent>(OnRejuvenate);
SubscribeLocalEvent<RiggableComponent, BeingMicrowavedEvent>(OnMicrowaved);
- SubscribeLocalEvent<RiggableComponent, SolutionContainerChangedEvent>(OnSolutionChanged);
+ SubscribeLocalEvent<RiggableComponent, SolutionChangedEvent>(OnSolutionChanged);
}
- private void OnRejuvenate(Entity<RiggableComponent> entity, ref RejuvenateEvent args)
+ private void OnRejuvenate(EntityUid uid, RiggableComponent component, RejuvenateEvent args)
{
- entity.Comp.IsRigged = false;
+ component.IsRigged = false;
}
- private void OnMicrowaved(Entity<RiggableComponent> entity, ref BeingMicrowavedEvent args)
+ private void OnMicrowaved(EntityUid uid, RiggableComponent component, BeingMicrowavedEvent args)
{
- if (TryComp<BatteryComponent>(entity, out var batteryComponent))
+ if (TryComp<BatteryComponent>(uid, out var batteryComponent))
{
if (batteryComponent.CurrentCharge == 0)
return;
args.Handled = true;
// What the fuck are you doing???
- Explode(entity.Owner, batteryComponent, args.User);
+ Explode(uid, batteryComponent, args.User);
}
- private void OnSolutionChanged(Entity<RiggableComponent> entity, ref SolutionContainerChangedEvent args)
+ private void OnSolutionChanged(EntityUid uid, RiggableComponent component, SolutionChangedEvent args)
{
- if (args.SolutionId != entity.Comp.Solution)
+ if (args.SolutionId != component.Solution)
return;
- var wasRigged = entity.Comp.IsRigged;
- var quantity = args.Solution.GetReagentQuantity(entity.Comp.RequiredQuantity.Reagent);
- entity.Comp.IsRigged = quantity >= entity.Comp.RequiredQuantity.Quantity;
+ var wasRigged = component.IsRigged;
+ var quantity = args.Solution.GetReagentQuantity(component.RequiredQuantity.Reagent);
+ component.IsRigged = quantity >= component.RequiredQuantity.Quantity;
- if (entity.Comp.IsRigged && !wasRigged)
+ if (component.IsRigged && !wasRigged)
{
- _adminLogger.Add(LogType.Explosion, LogImpact.Medium, $"{ToPrettyString(entity.Owner)} has been rigged up to explode when used.");
+ _adminLogger.Add(LogType.Explosion, LogImpact.Medium, $"{ToPrettyString(uid)} has been rigged up to explode when used.");
}
}
-using Content.Shared.Chemistry.Components;
-using Content.Shared.Chemistry.Components.SolutionManager;
+using Content.Shared.Chemistry.Components.SolutionManager;
+using Content.Shared.Chemistry.EntitySystems;
using Content.Shared.Chemistry.Reagent;
using Content.Shared.FixedPoint;
using Robust.Shared.Serialization.TypeSerializers.Implementations.Custom.Prototype;
public string Reagent = "WeldingFuel";
/// <summary>
- /// The name of <see cref="Solution"/>.
+ /// The solution on the <see cref="SolutionContainerManagerComponent"/> to use.
/// </summary>
[DataField("solution")]
[ViewVariables(VVAccess.ReadWrite)]
- public string SolutionName = "tank";
-
- /// <summary>
- /// The solution on the <see cref="SolutionContainerManagerComponent"/> to use.
- /// </summary>
- [DataField("solutionRef")]
- public Entity<SolutionComponent>? Solution = null;
+ public string Solution = "tank";
/// <summary>
/// Value to multiply reagent amount by to get fuel amount.
using Content.Server.Audio;
-using Content.Server.Chemistry.Containers.EntitySystems;
using Content.Server.Fluids.EntitySystems;
using Content.Server.Materials;
using Content.Server.Popups;
using Content.Server.Power.Components;
using Content.Server.Power.EntitySystems;
+using Content.Shared.Chemistry.EntitySystems;
using Content.Shared.FixedPoint;
using Content.Shared.Popups;
using Content.Shared.Power.Generator;
_materialStorage.EjectAllMaterial(uid);
}
- private void ChemicalEmpty(Entity<ChemicalFuelGeneratorAdapterComponent> entity, ref GeneratorEmpty args)
+ private void ChemicalEmpty(EntityUid uid, ChemicalFuelGeneratorAdapterComponent component, GeneratorEmpty args)
{
- if (!_solutionContainer.ResolveSolution(entity.Owner, entity.Comp.SolutionName, ref entity.Comp.Solution, out var solution))
+ if (!_solutionContainer.TryGetSolution(uid, component.Solution, out var solution))
return;
- var spillSolution = _solutionContainer.SplitSolution(entity.Comp.Solution.Value, solution.Volume);
- _puddle.TrySpillAt(entity.Owner, spillSolution, out _);
+ var spillSolution = _solutionContainer.SplitSolution(uid, solution, solution.Volume);
+ _puddle.TrySpillAt(uid, spillSolution, out _);
}
- private void ChemicalGetClogged(Entity<ChemicalFuelGeneratorAdapterComponent> entity, ref GeneratorGetCloggedEvent args)
+ private void ChemicalGetClogged(EntityUid uid, ChemicalFuelGeneratorAdapterComponent component, ref GeneratorGetCloggedEvent args)
{
- if (!_solutionContainer.ResolveSolution(entity.Owner, entity.Comp.SolutionName, ref entity.Comp.Solution, out var solution))
+ if (!_solutionContainer.TryGetSolution(uid, component.Solution, out var solution))
return;
foreach (var reagentQuantity in solution)
{
- if (reagentQuantity.Reagent.Prototype != entity.Comp.Reagent)
+ if (reagentQuantity.Reagent.Prototype != component.Reagent)
{
args.Clogged = true;
return;
}
}
- private void ChemicalUseFuel(Entity<ChemicalFuelGeneratorAdapterComponent> entity, ref GeneratorUseFuel args)
+ private void ChemicalUseFuel(EntityUid uid, ChemicalFuelGeneratorAdapterComponent component, GeneratorUseFuel args)
{
- if (!_solutionContainer.ResolveSolution(entity.Owner, entity.Comp.SolutionName, ref entity.Comp.Solution, out var solution))
+ if (!_solutionContainer.TryGetSolution(uid, component.Solution, out var solution))
return;
- var availableReagent = solution.GetTotalPrototypeQuantity(entity.Comp.Reagent).Value;
+ var availableReagent = solution.GetTotalPrototypeQuantity(component.Reagent).Value;
var toRemove = RemoveFractionalFuel(
- ref entity.Comp.FractionalReagent,
+ ref component.FractionalReagent,
args.FuelUsed,
- entity.Comp.Multiplier * FixedPoint2.Epsilon.Float(),
+ component.Multiplier * FixedPoint2.Epsilon.Float(),
availableReagent);
- _solutionContainer.RemoveReagent(entity.Comp.Solution.Value, entity.Comp.Reagent, FixedPoint2.FromCents(toRemove));
+ solution.RemoveReagent(component.Reagent, FixedPoint2.FromCents(toRemove));
}
- private void ChemicalGetFuel(Entity<ChemicalFuelGeneratorAdapterComponent> entity, ref GeneratorGetFuelEvent args)
+ private void ChemicalGetFuel(
+ EntityUid uid,
+ ChemicalFuelGeneratorAdapterComponent component,
+ ref GeneratorGetFuelEvent args)
{
- if (!_solutionContainer.ResolveSolution(entity.Owner, entity.Comp.SolutionName, ref entity.Comp.Solution, out var solution))
+ if (!_solutionContainer.TryGetSolution(uid, component.Solution, out var solution))
return;
- var availableReagent = solution.GetTotalPrototypeQuantity(entity.Comp.Reagent).Float();
- var reagent = entity.Comp.FractionalReagent * FixedPoint2.Epsilon.Float() + availableReagent;
- args.Fuel = reagent * entity.Comp.Multiplier;
+ var availableReagent = solution.GetTotalPrototypeQuantity(component.Reagent).Float();
+ var reagent = component.FractionalReagent * FixedPoint2.Epsilon.Float() + availableReagent;
+ args.Fuel = reagent * component.Multiplier;
}
private void SolidUseFuel(EntityUid uid, SolidFuelGeneratorAdapterComponent component, GeneratorUseFuel args)
base.Initialize();
SubscribeLocalEvent<BatteryComponent, ExaminedEvent>(OnExamined);
- SubscribeLocalEvent<StunbatonComponent, SolutionContainerChangedEvent>(OnSolutionChange);
+ SubscribeLocalEvent<StunbatonComponent, SolutionChangedEvent>(OnSolutionChange);
SubscribeLocalEvent<StunbatonComponent, StaminaDamageOnHitAttemptEvent>(OnStaminaHitAttempt);
SubscribeLocalEvent<StunbatonComponent, ItemToggleActivateAttemptEvent>(TryTurnOn);
SubscribeLocalEvent<StunbatonComponent, ItemToggleDoneEvent>(ToggleDone);
}
- private void OnStaminaHitAttempt(Entity<StunbatonComponent> entity, ref StaminaDamageOnHitAttemptEvent args)
+ private void OnStaminaHitAttempt(EntityUid uid, StunbatonComponent component, ref StaminaDamageOnHitAttemptEvent args)
{
- if (!_itemToggle.IsActivated(entity.Owner) ||
- !TryComp<BatteryComponent>(entity.Owner, out var battery) || !_battery.TryUseCharge(entity.Owner, entity.Comp.EnergyPerUse, battery))
+ if (!_itemToggle.IsActivated(uid) ||
+ !TryComp<BatteryComponent>(uid, out var battery) || !_battery.TryUseCharge(uid, component.EnergyPerUse, battery))
{
args.Cancelled = true;
return;
}
- if (battery.CurrentCharge < entity.Comp.EnergyPerUse)
+ if (battery.CurrentCharge < component.EnergyPerUse)
{
- _itemToggle.Toggle(entity.Owner, predicted: false);
+ _itemToggle.Toggle(uid, predicted: false);
}
}
- private void OnExamined(Entity<BatteryComponent> entity, ref ExaminedEvent args)
+ private void OnExamined(EntityUid uid, BatteryComponent battery, ExaminedEvent args)
{
- var onMsg = _itemToggle.IsActivated(entity.Owner)
+ var onMsg = _itemToggle.IsActivated(uid)
? Loc.GetString("comp-stunbaton-examined-on")
: Loc.GetString("comp-stunbaton-examined-off");
args.PushMarkup(onMsg);
var chargeMessage = Loc.GetString("stunbaton-component-on-examine-charge",
- ("charge", (int) (entity.Comp.CurrentCharge / entity.Comp.MaxCharge * 100)));
+ ("charge", (int) (battery.CurrentCharge / battery.MaxCharge * 100)));
args.PushMarkup(chargeMessage);
}
- private void ToggleDone(Entity<StunbatonComponent> entity, ref ItemToggleDoneEvent args)
+ private void ToggleDone(EntityUid uid, StunbatonComponent comp, ref ItemToggleDoneEvent args)
{
- if (!TryComp<ItemComponent>(entity, out var item))
+ if (!TryComp<ItemComponent>(uid, out var item))
return;
-
- _item.SetHeldPrefix(entity.Owner, args.Activated ? "on" : "off", item);
+ _item.SetHeldPrefix(uid, args.Activated ? "on" : "off", item);
}
- private void TryTurnOn(Entity<StunbatonComponent> entity, ref ItemToggleActivateAttemptEvent args)
+ private void TryTurnOn(EntityUid uid, StunbatonComponent comp, ref ItemToggleActivateAttemptEvent args)
{
- if (!TryComp<BatteryComponent>(entity, out var battery) || battery.CurrentCharge < entity.Comp.EnergyPerUse)
+ if (!TryComp<BatteryComponent>(uid, out var battery) || battery.CurrentCharge < comp.EnergyPerUse)
{
args.Cancelled = true;
if (args.User != null)
return;
}
- if (TryComp<RiggableComponent>(entity, out var rig) && rig.IsRigged)
+ if (TryComp<RiggableComponent>(uid, out var rig) && rig.IsRigged)
{
- _riggableSystem.Explode(entity.Owner, battery, args.User);
+ _riggableSystem.Explode(uid, battery, args.User);
}
}
// https://github.com/space-wizards/space-station-14/pull/17288#discussion_r1241213341
- private void OnSolutionChange(Entity<StunbatonComponent> entity, ref SolutionContainerChangedEvent args)
+ private void OnSolutionChange(EntityUid uid, StunbatonComponent component, SolutionChangedEvent args)
{
// Explode if baton is activated and rigged.
- if (!TryComp<RiggableComponent>(entity, out var riggable) ||
- !TryComp<BatteryComponent>(entity, out var battery))
+ if (!TryComp<RiggableComponent>(uid, out var riggable) ||
+ !TryComp<BatteryComponent>(uid, out var battery))
return;
- if (_itemToggle.IsActivated(entity.Owner) && riggable.IsRigged)
- _riggableSystem.Explode(entity.Owner, battery);
+ if (_itemToggle.IsActivated(uid) && riggable.IsRigged)
+ _riggableSystem.Explode(uid, battery);
}
private void SendPowerPulse(EntityUid target, EntityUid? user, EntityUid used)
-using Content.Shared.Chemistry.Components;
using Content.Shared.Chemistry.Reagent;
using Content.Shared.FixedPoint;
using Content.Shared.Tools.Components;
[RegisterComponent]
public sealed partial class WelderComponent : SharedWelderComponent
{
- /// <summary>
- /// Name of <see cref="FuelSolution"/>.
- /// </summary>
- [DataField("fuelSolution"), ViewVariables(VVAccess.ReadWrite)]
- public string FuelSolutionName = "Welder";
-
/// <summary>
/// Solution on the entity that contains the fuel.
/// </summary>
- [DataField("fuelSolutionRef")]
- public Entity<SolutionComponent>? FuelSolution = null;
+ [DataField, ViewVariables(VVAccess.ReadWrite)]
+ public string FuelSolution { get; private set; } = "Welder";
/// <summary>
/// Reagent that will be used as fuel for welding.
/// </summary>
[DataField, ViewVariables(VVAccess.ReadWrite)]
- public ProtoId<ReagentPrototype> FuelReagent = "WeldingFuel";
+ public ProtoId<ReagentPrototype> FuelReagent { get; private set; } = "WeldingFuel";
/// <summary>
/// Fuel consumption per second while the welder is active.
/// </summary>
[DataField, ViewVariables(VVAccess.ReadWrite)]
- public FixedPoint2 FuelConsumption = FixedPoint2.New(2.0f);
+ public FixedPoint2 FuelConsumption { get; private set; } = FixedPoint2.New(2.0f);
/// <summary>
/// A fuel amount to be consumed when the welder goes from being unlit to being lit.
/// </summary>
[DataField, ViewVariables(VVAccess.ReadWrite)]
- public FixedPoint2 FuelLitCost = FixedPoint2.New(0.5f);
+ public FixedPoint2 FuelLitCost { get; private set; } = FixedPoint2.New(0.5f);
/// <summary>
/// Sound played when refilling the welder.
/// </summary>
[DataField]
- public SoundSpecifier WelderRefill = new SoundPathSpecifier("/Audio/Effects/refill.ogg");
+ public SoundSpecifier WelderRefill { get; private set; } = new SoundPathSpecifier("/Audio/Effects/refill.ogg");
/// <summary>
/// Whether the item is safe to refill while lit without exploding the tank.
+using System.Linq;
using Content.Server.Chemistry.Components;
using Content.Server.IgnitionSource;
using Content.Server.Tools.Components;
using Content.Shared.Item.ItemToggle;
using Content.Shared.Tools.Components;
using Robust.Shared.GameStates;
-using System.Linq;
namespace Content.Server.Tools
{
public (FixedPoint2 fuel, FixedPoint2 capacity) GetWelderFuelAndCapacity(EntityUid uid, WelderComponent? welder = null, SolutionContainerManagerComponent? solutionContainer = null)
{
if (!Resolve(uid, ref welder, ref solutionContainer)
- || !_solutionContainer.ResolveSolution((uid, solutionContainer), welder.FuelSolutionName, ref welder.FuelSolution, out var fuelSolution))
+ || !_solutionContainer.TryGetSolution(uid, welder.FuelSolution, out var fuelSolution, solutionContainer))
return (FixedPoint2.Zero, FixedPoint2.Zero);
- return (fuelSolution.GetTotalPrototypeQuantity(welder.FuelReagent), fuelSolution.MaxVolume);
+ return (_solutionContainer.GetTotalPrototypeQuantity(uid, welder.FuelReagent), fuelSolution.MaxVolume);
}
- public void TryTurnOn(Entity<WelderComponent> entity, ref ItemToggleActivateAttemptEvent args)
+ public void TryTurnOn(EntityUid uid, WelderComponent welder, ref ItemToggleActivateAttemptEvent args)
{
- if (!_solutionContainer.ResolveSolution(entity.Owner, entity.Comp.FuelSolutionName, ref entity.Comp.FuelSolution, out var solution) ||
- !TryComp<TransformComponent>(entity, out var transform))
+ if (!_solutionContainer.TryGetSolution(uid, welder.FuelSolution, out var solution) ||
+ !TryComp<TransformComponent>(uid, out var transform))
{
args.Cancelled = true;
return;
}
-
- var fuel = solution.GetTotalPrototypeQuantity(entity.Comp.FuelReagent);
+ var fuel = solution.GetTotalPrototypeQuantity(welder.FuelReagent);
// Not enough fuel to lit welder.
- if (fuel == FixedPoint2.Zero || fuel < entity.Comp.FuelLitCost)
+ if (fuel == FixedPoint2.Zero || fuel < welder.FuelLitCost)
{
if (args.User != null)
{
- _popup.PopupEntity(Loc.GetString("welder-component-no-fuel-message"), entity, (EntityUid) args.User);
+ _popup.PopupEntity(Loc.GetString("welder-component-no-fuel-message"), uid, (EntityUid) args.User);
}
args.Cancelled = true;
return;
}
- _solutionContainer.RemoveReagent(entity.Comp.FuelSolution.Value, entity.Comp.FuelReagent, entity.Comp.FuelLitCost);
+ solution.RemoveReagent(welder.FuelReagent, welder.FuelLitCost);
// Logging
- _adminLogger.Add(LogType.InteractActivate, LogImpact.Low, $"{ToPrettyString(args.User):user} toggled {ToPrettyString(entity.Owner):welder} on");
+ _adminLogger.Add(LogType.InteractActivate, LogImpact.Low, $"{ToPrettyString(args.User):user} toggled {ToPrettyString(uid):welder} on");
- _ignitionSource.SetIgnited(entity.Owner);
+ _ignitionSource.SetIgnited(uid);
if (transform.GridUid is { } gridUid)
{
- var position = _transformSystem.GetGridOrMapTilePosition(entity.Owner, transform);
- _atmosphereSystem.HotspotExpose(gridUid, position, 700, 50, entity.Owner, true);
+ var position = _transformSystem.GetGridOrMapTilePosition(uid, transform);
+ _atmosphereSystem.HotspotExpose(gridUid, position, 700, 50, uid, true);
}
- Dirty(entity);
+ Dirty(uid, welder);
- _activeWelders.Add(entity);
+ _activeWelders.Add(uid);
}
- public void TurnOff(Entity<WelderComponent> entity, ref ItemToggleDeactivateAttemptEvent args)
+ public void TurnOff(EntityUid uid, WelderComponent welder, ref ItemToggleDeactivateAttemptEvent args)
{
// Logging
- _adminLogger.Add(LogType.InteractActivate, LogImpact.Low, $"{ToPrettyString(args.User):user} toggled {ToPrettyString(entity.Owner):welder} off");
+ _adminLogger.Add(LogType.InteractActivate, LogImpact.Low, $"{ToPrettyString(args.User):user} toggled {ToPrettyString(uid):welder} off");
- _ignitionSource.SetIgnited(entity.Owner, false);
+ _ignitionSource.SetIgnited(uid, false);
- Dirty(entity);
+ Dirty(uid, welder);
- _activeWelders.Remove(entity);
+ _activeWelders.Remove(uid);
}
- private void OnWelderExamine(Entity<WelderComponent> entity, ref ExaminedEvent args)
+ private void OnWelderExamine(EntityUid uid, WelderComponent welder, ExaminedEvent args)
{
- if (_itemToggle.IsActivated(entity.Owner))
+ if (_itemToggle.IsActivated(uid))
{
args.PushMarkup(Loc.GetString("welder-component-on-examine-welder-lit-message"));
}
if (args.IsInDetailsRange)
{
- var (fuel, capacity) = GetWelderFuelAndCapacity(entity.Owner, entity.Comp);
+ var (fuel, capacity) = GetWelderFuelAndCapacity(uid, welder);
args.PushMarkup(Loc.GetString("welder-component-on-examine-detailed-message",
("colorName", fuel < capacity / FixedPoint2.New(4f) ? "darkorange" : "orange"),
}
}
- private void OnWelderAfterInteract(Entity<WelderComponent> entity, ref AfterInteractEvent args)
+ private void OnWelderAfterInteract(EntityUid uid, WelderComponent welder, AfterInteractEvent args)
{
if (args.Handled)
return;
if (TryComp(target, out ReagentTankComponent? tank)
&& tank.TankType == ReagentTankType.Fuel
- && _solutionContainer.TryGetDrainableSolution(target, out var targetSoln, out var targetSolution)
- && _solutionContainer.ResolveSolution(entity.Owner, entity.Comp.FuelSolutionName, ref entity.Comp.FuelSolution, out var welderSolution))
+ && _solutionContainer.TryGetDrainableSolution(target, out var targetSolution)
+ && _solutionContainer.TryGetSolution(uid, welder.FuelSolution, out var welderSolution))
{
var trans = FixedPoint2.Min(welderSolution.AvailableVolume, targetSolution.Volume);
if (trans > 0)
{
- var drained = _solutionContainer.Drain(target, targetSoln.Value, trans);
- _solutionContainer.TryAddSolution(entity.Comp.FuelSolution.Value, drained);
- _audio.PlayPvs(entity.Comp.WelderRefill, entity);
- _popup.PopupEntity(Loc.GetString("welder-component-after-interact-refueled-message"), entity, args.User);
+ var drained = _solutionContainer.Drain(target, targetSolution, trans);
+ _solutionContainer.TryAddSolution(uid, welderSolution, drained);
+ _audio.PlayPvs(welder.WelderRefill, uid);
+ _popup.PopupEntity(Loc.GetString("welder-component-after-interact-refueled-message"), uid, args.User);
}
else if (welderSolution.AvailableVolume <= 0)
{
- _popup.PopupEntity(Loc.GetString("welder-component-already-full"), entity, args.User);
+ _popup.PopupEntity(Loc.GetString("welder-component-already-full"), uid, args.User);
}
else
{
- _popup.PopupEntity(Loc.GetString("welder-component-no-fuel-in-tank", ("owner", args.Target)), entity, args.User);
+ _popup.PopupEntity(Loc.GetString("welder-component-no-fuel-in-tank", ("owner", args.Target)), uid, args.User);
}
}
args.Handled = true;
}
- private void OnWelderToolUseAttempt(Entity<WelderComponent> entity, ref DoAfterAttemptEvent<ToolDoAfterEvent> args)
+ private void OnWelderToolUseAttempt(EntityUid uid, WelderComponent welder, DoAfterAttemptEvent<ToolDoAfterEvent> args)
{
var user = args.DoAfter.Args.User;
- if (!_itemToggle.IsActivated(entity.Owner))
+ if (!_itemToggle.IsActivated(uid))
{
- _popup.PopupEntity(Loc.GetString("welder-component-welder-not-lit-message"), entity, user);
+ _popup.PopupEntity(Loc.GetString("welder-component-welder-not-lit-message"), uid, user);
args.Cancel();
}
}
- private void OnWelderShutdown(Entity<WelderComponent> entity, ref ComponentShutdown args)
+ private void OnWelderShutdown(EntityUid uid, WelderComponent welder, ComponentShutdown args)
{
- _activeWelders.Remove(entity);
+ _activeWelders.Remove(uid);
}
- private void OnWelderGetState(Entity<WelderComponent> entity, ref ComponentGetState args)
+ private void OnWelderGetState(EntityUid uid, WelderComponent welder, ref ComponentGetState args)
{
- var (fuel, capacity) = GetWelderFuelAndCapacity(entity.Owner, entity.Comp);
+ var (fuel, capacity) = GetWelderFuelAndCapacity(uid, welder);
args.State = new WelderComponentState(capacity.Float(), fuel.Float());
}
|| !TryComp(tool, out SolutionContainerManagerComponent? solutionContainer))
continue;
- if (!_solutionContainer.ResolveSolution((tool, solutionContainer), welder.FuelSolutionName, ref welder.FuelSolution, out var solution))
+ if (!_solutionContainer.TryGetSolution(tool, welder.FuelSolution, out var solution, solutionContainer))
continue;
- _solutionContainer.RemoveReagent(welder.FuelSolution.Value, welder.FuelReagent, welder.FuelConsumption * _welderTimer);
+ solution.RemoveReagent(welder.FuelReagent, welder.FuelConsumption * _welderTimer);
if (solution.GetTotalPrototypeQuantity(welder.FuelReagent) <= FixedPoint2.Zero)
{
using Content.Server.Atmos.EntitySystems;
-using Content.Server.Chemistry.Containers.EntitySystems;
using Content.Server.Popups;
using Content.Server.Tools.Components;
+using Content.Shared.Chemistry.EntitySystems;
+using Content.Shared.Maps;
+using Content.Shared.Tools;
using Robust.Server.GameObjects;
+using Robust.Shared.Audio;
using Robust.Shared.Audio.Systems;
using Robust.Shared.Map;
-
using SharedToolSystem = Content.Shared.Tools.Systems.SharedToolSystem;
namespace Content.Server.Tools
+using System.Linq;
+using System.Numerics;
using Content.Server.Body.Components;
using Content.Server.Body.Systems;
using Content.Server.Chat.Systems;
using Content.Server.Chemistry.Components;
-using Content.Server.Chemistry.Containers.EntitySystems;
using Content.Server.CombatMode.Disarm;
using Content.Server.Contests;
using Content.Server.Movement.Systems;
using Content.Shared.Actions.Events;
using Content.Shared.Administration.Components;
+using Content.Shared.Chemistry.EntitySystems;
using Content.Shared.CombatMode;
using Content.Shared.Damage.Events;
using Content.Shared.Damage.Systems;
using Robust.Shared.Map;
using Robust.Shared.Player;
using Robust.Shared.Random;
-using System.Linq;
-using System.Numerics;
namespace Content.Server.Weapons.Melee;
}
- private void OnChemicalInjectorHit(Entity<MeleeChemicalInjectorComponent> entity, ref MeleeHitEvent args)
+ private void OnChemicalInjectorHit(EntityUid owner, MeleeChemicalInjectorComponent comp, MeleeHitEvent args)
{
if (!args.IsHit ||
!args.HitEntities.Any() ||
- !_solutions.TryGetSolution(entity.Owner, entity.Comp.Solution, out var solutionContainer))
+ !_solutions.TryGetSolution(owner, comp.Solution, out var solutionContainer))
{
return;
}
var hitBloodstreams = new List<(EntityUid Entity, BloodstreamComponent Component)>();
var bloodQuery = GetEntityQuery<BloodstreamComponent>();
- foreach (var hit in args.HitEntities)
+ foreach (var entity in args.HitEntities)
{
- if (Deleted(hit))
+ if (Deleted(entity))
continue;
// prevent deathnettles injecting through hardsuits
- if (!entity.Comp.PierceArmor && _inventory.TryGetSlotEntity(hit, "outerClothing", out var suit) && _tag.HasTag(suit.Value, "Hardsuit"))
+ if (!comp.PierceArmor && _inventory.TryGetSlotEntity(entity, "outerClothing", out var suit) && _tag.HasTag(suit.Value, "Hardsuit"))
{
- PopupSystem.PopupEntity(Loc.GetString("melee-inject-failed-hardsuit", ("weapon", entity.Owner)), args.User, args.User, PopupType.SmallCaution);
+ PopupSystem.PopupEntity(Loc.GetString("melee-inject-failed-hardsuit", ("weapon", owner)), args.User, args.User, PopupType.SmallCaution);
continue;
}
- if (bloodQuery.TryGetComponent(hit, out var bloodstream))
- hitBloodstreams.Add((hit, bloodstream));
+ if (bloodQuery.TryGetComponent(entity, out var bloodstream))
+ hitBloodstreams.Add((entity, bloodstream));
}
if (!hitBloodstreams.Any())
return;
- var removedSolution = _solutions.SplitSolution(solutionContainer.Value, entity.Comp.TransferAmount * hitBloodstreams.Count);
+ var removedSolution = solutionContainer.SplitSolution(comp.TransferAmount * hitBloodstreams.Count);
var removedVol = removedSolution.Volume;
- var solutionToInject = removedSolution.SplitSolution(removedVol * entity.Comp.TransferEfficiency);
+ var solutionToInject = removedSolution.SplitSolution(removedVol * comp.TransferEfficiency);
var volPerBloodstream = solutionToInject.Volume * (1 / hitBloodstreams.Count);
foreach (var (ent, bloodstream) in hitBloodstreams)
-using Content.Server.Chemistry.Containers.EntitySystems;
+using System.Linq;
using Content.Server.Weapons.Ranged.Components;
using Content.Shared.Chemistry.Components;
+using Content.Shared.Chemistry.EntitySystems;
using Content.Shared.Weapons.Ranged.Events;
-using System.Linq;
namespace Content.Server.Weapons.Ranged.Systems
{
public sealed class ChemicalAmmoSystem : EntitySystem
{
- [Dependency] private readonly SolutionContainerSystem _solutionContainerSystem = default!;
+ [Dependency] private readonly SolutionContainerSystem _solutionSystem = default!;
public override void Initialize()
{
SubscribeLocalEvent<ChemicalAmmoComponent, AmmoShotEvent>(OnFire);
}
- private void OnFire(Entity<ChemicalAmmoComponent> entity, ref AmmoShotEvent args)
+ private void OnFire(EntityUid uid, ChemicalAmmoComponent component, AmmoShotEvent args)
{
- if (!_solutionContainerSystem.TryGetSolution(entity.Owner, entity.Comp.SolutionName, out var ammoSoln, out var ammoSolution))
+ if (!_solutionSystem.TryGetSolution(uid, component.SolutionName, out var ammoSolution))
return;
var projectiles = args.FiredProjectiles;
- var projectileSolutionContainers = new List<(EntityUid, Entity<SolutionComponent>)>();
+ var projectileSolutionContainers = new List<(EntityUid, Solution)>();
foreach (var projectile in projectiles)
{
- if (_solutionContainerSystem
- .TryGetSolution(projectile, entity.Comp.SolutionName, out var projectileSoln, out _))
+ if (_solutionSystem
+ .TryGetSolution(projectile, component.SolutionName, out var projectileSolutionContainer))
{
- projectileSolutionContainers.Add((projectile, projectileSoln.Value));
+ projectileSolutionContainers.Add((uid, projectileSolutionContainer));
}
}
var solutionPerProjectile = ammoSolution.Volume * (1 / projectileSolutionContainers.Count);
- foreach (var (_, projectileSolution) in projectileSolutionContainers)
+ foreach (var (projectileUid, projectileSolution) in projectileSolutionContainers)
{
- var solutionToTransfer = _solutionContainerSystem.SplitSolution(ammoSoln.Value, solutionPerProjectile);
- _solutionContainerSystem.TryAddSolution(projectileSolution, solutionToTransfer);
+ var solutionToTransfer = _solutionSystem.SplitSolution(uid, ammoSolution, solutionPerProjectile);
+ _solutionSystem.TryAddSolution(projectileUid, projectileSolution, solutionToTransfer);
}
- _solutionContainerSystem.RemoveAllSolution(ammoSoln.Value);
+ _solutionSystem.RemoveAllSolution(uid, ammoSolution);
}
}
}
using Content.Server.Chemistry.Components;
-using Content.Server.Chemistry.Containers.EntitySystems;
using Content.Shared.Chemistry.Components;
using Content.Shared.Chemistry.EntitySystems;
using Content.Shared.FixedPoint;
base.InitializeSolution();
SubscribeLocalEvent<SolutionAmmoProviderComponent, MapInitEvent>(OnSolutionMapInit);
- SubscribeLocalEvent<SolutionAmmoProviderComponent, SolutionContainerChangedEvent>(OnSolutionChanged);
+ SubscribeLocalEvent<SolutionAmmoProviderComponent, SolutionChangedEvent>(OnSolutionChanged);
}
- private void OnSolutionMapInit(Entity<SolutionAmmoProviderComponent> entity, ref MapInitEvent args)
+ private void OnSolutionMapInit(EntityUid uid, SolutionAmmoProviderComponent component, MapInitEvent args)
{
- UpdateSolutionShots(entity.Owner, entity.Comp);
+ UpdateSolutionShots(uid, component);
}
- private void OnSolutionChanged(Entity<SolutionAmmoProviderComponent> entity, ref SolutionContainerChangedEvent args)
+ private void OnSolutionChanged(EntityUid uid, SolutionAmmoProviderComponent component, SolutionChangedEvent args)
{
- if (args.Solution.Name == entity.Comp.SolutionId)
- UpdateSolutionShots(entity.Owner, entity.Comp, args.Solution);
+ if (args.Solution.Name == component.SolutionId)
+ UpdateSolutionShots(uid, component, args.Solution);
}
protected override void UpdateSolutionShots(EntityUid uid, SolutionAmmoProviderComponent component, Solution? solution = null)
{
var shots = 0;
var maxShots = 0;
- if (solution == null && !_solutionContainer.TryGetSolution(uid, component.SolutionId, out _, out solution))
+ if (solution == null && !_solutionContainer.TryGetSolution(uid, component.SolutionId, out solution))
{
component.Shots = shots;
component.MaxShots = maxShots;
- Dirty(uid, component);
+ Dirty(component);
return;
}
component.Shots = shots;
component.MaxShots = maxShots;
- Dirty(uid, component);
+ Dirty(component);
UpdateSolutionAppearance(uid, component);
}
{
var (ent, shootable) = base.GetSolutionShot(uid, component, position);
- if (!_solutionContainer.TryGetSolution(uid, component.SolutionId, out var solution, out _))
+ if (!_solutionContainer.TryGetSolution(uid, component.SolutionId, out var solution))
return (ent, shootable);
- var newSolution = _solutionContainer.SplitSolution(solution.Value, component.FireCost);
+ var newSolution = _solutionContainer.SplitSolution(uid, solution, component.FireCost);
if (newSolution.Volume <= FixedPoint2.Zero)
return (ent, shootable);
}
// Add the solution to the vapor and actually send the thing
- if (_solutionContainer.TryGetSolution(ent, VaporComponent.SolutionName, out var vaporSolution, out _))
+ if (_solutionContainer.TryGetSolution(ent, VaporComponent.SolutionName, out var vaporSolution))
{
- _solutionContainer.TryAddSolution(vaporSolution.Value, newSolution);
+ _solutionContainer.TryAddSolution(ent, vaporSolution, newSolution);
}
return (ent, shootable);
}
using Content.Server.Xenoarchaeology.XenoArtifacts.Effects.Systems;
using Content.Shared.Chemistry.Components;
using Content.Shared.Chemistry.Reagent;
+using Robust.Shared.Prototypes;
+using Robust.Shared.Serialization.TypeSerializers.Implementations.Custom.Prototype;
using Robust.Shared.Serialization.TypeSerializers.Implementations.Custom.Prototype.List;
namespace Content.Server.Xenoarchaeology.XenoArtifacts.Effects.Components;
using Content.Shared.Eui;
using Robust.Shared.Serialization;
+using Content.Shared.Chemistry.Components;
namespace Content.Shared.Administration
{
public sealed class EditSolutionsEuiState : EuiStateBase
{
public readonly NetEntity Target;
- public readonly List<(string, NetEntity)>? Solutions;
+ public readonly Dictionary<string, Solution>? Solutions;
- public EditSolutionsEuiState(NetEntity target, List<(string, NetEntity)>? solutions)
+ public EditSolutionsEuiState(NetEntity target, Dictionary<string, Solution>? solutions)
{
Target = target;
Solutions = solutions;
/// <summary>
/// Solution name that can be drained.
/// </summary>
- [DataField, ViewVariables(VVAccess.ReadWrite)]
- public string Solution = "default";
+ [ViewVariables(VVAccess.ReadWrite)]
+ [DataField("solution")]
+ public string Solution { get; set; } = "default";
}
/// <summary>
/// Solution name that can be dumped into.
/// </summary>
- [DataField, ViewVariables(VVAccess.ReadWrite)]
- public string Solution = "default";
+ [ViewVariables(VVAccess.ReadWrite)]
+ [DataField("solution")]
+ public string Solution { get; set; } = "default";
/// <summary>
/// Whether the solution can be dumped into infinitely.
/// </summary>
- [DataField, ViewVariables(VVAccess.ReadWrite)]
- public bool Unlimited = false;
+ [ViewVariables(VVAccess.ReadWrite)]
+ [DataField("unlimited")]
+ public bool Unlimited { get; set; } = false;
}
using Robust.Shared.GameStates;
-namespace Content.Shared.Chemistry.Components;
-
-/// <summary>
-/// Allows the entity with this component to be placed in a <c>SharedReagentDispenserComponent</c>.
-/// <para>Otherwise it's considered to be too large or the improper shape to fit.</para>
-/// <para>Allows us to have obscenely large containers that are harder to abuse in chem dispensers
-/// since they can't be placed directly in them.</para>
-/// <see cref="Dispenser.SharedReagentDispenserComponent"/>
-/// </summary>
-[RegisterComponent]
-[NetworkedComponent] // only needed for white-lists. Client doesn't actually need Solution data;
-public sealed partial class FitsInDispenserComponent : Component
+namespace Content.Shared.Chemistry.Components
{
/// <summary>
- /// Solution name that will interact with ReagentDispenserComponent.
+ /// Allows the entity with this component to be placed in a <c>SharedReagentDispenserComponent</c>.
+ /// <para>Otherwise it's considered to be too large or the improper shape to fit.</para>
+ /// <para>Allows us to have obscenely large containers that are harder to abuse in chem dispensers
+ /// since they can't be placed directly in them.</para>
+ /// <see cref="Dispenser.SharedReagentDispenserComponent"/>
/// </summary>
- [DataField, ViewVariables(VVAccess.ReadWrite)]
- public string Solution = "default";
+ [RegisterComponent]
+ [NetworkedComponent] // only needed for white-lists. Client doesn't actually need Solution data;
+ public sealed partial class FitsInDispenserComponent : Component
+ {
+ /// <summary>
+ /// Solution name that will interact with ReagentDispenserComponent.
+ /// </summary>
+ [ViewVariables(VVAccess.ReadWrite)]
+ [DataField("solution")]
+ public string Solution { get; set; } = "default";
+ }
}
/// <summary>
/// Solution name that can added to easily.
/// </summary>
- [DataField, ViewVariables(VVAccess.ReadWrite)]
- public string Solution = "default";
+ [ViewVariables(VVAccess.ReadWrite)]
+ [DataField("solution")]
+ public string Solution { get; set; } = "default";
/// <summary>
/// The maximum amount that can be transferred to the solution at once
/// </summary>
- [DataField, ViewVariables(VVAccess.ReadWrite)]
- public FixedPoint2? MaxRefill = null;
+ [DataField("maxRefill")]
+ [ViewVariables(VVAccess.ReadWrite)]
+ public FixedPoint2? MaxRefill { get; set; } = null;
}
{
public const string SolutionName = "solutionArea";
- /// <summary>
- /// The solution on the entity with touch and ingestion reactions.
- /// </summary>
- [DataField]
- public Entity<SolutionComponent>? Solution = null;
-
/// <summary>
/// The max amount of tiles this smoke cloud can spread to.
/// </summary>
/// <summary>
/// The name of this solution, if it is contained in some <see cref="SolutionContainerManagerComponent"/>
/// </summary>
- [DataField]
public string? Name;
/// <summary>
foreach (var (reagent, quantity) in Contents)
{
_heatCapacity += (float) quantity *
- protoMan.Index<ReagentPrototype>(reagent.Prototype).SpecificHeat;
+ protoMan.Index<ReagentPrototype>(reagent.Prototype).SpecificHeat;
}
}
public Solution(Solution solution)
{
- Contents = solution.Contents.ShallowClone();
Volume = solution.Volume;
- MaxVolume = solution.MaxVolume;
- Temperature = solution.Temperature;
_heatCapacity = solution._heatCapacity;
_heatCapacityDirty = solution._heatCapacityDirty;
+ Contents = solution.Contents.ShallowClone();
ValidateSolution();
}
public void ValidateSolution()
{
// sandbox forbids: [Conditional("DEBUG")]
- #if DEBUG
+#if DEBUG
// Correct volume
DebugTools.Assert(Contents.Select(x => x.Quantity).Sum() == Volume);
UpdateHeatCapacity(null);
DebugTools.Assert(MathHelper.CloseTo(_heatCapacity, cur));
}
- #endif
+#endif
}
void ISerializationHooks.AfterDeserialization()
+++ /dev/null
-using Content.Shared.Chemistry.Components.SolutionManager;
-using Content.Shared.Materials;
-using Robust.Shared.GameStates;
-
-namespace Content.Shared.Chemistry.Components;
-
-/// <summary>
-/// <para>Holds the composition of an entity made from reagents and its reagent temperature.</para>
-/// <para>If the entity is used to represent a collection of reagents inside of a container such as a beaker, syringe, bloodstream, food, or similar the entity is tracked by a <see cref="SolutionContainerManagerComponent"/> on the container and has a <see cref="ContainedSolutionComponent"/> tracking which container it's in.</para>
-/// </summary>
-/// <remarks>
-/// <para>Once reagents and materials have been merged this component should be depricated in favor of using a combination of <see cref="PhysicalCompositionComponent"/> and <see cref="Content.Server.Temperature.Components.TemperatureComponent"/>. May require minor reworks to both.</para>
-/// </remarks>
-[RegisterComponent, NetworkedComponent, AutoGenerateComponentState]
-public sealed partial class SolutionComponent : Component
-{
- /// <summary>
- /// <para>The reagents the entity is composed of and their temperature.</para>
- /// </summary>
- [DataField, AutoNetworkedField]
- public Solution Solution = new();
-}
+++ /dev/null
-using Content.Shared.Chemistry.EntitySystems;
-using Robust.Shared.GameStates;
-using Robust.Shared.Serialization;
-
-namespace Content.Shared.Chemistry.Components.SolutionManager;
-
-/// <summary>
-/// Component used to relate a solution to its container.
-/// </summary>
-/// <remarks>
-/// When containers are finally ECS'd have this attach to the container entity.
-/// The <see cref="Solution.MaxVolume"/> field should then be extracted out into this component.
-/// Solution entities would just become an apporpriately composed entity hanging out in the container.
-/// Will probably require entities in components being given a relation to associate themselves with their container.
-/// </remarks>
-[RegisterComponent, NetworkedComponent, AutoGenerateComponentState]
-[Access(typeof(SharedSolutionContainerSystem))]
-public sealed partial class ContainedSolutionComponent : Component
-{
- /// <summary>
- /// The entity that the solution is contained in.
- /// </summary>
- [DataField(required: true), AutoNetworkedField]
- public EntityUid Container;
-
- /// <summary>
- /// The name/key of the container the solution is located in.
- /// </summary>
- [DataField(required: true), AutoNetworkedField]
- public string ContainerName = default!;
-}
/// <summary>
/// Solution name that can be removed with syringes.
/// </summary>
- [DataField, ViewVariables(VVAccess.ReadWrite)]
- public string Solution = "default";
+ [ViewVariables(VVAccess.ReadWrite)]
+ [DataField("solution")]
+ public string Solution { get; set; } = "default";
}
[RegisterComponent]
public sealed partial class ExaminableSolutionComponent : Component
{
- [DataField, ViewVariables(VVAccess.ReadWrite)]
- public string Solution = "default";
+ [ViewVariables(VVAccess.ReadWrite)]
+ [DataField("solution")]
+ public string Solution { get; set; } = "default";
}
/// <summary>
/// Solution name which can be added with syringes.
/// </summary>
- [DataField, ViewVariables(VVAccess.ReadWrite)]
- public string Solution = "default";
+ [ViewVariables(VVAccess.ReadWrite)]
+ [DataField("solution")]
+ public string Solution { get; set; } = "default";
}
using Content.Shared.Chemistry.EntitySystems;
-using Robust.Shared.Containers;
-using Robust.Shared.GameStates;
namespace Content.Shared.Chemistry.Components.SolutionManager;
-/// <summary>
-/// <para>A map of the solution entities contained within this entity.</para>
-/// <para>Every solution entity this maps should have a <see cref="SolutionComponent"/> to track its state and a <see cref="ContainedSolutionComponent"/> to track its container.</para>
-/// </summary>
-[RegisterComponent, NetworkedComponent, AutoGenerateComponentState]
-[Access(typeof(SharedSolutionContainerSystem))]
+[RegisterComponent]
+[Access(typeof(SolutionContainerSystem))]
public sealed partial class SolutionContainerManagerComponent : Component
{
- /// <summary>
- /// The default amount of space that will be allocated for solutions in solution containers.
- /// Most solution containers will only contain 1-2 solutions.
- /// </summary>
- public const int DefaultCapacity = 2;
-
- /// <summary>
- /// The names of each solution container attached to this entity.
- /// Actually accessing them must be done via <see cref="ContainerManagerComponent"/>.
- /// </summary>
- [DataField, AutoNetworkedField]
- public HashSet<string> Containers = new(DefaultCapacity);
-
- /// <summary>
- /// The set of solutions to load onto this entity during mapinit.
- /// </summary>
- /// <remarks>
- /// Should be null after mapinit.
- /// </remarks>
- [DataField(serverOnly: true)] // Needs to be serverOnly or these will get loaded on the client and never cleared. Can be reworked when entity spawning is predicted.
- public Dictionary<string, Solution>? Solutions = null;
+ [DataField("solutions")]
+ [Access(typeof(SolutionContainerSystem), Other = AccessPermissions.ReadExecute)] // FIXME Friends
+ public Dictionary<string, Solution> Solutions = new();
}
[Dependency] private readonly SharedAudioSystem _audio = default!;
[Dependency] private readonly SharedContainerSystem _container = default!;
[Dependency] private readonly SharedPopupSystem _popup = default!;
- [Dependency] private readonly SharedSolutionContainerSystem _solution = default!;
+ [Dependency] private readonly SolutionContainerSystem _solution = default!;
/// <inheritdoc/>
public override void Initialize()
foreach (var ent in container.ContainedEntities)
{
- if (!_solution.TryGetFitsInDispenser(ent, out var soln, out _))
+ if (!_solution.TryGetFitsInDispenser(ent, out var solution))
continue;
- _solution.UpdateChemicals(soln.Value, true, reactionMixer);
+ _solution.UpdateChemicals(ent, solution, true, reactionMixer);
}
}
+++ /dev/null
-using Content.Shared.Chemistry.Components;
-using Content.Shared.Chemistry.Components.SolutionManager;
-using Content.Shared.Chemistry.Reaction;
-using Content.Shared.FixedPoint;
-using Robust.Shared.Utility;
-using System.Diagnostics.CodeAnalysis;
-using System.Text;
-
-namespace Content.Shared.Chemistry.EntitySystems;
-
-public abstract partial class SharedSolutionContainerSystem
-{
- #region Solution Accessors
-
- public bool TryGetRefillableSolution(Entity<RefillableSolutionComponent?, SolutionContainerManagerComponent?> entity, [NotNullWhen(true)] out Entity<SolutionComponent>? soln, [NotNullWhen(true)] out Solution? solution)
- {
- if (!Resolve(entity, ref entity.Comp1, logMissing: false))
- {
- (soln, solution) = (default!, null);
- return false;
- }
-
- return TryGetSolution((entity.Owner, entity.Comp2), entity.Comp1.Solution, out soln, out solution);
- }
-
- public bool TryGetDrainableSolution(Entity<DrainableSolutionComponent?, SolutionContainerManagerComponent?> entity, [NotNullWhen(true)] out Entity<SolutionComponent>? soln, [NotNullWhen(true)] out Solution? solution)
- {
- if (!Resolve(entity, ref entity.Comp1, logMissing: false))
- {
- (soln, solution) = (default!, null);
- return false;
- }
-
- return TryGetSolution((entity.Owner, entity.Comp2), entity.Comp1.Solution, out soln, out solution);
- }
-
- public bool TryGetDumpableSolution(Entity<DumpableSolutionComponent?, SolutionContainerManagerComponent?> entity, [NotNullWhen(true)] out Entity<SolutionComponent>? soln, [NotNullWhen(true)] out Solution? solution)
- {
- if (!Resolve(entity, ref entity.Comp1, logMissing: false))
- {
- (soln, solution) = (default!, null);
- return false;
- }
-
- return TryGetSolution((entity.Owner, entity.Comp2), entity.Comp1.Solution, out soln, out solution);
- }
-
- public bool TryGetDrawableSolution(Entity<DrawableSolutionComponent?, SolutionContainerManagerComponent?> entity, [NotNullWhen(true)] out Entity<SolutionComponent>? soln, [NotNullWhen(true)] out Solution? solution)
- {
- if (!Resolve(entity, ref entity.Comp1, logMissing: false))
- {
- (soln, solution) = (default!, null);
- return false;
- }
-
- return TryGetSolution((entity.Owner, entity.Comp2), entity.Comp1.Solution, out soln, out solution);
- }
-
- public bool TryGetInjectableSolution(Entity<InjectableSolutionComponent?, SolutionContainerManagerComponent?> entity, [NotNullWhen(true)] out Entity<SolutionComponent>? soln, [NotNullWhen(true)] out Solution? solution)
- {
- if (!Resolve(entity, ref entity.Comp1, logMissing: false))
- {
- (soln, solution) = (default!, null);
- return false;
- }
-
- return TryGetSolution((entity.Owner, entity.Comp2), entity.Comp1.Solution, out soln, out solution);
- }
-
- public bool TryGetFitsInDispenser(Entity<FitsInDispenserComponent?, SolutionContainerManagerComponent?> entity, [NotNullWhen(true)] out Entity<SolutionComponent>? soln, [NotNullWhen(true)] out Solution? solution)
- {
- if (!Resolve(entity, ref entity.Comp1, logMissing: false))
- {
- (soln, solution) = (default!, null);
- return false;
- }
-
- return TryGetSolution((entity.Owner, entity.Comp2), entity.Comp1.Solution, out soln, out solution);
- }
-
- public bool TryGetMixableSolution(Entity<SolutionContainerManagerComponent?> container, [NotNullWhen(true)] out Entity<SolutionComponent>? solution)
- {
- var getMixableSolutionAttempt = new GetMixableSolutionAttemptEvent(container);
- RaiseLocalEvent(container, ref getMixableSolutionAttempt);
- if (getMixableSolutionAttempt.MixedSolution != null)
- {
- solution = getMixableSolutionAttempt.MixedSolution;
- return true;
- }
-
- if (!Resolve(container, ref container.Comp, false))
- {
- solution = default!;
- return false;
- }
-
- var tryGetSolution = EnumerateSolutions(container).FirstOrNull(x => x.Solution.Comp.Solution.CanMix);
- if (tryGetSolution.HasValue)
- {
- solution = tryGetSolution.Value.Solution;
- return true;
- }
-
- solution = default!;
- return false;
- }
-
- #endregion Solution Accessors
-
- #region Solution Modifiers
-
- public void Refill(Entity<RefillableSolutionComponent?> entity, Entity<SolutionComponent> soln, Solution refill)
- {
- if (!Resolve(entity, ref entity.Comp, logMissing: false))
- return;
-
- AddSolution(soln, refill);
- }
-
- public void Inject(Entity<InjectableSolutionComponent?> entity, Entity<SolutionComponent> soln, Solution inject)
- {
- if (!Resolve(entity, ref entity.Comp, logMissing: false))
- return;
-
- AddSolution(soln, inject);
- }
-
- public Solution Drain(Entity<DrainableSolutionComponent?> entity, Entity<SolutionComponent> soln, FixedPoint2 quantity)
- {
- if (!Resolve(entity, ref entity.Comp, logMissing: false))
- return new();
-
- return SplitSolution(soln, quantity);
- }
-
- public Solution Draw(Entity<DrawableSolutionComponent?> entity, Entity<SolutionComponent> soln, FixedPoint2 quantity)
- {
- if (!Resolve(entity, ref entity.Comp, logMissing: false))
- return new();
-
- return SplitSolution(soln, quantity);
- }
-
- #endregion Solution Modifiers
-
- public float PercentFull(EntityUid uid)
- {
- if (!TryGetDrainableSolution(uid, out _, out var solution) || solution.MaxVolume.Equals(FixedPoint2.Zero))
- return 0;
-
- return solution.FillFraction * 100;
- }
-
- #region Static Methods
-
- public static string ToPrettyString(Solution solution)
- {
- var sb = new StringBuilder();
- if (solution.Name == null)
- sb.Append("[");
- else
- sb.Append($"{solution.Name}:[");
- var first = true;
- foreach (var (id, quantity) in solution.Contents)
- {
- if (first)
- {
- first = false;
- }
- else
- {
- sb.Append(", ");
- }
-
- sb.AppendFormat("{0}: {1}u", id, quantity);
- }
-
- sb.Append(']');
- return sb.ToString();
- }
-
- #endregion Static Methods
-}
+++ /dev/null
-using Content.Shared.Chemistry.Components;
-using Content.Shared.Chemistry.Components.SolutionManager;
-using Content.Shared.Chemistry.Reaction;
-using Content.Shared.FixedPoint;
-
-namespace Content.Shared.Chemistry.EntitySystems;
-
-#region Events
-
-/// <summary>
-/// This event alerts system that the solution was changed
-/// </summary>
-[ByRefEvent]
-public record struct SolutionContainerChangedEvent
-{
- public readonly Solution Solution;
- public readonly string SolutionId;
-
- public SolutionContainerChangedEvent(Solution solution, string solutionId)
- {
- SolutionId = solutionId;
- Solution = solution;
- }
-}
-
-/// <summary>
-/// An event raised when more reagents are added to a (managed) solution than it can hold.
-/// </summary>
-[ByRefEvent]
-public record struct SolutionContainerOverflowEvent(EntityUid SolutionEnt, Solution SolutionHolder, Solution Overflow)
-{
- /// <summary>The entity which contains the solution that has overflowed.</summary>
- public readonly EntityUid SolutionEnt = SolutionEnt;
- /// <summary>The solution that has overflowed.</summary>
- public readonly Solution SolutionHolder = SolutionHolder;
- /// <summary>The reagents that have overflowed the solution.</summary>
- public readonly Solution Overflow = Overflow;
- /// <summary>The volume by which the solution has overflowed.</summary>
- public readonly FixedPoint2 OverflowVol = Overflow.Volume;
- /// <summary>Whether some subscriber has taken care of the effects of the overflow.</summary>
- public bool Handled = false;
-}
-
-/// <summary>
-/// Ref event used to relay events raised on solution entities to their containers.
-/// </summary>
-/// <typeparam name="TEvent"></typeparam>
-/// <param name="Event">The event that is being relayed.</param>
-/// <param name="ContainerEnt">The container entity that the event is being relayed to.</param>
-/// <param name="Name">The name of the solution entity that the event is being relayed from.</param>
-[ByRefEvent]
-public record struct SolutionRelayEvent<TEvent>(TEvent Event, EntityUid ContainerEnt, string Name)
-{
- public readonly EntityUid ContainerEnt = ContainerEnt;
- public readonly string Name = Name;
- public TEvent Event = Event;
-}
-
-/// <summary>
-/// Ref event used to relay events raised on solution containers to their contained solutions.
-/// </summary>
-/// <typeparam name="TEvent"></typeparam>
-/// <param name="Event">The event that is being relayed.</param>
-/// <param name="SolutionEnt">The solution entity that the event is being relayed to.</param>
-/// <param name="Name">The name of the solution entity that the event is being relayed to.</param>
-[ByRefEvent]
-public record struct SolutionContainerRelayEvent<TEvent>(TEvent Event, Entity<SolutionComponent> SolutionEnt, string Name)
-{
- public readonly Entity<SolutionComponent> SolutionEnt = SolutionEnt;
- public readonly string Name = Name;
- public TEvent Event = Event;
-}
-
-#endregion Events
-
-public abstract partial class SharedSolutionContainerSystem
-{
- protected void InitializeRelays()
- {
- SubscribeLocalEvent<ContainedSolutionComponent, SolutionChangedEvent>(OnSolutionChanged);
- SubscribeLocalEvent<ContainedSolutionComponent, SolutionOverflowEvent>(OnSolutionOverflow);
- SubscribeLocalEvent<ContainedSolutionComponent, ReactionAttemptEvent>(RelaySolutionRefEvent);
- }
-
- #region Event Handlers
-
- protected virtual void OnSolutionChanged(Entity<ContainedSolutionComponent> entity, ref SolutionChangedEvent args)
- {
- var (solutionId, solutionComp) = args.Solution;
- var solution = solutionComp.Solution;
-
- UpdateAppearance(entity.Comp.Container, (solutionId, solutionComp, entity.Comp));
-
- var relayEvent = new SolutionContainerChangedEvent(solution, entity.Comp.ContainerName);
- RaiseLocalEvent(entity.Comp.Container, ref relayEvent);
- }
-
- protected virtual void OnSolutionOverflow(Entity<ContainedSolutionComponent> entity, ref SolutionOverflowEvent args)
- {
- var solution = args.Solution.Comp.Solution;
- var overflow = solution.SplitSolution(args.Overflow);
- var relayEv = new SolutionContainerOverflowEvent(entity.Owner, solution, overflow)
- {
- Handled = args.Handled,
- };
-
- RaiseLocalEvent(entity.Comp.Container, ref relayEv);
- args.Handled = relayEv.Handled;
- }
-
- #region Relay Event Handlers
-
- private void RelaySolutionValEvent<TEvent>(EntityUid uid, ContainedSolutionComponent comp, TEvent @event)
- {
- var relayEvent = new SolutionRelayEvent<TEvent>(@event, uid, comp.ContainerName);
- RaiseLocalEvent(comp.Container, ref relayEvent);
- }
-
- private void RelaySolutionRefEvent<TEvent>(Entity<ContainedSolutionComponent> entity, ref TEvent @event)
- {
- var relayEvent = new SolutionRelayEvent<TEvent>(@event, entity.Owner, entity.Comp.ContainerName);
- RaiseLocalEvent(entity.Comp.Container, ref relayEvent);
- @event = relayEvent.Event;
- }
-
- private void RelaySolutionContainerEvent<TEvent>(EntityUid uid, SolutionContainerManagerComponent comp, TEvent @event)
- {
- foreach (var (name, soln) in EnumerateSolutions((uid, comp)))
- {
- var relayEvent = new SolutionContainerRelayEvent<TEvent>(@event, soln, name!);
- RaiseLocalEvent(soln, ref relayEvent);
- }
- }
-
- private void RelaySolutionContainerEvent<TEvent>(Entity<SolutionContainerManagerComponent> entity, ref TEvent @event)
- {
- foreach (var (name, soln) in EnumerateSolutions((entity.Owner, entity.Comp)))
- {
- var relayEvent = new SolutionContainerRelayEvent<TEvent>(@event, soln, name!);
- RaiseLocalEvent(soln, ref relayEvent);
- @event = relayEvent.Event;
- }
- }
-
- #endregion Relay Event Handlers
-
- #endregion Event Handlers
-}
+++ /dev/null
-using Content.Shared.Chemistry.Components;
-using Content.Shared.Chemistry.Components.SolutionManager;
-using Content.Shared.Chemistry.Reaction;
-using Content.Shared.Chemistry.Reagent;
-using Content.Shared.Examine;
-using Content.Shared.FixedPoint;
-using Content.Shared.Verbs;
-using JetBrains.Annotations;
-using Robust.Shared.Containers;
-using Robust.Shared.Prototypes;
-using Robust.Shared.Utility;
-using System.Diagnostics.CodeAnalysis;
-using System.Linq;
-using System.Runtime.CompilerServices;
-using System.Text;
-using Dependency = Robust.Shared.IoC.DependencyAttribute;
-
-namespace Content.Shared.Chemistry.EntitySystems;
-
-/// <summary>
-/// The event raised whenever a solution entity is modified.
-/// </summary>
-/// <remarks>
-/// Raised after chemcial reactions and <see cref="SolutionOverflowEvent"/> are handled.
-/// </remarks>
-/// <param name="Solution">The solution entity that has been modified.</param>
-[ByRefEvent]
-public readonly partial record struct SolutionChangedEvent(Entity<SolutionComponent> Solution);
-
-/// <summary>
-/// The event raised whenever a solution entity is filled past its capacity.
-/// </summary>
-/// <param name="Solution">The solution entity that has been overfilled.</param>
-/// <param name="Overflow">The amount by which the solution entity has been overfilled.</param>
-[ByRefEvent]
-public partial record struct SolutionOverflowEvent(Entity<SolutionComponent> Solution, FixedPoint2 Overflow)
-{
- /// <summary>The solution entity that has been overfilled.</summary>
- public readonly Entity<SolutionComponent> Solution = Solution;
- /// <summary>The amount by which the solution entity has been overfilled.</summary>
- public readonly FixedPoint2 Overflow = Overflow;
- /// <summary>Whether any of the event handlers for this event have handled overflow behaviour.</summary>
- public bool Handled = false;
-}
-
-/// <summary>
-/// Part of Chemistry system deal with SolutionContainers
-/// </summary>
-[UsedImplicitly]
-public abstract partial class SharedSolutionContainerSystem : EntitySystem
-{
- [Dependency] protected readonly IPrototypeManager PrototypeManager = default!;
- [Dependency] protected readonly ChemicalReactionSystem ChemicalReactionSystem = default!;
- [Dependency] protected readonly ExamineSystemShared ExamineSystem = default!;
- [Dependency] protected readonly SharedAppearanceSystem AppearanceSystem = default!;
- [Dependency] protected readonly SharedContainerSystem ContainerSystem = default!;
-
- public override void Initialize()
- {
- base.Initialize();
-
- InitializeRelays();
-
- SubscribeLocalEvent<SolutionComponent, ComponentInit>(OnComponentInit);
- SubscribeLocalEvent<SolutionComponent, ComponentStartup>(OnComponentStartup);
- SubscribeLocalEvent<SolutionComponent, ComponentShutdown>(OnComponentShutdown);
-
- SubscribeLocalEvent<SolutionContainerManagerComponent, ComponentInit>(OnComponentInit);
-
- SubscribeLocalEvent<ExaminableSolutionComponent, ExaminedEvent>(OnExamineSolution);
- SubscribeLocalEvent<ExaminableSolutionComponent, GetVerbsEvent<ExamineVerb>>(OnSolutionExaminableVerb);
- }
-
-
- /// <summary>
- /// Attempts to resolve a solution associated with an entity.
- /// </summary>
- /// <param name="container">The entity that holdes the container the solution entity is in.</param>
- /// <param name="name">The name of the solution entities container.</param>
- /// <param name="entity">A reference to a solution entity to load the associated solution entity into. Will be unchanged if not null.</param>
- /// <param name="solution">Returns the solution state of the solution entity.</param>
- /// <returns>Whether the solution was successfully resolved.</returns>
- [MethodImpl(MethodImplOptions.AggressiveInlining)]
- public bool ResolveSolution(Entity<SolutionContainerManagerComponent?> container, string? name, [NotNullWhen(true)] ref Entity<SolutionComponent>? entity, [NotNullWhen(true)] out Solution? solution)
- {
- if (!ResolveSolution(container, name, ref entity))
- {
- solution = null;
- return false;
- }
-
- solution = entity.Value.Comp.Solution;
- return true;
- }
-
- /// <inheritdoc cref="ResolveSolution"/>
- [MethodImpl(MethodImplOptions.AggressiveInlining)]
- public bool ResolveSolution(Entity<SolutionContainerManagerComponent?> container, string? name, [NotNullWhen(true)] ref Entity<SolutionComponent>? entity)
- {
- if (entity is not null)
- {
- DebugTools.Assert(TryGetSolution(container, name, out var debugEnt)
- && debugEnt.Value.Owner == entity.Value.Owner);
- return true;
- }
-
- return TryGetSolution(container, name, out entity);
- }
-
- /// <summary>
- /// Attempts to fetch a solution entity associated with an entity.
- /// </summary>
- /// <remarks>
- /// If the solution entity will be frequently accessed please use the equivalent <see cref="ResolveSolution"/> method and cache the result.
- /// </remarks>
- /// <param name="container">The entity the solution entity should be associated with.</param>
- /// <param name="name">The name of the solution entity to fetch.</param>
- /// <param name="entity">Returns the solution entity that was fetched.</param>
- /// <param name="solution">Returns the solution state of the solution entity that was fetched.</param>
- /// <returns></returns>
- public bool TryGetSolution(Entity<SolutionContainerManagerComponent?> container, string? name, [NotNullWhen(true)] out Entity<SolutionComponent>? entity, [NotNullWhen(true)] out Solution? solution)
- {
- if (!TryGetSolution(container, name, out entity))
- {
- solution = null;
- return false;
- }
-
- solution = entity.Value.Comp.Solution;
- return true;
- }
-
- /// <inheritdoc cref="TryGetSolution"/>
- public bool TryGetSolution(Entity<SolutionContainerManagerComponent?> container, string? name, [NotNullWhen(true)] out Entity<SolutionComponent>? entity)
- {
- EntityUid uid;
- if (name is null)
- uid = container;
- else if (
- ContainerSystem.TryGetContainer(container, $"solution@{name}", out var solutionContainer) &&
- solutionContainer is ContainerSlot solutionSlot &&
- solutionSlot.ContainedEntity is { } containedSolution
- )
- uid = containedSolution;
- else
- {
- entity = null;
- return false;
- }
-
- if (!TryComp(uid, out SolutionComponent? comp))
- {
- entity = null;
- return false;
- }
-
- entity = (uid, comp);
- return true;
- }
-
- public IEnumerable<(string? Name, Entity<SolutionComponent> Solution)> EnumerateSolutions(Entity<SolutionContainerManagerComponent?> container, bool includeSelf = true)
- {
- if (includeSelf && TryComp(container, out SolutionComponent? solutionComp))
- yield return (null, (container.Owner, solutionComp));
-
- if (!Resolve(container, ref container.Comp, logMissing: false))
- yield break;
-
- foreach (var name in container.Comp.Containers)
- {
- if (ContainerSystem.GetContainer(container, $"solution@{name}") is ContainerSlot slot && slot.ContainedEntity is { } solutionId)
- yield return (name, (solutionId, Comp<SolutionComponent>(solutionId)));
- }
- }
-
- public IEnumerable<(string Name, Solution Solution)> EnumerateSolutions(SolutionContainerManagerComponent container)
- {
- if (container.Solutions is not { Count: > 0 } solutions)
- yield break;
-
- foreach (var (name, solution) in solutions)
- {
- yield return (name, solution);
- }
- }
-
-
- protected void UpdateAppearance(Entity<AppearanceComponent?> container, Entity<SolutionComponent, ContainedSolutionComponent> soln)
- {
- var (uid, appearanceComponent) = container;
- if (!HasComp<SolutionContainerVisualsComponent>(uid) || !Resolve(uid, ref appearanceComponent, logMissing: false))
- return;
-
- var (_, comp, relation) = soln;
- var solution = comp.Solution;
-
- AppearanceSystem.SetData(uid, SolutionContainerVisuals.FillFraction, solution.FillFraction, appearanceComponent);
- AppearanceSystem.SetData(uid, SolutionContainerVisuals.Color, solution.GetColor(PrototypeManager), appearanceComponent);
- AppearanceSystem.SetData(uid, SolutionContainerVisuals.SolutionName, relation.ContainerName, appearanceComponent);
-
- if (solution.GetPrimaryReagentId() is { } reagent)
- AppearanceSystem.SetData(uid, SolutionContainerVisuals.BaseOverride, reagent.ToString(), appearanceComponent);
- else
- AppearanceSystem.SetData(uid, SolutionContainerVisuals.BaseOverride, string.Empty, appearanceComponent);
- }
-
-
- public FixedPoint2 GetTotalPrototypeQuantity(EntityUid owner, string reagentId)
- {
- var reagentQuantity = FixedPoint2.New(0);
- if (EntityManager.EntityExists(owner)
- && EntityManager.TryGetComponent(owner, out SolutionContainerManagerComponent? managerComponent))
- {
- foreach (var (_, soln) in EnumerateSolutions((owner, managerComponent)))
- {
- var solution = soln.Comp.Solution;
- reagentQuantity += solution.GetTotalPrototypeQuantity(reagentId);
- }
- }
-
- return reagentQuantity;
- }
-
-
- /// <summary>
- /// Dirties a solution entity that has been modified and prompts updates to chemical reactions and overflow state.
- /// Should be invoked whenever a solution entity is modified.
- /// </summary>
- /// <remarks>
- /// 90% of this system is ensuring that this proc is invoked whenever a solution entity is changed. The other 10% <i>is</i> this proc.
- /// </remarks>
- /// <param name="soln"></param>
- /// <param name="needsReactionsProcessing"></param>
- /// <param name="mixerComponent"></param>
- public void UpdateChemicals(Entity<SolutionComponent> soln, bool needsReactionsProcessing = true, ReactionMixerComponent? mixerComponent = null)
- {
- Dirty(soln);
-
- var (uid, comp) = soln;
- var solution = comp.Solution;
-
- // Process reactions
- if (needsReactionsProcessing && solution.CanReact)
- ChemicalReactionSystem.FullyReactSolution(soln, mixerComponent);
-
- var overflow = solution.Volume - solution.MaxVolume;
- if (overflow > FixedPoint2.Zero)
- {
- var overflowEv = new SolutionOverflowEvent(soln, overflow);
- RaiseLocalEvent(uid, ref overflowEv);
- }
-
- UpdateAppearance((uid, comp, null));
-
- var changedEv = new SolutionChangedEvent(soln);
- RaiseLocalEvent(uid, ref changedEv);
- }
-
- public void UpdateAppearance(Entity<SolutionComponent, AppearanceComponent?> soln)
- {
- var (uid, comp, appearanceComponent) = soln;
- var solution = comp.Solution;
-
- if (!EntityManager.EntityExists(uid) || !Resolve(uid, ref appearanceComponent, false))
- return;
-
- AppearanceSystem.SetData(uid, SolutionContainerVisuals.FillFraction, solution.FillFraction, appearanceComponent);
- AppearanceSystem.SetData(uid, SolutionContainerVisuals.Color, solution.GetColor(PrototypeManager), appearanceComponent);
-
- if (solution.GetPrimaryReagentId() is { } reagent)
- AppearanceSystem.SetData(uid, SolutionContainerVisuals.BaseOverride, reagent.ToString(), appearanceComponent);
- else
- AppearanceSystem.SetData(uid, SolutionContainerVisuals.BaseOverride, string.Empty, appearanceComponent);
- }
-
- /// <summary>
- /// Removes part of the solution in the container.
- /// </summary>
- /// <param name="targetUid"></param>
- /// <param name="solutionHolder"></param>
- /// <param name="quantity">the volume of solution to remove.</param>
- /// <returns>The solution that was removed.</returns>
- public Solution SplitSolution(Entity<SolutionComponent> soln, FixedPoint2 quantity)
- {
- var (uid, comp) = soln;
- var solution = comp.Solution;
-
- var splitSol = solution.SplitSolution(quantity);
- UpdateChemicals(soln);
- return splitSol;
- }
-
- public Solution SplitStackSolution(Entity<SolutionComponent> soln, FixedPoint2 quantity, int stackCount)
- {
- var (uid, comp) = soln;
- var solution = comp.Solution;
-
- var splitSol = solution.SplitSolution(quantity / stackCount);
- solution.SplitSolution(quantity - splitSol.Volume);
- UpdateChemicals(soln);
- return splitSol;
- }
-
- /// <summary>
- /// Splits a solution without the specified reagent(s).
- /// </summary>
- public Solution SplitSolutionWithout(Entity<SolutionComponent> soln, FixedPoint2 quantity, params string[] reagents)
- {
- var (uid, comp) = soln;
- var solution = comp.Solution;
-
- var splitSol = solution.SplitSolutionWithout(quantity, reagents);
- UpdateChemicals(soln);
- return splitSol;
- }
-
- public void RemoveAllSolution(Entity<SolutionComponent> soln)
- {
- var (uid, comp) = soln;
- var solution = comp.Solution;
-
- if (solution.Volume == 0)
- return;
-
- solution.RemoveAllSolution();
- UpdateChemicals(soln);
- }
-
- /// <summary>
- /// Sets the capacity (maximum volume) of a solution to a new value.
- /// </summary>
- /// <param name="targetUid">The entity containing the solution.</param>
- /// <param name="targetSolution">The solution to set the capacity of.</param>
- /// <param name="capacity">The value to set the capacity of the solution to.</param>
- public void SetCapacity(Entity<SolutionComponent> soln, FixedPoint2 capacity)
- {
- var (uid, comp) = soln;
- var solution = comp.Solution;
-
- if (solution.MaxVolume == capacity)
- return;
-
- solution.MaxVolume = capacity;
- UpdateChemicals(soln);
- }
-
- /// <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="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(Entity<SolutionComponent> soln, ReagentQuantity reagentQuantity, out FixedPoint2 acceptedQuantity, float? temperature = null)
- {
- var (uid, comp) = soln;
- var solution = comp.Solution;
-
- acceptedQuantity = solution.AvailableVolume > reagentQuantity.Quantity
- ? reagentQuantity.Quantity
- : solution.AvailableVolume;
-
- if (acceptedQuantity <= 0)
- return reagentQuantity.Quantity == 0;
-
- if (temperature == null)
- {
- solution.AddReagent(reagentQuantity.Reagent, acceptedQuantity);
- }
- else
- {
- var proto = PrototypeManager.Index<ReagentPrototype>(reagentQuantity.Reagent.Prototype);
- solution.AddReagent(proto, acceptedQuantity, temperature.Value, PrototypeManager);
- }
-
- UpdateChemicals(soln);
- 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>
- /// <returns>If all the reagent could be added.</returns>
- [PublicAPI]
- public bool TryAddReagent(Entity<SolutionComponent> soln, string prototype, FixedPoint2 quantity, float? temperature = null, ReagentData? data = null)
- => TryAddReagent(soln, new ReagentQuantity(prototype, quantity, data), out _, temperature);
-
- /// <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="acceptedQuantity">The amount of reagent successfully added.</param>
- /// <returns>If all the reagent could be added.</returns>
- public bool TryAddReagent(Entity<SolutionComponent> soln, string prototype, FixedPoint2 quantity, out FixedPoint2 acceptedQuantity, float? temperature = null, ReagentData? data = null)
- {
- var reagent = new ReagentQuantity(prototype, quantity, data);
- return TryAddReagent(soln, reagent, out acceptedQuantity, temperature);
- }
-
- /// <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(Entity<SolutionComponent> soln, ReagentId reagentId, FixedPoint2 quantity, out FixedPoint2 acceptedQuantity, float? temperature = null)
- {
- var quant = new ReagentQuantity(reagentId, quantity);
- return TryAddReagent(soln, quant, out acceptedQuantity, temperature);
- }
-
- /// <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="reagentQuantity">The reagent to remove.</param>
- /// <returns>If the reagent to remove was found in the container.</returns>
- public bool RemoveReagent(Entity<SolutionComponent> soln, ReagentQuantity reagentQuantity)
- {
- var (uid, comp) = soln;
- var solution = comp.Solution;
-
- var quant = solution.RemoveReagent(reagentQuantity);
- if (quant <= FixedPoint2.Zero)
- return false;
-
- UpdateChemicals(soln);
- 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(Entity<SolutionComponent> soln, string prototype, FixedPoint2 quantity, ReagentData? data = null)
- {
- return RemoveReagent(soln, 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(Entity<SolutionComponent> soln, ReagentId reagentId, FixedPoint2 quantity)
- {
- return RemoveReagent(soln, new ReagentQuantity(reagentId, quantity));
- }
-
- /// <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(Entity<SolutionComponent> soln, Solution source, FixedPoint2 quantity)
- {
- var (uid, comp) = soln;
- var solution = comp.Solution;
-
- if (quantity < 0)
- throw new InvalidOperationException("Quantity must be positive");
-
- quantity = FixedPoint2.Min(quantity, solution.AvailableVolume, source.Volume);
- if (quantity == 0)
- return false;
-
- // TODO This should be made into a function that directly transfers reagents.
- // Currently this is quite inefficient.
- solution.AddSolution(source.SplitSolution(quantity), PrototypeManager);
-
- UpdateChemicals(soln);
- return true;
- }
-
- /// <summary>
- /// Adds a solution to the container, if it can fully fit.
- /// </summary>
- /// <param name="targetUid">entity holding targetSolution</param>
- /// <param name="targetSolution">entity holding targetSolution</param>
- /// <param name="toAdd">solution being added</param>
- /// <returns>If the solution could be added.</returns>
- public bool TryAddSolution(Entity<SolutionComponent> soln, Solution toAdd)
- {
- var (uid, comp) = soln;
- var solution = comp.Solution;
-
- if (toAdd.Volume == FixedPoint2.Zero)
- return true;
- if (toAdd.Volume > solution.AvailableVolume)
- return false;
-
- ForceAddSolution(soln, toAdd);
- return true;
- }
-
- /// <summary>
- /// Adds as much of a solution to a container as can fit.
- /// </summary>
- /// <param name="targetUid">The entity containing <paramref cref="targetSolution"/></param>
- /// <param name="targetSolution">The solution being added to.</param>
- /// <param name="toAdd">The solution being added to <paramref cref="targetSolution"/></param>
- /// <returns>The quantity of the solution actually added.</returns>
- public FixedPoint2 AddSolution(Entity<SolutionComponent> soln, Solution toAdd)
- {
- var (uid, comp) = soln;
- var solution = comp.Solution;
-
- if (toAdd.Volume == FixedPoint2.Zero)
- return FixedPoint2.Zero;
-
- var quantity = FixedPoint2.Max(FixedPoint2.Zero, FixedPoint2.Min(toAdd.Volume, solution.AvailableVolume));
- if (quantity < toAdd.Volume)
- TryTransferSolution(soln, toAdd, quantity);
- else
- ForceAddSolution(soln, toAdd);
-
- return quantity;
- }
-
- /// <summary>
- /// Adds a solution to a container and updates the container.
- /// </summary>
- /// <param name="targetUid">The entity containing <paramref cref="targetSolution"/></param>
- /// <param name="targetSolution">The solution being added to.</param>
- /// <param name="toAdd">The solution being added to <paramref cref="targetSolution"/></param>
- /// <returns>Whether any reagents were added to the solution.</returns>
- public bool ForceAddSolution(Entity<SolutionComponent> soln, Solution toAdd)
- {
- var (uid, comp) = soln;
- var solution = comp.Solution;
-
- if (toAdd.Volume == FixedPoint2.Zero)
- return false;
-
- solution.AddSolution(toAdd, PrototypeManager);
- UpdateChemicals(soln);
- return true;
- }
-
- /// <summary>
- /// Adds a solution to the container, removing the overflow.
- /// Unlike <see cref="TryAddSolution"/> it will ignore size limits.
- /// </summary>
- /// <param name="targetUid">The entity containing <paramref cref="targetSolution"/></param>
- /// <param name="targetSolution">The solution being added to.</param>
- /// <param name="toAdd">The solution being added to <paramref cref="targetSolution"/></param>
- /// <param name="overflowThreshold">The combined volume above which the overflow will be returned.
- /// If the combined volume is below this an empty solution is returned.</param>
- /// <param name="overflowingSolution">Solution that exceeded overflowThreshold</param>
- /// <returns>Whether any reagents were added to <paramref cref="targetSolution"/>.</returns>
- public bool TryMixAndOverflow(Entity<SolutionComponent> soln, Solution toAdd, FixedPoint2 overflowThreshold, [MaybeNullWhen(false)] out Solution overflowingSolution)
- {
- var (uid, comp) = soln;
- var solution = comp.Solution;
-
- if (toAdd.Volume == 0 || overflowThreshold > solution.MaxVolume)
- {
- overflowingSolution = null;
- return false;
- }
-
- solution.AddSolution(toAdd, PrototypeManager);
- overflowingSolution = solution.SplitSolution(FixedPoint2.Max(FixedPoint2.Zero, solution.Volume - overflowThreshold));
- UpdateChemicals(soln);
- return true;
- }
-
- /// <summary>
- /// Removes an amount from all reagents in a solution, adding it to a new solution.
- /// </summary>
- /// <param name="uid">The entity containing the solution.</param>
- /// <param name="solution">The solution to remove reagents from.</param>
- /// <param name="quantity">The amount to remove from every reagent in the solution.</param>
- /// <returns>A new solution containing every removed reagent from the original solution.</returns>
- public Solution RemoveEachReagent(Entity<SolutionComponent> soln, FixedPoint2 quantity)
- {
- var (uid, comp) = soln;
- var solution = comp.Solution;
-
- if (quantity <= 0)
- return new Solution();
-
- var removedSolution = new Solution();
-
- // 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--)
- {
- var (reagent, _) = solution.Contents[i];
- var removedQuantity = solution.RemoveReagent(reagent, quantity);
- removedSolution.AddReagent(reagent, removedQuantity);
- }
-
- UpdateChemicals(soln);
- return removedSolution;
- }
-
- // Thermal energy and temperature management.
-
- #region Thermal Energy and Temperature
-
- /// <summary>
- /// Sets the temperature of a solution to a new value and then checks for reaction processing.
- /// </summary>
- /// <param name="owner">The entity in which the solution is located.</param>
- /// <param name="solution">The solution to set the temperature of.</param>
- /// <param name="temperature">The new value to set the temperature to.</param>
- public void SetTemperature(Entity<SolutionComponent> soln, float temperature)
- {
- var (_, comp) = soln;
- var solution = comp.Solution;
-
- if (temperature == solution.Temperature)
- return;
-
- solution.Temperature = temperature;
- UpdateChemicals(soln);
- }
-
- /// <summary>
- /// Sets the thermal energy of a solution to a new value and then checks for reaction processing.
- /// </summary>
- /// <param name="owner">The entity in which the solution is located.</param>
- /// <param name="solution">The solution to set the thermal energy of.</param>
- /// <param name="thermalEnergy">The new value to set the thermal energy to.</param>
- public void SetThermalEnergy(Entity<SolutionComponent> soln, float thermalEnergy)
- {
- var (_, comp) = soln;
- var solution = comp.Solution;
-
- var heatCap = solution.GetHeatCapacity(PrototypeManager);
- solution.Temperature = heatCap == 0 ? 0 : thermalEnergy / heatCap;
- UpdateChemicals(soln);
- }
-
- /// <summary>
- /// Adds some thermal energy to a solution and then checks for reaction processing.
- /// </summary>
- /// <param name="owner">The entity in which the solution is located.</param>
- /// <param name="solution">The solution to set the thermal energy of.</param>
- /// <param name="thermalEnergy">The new value to set the thermal energy to.</param>
- public void AddThermalEnergy(Entity<SolutionComponent> soln, float thermalEnergy)
- {
- var (_, comp) = soln;
- var solution = comp.Solution;
-
- if (thermalEnergy == 0.0f)
- return;
-
- var heatCap = solution.GetHeatCapacity(PrototypeManager);
- solution.Temperature += heatCap == 0 ? 0 : thermalEnergy / heatCap;
- UpdateChemicals(soln);
- }
-
- #endregion Thermal Energy and Temperature
-
- #region Event Handlers
-
- private void OnComponentInit(Entity<SolutionComponent> entity, ref ComponentInit args)
- {
- entity.Comp.Solution.ValidateSolution();
- }
-
- private void OnComponentStartup(Entity<SolutionComponent> entity, ref ComponentStartup args)
- {
- UpdateChemicals(entity);
- }
-
- private void OnComponentShutdown(Entity<SolutionComponent> entity, ref ComponentShutdown args)
- {
- RemoveAllSolution(entity);
- }
-
- private void OnComponentInit(Entity<SolutionContainerManagerComponent> entity, ref ComponentInit args)
- {
- if (entity.Comp.Containers is not { Count: > 0 } containers)
- return;
-
- var containerManager = EnsureComp<ContainerManagerComponent>(entity);
- foreach (var name in containers)
- {
- // The actual solution entity should be directly held within the corresponding slot.
- ContainerSystem.EnsureContainer<ContainerSlot>(entity.Owner, $"solution@{name}", containerManager);
- }
- }
-
- private void OnExamineSolution(Entity<ExaminableSolutionComponent> entity, ref ExaminedEvent args)
- {
- if (!TryGetSolution(entity.Owner, entity.Comp.Solution, out _, out var solution))
- {
- return;
- }
-
- var primaryReagent = solution.GetPrimaryReagentId();
-
- if (string.IsNullOrEmpty(primaryReagent?.Prototype))
- {
- args.PushText(Loc.GetString("shared-solution-container-component-on-examine-empty-container"));
- return;
- }
-
- if (!PrototypeManager.TryIndex(primaryReagent.Value.Prototype, out ReagentPrototype? primary))
- {
- Log.Error($"{nameof(Solution)} could not find the prototype associated with {primaryReagent}.");
- return;
- }
-
- 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.
- var messageString = "shared-solution-container-component-on-examine-main-text";
-
- args.PushMarkup(Loc.GetString(messageString,
- ("color", colorHex),
- ("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-multiple-reagents")),
- ("desc", primary.LocalizedPhysicalDescription)));
-
- var reagentPrototypes = solution.GetReagentPrototypes(PrototypeManager);
-
- // Sort the reagents by amount, descending then alphabetically
- var sortedReagentPrototypes = reagentPrototypes
- .OrderByDescending(pair => pair.Value.Value)
- .ThenBy(pair => pair.Key.LocalizedName);
-
- // Add descriptions of immediately recognizable reagents, like water or beer
- var recognized = new List<ReagentPrototype>();
- foreach (var keyValuePair in sortedReagentPrototypes)
- {
- var proto = keyValuePair.Key;
- if (!proto.Recognizable)
- {
- continue;
- }
-
- recognized.Add(proto);
- }
-
- // Skip if there's nothing recognizable
- if (recognized.Count == 0)
- return;
-
- var msg = new StringBuilder();
- foreach (var reagent in recognized)
- {
- string part;
- if (reagent == recognized[0])
- {
- part = "examinable-solution-recognized-first";
- }
- else if (reagent == recognized[^1])
- {
- // this loc specifically requires space to be appended, fluent doesnt support whitespace
- msg.Append(' ');
- part = "examinable-solution-recognized-last";
- }
- else
- {
- part = "examinable-solution-recognized-next";
- }
-
- msg.Append(Loc.GetString(part, ("color", reagent.SubstanceColor.ToHexNoAlpha()),
- ("chemical", reagent.LocalizedName)));
- }
-
- args.PushMarkup(Loc.GetString("examinable-solution-has-recognizable-chemicals", ("recognizedString", msg.ToString())));
- }
-
- private void OnSolutionExaminableVerb(Entity<ExaminableSolutionComponent> entity, ref GetVerbsEvent<ExamineVerb> args)
- {
- if (!args.CanInteract || !args.CanAccess)
- return;
-
- var scanEvent = new SolutionScanEvent();
- RaiseLocalEvent(args.User, scanEvent);
- if (!scanEvent.CanScan)
- {
- return;
- }
-
- if (!TryGetSolution(args.Target, entity.Comp.Solution, out _, out var solutionHolder))
- {
- return;
- }
-
- var target = args.Target;
- var user = args.User;
- var verb = new ExamineVerb()
- {
- Act = () =>
- {
- var markup = GetSolutionExamine(solutionHolder);
- ExamineSystem.SendExamineTooltip(user, target, markup, false, false);
- },
- Text = Loc.GetString("scannable-solution-verb-text"),
- Message = Loc.GetString("scannable-solution-verb-message"),
- Category = VerbCategory.Examine,
- Icon = new SpriteSpecifier.Texture(new("/Textures/Interface/VerbIcons/drink.svg.192dpi.png")),
- };
-
- args.Verbs.Add(verb);
- }
-
- private FormattedMessage GetSolutionExamine(Solution solution)
- {
- var msg = new FormattedMessage();
-
- if (solution.Volume == 0)
- {
- msg.AddMarkup(Loc.GetString("scannable-solution-empty-container"));
- return msg;
- }
-
- msg.AddMarkup(Loc.GetString("scannable-solution-main-text"));
-
- var reagentPrototypes = solution.GetReagentPrototypes(PrototypeManager);
-
- // Sort the reagents by amount, descending then alphabetically
- var sortedReagentPrototypes = reagentPrototypes
- .OrderByDescending(pair => pair.Value.Value)
- .ThenBy(pair => pair.Key.LocalizedName);
-
- foreach (var (proto, quantity) in sortedReagentPrototypes)
- {
- msg.PushNewline();
- msg.AddMarkup(Loc.GetString("scannable-solution-chemical"
- , ("type", proto.LocalizedName)
- , ("color", proto.SubstanceColor.ToHexNoAlpha())
- , ("amount", quantity)));
- }
-
- return msg;
- }
-
- #endregion Event Handlers
-}
--- /dev/null
+using System.Diagnostics.CodeAnalysis;
+using System.Text;
+using Content.Shared.Chemistry.Components;
+using Content.Shared.Chemistry.Components.SolutionManager;
+using Content.Shared.FixedPoint;
+
+namespace Content.Shared.Chemistry.EntitySystems;
+
+public sealed partial class SolutionContainerSystem
+{
+ public void Refill(EntityUid targetUid, Solution targetSolution, Solution addedSolution,
+ RefillableSolutionComponent? refillableSolution = null)
+ {
+ if (!Resolve(targetUid, ref refillableSolution, false))
+ return;
+
+ TryAddSolution(targetUid, targetSolution, addedSolution);
+ }
+
+ public void Inject(EntityUid targetUid, Solution targetSolution, Solution addedSolution,
+ InjectableSolutionComponent? injectableSolution = null)
+ {
+ if (!Resolve(targetUid, ref injectableSolution, false))
+ return;
+
+ TryAddSolution(targetUid, targetSolution, addedSolution);
+ }
+
+ public Solution Draw(EntityUid targetUid, Solution solution, FixedPoint2 amount,
+ DrawableSolutionComponent? drawableSolution = null)
+ {
+ if (!Resolve(targetUid, ref drawableSolution, false))
+ return new Solution();
+
+ return SplitSolution(targetUid, solution, amount);
+ }
+
+ public Solution Drain(EntityUid targetUid, Solution targetSolution, FixedPoint2 amount,
+ DrainableSolutionComponent? drainableSolution = null)
+ {
+ if (!Resolve(targetUid, ref drainableSolution, false))
+ return new Solution();
+
+ return SplitSolution(targetUid, targetSolution, amount);
+ }
+
+ public bool TryGetInjectableSolution(EntityUid targetUid,
+ [NotNullWhen(true)] out Solution? solution,
+ InjectableSolutionComponent? injectable = null,
+ SolutionContainerManagerComponent? manager = null
+ )
+ {
+ if (!Resolve(targetUid, ref manager, ref injectable, false)
+ || !manager.Solutions.TryGetValue(injectable.Solution, out solution))
+ {
+ solution = null;
+ return false;
+ }
+
+ return true;
+ }
+
+ public bool TryGetRefillableSolution(EntityUid targetUid,
+ [NotNullWhen(true)] out Solution? solution,
+ SolutionContainerManagerComponent? solutionManager = null,
+ RefillableSolutionComponent? refillable = null)
+ {
+ if (!Resolve(targetUid, ref solutionManager, ref refillable, false)
+ || !solutionManager.Solutions.TryGetValue(refillable.Solution, out var refillableSolution))
+ {
+ solution = null;
+ return false;
+ }
+
+ solution = refillableSolution;
+ return true;
+ }
+
+ public bool TryGetDrainableSolution(EntityUid uid,
+ [NotNullWhen(true)] out Solution? solution,
+ DrainableSolutionComponent? drainable = null,
+ SolutionContainerManagerComponent? manager = null)
+ {
+ if (!Resolve(uid, ref drainable, ref manager, false)
+ || !manager.Solutions.TryGetValue(drainable.Solution, out solution))
+ {
+ solution = null;
+ return false;
+ }
+
+ return true;
+ }
+
+ public bool TryGetDumpableSolution(EntityUid uid,
+ [NotNullWhen(true)] out Solution? solution,
+ DumpableSolutionComponent? dumpable = null,
+ SolutionContainerManagerComponent? manager = null)
+ {
+ if (!Resolve(uid, ref dumpable, ref manager, false)
+ || !manager.Solutions.TryGetValue(dumpable.Solution, out solution))
+ {
+ solution = null;
+ return false;
+ }
+
+ return true;
+ }
+
+ public bool TryGetDrawableSolution(EntityUid uid,
+ [NotNullWhen(true)] out Solution? solution,
+ DrawableSolutionComponent? drawable = null,
+ SolutionContainerManagerComponent? manager = null)
+ {
+ if (!Resolve(uid, ref drawable, ref manager, false)
+ || !manager.Solutions.TryGetValue(drawable.Solution, out solution))
+ {
+ solution = null;
+ return false;
+ }
+
+ return true;
+ }
+
+ public FixedPoint2 DrainAvailable(EntityUid uid)
+ {
+ return !TryGetDrainableSolution(uid, out var solution)
+ ? FixedPoint2.Zero
+ : solution.Volume;
+ }
+
+ public float PercentFull(EntityUid uid)
+ {
+ if (!TryGetDrainableSolution(uid, out var solution) || solution.MaxVolume.Equals(FixedPoint2.Zero))
+ return 0;
+
+ return solution.FillFraction * 100;
+ }
+
+ public bool TryGetFitsInDispenser(EntityUid owner,
+ [NotNullWhen(true)] out Solution? solution,
+ FitsInDispenserComponent? dispenserFits = null,
+ SolutionContainerManagerComponent? solutionManager = null)
+ {
+ if (!Resolve(owner, ref dispenserFits, ref solutionManager, false)
+ || !solutionManager.Solutions.TryGetValue(dispenserFits.Solution, out solution))
+ {
+ solution = null;
+ return false;
+ }
+
+ return true;
+ }
+
+ public static string ToPrettyString(Solution solution)
+ {
+ var sb = new StringBuilder();
+ if (solution.Name == null)
+ sb.Append("[");
+ else
+ sb.Append($"{solution.Name}:[");
+ var first = true;
+ foreach (var (id, quantity) in solution.Contents)
+ {
+ if (first)
+ {
+ first = false;
+ }
+ else
+ {
+ sb.Append(", ");
+ }
+
+ sb.AppendFormat("{0}: {1}u", id, quantity);
+ }
+
+ sb.Append(']');
+ return sb.ToString();
+ }
+}
--- /dev/null
+using System.Diagnostics.CodeAnalysis;
+using System.Linq;
+using System.Text;
+using Content.Shared.Chemistry.Components;
+using Content.Shared.Chemistry.Components.SolutionManager;
+using Content.Shared.Chemistry.Reaction;
+using Content.Shared.Chemistry.Reagent;
+using Content.Shared.Examine;
+using Content.Shared.FixedPoint;
+using Content.Shared.Verbs;
+using JetBrains.Annotations;
+using Robust.Shared.Audio;
+using Robust.Shared.Prototypes;
+using Robust.Shared.Utility;
+
+namespace Content.Shared.Chemistry.EntitySystems;
+
+/// <summary>
+/// This event alerts system that the solution was changed
+/// </summary>
+public sealed class SolutionChangedEvent : EntityEventArgs
+{
+ public readonly Solution Solution;
+ public readonly string SolutionId;
+
+ public SolutionChangedEvent(Solution solution, string solutionId)
+ {
+ SolutionId = solutionId;
+ Solution = solution;
+ }
+}
+
+/// <summary>
+/// An event raised when more reagents are added to a (managed) solution than it can hold.
+/// </summary>
+[ByRefEvent]
+public record struct SolutionOverflowEvent(EntityUid SolutionEnt, Solution SolutionHolder, Solution Overflow)
+{
+ /// <summary>The entity which contains the solution that has overflowed.</summary>
+ public readonly EntityUid SolutionEnt = SolutionEnt;
+ /// <summary>The solution that has overflowed.</summary>
+ public readonly Solution SolutionHolder = SolutionHolder;
+ /// <summary>The reagents that have overflowed the solution.</summary>
+ public readonly Solution Overflow = Overflow;
+ /// <summary>The volume by which the solution has overflowed.</summary>
+ public readonly FixedPoint2 OverflowVol = Overflow.Volume;
+ /// <summary>Whether some subscriber has taken care of the effects of the overflow.</summary>
+ public bool Handled = false;
+}
+
+/// <summary>
+/// Part of Chemistry system deal with SolutionContainers
+/// </summary>
+[UsedImplicitly]
+public sealed partial class SolutionContainerSystem : EntitySystem
+{
+ [Dependency] private readonly ChemicalReactionSystem _chemistrySystem = default!;
+
+ [Dependency] private readonly SharedAppearanceSystem _appearance = default!;
+
+ [Dependency] private readonly IPrototypeManager _prototypeManager = default!;
+ [Dependency] private readonly ExamineSystemShared _examine = default!;
+
+ public override void Initialize()
+ {
+ base.Initialize();
+
+ SubscribeLocalEvent<SolutionContainerManagerComponent, ComponentInit>(InitSolution);
+ SubscribeLocalEvent<ExaminableSolutionComponent, ExaminedEvent>(OnExamineSolution);
+ SubscribeLocalEvent<ExaminableSolutionComponent, GetVerbsEvent<ExamineVerb>>(OnSolutionExaminableVerb);
+ }
+
+ private void InitSolution(EntityUid uid, SolutionContainerManagerComponent component, ComponentInit args)
+ {
+ foreach (var (name, solutionHolder) in component.Solutions)
+ {
+ solutionHolder.Name = name;
+ solutionHolder.ValidateSolution();
+ UpdateAppearance(uid, solutionHolder);
+ }
+ }
+
+ private void OnSolutionExaminableVerb(EntityUid uid, ExaminableSolutionComponent component, GetVerbsEvent<ExamineVerb> args)
+ {
+ if (!args.CanInteract || !args.CanAccess)
+ return;
+
+ var scanEvent = new SolutionScanEvent();
+ RaiseLocalEvent(args.User, scanEvent);
+ if (!scanEvent.CanScan)
+ {
+ return;
+ }
+
+ SolutionContainerManagerComponent? solutionsManager = null;
+ if (!Resolve(args.Target, ref solutionsManager)
+ || !solutionsManager.Solutions.TryGetValue(component.Solution, out var solutionHolder))
+ {
+ return;
+ }
+
+ var verb = new ExamineVerb()
+ {
+ Act = () =>
+ {
+ var markup = GetSolutionExamine(solutionHolder);
+ _examine.SendExamineTooltip(args.User, uid, markup, false, false);
+ },
+ Text = Loc.GetString("scannable-solution-verb-text"),
+ Message = Loc.GetString("scannable-solution-verb-message"),
+ Category = VerbCategory.Examine,
+ Icon = new SpriteSpecifier.Texture(new("/Textures/Interface/VerbIcons/drink.svg.192dpi.png")),
+ };
+
+ args.Verbs.Add(verb);
+ }
+
+ private FormattedMessage GetSolutionExamine(Solution solution)
+ {
+ var msg = new FormattedMessage();
+
+ if (solution.Volume == 0)
+ {
+ msg.AddMarkup(Loc.GetString("scannable-solution-empty-container"));
+ return msg;
+ }
+
+ msg.AddMarkup(Loc.GetString("scannable-solution-main-text"));
+
+ foreach (var (proto, quantity) in solution.GetReagentPrototypes(_prototypeManager))
+ {
+ msg.PushNewline();
+ msg.AddMarkup(Loc.GetString("scannable-solution-chemical"
+ , ("type", proto.LocalizedName)
+ , ("color", proto.SubstanceColor.ToHexNoAlpha())
+ , ("amount", quantity)));
+ }
+
+ return msg;
+ }
+
+ private void OnExamineSolution(EntityUid uid, ExaminableSolutionComponent examinableComponent,
+ ExaminedEvent args)
+ {
+ SolutionContainerManagerComponent? solutionsManager = null;
+ if (!Resolve(args.Examined, ref solutionsManager)
+ || !solutionsManager.Solutions.TryGetValue(examinableComponent.Solution, out var solution))
+ {
+ return;
+ }
+
+ var primaryReagent = solution.GetPrimaryReagentId();
+
+ if (string.IsNullOrEmpty(primaryReagent?.Prototype))
+ {
+ args.PushText(Loc.GetString("shared-solution-container-component-on-examine-empty-container"));
+ return;
+ }
+
+ if (!_prototypeManager.TryIndex(primaryReagent.Value.Prototype, out ReagentPrototype? primary))
+ {
+ Log.Error($"{nameof(Solution)} could not find the prototype associated with {primaryReagent}.");
+ return;
+ }
+
+ 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.
+ var messageString = "shared-solution-container-component-on-examine-main-text";
+
+ args.PushMarkup(Loc.GetString(messageString,
+ ("color", colorHex),
+ ("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-multiple-reagents")),
+ ("desc", primary.LocalizedPhysicalDescription)));
+
+
+ var reagentPrototypes = solution.GetReagentPrototypes(_prototypeManager);
+
+ // Sort the reagents by amount, descending then alphabetically
+ var sortedReagentPrototypes = reagentPrototypes
+ .OrderByDescending(pair => pair.Value.Value)
+ .ThenBy(pair => pair.Key.LocalizedName);
+
+ // Add descriptions of immediately recognizable reagents, like water or beer
+ var recognized = new List<ReagentPrototype>();
+ foreach (var keyValuePair in sortedReagentPrototypes)
+ {
+ var proto = keyValuePair.Key;
+ if (!proto.Recognizable)
+ {
+ continue;
+ }
+
+ recognized.Add(proto);
+ }
+
+ // Skip if there's nothing recognizable
+ if (recognized.Count == 0)
+ return;
+
+ var msg = new StringBuilder();
+ foreach (var reagent in recognized)
+ {
+ string part;
+ if (reagent == recognized[0])
+ {
+ part = "examinable-solution-recognized-first";
+ }
+ else if (reagent == recognized[^1])
+ {
+ // this loc specifically requires space to be appended, fluent doesnt support whitespace
+ msg.Append(' ');
+ part = "examinable-solution-recognized-last";
+ }
+ else
+ {
+ part = "examinable-solution-recognized-next";
+ }
+
+ msg.Append(Loc.GetString(part, ("color", reagent.SubstanceColor.ToHexNoAlpha()),
+ ("chemical", reagent.LocalizedName)));
+ }
+
+ args.PushMarkup(Loc.GetString("examinable-solution-has-recognizable-chemicals", ("recognizedString", msg.ToString())));
+ }
+
+ public void UpdateAppearance(EntityUid uid, Solution solution,
+ AppearanceComponent? appearanceComponent = null)
+ {
+ if (!HasComp<SolutionContainerVisualsComponent>(uid) || !Resolve(uid, ref appearanceComponent, false))
+ return;
+
+ _appearance.SetData(uid, SolutionContainerVisuals.FillFraction, solution.FillFraction, appearanceComponent);
+ _appearance.SetData(uid, SolutionContainerVisuals.Color, solution.GetColor(_prototypeManager), appearanceComponent);
+ if (solution.Name != null)
+ {
+ _appearance.SetData(uid, SolutionContainerVisuals.SolutionName, solution.Name, appearanceComponent);
+ }
+
+ if (solution.GetPrimaryReagentId() is { } reagent)
+ {
+ _appearance.SetData(uid, SolutionContainerVisuals.BaseOverride, reagent.ToString(), appearanceComponent);
+ }
+ else
+ {
+ _appearance.SetData(uid, SolutionContainerVisuals.BaseOverride, string.Empty, appearanceComponent);
+ }
+ }
+
+ /// <summary>
+ /// Removes part of the solution in the container.
+ /// </summary>
+ /// <param name="targetUid"></param>
+ /// <param name="solutionHolder"></param>
+ /// <param name="quantity">the volume of solution to remove.</param>
+ /// <returns>The solution that was removed.</returns>
+ public Solution SplitSolution(EntityUid targetUid, Solution solutionHolder, FixedPoint2 quantity)
+ {
+ var splitSol = solutionHolder.SplitSolution(quantity);
+ UpdateChemicals(targetUid, solutionHolder);
+ return splitSol;
+ }
+
+ public Solution SplitStackSolution(EntityUid targetUid, Solution solutionHolder, FixedPoint2 quantity, int stackCount)
+ {
+ var splitSol = solutionHolder.SplitSolution(quantity / stackCount);
+ solutionHolder.SplitSolution(quantity - splitSol.Volume);
+ UpdateChemicals(targetUid, solutionHolder);
+ return splitSol;
+ }
+
+ /// <summary>
+ /// Splits a solution without the specified reagent(s).
+ /// </summary>
+ public Solution SplitSolutionWithout(EntityUid targetUid, Solution solutionHolder, FixedPoint2 quantity,
+ params string[] reagents)
+ {
+ var splitSol = solutionHolder.SplitSolutionWithout(quantity, reagents);
+ UpdateChemicals(targetUid, solutionHolder);
+ return splitSol;
+ }
+
+ public void UpdateChemicals(EntityUid uid, Solution solutionHolder, bool needsReactionsProcessing = false, ReactionMixerComponent? mixerComponent = null)
+ {
+ DebugTools.Assert(solutionHolder.Name != null && TryGetSolution(uid, solutionHolder.Name, out var tmp) && tmp == solutionHolder);
+
+ // Process reactions
+ if (needsReactionsProcessing && solutionHolder.CanReact)
+ {
+ _chemistrySystem.FullyReactSolution(solutionHolder, uid, solutionHolder.MaxVolume, mixerComponent);
+ }
+
+ var overflowVol = solutionHolder.Volume - solutionHolder.MaxVolume;
+ if (overflowVol > FixedPoint2.Zero)
+ {
+ var overflow = solutionHolder.SplitSolution(overflowVol);
+ var overflowEv = new SolutionOverflowEvent(uid, solutionHolder, overflow);
+ RaiseLocalEvent(uid, ref overflowEv);
+ }
+
+ UpdateAppearance(uid, solutionHolder);
+ RaiseLocalEvent(uid, new SolutionChangedEvent(solutionHolder, solutionHolder.Name));
+ }
+
+ public void RemoveAllSolution(EntityUid uid, Solution solutionHolder)
+ {
+ if (solutionHolder.Volume == 0)
+ return;
+
+ solutionHolder.RemoveAllSolution();
+ UpdateChemicals(uid, solutionHolder);
+ }
+
+ public void RemoveAllSolution(EntityUid uid, SolutionContainerManagerComponent? solutionContainerManager = null)
+ {
+ if (!Resolve(uid, ref solutionContainerManager))
+ return;
+
+ foreach (var solution in solutionContainerManager.Solutions.Values)
+ {
+ RemoveAllSolution(uid, solution);
+ }
+ }
+
+ /// <summary>
+ /// Sets the capacity (maximum volume) of a solution to a new value.
+ /// </summary>
+ /// <param name="targetUid">The entity containing the solution.</param>
+ /// <param name="targetSolution">The solution to set the capacity of.</param>
+ /// <param name="capacity">The value to set the capacity of the solution to.</param>
+ public void SetCapacity(EntityUid targetUid, Solution targetSolution, FixedPoint2 capacity)
+ {
+ if (targetSolution.MaxVolume == capacity)
+ return;
+
+ targetSolution.MaxVolume = capacity;
+ if (capacity < targetSolution.Volume)
+ targetSolution.RemoveSolution(targetSolution.Volume - capacity);
+
+ UpdateChemicals(targetUid, targetSolution);
+ }
+
+ /// <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="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>
+ /// <returns>If all the reagent could be added.</returns>
+ [PublicAPI]
+ public bool TryAddReagent(EntityUid targetUid, Solution targetSolution, string prototype, FixedPoint2 quantity,
+ float? temperature = null, ReagentData? data = null)
+ {
+ var reagent = new ReagentQuantity(prototype, quantity, data);
+ return TryAddReagent(targetUid, targetSolution, reagent, out _, temperature);
+ }
+
+ /// <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="acceptedQuantity">The amount of reagent successfully added.</param>
+ /// <returns>If all the reagent could be added.</returns>
+ public bool TryAddReagent(EntityUid targetUid, Solution targetSolution, string prototype, FixedPoint2 quantity,
+ out FixedPoint2 acceptedQuantity, float? temperature = null, ReagentData? data = null)
+ {
+ var reagent = new ReagentQuantity(prototype, quantity, data);
+ return TryAddReagent(targetUid, targetSolution, reagent, out acceptedQuantity, temperature);
+ }
+
+ /// <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>
+ /// Removes reagent from a container.
+ /// </summary>
+ /// <param name="targetUid"></param>
+ /// <param name="container">Solution container from which we are removing reagent</param>
+ /// <param name="reagentQuantity">The reagent to remove.</param>
+ /// <returns>If the reagent to remove was found in the container.</returns>
+ public bool RemoveReagent(EntityUid targetUid, Solution? container, ReagentQuantity reagentQuantity)
+ {
+ if (container == null)
+ return false;
+
+ var quant = container.RemoveReagent(reagentQuantity);
+ if (quant <= FixedPoint2.Zero)
+ return false;
+
+ UpdateChemicals(targetUid, container);
+ 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>
+ /// 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 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)
+ throw new InvalidOperationException("Quantity must be positive");
+
+ quantity = FixedPoint2.Min(quantity, target.AvailableVolume, source.Volume);
+ if (quantity == 0)
+ return false;
+
+ // TODO This should be made into a function that directly transfers reagents.
+ // Currently this is quite inefficient.
+ target.AddSolution(source.SplitSolution(quantity), _prototypeManager);
+
+ UpdateChemicals(targetUid, target, true);
+ 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 sourceUid, EntityUid targetUid, string source, string target, FixedPoint2 quantity)
+ {
+ if (!TryGetSolution(sourceUid, source, out var sourceSoln))
+ return false;
+
+ if (!TryGetSolution(targetUid, target, out var targetSoln))
+ return false;
+
+ return TryTransferSolution(sourceUid, targetUid, sourceSoln, targetSoln, quantity);
+ }
+
+ /// <summary>
+ /// Adds a solution to the container, if it can fully fit.
+ /// </summary>
+ /// <param name="targetUid">entity holding targetSolution</param>
+ /// <param name="targetSolution">entity holding targetSolution</param>
+ /// <param name="toAdd">solution being added</param>
+ /// <returns>If the solution could be added.</returns>
+ public bool TryAddSolution(EntityUid targetUid, Solution targetSolution, Solution toAdd)
+ {
+ if (toAdd.Volume == FixedPoint2.Zero)
+ return true;
+ if (toAdd.Volume > targetSolution.AvailableVolume)
+ return false;
+
+ ForceAddSolution(targetUid, targetSolution, toAdd);
+ return true;
+ }
+
+ /// <summary>
+ /// Adds as much of a solution to a container as can fit.
+ /// </summary>
+ /// <param name="targetUid">The entity containing <paramref cref="targetSolution"/></param>
+ /// <param name="targetSolution">The solution being added to.</param>
+ /// <param name="toAdd">The solution being added to <paramref cref="targetSolution"/></param>
+ /// <returns>The quantity of the solution actually added.</returns>
+ public FixedPoint2 AddSolution(EntityUid targetUid, Solution targetSolution, Solution toAdd)
+ {
+ if (toAdd.Volume == FixedPoint2.Zero)
+ return FixedPoint2.Zero;
+
+ var quantity = FixedPoint2.Max(FixedPoint2.Zero, FixedPoint2.Min(toAdd.Volume, targetSolution.AvailableVolume));
+ if (quantity < toAdd.Volume)
+ TryTransferSolution(targetUid, targetSolution, toAdd, quantity);
+ else
+ ForceAddSolution(targetUid, targetSolution, toAdd);
+
+ return quantity;
+ }
+
+ /// <summary>
+ /// Adds a solution to a container and updates the container.
+ /// </summary>
+ /// <param name="targetUid">The entity containing <paramref cref="targetSolution"/></param>
+ /// <param name="targetSolution">The solution being added to.</param>
+ /// <param name="toAdd">The solution being added to <paramref cref="targetSolution"/></param>
+ /// <returns>Whether any reagents were added to the solution.</returns>
+ public bool ForceAddSolution(EntityUid targetUid, Solution targetSolution, Solution toAdd)
+ {
+ if (toAdd.Volume == FixedPoint2.Zero)
+ return false;
+
+ targetSolution.AddSolution(toAdd, _prototypeManager);
+ UpdateChemicals(targetUid, targetSolution, needsReactionsProcessing: true);
+ return true;
+ }
+
+ /// <summary>
+ /// Adds a solution to the container, removing the overflow.
+ /// Unlike <see cref="TryAddSolution"/> it will ignore size limits.
+ /// </summary>
+ /// <param name="targetUid">The entity containing <paramref cref="targetSolution"/></param>
+ /// <param name="targetSolution">The solution being added to.</param>
+ /// <param name="toAdd">The solution being added to <paramref cref="targetSolution"/></param>
+ /// <param name="overflowThreshold">The combined volume above which the overflow will be returned.
+ /// If the combined volume is below this an empty solution is returned.</param>
+ /// <param name="overflowingSolution">Solution that exceeded overflowThreshold</param>
+ /// <returns>Whether any reagents were added to <paramref cref="targetSolution"/>.</returns>
+ public bool TryMixAndOverflow(EntityUid targetUid, Solution targetSolution,
+ Solution toAdd,
+ FixedPoint2 overflowThreshold,
+ [NotNullWhen(true)] out Solution? overflowingSolution)
+ {
+ if (toAdd.Volume == 0 || overflowThreshold > targetSolution.MaxVolume)
+ {
+ overflowingSolution = null;
+ return false;
+ }
+
+ targetSolution.AddSolution(toAdd, _prototypeManager);
+ overflowingSolution = targetSolution.SplitSolution(FixedPoint2.Max(FixedPoint2.Zero, targetSolution.Volume - overflowThreshold));
+ UpdateChemicals(targetUid, targetSolution, true);
+ return true;
+ }
+
+ public bool TryGetSolution([NotNullWhen(true)] EntityUid? uid, string name,
+ [NotNullWhen(true)] out Solution? solution,
+ SolutionContainerManagerComponent? solutionsMgr = null)
+ {
+ if (uid == null || !Resolve(uid.Value, ref solutionsMgr, false))
+ {
+ solution = null;
+ return false;
+ }
+
+ return solutionsMgr.Solutions.TryGetValue(name, out solution);
+ }
+
+
+ /// <summary>
+ /// Will ensure a solution is added to given entity even if it's missing solutionContainerManager
+ /// </summary>
+ /// <param name="uid">EntityUid to which to add solution</param>
+ /// <param name="name">name for the solution</param>
+ /// <param name="solutionsMgr">solution components used in resolves</param>
+ /// <param name="existed">true if the solution already existed</param>
+ /// <returns>solution</returns>
+ public Solution EnsureSolution(EntityUid uid, string name, out bool existed,
+ SolutionContainerManagerComponent? solutionsMgr = null)
+ {
+ if (!Resolve(uid, ref solutionsMgr, false))
+ {
+ solutionsMgr = EntityManager.EnsureComponent<SolutionContainerManagerComponent>(uid);
+ }
+
+ if (!solutionsMgr.Solutions.TryGetValue(name, out var existing))
+ {
+ var newSolution = new Solution() { Name = name };
+ solutionsMgr.Solutions.Add(name, newSolution);
+ existed = false;
+ return newSolution;
+ }
+
+ existed = true;
+ return existing;
+ }
+
+ /// <summary>
+ /// Will ensure a solution is added to given entity even if it's missing solutionContainerManager
+ /// </summary>
+ /// <param name="uid">EntityUid to which to add solution</param>
+ /// <param name="name">name for the solution</param>
+ /// <param name="solutionsMgr">solution components used in resolves</param>
+ /// <returns>solution</returns>
+ public Solution EnsureSolution(EntityUid uid, string name, SolutionContainerManagerComponent? solutionsMgr = null)
+ => EnsureSolution(uid, name, out _, solutionsMgr);
+
+ /// <summary>
+ /// Will ensure a solution is added to given entity even if it's missing solutionContainerManager
+ /// </summary>
+ /// <param name="uid">EntityUid to which to add solution</param>
+ /// <param name="name">name for the solution</param>
+ /// <param name="minVol">Ensures that the solution's maximum volume is larger than this value.</param>
+ /// <param name="solutionsMgr">solution components used in resolves</param>
+ /// <returns>solution</returns>
+ public Solution EnsureSolution(EntityUid uid, string name, FixedPoint2 minVol, out bool existed,
+ SolutionContainerManagerComponent? solutionsMgr = null)
+ {
+ if (!Resolve(uid, ref solutionsMgr, false))
+ {
+ solutionsMgr = EntityManager.EnsureComponent<SolutionContainerManagerComponent>(uid);
+ }
+
+ if (!solutionsMgr.Solutions.TryGetValue(name, out var existing))
+ {
+ var newSolution = new Solution() { Name = name };
+ solutionsMgr.Solutions.Add(name, newSolution);
+ existed = false;
+ newSolution.MaxVolume = minVol;
+ return newSolution;
+ }
+
+ existed = true;
+ existing.MaxVolume = FixedPoint2.Max(existing.MaxVolume, minVol);
+ return existing;
+ }
+
+ public Solution EnsureSolution(EntityUid uid, string name,
+ IEnumerable<ReagentQuantity> reagents,
+ bool setMaxVol = true,
+ SolutionContainerManagerComponent? solutionsMgr = null)
+ {
+ if (!Resolve(uid, ref solutionsMgr, false))
+ solutionsMgr = EntityManager.EnsureComponent<SolutionContainerManagerComponent>(uid);
+
+ if (!solutionsMgr.Solutions.TryGetValue(name, out var existing))
+ {
+ var newSolution = new Solution(reagents, setMaxVol);
+ solutionsMgr.Solutions.Add(name, newSolution);
+ return newSolution;
+ }
+
+ existing.SetContents(reagents, setMaxVol);
+ return existing;
+ }
+ /// <summary>
+ /// Removes an amount from all reagents in a solution, adding it to a new solution.
+ /// </summary>
+ /// <param name="uid">The entity containing the solution.</param>
+ /// <param name="solution">The solution to remove reagents from.</param>
+ /// <param name="quantity">The amount to remove from every reagent in the solution.</param>
+ /// <returns>A new solution containing every removed reagent from the original solution.</returns>
+ public Solution RemoveEachReagent(EntityUid uid, Solution solution, FixedPoint2 quantity)
+ {
+ if (quantity <= 0)
+ return new Solution();
+
+ var removedSolution = new Solution();
+
+ // 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--)
+ {
+ var (reagent, _) = solution.Contents[i];
+ var removedQuantity = solution.RemoveReagent(reagent, quantity);
+ removedSolution.AddReagent(reagent, removedQuantity);
+ }
+
+ UpdateChemicals(uid, solution);
+ return removedSolution;
+ }
+
+ public FixedPoint2 GetTotalPrototypeQuantity(EntityUid owner, string reagentId)
+ {
+ var reagentQuantity = FixedPoint2.New(0);
+ if (EntityManager.EntityExists(owner)
+ && EntityManager.TryGetComponent(owner, out SolutionContainerManagerComponent? managerComponent))
+ {
+ foreach (var solution in managerComponent.Solutions.Values)
+ {
+ reagentQuantity += solution.GetTotalPrototypeQuantity(reagentId);
+ }
+ }
+
+ return reagentQuantity;
+ }
+
+ public bool TryGetMixableSolution(EntityUid uid,
+ [NotNullWhen(true)] out Solution? solution,
+ SolutionContainerManagerComponent? solutionsMgr = null)
+ {
+
+ if (!Resolve(uid, ref solutionsMgr, false))
+ {
+ solution = null;
+ return false;
+ }
+
+ var getMixableSolutionAttempt = new GetMixableSolutionAttemptEvent(uid);
+ RaiseLocalEvent(uid, ref getMixableSolutionAttempt);
+ if (getMixableSolutionAttempt.MixedSolution != null)
+ {
+ solution = getMixableSolutionAttempt.MixedSolution;
+ return true;
+ }
+
+ var tryGetSolution = solutionsMgr.Solutions.FirstOrNull(x => x.Value.CanMix);
+ if (tryGetSolution.HasValue)
+ {
+ solution = tryGetSolution.Value.Value;
+ return true;
+ }
+
+ solution = null;
+ return false;
+ }
+
+ /// <summary>
+ /// Gets the most common reagent across all solutions by volume.
+ /// </summary>
+ /// <param name="component"></param>
+ public ReagentPrototype? GetMaxReagent(SolutionContainerManagerComponent component)
+ {
+ if (component.Solutions.Count == 0)
+ return null;
+
+ var reagentCounts = new Dictionary<ReagentId, FixedPoint2>();
+
+ foreach (var solution in component.Solutions.Values)
+ {
+ foreach (var (reagent, quantity) in solution.Contents)
+ {
+ reagentCounts.TryGetValue(reagent, out var existing);
+ existing += quantity;
+ reagentCounts[reagent] = existing;
+ }
+ }
+
+ var max = reagentCounts.Max();
+
+ return _prototypeManager.Index<ReagentPrototype>(max.Key.Prototype);
+ }
+
+ public SoundSpecifier? GetSound(SolutionContainerManagerComponent component)
+ {
+ var max = GetMaxReagent(component);
+ return max?.FootstepSound;
+ }
+
+ // Thermal energy and temperature management.
+
+ #region Thermal Energy and Temperature
+
+ /// <summary>
+ /// Sets the temperature of a solution to a new value and then checks for reaction processing.
+ /// </summary>
+ /// <param name="owner">The entity in which the solution is located.</param>
+ /// <param name="solution">The solution to set the temperature of.</param>
+ /// <param name="temperature">The new value to set the temperature to.</param>
+ public void SetTemperature(EntityUid owner, Solution solution, float temperature)
+ {
+ if (temperature == solution.Temperature)
+ return;
+
+ solution.Temperature = temperature;
+ UpdateChemicals(owner, solution, true);
+ }
+
+ /// <summary>
+ /// Sets the thermal energy of a solution to a new value and then checks for reaction processing.
+ /// </summary>
+ /// <param name="owner">The entity in which the solution is located.</param>
+ /// <param name="solution">The solution to set the thermal energy of.</param>
+ /// <param name="thermalEnergy">The new value to set the thermal energy to.</param>
+ public void SetThermalEnergy(EntityUid owner, Solution solution, float thermalEnergy)
+ {
+ var heatCap = solution.GetHeatCapacity(_prototypeManager);
+ solution.Temperature = heatCap == 0 ? 0 : thermalEnergy / heatCap;
+ UpdateChemicals(owner, solution, true);
+ }
+
+ /// <summary>
+ /// Adds some thermal energy to a solution and then checks for reaction processing.
+ /// </summary>
+ /// <param name="owner">The entity in which the solution is located.</param>
+ /// <param name="solution">The solution to set the thermal energy of.</param>
+ /// <param name="thermalEnergy">The new value to set the thermal energy to.</param>
+ public void AddThermalEnergy(EntityUid owner, Solution solution, float thermalEnergy)
+ {
+ if (thermalEnergy == 0.0f)
+ return;
+
+ var heatCap = solution.GetHeatCapacity(_prototypeManager);
+ solution.Temperature += heatCap == 0 ? 0 : thermalEnergy / heatCap;
+ UpdateChemicals(owner, solution, true);
+ }
+
+ #endregion Thermal Energy and Temperature
+
+ #region Event Handlers
+
+ #endregion Event Handlers
+}
+using System.Collections.Frozen;
+using System.Linq;
using Content.Shared.Administration.Logs;
using Content.Shared.Chemistry.Components;
using Content.Shared.Chemistry.Reagent;
using Content.Shared.Database;
using Content.Shared.FixedPoint;
+using Robust.Shared.Audio;
using Robust.Shared.Audio.Systems;
using Robust.Shared.Prototypes;
using Robust.Shared.Utility;
-using System.Collections.Frozen;
-using System.Linq;
namespace Content.Shared.Chemistry.Reaction
{
{
// Construct single-reaction dictionary.
var dict = new Dictionary<string, List<ReactionPrototype>>();
- foreach (var reaction in _prototypeManager.EnumeratePrototypes<ReactionPrototype>())
+ foreach(var reaction in _prototypeManager.EnumeratePrototypes<ReactionPrototype>())
{
// For this dictionary we only need to cache based on the first reagent.
var reagent = reaction.Reactants.Keys.First();
_reactionsSingle = dict.ToFrozenDictionary();
dict.Clear();
- foreach (var reaction in _prototypeManager.EnumeratePrototypes<ReactionPrototype>())
+ foreach(var reaction in _prototypeManager.EnumeratePrototypes<ReactionPrototype>())
{
foreach (var reagent in reaction.Reactants.Keys)
{
/// <param name="reaction">The reaction to check.</param>
/// <param name="lowestUnitReactions">How many times this reaction can occur.</param>
/// <returns></returns>
- private bool CanReact(Entity<SolutionComponent> soln, ReactionPrototype reaction, ReactionMixerComponent? mixerComponent, out FixedPoint2 lowestUnitReactions)
+ private bool CanReact(Solution solution, ReactionPrototype reaction, EntityUid owner, ReactionMixerComponent? mixerComponent, out FixedPoint2 lowestUnitReactions)
{
- var solution = soln.Comp.Solution;
-
lowestUnitReactions = FixedPoint2.MaxValue;
if (solution.Temperature < reaction.MinimumTemperature)
{
return false;
}
- if ((mixerComponent == null && reaction.MixingCategories != null) ||
+ if((mixerComponent == null && reaction.MixingCategories != null) ||
mixerComponent != null && reaction.MixingCategories != null && reaction.MixingCategories.Except(mixerComponent.ReactionTypes).Any())
{
lowestUnitReactions = FixedPoint2.Zero;
return false;
}
- var attempt = new ReactionAttemptEvent(reaction, soln);
- RaiseLocalEvent(soln, ref attempt);
+ var attempt = new ReactionAttemptEvent(reaction, solution);
+ RaiseLocalEvent(owner, attempt);
if (attempt.Cancelled)
{
lowestUnitReactions = FixedPoint2.Zero;
/// Perform a reaction on a solution. This assumes all reaction criteria are met.
/// Removes the reactants from the solution, adds products, and returns a list of products.
/// </summary>
- private List<string> PerformReaction(Entity<SolutionComponent> soln, ReactionPrototype reaction, FixedPoint2 unitReactions)
+ private List<string> PerformReaction(Solution solution, EntityUid owner, ReactionPrototype reaction, FixedPoint2 unitReactions)
{
- var (uid, comp) = soln;
- var solution = comp.Solution;
-
var energy = reaction.ConserveEnergy ? solution.GetThermalEnergy(_prototypeManager) : 0;
//Remove reactants
solution.Temperature = energy / newCap;
}
- OnReaction(soln, reaction, null, unitReactions);
+ OnReaction(solution, reaction, null, owner, unitReactions);
return products;
}
- private void OnReaction(Entity<SolutionComponent> soln, ReactionPrototype reaction, ReagentPrototype? reagent, FixedPoint2 unitReactions)
+ private void OnReaction(Solution solution, ReactionPrototype reaction, ReagentPrototype? reagent, EntityUid owner, FixedPoint2 unitReactions)
{
- var args = new ReagentEffectArgs(soln, null, soln.Comp.Solution,
+ var args = new ReagentEffectArgs(owner, null, solution,
reagent,
unitReactions, EntityManager, null, 1f);
- var coordinates = Transform(soln).Coordinates;
+ var coordinates = Transform(owner).Coordinates;
_adminLogger.Add(LogType.ChemicalReaction, reaction.Impact,
- $"Chemical reaction {reaction.ID:reaction} occurred with strength {unitReactions:strength} on entity {ToPrettyString(soln):metabolizer} at {coordinates}");
+ $"Chemical reaction {reaction.ID:reaction} occurred with strength {unitReactions:strength} on entity {ToPrettyString(owner):metabolizer} at {coordinates}");
foreach (var effect in reaction.Effects)
{
effect.Effect(args);
}
- _audio.PlayPvs(reaction.Sound, soln);
+ _audio.PlayPvs(reaction.Sound, owner);
}
/// <summary>
/// Removes the reactants from the solution, then returns a solution with all products.
/// WARNING: Does not trigger reactions between solution and new products.
/// </summary>
- private bool ProcessReactions(Entity<SolutionComponent> soln, SortedSet<ReactionPrototype> reactions, ReactionMixerComponent? mixerComponent)
+ private bool ProcessReactions(Solution solution, EntityUid owner, FixedPoint2 maxVolume, SortedSet<ReactionPrototype> reactions, ReactionMixerComponent? mixerComponent)
{
HashSet<ReactionPrototype> toRemove = new();
List<string>? products = null;
// attempt to perform any applicable reaction
foreach (var reaction in reactions)
{
- if (!CanReact(soln, reaction, mixerComponent, out var unitReactions))
+ if (!CanReact(solution, reaction, owner, mixerComponent, out var unitReactions))
{
toRemove.Add(reaction);
continue;
}
- products = PerformReaction(soln, reaction, unitReactions);
+ products = PerformReaction(solution, owner, reaction, unitReactions);
break;
}
/// <summary>
/// Continually react a solution until no more reactions occur, with a volume constraint.
/// </summary>
- public void FullyReactSolution(Entity<SolutionComponent> soln, ReactionMixerComponent? mixerComponent = null)
+ public void FullyReactSolution(Solution solution, EntityUid owner, FixedPoint2 maxVolume, ReactionMixerComponent? mixerComponent = null)
{
// construct the initial set of reactions to check.
SortedSet<ReactionPrototype> reactions = new();
- foreach (var reactant in soln.Comp.Solution.Contents)
+ foreach (var reactant in solution.Contents)
{
if (_reactionsSingle.TryGetValue(reactant.Reagent.Prototype, out var reactantReactions))
reactions.UnionWith(reactantReactions);
// exceed the iteration limit.
for (var i = 0; i < MaxReactionIterations; i++)
{
- if (!ProcessReactions(soln, reactions, mixerComponent))
+ if (!ProcessReactions(solution, owner, maxVolume, reactions, mixerComponent))
return;
}
- Log.Error($"{nameof(Solution)} {soln.Owner} could not finish reacting in under {MaxReactionIterations} loops.");
+ Log.Error($"{nameof(Solution)} {owner} could not finish reacting in under {MaxReactionIterations} loops.");
}
}
/// <reamrks>
/// Some solution containers (e.g., bloodstream, smoke, foam) use this to block certain reactions from occurring.
/// </reamrks>
- [ByRefEvent]
- public record struct ReactionAttemptEvent(ReactionPrototype Reaction, Entity<SolutionComponent> Solution)
+ public sealed class ReactionAttemptEvent : CancellableEntityEventArgs
{
- public readonly ReactionPrototype Reaction = Reaction;
- public readonly Entity<SolutionComponent> Solution = Solution;
- public bool Cancelled = false;
+ public readonly ReactionPrototype Reaction;
+ public readonly Solution Solution;
+
+ public ReactionAttemptEvent(ReactionPrototype reaction, Solution solution)
+ {
+ Reaction = reaction;
+ Solution = solution;
+ }
}
}
public readonly record struct AfterMixingEvent(EntityUid Mixed, EntityUid Mixer);
[ByRefEvent]
-public record struct GetMixableSolutionAttemptEvent(EntityUid Mixed, Entity<SolutionComponent>? MixedSolution = null);
+public record struct GetMixableSolutionAttemptEvent(EntityUid Mixed, Solution? MixedSolution = null);
using Content.Shared.Chemistry.Reaction;
using Content.Shared.Chemistry.Reagent;
using Content.Shared.Database;
+using Content.Shared.FixedPoint;
using JetBrains.Annotations;
using Robust.Shared.Prototypes;
using Robust.Shared.Random;
+using Content.Shared.Chemistry.Components;
using Content.Shared.Chemistry.Reagent;
using Content.Shared.FixedPoint;
using Robust.Shared.Serialization;
-using Content.Shared.Chemistry.Components;
using Content.Shared.Tag;
using Robust.Shared.Audio;
[ValidatePrototypeId<TagPrototype>]
public const string PlungerTag = "Plunger";
- [DataField]
- public Entity<SolutionComponent>? Solution = null;
-
[DataField("accumulator")]
public float Accumulator = 0f;
-using Content.Shared.Chemistry.Components;
using Content.Shared.FixedPoint;
using Robust.Shared.Audio;
using Robust.Shared.GameStates;
public FixedPoint2 OverflowVolume = FixedPoint2.New(20);
[DataField("solution")] public string SolutionName = "puddle";
-
- [DataField("solutionRef")]
- public Entity<SolutionComponent>? Solution;
}
}
using Content.Shared.Chemistry.Components;
using Content.Shared.DragDrop;
+using Content.Shared.Fluids.Components;
namespace Content.Shared.Fluids;
SubscribeLocalEvent<RefillableSolutionComponent, CanDropDraggedEvent>(OnRefillableCanDropDragged);
}
- private void OnRefillableCanDrag(Entity<RefillableSolutionComponent> entity, ref CanDragEvent args)
+ private void OnRefillableCanDrag(EntityUid uid, RefillableSolutionComponent component, ref CanDragEvent args)
{
args.Handled = true;
}
- private void OnDumpCanDropTarget(Entity<DumpableSolutionComponent> entity, ref CanDropTargetEvent args)
+ private void OnDumpCanDropTarget(EntityUid uid, DumpableSolutionComponent component, ref CanDropTargetEvent args)
{
if (HasComp<DrainableSolutionComponent>(args.Dragged))
{
}
}
- private void OnDrainCanDropTarget(Entity<DrainableSolutionComponent> entity, ref CanDropTargetEvent args)
+ private void OnDrainCanDropTarget(EntityUid uid, DrainableSolutionComponent component, ref CanDropTargetEvent args)
{
if (HasComp<RefillableSolutionComponent>(args.Dragged))
{
}
}
- private void OnRefillableCanDropDragged(Entity<RefillableSolutionComponent> entity, ref CanDropDraggedEvent args)
+ private void OnRefillableCanDropDragged(EntityUid uid, RefillableSolutionComponent component, ref CanDropDraggedEvent args)
{
if (!HasComp<DrainableSolutionComponent>(args.Target) && !HasComp<DumpableSolutionComponent>(args.Target))
return;
+using Content.Shared.Chemistry.Components;
using Content.Shared.Chemistry.Reagent;
using Robust.Shared.Serialization;
+using Content.Shared.Chemistry.Components;
using Content.Shared.Chemistry.Reagent;
using Robust.Shared.Serialization;
-using Content.Shared.Construction.Prototypes;
+using Content.Shared.Chemistry.Components;
+using Content.Shared.Construction.Prototypes;
using Content.Shared.Whitelist;
using Robust.Shared.Audio;
using Robust.Shared.GameStates;
[DataField, ViewVariables(VVAccess.ReadWrite)]
public string SolutionContainerId = "output";
+ /// <summary>
+ /// The solution itself.
+ /// </summary>
+ [ViewVariables(VVAccess.ReadWrite)]
+ public Solution OutputSolution = default!;
+
/// <summary>
/// a whitelist for what entities can be inserted into this reclaimer
/// </summary>
-using Content.Shared.Chemistry.Components;
-using Content.Shared.DoAfter;
+using Content.Shared.DoAfter;
using Robust.Shared.Serialization;
+using Content.Shared.Chemistry.Components;
namespace Content.Shared.Nutrition;
public VapeDoAfterEvent(Solution solution, bool forced)
{
- Solution = solution;
- Forced = forced;
+ Solution = solution;
+ Forced = forced;
}
public override DoAfterEvent Clone() => this;
using Content.Shared.Chemistry.Components;
using Content.Shared.FixedPoint;
-using NUnit.Framework;
using Robust.Shared.IoC;
using Robust.Shared.Prototypes;
+using NUnit.Framework;
+using Robust.Shared.Utility;
namespace Content.Tests.Shared.Chemistry;