Revert "Solution Entities" (#23160)

Revert "Solution Entities (#21916)"

This reverts commit d75e743dd7.
This commit is contained in:
Emisse
2023-12-28 20:45:42 -07:00
committed by GitHub
parent c2c76c2035
commit 938d6d9945
180 changed files with 2959 additions and 3543 deletions

View File

@@ -1,3 +1,4 @@
using Content.Server.Chemistry.EntitySystems;
using Content.Shared.Chemistry.Components;
using Content.Shared.FixedPoint;
using Robust.Shared.Audio;

View File

@@ -1,6 +1,8 @@
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;
@@ -15,13 +17,7 @@ public sealed partial class SolutionRegenerationComponent : Component
/// 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.

View File

@@ -1,185 +0,0 @@
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
}

View File

@@ -1,5 +1,6 @@
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;
@@ -18,8 +19,6 @@ using Robust.Server.GameObjects;
using Robust.Shared.Audio;
using Robust.Shared.Containers;
using Robust.Shared.Prototypes;
using System.Diagnostics.CodeAnalysis;
using System.Linq;
namespace Content.Server.Chemistry.EntitySystems
{
@@ -48,7 +47,7 @@ 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);
@@ -68,7 +67,7 @@ namespace Content.Server.Chemistry.EntitySystems
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);
@@ -131,8 +130,8 @@ namespace Content.Server.Chemistry.EntitySystems
{
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;
}
@@ -141,12 +140,12 @@ namespace Content.Server.Chemistry.EntitySystems
{
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);
}
@@ -157,7 +156,7 @@ namespace Content.Server.Chemistry.EntitySystems
{
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;
@@ -166,9 +165,9 @@ namespace Content.Server.Chemistry.EntitySystems
{
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;
@@ -211,8 +210,10 @@ namespace Content.Server.Chemistry.EntitySystems
_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;
@@ -222,13 +223,13 @@ namespace Content.Server.Chemistry.EntitySystems
{
// 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)}");
}
}
@@ -241,7 +242,8 @@ namespace Content.Server.Chemistry.EntitySystems
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
}
@@ -258,7 +260,8 @@ namespace Content.Server.Chemistry.EntitySystems
return;
_labelSystem.Label(container, message.Label);
_solutionContainerSystem.TryAddSolution(soln.Value, withdrawal);
_solutionContainerSystem.TryAddSolution(
container, solution, withdrawal);
if (user.HasValue)
{
@@ -284,7 +287,8 @@ namespace Content.Server.Chemistry.EntitySystems
{
outputSolution = null;
if (!_solutionContainerSystem.TryGetSolution(chemMaster.Owner, SharedChemMaster.BufferSolutionName, out _, out var solution))
if (!_solutionContainerSystem.TryGetSolution(
chemMaster, SharedChemMaster.BufferSolutionName, out var solution))
{
return false;
}
@@ -319,7 +323,7 @@ namespace Content.Server.Chemistry.EntitySystems
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;
}
@@ -335,7 +339,7 @@ namespace Content.Server.Chemistry.EntitySystems
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);
}
@@ -346,7 +350,7 @@ namespace Content.Server.Chemistry.EntitySystems
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();

View File

@@ -1,22 +1,21 @@
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 Content.Shared.Mobs.Components;
using Content.Shared.Stacks;
using Content.Shared.Verbs;
using Robust.Shared.GameStates;
using Content.Shared.DoAfter;
using Content.Shared.Mobs.Components;
using Content.Shared.Verbs;
using Content.Shared.Stacks;
using Robust.Shared.Player;
using Content.Shared.Forensics;
namespace Content.Server.Chemistry.EntitySystems;
@@ -26,11 +25,11 @@ public sealed partial class ChemistrySystem
/// <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);
@@ -38,7 +37,7 @@ public sealed partial class ChemistrySystem
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;
@@ -46,14 +45,11 @@ public sealed partial class ChemistrySystem
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();
@@ -62,7 +58,7 @@ public sealed partial class ChemistrySystem
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.
@@ -73,22 +69,22 @@ public sealed partial class ChemistrySystem
}
}
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
{
@@ -96,112 +92,111 @@ public sealed partial class ChemistrySystem
("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:
@@ -214,18 +209,18 @@ public sealed partial class ChemistrySystem
/// <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;
@@ -249,7 +244,7 @@ public sealed partial class ChemistrySystem
}
// 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}");
@@ -260,11 +255,11 @@ public sealed partial class ChemistrySystem
// 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,
@@ -273,80 +268,77 @@ public sealed partial class ChemistrySystem
});
}
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
@@ -354,12 +346,13 @@ public sealed partial class ChemistrySystem
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
@@ -367,68 +360,70 @@ public sealed partial class ChemistrySystem
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);
}
}

View File

@@ -1,12 +1,13 @@
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;
@@ -23,7 +24,7 @@ public sealed partial class ChemistrySystem : EntitySystem
[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()
{

View File

@@ -1,21 +1,20 @@
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
{
@@ -27,33 +26,33 @@ 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;
@@ -61,20 +60,21 @@ namespace Content.Server.Chemistry.EntitySystems
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;
@@ -92,13 +92,15 @@ namespace Content.Server.Chemistry.EntitySystems
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;
@@ -125,17 +127,17 @@ namespace Content.Server.Chemistry.EntitySystems
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);

View File

@@ -1,6 +1,10 @@
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;
@@ -11,26 +15,27 @@ public sealed partial class ChemistrySystem
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);
}
}

View File

@@ -1,5 +1,4 @@
using Content.Server.Chemistry.Components.DeleteOnSolutionEmptyComponent;
using Content.Server.Chemistry.Containers.EntitySystems;
using Content.Shared.Chemistry.Components.SolutionManager;
using Content.Shared.Chemistry.EntitySystems;
@@ -13,27 +12,27 @@ namespace Content.Server.Chemistry.EntitySystems.DeleteOnSolutionEmptySystem
{
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);
}
}
}

View File

@@ -1,6 +1,6 @@
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;
@@ -15,7 +15,6 @@ using Robust.Server.GameObjects;
using Robust.Shared.Audio;
using Robust.Shared.Containers;
using Robust.Shared.Prototypes;
using System.Linq;
namespace Content.Server.Chemistry.EntitySystems
{
@@ -37,7 +36,7 @@ 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);
@@ -69,7 +68,7 @@ namespace Content.Server.Chemistry.EntitySystems
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)
{
@@ -123,10 +122,10 @@ namespace Content.Server.Chemistry.EntitySystems
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,
@@ -140,10 +139,10 @@ namespace Content.Server.Chemistry.EntitySystems
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);
}

View File

@@ -1,5 +1,4 @@
using Content.Server.Chemistry.Components;
using Content.Server.Chemistry.Containers.EntitySystems;
using Content.Shared.Chemistry.EntitySystems;
using Content.Shared.FixedPoint;
using Content.Shared.Popups;
@@ -17,23 +16,21 @@ public sealed class RehydratableSystem : EntitySystem
{
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);

View File

@@ -1,10 +1,10 @@
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;
@@ -13,7 +13,7 @@ public sealed class SolutionHeaterSystem : EntitySystem
{
[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()
@@ -51,41 +51,41 @@ public sealed class SolutionHeaterSystem : EntitySystem
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)
@@ -97,13 +97,13 @@ public sealed class SolutionHeaterSystem : EntitySystem
{
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);
}
}
}

View File

@@ -1,17 +1,19 @@
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!;
@@ -28,7 +30,7 @@ namespace Content.Server.Chemistry.EntitySystems
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;
}
@@ -42,7 +44,7 @@ namespace Content.Server.Chemistry.EntitySystems
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);

View File

@@ -1,6 +1,7 @@
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;
@@ -29,13 +30,13 @@ public sealed class SolutionPurgeSystem : EntitySystem
// 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;
}
}

View File

@@ -1,5 +1,5 @@
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;
@@ -21,12 +21,13 @@ public sealed class SolutionRandomFillSystem : EntitySystem
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;
@@ -37,7 +38,6 @@ public sealed class SolutionRandomFillSystem : EntitySystem
return;
}
var target = _solutionsSystem.EnsureSolutionEntity(entity.Owner, entity.Comp.Solution, pick.quantity, null, out _);
_solutionsSystem.TryAddReagent(target, reagent, quantity, out _);
target.AddReagent(reagent, quantity);
}
}

View File

@@ -1,7 +1,7 @@
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;
@@ -31,7 +31,7 @@ public sealed class SolutionRegenerationSystem : EntitySystem
// 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)
@@ -48,13 +48,13 @@ public sealed class SolutionRegenerationSystem : EntitySystem
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;
}
}

View File

@@ -1,10 +1,12 @@
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;
@@ -19,7 +21,7 @@ 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!;
@@ -28,9 +30,9 @@ public sealed class SolutionSpikableSystem : EntitySystem
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>
@@ -47,8 +49,8 @@ public sealed class SolutionSpikableSystem : EntitySystem
{
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;
}
@@ -59,7 +61,7 @@ public sealed class SolutionSpikableSystem : EntitySystem
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);

View File

@@ -1,14 +1,14 @@
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
@@ -24,7 +24,7 @@ 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()
{
@@ -35,19 +35,17 @@ namespace Content.Server.Chemistry.EntitySystems
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;
@@ -58,16 +56,15 @@ namespace Content.Server.Chemistry.EntitySystems
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();
@@ -76,7 +73,7 @@ namespace Content.Server.Chemistry.EntitySystems
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.
@@ -87,19 +84,18 @@ namespace Content.Server.Chemistry.EntitySystems
}
}
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))
{
@@ -110,7 +106,7 @@ namespace Content.Server.Chemistry.EntitySystems
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;
@@ -126,8 +122,8 @@ namespace Content.Server.Chemistry.EntitySystems
}
// 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;
@@ -136,7 +132,7 @@ namespace Content.Server.Chemistry.EntitySystems
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)
{
@@ -154,9 +150,9 @@ namespace Content.Server.Chemistry.EntitySystems
/// <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);
@@ -169,8 +165,7 @@ namespace Content.Server.Chemistry.EntitySystems
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;
@@ -184,20 +179,19 @@ namespace Content.Server.Chemistry.EntitySystems
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;
}

View File

@@ -1,5 +1,4 @@
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;
@@ -17,38 +16,38 @@ public sealed class TransformableContainerSystem : EntitySystem
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;
}
@@ -57,29 +56,29 @@ public sealed class TransformableContainerSystem : EntitySystem
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);
}
}
}

View File

@@ -1,8 +1,9 @@
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;
@@ -15,7 +16,6 @@ using Robust.Shared.Physics.Events;
using Robust.Shared.Physics.Systems;
using Robust.Shared.Prototypes;
using Robust.Shared.Spawners;
using System.Numerics;
namespace Content.Server.Chemistry.EntitySystems
{
@@ -40,20 +40,19 @@ 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);
}
}
@@ -84,27 +83,28 @@ namespace Content.Server.Chemistry.EntitySystems
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)
@@ -112,7 +112,6 @@ namespace Content.Server.Chemistry.EntitySystems
vapor.ReactTimer += frameTime;
var contents = soln.Comp.Solution;
if (vapor.ReactTimer >= ReactTime && TryComp(xform.GridUid, out MapGridComponent? gridComp))
{
vapor.ReactTimer = 0;
@@ -132,7 +131,7 @@ namespace Content.Server.Chemistry.EntitySystems
reaction = reagentQuantity.Quantity;
}
_solutionContainerSystem.RemoveReagent(soln, reagentQuantity.Reagent, reaction);
_solutionContainerSystem.RemoveReagent(entity, contents, reagentQuantity.Reagent, reaction);
}
}

View File

@@ -1,5 +1,6 @@
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;
@@ -29,7 +30,7 @@ namespace Content.Server.Chemistry.ReactionEffects
/// <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.
@@ -55,7 +56,7 @@ namespace Content.Server.Chemistry.ReactionEffects
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>();

View File

@@ -11,13 +11,13 @@ public sealed partial class CreateEntityReactionEffect : ReagentEffect
/// <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)

View File

@@ -23,7 +23,7 @@ public sealed partial class EmpReactionEffect : ReagentEffect
/// <summary>
/// How much energy will be drain from sources
/// </summary>
[DataField]
[DataField("energyConsumption")]
public float EnergyConsumption = 12500;
/// <summary>

View File

@@ -1,10 +1,10 @@
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
{
@@ -14,7 +14,7 @@ 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!;
@@ -22,14 +22,14 @@ namespace Content.Server.Chemistry.ReactionEffects
/// 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;
@@ -40,14 +40,14 @@ namespace Content.Server.Chemistry.ReactionEffects
/// <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;

View File

@@ -0,0 +1 @@


View File

@@ -1,5 +1,7 @@
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
{
@@ -119,3 +121,5 @@ namespace Content.Server.Chemistry.ReactionEffects
}
}

View File

@@ -10,10 +10,10 @@ namespace Content.Server.Chemistry.ReagentEffectConditions
/// </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)
{

View File

@@ -9,10 +9,10 @@ namespace Content.Server.Chemistry.ReagentEffectConditions;
[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)

View File

@@ -7,14 +7,16 @@ namespace Content.Server.Chemistry.ReagentEffectConditions
{
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;
}
@@ -23,7 +25,7 @@ namespace Content.Server.Chemistry.ReagentEffectConditions
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));
}
}
}

View File

@@ -11,13 +11,13 @@ namespace Content.Server.Chemistry.ReagentEffectConditions
/// </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)

View File

@@ -13,14 +13,14 @@ namespace Content.Server.Chemistry.ReagentEffectConditions
/// </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)

View File

@@ -9,10 +9,10 @@ namespace Content.Server.Chemistry.ReagentEffectConditions
/// </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)
{

View File

@@ -7,10 +7,10 @@ namespace Content.Server.Chemistry.ReagentEffectConditions
{
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)

View File

@@ -1,4 +1,4 @@
using Content.Server.Chemistry.Containers.EntitySystems;
using Content.Shared.Chemistry.EntitySystems;
using Content.Shared.Chemistry.Reagent;
using JetBrains.Annotations;
using Robust.Shared.Prototypes;
@@ -17,11 +17,12 @@ namespace Content.Server.Chemistry.ReagentEffects
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);
}

View File

@@ -10,13 +10,13 @@ public sealed partial class AdjustAlert : ReagentEffect
[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.

View File

@@ -1,4 +1,5 @@
using Content.Shared.Body.Prototypes;
using Content.Shared.Chemistry.EntitySystems;
using Content.Shared.Chemistry.Reagent;
using Content.Shared.FixedPoint;
using JetBrains.Annotations;
@@ -13,7 +14,7 @@ namespace Content.Server.Chemistry.ReagentEffects
/// <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
@@ -21,39 +22,41 @@ namespace Content.Server.Chemistry.ReagentEffects
/// 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;
var amount = Amount;
amount *= args.Scale;
if (Reagent != null)
if (args.Source != 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())
var solutionSys = args.EntityManager.EntitySysManager.GetEntitySystem<SolutionContainerSystem>();
var amount = Amount;
amount *= args.Scale;
if (Reagent != null)
{
var proto = prototypeMan.Index<ReagentPrototype>(quant.Reagent.Prototype);
if (proto.Metabolisms != null && proto.Metabolisms.ContainsKey(Group))
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 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 _);
}
}
}
}

View File

@@ -7,7 +7,7 @@ namespace Content.Server.Chemistry.ReagentEffects
{
public sealed partial class AdjustTemperature : ReagentEffect
{
[DataField]
[DataField("amount")]
public float Amount;
protected override string? ReagentEffectGuidebookText(IPrototypeManager prototype, IEntitySystemManager entSys)

View File

@@ -1,8 +1,10 @@
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

View File

@@ -1,6 +1,6 @@
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
@@ -11,7 +11,7 @@ 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)

View File

@@ -15,7 +15,7 @@ namespace Content.Server.Chemistry.ReagentEffects
/// <summary>
/// How much eye damage to add.
/// </summary>
[DataField]
[DataField("amount")]
public int Amount = -1;
protected override string? ReagentEffectGuidebookText(IPrototypeManager prototype, IEntitySystemManager entSys)

View File

@@ -1,5 +1,5 @@
using Content.Server.Medical;
using Content.Shared.Chemistry.Reagent;
using Content.Server.Medical;
using JetBrains.Annotations;
using Robust.Shared.Prototypes;
@@ -12,10 +12,10 @@ namespace Content.Server.Chemistry.ReagentEffects
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)

View File

@@ -8,13 +8,13 @@ namespace Content.Server.Chemistry.ReagentEffects;
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;

View File

@@ -1,13 +1,14 @@
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)

View File

@@ -9,13 +9,13 @@ public sealed partial class Drunk : ReagentEffect
/// <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)

View File

@@ -6,14 +6,14 @@ namespace Content.Server.Chemistry.ReagentEffects;
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));

View File

@@ -16,7 +16,7 @@ public sealed partial class Emote : ReagentEffect
[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.

View File

@@ -10,7 +10,7 @@ namespace Content.Server.Chemistry.ReagentEffects
[UsedImplicitly]
public sealed partial class FlammableReaction : ReagentEffect
{
[DataField]
[DataField("multiplier")]
public float Multiplier = 0.05f;
public override bool ShouldLog => true;

View File

@@ -1,3 +1,5 @@
using System.Linq;
using System.Text.Json.Serialization;
using Content.Shared.Chemistry.Reagent;
using Content.Shared.Damage;
using Content.Shared.Damage.Prototypes;
@@ -5,8 +7,6 @@ using Content.Shared.FixedPoint;
using Content.Shared.Localizations;
using JetBrains.Annotations;
using Robust.Shared.Prototypes;
using System.Linq;
using System.Text.Json.Serialization;
namespace Content.Server.Chemistry.ReagentEffects
{
@@ -19,19 +19,19 @@ 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;

View File

@@ -7,10 +7,10 @@ namespace Content.Server.Chemistry.ReagentEffects;
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)

View File

@@ -8,10 +8,10 @@ namespace Content.Server.Chemistry.ReagentEffects;
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)

View File

@@ -15,19 +15,19 @@ namespace Content.Server.Chemistry.ReagentEffects
/// <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)

View File

@@ -7,7 +7,7 @@ namespace Content.Server.Chemistry.ReagentEffects;
public sealed partial class Oxygenate : ReagentEffect
{
[DataField]
[DataField("factor")]
public float Factor = 1f;
// JUSTIFICATION: This is internal magic that players never directly interact with.

View File

@@ -1,17 +1,17 @@
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",

View File

@@ -1,19 +1,16 @@
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.

View File

@@ -11,13 +11,13 @@ namespace Content.Server.Chemistry.ReagentEffects.PlantMetabolism
[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)

View File

@@ -8,13 +8,13 @@ namespace Content.Server.Chemistry.ReagentEffects
{
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.

View File

@@ -17,25 +17,25 @@ namespace Content.Server.Chemistry.ReagentEffects.StatusEffects
[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)

View File

@@ -11,19 +11,19 @@ namespace Content.Server.Chemistry.ReagentEffects.StatusEffects
/// </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)

View File

@@ -1,3 +1,4 @@
using System.Numerics;
using Content.Server.Decals;
using Content.Shared.Chemistry.Reaction;
using Content.Shared.Chemistry.Reagent;
@@ -5,7 +6,6 @@ using Content.Shared.Decals;
using Content.Shared.FixedPoint;
using Robust.Shared.Map;
using Robust.Shared.Map.Components;
using System.Numerics;
namespace Content.Server.Chemistry.TileReactions;
@@ -18,7 +18,7 @@ public sealed partial class CleanDecalsReaction : ITileReaction
/// <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)

View File

@@ -1,12 +1,12 @@
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;
@@ -28,7 +28,7 @@ public sealed partial class CleanTileReaction : ITileReaction
/// <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)
@@ -43,16 +43,17 @@ public sealed partial class CleanTileReaction : ITileReaction
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;

View File

@@ -1,4 +1,5 @@
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;
@@ -7,23 +8,22 @@ using Robust.Shared.Map;
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>
@@ -32,7 +32,7 @@ public sealed partial class CreateEntityTileReaction : ITileReaction
[DataField("maxOnTileWhitelist")]
public EntityWhitelist? Whitelist;
[DataField]
[DataField("randomOffsetMax")]
public float RandomOffsetMax = 0.0f;
public FixedPoint2 TileReact(TileRef tile, ReagentPrototype reagent, FixedPoint2 reactVolume)