diff --git a/Content.Client/Chemistry/UI/ReagentCardControl.xaml b/Content.Client/Chemistry/UI/ReagentCardControl.xaml
index 41bf884b60c..430adb01723 100644
--- a/Content.Client/Chemistry/UI/ReagentCardControl.xaml
+++ b/Content.Client/Chemistry/UI/ReagentCardControl.xaml
@@ -5,39 +5,31 @@ SPDX-FileCopyrightText: 2025 Aiden <28298836+Aidenkrz@users.noreply.github.com>
SPDX-License-Identifier: AGPL-3.0-or-later
-->
+
-
-
+
diff --git a/Content.Client/Chemistry/UI/ReagentCardControl.xaml.cs b/Content.Client/Chemistry/UI/ReagentCardControl.xaml.cs
index 93e24ac5e6a..d90aa8d9a1b 100644
--- a/Content.Client/Chemistry/UI/ReagentCardControl.xaml.cs
+++ b/Content.Client/Chemistry/UI/ReagentCardControl.xaml.cs
@@ -3,7 +3,10 @@
//
// SPDX-License-Identifier: AGPL-3.0-or-later
+// Maid START PR №21
+
using Content.Shared.Chemistry;
+using Content.Shared.Chemistry.Reagent;
using Content.Shared.Storage;
using Robust.Client.AutoGenerated;
using Robust.Client.Graphics;
@@ -15,24 +18,23 @@ namespace Content.Client.Chemistry.UI;
[GenerateTypedNameReferences]
public sealed partial class ReagentCardControl : Control
{
- public ItemStorageLocation StorageLocation { get; }
- public Action? OnPressed;
- public Action? OnEjectButtonPressed;
+ public ReagentId ReagentId { get; private init; }
+ public Action? OnPressed;
- public ReagentCardControl(ReagentInventoryItem item)
+ public ReagentCardControl(ReagentId reagentId, ReagentPrototype? prototype, int cost)
{
RobustXamlLoader.Load(this);
- StorageLocation = item.StorageLocation;
- ColorPanel.PanelOverride = new StyleBoxFlat { BackgroundColor = item.ReagentColor };
- ReagentNameLabel.Text = item.ReagentLabel;
- FillLabel.Text = Loc.GetString("reagent-dispenser-window-quantity-label-text", ("quantity", item.Quantity));;
- EjectButtonIcon.Text = Loc.GetString("reagent-dispenser-window-eject-container-button");
-
- if (item.Quantity == 0.0)
- MainButton.Disabled = true;
+ ReagentId = reagentId;
+ ReagentNameLabel.Text = prototype?.LocalizedName ?? Loc.GetString("reagent-dispenser-window-reagent-name-not-found-text");
+ MainButton.OnPressed += args => OnPressed?.Invoke(ReagentId);
- MainButton.OnPressed += args => OnPressed?.Invoke(StorageLocation);
- EjectButton.OnPressed += args => OnEjectButtonPressed?.Invoke(StorageLocation);
+ ReagentCostLabel.Text = cost.ToString();
+ if (cost == 0)
+ {
+ ReagentCostControl.Visible = false;
+ }
}
-}
\ No newline at end of file
+}
+
+// Maid END
diff --git a/Content.Client/Chemistry/UI/ReagentDispenserBoundUserInterface.cs b/Content.Client/Chemistry/UI/ReagentDispenserBoundUserInterface.cs
index 9d6ed87fa34..99284980c7b 100644
--- a/Content.Client/Chemistry/UI/ReagentDispenserBoundUserInterface.cs
+++ b/Content.Client/Chemistry/UI/ReagentDispenserBoundUserInterface.cs
@@ -68,8 +68,13 @@ protected override void Open()
_window.AmountGrid.OnButtonPressed += s => SendMessage(new ReagentDispenserSetDispenseAmountMessage(s));
+ // Maid START PR №21
+ /*
_window.OnDispenseReagentButtonPressed += (location) => SendMessage(new ReagentDispenserDispenseReagentMessage(location));
_window.OnEjectJugButtonPressed += (location) => SendMessage(new ReagentDispenserEjectContainerMessage(location));
+ */
+ _window.OnDispenseReagentButtonPressed += (reagent) => SendMessage(new ReagentDispenserDispenseReagentMessage(reagent));
+ // Maid END
}
///
@@ -87,4 +92,4 @@ protected override void UpdateState(BoundUserInterfaceState state)
_window?.UpdateState(castState); //Update window state
}
}
-}
\ No newline at end of file
+}
diff --git a/Content.Client/Chemistry/UI/ReagentDispenserWindow.xaml b/Content.Client/Chemistry/UI/ReagentDispenserWindow.xaml
index af778556c01..f6591866252 100644
--- a/Content.Client/Chemistry/UI/ReagentDispenserWindow.xaml
+++ b/Content.Client/Chemistry/UI/ReagentDispenserWindow.xaml
@@ -14,65 +14,70 @@ SPDX-FileCopyrightText: 2025 Aiden <28298836+Aidenkrz@users.noreply.github.com>
SPDX-License-Identifier: AGPL-3.0-or-later
-->
-
+
-
-
-
+
+
+
-
-
-
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
-
-
-
+ Scale="2 2"/>
+
+
+
+
+
-
-
-
-
+
+
-
-
+
+
+
diff --git a/Content.Client/Chemistry/UI/ReagentDispenserWindow.xaml.cs b/Content.Client/Chemistry/UI/ReagentDispenserWindow.xaml.cs
index 676781ad8f4..008c4a33f54 100644
--- a/Content.Client/Chemistry/UI/ReagentDispenserWindow.xaml.cs
+++ b/Content.Client/Chemistry/UI/ReagentDispenserWindow.xaml.cs
@@ -32,17 +32,24 @@
//
// SPDX-License-Identifier: AGPL-3.0-or-later
+using Content.Client.Charges;
using Content.Client.Stylesheets;
using Content.Client.UserInterface.Controls;
+using Content.Shared.Charges.Components;
+using Content.Shared.Charges.Systems;
using Content.Shared.Chemistry;
using Content.Shared.Chemistry.Reagent;
using Content.Shared.Storage;
+using JetBrains.Annotations;
using Robust.Client.AutoGenerated;
using Robust.Client.UserInterface.Controls;
using Robust.Client.UserInterface.XAML;
using Robust.Shared.Prototypes;
+using Robust.Shared.Timing;
+using System.Linq;
using static Robust.Client.UserInterface.Controls.BoxContainer;
+// Maid START PR №21
namespace Content.Client.Chemistry.UI
{
///
@@ -53,8 +60,10 @@ public sealed partial class ReagentDispenserWindow : FancyWindow
{
[Dependency] private readonly IPrototypeManager _prototypeManager = default!;
[Dependency] private readonly IEntityManager _entityManager = default!;
- public event Action? OnDispenseReagentButtonPressed;
- public event Action? OnEjectJugButtonPressed;
+ private readonly ChargesSystem _chargesSystem = default!;
+
+ public event Action? OnDispenseReagentButtonPressed;
+ Entity? _chargesEntity;
///
/// Create and initialize the dispenser UI client-side. Creates the basic layout,
@@ -64,26 +73,49 @@ public ReagentDispenserWindow()
{
RobustXamlLoader.Load(this);
IoCManager.InjectDependencies(this);
+
+ _chargesSystem = _entityManager.System();
+ }
+
+ protected override void FrameUpdate(FrameEventArgs args)
+ {
+ if (_chargesEntity?.Comp1 is not null)
+ {
+ ChargeAmountLabel.Text = _chargesSystem.GetCurrentCharges(_chargesEntity.Value).ToString();
+ }
+
+ base.FrameUpdate(args);
}
///
/// Update the button grid of reagents which can be dispensed.
///
/// Reagents which can be dispensed by this dispenser
- public void UpdateReagentsList(List inventory)
+ public void UpdateReagentsList(List<(ReagentId reagent, int cost)> inventory, int amount, bool showPrices)
{
if (ReagentList == null)
return;
ReagentList.Children.Clear();
- //Sort inventory by reagentLabel
- inventory.Sort((x, y) => x.ReagentLabel.CompareTo(y.ReagentLabel));
- foreach (var item in inventory)
+ string untranslatedText = Loc.GetString("reagent-dispenser-window-reagent-name-not-found-text");
+
+ var reagentPrototypes = inventory
+ // Convert reagentId[] to (reagentId, prototype)[]
+ .Select(reagentPair => (
+ reagentPair.reagent,
+ prototype: _prototypeManager.TryIndex(reagentPair.reagent.Prototype, out ReagentPrototype? prototype) ? prototype : null,
+ reagentPair.cost
+ ))
+ .ToList(); // Copy, but should be fine since there not that much reagents
+
+ // Sort reagents by name
+ reagentPrototypes.Sort((x, y) => x.prototype?.LocalizedName?.CompareTo(y.prototype?.LocalizedName ?? untranslatedText) ?? 0);
+
+ foreach (var item in reagentPrototypes)
{
- var card = new ReagentCardControl(item);
+ var card = new ReagentCardControl(item.reagent, item.prototype, showPrices ? item.cost * amount : 0);
card.OnPressed += OnDispenseReagentButtonPressed;
- card.OnEjectButtonPressed += OnEjectJugButtonPressed;
ReagentList.Children.Add(card);
}
}
@@ -95,8 +127,28 @@ public void UpdateReagentsList(List inventory)
public void UpdateState(BoundUserInterfaceState state)
{
var castState = (ReagentDispenserBoundUserInterfaceState) state;
+
+ // Show charge amount
+ ChargeAmount.Visible = false;
+
+ var ent = _entityManager.GetEntity(castState.ChargesContainerEntity);
+ if (ent is not null)
+ {
+ _chargesEntity = new(
+ ent.Value,
+ _entityManager.GetComponentOrNull(ent),
+ _entityManager.GetComponentOrNull(ent)
+ );
+
+ if (_chargesEntity?.Comp1 is not null)
+ {
+ ChargeAmount.Visible = true;
+ ChargeAmountLabel.Text = _chargesSystem.GetCurrentCharges(_chargesEntity.Value).ToString();
+ }
+ }
+
UpdateContainerInfo(castState);
- UpdateReagentsList(castState.Inventory);
+ UpdateReagentsList(castState.Inventory, (int) castState.SelectedDispenseAmount, _chargesEntity?.Comp1 is not null);
_entityManager.TryGetEntity(castState.OutputContainerEntity, out var outputContainerEnt);
View.SetEntity(outputContainerEnt);
@@ -105,7 +157,7 @@ public void UpdateState(BoundUserInterfaceState state)
ClearButton.Disabled = castState.OutputContainer is null;
EjectButton.Disabled = castState.OutputContainer is null;
- AmountGrid.Selected = ((int)castState.SelectedDispenseAmount).ToString();
+ AmountGrid.Selected = ((int) castState.SelectedDispenseAmount).ToString();
}
///
@@ -120,9 +172,8 @@ public void UpdateContainerInfo(ReagentDispenserBoundUserInterfaceState state)
if (state.OutputContainer is null)
{
- ContainerInfoName.Text = "";
+ ContainerInfoName.Text = Loc.GetString("reagent-dispenser-window-no-container-loaded-text");
ContainerInfoFill.Text = "";
- ContainerInfo.Children.Add(new Label { Text = Loc.GetString("reagent-dispenser-window-no-container-loaded-text") });
return;
}
@@ -156,4 +207,6 @@ public void UpdateContainerInfo(ReagentDispenserBoundUserInterfaceState state)
}
}
}
-}
\ No newline at end of file
+}
+
+// Maid END
diff --git a/Content.Server/Chemistry/Components/ReagentDispenserComponent.cs b/Content.Server/Chemistry/Components/ReagentDispenserComponent.cs
index a038cde3db7..99ec778f554 100644
--- a/Content.Server/Chemistry/Components/ReagentDispenserComponent.cs
+++ b/Content.Server/Chemistry/Components/ReagentDispenserComponent.cs
@@ -60,6 +60,7 @@
using Content.Shared.Chemistry;
using Robust.Shared.Audio;
using Robust.Shared.Serialization.TypeSerializers.Implementations.Custom.Prototype;
+using Content.Shared.Chemistry.Dispenser; // Maid PR №21
namespace Content.Server.Chemistry.Components
{
@@ -78,5 +79,23 @@ public sealed partial class ReagentDispenserComponent : Component
[ViewVariables(VVAccess.ReadWrite)]
public ReagentDispenserDispenseAmount DispenseAmount = ReagentDispenserDispenseAmount.U10;
+
+ // Maid START PR №21
+
+ ///
+ /// Used for reagents that got collected from
+ ///
+ [DataField("defaultReagentCost")]
+ public int DefaultReagentCost = 30;
+
+ [DataField("pack", customTypeSerializer: typeof(PrototypeIdSerializer))]
+ [ViewVariables(VVAccess.ReadWrite)]
+ public string? PackPrototypeId = default!;
+
+ [DataField("emagPack", customTypeSerializer: typeof(PrototypeIdSerializer))]
+ [ViewVariables(VVAccess.ReadWrite)]
+ public string? EmagPackPrototypeId = default!;
+
+ // Maid END
}
-}
\ No newline at end of file
+}
diff --git a/Content.Server/Chemistry/EntitySystems/ReagentDispenserSystem.cs b/Content.Server/Chemistry/EntitySystems/ReagentDispenserSystem.cs
index c7a347a5c82..09b053454af 100644
--- a/Content.Server/Chemistry/EntitySystems/ReagentDispenserSystem.cs
+++ b/Content.Server/Chemistry/EntitySystems/ReagentDispenserSystem.cs
@@ -33,13 +33,19 @@
//
// SPDX-License-Identifier: AGPL-3.0-or-later
-using System.Linq;
+using Content.Goobstation.Maths.FixedPoint;
+using Content.Server.Charges;
using Content.Server.Chemistry.Components;
+using Content.Server.Hands.Systems;
+using Content.Shared.Charges.Components;
using Content.Shared.Chemistry;
+using Content.Shared.Chemistry.Dispenser;
using Content.Shared.Chemistry.EntitySystems;
+using Content.Shared.Chemistry.Reagent;
using Content.Shared.Containers.ItemSlots;
-using Content.Goobstation.Maths.FixedPoint;
+using Content.Shared.Emag.Components;
using Content.Shared.Nutrition.EntitySystems;
+using Content.Shared.Storage.Components;
using Content.Shared.Storage.EntitySystems;
using JetBrains.Annotations;
using Robust.Server.Audio;
@@ -47,9 +53,14 @@
using Robust.Shared.Audio;
using Robust.Shared.Containers;
using Robust.Shared.Prototypes;
-using Content.Shared.Labels.Components;
-using Content.Shared.Storage;
-using Content.Server.Hands.Systems;
+using Robust.Shared.Serialization.Markdown.Mapping;
+using Robust.Shared.Serialization.Markdown.Sequence;
+using Robust.Shared.Serialization.Markdown.Value;
+using Robust.Shared.Utility;
+using System.Diagnostics;
+using System.Linq;
+
+// Maid START PR №21
namespace Content.Server.Chemistry.EntitySystems
{
@@ -68,6 +79,7 @@ public sealed class ReagentDispenserSystem : EntitySystem
[Dependency] private readonly IPrototypeManager _prototypeManager = default!;
[Dependency] private readonly OpenableSystem _openable = default!;
[Dependency] private readonly HandsSystem _handsSystem = default!;
+ [Dependency] private readonly ChargesSystem _chargesSystem = default!;
public override void Initialize()
{
@@ -81,26 +93,36 @@ public override void Initialize()
SubscribeLocalEvent(OnSetDispenseAmountMessage);
SubscribeLocalEvent(OnDispenseReagentMessage);
- SubscribeLocalEvent(OnEjectReagentMessage);
SubscribeLocalEvent(OnClearContainerSolutionMessage);
SubscribeLocalEvent(OnMapInit, before: new[] { typeof(ItemSlotsSystem) });
}
+ public override void Update(float frameTime)
+ {
+ base.Update(frameTime);
+ }
private void SubscribeUpdateUiState(Entity ent, ref T ev)
{
- UpdateUiState(ent);
+ UpdateUiState(ent.Owner, ent.Comp);
}
- private void UpdateUiState(Entity reagentDispenser)
+ private void UpdateUiState(EntityUid reagentDispenserEnt, ReagentDispenserComponent reagentDispenserComp)
{
- var outputContainer = _itemSlotsSystem.GetItemOrNull(reagentDispenser, SharedReagentDispenser.OutputSlotName);
+ var outputContainer = _itemSlotsSystem.GetItemOrNull(reagentDispenserEnt, SharedReagentDispenser.OutputSlotName);
var outputContainerInfo = BuildOutputContainerInfo(outputContainer);
- var inventory = GetInventory(reagentDispenser);
+ var inventory = GetInventory(reagentDispenserEnt, reagentDispenserComp).ToList(); // TODO: Another copy, optimize
+
+ var state = new ReagentDispenserBoundUserInterfaceState(
+ outputContainerInfo,
+ GetNetEntity(outputContainer),
+ inventory,
+ reagentDispenserComp.DispenseAmount,
+ GetNetEntity(reagentDispenserEnt)
+ );
- var state = new ReagentDispenserBoundUserInterfaceState(outputContainerInfo, GetNetEntity(outputContainer), inventory, reagentDispenser.Comp.DispenseAmount);
- _userInterfaceSystem.SetUiState(reagentDispenser.Owner, ReagentDispenserUiKey.Key, state);
+ _userInterfaceSystem.SetUiState(reagentDispenserEnt, ReagentDispenserUiKey.Key, state);
}
private ContainerInfo? BuildOutputContainerInfo(EntityUid? container)
@@ -119,90 +141,85 @@ private void UpdateUiState(Entity reagentDispenser)
return null;
}
- private List GetInventory(Entity reagentDispenser)
+ private IEnumerable<(ReagentId reagent, int cost)> GetInventory(EntityUid dispenserEnt, ReagentDispenserComponent dispenserComp)
{
- if (!TryComp(reagentDispenser.Owner, out var storage))
+ var inventory = new Dictionary();
+ // Collect reagents from packs:
+
+ if (
+ dispenserComp.PackPrototypeId is not null
+ && _prototypeManager.TryIndex(dispenserComp.PackPrototypeId, out ReagentDispenserInventoryPrototype? packPrototype)
+ )
{
- return [];
+ foreach (var reagentId in packPrototype.Inventory)
+ {
+ inventory[reagentId.Key] = reagentId.Value;
+ }
}
- var inventory = new List();
-
- foreach (var (storedContainer, storageLocation) in storage.StoredItems)
+ if (
+ HasComp(dispenserEnt)
+ && dispenserComp.EmagPackPrototypeId is not null
+ && _prototypeManager.TryIndex(dispenserComp.EmagPackPrototypeId, out ReagentDispenserInventoryPrototype? emagPackPrototype)
+ )
{
- string reagentLabel;
- if (TryComp(storedContainer, out var label) && !string.IsNullOrEmpty(label.CurrentLabel))
- reagentLabel = label.CurrentLabel;
- else
- reagentLabel = Name(storedContainer);
-
- // Get volume remaining and color of solution
- FixedPoint2 quantity = 0f;
- var reagentColor = Color.White;
- if (_solutionContainerSystem.TryGetDrainableSolution(storedContainer, out _, out var sol))
+ foreach (var reagentId in emagPackPrototype.Inventory)
{
- quantity = sol.Volume;
- reagentColor = sol.GetColor(_prototypeManager);
+ inventory[reagentId.Key] = reagentId.Value;
}
-
- inventory.Add(new ReagentInventoryItem(storageLocation, reagentLabel, quantity, reagentColor));
}
- return inventory;
+ return inventory.Select(pair => (new ReagentId(pair.Key, null), pair.Value));
}
private void OnSetDispenseAmountMessage(Entity reagentDispenser, ref ReagentDispenserSetDispenseAmountMessage message)
{
reagentDispenser.Comp.DispenseAmount = message.ReagentDispenserDispenseAmount;
- UpdateUiState(reagentDispenser);
+ UpdateUiState(reagentDispenser.Owner, reagentDispenser.Comp);
ClickSound(reagentDispenser);
}
private void OnDispenseReagentMessage(Entity reagentDispenser, ref ReagentDispenserDispenseReagentMessage message)
{
- if (!TryComp(reagentDispenser.Owner, out var storage))
- {
- return;
- }
-
- // Ensure that the reagent is something this reagent dispenser can dispense.
- var storageLocation = message.StorageLocation;
- var storedContainer = storage.StoredItems.FirstOrDefault(kvp => kvp.Value == storageLocation).Key;
- if (storedContainer == EntityUid.Invalid)
- return;
+ var reagentId = message.ReagentId;
+ var reagentDispenserComp = reagentDispenser.Comp;
var outputContainer = _itemSlotsSystem.GetItemOrNull(reagentDispenser, SharedReagentDispenser.OutputSlotName);
if (outputContainer is not { Valid: true } || !_solutionContainerSystem.TryGetFitsInDispenser(outputContainer.Value, out var solution, out _))
return;
- if (_solutionContainerSystem.TryGetDrainableSolution(storedContainer, out var src, out _) &&
- _solutionContainerSystem.TryGetRefillableSolution(outputContainer.Value, out var dst, out _))
+ // Check if we even can dispense that
+ var inventory = GetInventory(reagentDispenser.Owner, reagentDispenser.Comp);
+ if (!inventory.TryFirstOrNull(data => data.reagent == reagentId, out var inventoryElement))
+ return;
+
+ var singleCost = inventoryElement?.cost ?? 1; // "?? 1" should be unreachable
+
+ float requestedDispenseAmount = (int) reagentDispenserComp.DispenseAmount;
+
+ // How much would be dispensed (less then required, if there not enough charges)
+ float totalDispenseAmount = requestedDispenseAmount;
+
+ bool hasChargesComponent = TryComp(reagentDispenser.Owner, out LimitedChargesComponent? charges);
+ if (hasChargesComponent)
{
- // force open container, if applicable, to avoid confusing people on why it doesn't dispense
- _openable.SetOpen(storedContainer, true);
- _solutionTransferSystem.Transfer(reagentDispenser,
- storedContainer, src.Value,
- outputContainer.Value, dst.Value,
- (int)reagentDispenser.Comp.DispenseAmount);
+ var avalaibleCharges = _chargesSystem.GetCurrentCharges(reagentDispenser.Owner);
+
+ totalDispenseAmount = requestedDispenseAmount;
+ if (requestedDispenseAmount * singleCost > avalaibleCharges)
+ totalDispenseAmount = avalaibleCharges / singleCost;
}
- UpdateUiState(reagentDispenser);
- ClickSound(reagentDispenser);
- }
+ // sollution is not null because [NotNullWhen(true)]
+ _solutionContainerSystem.TryAddReagent(solution ?? throw new UnreachableException(), reagentId.Prototype, totalDispenseAmount, out var dispensed);
- private void OnEjectReagentMessage(Entity reagentDispenser, ref ReagentDispenserEjectContainerMessage message)
- {
- if (!TryComp(reagentDispenser.Owner, out var storage))
+ if (hasChargesComponent && dispensed > float.Epsilon)
{
- return;
+ _chargesSystem.AddCharges(reagentDispenser.Owner, -((int) (MathF.Ceiling((float) dispensed * singleCost))));
}
- var storageLocation = message.StorageLocation;
- var storedContainer = storage.StoredItems.FirstOrDefault(kvp => kvp.Value == storageLocation).Key;
- if (storedContainer == EntityUid.Invalid)
- return;
-
- _handsSystem.TryPickupAnyHand(message.Actor, storedContainer);
+ UpdateUiState(reagentDispenser.Owner, reagentDispenser.Comp);
+ ClickSound(reagentDispenser);
}
private void OnClearContainerSolutionMessage(Entity reagentDispenser, ref ReagentDispenserClearContainerSolutionMessage message)
@@ -212,7 +229,7 @@ private void OnClearContainerSolutionMessage(Entity r
return;
_solutionContainerSystem.RemoveAllSolution(solution.Value);
- UpdateUiState(reagentDispenser);
+ UpdateUiState(reagentDispenser.Owner, reagentDispenser.Comp);
ClickSound(reagentDispenser);
}
@@ -230,3 +247,5 @@ private void OnMapInit(Entity ent, ref MapInitEvent a
}
}
}
+
+// Maid END
diff --git a/Content.Shared/Chemistry/Dispenser/ReagentDispenserInventoryPrototype.cs b/Content.Shared/Chemistry/Dispenser/ReagentDispenserInventoryPrototype.cs
new file mode 100644
index 00000000000..6fa93651386
--- /dev/null
+++ b/Content.Shared/Chemistry/Dispenser/ReagentDispenserInventoryPrototype.cs
@@ -0,0 +1,32 @@
+// Maid PR №21
+
+using Content.Shared.Chemistry.Reagent;
+using Robust.Shared.Prototypes;
+using Robust.Shared.Serialization;
+using Robust.Shared.Serialization.TypeSerializers.Implementations.Custom.Prototype.List;
+using System;
+using System.Collections.Generic;
+using System.Linq;
+using System.Text;
+using System.Threading.Tasks;
+
+namespace Content.Shared.Chemistry.Dispenser
+{
+ ///
+ /// Is simply a list of reagents defined in yaml. This can then be set as a
+ /// reagent dispenser pack value (also in yaml),
+ /// to define which reagents it's able to dispense. Based off of how vending
+ /// machines define their inventory.
+ ///
+ [Prototype("reagentDispenserInventory")]
+ [DataDefinition]
+ public sealed partial class ReagentDispenserInventoryPrototype : IPrototype
+ {
+ [ViewVariables, IdDataField]
+ public string ID { get; private set; } = default!;
+
+ // TODO use ReagentId
+ [DataField("inventory")]
+ public Dictionary Inventory = new();
+ }
+}
diff --git a/Content.Shared/Chemistry/SharedReagentDispenser.cs b/Content.Shared/Chemistry/SharedReagentDispenser.cs
index 8f058e28e36..bf2758ed22b 100644
--- a/Content.Shared/Chemistry/SharedReagentDispenser.cs
+++ b/Content.Shared/Chemistry/SharedReagentDispenser.cs
@@ -12,11 +12,11 @@
//
// SPDX-License-Identifier: AGPL-3.0-or-later
-using Content.Goobstation.Maths.FixedPoint;
using Content.Shared.Chemistry.Reagent;
-using Content.Shared.Storage;
using Robust.Shared.Serialization;
+// Maid START PR №21
+
namespace Content.Shared.Chemistry
{
///
@@ -81,25 +81,11 @@ public ReagentDispenserSetDispenseAmountMessage(String s)
[Serializable, NetSerializable]
public sealed class ReagentDispenserDispenseReagentMessage : BoundUserInterfaceMessage
{
- public readonly ItemStorageLocation StorageLocation;
-
- public ReagentDispenserDispenseReagentMessage(ItemStorageLocation storageLocation)
- {
- StorageLocation = storageLocation;
- }
- }
-
- ///
- /// Message sent by the user interface to ask the reagent dispenser to eject a container
- ///
- [Serializable, NetSerializable]
- public sealed class ReagentDispenserEjectContainerMessage : BoundUserInterfaceMessage
- {
- public readonly ItemStorageLocation StorageLocation;
+ public readonly ReagentId ReagentId;
- public ReagentDispenserEjectContainerMessage(ItemStorageLocation storageLocation)
+ public ReagentDispenserDispenseReagentMessage(ReagentId reagentId)
{
- StorageLocation = storageLocation;
+ ReagentId = reagentId;
}
}
@@ -122,35 +108,35 @@ public enum ReagentDispenserDispenseAmount
U100 = 100,
}
- [Serializable, NetSerializable]
- public sealed class ReagentInventoryItem(ItemStorageLocation storageLocation, string reagentLabel, FixedPoint2 quantity, Color reagentColor)
- {
- public ItemStorageLocation StorageLocation = storageLocation;
- public string ReagentLabel = reagentLabel;
- public FixedPoint2 Quantity = quantity;
- public Color ReagentColor = reagentColor;
- }
[Serializable, NetSerializable]
public sealed class ReagentDispenserBoundUserInterfaceState : BoundUserInterfaceState
{
public readonly ContainerInfo? OutputContainer;
-
public readonly NetEntity? OutputContainerEntity;
///
- /// A list of the reagents which this dispenser can dispense.
+ /// A list of the reagents which this dispenser can dispense and their cost.
///
- public readonly List Inventory;
+ public readonly List<(ReagentId reagent, int cost)> Inventory;
public readonly ReagentDispenserDispenseAmount SelectedDispenseAmount;
- public ReagentDispenserBoundUserInterfaceState(ContainerInfo? outputContainer, NetEntity? outputContainerEntity, List inventory, ReagentDispenserDispenseAmount selectedDispenseAmount)
+ public readonly NetEntity? ChargesContainerEntity;
+
+ public ReagentDispenserBoundUserInterfaceState(
+ ContainerInfo? outputContainer,
+ NetEntity? outputContainerEntity,
+ List<(ReagentId reagent, int cost)> inventory,
+ ReagentDispenserDispenseAmount selectedDispenseAmount,
+ NetEntity? charges
+ )
{
OutputContainer = outputContainer;
OutputContainerEntity = outputContainerEntity;
Inventory = inventory;
SelectedDispenseAmount = selectedDispenseAmount;
+ ChargesContainerEntity = charges;
}
}
@@ -160,3 +146,5 @@ public enum ReagentDispenserUiKey
Key
}
}
+
+// Maid END
diff --git a/Resources/Locale/en-US/chemistry/components/reagent-dispenser-component.ftl b/Resources/Locale/en-US/chemistry/components/reagent-dispenser-component.ftl
index f5b03b207d9..3dd78b21a44 100644
--- a/Resources/Locale/en-US/chemistry/components/reagent-dispenser-component.ftl
+++ b/Resources/Locale/en-US/chemistry/components/reagent-dispenser-component.ftl
@@ -27,3 +27,5 @@ reagent-dispenser-window-no-container-loaded-text = No container loaded.
reagent-dispenser-window-reagent-name-not-found-text = Reagent name not found
reagent-dispenser-window-unknown-reagent-text = Unknown reagent
reagent-dispenser-window-quantity-label-text = {$quantity}u
+# Maid PR №21
+reagent-dispenser-window-charge-amount = charge
diff --git a/Resources/Locale/ru-RU/chemistry/components/reagent-dispenser-component.ftl b/Resources/Locale/ru-RU/chemistry/components/reagent-dispenser-component.ftl
index ba746c40940..28fa338e98d 100644
--- a/Resources/Locale/ru-RU/chemistry/components/reagent-dispenser-component.ftl
+++ b/Resources/Locale/ru-RU/chemistry/components/reagent-dispenser-component.ftl
@@ -17,3 +17,5 @@ reagent-dispenser-window-no-container-loaded-text = Контейнер не за
reagent-dispenser-window-reagent-name-not-found-text = Имя реагента не найдено
reagent-dispenser-window-unknown-reagent-text = Неизвестный реагент
reagent-dispenser-window-quantity-label-text = { $quantity } ед.
+# Maid PR №21
+reagent-dispenser-window-charge-amount = заряд
diff --git a/Resources/Prototypes/Catalog/reagent_dispenser.yml b/Resources/Prototypes/Catalog/reagent_dispenser.yml
new file mode 100644
index 00000000000..42a325922a9
--- /dev/null
+++ b/Resources/Prototypes/Catalog/reagent_dispenser.yml
@@ -0,0 +1,96 @@
+# Maid PR №21
+
+- type: reagentDispenserInventory
+ id: ChemDispenserStandardInventory
+ inventory:
+ Aluminium: 10
+ Carbon: 10
+ Chlorine: 10
+ Copper: 10
+ Ethanol: 10
+ Fluorine: 10
+ Sugar: 10
+ Hydrogen: 10
+ Iodine: 10
+ Iron: 10
+ Lithium: 10
+ Mercury: 10
+ Nitrogen: 10
+ Oxygen: 10
+ Phosphorus: 10
+ Potassium: 10
+ Radium: 10
+ Silicon: 10
+ Sodium: 10
+ Sulfur: 10
+
+- type: reagentDispenserInventory
+ id: ChemDispenserEmaggedInventory
+ inventory: ##Feel free to change this to something more interesting when more chems are added
+ Napalm: 30
+ Toxin: 30
+ Epinephrine: 30
+ Ultravasculine: 30
+
+
+- type: reagentDispenserInventory
+ id: SodaDispenserInventory
+ inventory:
+ Ice: 5
+ Coffee: 5
+ Cream: 5
+ Tea: 5
+ GreenTea: 5
+ IcedTea: 5
+ IcedGreenTea: 5
+ Cola: 5
+ SpaceMountainWind: 5
+ DrGibb: 5
+ RootBeer: 5
+ SpaceUp: 5
+ TonicWater: 5
+ SodaWater: 5
+ LemonLime: 5
+ Sugar: 5
+ JuiceOrange: 5
+ JuiceLime: 5
+ JuiceWatermelon: 5
+ ###Hacked
+ #- Fourteen Loko
+ #- GrapeSoda
+
+- type: reagentDispenserInventory
+ id: SodaDispenserEmagInventory
+ inventory:
+ FourteenLoko: 15
+ Ephedrine: 15
+ Histamine: 15
+
+- type: reagentDispenserInventory
+ id: BoozeDispenserInventory
+ inventory:
+ Beer: 5
+ CoffeeLiqueur: 5
+ Whiskey: 5
+ Wine: 5
+ Vodka: 5
+ Gin: 5
+ Rum: 5
+ Tequila: 5
+ Vermouth: 5
+ Cognac: 5
+ Ale: 5
+ Mead: 5
+ ###Hacked
+ #- Goldschlager
+ #- Patron
+ #- JuiceWatermelon
+ #- JuiceBerry
+
+- type: reagentDispenserInventory
+ id: BoozeDispenserEmagInventory
+ inventory:
+ AtomicBomb: 15
+ Ethanol: 15
+ Iron: 15
+
diff --git a/Resources/Prototypes/Entities/Structures/Dispensers/base_structuredispensers.yml b/Resources/Prototypes/Entities/Structures/Dispensers/base_structuredispensers.yml
index 0602e51c937..c3e1ef67bc5 100644
--- a/Resources/Prototypes/Entities/Structures/Dispensers/base_structuredispensers.yml
+++ b/Resources/Prototypes/Entities/Structures/Dispensers/base_structuredispensers.yml
@@ -78,8 +78,8 @@
interfaces:
enum.ReagentDispenserUiKey.Key:
type: ReagentDispenserBoundUserInterface
- enum.StorageUiKey.Key:
- type: StorageBoundUserInterface
+# enum.StorageUiKey.Key: # Maid PR №21
+# type: StorageBoundUserInterface # Maid PR №21
- type: Anchorable
- type: Pullable
- type: Damageable
@@ -102,10 +102,12 @@
- !type:PlaySoundBehavior
sound:
collection: MetalGlassBreak
- - type: Storage
- maxItemSize: Normal
- grid:
- - 0,0,19,5
+# Maid START PR №21
+# - type: Storage
+# maxItemSize: Normal
+# grid:
+# - 0,0,19,5
+# Maid END
- type: ReagentDispenser
beakerSlot:
whitelistFailPopup: reagent-dispenser-component-cannot-put-entity-message
@@ -119,7 +121,7 @@
machine_board: !type:Container
machine_parts: !type:Container
beakerSlot: !type:ContainerSlot
- storagebase: !type:Container
+ # storagebase: !type:Container # Maid PR №21
- type: StaticPrice
price: 1000
- - type: WiresPanel
\ No newline at end of file
+ - type: WiresPanel
diff --git a/Resources/Prototypes/Entities/Structures/Dispensers/booze.yml b/Resources/Prototypes/Entities/Structures/Dispensers/booze.yml
index c10862baa5f..ad7a452958b 100644
--- a/Resources/Prototypes/Entities/Structures/Dispensers/booze.yml
+++ b/Resources/Prototypes/Entities/Structures/Dispensers/booze.yml
@@ -111,25 +111,35 @@
sprite: Structures/smalldispensers.rsi
drawdepth: SmallObjects
state: booze
- - type: Storage
- openOnActivate: false
- whitelist:
- tags:
- - DrinkBottle
- - type: StorageFill
- contents:
- - id: DrinkAleBottleFullGrowler
- - id: DrinkBeerGrowler
- - id: DrinkCoffeeLiqueurBottleFull
- - id: DrinkCognacBottleFull
- - id: DrinkGinBottleFull
- - id: DrinkMeadJug
- - id: DrinkRumBottleFull
- - id: DrinkTequilaBottleFull
- - id: DrinkVermouthBottleFull
- - id: DrinkVodkaBottleFull
- - id: DrinkWhiskeyBottleFull
- - id: DrinkWineBottleFull
+## Maid START PR №21
+# - type: Storage
+# openOnActivate: false
+# whitelist:
+# tags:
+# - DrinkBottle
+# - type: StorageFill
+# contents:
+# - id: DrinkAleBottleFullGrowler
+# - id: DrinkBeerGrowler
+# - id: DrinkCoffeeLiqueurBottleFull
+# - id: DrinkCognacBottleFull
+# - id: DrinkGinBottleFull
+# - id: DrinkMeadJug
+# - id: DrinkRumBottleFull
+# - id: DrinkTequilaBottleFull
+# - id: DrinkVermouthBottleFull
+# - id: DrinkVodkaBottleFull
+# - id: DrinkWhiskeyBottleFull
+# - id: DrinkWineBottleFull
+ - type: ReagentDispenser
+ pack: BoozeDispenserInventory
+ emagPack: BoozeDispenserEmagInventory
+ - type: LimitedCharges
+ maxCharges: 1000
+ lastCharges: 1000
+ - type: AutoRecharge
+ rechargeDuration: 0.1
+## Maid END
- type: Transform
noRot: false
- type: Machine
@@ -146,7 +156,11 @@
suffix: Empty
parent: BoozeDispenser
components:
- - type: Storage
- whitelist:
- tags:
- - DrinkBottle
+## Maid START PR №21
+# - type: Storage
+# whitelist:
+# tags:
+# - DrinkBottle
+ - type: LimitedCharges
+ lastCharges: 0 # Doesn't work, search for comment in PR 21 for more info
+## Maid END
diff --git a/Resources/Prototypes/Entities/Structures/Dispensers/chem.yml b/Resources/Prototypes/Entities/Structures/Dispensers/chem.yml
index da48dc8506c..907e66e0f37 100644
--- a/Resources/Prototypes/Entities/Structures/Dispensers/chem.yml
+++ b/Resources/Prototypes/Entities/Structures/Dispensers/chem.yml
@@ -55,11 +55,21 @@
sprite: Structures/dispensers.rsi
state: industrial-working
snapCardinals: true
- - type: Storage
- openOnActivate: false
- whitelist:
- tags:
- - ChemDispensable
+## Maid START PR №21
+# - type: Storage
+# openOnActivate: false
+# whitelist:
+# tags:
+# - ChemDispensable
+ - type: ReagentDispenser
+ pack: ChemDispenserStandardInventory
+ emagPack: ChemDispenserEmaggedInventory
+ - type: LimitedCharges
+ maxCharges: 1000
+ lastCharges: 0 # Doesn't work, search for comment in PR 21 for more info
+ - type: AutoRecharge
+ rechargeDuration: 0.1
+## Maid END
- type: ApcPowerReceiver
- type: ExtensionCableReceiver
- type: Destructible
@@ -100,26 +110,30 @@
suffix: Filled
parent: ChemDispenserEmpty
components:
- - type: ReagentDispenser
- - type: StorageFill
- contents:
- - id: JugAluminium
- - id: JugCarbon
- - id: JugChlorine
- - id: JugCopper
- - id: JugEthanol
- - id: JugFluorine
- - id: JugSugar
- - id: JugHydrogen
- - id: JugIodine
- - id: JugIron
- - id: JugLithium
- - id: JugMercury
- - id: JugNitrogen
- - id: JugOxygen
- - id: JugPhosphorus
- - id: JugPotassium
- - id: JugRadium
- - id: JugSilicon
- - id: JugSodium
- - id: JugSulfur
+## Maid START PR №21
+# - type: ReagentDispenser
+# - type: StorageFill
+# contents:
+# - id: JugAluminium
+# - id: JugCarbon
+# - id: JugChlorine
+# - id: JugCopper
+# - id: JugEthanol
+# - id: JugFluorine
+# - id: JugSugar
+# - id: JugHydrogen
+# - id: JugIodine
+# - id: JugIron
+# - id: JugLithium
+# - id: JugMercury
+# - id: JugNitrogen
+# - id: JugOxygen
+# - id: JugPhosphorus
+# - id: JugPotassium
+# - id: JugRadium
+# - id: JugSilicon
+# - id: JugSodium
+# - id: JugSulfur
+ - type: LimitedCharges
+ lastCharges: 1000
+## Maid END
diff --git a/Resources/Prototypes/Entities/Structures/Dispensers/soda.yml b/Resources/Prototypes/Entities/Structures/Dispensers/soda.yml
index 80d7b4327c2..08e26289753 100644
--- a/Resources/Prototypes/Entities/Structures/Dispensers/soda.yml
+++ b/Resources/Prototypes/Entities/Structures/Dispensers/soda.yml
@@ -112,32 +112,42 @@
sprite: Structures/smalldispensers.rsi
drawdepth: SmallObjects
state: soda
- - type: Storage
- openOnActivate: false
- whitelist:
- tags:
- - DrinkBottle
- - type: StorageFill
- contents:
- - id: DrinkCoconutWaterJug
- - id: DrinkCoffeeJug
- - id: DrinkColaBottleFull
- - id: DrinkCreamCartonXL
- - id: DrinkDrGibbJug
- - id: DrinkEnergyDrinkJug
- - id: DrinkGreenTeaJug
- - id: DrinkIceJug
- - id: DrinkJuiceLimeCartonXL
- - id: DrinkJuiceOrangeCartonXL
- - id: DrinkLemonLimeJug
- - id: DrinkRootBeerJug
- - id: DrinkSodaWaterBottleFull
- - id: DrinkSpaceMountainWindBottleFull
- - id: DrinkSpaceUpBottleFull
- - id: DrinkSugarJug
- - id: DrinkTeaJug
- - id: DrinkTonicWaterBottleFull
- - id: DrinkWaterMelonJuiceJug
+## Maid START PR №21
+# - type: Storage
+# openOnActivate: false
+# whitelist:
+# tags:
+# - DrinkBottle
+# - type: StorageFill
+# contents:
+# - id: DrinkCoconutWaterJug
+# - id: DrinkCoffeeJug
+# - id: DrinkColaBottleFull
+# - id: DrinkCreamCartonXL
+# - id: DrinkDrGibbJug
+# - id: DrinkEnergyDrinkJug
+# - id: DrinkGreenTeaJug
+# - id: DrinkIceJug
+# - id: DrinkJuiceLimeCartonXL
+# - id: DrinkJuiceOrangeCartonXL
+# - id: DrinkLemonLimeJug
+# - id: DrinkRootBeerJug
+# - id: DrinkSodaWaterBottleFull
+# - id: DrinkSpaceMountainWindBottleFull
+# - id: DrinkSpaceUpBottleFull
+# - id: DrinkSugarJug
+# - id: DrinkTeaJug
+# - id: DrinkTonicWaterBottleFull
+# - id: DrinkWaterMelonJuiceJug
+ - type: ReagentDispenser
+ pack: SodaDispenserInventory
+ emagPack: SodaDispenserEmagInventory
+ - type: LimitedCharges
+ maxCharges: 1000
+ lastCharges: 1000
+ - type: AutoRecharge
+ rechargeDuration: 0.1
+## Maid END
- type: Transform
noRot: false
- type: Machine
@@ -151,3 +161,8 @@
parent: SodaDispenser
id: SodaDispenserEmpty
suffix: Empty
+ components:
+## Maid START PR №21
+ - type: LimitedCharges
+ lastCharges: 0 # Doesn't work, search for comment in PR 21 for more info
+# Maid END