From 1d12cee9f186c8e87f68717b4660059c45cf6db6 Mon Sep 17 00:00:00 2001 From: ash lea Date: Wed, 24 May 2023 21:10:32 -0400 Subject: [PATCH 1/3] give hyposprays a swappable bottle for reagents --- .../Components/HyposprayComponent.cs | 9 +- .../EntitySystems/ChemistrySystemHypospray.cs | 84 +++++++++++++++++-- .../Components/SharedHyposprayComponent.cs | 2 + .../components/hypospray-component.ftl | 2 + .../Objects/Specific/Medical/hypospray.yml | 19 +++-- 5 files changed, 100 insertions(+), 16 deletions(-) diff --git a/Content.Server/Chemistry/Components/HyposprayComponent.cs b/Content.Server/Chemistry/Components/HyposprayComponent.cs index abb8ff8797..5968982543 100644 --- a/Content.Server/Chemistry/Components/HyposprayComponent.cs +++ b/Content.Server/Chemistry/Components/HyposprayComponent.cs @@ -1,5 +1,6 @@ using Content.Server.Chemistry.EntitySystems; using Content.Shared.Chemistry.Components; +using Content.Shared.Containers.ItemSlots; using Content.Shared.FixedPoint; using Robust.Shared.Audio; @@ -30,8 +31,14 @@ public sealed class HyposprayComponent : SharedHyposprayComponent public override ComponentState GetComponentState() { + var itemSlotSys = _entMan.EntitySysManager.GetEntitySystem(); var solutionSys = _entMan.EntitySysManager.GetEntitySystem(); - return solutionSys.TryGetSolution(Owner, SolutionName, out var solution) + + EntityUid? container = Owner; + if (SolutionSlot != null) { + container = itemSlotSys.GetItemOrNull(Owner, SolutionSlot); + } + return solutionSys.TryGetSolution(container, SolutionName, out var solution) ? new HyposprayComponentState(solution.Volume, solution.MaxVolume) : new HyposprayComponentState(FixedPoint2.Zero, FixedPoint2.Zero); } diff --git a/Content.Server/Chemistry/EntitySystems/ChemistrySystemHypospray.cs b/Content.Server/Chemistry/EntitySystems/ChemistrySystemHypospray.cs index fbd9cd3250..f106856199 100644 --- a/Content.Server/Chemistry/EntitySystems/ChemistrySystemHypospray.cs +++ b/Content.Server/Chemistry/EntitySystems/ChemistrySystemHypospray.cs @@ -14,21 +14,30 @@ using Content.Shared.Tag; using Content.Shared.Popups; using Content.Shared.Timing; -using Robust.Shared.Player; +using Content.Shared.Containers.ItemSlots; +using Robust.Shared.Containers; +using Content.Shared.Examine; +using Robust.Shared.Prototypes; +using Content.Shared.Chemistry.Components; namespace Content.Server.Chemistry.EntitySystems { public sealed partial class ChemistrySystem { [Dependency] private readonly UseDelaySystem _useDelay = default!; + [Dependency] private readonly ItemSlotsSystem _itemSlotsSystem = default!; + [Dependency] private readonly IPrototypeManager _prototypeManager = default!; private void InitializeHypospray() { SubscribeLocalEvent(OnAfterInteract); SubscribeLocalEvent(OnAttack); SubscribeLocalEvent(OnSolutionChange); + SubscribeLocalEvent(OnContainerModified); + SubscribeLocalEvent(OnContainerModified); SubscribeLocalEvent(OnUseInHand); SubscribeLocalEvent(OnStartup); + SubscribeLocalEvent(OnExamine); } private void OnStartup(EntityUid uid, HyposprayComponent component, ComponentStartup args) @@ -50,6 +59,11 @@ private void OnSolutionChange(EntityUid uid, HyposprayComponent component, Solut Dirty(component); } + private void OnContainerModified(EntityUid uid, HyposprayComponent component, ContainerModifiedMessage args) + { + Dirty(component); + } + public void OnAfterInteract(EntityUid uid, HyposprayComponent component, AfterInteractEvent args) { if (!args.CanReach) @@ -88,9 +102,7 @@ public bool TryDoInject(EntityUid uid, EntityUid? target, EntityUid user, Hyposp if (tag.Tags.Contains("HardsuitOn")) { if (target == null) return false; - var taget = (EntityUid) target; - - _popup.PopupEntity("You cant get the needle to go through the thick plating!", taget, user, PopupType.MediumCaution); + _popup.PopupEntity("You cant get the needle to go through the thick plating!", target.Value, user, PopupType.MediumCaution); return false; } } @@ -103,7 +115,18 @@ public bool TryDoInject(EntityUid uid, EntityUid? target, EntityUid user, Hyposp target = user; } - _solutions.TryGetSolution(uid, component.SolutionName, out var hypoSpraySolution); + EntityUid? container = uid; + + if (component.SolutionSlot != null) { + container = _itemSlotsSystem.GetItemOrNull(uid, component.SolutionSlot); + } + + if (container == null) { + _popup.PopupCursor(Loc.GetString("hypospray-component-no-container-message"), user); + return false; + } + + _solutions.TryGetSolution(container, component.SolutionName, out var hypoSpraySolution); if (hypoSpraySolution == null || hypoSpraySolution.Volume == 0) { @@ -145,13 +168,15 @@ public bool TryDoInject(EntityUid uid, EntityUid? target, EntityUid user, Hyposp } // Move units from attackSolution to targetSolution - var removedSolution = _solutions.SplitSolution(uid, hypoSpraySolution, realTransferAmount); + var removedSolution = _solutions.SplitSolution(container.Value, hypoSpraySolution, realTransferAmount); if (!targetSolution.CanAddSolution(removedSolution)) return true; _reactiveSystem.DoEntityReaction(target.Value, removedSolution, ReactionMethod.Injection); _solutions.TryAddSolution(target.Value, targetSolution, removedSolution); + Dirty(component); + //same logtype as syringes... _adminLogger.Add(LogType.ForceFeed, $"{_entMan.ToPrettyString(user):user} injected {_entMan.ToPrettyString(target.Value):target} with a solution {SolutionContainerSystem.ToPrettyString(removedSolution):removedSolution} using a {_entMan.ToPrettyString(uid):using}"); @@ -166,5 +191,52 @@ static bool EligibleEntity([NotNullWhen(true)] EntityUid? entity, IEntityManager return entMan.HasComponent(entity) && entMan.HasComponent(entity); } + + private void OnExamine(EntityUid uid, HyposprayComponent component, ExaminedEvent args) + { + if (component.SolutionSlot != null) { + var container = _itemSlotsSystem.GetItemOrNull(uid, component.SolutionSlot); + if (container == null) { + args.PushText(Loc.GetString("hypospray-component-on-examine-no-container")); + return; + } + + if (!TryComp(container, out ExaminableSolutionComponent? examinableComponent)) + return; + + // Mostly copied from SolutionContainerSystem.OnExamineSolution + + SolutionContainerManagerComponent? solutionsManager = null; + if (!Resolve(container.Value, ref solutionsManager) + || !solutionsManager.Solutions.TryGetValue(examinableComponent.Solution, out var solutionHolder)) + return; + + var primaryReagent = solutionHolder.GetPrimaryReagentId(); + + if (string.IsNullOrEmpty(primaryReagent)) + { + args.PushText(Loc.GetString("shared-solution-container-component-on-examine-empty-container")); + return; + } + + if (!_prototypeManager.TryIndex(primaryReagent, out ReagentPrototype? proto)) + { + Logger.Error( + $"{nameof(Solution)} could not find the prototype associated with {primaryReagent}."); + return; + } + + var colorHex = solutionHolder.GetColor(_prototypeManager) + .ToHexNoAlpha(); //TODO: If the chem has a dark color, the examine text becomes black on a black background, which is unreadable. + var messageString = "shared-solution-container-component-on-examine-main-text"; + + args.PushMarkup(Loc.GetString(messageString, + ("color", colorHex), + ("wordedAmount", Loc.GetString(solutionHolder.Contents.Count == 1 + ? "shared-solution-container-component-on-examine-worded-amount-one-reagent" + : "shared-solution-container-component-on-examine-worded-amount-multiple-reagents")), + ("desc", proto.LocalizedPhysicalDescription))); + } + } } } diff --git a/Content.Shared/Chemistry/Components/SharedHyposprayComponent.cs b/Content.Shared/Chemistry/Components/SharedHyposprayComponent.cs index 59d3192cfb..67a73c33fb 100644 --- a/Content.Shared/Chemistry/Components/SharedHyposprayComponent.cs +++ b/Content.Shared/Chemistry/Components/SharedHyposprayComponent.cs @@ -7,6 +7,8 @@ namespace Content.Shared.Chemistry.Components [NetworkedComponent()] public abstract class SharedHyposprayComponent : Component { + [DataField("solutionSlot")] + public string? SolutionSlot = null; [DataField("solutionName")] public string SolutionName = "hypospray"; } diff --git a/Resources/Locale/en-US/chemistry/components/hypospray-component.ftl b/Resources/Locale/en-US/chemistry/components/hypospray-component.ftl index 7acbe8664c..8009608e70 100644 --- a/Resources/Locale/en-US/chemistry/components/hypospray-component.ftl +++ b/Resources/Locale/en-US/chemistry/components/hypospray-component.ftl @@ -7,7 +7,9 @@ hypospray-volume-text = Volume: [color=white]{$currentVolume}/{$totalVolume}[/co hypospray-component-inject-other-message = You inject {$other}. hypospray-component-inject-self-message = You inject yourself. hypospray-component-inject-self-clumsy-message = Oops! You injected yourself. +hypospray-component-no-container-message = It has no container to draw from! hypospray-component-empty-message = It's empty! hypospray-component-feel-prick-message = You feel a tiny prick! hypospray-component-transfer-already-full-message = {$owner} is already full! hypospray-cant-inject = Can't inject into {$target}! +hypospray-component-on-examine-no-container = It has no solution container. diff --git a/Resources/Prototypes/Entities/Objects/Specific/Medical/hypospray.yml b/Resources/Prototypes/Entities/Objects/Specific/Medical/hypospray.yml index e1d29b2836..678a62f60d 100644 --- a/Resources/Prototypes/Entities/Objects/Specific/Medical/hypospray.yml +++ b/Resources/Prototypes/Entities/Objects/Specific/Medical/hypospray.yml @@ -1,4 +1,4 @@ -- type: entity +- type: entity name: hypospray parent: BaseItem description: A sterile injector for rapid administration of drugs to patients. @@ -9,15 +9,16 @@ state: hypo - type: Item sprite: Objects/Specific/Medical/hypospray.rsi - - type: SolutionContainerManager - solutions: - hypospray: - maxVol: 30 - - type: RefillableSolution - solution: hypospray - - type: ExaminableSolution - solution: hypospray + - type: ItemSlots + slots: + container: + whitelist: + tags: + - Bottle + startingItem: ChemistryEmptyBottle01 - type: Hypospray + solutionSlot: container + solutionName: drink pierceArmor: true - type: DynamicPrice price: 750 From 762bfee4a1c8245ac4e002d4a3a1fa5258ce3930 Mon Sep 17 00:00:00 2001 From: ash lea Date: Thu, 25 May 2023 16:06:10 -0400 Subject: [PATCH 2/3] add medipen cartridges --- .../UI/ChemMasterBoundUserInterface.cs | 2 + .../Chemistry/UI/ChemMasterWindow.xaml | 8 +++ .../Chemistry/UI/ChemMasterWindow.xaml.cs | 7 ++- .../EntitySystems/ChemMasterSystem.cs | 60 +++++++++++++++++- Content.Shared/Chemistry/SharedChemMaster.cs | 14 +++++ .../components/chem-master-component.ftl | 1 + .../Maps/SimpleStation14/syndiecomms.yml | 6 +- .../Maps/SimpleStation14/syndiecommsatmos.yml | 6 +- .../Catalog/Research/technologies.yml | 1 + .../VendingMachines/Inventories/medical.yml | 2 +- .../VendingMachines/Inventories/wallmed.yml | 2 +- .../Objects/Specific/Medical/hypospray.yml | 61 ++++++++++++++++++- .../Structures/Machines/chem_master.yml | 1 + .../Entities/Structures/Machines/lathe.yml | 1 + .../Prototypes/Recipes/Lathes/chemistry.yml | 7 +++ Resources/Prototypes/SimpleStation14/tags.yml | 8 +++ 16 files changed, 175 insertions(+), 12 deletions(-) diff --git a/Content.Client/Chemistry/UI/ChemMasterBoundUserInterface.cs b/Content.Client/Chemistry/UI/ChemMasterBoundUserInterface.cs index 0577aa1fcb..9af4c49d2a 100644 --- a/Content.Client/Chemistry/UI/ChemMasterBoundUserInterface.cs +++ b/Content.Client/Chemistry/UI/ChemMasterBoundUserInterface.cs @@ -51,6 +51,8 @@ protected override void Open() (uint)_window.PillDosage.Value, (uint)_window.PillNumber.Value, _window.LabelLine)); _window.CreateBottleButton.OnPressed += _ => SendMessage( new ChemMasterOutputToBottleMessage((uint)_window.BottleDosage.Value, _window.LabelLine)); + _window.CreateCartridgeButton.OnPressed += _ => SendMessage( + new ChemMasterCreateCartridgeMessage((uint)_window.CartridgeDosage.Value, _window.LabelLine)); for (uint i = 0; i < _window.PillTypeButtons.Length; i++) { diff --git a/Content.Client/Chemistry/UI/ChemMasterWindow.xaml b/Content.Client/Chemistry/UI/ChemMasterWindow.xaml index e5ffeb7809..0f6fe4e763 100644 --- a/Content.Client/Chemistry/UI/ChemMasterWindow.xaml +++ b/Content.Client/Chemistry/UI/ChemMasterWindow.xaml @@ -125,6 +125,14 @@