Solution refactor (#4407)
* Rename SolutionContainerCaps -> Capability * Move IExamine event to Chemistry System. * ECS the ISolutionChange into SolutionChangeEvent * Unify SolutionContainer into a single shared component * Replace ISolutionInteraction with SolutionContainerComponent * Move all methods from SolutionContainer to ChemistrySystem * Refactor EntitySystem calls to Dependencies * Refactor SolutionContainer to SolutionManager * Fix yamls * Fix test fails * Fix post merge issues * Fix various issues with SolutionManager * More fixes * Fix more components * Fix events not being directed * Fixes for Hypospray * Separate removal and iteration on Metabolism * Fix creampie problems * Address some of sloth's issues * Refactors for Systems * Refactored solution location * Fix tests * Address more sloth issues * Fix dependency * Fix merge conflicts * Add xmldocs for Capabilities components * Remove HasSolution/TryGetDefaultSolution and Add/Remove Drainable/Refillable * Replace Grindable/Juiceable with Extractable * Refactor field names * Fix Drainable * Fix some issues with spillable and injector * Fix issues with Grinder * Fix Beaker having duplicate solutions * Fix foaming * Address some MGS issues * Fix Uid issues * Fix errors in solution Tranfer * Fixed some extra values constant values * Cola is drinkable now
This commit is contained in:
@@ -6,10 +6,10 @@ using Content.Server.Items;
|
||||
using Content.Server.Power.Components;
|
||||
using Content.Server.UserInterface;
|
||||
using Content.Shared.ActionBlocker;
|
||||
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.Chemistry.Solution;
|
||||
using Content.Shared.Interaction;
|
||||
using Content.Shared.Notification.Managers;
|
||||
using Content.Shared.Random.Helpers;
|
||||
@@ -35,19 +35,31 @@ namespace Content.Server.Chemistry.Components
|
||||
[RegisterComponent]
|
||||
[ComponentReference(typeof(IActivate))]
|
||||
[ComponentReference(typeof(IInteractUsing))]
|
||||
public class ChemMasterComponent : SharedChemMasterComponent, IActivate, IInteractUsing, ISolutionChange
|
||||
public class ChemMasterComponent : SharedChemMasterComponent, IActivate, IInteractUsing
|
||||
{
|
||||
[ViewVariables] private ContainerSlot _beakerContainer = default!;
|
||||
[ViewVariables] private bool HasBeaker => _beakerContainer.ContainedEntity != null;
|
||||
[ViewVariables] private bool _bufferModeTransfer = true;
|
||||
[ViewVariables]
|
||||
private ContainerSlot _beakerContainer = default!;
|
||||
|
||||
[ViewVariables] private bool Powered => !Owner.TryGetComponent(out ApcPowerReceiverComponent? receiver) || receiver.Powered;
|
||||
[ViewVariables]
|
||||
private bool HasBeaker => _beakerContainer.ContainedEntity != null;
|
||||
|
||||
[ViewVariables] private readonly Solution BufferSolution = new();
|
||||
[ViewVariables]
|
||||
private bool _bufferModeTransfer = true;
|
||||
|
||||
[ViewVariables] private BoundUserInterface? UserInterface => Owner.GetUIOrNull(ChemMasterUiKey.Key);
|
||||
[ViewVariables]
|
||||
private bool Powered => !Owner.TryGetComponent(out ApcPowerReceiverComponent? receiver) || receiver.Powered;
|
||||
|
||||
[ViewVariables]
|
||||
private Solution BufferSolution => _bufferSolution ??= EntitySystem.Get<SolutionContainerSystem>().EnsureSolution(Owner, SolutionName);
|
||||
|
||||
private Solution? _bufferSolution;
|
||||
|
||||
[ViewVariables]
|
||||
private BoundUserInterface? UserInterface => Owner.GetUIOrNull(ChemMasterUiKey.Key);
|
||||
|
||||
[DataField("clickSound")]
|
||||
private SoundSpecifier _clickSound = new SoundPathSpecifier("/Audio/Machines/machine_switch.ogg");
|
||||
|
||||
[DataField("clickSound")] private SoundSpecifier _clickSound = new SoundPathSpecifier("/Audio/Machines/machine_switch.ogg");
|
||||
|
||||
/// <summary>
|
||||
/// Called once per instance of this component. Gets references to any other components needed
|
||||
@@ -65,8 +77,7 @@ namespace Content.Server.Chemistry.Components
|
||||
_beakerContainer =
|
||||
ContainerHelpers.EnsureContainer<ContainerSlot>(Owner, $"{Name}-reagentContainerContainer");
|
||||
|
||||
//BufferSolution = Owner.BufferSolution
|
||||
BufferSolution.RemoveAllSolution();
|
||||
_bufferSolution = EntitySystem.Get<SolutionContainerSystem>().EnsureSolution(Owner, SolutionName);
|
||||
|
||||
UpdateUserInterface();
|
||||
}
|
||||
@@ -76,13 +87,13 @@ namespace Content.Server.Chemistry.Components
|
||||
base.HandleMessage(message, component);
|
||||
switch (message)
|
||||
{
|
||||
case PowerChangedMessage powerChanged:
|
||||
OnPowerChanged(powerChanged);
|
||||
case PowerChangedMessage:
|
||||
OnPowerChanged();
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
private void OnPowerChanged(PowerChangedMessage e)
|
||||
private void OnPowerChanged()
|
||||
{
|
||||
UpdateUserInterface();
|
||||
}
|
||||
@@ -140,6 +151,7 @@ namespace Content.Server.Chemistry.Components
|
||||
/// Checks whether the player entity is able to use the chem master.
|
||||
/// </summary>
|
||||
/// <param name="playerEntity">The player entity.</param>
|
||||
/// <param name="needsPower">whether the device requires power</param>
|
||||
/// <returns>Returns true if the entity can use the chem master, and false if it cannot.</returns>
|
||||
private bool PlayerCanUseChemMaster(IEntity? playerEntity, bool needsPower = true)
|
||||
{
|
||||
@@ -166,25 +178,30 @@ namespace Content.Server.Chemistry.Components
|
||||
private ChemMasterBoundUserInterfaceState GetUserInterfaceState()
|
||||
{
|
||||
var beaker = _beakerContainer.ContainedEntity;
|
||||
if (beaker == null)
|
||||
EntitySystem.Get<SolutionContainerSystem>().TryGetSolution(beaker, SolutionName, out var beakerSolution);
|
||||
// TODO this is just a guess
|
||||
if (beaker == null || beakerSolution == null)
|
||||
{
|
||||
return new ChemMasterBoundUserInterfaceState(Powered, false, ReagentUnit.New(0), ReagentUnit.New(0),
|
||||
"", Owner.Name, new List<Solution.ReagentQuantity>(), BufferSolution.Contents, _bufferModeTransfer, BufferSolution.TotalVolume);
|
||||
"", Owner.Name, new List<Solution.ReagentQuantity>(), BufferSolution.Contents, _bufferModeTransfer,
|
||||
BufferSolution.TotalVolume);
|
||||
}
|
||||
|
||||
var solution = beaker.GetComponent<SolutionContainerComponent>();
|
||||
return new ChemMasterBoundUserInterfaceState(Powered, true, solution.CurrentVolume, solution.MaxVolume,
|
||||
beaker.Name, Owner.Name, solution.ReagentList, BufferSolution.Contents, _bufferModeTransfer, BufferSolution.TotalVolume);
|
||||
|
||||
return new ChemMasterBoundUserInterfaceState(Powered, true, beakerSolution.CurrentVolume,
|
||||
beakerSolution.MaxVolume,
|
||||
beaker.Name, Owner.Name, beakerSolution.Contents, BufferSolution.Contents, _bufferModeTransfer,
|
||||
BufferSolution.TotalVolume);
|
||||
}
|
||||
|
||||
private void UpdateUserInterface()
|
||||
public void UpdateUserInterface()
|
||||
{
|
||||
var state = GetUserInterfaceState();
|
||||
UserInterface?.SetState(state);
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// If this component contains an entity with a <see cref="SolutionContainerComponent"/>, eject it.
|
||||
/// If this component contains an entity with a <see cref="Solution"/>, eject it.
|
||||
/// Tries to eject into user's hands first, then ejects onto chem master if both hands are full.
|
||||
/// </summary>
|
||||
private void TryEject(IEntity user)
|
||||
@@ -194,13 +211,14 @@ namespace Content.Server.Chemistry.Components
|
||||
|
||||
var beaker = _beakerContainer.ContainedEntity;
|
||||
|
||||
if(beaker is null)
|
||||
if (beaker is null)
|
||||
return;
|
||||
|
||||
_beakerContainer.Remove(beaker);
|
||||
UpdateUserInterface();
|
||||
|
||||
if(!user.TryGetComponent<HandsComponent>(out var hands) || !beaker.TryGetComponent<ItemComponent>(out var item))
|
||||
if (!user.TryGetComponent<HandsComponent>(out var hands) ||
|
||||
!beaker.TryGetComponent<ItemComponent>(out var item))
|
||||
return;
|
||||
if (hands.CanPutInHand(item))
|
||||
hands.PutInHand(item);
|
||||
@@ -211,10 +229,12 @@ namespace Content.Server.Chemistry.Components
|
||||
if (!HasBeaker && _bufferModeTransfer) return;
|
||||
var beaker = _beakerContainer.ContainedEntity;
|
||||
|
||||
if(beaker is null)
|
||||
if (beaker is null)
|
||||
return;
|
||||
|
||||
if (!EntitySystem.Get<SolutionContainerSystem>().TryGetSolution(beaker, SolutionName, out var beakerSolution))
|
||||
return;
|
||||
|
||||
var beakerSolution = beaker.GetComponent<SolutionContainerComponent>();
|
||||
if (isBuffer)
|
||||
{
|
||||
foreach (var reagent in BufferSolution.Contents)
|
||||
@@ -222,30 +242,33 @@ namespace Content.Server.Chemistry.Components
|
||||
if (reagent.ReagentId == id)
|
||||
{
|
||||
ReagentUnit actualAmount;
|
||||
if (amount == ReagentUnit.New(-1)) //amount is ReagentUnit.New(-1) when the client sends a message requesting to remove all solution from the container
|
||||
if (
|
||||
amount == ReagentUnit
|
||||
.New(-1)) //amount is ReagentUnit.New(-1) when the client sends a message requesting to remove all solution from the container
|
||||
{
|
||||
actualAmount = ReagentUnit.Min(reagent.Quantity, beakerSolution.EmptyVolume);
|
||||
actualAmount = ReagentUnit.Min(reagent.Quantity, beakerSolution.AvailableVolume);
|
||||
}
|
||||
else
|
||||
{
|
||||
actualAmount = ReagentUnit.Min(reagent.Quantity, amount, beakerSolution.EmptyVolume);
|
||||
actualAmount = ReagentUnit.Min(reagent.Quantity, amount, beakerSolution.AvailableVolume);
|
||||
}
|
||||
|
||||
|
||||
BufferSolution.RemoveReagent(id, actualAmount);
|
||||
if (_bufferModeTransfer)
|
||||
{
|
||||
beakerSolution.TryAddReagent(id, actualAmount, out var _);
|
||||
EntitySystem.Get<SolutionContainerSystem>()
|
||||
.TryAddReagent(beaker.Uid, beakerSolution, id, actualAmount, out var _);
|
||||
// beakerSolution.Solution.AddReagent(id, actualAmount);
|
||||
}
|
||||
|
||||
break;
|
||||
}
|
||||
|
||||
}
|
||||
}
|
||||
else
|
||||
{
|
||||
foreach (var reagent in beakerSolution.Solution.Contents)
|
||||
foreach (var reagent in beakerSolution.Contents)
|
||||
{
|
||||
if (reagent.ReagentId == id)
|
||||
{
|
||||
@@ -258,7 +281,8 @@ namespace Content.Server.Chemistry.Components
|
||||
{
|
||||
actualAmount = ReagentUnit.Min(reagent.Quantity, amount);
|
||||
}
|
||||
beakerSolution.TryRemoveReagent(id, actualAmount);
|
||||
|
||||
EntitySystem.Get<SolutionContainerSystem>().TryRemoveReagent(beaker.Uid, beakerSolution, id, actualAmount);
|
||||
BufferSolution.AddReagent(id, actualAmount);
|
||||
break;
|
||||
}
|
||||
@@ -285,9 +309,9 @@ namespace Content.Server.Chemistry.Components
|
||||
var bottle = Owner.EntityManager.SpawnEntity("ChemistryEmptyBottle01", Owner.Transform.Coordinates);
|
||||
|
||||
var bufferSolution = BufferSolution.SplitSolution(actualVolume);
|
||||
var bottleSolution = EntitySystem.Get<SolutionContainerSystem>().EnsureSolution(bottle, "bottle");
|
||||
|
||||
bottle.TryGetComponent<SolutionContainerComponent>(out var bottleSolution);
|
||||
bottleSolution?.TryAddSolution(bufferSolution);
|
||||
EntitySystem.Get<SolutionContainerSystem>().TryAddSolution(bottle.Uid, bottleSolution, bufferSolution);
|
||||
|
||||
//Try to give them the bottle
|
||||
if (user.TryGetComponent<HandsComponent>(out var hands) &&
|
||||
@@ -305,7 +329,6 @@ namespace Content.Server.Chemistry.Components
|
||||
//Give it an offset
|
||||
bottle.RandomOffset(0.2f);
|
||||
}
|
||||
|
||||
}
|
||||
else //Pills
|
||||
{
|
||||
@@ -320,8 +343,8 @@ namespace Content.Server.Chemistry.Components
|
||||
|
||||
var bufferSolution = BufferSolution.SplitSolution(actualVolume);
|
||||
|
||||
pill.TryGetComponent<SolutionContainerComponent>(out var pillSolution);
|
||||
pillSolution?.TryAddSolution(bufferSolution);
|
||||
var pillSolution = EntitySystem.Get<SolutionContainerSystem>().EnsureSolution(pill, "pill");
|
||||
EntitySystem.Get<SolutionContainerSystem>().TryAddSolution(pill.Uid, pillSolution, bufferSolution);
|
||||
|
||||
//Try to give them the bottle
|
||||
if (user.TryGetComponent<HandsComponent>(out var hands) &&
|
||||
@@ -332,7 +355,6 @@ namespace Content.Server.Chemistry.Components
|
||||
hands.PutInHand(item);
|
||||
continue;
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
//Put it on the floor
|
||||
@@ -371,7 +393,7 @@ namespace Content.Server.Chemistry.Components
|
||||
|
||||
/// <summary>
|
||||
/// Called when you click the owner entity with something in your active hand. If the entity in your hand
|
||||
/// contains a <see cref="SolutionContainerComponent"/>, if you have hands, and if the chem master doesn't already
|
||||
/// contains a <see cref="Solution"/>, if you have hands, and if the chem master doesn't already
|
||||
/// hold a container, it will be added to the chem master.
|
||||
/// </summary>
|
||||
/// <param name="args">Data relevant to the event such as the actor which triggered it.</param>
|
||||
@@ -391,16 +413,18 @@ namespace Content.Server.Chemistry.Components
|
||||
}
|
||||
|
||||
var activeHandEntity = hands.GetActiveHand.Owner;
|
||||
if (activeHandEntity.TryGetComponent<SolutionContainerComponent>(out var solution))
|
||||
if (activeHandEntity.HasComponent<SolutionContainerManagerComponent>())
|
||||
{
|
||||
if (HasBeaker)
|
||||
{
|
||||
Owner.PopupMessage(args.User, Loc.GetString("chem-master-component-has-beaker-already-message"));
|
||||
}
|
||||
else if (!solution.CanUseWithChemDispenser)
|
||||
else if (!activeHandEntity.HasComponent<FitsInDispenserComponent>())
|
||||
{
|
||||
//If it can't fit in the chem master, don't put it in. For example, buckets and mop buckets can't fit.
|
||||
Owner.PopupMessage(args.User, Loc.GetString("chem-master-component-container-too-large-message",("container", activeHandEntity)));
|
||||
Owner.PopupMessage(args.User,
|
||||
Loc.GetString("chem-master-component-container-too-large-message",
|
||||
("container", activeHandEntity)));
|
||||
}
|
||||
else
|
||||
{
|
||||
@@ -410,14 +434,13 @@ namespace Content.Server.Chemistry.Components
|
||||
}
|
||||
else
|
||||
{
|
||||
Owner.PopupMessage(args.User, Loc.GetString("chem-master-component-cannot-put-entity-message", ("entity", activeHandEntity)));
|
||||
Owner.PopupMessage(args.User,
|
||||
Loc.GetString("chem-master-component-cannot-put-entity-message", ("entity", activeHandEntity)));
|
||||
}
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
void ISolutionChange.SolutionChanged(SolutionChangeEventArgs eventArgs) => UpdateUserInterface();
|
||||
|
||||
private void ClickSound()
|
||||
{
|
||||
SoundSystem.Play(Filter.Pvs(Owner), _clickSound.GetSound(), Owner, AudioParams.Default.WithVolume(-2f));
|
||||
@@ -446,6 +469,5 @@ namespace Content.Server.Chemistry.Components
|
||||
component.TryEject(user);
|
||||
}
|
||||
}
|
||||
|
||||
}
|
||||
}
|
||||
|
||||
@@ -1,6 +1,8 @@
|
||||
using Content.Server.Body.Circulatory;
|
||||
using Content.Server.Inventory.Components;
|
||||
using Content.Server.Items;
|
||||
using Content.Shared.Chemistry;
|
||||
using Content.Shared.Chemistry.EntitySystems;
|
||||
using Content.Shared.Chemistry.Reagent;
|
||||
using Content.Shared.Foam;
|
||||
using Content.Shared.Inventory;
|
||||
@@ -15,21 +17,22 @@ namespace Content.Server.Chemistry.Components
|
||||
public class FoamSolutionAreaEffectComponent : SolutionAreaEffectComponent
|
||||
{
|
||||
public override string Name => "FoamSolutionAreaEffect";
|
||||
public static string SolutionName = "foam";
|
||||
|
||||
[DataField("foamedMetalPrototype")] private string? _foamedMetalPrototype;
|
||||
|
||||
protected override void UpdateVisuals()
|
||||
{
|
||||
if (Owner.TryGetComponent(out AppearanceComponent? appearance) &&
|
||||
SolutionContainerComponent != null)
|
||||
EntitySystem.Get<SolutionContainerSystem>().TryGetSolution(Owner, SolutionName, out var solution))
|
||||
{
|
||||
appearance.SetData(FoamVisuals.Color, SolutionContainerComponent.Color.WithAlpha(0.80f));
|
||||
appearance.SetData(FoamVisuals.Color, solution.Color.WithAlpha(0.80f));
|
||||
}
|
||||
}
|
||||
|
||||
protected override void ReactWithEntity(IEntity entity, double solutionFraction)
|
||||
{
|
||||
if (SolutionContainerComponent == null)
|
||||
if (!EntitySystem.Get<SolutionContainerSystem>().TryGetSolution(Owner, SolutionName, out var solution))
|
||||
return;
|
||||
|
||||
if (!entity.TryGetComponent(out BloodstreamComponent? bloodstream))
|
||||
@@ -53,8 +56,9 @@ namespace Content.Server.Chemistry.Components
|
||||
}
|
||||
}
|
||||
|
||||
var cloneSolution = SolutionContainerComponent.Solution.Clone();
|
||||
var transferAmount = ReagentUnit.Min(cloneSolution.TotalVolume * solutionFraction * (1 - protection), bloodstream.EmptyVolume);
|
||||
var cloneSolution = solution.Clone();
|
||||
var transferAmount = ReagentUnit.Min(cloneSolution.TotalVolume * solutionFraction * (1 - protection),
|
||||
bloodstream.EmptyVolume);
|
||||
var transferSolution = cloneSolution.SplitSolution(transferAmount);
|
||||
|
||||
bloodstream.TryTransferSolution(transferSolution);
|
||||
@@ -68,12 +72,14 @@ namespace Content.Server.Chemistry.Components
|
||||
{
|
||||
appearance.SetData(FoamVisuals.State, true);
|
||||
}
|
||||
|
||||
Owner.SpawnTimer(600, () =>
|
||||
{
|
||||
if (!string.IsNullOrEmpty(_foamedMetalPrototype))
|
||||
{
|
||||
Owner.EntityManager.SpawnEntity(_foamedMetalPrototype, Owner.Transform.Coordinates);
|
||||
}
|
||||
|
||||
Owner.QueueDelete();
|
||||
});
|
||||
}
|
||||
|
||||
@@ -1,8 +1,8 @@
|
||||
using Content.Server.Interaction.Components;
|
||||
using Content.Server.MobState.States;
|
||||
using Content.Server.Weapon.Melee;
|
||||
using Content.Shared.Chemistry;
|
||||
using Content.Shared.Chemistry.Components;
|
||||
using Content.Shared.Chemistry.EntitySystems;
|
||||
using Content.Shared.Chemistry.Reagent;
|
||||
using Content.Shared.Notification.Managers;
|
||||
using Content.Shared.Sound;
|
||||
@@ -18,7 +18,7 @@ using Robust.Shared.ViewVariables;
|
||||
namespace Content.Server.Chemistry.Components
|
||||
{
|
||||
[RegisterComponent]
|
||||
public sealed class HyposprayComponent : SharedHyposprayComponent, ISolutionChange
|
||||
public sealed class HyposprayComponent : SharedHyposprayComponent
|
||||
{
|
||||
[DataField("ClumsyFailChance")]
|
||||
[ViewVariables(VVAccess.ReadWrite)]
|
||||
@@ -31,8 +31,6 @@ namespace Content.Server.Chemistry.Components
|
||||
[DataField("InjectSound")]
|
||||
private SoundSpecifier _injectSound = new SoundPathSpecifier("/Audio/Items/hypospray.ogg");
|
||||
|
||||
[ComponentDependency] private readonly SolutionContainerComponent? _solution = default!;
|
||||
|
||||
protected override void Initialize()
|
||||
{
|
||||
base.Initialize();
|
||||
@@ -57,13 +55,24 @@ namespace Content.Server.Chemistry.Components
|
||||
target = user;
|
||||
}
|
||||
|
||||
if (_solution == null || _solution.CurrentVolume == 0)
|
||||
var solutionsSys = EntitySystem.Get<SolutionContainerSystem>();
|
||||
solutionsSys.TryGetSolution(Owner, SolutionName, out var hypoSpraySolution);
|
||||
|
||||
if (hypoSpraySolution == null || hypoSpraySolution.CurrentVolume == 0)
|
||||
{
|
||||
user.PopupMessageCursor(Loc.GetString("hypospray-component-empty-message"));
|
||||
return true;
|
||||
}
|
||||
|
||||
user.PopupMessage(Loc.GetString(msgFormat ?? "hypospray-component-inject-other-message",("other", target)));
|
||||
if (!solutionsSys.TryGetInjectableSolution(target.Uid, out var targetSolution))
|
||||
{
|
||||
user.PopupMessage(user,
|
||||
Loc.GetString("hypospray-cant-inject", ("target", target)));
|
||||
return false;
|
||||
}
|
||||
|
||||
user.PopupMessage(Loc.GetString(msgFormat ?? "hypospray-component-inject-other-message",
|
||||
("other", target)));
|
||||
if (target != user)
|
||||
{
|
||||
target.PopupMessage(Loc.GetString("hypospray-component-feel-prick-message"));
|
||||
@@ -74,19 +83,21 @@ namespace Content.Server.Chemistry.Components
|
||||
|
||||
SoundSystem.Play(Filter.Pvs(user), _injectSound.GetSound(), user);
|
||||
|
||||
var targetSolution = target.GetComponent<SolutionContainerComponent>();
|
||||
|
||||
// Get transfer amount. May be smaller than _transferAmount if not enough room
|
||||
var realTransferAmount = ReagentUnit.Min(TransferAmount, targetSolution.EmptyVolume);
|
||||
var realTransferAmount = ReagentUnit.Min(TransferAmount, targetSolution.AvailableVolume);
|
||||
|
||||
if (realTransferAmount <= 0)
|
||||
{
|
||||
user.PopupMessage(user, Loc.GetString("hypospray-component-transfer-already-full-message ",("owner", targetSolution.Owner)));
|
||||
user.PopupMessage(user,
|
||||
Loc.GetString("hypospray-component-transfer-already-full-message",
|
||||
("owner", target)));
|
||||
return true;
|
||||
}
|
||||
|
||||
// Move units from attackSolution to targetSolution
|
||||
var removedSolution = _solution.SplitSolution(realTransferAmount);
|
||||
var removedSolution =
|
||||
EntitySystem.Get<SolutionContainerSystem>()
|
||||
.SplitSolution(Owner.Uid, hypoSpraySolution, realTransferAmount);
|
||||
|
||||
if (!targetSolution.CanAddSolution(removedSolution))
|
||||
{
|
||||
@@ -95,29 +106,26 @@ namespace Content.Server.Chemistry.Components
|
||||
|
||||
removedSolution.DoEntityReaction(target, ReactionMethod.Injection);
|
||||
|
||||
targetSolution.TryAddSolution(removedSolution);
|
||||
EntitySystem.Get<SolutionContainerSystem>().TryAddSolution(target.Uid, targetSolution, removedSolution);
|
||||
|
||||
static bool EligibleEntity(IEntity entity)
|
||||
{
|
||||
// TODO: Does checking for BodyComponent make sense as a "can be hypospray'd" tag?
|
||||
// In SS13 the hypospray ONLY works on mobs, NOT beakers or anything else.
|
||||
return entity.HasComponent<SolutionContainerComponent>() && entity.HasComponent<MobStateComponent>();
|
||||
|
||||
return entity.HasComponent<SharedChemMasterComponent>()
|
||||
&& entity.HasComponent<MobStateComponent>();
|
||||
}
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
void ISolutionChange.SolutionChanged(SolutionChangeEventArgs eventArgs)
|
||||
{
|
||||
Dirty();
|
||||
}
|
||||
|
||||
public override ComponentState GetComponentState(ICommonSession player)
|
||||
{
|
||||
if (_solution == null)
|
||||
return new HyposprayComponentState(ReagentUnit.Zero, ReagentUnit.Zero);
|
||||
|
||||
return new HyposprayComponentState(_solution.CurrentVolume, _solution.MaxVolume);
|
||||
var solutionSys = Owner.EntityManager.EntitySysManager.GetEntitySystem<SolutionContainerSystem>();
|
||||
return solutionSys.TryGetSolution(Owner, SolutionName, out var solution)
|
||||
? new HyposprayComponentState(solution.CurrentVolume, solution.MaxVolume)
|
||||
: new HyposprayComponentState(ReagentUnit.Zero, ReagentUnit.Zero);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@@ -1,10 +1,11 @@
|
||||
using System;
|
||||
using System.Threading.Tasks;
|
||||
using Content.Server.Body.Circulatory;
|
||||
using Content.Shared.Chemistry;
|
||||
using Content.Shared.Body.Networks;
|
||||
using Content.Shared.Chemistry.Components;
|
||||
using Content.Shared.Chemistry.Components.SolutionManager;
|
||||
using Content.Shared.Chemistry.EntitySystems;
|
||||
using Content.Shared.Chemistry.Reagent;
|
||||
using Content.Shared.Chemistry.Solution.Components;
|
||||
using Content.Shared.Interaction;
|
||||
using Content.Shared.Interaction.Helpers;
|
||||
using Content.Shared.Notification.Managers;
|
||||
@@ -22,8 +23,10 @@ namespace Content.Server.Chemistry.Components
|
||||
/// containers, and can directly inject into a mobs bloodstream.
|
||||
/// </summary>
|
||||
[RegisterComponent]
|
||||
public class InjectorComponent : SharedInjectorComponent, IAfterInteract, IUse, ISolutionChange
|
||||
public class InjectorComponent : SharedInjectorComponent, IAfterInteract, IUse
|
||||
{
|
||||
public const string SolutionName = "injector";
|
||||
|
||||
/// <summary>
|
||||
/// Whether or not the injector is able to draw from containers or if it's a single use
|
||||
/// device that can only inject.
|
||||
@@ -109,47 +112,46 @@ namespace Content.Server.Chemistry.Components
|
||||
if (!eventArgs.InRangeUnobstructed(ignoreInsideBlocker: true, popup: true))
|
||||
return false;
|
||||
|
||||
var solutionsSys = EntitySystem.Get<SolutionContainerSystem>();
|
||||
//Make sure we have the attacking entity
|
||||
if (eventArgs.Target == null || !Owner.HasComponent<SolutionContainerComponent>())
|
||||
if (eventArgs.Target == null || !Owner.HasComponent<SolutionContainerManagerComponent>())
|
||||
{
|
||||
return false;
|
||||
}
|
||||
|
||||
var targetEntity = eventArgs.Target;
|
||||
|
||||
|
||||
// Handle injecting/drawing for solutions
|
||||
if (targetEntity.TryGetComponent<ISolutionInteractionsComponent>(out var targetSolution))
|
||||
if (ToggleState == InjectorToggleMode.Inject)
|
||||
{
|
||||
if (ToggleState == InjectorToggleMode.Inject)
|
||||
if (solutionsSys.TryGetInjectableSolution(targetEntity.Uid, out var injectableSolution))
|
||||
{
|
||||
if (targetSolution.CanInject)
|
||||
{
|
||||
TryInject(targetSolution, eventArgs.User);
|
||||
}
|
||||
else
|
||||
{
|
||||
eventArgs.User.PopupMessage(eventArgs.User,
|
||||
Loc.GetString("injector-component-cannot-transfer-message", ("owner", targetSolution.Owner)));
|
||||
}
|
||||
TryInject(targetEntity, injectableSolution, eventArgs.User);
|
||||
}
|
||||
else if (ToggleState == InjectorToggleMode.Draw)
|
||||
else if (targetEntity.TryGetComponent(out BloodstreamComponent? bloodstream))
|
||||
{
|
||||
if (targetSolution.CanDraw)
|
||||
{
|
||||
TryDraw(targetSolution, eventArgs.User);
|
||||
}
|
||||
else
|
||||
{
|
||||
eventArgs.User.PopupMessage(eventArgs.User,
|
||||
Loc.GetString("injector-component-cannot-draw-message", ("owner", targetSolution.Owner)));
|
||||
}
|
||||
TryInjectIntoBloodstream(bloodstream, eventArgs.User);
|
||||
}
|
||||
else
|
||||
{
|
||||
eventArgs.User.PopupMessage(eventArgs.User,
|
||||
Loc.GetString("injector-component-cannot-transfer-message",
|
||||
("owner", eventArgs.User)));
|
||||
}
|
||||
}
|
||||
// Handle injecting into bloodstream
|
||||
else if (targetEntity.TryGetComponent(out BloodstreamComponent? bloodstream) &&
|
||||
ToggleState == InjectorToggleMode.Inject)
|
||||
else if (ToggleState == InjectorToggleMode.Draw)
|
||||
{
|
||||
TryInjectIntoBloodstream(bloodstream, eventArgs.User);
|
||||
if (solutionsSys.TryGetDrawableSolution(targetEntity, out var drawableSolution))
|
||||
{
|
||||
TryDraw(targetEntity, drawableSolution, eventArgs.User);
|
||||
}
|
||||
else
|
||||
{
|
||||
eventArgs.User.PopupMessage(eventArgs.User,
|
||||
Loc.GetString("injector-component-cannot-draw-message",
|
||||
("owner", eventArgs.User)));
|
||||
}
|
||||
}
|
||||
|
||||
return true;
|
||||
@@ -168,10 +170,10 @@ namespace Content.Server.Chemistry.Components
|
||||
|
||||
private void TryInjectIntoBloodstream(BloodstreamComponent targetBloodstream, IEntity user)
|
||||
{
|
||||
if (!Owner.TryGetComponent(out SolutionContainerComponent? solution) || solution.CurrentVolume == 0)
|
||||
{
|
||||
if (!EntitySystem.Get<SolutionContainerSystem>()
|
||||
.TryGetSolution(user, SharedBloodstreamComponent.DefaultSolutionName, out var bloodstream)
|
||||
|| bloodstream.CurrentVolume == 0)
|
||||
return;
|
||||
}
|
||||
|
||||
// Get transfer amount. May be smaller than _transferAmount if not enough room
|
||||
var realTransferAmount = ReagentUnit.Min(_transferAmount, targetBloodstream.EmptyVolume);
|
||||
@@ -179,61 +181,65 @@ namespace Content.Server.Chemistry.Components
|
||||
if (realTransferAmount <= 0)
|
||||
{
|
||||
Owner.PopupMessage(user,
|
||||
Loc.GetString("injector-component-cannot-inject-message",("owner", targetBloodstream.Owner)));
|
||||
Loc.GetString("injector-component-cannot-inject-message", ("owner", targetBloodstream.Owner)));
|
||||
return;
|
||||
}
|
||||
|
||||
// Move units from attackSolution to targetSolution
|
||||
var removedSolution = solution.SplitSolution(realTransferAmount);
|
||||
var removedSolution =
|
||||
EntitySystem.Get<SolutionContainerSystem>().SplitSolution(user.Uid, bloodstream, realTransferAmount);
|
||||
|
||||
if (!solution.CanAddSolution(removedSolution))
|
||||
if (!bloodstream.CanAddSolution(removedSolution))
|
||||
{
|
||||
return;
|
||||
}
|
||||
|
||||
// TODO: Account for partial transfer.
|
||||
var bloodsStreamEntity = Owner.EntityManager.GetEntity(user.Uid);
|
||||
removedSolution.DoEntityReaction(bloodsStreamEntity, ReactionMethod.Injection);
|
||||
|
||||
removedSolution.DoEntityReaction(solution.Owner, ReactionMethod.Injection);
|
||||
|
||||
solution.TryAddSolution(removedSolution);
|
||||
EntitySystem.Get<SolutionContainerSystem>().TryAddSolution(user.Uid, bloodstream, removedSolution);
|
||||
|
||||
removedSolution.DoEntityReaction(targetBloodstream.Owner, ReactionMethod.Injection);
|
||||
|
||||
Owner.PopupMessage(user,
|
||||
Loc.GetString("injector-component-inject-success-message",
|
||||
("amount", removedSolution.TotalVolume),
|
||||
("target", targetBloodstream.Owner)));
|
||||
("amount", removedSolution.TotalVolume),
|
||||
("target", targetBloodstream.Owner)));
|
||||
Dirty();
|
||||
AfterInject();
|
||||
}
|
||||
|
||||
private void TryInject(ISolutionInteractionsComponent targetSolution, IEntity user)
|
||||
private void TryInject(IEntity targetEntity, Solution targetSolution, IEntity user)
|
||||
{
|
||||
if (!Owner.TryGetComponent(out SolutionContainerComponent? solution) || solution.CurrentVolume == 0)
|
||||
if (!EntitySystem.Get<SolutionContainerSystem>().TryGetSolution(Owner, SolutionName, out var solution)
|
||||
|| solution.CurrentVolume == 0)
|
||||
{
|
||||
return;
|
||||
}
|
||||
|
||||
// Get transfer amount. May be smaller than _transferAmount if not enough room
|
||||
var realTransferAmount = ReagentUnit.Min(_transferAmount, targetSolution.InjectSpaceAvailable);
|
||||
var realTransferAmount = ReagentUnit.Min(_transferAmount, targetSolution.AvailableVolume);
|
||||
|
||||
if (realTransferAmount <= 0)
|
||||
{
|
||||
Owner.PopupMessage(user, Loc.GetString("injector-component-target-already-full-message", ("target", targetSolution.Owner)));
|
||||
Owner.PopupMessage(user,
|
||||
Loc.GetString("injector-component-target-already-full-message", ("target", targetEntity)));
|
||||
return;
|
||||
}
|
||||
|
||||
// Move units from attackSolution to targetSolution
|
||||
var removedSolution = solution.SplitSolution(realTransferAmount);
|
||||
var removedSolution = EntitySystem.Get<SolutionContainerSystem>().SplitSolution(Owner.Uid, solution, realTransferAmount);
|
||||
|
||||
removedSolution.DoEntityReaction(targetSolution.Owner, ReactionMethod.Injection);
|
||||
removedSolution.DoEntityReaction(targetEntity, ReactionMethod.Injection);
|
||||
|
||||
targetSolution.Inject(removedSolution);
|
||||
EntitySystem.Get<SolutionContainerSystem>()
|
||||
.Inject(targetEntity.Uid, targetSolution, removedSolution);
|
||||
|
||||
Owner.PopupMessage(user,
|
||||
Loc.GetString("injector-component-transfer-success-message",
|
||||
("amount", removedSolution.TotalVolume),
|
||||
("target", targetSolution.Owner)));
|
||||
("amount", removedSolution.TotalVolume),
|
||||
("target", targetEntity)));
|
||||
Dirty();
|
||||
AfterInject();
|
||||
}
|
||||
@@ -241,15 +247,27 @@ namespace Content.Server.Chemistry.Components
|
||||
private void AfterInject()
|
||||
{
|
||||
// Automatically set syringe to draw after completely draining it.
|
||||
if (Owner.GetComponent<SolutionContainerComponent>().CurrentVolume == 0)
|
||||
if (EntitySystem.Get<SolutionContainerSystem>().TryGetSolution(Owner, SolutionName, out var solution)
|
||||
&& solution.CurrentVolume == 0)
|
||||
{
|
||||
ToggleState = InjectorToggleMode.Draw;
|
||||
}
|
||||
}
|
||||
|
||||
private void TryDraw(ISolutionInteractionsComponent targetSolution, IEntity user)
|
||||
private void AfterDraw()
|
||||
{
|
||||
if (!Owner.TryGetComponent(out SolutionContainerComponent? solution) || solution.EmptyVolume == 0)
|
||||
// Automatically set syringe to inject after completely filling it.
|
||||
if (EntitySystem.Get<SolutionContainerSystem>().TryGetSolution(Owner, SolutionName, out var solution)
|
||||
&& solution.AvailableVolume == 0)
|
||||
{
|
||||
ToggleState = InjectorToggleMode.Inject;
|
||||
}
|
||||
}
|
||||
|
||||
private void TryDraw(IEntity targetEntity, Solution targetSolution, IEntity user)
|
||||
{
|
||||
if (!EntitySystem.Get<SolutionContainerSystem>().TryGetSolution(Owner, SolutionName, out var solution)
|
||||
|| solution.AvailableVolume == 0)
|
||||
{
|
||||
return;
|
||||
}
|
||||
@@ -259,43 +277,33 @@ namespace Content.Server.Chemistry.Components
|
||||
|
||||
if (realTransferAmount <= 0)
|
||||
{
|
||||
Owner.PopupMessage(user, Loc.GetString("injector-component-target-is-empty-message",("target", targetSolution.Owner)));
|
||||
Owner.PopupMessage(user,
|
||||
Loc.GetString("injector-component-target-is-empty-message", ("target", targetEntity)));
|
||||
return;
|
||||
}
|
||||
|
||||
// Move units from attackSolution to targetSolution
|
||||
var removedSolution = targetSolution.Draw(realTransferAmount);
|
||||
var removedSolution = EntitySystem.Get<SolutionContainerSystem>()
|
||||
.Draw(targetEntity.Uid, targetSolution, realTransferAmount);
|
||||
|
||||
if (!solution.TryAddSolution(removedSolution))
|
||||
if (!EntitySystem.Get<SolutionContainerSystem>().TryAddSolution(targetEntity.Uid, solution, removedSolution))
|
||||
{
|
||||
return;
|
||||
}
|
||||
|
||||
Owner.PopupMessage(user,
|
||||
Loc.GetString("injector-component-draw-success-message",
|
||||
("amount", removedSolution.TotalVolume),
|
||||
("target", targetSolution.Owner)));
|
||||
("amount", removedSolution.TotalVolume),
|
||||
("target", targetEntity)));
|
||||
Dirty();
|
||||
AfterDraw();
|
||||
}
|
||||
|
||||
private void AfterDraw()
|
||||
{
|
||||
// Automatically set syringe to inject after completely filling it.
|
||||
if (Owner.GetComponent<SolutionContainerComponent>().EmptyVolume == 0)
|
||||
{
|
||||
ToggleState = InjectorToggleMode.Inject;
|
||||
}
|
||||
}
|
||||
|
||||
void ISolutionChange.SolutionChanged(SolutionChangeEventArgs eventArgs)
|
||||
{
|
||||
Dirty();
|
||||
}
|
||||
|
||||
public override ComponentState GetComponentState(ICommonSession player)
|
||||
{
|
||||
Owner.TryGetComponent(out SolutionContainerComponent? solution);
|
||||
Owner.EntityManager.EntitySysManager.GetEntitySystem<SolutionContainerSystem>()
|
||||
.TryGetSolution(Owner, SolutionName, out var solution);
|
||||
|
||||
var currentVolume = solution?.CurrentVolume ?? ReagentUnit.Zero;
|
||||
var maxVolume = solution?.MaxVolume ?? ReagentUnit.Zero;
|
||||
|
||||
@@ -7,10 +7,10 @@ using Content.Server.Items;
|
||||
using Content.Server.Power.Components;
|
||||
using Content.Server.UserInterface;
|
||||
using Content.Shared.ActionBlocker;
|
||||
using Content.Shared.Chemistry;
|
||||
using Content.Shared.Chemistry.Components;
|
||||
using Content.Shared.Chemistry.Dispenser;
|
||||
using Content.Shared.Chemistry.EntitySystems;
|
||||
using Content.Shared.Chemistry.Reagent;
|
||||
using Content.Shared.Chemistry.Solution;
|
||||
using Content.Shared.Interaction;
|
||||
using Content.Shared.Notification.Managers;
|
||||
using Content.Shared.Sound;
|
||||
@@ -38,9 +38,10 @@ namespace Content.Server.Chemistry.Components
|
||||
[RegisterComponent]
|
||||
[ComponentReference(typeof(IActivate))]
|
||||
[ComponentReference(typeof(IInteractUsing))]
|
||||
public class ReagentDispenserComponent : SharedReagentDispenserComponent, IActivate, IInteractUsing, ISolutionChange
|
||||
public class ReagentDispenserComponent : SharedReagentDispenserComponent, IActivate, IInteractUsing
|
||||
{
|
||||
private static ReagentInventoryComparer _comparer = new();
|
||||
public static string SolutionName = "reagent";
|
||||
|
||||
[Dependency] private readonly IPrototypeManager _prototypeManager = default!;
|
||||
|
||||
@@ -52,9 +53,20 @@ namespace Content.Server.Chemistry.Components
|
||||
|
||||
[ViewVariables] private bool HasBeaker => _beakerContainer.ContainedEntity != null;
|
||||
[ViewVariables] private ReagentUnit _dispenseAmount = ReagentUnit.New(10);
|
||||
[UsedImplicitly] [ViewVariables] private SolutionContainerComponent? Solution => _beakerContainer.ContainedEntity?.GetComponent<SolutionContainerComponent>();
|
||||
|
||||
[ViewVariables] private bool Powered => !Owner.TryGetComponent(out ApcPowerReceiverComponent? receiver) || receiver.Powered;
|
||||
[UsedImplicitly]
|
||||
[ViewVariables]
|
||||
private Solution? Solution
|
||||
{
|
||||
get
|
||||
{
|
||||
EntitySystem.Get<SolutionContainerSystem>().TryGetSolution(Owner, SolutionName, out var solution);
|
||||
return solution;
|
||||
}
|
||||
}
|
||||
|
||||
[ViewVariables]
|
||||
private bool Powered => !Owner.TryGetComponent(out ApcPowerReceiverComponent? receiver) || receiver.Powered;
|
||||
|
||||
[ViewVariables] private BoundUserInterface? UserInterface => Owner.GetUIOrNull(ReagentDispenserUiKey.Key);
|
||||
|
||||
@@ -134,7 +146,7 @@ namespace Content.Server.Chemistry.Components
|
||||
_ => true,
|
||||
};
|
||||
|
||||
if(!PlayerCanUseDispenser(obj.Session.AttachedEntity, needsPower))
|
||||
if (!PlayerCanUseDispenser(obj.Session.AttachedEntity, needsPower))
|
||||
return;
|
||||
|
||||
switch (msg.Button)
|
||||
@@ -216,25 +228,27 @@ namespace Content.Server.Chemistry.Components
|
||||
private ReagentDispenserBoundUserInterfaceState GetUserInterfaceState()
|
||||
{
|
||||
var beaker = _beakerContainer.ContainedEntity;
|
||||
if (beaker == null)
|
||||
if (beaker == null ||
|
||||
!EntitySystem.Get<SolutionContainerSystem>().TryGetSolution(beaker, "beaker", out var solution))
|
||||
{
|
||||
return new ReagentDispenserBoundUserInterfaceState(Powered, false, ReagentUnit.New(0), ReagentUnit.New(0),
|
||||
return new ReagentDispenserBoundUserInterfaceState(Powered, false, ReagentUnit.New(0),
|
||||
ReagentUnit.New(0),
|
||||
string.Empty, Inventory, Owner.Name, null, _dispenseAmount);
|
||||
}
|
||||
|
||||
var solution = beaker.GetComponent<SolutionContainerComponent>();
|
||||
return new ReagentDispenserBoundUserInterfaceState(Powered, true, solution.CurrentVolume, solution.MaxVolume,
|
||||
beaker.Name, Inventory, Owner.Name, solution.ReagentList.ToList(), _dispenseAmount);
|
||||
return new ReagentDispenserBoundUserInterfaceState(Powered, true, solution.CurrentVolume,
|
||||
solution.MaxVolume,
|
||||
beaker.Name, Inventory, Owner.Name, solution.Contents.ToList(), _dispenseAmount);
|
||||
}
|
||||
|
||||
private void UpdateUserInterface()
|
||||
public void UpdateUserInterface()
|
||||
{
|
||||
var state = GetUserInterfaceState();
|
||||
UserInterface?.SetState(state);
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// If this component contains an entity with a <see cref="SolutionContainerComponent"/>, eject it.
|
||||
/// If this component contains an entity with a <see cref="SolutionHolder"/>, eject it.
|
||||
/// Tries to eject into user's hands first, then ejects onto dispenser if both hands are full.
|
||||
/// </summary>
|
||||
private void TryEject(IEntity user)
|
||||
@@ -243,46 +257,48 @@ namespace Content.Server.Chemistry.Components
|
||||
return;
|
||||
|
||||
var beaker = _beakerContainer.ContainedEntity;
|
||||
if(beaker is null)
|
||||
if (beaker is null)
|
||||
return;
|
||||
|
||||
_beakerContainer.Remove(beaker);
|
||||
UpdateUserInterface();
|
||||
|
||||
if(!user.TryGetComponent<HandsComponent>(out var hands) || !beaker.TryGetComponent<ItemComponent>(out var item))
|
||||
if (!user.TryGetComponent<HandsComponent>(out var hands) ||
|
||||
!beaker.TryGetComponent<ItemComponent>(out var item))
|
||||
return;
|
||||
if (hands.CanPutInHand(item))
|
||||
hands.PutInHand(item);
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// If this component contains an entity with a <see cref="SolutionContainerComponent"/>, remove all of it's reagents / solutions.
|
||||
/// If this component contains an entity with a <see cref="SolutionHolder"/>, remove all of it's reagents / solutions.
|
||||
/// </summary>
|
||||
private void TryClear()
|
||||
{
|
||||
if (!HasBeaker) return;
|
||||
var solution = _beakerContainer.ContainedEntity?.GetComponent<SolutionContainerComponent>();
|
||||
if(solution is null)
|
||||
if (!HasBeaker ||
|
||||
!EntitySystem.Get<SolutionContainerSystem>()
|
||||
.TryGetSolution(_beakerContainer.ContainedEntity, "beaker", out var solution))
|
||||
return;
|
||||
|
||||
solution.RemoveAllSolution();
|
||||
EntitySystem.Get<SolutionContainerSystem>().RemoveAllSolution(_beakerContainer.ContainedEntity!.Uid, solution);
|
||||
|
||||
UpdateUserInterface();
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// If this component contains an entity with a <see cref="SolutionContainerComponent"/>, attempt to dispense the specified reagent to it.
|
||||
/// If this component contains an entity with a <see cref="SolutionHolder"/>, attempt to dispense the specified reagent to it.
|
||||
/// </summary>
|
||||
/// <param name="dispenseIndex">The index of the reagent in <c>Inventory</c>.</param>
|
||||
private void TryDispense(int dispenseIndex)
|
||||
{
|
||||
if (!HasBeaker) return;
|
||||
|
||||
var solution = _beakerContainer.ContainedEntity?.GetComponent<SolutionContainerComponent>();
|
||||
if (solution is null)
|
||||
return;
|
||||
if (_beakerContainer.ContainedEntity == null
|
||||
|| !EntitySystem.Get<SolutionContainerSystem>()
|
||||
.TryGetSolution(_beakerContainer.ContainedEntity, "beaker", out var solution)) return;
|
||||
|
||||
solution.TryAddReagent(Inventory[dispenseIndex].ID, _dispenseAmount, out _);
|
||||
EntitySystem.Get<SolutionContainerSystem>()
|
||||
.TryAddReagent(_beakerContainer.ContainedEntity.Uid, solution, Inventory[dispenseIndex].ID, _dispenseAmount, out _);
|
||||
|
||||
UpdateUserInterface();
|
||||
}
|
||||
@@ -313,7 +329,7 @@ namespace Content.Server.Chemistry.Components
|
||||
|
||||
/// <summary>
|
||||
/// Called when you click the owner entity with something in your active hand. If the entity in your hand
|
||||
/// contains a <see cref="SolutionContainerComponent"/>, if you have hands, and if the dispenser doesn't already
|
||||
/// contains a <see cref="SolutionHolder"/>, if you have hands, and if the dispenser doesn't already
|
||||
/// hold a container, it will be added to the dispenser.
|
||||
/// </summary>
|
||||
/// <param name="args">Data relevant to the event such as the actor which triggered it.</param>
|
||||
@@ -328,18 +344,21 @@ namespace Content.Server.Chemistry.Components
|
||||
|
||||
if (hands.GetActiveHand == null)
|
||||
{
|
||||
Owner.PopupMessage(args.User, Loc.GetString("reagent-dispenser-component-interact-using-nothing-in-hands"));
|
||||
Owner.PopupMessage(args.User,
|
||||
Loc.GetString("reagent-dispenser-component-interact-using-nothing-in-hands"));
|
||||
return false;
|
||||
}
|
||||
|
||||
var solutionSys = EntitySystem.Get<SolutionContainerSystem>();
|
||||
var activeHandEntity = hands.GetActiveHand.Owner;
|
||||
if (activeHandEntity.TryGetComponent<SolutionContainerComponent>(out var solution))
|
||||
if (solutionSys.TryGetSolution(activeHandEntity, "beaker", out _))
|
||||
{
|
||||
if (HasBeaker)
|
||||
{
|
||||
Owner.PopupMessage(args.User, Loc.GetString("reagent-dispenser-component-has-container-already-message"));
|
||||
Owner.PopupMessage(args.User,
|
||||
Loc.GetString("reagent-dispenser-component-has-container-already-message"));
|
||||
}
|
||||
else if ((solution.Capabilities & SolutionContainerCaps.FitsInDispenser) == 0)
|
||||
else if (!solutionSys.HasFitsInDispenser(activeHandEntity))
|
||||
{
|
||||
//If it can't fit in the dispenser, don't put it in. For example, buckets and mop buckets can't fit.
|
||||
Owner.PopupMessage(args.User, Loc.GetString("reagent-dispenser-component-cannot-fit-message"));
|
||||
@@ -352,14 +371,14 @@ namespace Content.Server.Chemistry.Components
|
||||
}
|
||||
else
|
||||
{
|
||||
Owner.PopupMessage(args.User, Loc.GetString("reagent-dispenser-component-cannot-put-entity-message", ("entity", activeHandEntity)));
|
||||
Owner.PopupMessage(args.User,
|
||||
Loc.GetString("reagent-dispenser-component-cannot-put-entity-message",
|
||||
("entity", activeHandEntity)));
|
||||
}
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
void ISolutionChange.SolutionChanged(SolutionChangeEventArgs eventArgs) => UpdateUserInterface();
|
||||
|
||||
private void ClickSound()
|
||||
{
|
||||
SoundSystem.Play(Filter.Pvs(Owner), _clickSound.GetSound(), Owner, AudioParams.Default.WithVolume(-2f));
|
||||
|
||||
@@ -1,8 +1,4 @@
|
||||
using Content.Server.Notification;
|
||||
using Content.Shared.Chemistry;
|
||||
using Content.Shared.Chemistry.Reagent;
|
||||
using Robust.Shared.GameObjects;
|
||||
using Robust.Shared.Localization;
|
||||
using Robust.Shared.Serialization.Manager.Attributes;
|
||||
using Robust.Shared.ViewVariables;
|
||||
|
||||
@@ -13,44 +9,18 @@ namespace Content.Server.Chemistry.Components
|
||||
/// But specifically, this component deletes the entity and spawns in a new entity when the entity is exposed to a given reagent.
|
||||
/// </summary>
|
||||
[RegisterComponent]
|
||||
[ComponentReference(typeof(ISolutionChange))]
|
||||
public class RehydratableComponent : Component, ISolutionChange
|
||||
public class RehydratableComponent : Component
|
||||
{
|
||||
public override string Name => "Rehydratable";
|
||||
|
||||
[ViewVariables]
|
||||
[DataField("catalyst")]
|
||||
private string _catalystPrototype = "Water";
|
||||
internal string CatalystPrototype = "Water";
|
||||
|
||||
[ViewVariables]
|
||||
[DataField("target")]
|
||||
private string? _targetPrototype = default!;
|
||||
internal string? TargetPrototype = default!;
|
||||
|
||||
private bool _expanding;
|
||||
|
||||
void ISolutionChange.SolutionChanged(SolutionChangeEventArgs eventArgs)
|
||||
{
|
||||
var solution = eventArgs.Owner.GetComponent<SolutionContainerComponent>();
|
||||
if (solution.Solution.GetReagentQuantity(_catalystPrototype) > ReagentUnit.Zero)
|
||||
{
|
||||
Expand();
|
||||
}
|
||||
}
|
||||
|
||||
// Try not to make this public if you can help it.
|
||||
private void Expand()
|
||||
{
|
||||
if (_expanding)
|
||||
{
|
||||
return;
|
||||
}
|
||||
_expanding = true;
|
||||
Owner.PopupMessageEveryone(Loc.GetString("rehydratable-component-expands-message",("owner", Owner)));
|
||||
if (!string.IsNullOrEmpty(_targetPrototype))
|
||||
{
|
||||
var ent = Owner.EntityManager.SpawnEntity(_targetPrototype, Owner.Transform.Coordinates);
|
||||
ent.Transform.AttachToGridOrMap();
|
||||
}
|
||||
Owner.Delete();
|
||||
}
|
||||
internal bool Expanding;
|
||||
}
|
||||
}
|
||||
|
||||
@@ -1,7 +1,7 @@
|
||||
using System.Linq;
|
||||
using Content.Server.Body.Circulatory;
|
||||
using Content.Server.Body.Circulatory;
|
||||
using Content.Server.Body.Respiratory;
|
||||
using Content.Shared.Chemistry;
|
||||
using Content.Shared.Chemistry.EntitySystems;
|
||||
using Content.Shared.Chemistry.Reagent;
|
||||
using Content.Shared.Smoking;
|
||||
using Robust.Server.GameObjects;
|
||||
@@ -14,19 +14,20 @@ namespace Content.Server.Chemistry.Components
|
||||
public class SmokeSolutionAreaEffectComponent : SolutionAreaEffectComponent
|
||||
{
|
||||
public override string Name => "SmokeSolutionAreaEffect";
|
||||
public const string SolutionName = "smoke";
|
||||
|
||||
protected override void UpdateVisuals()
|
||||
{
|
||||
if (Owner.TryGetComponent(out AppearanceComponent? appearance) &&
|
||||
SolutionContainerComponent != null)
|
||||
EntitySystem.Get<SolutionContainerSystem>().TryGetSolution(Owner, SolutionName, out var solution))
|
||||
{
|
||||
appearance.SetData(SmokeVisuals.Color, SolutionContainerComponent.Color);
|
||||
appearance.SetData(SmokeVisuals.Color, solution.Color);
|
||||
}
|
||||
}
|
||||
|
||||
protected override void ReactWithEntity(IEntity entity, double solutionFraction)
|
||||
{
|
||||
if (SolutionContainerComponent == null)
|
||||
if (!EntitySystem.Get<SolutionContainerSystem>().TryGetSolution(Owner, SolutionName, out var solution))
|
||||
return;
|
||||
|
||||
if (!entity.TryGetComponent(out BloodstreamComponent? bloodstream))
|
||||
@@ -37,7 +38,7 @@ namespace Content.Server.Chemistry.Components
|
||||
return;
|
||||
|
||||
var chemistry = EntitySystem.Get<ChemistrySystem>();
|
||||
var cloneSolution = SolutionContainerComponent.Solution.Clone();
|
||||
var cloneSolution = solution.Clone();
|
||||
var transferAmount = ReagentUnit.Min(cloneSolution.TotalVolume * solutionFraction, bloodstream.EmptyVolume);
|
||||
var transferSolution = cloneSolution.SplitSolution(transferAmount);
|
||||
|
||||
|
||||
@@ -3,8 +3,9 @@ using System.Linq;
|
||||
using Content.Server.Atmos.Components;
|
||||
using Content.Server.Coordinates.Helpers;
|
||||
using Content.Shared.Chemistry;
|
||||
using Content.Shared.Chemistry.Components;
|
||||
using Content.Shared.Chemistry.EntitySystems;
|
||||
using Content.Shared.Chemistry.Reagent;
|
||||
using Content.Shared.Chemistry.Solution;
|
||||
using Robust.Shared.GameObjects;
|
||||
using Robust.Shared.IoC;
|
||||
using Robust.Shared.Log;
|
||||
@@ -20,10 +21,10 @@ namespace Content.Server.Chemistry.Components
|
||||
/// </summary>
|
||||
public abstract class SolutionAreaEffectComponent : Component
|
||||
{
|
||||
public const string SolutionName = "solutionArea";
|
||||
|
||||
[Dependency] protected readonly IMapManager MapManager = default!;
|
||||
[Dependency] protected readonly IPrototypeManager PrototypeManager = default!;
|
||||
|
||||
[ComponentDependency] protected readonly SolutionContainerComponent? SolutionContainerComponent = default!;
|
||||
public int Amount { get; set; }
|
||||
public SolutionAreaEffectInceptionComponent? Inception { get; set; }
|
||||
|
||||
@@ -67,10 +68,12 @@ namespace Content.Server.Chemistry.Components
|
||||
var coords = Owner.Transform.Coordinates;
|
||||
foreach (var neighbor in grid.GetInDir(coords, dir))
|
||||
{
|
||||
if (Owner.EntityManager.ComponentManager.TryGetComponent(neighbor, out SolutionAreaEffectComponent? comp) && comp.Inception == Inception)
|
||||
if (Owner.EntityManager.ComponentManager.TryGetComponent(neighbor,
|
||||
out SolutionAreaEffectComponent? comp) && comp.Inception == Inception)
|
||||
return;
|
||||
|
||||
if (Owner.EntityManager.ComponentManager.TryGetComponent(neighbor, out AirtightComponent? airtight) && airtight.AirBlocked)
|
||||
if (Owner.EntityManager.ComponentManager.TryGetComponent(neighbor,
|
||||
out AirtightComponent? airtight) && airtight.AirBlocked)
|
||||
return;
|
||||
}
|
||||
|
||||
@@ -82,9 +85,9 @@ namespace Content.Server.Chemistry.Components
|
||||
return;
|
||||
}
|
||||
|
||||
if (SolutionContainerComponent != null)
|
||||
if (EntitySystem.Get<SolutionContainerSystem>().TryGetSolution(Owner, SolutionName, out var solution))
|
||||
{
|
||||
effectComponent.TryAddSolution(SolutionContainerComponent.Solution.Clone());
|
||||
effectComponent.TryAddSolution(solution.Clone());
|
||||
}
|
||||
|
||||
effectComponent.Amount = Amount - 1;
|
||||
@@ -95,7 +98,6 @@ namespace Content.Server.Chemistry.Components
|
||||
SpreadToDir(Direction.East);
|
||||
SpreadToDir(Direction.South);
|
||||
SpreadToDir(Direction.West);
|
||||
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
@@ -120,7 +122,7 @@ namespace Content.Server.Chemistry.Components
|
||||
/// with the other area effects from the inception.</param>
|
||||
public void React(float averageExposures)
|
||||
{
|
||||
if (SolutionContainerComponent == null)
|
||||
if (!EntitySystem.Get<SolutionContainerSystem>().TryGetSolution(Owner, SolutionName, out var solution))
|
||||
return;
|
||||
|
||||
var chemistry = EntitySystem.Get<ChemistrySystem>();
|
||||
@@ -129,7 +131,7 @@ namespace Content.Server.Chemistry.Components
|
||||
|
||||
var solutionFraction = 1 / Math.Floor(averageExposures);
|
||||
|
||||
foreach (var reagentQuantity in SolutionContainerComponent.ReagentList.ToArray())
|
||||
foreach (var reagentQuantity in solution.Contents)
|
||||
{
|
||||
if (reagentQuantity.Quantity == ReagentUnit.Zero) continue;
|
||||
var reagent = PrototypeManager.Index<ReagentPrototype>(reagentQuantity.ReagentId);
|
||||
@@ -140,7 +142,8 @@ namespace Content.Server.Chemistry.Components
|
||||
// Touch every entity on the tile
|
||||
foreach (var entity in tile.GetEntitiesInTileFast().ToArray())
|
||||
{
|
||||
chemistry.ReactionEntity(entity, ReactionMethod.Touch, reagent, reagentQuantity.Quantity * solutionFraction, SolutionContainerComponent.Solution);
|
||||
chemistry.ReactionEntity(entity, ReactionMethod.Touch, reagent,
|
||||
reagentQuantity.Quantity * solutionFraction, solution);
|
||||
}
|
||||
}
|
||||
|
||||
@@ -157,13 +160,13 @@ namespace Content.Server.Chemistry.Components
|
||||
if (solution.TotalVolume == 0)
|
||||
return;
|
||||
|
||||
if (SolutionContainerComponent == null)
|
||||
if (!EntitySystem.Get<SolutionContainerSystem>().TryGetSolution(Owner, SolutionName, out var solutionArea))
|
||||
return;
|
||||
|
||||
var addSolution =
|
||||
solution.SplitSolution(ReagentUnit.Min(solution.TotalVolume, SolutionContainerComponent.EmptyVolume));
|
||||
solution.SplitSolution(ReagentUnit.Min(solution.TotalVolume, solutionArea.AvailableVolume));
|
||||
|
||||
SolutionContainerComponent.TryAddSolution(addSolution);
|
||||
EntitySystem.Get<SolutionContainerSystem>().TryAddSolution(Owner.Uid, solutionArea, addSolution);
|
||||
|
||||
UpdateVisuals();
|
||||
}
|
||||
|
||||
@@ -1,12 +0,0 @@
|
||||
using Content.Shared.Chemistry.Solution.Components;
|
||||
using Robust.Shared.GameObjects;
|
||||
|
||||
namespace Content.Server.Chemistry.Components
|
||||
{
|
||||
[RegisterComponent]
|
||||
[ComponentReference(typeof(SharedSolutionContainerComponent))]
|
||||
[ComponentReference(typeof(ISolutionInteractionsComponent))]
|
||||
public class SolutionContainerComponent : SharedSolutionContainerComponent
|
||||
{
|
||||
}
|
||||
}
|
||||
@@ -3,12 +3,15 @@ using System.Threading.Tasks;
|
||||
using Content.Server.UserInterface;
|
||||
using Content.Shared.ActionBlocker;
|
||||
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.Chemistry.Solution.Components;
|
||||
using Content.Shared.Interaction;
|
||||
using Content.Shared.Interaction.Helpers;
|
||||
using Content.Shared.Notification.Managers;
|
||||
using Content.Shared.Verbs;
|
||||
using Microsoft.EntityFrameworkCore.Metadata.Builders;
|
||||
using Robust.Server.GameObjects;
|
||||
using Robust.Shared.GameObjects;
|
||||
using Robust.Shared.Localization;
|
||||
@@ -108,7 +111,8 @@ namespace Content.Server.Chemistry.Components
|
||||
var amount = Math.Clamp(sval, MinimumTransferAmount.Float(),
|
||||
MaximumTransferAmount.Float());
|
||||
|
||||
serverMsg.Session.AttachedEntity?.PopupMessage(Loc.GetString("comp-solution-transfer-set-amount", ("amount", amount)));
|
||||
serverMsg.Session.AttachedEntity?.PopupMessage(Loc.GetString("comp-solution-transfer-set-amount",
|
||||
("amount", amount)));
|
||||
SetTransferAmount(ReagentUnit.New(amount));
|
||||
break;
|
||||
}
|
||||
@@ -116,50 +120,57 @@ namespace Content.Server.Chemistry.Components
|
||||
|
||||
public void SetTransferAmount(ReagentUnit amount)
|
||||
{
|
||||
amount = ReagentUnit.New(Math.Clamp(amount.Int(), MinimumTransferAmount.Int(), MaximumTransferAmount.Int()));
|
||||
amount = ReagentUnit.New(Math.Clamp(amount.Int(), MinimumTransferAmount.Int(),
|
||||
MaximumTransferAmount.Int()));
|
||||
TransferAmount = amount;
|
||||
}
|
||||
|
||||
async Task<bool> IAfterInteract.AfterInteract(AfterInteractEventArgs eventArgs)
|
||||
{
|
||||
var solutionsSys = EntitySystem.Get<SolutionContainerSystem>();
|
||||
|
||||
if (!eventArgs.InRangeUnobstructed() || eventArgs.Target == null)
|
||||
return false;
|
||||
|
||||
if (!Owner.TryGetComponent(out ISolutionInteractionsComponent? ownerSolution))
|
||||
if (!Owner.HasComponent<SolutionContainerManagerComponent>())
|
||||
return false;
|
||||
|
||||
var target = eventArgs.Target;
|
||||
if (!target.TryGetComponent(out ISolutionInteractionsComponent? targetSolution))
|
||||
var target = eventArgs.Target!;
|
||||
if (!target.HasComponent<SolutionContainerManagerComponent>())
|
||||
{
|
||||
return false;
|
||||
}
|
||||
|
||||
|
||||
if (CanReceive && target.TryGetComponent(out ReagentTankComponent? tank)
|
||||
&& ownerSolution.CanRefill && targetSolution.CanDrain)
|
||||
&& solutionsSys.TryGetRefillableSolution(Owner.Uid, out var ownerRefill)
|
||||
&& solutionsSys.TryGetDrainableSolution(eventArgs.Target.Uid, out var targetDrain))
|
||||
{
|
||||
var transferred = DoTransfer(targetSolution, ownerSolution, tank.TransferAmount, eventArgs.User);
|
||||
var transferred = DoTransfer(eventArgs.User, eventArgs.Target, targetDrain, Owner, ownerRefill, tank.TransferAmount);
|
||||
if (transferred > 0)
|
||||
{
|
||||
var toTheBrim = ownerSolution.RefillSpaceAvailable == 0;
|
||||
var toTheBrim = ownerRefill.AvailableVolume == 0;
|
||||
var msg = toTheBrim
|
||||
? "comp-solution-transfer-fill-fully"
|
||||
: "comp-solution-transfer-fill-normal";
|
||||
|
||||
target.PopupMessage(eventArgs.User, Loc.GetString(msg,("owner", Owner),("amount", transferred),("target", target)));
|
||||
target.PopupMessage(eventArgs.User,
|
||||
Loc.GetString(msg, ("owner", eventArgs.Target), ("amount", transferred), ("target", Owner)));
|
||||
return true;
|
||||
}
|
||||
}
|
||||
|
||||
if (CanSend && targetSolution.CanRefill && ownerSolution.CanDrain)
|
||||
if (CanSend && solutionsSys.TryGetRefillableSolution(eventArgs.Target.Uid, out var targetRefill)
|
||||
&& solutionsSys.TryGetDrainableSolution(Owner.Uid, out var ownerDrain))
|
||||
{
|
||||
var transferred = DoTransfer(ownerSolution, targetSolution, TransferAmount, eventArgs.User);
|
||||
var transferred = DoTransfer(eventArgs.User, Owner, ownerDrain, target, targetRefill, TransferAmount);
|
||||
|
||||
if (transferred > 0)
|
||||
{
|
||||
Owner.PopupMessage(eventArgs.User,
|
||||
Loc.GetString("comp-solution-transfer-transfer-solution",
|
||||
("amount",transferred),
|
||||
("target",target)));
|
||||
Loc.GetString("comp-solution-transfer-transfer-solution",
|
||||
("amount", transferred),
|
||||
("target", target)));
|
||||
|
||||
return true;
|
||||
}
|
||||
@@ -169,29 +180,33 @@ namespace Content.Server.Chemistry.Components
|
||||
}
|
||||
|
||||
/// <returns>The actual amount transferred.</returns>
|
||||
private static ReagentUnit DoTransfer(
|
||||
ISolutionInteractionsComponent source,
|
||||
ISolutionInteractionsComponent target,
|
||||
ReagentUnit amount,
|
||||
IEntity user)
|
||||
private static ReagentUnit DoTransfer(IEntity user,
|
||||
IEntity sourceEntity,
|
||||
Solution source,
|
||||
IEntity targetEntity,
|
||||
Solution target,
|
||||
ReagentUnit amount)
|
||||
{
|
||||
|
||||
if (source.DrainAvailable == 0)
|
||||
{
|
||||
source.Owner.PopupMessage(user, Loc.GetString("comp-solution-transfer-is-empty", ("target", source.Owner)));
|
||||
sourceEntity.PopupMessage(user,
|
||||
Loc.GetString("comp-solution-transfer-is-empty", ("target", sourceEntity)));
|
||||
return ReagentUnit.Zero;
|
||||
}
|
||||
|
||||
if (target.RefillSpaceAvailable == 0)
|
||||
if (target.AvailableVolume == 0)
|
||||
{
|
||||
target.Owner.PopupMessage(user, Loc.GetString("comp-solution-transfer-is-full", ("target", target.Owner)));
|
||||
targetEntity.PopupMessage(user,
|
||||
Loc.GetString("comp-solution-transfer-is-full", ("target", targetEntity)));
|
||||
return ReagentUnit.Zero;
|
||||
}
|
||||
|
||||
var actualAmount =
|
||||
ReagentUnit.Min(amount, ReagentUnit.Min(source.DrainAvailable, target.RefillSpaceAvailable));
|
||||
ReagentUnit.Min(amount, ReagentUnit.Min(source.DrainAvailable, target.AvailableVolume));
|
||||
|
||||
var solution = source.Drain(actualAmount);
|
||||
target.Refill(solution);
|
||||
var solution = EntitySystem.Get<SolutionContainerSystem>().Drain(sourceEntity.Uid, source, actualAmount);
|
||||
EntitySystem.Get<SolutionContainerSystem>().Refill(targetEntity.Uid, target, solution);
|
||||
|
||||
return actualAmount;
|
||||
}
|
||||
@@ -251,7 +266,8 @@ namespace Content.Server.Chemistry.Components
|
||||
protected override void Activate(IEntity user, SolutionTransferComponent component)
|
||||
{
|
||||
component.TransferAmount = component.SubjectiveBestTransferAmount();
|
||||
user.PopupMessage(Loc.GetString("comp-solution-transfer-set-amount", ("amount", component.TransferAmount.Int())));
|
||||
user.PopupMessage(Loc.GetString("comp-solution-transfer-set-amount",
|
||||
("amount", component.TransferAmount.Int())));
|
||||
}
|
||||
}
|
||||
|
||||
@@ -275,7 +291,8 @@ namespace Content.Server.Chemistry.Components
|
||||
protected override void Activate(IEntity user, SolutionTransferComponent component)
|
||||
{
|
||||
component.TransferAmount = component.MaximumTransferAmount;
|
||||
user.PopupMessage(Loc.GetString("comp-solution-transfer-set-amount", ("amount", component.TransferAmount.Int())));
|
||||
user.PopupMessage(Loc.GetString("comp-solution-transfer-set-amount",
|
||||
("amount", component.TransferAmount.Int())));
|
||||
}
|
||||
}
|
||||
|
||||
@@ -303,6 +320,7 @@ namespace Content.Server.Chemistry.Components
|
||||
{
|
||||
return;
|
||||
}
|
||||
|
||||
component.UserInterface?.Open(actor.PlayerSession);
|
||||
}
|
||||
}
|
||||
|
||||
@@ -1,27 +1,22 @@
|
||||
using Content.Shared.Chemistry;
|
||||
using Content.Shared.Chemistry.Components.SolutionManager;
|
||||
using Content.Shared.Chemistry.Reagent;
|
||||
using Content.Shared.Chemistry.Solution;
|
||||
using Robust.Server.GameObjects;
|
||||
using Robust.Shared.GameObjects;
|
||||
using Robust.Shared.IoC;
|
||||
using Robust.Shared.Prototypes;
|
||||
using Robust.Shared.Utility;
|
||||
|
||||
namespace Content.Server.Chemistry.Components
|
||||
{
|
||||
[RegisterComponent]
|
||||
public class TransformableContainerComponent : Component, ISolutionChange
|
||||
public class TransformableContainerComponent : Component
|
||||
{
|
||||
[Dependency] private readonly IPrototypeManager _prototypeManager = default!;
|
||||
|
||||
public override string Name => "TransformableContainer";
|
||||
|
||||
private SpriteSpecifier? _initialSprite;
|
||||
private string _initialName = default!;
|
||||
private string _initialDescription = default!;
|
||||
private ReagentPrototype? _currentReagent;
|
||||
public SpriteSpecifier? InitialSprite;
|
||||
public string InitialName = default!;
|
||||
public string InitialDescription = default!;
|
||||
public ReagentPrototype? CurrentReagent;
|
||||
|
||||
public bool Transformed { get; private set; }
|
||||
public bool Transformed { get; internal set; }
|
||||
|
||||
protected override void Initialize()
|
||||
{
|
||||
@@ -30,72 +25,19 @@ namespace Content.Server.Chemistry.Components
|
||||
if (Owner.TryGetComponent(out SpriteComponent? sprite) &&
|
||||
sprite.BaseRSIPath != null)
|
||||
{
|
||||
_initialSprite = new SpriteSpecifier.Rsi(new ResourcePath(sprite.BaseRSIPath), "icon");
|
||||
InitialSprite = new SpriteSpecifier.Rsi(new ResourcePath(sprite.BaseRSIPath), "icon");
|
||||
}
|
||||
|
||||
_initialName = Owner.Name;
|
||||
_initialDescription = Owner.Description;
|
||||
InitialName = Owner.Name;
|
||||
InitialDescription = Owner.Description;
|
||||
}
|
||||
|
||||
protected override void Startup()
|
||||
{
|
||||
base.Startup();
|
||||
|
||||
Owner.EnsureComponentWarn(out SolutionContainerComponent solution);
|
||||
|
||||
solution.Capabilities |= SolutionContainerCaps.FitsInDispenser;
|
||||
}
|
||||
|
||||
public void CancelTransformation()
|
||||
{
|
||||
_currentReagent = null;
|
||||
Transformed = false;
|
||||
|
||||
if (Owner.TryGetComponent(out SpriteComponent? sprite) &&
|
||||
_initialSprite != null)
|
||||
{
|
||||
sprite.LayerSetSprite(0, _initialSprite);
|
||||
}
|
||||
|
||||
Owner.Name = _initialName;
|
||||
Owner.Description = _initialDescription;
|
||||
}
|
||||
|
||||
void ISolutionChange.SolutionChanged(SolutionChangeEventArgs eventArgs)
|
||||
{
|
||||
var solution = eventArgs.Owner.GetComponent<SolutionContainerComponent>();
|
||||
//Transform container into initial state when emptied
|
||||
if (_currentReagent != null && solution.ReagentList.Count == 0)
|
||||
{
|
||||
CancelTransformation();
|
||||
}
|
||||
|
||||
//the biggest reagent in the solution decides the appearance
|
||||
var reagentId = solution.Solution.GetPrimaryReagentId();
|
||||
|
||||
//If biggest reagent didn't changed - don't change anything at all
|
||||
if (_currentReagent != null && _currentReagent.ID == reagentId)
|
||||
{
|
||||
return;
|
||||
}
|
||||
|
||||
//Only reagents with spritePath property can change appearance of transformable containers!
|
||||
if (!string.IsNullOrWhiteSpace(reagentId) &&
|
||||
_prototypeManager.TryIndex(reagentId, out ReagentPrototype? proto) &&
|
||||
!string.IsNullOrWhiteSpace(proto.SpriteReplacementPath))
|
||||
{
|
||||
var spriteSpec = new SpriteSpecifier.Rsi(new ResourcePath("Objects/Consumable/Drinks/" + proto.SpriteReplacementPath),"icon");
|
||||
|
||||
if (Owner.TryGetComponent(out SpriteComponent? sprite))
|
||||
{
|
||||
sprite?.LayerSetSprite(0, spriteSpec);
|
||||
}
|
||||
|
||||
Owner.Name = proto.Name + " glass";
|
||||
Owner.Description = proto.Description;
|
||||
_currentReagent = proto;
|
||||
Transformed = true;
|
||||
}
|
||||
Owner.EnsureComponentWarn<SolutionContainerManagerComponent>();
|
||||
Owner.EnsureComponentWarn<FitsInDispenserComponent>();
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
Reference in New Issue
Block a user