diff --git a/Content.Server/Chemistry/Components/HyposprayComponent.cs b/Content.Server/Chemistry/Components/HyposprayComponent.cs index 223ebf0e0c..4877367cca 100644 --- a/Content.Server/Chemistry/Components/HyposprayComponent.cs +++ b/Content.Server/Chemistry/Components/HyposprayComponent.cs @@ -106,7 +106,7 @@ namespace Content.Server.Chemistry.Components return true; } - removedSolution.DoEntityReaction(target, ReactionMethod.Injection); + removedSolution.DoEntityReaction(target.Uid, ReactionMethod.Injection); EntitySystem.Get().TryAddSolution(target.Uid, targetSolution, removedSolution); diff --git a/Content.Server/Chemistry/Components/InjectorComponent.cs b/Content.Server/Chemistry/Components/InjectorComponent.cs index 54b0baefb5..b8ae14ae6e 100644 --- a/Content.Server/Chemistry/Components/InjectorComponent.cs +++ b/Content.Server/Chemistry/Components/InjectorComponent.cs @@ -201,11 +201,11 @@ namespace Content.Server.Chemistry.Components // TODO: Account for partial transfer. var bloodsStreamEntity = Owner.EntityManager.GetEntity(user.Uid); - removedSolution.DoEntityReaction(bloodsStreamEntity, ReactionMethod.Injection); + removedSolution.DoEntityReaction(bloodsStreamEntity.Uid, ReactionMethod.Injection); EntitySystem.Get().TryAddSolution(user.Uid, bloodstream, removedSolution); - removedSolution.DoEntityReaction(targetBloodstream.Owner, ReactionMethod.Injection); + removedSolution.DoEntityReaction(targetBloodstream.Owner.Uid, ReactionMethod.Injection); Owner.PopupMessage(user, Loc.GetString("injector-component-inject-success-message", @@ -236,7 +236,7 @@ namespace Content.Server.Chemistry.Components // Move units from attackSolution to targetSolution var removedSolution = EntitySystem.Get().SplitSolution(Owner.Uid, solution, realTransferAmount); - removedSolution.DoEntityReaction(targetEntity, ReactionMethod.Injection); + removedSolution.DoEntityReaction(targetEntity.Uid, ReactionMethod.Injection); if (!asRefill) { diff --git a/Content.Server/Chemistry/Components/SmokeSolutionAreaEffectComponent.cs b/Content.Server/Chemistry/Components/SmokeSolutionAreaEffectComponent.cs index f1dc187bb7..e57190369c 100644 --- a/Content.Server/Chemistry/Components/SmokeSolutionAreaEffectComponent.cs +++ b/Content.Server/Chemistry/Components/SmokeSolutionAreaEffectComponent.cs @@ -46,7 +46,7 @@ namespace Content.Server.Chemistry.Components foreach (var reagentQuantity in transferSolution.Contents.ToArray()) { if (reagentQuantity.Quantity == FixedPoint2.Zero) continue; - chemistry.ReactionEntity(entity, ReactionMethod.Ingestion, reagentQuantity.ReagentId, reagentQuantity.Quantity, transferSolution); + chemistry.ReactionEntity(entity.Uid, ReactionMethod.Ingestion, reagentQuantity.ReagentId, reagentQuantity.Quantity, transferSolution); } bloodstream.TryTransferSolution(transferSolution); diff --git a/Content.Server/Chemistry/Components/SolutionAreaEffectComponent.cs b/Content.Server/Chemistry/Components/SolutionAreaEffectComponent.cs index 1fee4a57a0..eb803d7df6 100644 --- a/Content.Server/Chemistry/Components/SolutionAreaEffectComponent.cs +++ b/Content.Server/Chemistry/Components/SolutionAreaEffectComponent.cs @@ -143,7 +143,7 @@ namespace Content.Server.Chemistry.Components // Touch every entity on the tile foreach (var entity in tile.GetEntitiesInTileFast().ToArray()) { - chemistry.ReactionEntity(entity, ReactionMethod.Touch, reagent, + chemistry.ReactionEntity(entity.Uid, ReactionMethod.Touch, reagent, reagentQuantity.Quantity * solutionFraction, solution); } } diff --git a/Content.Server/Chemistry/EntitySystems/VaporSystem.cs b/Content.Server/Chemistry/EntitySystems/VaporSystem.cs index f3cb54896d..a552c69983 100644 --- a/Content.Server/Chemistry/EntitySystems/VaporSystem.cs +++ b/Content.Server/Chemistry/EntitySystems/VaporSystem.cs @@ -36,7 +36,7 @@ namespace Content.Server.Chemistry.EntitySystems foreach (var (_, value) in contents.Solutions) { - value.DoEntityReaction(args.OtherFixture.Body.Owner, ReactionMethod.Touch); + value.DoEntityReaction(args.OtherFixture.Body.Owner.Uid, ReactionMethod.Touch); } // Check for collision with a impassable object (e.g. wall) and stop diff --git a/Content.Server/Fluids/Components/SpillExtensions.cs b/Content.Server/Fluids/Components/SpillExtensions.cs index 9b515efbad..bbb33c04b3 100644 --- a/Content.Server/Fluids/Components/SpillExtensions.cs +++ b/Content.Server/Fluids/Components/SpillExtensions.cs @@ -13,6 +13,7 @@ using Robust.Shared.Map; namespace Content.Server.Fluids.Components { + // TODO: Kill these with fire public static class SpillExtensions { /// @@ -31,6 +32,25 @@ namespace Content.Server.Fluids.Components return solution.SpillAt(entity.Transform.Coordinates, prototype, sound); } + /// + /// Spills the specified solution at the entity's location if possible. + /// + /// + /// The entity to use as a location to spill the solution at. + /// + /// Initial solution for the prototype. + /// The prototype to use. + /// Play the spill sound. + /// + /// The puddle if one was created, null otherwise. + public static PuddleComponent? SpillAt(this Solution solution, EntityUid entity, string prototype, + bool sound = true, IEntityManager? entityManager = null) + { + entityManager ??= IoCManager.Resolve(); + + return solution.SpillAt(entityManager.GetComponent(entity).Coordinates, prototype, sound); + } + /// /// Spills the specified solution at the entity's location if possible. /// diff --git a/Content.Server/Nutrition/Components/FoodComponent.cs b/Content.Server/Nutrition/Components/FoodComponent.cs index 2bebd99b09..c12beb98f2 100644 --- a/Content.Server/Nutrition/Components/FoodComponent.cs +++ b/Content.Server/Nutrition/Components/FoodComponent.cs @@ -176,7 +176,7 @@ namespace Content.Server.Nutrition.Components // TODO: Account for partial transfer. - split.DoEntityReaction(trueTarget, ReactionMethod.Ingestion); + split.DoEntityReaction(trueTarget.Uid, ReactionMethod.Ingestion); firstStomach.TryTransferSolution(split); diff --git a/Content.Server/Nutrition/EntitySystems/DrinkSystem.cs b/Content.Server/Nutrition/EntitySystems/DrinkSystem.cs index 679e3c3a15..85df2a1640 100644 --- a/Content.Server/Nutrition/EntitySystems/DrinkSystem.cs +++ b/Content.Server/Nutrition/EntitySystems/DrinkSystem.cs @@ -4,6 +4,7 @@ using Content.Server.Chemistry.Components.SolutionManager; using Content.Server.Chemistry.EntitySystems; using Content.Server.Fluids.Components; using Content.Server.Nutrition.Components; +using Content.Server.Popups; using Content.Shared.Body.Components; using Content.Shared.Chemistry.Reagent; using Content.Shared.Examine; @@ -29,6 +30,7 @@ namespace Content.Server.Nutrition.EntitySystems { [Dependency] private readonly IRobustRandom _random = default!; [Dependency] private readonly SolutionContainerSystem _solutionContainerSystem = default!; + [Dependency] private readonly PopupSystem _popupSystem = default!; public override void Initialize() { @@ -104,7 +106,7 @@ namespace Content.Server.Nutrition.EntitySystems if (args.Target == null) return; - if (TryUseDrink(uid, args.User, args.Target, true, component)) + if (TryUseDrink(uid, args.User.Uid, args.Target.Uid, true, component)) args.Handled = true; } @@ -126,7 +128,7 @@ namespace Content.Server.Nutrition.EntitySystems return; } - if (TryUseDrink(uid, args.User, args.User, false, component)) + if (TryUseDrink(uid, args.User.Uid, args.User.Uid, false, component)) args.Handled = true; } @@ -184,7 +186,7 @@ namespace Content.Server.Nutrition.EntitySystems appearance.SetData(DrinkCanStateVisual.Opened, component.Opened); } - private bool TryUseDrink(EntityUid uid, IEntity user, IEntity target, bool forced, DrinkComponent? component = null) + private bool TryUseDrink(EntityUid uid, EntityUid userUid, EntityUid targetUid, bool forced, DrinkComponent? component = null) { if(!Resolve(uid, ref component)) return false; @@ -193,7 +195,7 @@ namespace Content.Server.Nutrition.EntitySystems if (!component.Opened) { - target.PopupMessage(Loc.GetString("drink-component-try-use-drink-not-open", ("owner", owner))); + _popupSystem.PopupEntity(Loc.GetString("drink-component-try-use-drink-not-open", ("owner", owner)), targetUid, Filter.Entities(userUid)); return false; } @@ -202,20 +204,20 @@ namespace Content.Server.Nutrition.EntitySystems { if (!forced) { - target.PopupMessage(Loc.GetString("drink-component-try-use-drink-is-empty", ("entity", owner))); + _popupSystem.PopupEntity(Loc.GetString("drink-component-try-use-drink-is-empty", ("entity", owner)), targetUid, Filter.Entities(userUid)); } return false; } - if (!EntityManager.TryGetComponent(target.Uid, out SharedBodyComponent? body) || + if (!EntityManager.TryGetComponent(targetUid, out SharedBodyComponent? body) || !body.TryGetMechanismBehaviors(out var stomachs)) { - target.PopupMessage(Loc.GetString("drink-component-try-use-drink-cannot-drink", ("owner", owner))); + _popupSystem.PopupEntity(Loc.GetString("drink-component-try-use-drink-cannot-drink", ("owner", owner)), targetUid, Filter.Entities(targetUid)); return false; } - if (user != target && !user.InRangeUnobstructed(target, popup: true)) + if (userUid != targetUid && !userUid.InRangeUnobstructed(targetUid, popup: true)) return false; var transferAmount = FixedPoint2.Min(component.TransferAmount, interactions.DrainAvailable); @@ -225,11 +227,11 @@ namespace Content.Server.Nutrition.EntitySystems // All stomach are full or can't handle whatever solution we have. if (firstStomach == null) { - target.PopupMessage(Loc.GetString("drink-component-try-use-drink-had-enough", ("owner", owner))); + _popupSystem.PopupEntity(Loc.GetString("drink-component-try-use-drink-had-enough", ("owner", owner)), targetUid, Filter.Entities(targetUid)); if (EntityManager.HasComponent(uid)) { - drain.SpillAt(target, "PuddleSmear"); + drain.SpillAt(targetUid, "PuddleSmear"); return false; } @@ -237,13 +239,13 @@ namespace Content.Server.Nutrition.EntitySystems return false; } - SoundSystem.Play(Filter.Pvs(target), component.UseSound.GetSound(), target, AudioParams.Default.WithVolume(-2f)); + SoundSystem.Play(Filter.Pvs(targetUid), component.UseSound.GetSound(), targetUid, AudioParams.Default.WithVolume(-2f)); - target.PopupMessage(Loc.GetString("drink-component-try-use-drink-success-slurp")); + _popupSystem.PopupEntity(Loc.GetString("drink-component-try-use-drink-success-slurp"), targetUid, Filter.Pvs(targetUid)); // TODO: Account for partial transfer. - drain.DoEntityReaction(target, ReactionMethod.Ingestion); + drain.DoEntityReaction(targetUid, ReactionMethod.Ingestion); firstStomach.TryTransferSolution(drain); diff --git a/Content.Server/Nutrition/EntitySystems/SmokingSystem.cs b/Content.Server/Nutrition/EntitySystems/SmokingSystem.cs index e000e8cdc2..26563ed29a 100644 --- a/Content.Server/Nutrition/EntitySystems/SmokingSystem.cs +++ b/Content.Server/Nutrition/EntitySystems/SmokingSystem.cs @@ -98,7 +98,7 @@ namespace Content.Server.Nutrition.EntitySystems !containerManager.Owner.TryGetComponent(out BloodstreamComponent? bloodstream)) continue; - _chemistrySystem.ReactionEntity(containerManager.Owner, ReactionMethod.Ingestion, inhaledSolution); + _chemistrySystem.ReactionEntity(containerManager.Owner.Uid, ReactionMethod.Ingestion, inhaledSolution); bloodstream.TryTransferSolution(inhaledSolution); } diff --git a/Content.Shared/Chemistry/ChemistrySystem.cs b/Content.Shared/Chemistry/ChemistrySystem.cs index 12373135e2..6036bafdcb 100644 --- a/Content.Shared/Chemistry/ChemistrySystem.cs +++ b/Content.Shared/Chemistry/ChemistrySystem.cs @@ -14,30 +14,30 @@ namespace Content.Shared.Chemistry { [Dependency] private readonly IPrototypeManager _prototypeManager = default!; - public void ReactionEntity(IEntity entity, ReactionMethod method, Solution solution) + public void ReactionEntity(EntityUid uid, ReactionMethod method, Solution solution) { foreach (var (id, quantity) in solution) { - ReactionEntity(entity, method, id, quantity, solution); + ReactionEntity(uid, method, id, quantity, solution); } } - public void ReactionEntity(IEntity entity, ReactionMethod method, string reagentId, FixedPoint2 reactVolume, Solution? source) + public void ReactionEntity(EntityUid uid, ReactionMethod method, string reagentId, FixedPoint2 reactVolume, Solution? source) { // We throw if the reagent specified doesn't exist. - ReactionEntity(entity, method, _prototypeManager.Index(reagentId), reactVolume, source); + ReactionEntity(uid, method, _prototypeManager.Index(reagentId), reactVolume, source); } - public void ReactionEntity(IEntity entity, ReactionMethod method, ReagentPrototype reagent, + public void ReactionEntity(EntityUid uid, ReactionMethod method, ReagentPrototype reagent, FixedPoint2 reactVolume, Solution? source) { - if (entity == null || entity.Deleted || !entity.TryGetComponent(out ReactiveComponent? reactive)) + if (!EntityManager.TryGetComponent(uid, out ReactiveComponent? reactive)) return; foreach (var reaction in reactive.Reactions) { // If we have a source solution, use the reagent quantity we have left. Otherwise, use the reaction volume specified. - reaction.React(method, entity.Uid, reagent, source?.GetReagentQuantity(reagent.ID) ?? reactVolume, source, EntityManager); + reaction.React(method, uid, reagent, source?.GetReagentQuantity(reagent.ID) ?? reactVolume, source, EntityManager); // Make sure we still have enough reagent to go... if (source != null && !source.ContainsReagent(reagent.ID)) diff --git a/Content.Shared/Chemistry/Components/Solution.cs b/Content.Shared/Chemistry/Components/Solution.cs index 3a11c7e584..885e960e03 100644 --- a/Content.Shared/Chemistry/Components/Solution.cs +++ b/Content.Shared/Chemistry/Components/Solution.cs @@ -28,7 +28,7 @@ namespace Content.Shared.Chemistry.Components [ViewVariables] [DataField("reagents")] public List Contents = new(2); - + /// /// The calculated total volume of all reagents in the solution (ex. Total volume of liquid in beaker). /// @@ -332,13 +332,13 @@ namespace Content.Shared.Chemistry.Components return newSolution; } - public void DoEntityReaction(IEntity entity, ReactionMethod method) + public void DoEntityReaction(EntityUid uid, ReactionMethod method) { var chemistry = EntitySystem.Get(); foreach (var (reagentId, quantity) in Contents.ToArray()) { - chemistry.ReactionEntity(entity, method, reagentId, quantity, this); + chemistry.ReactionEntity(uid, method, reagentId, quantity, this); } } diff --git a/Content.Shared/Interaction/Helpers/SharedUnobstructedExtensions.cs b/Content.Shared/Interaction/Helpers/SharedUnobstructedExtensions.cs index 691943ab69..b54670ab18 100644 --- a/Content.Shared/Interaction/Helpers/SharedUnobstructedExtensions.cs +++ b/Content.Shared/Interaction/Helpers/SharedUnobstructedExtensions.cs @@ -8,6 +8,7 @@ using static Content.Shared.Interaction.SharedInteractionSystem; namespace Content.Shared.Interaction.Helpers { + // TODO: Kill these with fire. public static class SharedUnobstructedExtensions { private static SharedInteractionSystem SharedInteractionSystem => EntitySystem.Get(); @@ -26,6 +27,22 @@ namespace Content.Shared.Interaction.Helpers ignoreInsideBlocker, popup); } + public static bool InRangeUnobstructed( + this EntityUid origin, + EntityUid other, + float range = InteractionRange, + CollisionGroup collisionMask = CollisionGroup.Impassable, + Ignored? predicate = null, + bool ignoreInsideBlocker = false, + bool popup = false, + IEntityManager? entityManager = null) + { + entityManager ??= IoCManager.Resolve(); + + return InRangeUnobstructed(entityManager.GetEntity(origin), entityManager.GetEntity(other), + range, collisionMask, predicate, ignoreInsideBlocker, popup); + } + public static bool InRangeUnobstructed( this IEntity origin, IComponent other,