+++ /dev/null
-using Content.Shared.Chemistry.Components;
-using Content.Shared.Chemistry.Reaction;
-using Content.Shared.DoAfter;
-using Content.Shared.IdentityManagement;
-using Content.Shared.Interaction;
-using Content.Shared.Nutrition.EntitySystems;
-using Content.Shared.Chemistry.EntitySystems;
-using Content.Server.Popups;
-
-namespace Content.Server.Chemistry.EntitySystems;
-
-public sealed partial class ReactionMixerSystem : EntitySystem
-{
- [Dependency] private readonly PopupSystem _popup = default!;
- [Dependency] private readonly SharedSolutionContainerSystem _solutionContainers = default!;
- [Dependency] private readonly SharedDoAfterSystem _doAfterSystem = default!;
-
- public override void Initialize()
- {
- base.Initialize();
-
- SubscribeLocalEvent<ReactionMixerComponent, AfterInteractEvent>(OnAfterInteract, before: [typeof(IngestionSystem)]);
- SubscribeLocalEvent<ReactionMixerComponent, ShakeEvent>(OnShake);
- SubscribeLocalEvent<ReactionMixerComponent, ReactionMixDoAfterEvent>(OnDoAfter);
- }
-
- private void OnAfterInteract(Entity<ReactionMixerComponent> entity, ref AfterInteractEvent args)
- {
- if (!args.Target.HasValue || !args.CanReach || !entity.Comp.MixOnInteract)
- return;
-
- if (!MixAttempt(entity, args.Target.Value, out _))
- return;
-
- var doAfterArgs = new DoAfterArgs(EntityManager, args.User, entity.Comp.TimeToMix, new ReactionMixDoAfterEvent(), entity, args.Target.Value, entity);
-
- _doAfterSystem.TryStartDoAfter(doAfterArgs);
- args.Handled = true;
- }
-
- private void OnDoAfter(Entity<ReactionMixerComponent> entity, ref ReactionMixDoAfterEvent args)
- {
- //Do again to get the solution again
- if (!MixAttempt(entity, args.Target!.Value, out var 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);
-
- _solutionContainers.UpdateChemicals(solution!.Value, true, entity.Comp);
-
- var afterMixingEvent = new AfterMixingEvent(entity, args.Target!.Value);
- RaiseLocalEvent(entity, afterMixingEvent);
- }
-
- private void OnShake(Entity<ReactionMixerComponent> entity, ref ShakeEvent args)
- {
- if (!MixAttempt(entity, entity, out var solution))
- return;
-
- _solutionContainers.UpdateChemicals(solution!.Value, true, entity.Comp);
-
- var afterMixingEvent = new AfterMixingEvent(entity, entity);
- RaiseLocalEvent(entity, afterMixingEvent);
- }
-
- private bool MixAttempt(EntityUid ent, EntityUid target, out Entity<SolutionComponent>? solution)
- {
- solution = null;
- var mixAttemptEvent = new MixingAttemptEvent(ent);
- RaiseLocalEvent(ent, ref mixAttemptEvent);
- if (mixAttemptEvent.Cancelled)
- {
- return false;
- }
-
- if (!_solutionContainers.TryGetMixableSolution(target, out solution, out _))
- return false;
-
- return true;
- }
-}
-using Content.Shared.Chemistry.Components;
using Content.Shared.DoAfter;
+using Robust.Shared.GameStates;
using Robust.Shared.Prototypes;
using Robust.Shared.Serialization;
namespace Content.Shared.Chemistry.Reaction;
-[RegisterComponent]
+[RegisterComponent, NetworkedComponent, AutoGenerateComponentState]
public sealed partial class ReactionMixerComponent : Component
{
/// <summary>
- /// A list of IDs for categories of reactions that can be mixed (i.e. HOLY for a bible, DRINK for a spoon)
+ /// A list of IDs for categories of reactions that can be mixed (i.e. HOLY for a bible, DRINK for a spoon).
/// </summary>
- [ViewVariables]
- [DataField]
- public List<ProtoId<MixingCategoryPrototype>> ReactionTypes = default!;
+ [DataField, AutoNetworkedField]
+ public List<ProtoId<MixingCategoryPrototype>> ReactionTypes = new();
/// <summary>
- /// A string which identifies the string to be sent when successfully mixing a solution
+ /// The popup message when successfully mixing a solution.
/// </summary>
- [ViewVariables]
- [DataField]
+ [DataField, AutoNetworkedField]
public LocId MixMessage = "default-mixing-success";
/// <summary>
- /// Defines if interacting is enough to mix with this component
+ /// Defines if interacting is enough to mix with this component.
/// </summary>
- [ViewVariables]
- [DataField]
+ [DataField, AutoNetworkedField]
public bool MixOnInteract = true;
/// <summary>
- /// How long it takes to mix with this
+ /// How long it takes to mix with this.
/// </summary>
- [ViewVariables]
- [DataField]
+ [DataField, AutoNetworkedField]
public TimeSpan TimeToMix = TimeSpan.Zero;
}
[ByRefEvent]
public record struct MixingAttemptEvent(EntityUid Mixed, bool Cancelled = false);
+[ByRefEvent]
public readonly record struct AfterMixingEvent(EntityUid Mixed, EntityUid Mixer);
[Serializable, NetSerializable]
-public sealed partial class ReactionMixDoAfterEvent : SimpleDoAfterEvent
-{
-}
+public sealed partial class ReactionMixDoAfterEvent : SimpleDoAfterEvent;
--- /dev/null
+using Content.Shared.Chemistry.Components;
+using Content.Shared.DoAfter;
+using Content.Shared.IdentityManagement;
+using Content.Shared.Interaction;
+using Content.Shared.Nutrition.EntitySystems;
+using Content.Shared.Chemistry.EntitySystems;
+using Content.Shared.Popups;
+
+namespace Content.Shared.Chemistry.Reaction;
+
+public sealed partial class ReactionMixerSystem : EntitySystem
+{
+ [Dependency] private readonly SharedPopupSystem _popup = default!;
+ [Dependency] private readonly SharedSolutionContainerSystem _solutionContainer = default!;
+ [Dependency] private readonly SharedDoAfterSystem _doAfter = default!;
+
+ public override void Initialize()
+ {
+ base.Initialize();
+
+ SubscribeLocalEvent<ReactionMixerComponent, AfterInteractEvent>(OnAfterInteract, before: [typeof(IngestionSystem)]);
+ SubscribeLocalEvent<ReactionMixerComponent, ShakeEvent>(OnShake);
+ SubscribeLocalEvent<ReactionMixerComponent, ReactionMixDoAfterEvent>(OnDoAfter);
+ }
+
+ private void OnAfterInteract(Entity<ReactionMixerComponent> ent, ref AfterInteractEvent args)
+ {
+ if (!args.Target.HasValue || !args.CanReach || !ent.Comp.MixOnInteract)
+ return;
+
+ if (!CanMix(ent.AsNullable(), args.Target.Value))
+ return;
+
+ var doAfterArgs = new DoAfterArgs(EntityManager, args.User, ent.Comp.TimeToMix, new ReactionMixDoAfterEvent(), ent, args.Target.Value, ent);
+
+ _doAfter.TryStartDoAfter(doAfterArgs);
+ args.Handled = true;
+ }
+
+ private void OnDoAfter(Entity<ReactionMixerComponent> ent, ref ReactionMixDoAfterEvent args)
+ {
+ if (args.Target == null)
+ return;
+
+ if (!TryMix(ent.AsNullable(), args.Target.Value))
+ return;
+
+ _popup.PopupClient(
+ Loc.GetString(
+ ent.Comp.MixMessage,
+ ("mixed", Identity.Entity(args.Target.Value, EntityManager)),
+ ("mixer", Identity.Entity(ent.Owner, EntityManager))),
+ args.User,
+ args.User);
+ }
+
+ private void OnShake(Entity<ReactionMixerComponent> ent, ref ShakeEvent args)
+ {
+ TryMix(ent.AsNullable(), ent);
+ }
+
+ /// <summary>
+ /// Returns true if given reaction mixer is able to mix the solution inside the target entity, false otherwise.
+ /// </summary>
+ /// <param name="ent">The reaction mixer used to cause the reaction.</param>
+ /// <param name="target">The target solution container with a <see cref="MixableSolutionComponent"/>.</param>
+ public bool CanMix(Entity<ReactionMixerComponent?> ent, EntityUid target)
+ {
+ if (!Resolve(ent, ref ent.Comp, false)) // The used entity needs the component to be able to mix a solution
+ return false;
+
+ var mixAttemptEvent = new MixingAttemptEvent(ent);
+ RaiseLocalEvent(ent, ref mixAttemptEvent);
+ if (mixAttemptEvent.Cancelled)
+ return false;
+
+ if (!_solutionContainer.TryGetMixableSolution(target, out _, out _))
+ return false;
+
+ return true;
+ }
+
+ /// <summary>
+ /// Attempts to mix the solution inside the target entity using the given reaction mixer.
+ /// </summary>
+ /// <param name="ent">The reaction mixer used to cause the reaction.</param>
+ /// <param name="target">The target solution container with a <see cref="MixableSolutionComponent"/>.</param>
+ /// <returns>If the reaction mixer was able to mix the solution. This does not necessarily mean a reaction took place.</returns>
+ public bool TryMix(Entity<ReactionMixerComponent?> ent, EntityUid target)
+ {
+ if (!Resolve(ent, ref ent.Comp, false))
+ return false;
+
+ var mixAttemptEvent = new MixingAttemptEvent(ent);
+ RaiseLocalEvent(ent, ref mixAttemptEvent);
+ if (mixAttemptEvent.Cancelled)
+ return false;
+
+ if (!_solutionContainer.TryGetMixableSolution(target, out var solutionEnt, out _))
+ return false;
+
+ _solutionContainer.UpdateChemicals(solutionEnt.Value, true, ent.Comp);
+
+ var afterMixingEvent = new AfterMixingEvent(ent, target);
+ RaiseLocalEvent(ent, ref afterMixingEvent);
+
+ return true;
+ }
+}