diff --git a/Content.Server/_White/AutoRegenReagent/AutoRegenReagentComponent.cs b/Content.Server/_White/AutoRegenReagent/AutoRegenReagentComponent.cs new file mode 100644 index 0000000000..65eac36ab6 --- /dev/null +++ b/Content.Server/_White/AutoRegenReagent/AutoRegenReagentComponent.cs @@ -0,0 +1,33 @@ +using Content.Shared.Chemistry.Components; +using Content.Shared.Chemistry.Reagent; +using Robust.Shared.Serialization.TypeSerializers.Implementations.Custom; + +namespace Content.Server._White.AutoRegenReagent +{ + [RegisterComponent] + public sealed partial class AutoRegenReagentComponent : Component + { + [DataField("solution", required: true)] + public string? SolutionName = null; // we'll fail during tests otherwise + + [DataField("reagents", required: true)] + public List Reagents = default!; + + [DataField] + public string CurrentReagent = ""; + + [DataField] + public int CurrentIndex = 0; + + public Entity? Solution = default!; + + [DataField("interval")] + public TimeSpan Interval = TimeSpan.FromSeconds(10); + + [DataField(customTypeSerializer: typeof(TimeOffsetSerializer))] + public TimeSpan NextUpdate; + + [DataField("unitsPerInterval")] + public float UnitsPerInterval = 1f; + } +} diff --git a/Content.Server/_White/AutoRegenReagent/AutoRegenReagentSystem.cs b/Content.Server/_White/AutoRegenReagent/AutoRegenReagentSystem.cs new file mode 100644 index 0000000000..267842b087 --- /dev/null +++ b/Content.Server/_White/AutoRegenReagent/AutoRegenReagentSystem.cs @@ -0,0 +1,127 @@ +using Content.Server.Chemistry.Containers.EntitySystems; +using Content.Server.Chemistry.EntitySystems; +using Content.Server.Popups; +using Content.Shared.Examine; +using Content.Shared.Interaction.Events; +using Content.Shared.Verbs; +using Robust.Shared.Timing; + +namespace Content.Server._White.AutoRegenReagent +{ + /// + /// So we have a solution name in AutoRegenReagent comp. We will try to get it and start generating reagents. When we switch reagents we clear the solution and start generating different reagent. + /// + public sealed class AutoRegenReagentSystem : EntitySystem + { + [Dependency] private readonly SolutionContainerSystem _solutionSystem = default!; + [Dependency] private readonly PopupSystem _popups = default!; + [Dependency] private readonly IGameTiming _timing = default!; + + public override void Initialize() + { + base.Initialize(); + + SubscribeLocalEvent(OnCompInit); + SubscribeLocalEvent>(AddSwitchVerb); + SubscribeLocalEvent(OnExamined); + SubscribeLocalEvent(OnUseInHand, + before: new[] { typeof(ChemistrySystem) }); + } + + public override void Update(float frameTime) + { + base.Update(frameTime); + var query = EntityQueryEnumerator(); + while (query.MoveNext(out var uid, out var autoComp)) + { + if (_timing.CurTime < autoComp.NextUpdate) + return; + + autoComp.NextUpdate += autoComp.Interval; + + if (autoComp.Solution == null) + TryGetSolution(uid, autoComp); + + if (autoComp.Solution == null) + return; + + _solutionSystem.TryAddReagent(autoComp.Solution.Value, autoComp.CurrentReagent, autoComp.UnitsPerInterval); + } + } + + private void OnCompInit(EntityUid uid, AutoRegenReagentComponent component, ComponentInit args) + { + component.NextUpdate = _timing.CurTime + component.Interval; + SwitchReagent(component); + } + + private void OnUseInHand(EntityUid uid, AutoRegenReagentComponent component, UseInHandEvent args) + { + if (args.Handled) + return; + + if (component.Reagents.Count <= 1) + return; + + SwitchReagent(component, args.User); + args.Handled = true; + } + + private void OnExamined(EntityUid uid, AutoRegenReagentComponent component, ExaminedEvent args) + { + args.PushMarkup(Loc.GetString("reagent-name", ("reagent", component.CurrentReagent))); + } + + private void AddSwitchVerb(EntityUid uid, AutoRegenReagentComponent component, + GetVerbsEvent args) + { + if (!args.CanInteract || !args.CanAccess) + return; + + if (component.Reagents.Count <= 1) + return; + + AlternativeVerb verb = new() + { + Act = () => + { + SwitchReagent(component, args.User); + }, + Text = Loc.GetString("autoreagent-switch"), + Priority = 2 + }; + args.Verbs.Add(verb); + } + + private void TryGetSolution(EntityUid uid, AutoRegenReagentComponent component) + { + if (component.SolutionName == null) + return; + + if (!_solutionSystem.TryGetSolution(uid, component.SolutionName, out var solution)) + return; + + component.Solution = solution; + + component.CurrentReagent = component.Reagents[component.CurrentIndex]; + } + + private string SwitchReagent(AutoRegenReagentComponent component, EntityUid? user = null) + { + if (component.CurrentIndex + 1 == component.Reagents.Count) + component.CurrentIndex = 0; + else + component.CurrentIndex++; + + if (component.Solution != null) + _solutionSystem.RemoveAllSolution(component.Solution.Value); + + component.CurrentReagent = component.Reagents[component.CurrentIndex]; + + if (user != null) + _popups.PopupEntity(Loc.GetString("autoregen-switched", ("reagent", component.CurrentReagent)), user.Value, user.Value); + + return component.CurrentReagent; + } + } +} diff --git a/Resources/Prototypes/_White/Entities/Objects/Specific/Medical/debug_hypo.yml b/Resources/Prototypes/_White/Entities/Objects/Specific/Medical/debug_hypo.yml new file mode 100644 index 0000000000..b293445f1b --- /dev/null +++ b/Resources/Prototypes/_White/Entities/Objects/Specific/Medical/debug_hypo.yml @@ -0,0 +1,13 @@ +- type: entity + id: HyposprayRefillingDebug + name: debug refilling hypospray + parent: Hypospray + suffix: DEBUG + components: + - type: AutoRegenReagent + reagents: + - Ichor + - Stimulants + - Nocturine + interval: 1 + solution: hypospray