Rerun of "Add Reagent Grinder/Juicer" (#2570)
* commit skeleton reagent grinder component * add reagentgrinder bounduserinterface, add suffix to grinder yml, add reagentgrinder sprites * implement much more of the grinder ui functionality * get more use out of hasbeaker bool * complete wiring up most of the chamber/beaker UI controls * remove whitelist prototype id. add grindable tag component * add juiceable component * rename boolparam to be clearer * more juice * add some juice reagents and apply them to their drink prototypes * re add glassyellow * implement juicing and results * add time delay to grindjuice * add reagent grinder visualizer, add reagent grinder sounds, fix some yaml errors too * interface has clear indication of currennt operation, and busy status * add ReagentGrinder to Client ignnored components * Update Content.Client/GameObjects/Components/Kitchen/ReagentGrinderBoundUserInterface.cs Co-authored-by: metalgearsloth <31366439+metalgearsloth@users.noreply.github.com> * Update Content.Client/GameObjects/Components/Kitchen/ReagentGrinderBoundUserInterface.cs Co-authored-by: metalgearsloth <31366439+metalgearsloth@users.noreply.github.com> * Update Content.Shared/Kitchen/SharedReagentGrinderComponent.cs Co-authored-by: metalgearsloth <31366439+metalgearsloth@users.noreply.github.com> * implemennt sloth changes * fix isbusy * Disable grind/juice buttons if there's nothing to grind or juice, also some misc fixes * unsubscribe from messages on remove + fix xmlcomment * fix bounding box * Add these to dictionary * Add these to client ignore * Whitespace and unneeded import fixes * tommy's toes * Where'd these newlines come from * power * improve bounding box * Check power better & show contents when beaker is ejected * check power here * Disable eject buttons when running * improve comments * readwrite for viewvars on work time and capacity * Address most of Sloth's reviews * Make this cleaner * add grindablecomponent to motherfucking everything * Fix reviews * some more null suppressions * remove unused random field Co-authored-by: scuffedjays <yetanotherscuffed@gmail.com> Co-authored-by: namespace-Memory <66768086+namespace-Memory@users.noreply.github.com> Co-authored-by: metalgearsloth <31366439+metalgearsloth@users.noreply.github.com>
This commit is contained in:
@@ -0,0 +1,292 @@
|
|||||||
|
using System.Collections.Generic;
|
||||||
|
using Robust.Client.GameObjects.Components.UserInterface;
|
||||||
|
using Robust.Client.UserInterface;
|
||||||
|
using Robust.Client.UserInterface.Controls;
|
||||||
|
using Robust.Client.UserInterface.CustomControls;
|
||||||
|
using Robust.Shared.GameObjects.Components.UserInterface;
|
||||||
|
using Robust.Shared.Localization;
|
||||||
|
using Robust.Shared.Maths;
|
||||||
|
using Content.Shared.Kitchen;
|
||||||
|
using Robust.Shared.GameObjects;
|
||||||
|
using Content.Shared.Chemistry;
|
||||||
|
using Robust.Shared.IoC;
|
||||||
|
using Robust.Shared.Interfaces.GameObjects;
|
||||||
|
using Robust.Shared.Prototypes;
|
||||||
|
using Robust.Client.GameObjects;
|
||||||
|
|
||||||
|
namespace Content.Client.GameObjects.Components.Kitchen
|
||||||
|
{
|
||||||
|
public class ReagentGrinderBoundUserInterface : BoundUserInterface
|
||||||
|
{
|
||||||
|
[Dependency] private readonly IEntityManager _entityManager = default!;
|
||||||
|
[Dependency] private readonly IPrototypeManager _prototypeManager = default!;
|
||||||
|
|
||||||
|
private GrinderMenu _menu;
|
||||||
|
private Dictionary<int, EntityUid> _chamberVisualContents = new Dictionary<int, EntityUid>();
|
||||||
|
private Dictionary<int, Solution.ReagentQuantity> _beakerVisualContents = new Dictionary<int, Solution.ReagentQuantity>();
|
||||||
|
public ReagentGrinderBoundUserInterface(ClientUserInterfaceComponent owner, object uiKey) : base(owner, uiKey) { }
|
||||||
|
|
||||||
|
protected override void Open()
|
||||||
|
{
|
||||||
|
base.Open();
|
||||||
|
_menu = new GrinderMenu(this);
|
||||||
|
_menu.OpenCentered();
|
||||||
|
_menu.OnClose += Close;
|
||||||
|
_menu.GrindButton.OnPressed += args => SendMessage(new SharedReagentGrinderComponent.ReagentGrinderGrindStartMessage());
|
||||||
|
_menu.JuiceButton.OnPressed += args => SendMessage(new SharedReagentGrinderComponent.ReagentGrinderJuiceStartMessage());
|
||||||
|
_menu.ChamberContentBox.EjectButton.OnPressed += args => SendMessage(new SharedReagentGrinderComponent.ReagentGrinderEjectChamberAllMessage());
|
||||||
|
_menu.BeakerContentBox.EjectButton.OnPressed += args => SendMessage(new SharedReagentGrinderComponent.ReagentGrinderEjectBeakerMessage());
|
||||||
|
_menu.ChamberContentBox.BoxContents.OnItemSelected += args =>
|
||||||
|
{
|
||||||
|
SendMessage(new SharedReagentGrinderComponent.ReagentGrinderEjectChamberContentMessage(_chamberVisualContents[args.ItemIndex]));
|
||||||
|
};
|
||||||
|
|
||||||
|
_menu.BeakerContentBox.BoxContents.OnItemSelected += args =>
|
||||||
|
{
|
||||||
|
SendMessage(new SharedReagentGrinderComponent.ReagentGrinderVaporizeReagentIndexedMessage(_beakerVisualContents[args.ItemIndex]));
|
||||||
|
};
|
||||||
|
}
|
||||||
|
|
||||||
|
protected override void Dispose(bool disposing)
|
||||||
|
{
|
||||||
|
base.Dispose(disposing);
|
||||||
|
if (!disposing)
|
||||||
|
{
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
_chamberVisualContents?.Clear();
|
||||||
|
_beakerVisualContents?.Clear();
|
||||||
|
_menu?.Dispose();
|
||||||
|
}
|
||||||
|
|
||||||
|
protected override void UpdateState(BoundUserInterfaceState state)
|
||||||
|
{
|
||||||
|
base.UpdateState(state);
|
||||||
|
if (!(state is ReagentGrinderInterfaceState cState))
|
||||||
|
{
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
_menu.BeakerContentBox.EjectButton.Disabled = !cState.HasBeakerIn;
|
||||||
|
_menu.ChamberContentBox.EjectButton.Disabled = cState.ChamberContents.Length <= 0;
|
||||||
|
_menu.GrindButton.Disabled = !cState.CanGrind || !cState.Powered;
|
||||||
|
_menu.JuiceButton.Disabled = !cState.CanJuice || !cState.Powered;
|
||||||
|
RefreshContentsDisplay(cState.ReagentQuantities, cState.ChamberContents, cState.HasBeakerIn);
|
||||||
|
}
|
||||||
|
|
||||||
|
protected override void ReceiveMessage(BoundUserInterfaceMessage message)
|
||||||
|
{
|
||||||
|
base.ReceiveMessage(message);
|
||||||
|
switch (message)
|
||||||
|
{
|
||||||
|
case SharedReagentGrinderComponent.ReagentGrinderWorkStartedMessage workStarted:
|
||||||
|
_menu.GrindButton.Disabled = true;
|
||||||
|
_menu.GrindButton.Modulate = workStarted.GrinderProgram == SharedReagentGrinderComponent.GrinderProgram.Grind ? Color.Green : Color.White;
|
||||||
|
_menu.JuiceButton.Disabled = true;
|
||||||
|
_menu.JuiceButton.Modulate = workStarted.GrinderProgram == SharedReagentGrinderComponent.GrinderProgram.Juice ? Color.Green : Color.White;
|
||||||
|
_menu.BeakerContentBox.EjectButton.Disabled = true;
|
||||||
|
_menu.ChamberContentBox.EjectButton.Disabled = true;
|
||||||
|
break;
|
||||||
|
case SharedReagentGrinderComponent.ReagentGrinderWorkCompleteMessage doneMessage:
|
||||||
|
_menu.GrindButton.Disabled = false;
|
||||||
|
_menu.JuiceButton.Disabled = false;
|
||||||
|
_menu.GrindButton.Modulate = Color.White;
|
||||||
|
_menu.JuiceButton.Modulate = Color.White;
|
||||||
|
_menu.BeakerContentBox.EjectButton.Disabled = false;
|
||||||
|
_menu.ChamberContentBox.EjectButton.Disabled = false;
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
private void RefreshContentsDisplay(IList<Solution.ReagentQuantity> reagents, IReadOnlyList<EntityUid> containedSolids, bool isBeakerAttached)
|
||||||
|
{
|
||||||
|
//Refresh chamber contents
|
||||||
|
_chamberVisualContents.Clear();
|
||||||
|
_menu.ChamberContentBox.BoxContents.Clear();
|
||||||
|
foreach (var uid in containedSolids)
|
||||||
|
{
|
||||||
|
if (!_entityManager.TryGetEntity(uid, out var entity))
|
||||||
|
{
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
var texture = entity.GetComponent<SpriteComponent>().Icon?.Default;
|
||||||
|
|
||||||
|
var solidItem = _menu.ChamberContentBox.BoxContents.AddItem(entity.Name, texture);
|
||||||
|
var solidIndex = _menu.ChamberContentBox.BoxContents.IndexOf(solidItem);
|
||||||
|
_chamberVisualContents.Add(solidIndex, uid);
|
||||||
|
}
|
||||||
|
|
||||||
|
//Refresh beaker contents
|
||||||
|
_beakerVisualContents.Clear();
|
||||||
|
_menu.BeakerContentBox.BoxContents.Clear();
|
||||||
|
//if no beaker is attached use this guard to prevent hitting a null reference.
|
||||||
|
if (!isBeakerAttached || reagents == null)
|
||||||
|
{
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
//Looks like we have a beaker attached.
|
||||||
|
if (reagents.Count <= 0)
|
||||||
|
{
|
||||||
|
_menu.BeakerContentBox.BoxContents.AddItem(Loc.GetString("Empty"));
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
for (var i = 0; i < reagents.Count; i++)
|
||||||
|
{
|
||||||
|
var goodIndex = _prototypeManager.TryIndex(reagents[i].ReagentId, out ReagentPrototype proto);
|
||||||
|
var reagentName = goodIndex ? Loc.GetString($"{reagents[i].Quantity} {proto.Name}") : Loc.GetString("???");
|
||||||
|
var reagentAdded = _menu.BeakerContentBox.BoxContents.AddItem(reagentName);
|
||||||
|
var reagentIndex = _menu.BeakerContentBox.BoxContents.IndexOf(reagentAdded);
|
||||||
|
_beakerVisualContents.Add(reagentIndex, reagents[i]);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
public class GrinderMenu : SS14Window
|
||||||
|
{
|
||||||
|
/*The contents of the chamber and beaker will both be vertical scroll rectangles.
|
||||||
|
* Will have a vsplit to split the g/j buttons from the contents menu.
|
||||||
|
* |--------------------------------\
|
||||||
|
* | | Chamber [E] Beaker [E] |
|
||||||
|
* | [G] | | | | | |
|
||||||
|
* | | | | | | |
|
||||||
|
* | | | | | | |
|
||||||
|
* | [J] | |-----| |-----| |
|
||||||
|
* | | |
|
||||||
|
* \---------------------------------/
|
||||||
|
*
|
||||||
|
*/
|
||||||
|
|
||||||
|
private ReagentGrinderBoundUserInterface Owner { get; set; }
|
||||||
|
protected override Vector2? CustomSize => (512, 256);
|
||||||
|
|
||||||
|
//We'll need 4 buttons, grind, juice, eject beaker, eject the chamber contents.
|
||||||
|
//The other 2 are referenced in the Open function.
|
||||||
|
public Button GrindButton { get; }
|
||||||
|
public Button JuiceButton { get; }
|
||||||
|
|
||||||
|
public LabelledContentBox ChamberContentBox { get; }
|
||||||
|
public LabelledContentBox BeakerContentBox { get; }
|
||||||
|
|
||||||
|
public sealed class LabelledContentBox : VBoxContainer
|
||||||
|
{
|
||||||
|
public string LabelText { get; set; }
|
||||||
|
public ItemList BoxContents { get; set; }
|
||||||
|
|
||||||
|
public Button EjectButton { get; set; }
|
||||||
|
|
||||||
|
private Label _label;
|
||||||
|
|
||||||
|
public LabelledContentBox(string labelText, string buttonText)
|
||||||
|
{
|
||||||
|
|
||||||
|
_label = new Label
|
||||||
|
{
|
||||||
|
Text = labelText,
|
||||||
|
Align = Label.AlignMode.Center,
|
||||||
|
};
|
||||||
|
|
||||||
|
EjectButton = new Button
|
||||||
|
{
|
||||||
|
Text = buttonText,
|
||||||
|
TextAlign = Label.AlignMode.Center,
|
||||||
|
};
|
||||||
|
|
||||||
|
var vSplit = new HSplitContainer
|
||||||
|
{
|
||||||
|
Children =
|
||||||
|
{
|
||||||
|
_label,
|
||||||
|
EjectButton
|
||||||
|
}
|
||||||
|
};
|
||||||
|
|
||||||
|
AddChild(vSplit);
|
||||||
|
BoxContents = new ItemList
|
||||||
|
{
|
||||||
|
SizeFlagsVertical = SizeFlags.FillExpand,
|
||||||
|
SizeFlagsHorizontal = SizeFlags.FillExpand,
|
||||||
|
SelectMode = ItemList.ItemListSelectMode.Button,
|
||||||
|
SizeFlagsStretchRatio = 2,
|
||||||
|
CustomMinimumSize = (100, 128)
|
||||||
|
};
|
||||||
|
AddChild(BoxContents);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
public GrinderMenu(ReagentGrinderBoundUserInterface owner = null)
|
||||||
|
{
|
||||||
|
Owner = owner;
|
||||||
|
Title = Loc.GetString("All-In-One Grinder 3000");
|
||||||
|
|
||||||
|
var hSplit = new HBoxContainer
|
||||||
|
{
|
||||||
|
SizeFlagsHorizontal = SizeFlags.Fill,
|
||||||
|
SizeFlagsVertical = SizeFlags.Fill
|
||||||
|
};
|
||||||
|
|
||||||
|
var vBoxGrindJuiceButtonPanel = new VBoxContainer
|
||||||
|
{
|
||||||
|
SizeFlagsVertical = SizeFlags.ShrinkCenter
|
||||||
|
};
|
||||||
|
|
||||||
|
GrindButton = new Button
|
||||||
|
{
|
||||||
|
Text = Loc.GetString("Grind"),
|
||||||
|
TextAlign = Label.AlignMode.Center,
|
||||||
|
CustomMinimumSize = (64, 64)
|
||||||
|
};
|
||||||
|
|
||||||
|
JuiceButton = new Button
|
||||||
|
{
|
||||||
|
Text = Loc.GetString("Juice"),
|
||||||
|
TextAlign = Label.AlignMode.Center,
|
||||||
|
CustomMinimumSize = (64, 64)
|
||||||
|
};
|
||||||
|
|
||||||
|
vBoxGrindJuiceButtonPanel.AddChild(GrindButton);
|
||||||
|
//inner button padding
|
||||||
|
vBoxGrindJuiceButtonPanel.AddChild(new Control
|
||||||
|
{
|
||||||
|
CustomMinimumSize = (0, 16),
|
||||||
|
});
|
||||||
|
vBoxGrindJuiceButtonPanel.AddChild(JuiceButton);
|
||||||
|
|
||||||
|
ChamberContentBox = new LabelledContentBox(Loc.GetString("Chamber"), Loc.GetString("Eject Contents"))
|
||||||
|
{
|
||||||
|
//Modulate = Color.Red,
|
||||||
|
SizeFlagsVertical = SizeFlags.FillExpand,
|
||||||
|
SizeFlagsHorizontal = SizeFlags.FillExpand,
|
||||||
|
SizeFlagsStretchRatio = 2,
|
||||||
|
|
||||||
|
};
|
||||||
|
|
||||||
|
BeakerContentBox = new LabelledContentBox(Loc.GetString("Beaker"), Loc.GetString("Eject Beaker"))
|
||||||
|
{
|
||||||
|
//Modulate = Color.Blue,
|
||||||
|
SizeFlagsVertical = SizeFlags.FillExpand,
|
||||||
|
SizeFlagsHorizontal = SizeFlags.FillExpand,
|
||||||
|
SizeFlagsStretchRatio = 2,
|
||||||
|
};
|
||||||
|
|
||||||
|
hSplit.AddChild(vBoxGrindJuiceButtonPanel);
|
||||||
|
|
||||||
|
//Padding between the g/j buttons panel and the itemlist boxes panel.
|
||||||
|
hSplit.AddChild(new Control
|
||||||
|
{
|
||||||
|
CustomMinimumSize = (16, 0),
|
||||||
|
});
|
||||||
|
hSplit.AddChild(ChamberContentBox);
|
||||||
|
|
||||||
|
//Padding between the two itemlists.
|
||||||
|
hSplit.AddChild(new Control
|
||||||
|
{
|
||||||
|
CustomMinimumSize = (8, 0),
|
||||||
|
});
|
||||||
|
hSplit.AddChild(BeakerContentBox);
|
||||||
|
Contents.AddChild(hSplit);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
@@ -0,0 +1,17 @@
|
|||||||
|
using Robust.Client.GameObjects;
|
||||||
|
using Robust.Client.Interfaces.GameObjects.Components;
|
||||||
|
using static Content.Shared.Kitchen.SharedReagentGrinderComponent;
|
||||||
|
|
||||||
|
namespace Content.Client.GameObjects.Components.Kitchen
|
||||||
|
{
|
||||||
|
public class ReagentGrinderVisualizer : AppearanceVisualizer
|
||||||
|
{
|
||||||
|
public override void OnChangeData(AppearanceComponent component)
|
||||||
|
{
|
||||||
|
base.OnChangeData(component);
|
||||||
|
var sprite = component.Owner.GetComponent<ISpriteComponent>();
|
||||||
|
component.TryGetData(ReagentGrinderVisualState.BeakerAttached, out bool hasBeaker);
|
||||||
|
sprite.LayerSetState(0, $"juicer{(hasBeaker ? "1" : "0")}");
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
@@ -209,6 +209,9 @@
|
|||||||
"CrematoriumEntityStorage",
|
"CrematoriumEntityStorage",
|
||||||
"RandomArcade",
|
"RandomArcade",
|
||||||
"RandomSpriteState",
|
"RandomSpriteState",
|
||||||
|
"ReagentGrinder",
|
||||||
|
"Grindable",
|
||||||
|
"Juiceable",
|
||||||
"WelderRefinable",
|
"WelderRefinable",
|
||||||
"ConveyorAssembly",
|
"ConveyorAssembly",
|
||||||
"TwoWayLever",
|
"TwoWayLever",
|
||||||
|
|||||||
@@ -0,0 +1,13 @@
|
|||||||
|
using Robust.Shared.GameObjects;
|
||||||
|
|
||||||
|
namespace Content.Server.GameObjects.Components.Kitchen
|
||||||
|
{
|
||||||
|
/// <summary>
|
||||||
|
/// Tag component that denotes an entity as Grindable by the reagentgrinder.
|
||||||
|
/// </summary>
|
||||||
|
[RegisterComponent]
|
||||||
|
public class GrindableComponent : Component
|
||||||
|
{
|
||||||
|
public override string Name => "Grindable";
|
||||||
|
}
|
||||||
|
}
|
||||||
@@ -0,0 +1,23 @@
|
|||||||
|
using Content.Shared.Chemistry;
|
||||||
|
using Robust.Shared.GameObjects;
|
||||||
|
using Robust.Shared.Serialization;
|
||||||
|
using Robust.Shared.ViewVariables;
|
||||||
|
|
||||||
|
namespace Content.Server.GameObjects.Components.Kitchen
|
||||||
|
{
|
||||||
|
/// <summary>
|
||||||
|
/// Tag component that denotes an entity as Juiceable
|
||||||
|
/// </summary>
|
||||||
|
[RegisterComponent]
|
||||||
|
public class JuiceableComponent : Component
|
||||||
|
{
|
||||||
|
public override string Name => "Juiceable";
|
||||||
|
[ViewVariables] public Solution JuiceResultSolution;
|
||||||
|
public override void ExposeData(ObjectSerializer serializer)
|
||||||
|
{
|
||||||
|
base.ExposeData(serializer);
|
||||||
|
serializer.DataField(this, x => x.JuiceResultSolution, "result", new Solution());
|
||||||
|
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
@@ -0,0 +1,375 @@
|
|||||||
|
#nullable enable
|
||||||
|
using System;
|
||||||
|
using System.Linq;
|
||||||
|
using System.Threading.Tasks;
|
||||||
|
using Content.Server.GameObjects.Components.Chemistry;
|
||||||
|
using Content.Server.GameObjects.Components.GUI;
|
||||||
|
using Content.Server.GameObjects.Components.Items.Storage;
|
||||||
|
using Content.Server.GameObjects.Components.Power.ApcNetComponents;
|
||||||
|
using Content.Server.Interfaces.GameObjects.Components.Items;
|
||||||
|
using Content.Server.Utility;
|
||||||
|
using Content.Shared.Chemistry;
|
||||||
|
using Content.Shared.Interfaces;
|
||||||
|
using Content.Shared.Interfaces.GameObjects.Components;
|
||||||
|
using Content.Shared.Kitchen;
|
||||||
|
using Content.Shared.Utility;
|
||||||
|
using Robust.Server.GameObjects;
|
||||||
|
using Robust.Server.GameObjects.Components.Container;
|
||||||
|
using Robust.Server.GameObjects.Components.UserInterface;
|
||||||
|
using Robust.Server.GameObjects.EntitySystems;
|
||||||
|
using Robust.Server.Interfaces.GameObjects;
|
||||||
|
using Robust.Shared.Audio;
|
||||||
|
using Robust.Shared.GameObjects;
|
||||||
|
using Robust.Shared.GameObjects.Components.Timers;
|
||||||
|
using Robust.Shared.GameObjects.Systems;
|
||||||
|
using Robust.Shared.Interfaces.GameObjects;
|
||||||
|
using Robust.Shared.Localization;
|
||||||
|
using Robust.Shared.Serialization;
|
||||||
|
using Robust.Shared.ViewVariables;
|
||||||
|
|
||||||
|
namespace Content.Server.GameObjects.Components.Kitchen
|
||||||
|
{
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// The combo reagent grinder/juicer. The reason why grinding and juicing are seperate is simple,
|
||||||
|
/// think of grinding as a utility to break an object down into its reagents. Think of juicing as
|
||||||
|
/// converting something into its single juice form. E.g, grind an apple and get the nutriment and sugar
|
||||||
|
/// it contained, juice an apple and get "apple juice".
|
||||||
|
/// </summary>
|
||||||
|
[RegisterComponent]
|
||||||
|
[ComponentReference(typeof(IActivate))]
|
||||||
|
public class ReagentGrinderComponent : SharedReagentGrinderComponent, IActivate, IInteractUsing
|
||||||
|
{
|
||||||
|
private AudioSystem _audioSystem = default!;
|
||||||
|
[ViewVariables] private ContainerSlot _beakerContainer = default!;
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// Can be null since we won't always have a beaker in the grinder.
|
||||||
|
/// </summary>
|
||||||
|
[ViewVariables] private SolutionContainerComponent? _heldBeaker = default!;
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// Contains the things that are going to be ground or juiced.
|
||||||
|
/// </summary>
|
||||||
|
[ViewVariables] private Container _chamber = default!;
|
||||||
|
|
||||||
|
[ViewVariables] private bool ChamberEmpty => _chamber.ContainedEntities.Count <= 0;
|
||||||
|
[ViewVariables] private bool HasBeaker => _beakerContainer.ContainedEntity != null;
|
||||||
|
[ViewVariables] private BoundUserInterface? UserInterface => Owner.GetUIOrNull(ReagentGrinderUiKey.Key);
|
||||||
|
|
||||||
|
private bool Powered => !Owner.TryGetComponent(out PowerReceiverComponent? receiver) || receiver.Powered;
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// Should the BoundUI be told to update?
|
||||||
|
/// </summary>
|
||||||
|
private bool _uiDirty = true;
|
||||||
|
/// <summary>
|
||||||
|
/// Is the machine actively doing something and can't be used right now?
|
||||||
|
/// </summary>
|
||||||
|
private bool _busy = false;
|
||||||
|
|
||||||
|
//YAML serialization vars
|
||||||
|
[ViewVariables(VVAccess.ReadWrite)] private int _storageCap = 16;
|
||||||
|
[ViewVariables(VVAccess.ReadWrite)] private int _workTime = 3500; //3.5 seconds, completely arbitrary for now.
|
||||||
|
|
||||||
|
public override void ExposeData(ObjectSerializer serializer)
|
||||||
|
{
|
||||||
|
base.ExposeData(serializer);
|
||||||
|
serializer.DataField(ref _storageCap, "chamberCapacity", 16);
|
||||||
|
serializer.DataField(ref _workTime, "workTime", 3500);
|
||||||
|
}
|
||||||
|
|
||||||
|
public override void Initialize()
|
||||||
|
{
|
||||||
|
base.Initialize();
|
||||||
|
//A slot for the beaker where the grounds/juices will go.
|
||||||
|
_beakerContainer =
|
||||||
|
ContainerManagerComponent.Ensure<ContainerSlot>($"{Name}-reagentContainerContainer", Owner);
|
||||||
|
|
||||||
|
//A container for the things that WILL be ground/juiced. Useful for ejecting them instead of deleting them from the hands of the user.
|
||||||
|
_chamber =
|
||||||
|
ContainerManagerComponent.Ensure<Container>($"{Name}-entityContainerContainer", Owner);
|
||||||
|
|
||||||
|
if (UserInterface != null)
|
||||||
|
{
|
||||||
|
UserInterface.OnReceiveMessage += UserInterfaceOnReceiveMessage;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (Owner.TryGetComponent(out PowerReceiverComponent? receiver))
|
||||||
|
{
|
||||||
|
receiver.OnPowerStateChanged += OnPowerStateChanged;
|
||||||
|
}
|
||||||
|
|
||||||
|
_audioSystem = EntitySystem.Get<AudioSystem>();
|
||||||
|
}
|
||||||
|
|
||||||
|
public override void OnRemove()
|
||||||
|
{
|
||||||
|
base.OnRemove();
|
||||||
|
if (UserInterface != null)
|
||||||
|
{
|
||||||
|
UserInterface.OnReceiveMessage -= UserInterfaceOnReceiveMessage;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (Owner.TryGetComponent(out PowerReceiverComponent? receiver))
|
||||||
|
{
|
||||||
|
receiver.OnPowerStateChanged -= OnPowerStateChanged;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
private void UserInterfaceOnReceiveMessage(ServerBoundUserInterfaceMessage message)
|
||||||
|
{
|
||||||
|
if(_busy)
|
||||||
|
{
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
switch(message.Message)
|
||||||
|
{
|
||||||
|
case ReagentGrinderGrindStartMessage msg:
|
||||||
|
if (!Powered) break;
|
||||||
|
ClickSound();
|
||||||
|
DoWork(message.Session.AttachedEntity!, GrinderProgram.Grind);
|
||||||
|
break;
|
||||||
|
|
||||||
|
case ReagentGrinderJuiceStartMessage msg:
|
||||||
|
if (!Powered) break;
|
||||||
|
ClickSound();
|
||||||
|
DoWork(message.Session.AttachedEntity!, GrinderProgram.Juice);
|
||||||
|
break;
|
||||||
|
|
||||||
|
case ReagentGrinderEjectChamberAllMessage msg:
|
||||||
|
if(!ChamberEmpty)
|
||||||
|
{
|
||||||
|
ClickSound();
|
||||||
|
for (var i = _chamber.ContainedEntities.Count - 1; i >= 0; i--)
|
||||||
|
{
|
||||||
|
EjectSolid(_chamber.ContainedEntities.ElementAt(i).Uid);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
break;
|
||||||
|
|
||||||
|
case ReagentGrinderEjectChamberContentMessage msg:
|
||||||
|
if (!ChamberEmpty)
|
||||||
|
{
|
||||||
|
EjectSolid(msg.EntityID);
|
||||||
|
ClickSound();
|
||||||
|
_uiDirty = true;
|
||||||
|
}
|
||||||
|
break;
|
||||||
|
|
||||||
|
case ReagentGrinderEjectBeakerMessage msg:
|
||||||
|
ClickSound();
|
||||||
|
EjectBeaker(message.Session.AttachedEntity);
|
||||||
|
//EjectBeaker will dirty the UI for us, we don't have to do it explicitly here.
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
private void OnPowerStateChanged(object? sender, PowerStateEventArgs e)
|
||||||
|
{
|
||||||
|
_uiDirty = true;
|
||||||
|
}
|
||||||
|
|
||||||
|
private void ClickSound()
|
||||||
|
{
|
||||||
|
_audioSystem.PlayFromEntity("/Audio/Machines/machine_switch.ogg", Owner, AudioParams.Default.WithVolume(-2f));
|
||||||
|
}
|
||||||
|
|
||||||
|
private void SetAppearance()
|
||||||
|
{
|
||||||
|
if (Owner.TryGetComponent(out AppearanceComponent? appearance))
|
||||||
|
{
|
||||||
|
appearance.SetData(ReagentGrinderVisualState.BeakerAttached, HasBeaker);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
public void OnUpdate()
|
||||||
|
{
|
||||||
|
if(_uiDirty)
|
||||||
|
{
|
||||||
|
UpdateInterface();
|
||||||
|
_uiDirty = false;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
// This doesn't check for UI dirtiness so handle that when calling this.
|
||||||
|
private void UpdateInterface()
|
||||||
|
{
|
||||||
|
bool canJuice = false;
|
||||||
|
bool canGrind = false;
|
||||||
|
if (HasBeaker)
|
||||||
|
{
|
||||||
|
foreach (var entity in _chamber.ContainedEntities)
|
||||||
|
{
|
||||||
|
if (!canJuice && entity.HasComponent<JuiceableComponent>()) canJuice = true;
|
||||||
|
if (!canGrind && entity.HasComponent<GrindableComponent>()) canGrind = true;
|
||||||
|
if (canJuice && canGrind) break;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
UserInterface?.SetState(new ReagentGrinderInterfaceState
|
||||||
|
(
|
||||||
|
_busy,
|
||||||
|
HasBeaker,
|
||||||
|
Powered,
|
||||||
|
canJuice,
|
||||||
|
canGrind,
|
||||||
|
_chamber.ContainedEntities.Select(item => item.Uid).ToArray(),
|
||||||
|
//Remember the beaker can be null!
|
||||||
|
_heldBeaker?.Solution.Contents.ToArray()
|
||||||
|
));
|
||||||
|
_uiDirty = false;
|
||||||
|
}
|
||||||
|
|
||||||
|
private void EjectSolid(EntityUid entityID)
|
||||||
|
{
|
||||||
|
if (_busy)
|
||||||
|
return;
|
||||||
|
|
||||||
|
if (Owner.EntityManager.TryGetEntity(entityID, out var entity))
|
||||||
|
{
|
||||||
|
_chamber.Remove(entity);
|
||||||
|
|
||||||
|
//Give the ejected entity a tiny bit of offset so each one is apparent in case of a big stack,
|
||||||
|
//but (hopefully) not enough to clip it through a solid (wall).
|
||||||
|
entity.RandomOffset(0.4f);
|
||||||
|
}
|
||||||
|
_uiDirty = true;
|
||||||
|
}
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// Tries to eject whatever is in the beaker slot. Puts the item in the user's hands or failing that on top
|
||||||
|
/// of the grinder.
|
||||||
|
/// </summary>
|
||||||
|
private void EjectBeaker(IEntity? user)
|
||||||
|
{
|
||||||
|
if (!HasBeaker || _heldBeaker == null || _busy)
|
||||||
|
return;
|
||||||
|
|
||||||
|
_beakerContainer.Remove(_beakerContainer.ContainedEntity);
|
||||||
|
|
||||||
|
if (user == null || !user.TryGetComponent<HandsComponent>(out var hands) || !_heldBeaker.Owner.TryGetComponent<ItemComponent>(out var item))
|
||||||
|
return;
|
||||||
|
hands.PutInHandOrDrop(item);
|
||||||
|
|
||||||
|
_heldBeaker = null;
|
||||||
|
_uiDirty = true;
|
||||||
|
SetAppearance();
|
||||||
|
}
|
||||||
|
|
||||||
|
void IActivate.Activate(ActivateEventArgs eventArgs)
|
||||||
|
{
|
||||||
|
if (!eventArgs.User.TryGetComponent(out IActorComponent? actor))
|
||||||
|
{
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
_uiDirty = true;
|
||||||
|
UserInterface?.Toggle(actor.playerSession);
|
||||||
|
}
|
||||||
|
|
||||||
|
public async Task<bool> InteractUsing(InteractUsingEventArgs eventArgs)
|
||||||
|
{
|
||||||
|
if (!eventArgs.User.TryGetComponent(out IHandsComponent? hands))
|
||||||
|
{
|
||||||
|
Owner.PopupMessage(eventArgs.User, Loc.GetString("You have no hands."));
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
|
||||||
|
IEntity heldEnt = eventArgs.Using;
|
||||||
|
|
||||||
|
//First, check if user is trying to insert a beaker.
|
||||||
|
//No promise it will be a beaker right now, but whatever.
|
||||||
|
//Maybe this should whitelist "beaker" in the prototype id of heldEnt?
|
||||||
|
if(heldEnt.TryGetComponent(out SolutionContainerComponent? beaker) && beaker.Capabilities.HasFlag(SolutionContainerCaps.FitsInDispenser))
|
||||||
|
{
|
||||||
|
_beakerContainer.Insert(heldEnt);
|
||||||
|
_heldBeaker = beaker;
|
||||||
|
_uiDirty = true;
|
||||||
|
//We are done, return. Insert the beaker and exit!
|
||||||
|
SetAppearance();
|
||||||
|
ClickSound();
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
|
||||||
|
//Next, see if the user is trying to insert something they want to be ground/juiced.
|
||||||
|
if(!heldEnt.TryGetComponent(out GrindableComponent? grind) && !heldEnt.TryGetComponent(out JuiceableComponent? juice))
|
||||||
|
{
|
||||||
|
//Entity did NOT pass the whitelist for grind/juice.
|
||||||
|
//Wouldn't want the clown grinding up the Captain's ID card now would you?
|
||||||
|
//Why am I asking you? You're biased.
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
|
||||||
|
//Cap the chamber. Don't want someone putting in 500 entities and ejecting them all at once.
|
||||||
|
//Maybe I should have done that for the microwave too?
|
||||||
|
if (_chamber.ContainedEntities.Count >= _storageCap)
|
||||||
|
{
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (!_chamber.Insert(heldEnt))
|
||||||
|
return false;
|
||||||
|
|
||||||
|
_uiDirty = true;
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// The wzhzhzh of the grinder. Processes the contents of the grinder and puts the output in the beaker.
|
||||||
|
/// </summary>
|
||||||
|
/// <param name="isJuiceIntent">true for wanting to juice, false for wanting to grind.</param>
|
||||||
|
private async void DoWork(IEntity user, GrinderProgram program)
|
||||||
|
{
|
||||||
|
//Have power, are we busy, chamber has anything to grind, a beaker for the grounds to go?
|
||||||
|
if(!Powered || _busy || ChamberEmpty || !HasBeaker || _heldBeaker == null)
|
||||||
|
{
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
_busy = true;
|
||||||
|
|
||||||
|
UserInterface?.SendMessage(new ReagentGrinderWorkStartedMessage(program));
|
||||||
|
switch (program)
|
||||||
|
{
|
||||||
|
case GrinderProgram.Grind:
|
||||||
|
_audioSystem.PlayFromEntity("/Audio/Machines/blender.ogg", Owner, AudioParams.Default);
|
||||||
|
//Get each item inside the chamber and get the reagents it contains. Transfer those reagents to the beaker, given we have one in.
|
||||||
|
Owner.SpawnTimer(_workTime, (Action) (() =>
|
||||||
|
{
|
||||||
|
foreach (var item in _chamber.ContainedEntities.ToList())
|
||||||
|
{
|
||||||
|
if (!item.HasComponent<GrindableComponent>()) continue;
|
||||||
|
if (!item.TryGetComponent<SolutionContainerComponent>(out var solution)) continue;
|
||||||
|
if (_heldBeaker.CurrentVolume + solution.CurrentVolume > _heldBeaker.MaxVolume) continue;
|
||||||
|
_heldBeaker.TryAddSolution(solution.Solution);
|
||||||
|
solution.RemoveAllSolution();
|
||||||
|
item.Delete();
|
||||||
|
}
|
||||||
|
|
||||||
|
_busy = false;
|
||||||
|
_uiDirty = true;
|
||||||
|
UserInterface?.SendMessage(new ReagentGrinderWorkCompleteMessage());
|
||||||
|
}));
|
||||||
|
break;
|
||||||
|
|
||||||
|
case GrinderProgram.Juice:
|
||||||
|
_audioSystem.PlayFromEntity("/Audio/Machines/juicer.ogg", Owner, AudioParams.Default);
|
||||||
|
Owner.SpawnTimer(_workTime, (Action) (() =>
|
||||||
|
{
|
||||||
|
foreach (var item in _chamber.ContainedEntities.ToList())
|
||||||
|
{
|
||||||
|
if (!item.TryGetComponent<JuiceableComponent>(out var juiceMe)) continue;
|
||||||
|
if (_heldBeaker.CurrentVolume + juiceMe.JuiceResultSolution.TotalVolume > _heldBeaker.MaxVolume) continue;
|
||||||
|
_heldBeaker.TryAddSolution(juiceMe.JuiceResultSolution);
|
||||||
|
item.Delete();
|
||||||
|
}
|
||||||
|
UserInterface?.SendMessage(new ReagentGrinderWorkCompleteMessage());
|
||||||
|
_busy = false;
|
||||||
|
_uiDirty = true;
|
||||||
|
}));
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
@@ -0,0 +1,19 @@
|
|||||||
|
using Content.Server.GameObjects.Components.Kitchen;
|
||||||
|
using JetBrains.Annotations;
|
||||||
|
using Robust.Shared.GameObjects.Systems;
|
||||||
|
|
||||||
|
namespace Content.Server.GameObjects.EntitySystems
|
||||||
|
{
|
||||||
|
[UsedImplicitly]
|
||||||
|
internal sealed class ReagentGrinderSystem : EntitySystem
|
||||||
|
{
|
||||||
|
public override void Update(float frameTime)
|
||||||
|
{
|
||||||
|
base.Update(frameTime);
|
||||||
|
foreach (var comp in ComponentManager.EntityQuery<ReagentGrinderComponent>())
|
||||||
|
{
|
||||||
|
comp.OnUpdate();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
@@ -85,6 +85,7 @@
|
|||||||
public const uint GAS_TANK = 1079;
|
public const uint GAS_TANK = 1079;
|
||||||
public const uint SINGULARITY = 1080;
|
public const uint SINGULARITY = 1080;
|
||||||
public const uint CHARACTERINFO = 1081;
|
public const uint CHARACTERINFO = 1081;
|
||||||
|
public const uint REAGENT_GRINDER = 1082;
|
||||||
|
|
||||||
// Net IDs for integration tests.
|
// Net IDs for integration tests.
|
||||||
public const uint PREDICTION_TEST = 10001;
|
public const uint PREDICTION_TEST = 10001;
|
||||||
|
|||||||
126
Content.Shared/Kitchen/SharedReagentGrinderComponent.cs
Normal file
126
Content.Shared/Kitchen/SharedReagentGrinderComponent.cs
Normal file
@@ -0,0 +1,126 @@
|
|||||||
|
using System;
|
||||||
|
using Content.Shared.Chemistry;
|
||||||
|
using Content.Shared.GameObjects;
|
||||||
|
using Robust.Shared.GameObjects;
|
||||||
|
using Robust.Shared.GameObjects.Components.UserInterface;
|
||||||
|
using Robust.Shared.Serialization;
|
||||||
|
|
||||||
|
namespace Content.Shared.Kitchen
|
||||||
|
{
|
||||||
|
public abstract class SharedReagentGrinderComponent : Component
|
||||||
|
{
|
||||||
|
public override string Name => "ReagentGrinder";
|
||||||
|
public override uint? NetID => ContentNetIDs.REAGENT_GRINDER;
|
||||||
|
|
||||||
|
[Serializable, NetSerializable]
|
||||||
|
public class ReagentGrinderGrindStartMessage : BoundUserInterfaceMessage
|
||||||
|
{
|
||||||
|
public ReagentGrinderGrindStartMessage()
|
||||||
|
{
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
[Serializable, NetSerializable]
|
||||||
|
public class ReagentGrinderJuiceStartMessage : BoundUserInterfaceMessage
|
||||||
|
{
|
||||||
|
public ReagentGrinderJuiceStartMessage()
|
||||||
|
{
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
[Serializable, NetSerializable]
|
||||||
|
public class ReagentGrinderEjectChamberAllMessage : BoundUserInterfaceMessage
|
||||||
|
{
|
||||||
|
public ReagentGrinderEjectChamberAllMessage()
|
||||||
|
{
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
[Serializable, NetSerializable]
|
||||||
|
public class ReagentGrinderEjectBeakerMessage : BoundUserInterfaceMessage
|
||||||
|
{
|
||||||
|
public ReagentGrinderEjectBeakerMessage()
|
||||||
|
{
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
[Serializable, NetSerializable]
|
||||||
|
public class ReagentGrinderEjectChamberContentMessage : BoundUserInterfaceMessage
|
||||||
|
{
|
||||||
|
public EntityUid EntityID;
|
||||||
|
public ReagentGrinderEjectChamberContentMessage(EntityUid entityID)
|
||||||
|
{
|
||||||
|
EntityID = entityID;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
[Serializable, NetSerializable]
|
||||||
|
public class ReagentGrinderVaporizeReagentIndexedMessage : BoundUserInterfaceMessage
|
||||||
|
{
|
||||||
|
public Solution.ReagentQuantity ReagentQuantity;
|
||||||
|
public ReagentGrinderVaporizeReagentIndexedMessage(Solution.ReagentQuantity reagentQuantity)
|
||||||
|
{
|
||||||
|
ReagentQuantity = reagentQuantity;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
[Serializable, NetSerializable]
|
||||||
|
public class ReagentGrinderWorkStartedMessage : BoundUserInterfaceMessage
|
||||||
|
{
|
||||||
|
public GrinderProgram GrinderProgram;
|
||||||
|
public ReagentGrinderWorkStartedMessage(GrinderProgram grinderProgram)
|
||||||
|
{
|
||||||
|
GrinderProgram = grinderProgram;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
[Serializable, NetSerializable]
|
||||||
|
public class ReagentGrinderWorkCompleteMessage : BoundUserInterfaceMessage
|
||||||
|
{
|
||||||
|
public ReagentGrinderWorkCompleteMessage()
|
||||||
|
{
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
[Serializable, NetSerializable]
|
||||||
|
public enum ReagentGrinderVisualState : byte
|
||||||
|
{
|
||||||
|
BeakerAttached
|
||||||
|
}
|
||||||
|
|
||||||
|
[NetSerializable, Serializable]
|
||||||
|
public enum ReagentGrinderUiKey : byte
|
||||||
|
{
|
||||||
|
Key
|
||||||
|
}
|
||||||
|
|
||||||
|
[Serializable, NetSerializable]
|
||||||
|
public enum GrinderProgram : byte
|
||||||
|
{
|
||||||
|
Grind,
|
||||||
|
Juice
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
[NetSerializable, Serializable]
|
||||||
|
public sealed class ReagentGrinderInterfaceState : BoundUserInterfaceState
|
||||||
|
{
|
||||||
|
public bool IsBusy;
|
||||||
|
public bool HasBeakerIn;
|
||||||
|
public bool Powered;
|
||||||
|
public bool CanJuice;
|
||||||
|
public bool CanGrind;
|
||||||
|
public EntityUid[] ChamberContents;
|
||||||
|
public Solution.ReagentQuantity[] ReagentQuantities;
|
||||||
|
public ReagentGrinderInterfaceState(bool isBusy, bool hasBeaker, bool powered, bool canJuice, bool canGrind, EntityUid[] chamberContents, Solution.ReagentQuantity[] heldBeakerContents)
|
||||||
|
{
|
||||||
|
IsBusy = isBusy;
|
||||||
|
HasBeakerIn = hasBeaker;
|
||||||
|
Powered = powered;
|
||||||
|
CanJuice = canJuice;
|
||||||
|
CanGrind = canGrind;
|
||||||
|
ChamberContents = chamberContents;
|
||||||
|
ReagentQuantities = heldBeakerContents;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
BIN
Resources/Audio/Machines/blender.ogg
Normal file
BIN
Resources/Audio/Machines/blender.ogg
Normal file
Binary file not shown.
BIN
Resources/Audio/Machines/juicer.ogg
Normal file
BIN
Resources/Audio/Machines/juicer.ogg
Normal file
Binary file not shown.
@@ -0,0 +1,35 @@
|
|||||||
|
- type: entity
|
||||||
|
id: KitchenReagentGrinder
|
||||||
|
name: reagent grinder
|
||||||
|
suffix: grinder/juicer
|
||||||
|
placement:
|
||||||
|
mode: SnapgridCenter
|
||||||
|
components:
|
||||||
|
- type: SnapGrid
|
||||||
|
offset: Center
|
||||||
|
- type: ReagentGrinder
|
||||||
|
- type: UserInterface
|
||||||
|
interfaces:
|
||||||
|
- key: enum.ReagentGrinderUiKey.Key
|
||||||
|
type: ReagentGrinderBoundUserInterface
|
||||||
|
- type: Appearance
|
||||||
|
visuals:
|
||||||
|
- type: ReagentGrinderVisualizer
|
||||||
|
- type: Clickable
|
||||||
|
- type: InteractionOutline
|
||||||
|
- type: PowerReceiver
|
||||||
|
- type: LoopingSound
|
||||||
|
- type: Physics
|
||||||
|
shapes:
|
||||||
|
- !type:PhysShapeAabb
|
||||||
|
bounds: "-0.35,-0.08,0.25,0.15"
|
||||||
|
layer:
|
||||||
|
- Opaque
|
||||||
|
- Impassable
|
||||||
|
- MobImpassable
|
||||||
|
- VaultImpassable
|
||||||
|
- type: Sprite
|
||||||
|
netsync: false
|
||||||
|
sprite: Constructible/Power/juicer.rsi
|
||||||
|
state: juicer0
|
||||||
|
drawdepth: Items
|
||||||
@@ -27,6 +27,7 @@
|
|||||||
Quantity: 5
|
Quantity: 5
|
||||||
- type: Produce
|
- type: Produce
|
||||||
seed: wheat
|
seed: wheat
|
||||||
|
- type: Grindable
|
||||||
|
|
||||||
- type: entity
|
- type: entity
|
||||||
name: sugarcane
|
name: sugarcane
|
||||||
@@ -46,6 +47,7 @@
|
|||||||
Quantity: 5
|
Quantity: 5
|
||||||
- type: Produce
|
- type: Produce
|
||||||
seed: sugarcane
|
seed: sugarcane
|
||||||
|
- type: Grindable
|
||||||
|
|
||||||
- type: entity
|
- type: entity
|
||||||
name: tower-cap log
|
name: tower-cap log
|
||||||
@@ -79,6 +81,12 @@
|
|||||||
sprite: Objects/Specific/Hydroponics/banana.rsi
|
sprite: Objects/Specific/Hydroponics/banana.rsi
|
||||||
- type: Produce
|
- type: Produce
|
||||||
seed: banana
|
seed: banana
|
||||||
|
- type: Grindable
|
||||||
|
- type: Juiceable
|
||||||
|
result:
|
||||||
|
reagents:
|
||||||
|
- ReagentId: chem.BananaJuice
|
||||||
|
Quantity: 10
|
||||||
|
|
||||||
- type: entity
|
- type: entity
|
||||||
name: carrot
|
name: carrot
|
||||||
@@ -96,6 +104,12 @@
|
|||||||
sprite: Objects/Specific/Hydroponics/carrot.rsi
|
sprite: Objects/Specific/Hydroponics/carrot.rsi
|
||||||
- type: Produce
|
- type: Produce
|
||||||
seed: carrots
|
seed: carrots
|
||||||
|
- type: Grindable
|
||||||
|
- type: Juiceable
|
||||||
|
result:
|
||||||
|
reagents:
|
||||||
|
- ReagentId: chem.CarrotJuice
|
||||||
|
Quantity: 10
|
||||||
|
|
||||||
- type: entity
|
- type: entity
|
||||||
name: lemon
|
name: lemon
|
||||||
@@ -113,6 +127,12 @@
|
|||||||
sprite: Objects/Specific/Hydroponics/lemon.rsi
|
sprite: Objects/Specific/Hydroponics/lemon.rsi
|
||||||
- type: Produce
|
- type: Produce
|
||||||
seed: lemon
|
seed: lemon
|
||||||
|
- type: Grindable
|
||||||
|
- type: Juiceable
|
||||||
|
result:
|
||||||
|
reagents:
|
||||||
|
- ReagentId: chem.LimeJuice
|
||||||
|
Quantity: 10
|
||||||
|
|
||||||
- type: entity
|
- type: entity
|
||||||
name: potato
|
name: potato
|
||||||
@@ -130,6 +150,12 @@
|
|||||||
sprite: Objects/Specific/Hydroponics/potato.rsi
|
sprite: Objects/Specific/Hydroponics/potato.rsi
|
||||||
- type: Produce
|
- type: Produce
|
||||||
seed: potato
|
seed: potato
|
||||||
|
- type: Grindable
|
||||||
|
- type: Juiceable
|
||||||
|
result:
|
||||||
|
reagents:
|
||||||
|
- ReagentId: chem.PotatoJuice
|
||||||
|
Quantity: 10
|
||||||
|
|
||||||
- type: entity
|
- type: entity
|
||||||
name: tomato
|
name: tomato
|
||||||
@@ -147,6 +173,12 @@
|
|||||||
sprite: Objects/Specific/Hydroponics/tomato.rsi
|
sprite: Objects/Specific/Hydroponics/tomato.rsi
|
||||||
- type: Produce
|
- type: Produce
|
||||||
seed: tomato
|
seed: tomato
|
||||||
|
- type: Grindable
|
||||||
|
- type: Juiceable
|
||||||
|
result:
|
||||||
|
reagents:
|
||||||
|
- ReagentId: chem.TomatoJuice
|
||||||
|
Quantity: 10
|
||||||
|
|
||||||
- type: entity
|
- type: entity
|
||||||
name: eggplant
|
name: eggplant
|
||||||
@@ -164,6 +196,7 @@
|
|||||||
sprite: Objects/Specific/Hydroponics/eggplant.rsi
|
sprite: Objects/Specific/Hydroponics/eggplant.rsi
|
||||||
- type: Produce
|
- type: Produce
|
||||||
seed: eggplant
|
seed: eggplant
|
||||||
|
- type: Grindable
|
||||||
|
|
||||||
- type: entity
|
- type: entity
|
||||||
name: apple
|
name: apple
|
||||||
@@ -181,6 +214,12 @@
|
|||||||
sprite: Objects/Specific/Hydroponics/apple.rsi
|
sprite: Objects/Specific/Hydroponics/apple.rsi
|
||||||
- type: Produce
|
- type: Produce
|
||||||
seed: apple
|
seed: apple
|
||||||
|
- type: Grindable
|
||||||
|
- type: Juiceable
|
||||||
|
result:
|
||||||
|
reagents:
|
||||||
|
- ReagentId: chem.AppleJuice
|
||||||
|
Quantity: 10
|
||||||
|
|
||||||
- type: entity
|
- type: entity
|
||||||
name: ear of corn
|
name: ear of corn
|
||||||
@@ -199,6 +238,7 @@
|
|||||||
sprite: Objects/Specific/Hydroponics/corn.rsi
|
sprite: Objects/Specific/Hydroponics/corn.rsi
|
||||||
- type: Produce
|
- type: Produce
|
||||||
seed: corn
|
seed: corn
|
||||||
|
- type: Grindable
|
||||||
|
|
||||||
- type: entity
|
- type: entity
|
||||||
name: chanterelle cluster
|
name: chanterelle cluster
|
||||||
@@ -216,3 +256,4 @@
|
|||||||
sprite: Objects/Specific/Hydroponics/chanterelle.rsi
|
sprite: Objects/Specific/Hydroponics/chanterelle.rsi
|
||||||
- type: Produce
|
- type: Produce
|
||||||
seed: chanterelle
|
seed: chanterelle
|
||||||
|
- type: Grindable
|
||||||
|
|||||||
@@ -165,11 +165,17 @@
|
|||||||
|
|
||||||
- type: entity
|
- type: entity
|
||||||
parent: DrinkGlassBase
|
parent: DrinkGlassBase
|
||||||
id: DrinkBerryjJice
|
id: DrinkBerryJuice
|
||||||
name: berry juice
|
name: berry juice
|
||||||
description: A delicious blend of several different kinds of berries.
|
description: A delicious blend of several different kinds of berries.
|
||||||
components:
|
components:
|
||||||
- type: Drink
|
- type: Drink
|
||||||
|
- type: SolutionContainer
|
||||||
|
maxVol: 20
|
||||||
|
contents:
|
||||||
|
reagents:
|
||||||
|
- ReagentId: chem.BerryJuice
|
||||||
|
Quantity: 20
|
||||||
- type: Sprite
|
- type: Sprite
|
||||||
sprite: Objects/Consumable/Drinks/berryjuice.rsi
|
sprite: Objects/Consumable/Drinks/berryjuice.rsi
|
||||||
|
|
||||||
@@ -252,6 +258,12 @@
|
|||||||
description: Has a uniquely sweet flavour of concentrated carrots.
|
description: Has a uniquely sweet flavour of concentrated carrots.
|
||||||
components:
|
components:
|
||||||
- type: Drink
|
- type: Drink
|
||||||
|
- type: SolutionContainer
|
||||||
|
maxVol: 20
|
||||||
|
contents:
|
||||||
|
reagents:
|
||||||
|
- ReagentId: chem.CarrotJuice
|
||||||
|
Quantity: 20
|
||||||
- type: Sprite
|
- type: Sprite
|
||||||
sprite: Objects/Consumable/Drinks/carrotjuice.rsi
|
sprite: Objects/Consumable/Drinks/carrotjuice.rsi
|
||||||
|
|
||||||
@@ -564,6 +576,12 @@
|
|||||||
description: The sweet-sour juice of limes.
|
description: The sweet-sour juice of limes.
|
||||||
components:
|
components:
|
||||||
- type: Drink
|
- type: Drink
|
||||||
|
- type: SolutionContainer
|
||||||
|
maxVol: 20
|
||||||
|
contents:
|
||||||
|
reagents:
|
||||||
|
- ReagentId: chem.LimeJuice
|
||||||
|
Quantity: 20
|
||||||
- type: Sprite
|
- type: Sprite
|
||||||
sprite: Objects/Consumable/Drinks/glass_green.rsi
|
sprite: Objects/Consumable/Drinks/glass_green.rsi
|
||||||
|
|
||||||
@@ -575,9 +593,31 @@
|
|||||||
description: Liquid extract of the orange tree fruit, produced by squeezing or reaming oranges.
|
description: Liquid extract of the orange tree fruit, produced by squeezing or reaming oranges.
|
||||||
components:
|
components:
|
||||||
- type: Drink
|
- type: Drink
|
||||||
|
- type: SolutionContainer
|
||||||
|
maxVol: 20
|
||||||
|
contents:
|
||||||
|
reagents:
|
||||||
|
- ReagentId: chem.OrangeJuice
|
||||||
|
Quantity: 20
|
||||||
- type: Sprite
|
- type: Sprite
|
||||||
sprite: Objects/Consumable/Drinks/glass_orange.rsi
|
sprite: Objects/Consumable/Drinks/glass_orange.rsi
|
||||||
|
|
||||||
|
- type: entity
|
||||||
|
parent: DrinkGlassBase
|
||||||
|
id: DrinkGlassYellow
|
||||||
|
name: lemon juice
|
||||||
|
description: Used to make lemonade, soft drinks, and cocktails.
|
||||||
|
components:
|
||||||
|
- type: Drink
|
||||||
|
- type: SolutionContainer
|
||||||
|
maxVol: 20
|
||||||
|
contents:
|
||||||
|
reagents:
|
||||||
|
- ReagentId: chem.LemonJuice
|
||||||
|
Quantity: 20
|
||||||
|
- type: Sprite
|
||||||
|
sprite: Objects/Consumable/Drinks/glass_yellow.rsi
|
||||||
|
|
||||||
|
|
||||||
- type: entity
|
- type: entity
|
||||||
parent: DrinkGlassBase
|
parent: DrinkGlassBase
|
||||||
@@ -586,6 +626,12 @@
|
|||||||
description: Juice made from tomatoes, usually used as a beverage, either plain or in cocktails
|
description: Juice made from tomatoes, usually used as a beverage, either plain or in cocktails
|
||||||
components:
|
components:
|
||||||
- type: Drink
|
- type: Drink
|
||||||
|
- type: SolutionContainer
|
||||||
|
maxVol: 20
|
||||||
|
contents:
|
||||||
|
reagents:
|
||||||
|
- ReagentId: chem.TomatoJuice
|
||||||
|
Quantity: 20
|
||||||
- type: Sprite
|
- type: Sprite
|
||||||
sprite: Objects/Consumable/Drinks/glass_red.rsi
|
sprite: Objects/Consumable/Drinks/glass_red.rsi
|
||||||
|
|
||||||
@@ -605,18 +651,6 @@
|
|||||||
- type: Sprite
|
- type: Sprite
|
||||||
sprite: Objects/Consumable/Drinks/glass_white.rsi
|
sprite: Objects/Consumable/Drinks/glass_white.rsi
|
||||||
|
|
||||||
|
|
||||||
- type: entity
|
|
||||||
parent: DrinkGlassBase
|
|
||||||
id: DrinkGlassYellow
|
|
||||||
name: lemon juice
|
|
||||||
description: ''
|
|
||||||
components:
|
|
||||||
- type: Drink
|
|
||||||
- type: Sprite
|
|
||||||
sprite: Objects/Consumable/Drinks/glass_yellow.rsi
|
|
||||||
|
|
||||||
|
|
||||||
- type: entity
|
- type: entity
|
||||||
parent: DrinkGlassBase
|
parent: DrinkGlassBase
|
||||||
id: DrinkGoldschlagerGlass
|
id: DrinkGoldschlagerGlass
|
||||||
@@ -635,6 +669,12 @@
|
|||||||
description: The juice is often sold in stores or fermented and made into wine, brandy, or vinegar.
|
description: The juice is often sold in stores or fermented and made into wine, brandy, or vinegar.
|
||||||
components:
|
components:
|
||||||
- type: Drink
|
- type: Drink
|
||||||
|
- type: SolutionContainer
|
||||||
|
maxVol: 20
|
||||||
|
contents:
|
||||||
|
reagents:
|
||||||
|
- ReagentId: chem.GrapeJuice
|
||||||
|
Quantity: 20
|
||||||
- type: Sprite
|
- type: Sprite
|
||||||
sprite: Objects/Consumable/Drinks/grapejuice.rsi
|
sprite: Objects/Consumable/Drinks/grapejuice.rsi
|
||||||
|
|
||||||
@@ -903,6 +943,12 @@
|
|||||||
description: Used to make lemonade, soft drinks, and cocktails.
|
description: Used to make lemonade, soft drinks, and cocktails.
|
||||||
components:
|
components:
|
||||||
- type: Drink
|
- type: Drink
|
||||||
|
- type: SolutionContainer
|
||||||
|
maxVol: 20
|
||||||
|
contents:
|
||||||
|
reagents:
|
||||||
|
- ReagentId: chem.LemonJuice
|
||||||
|
Quantity: 20
|
||||||
- type: Sprite
|
- type: Sprite
|
||||||
sprite: Objects/Consumable/Drinks/lemonjuice.rsi
|
sprite: Objects/Consumable/Drinks/lemonjuice.rsi
|
||||||
|
|
||||||
@@ -914,6 +960,14 @@
|
|||||||
description: A tangy substance made of lime and lemon.
|
description: A tangy substance made of lime and lemon.
|
||||||
components:
|
components:
|
||||||
- type: Drink
|
- type: Drink
|
||||||
|
- type: SolutionContainer
|
||||||
|
maxVol: 20
|
||||||
|
contents:
|
||||||
|
reagents:
|
||||||
|
- ReagentId: chem.LemonJuice
|
||||||
|
Quantity: 10
|
||||||
|
- ReagentId: chem.LimeJuice
|
||||||
|
Quantity: 10
|
||||||
- type: Sprite
|
- type: Sprite
|
||||||
sprite: Objects/Consumable/Drinks/lemonlime.rsi
|
sprite: Objects/Consumable/Drinks/lemonlime.rsi
|
||||||
|
|
||||||
@@ -925,6 +979,12 @@
|
|||||||
description: The sweet-sour juice of limes.
|
description: The sweet-sour juice of limes.
|
||||||
components:
|
components:
|
||||||
- type: Drink
|
- type: Drink
|
||||||
|
- type: SolutionContainer
|
||||||
|
maxVol: 20
|
||||||
|
contents:
|
||||||
|
reagents:
|
||||||
|
- ReagentId: chem.LimeJuice
|
||||||
|
Quantity: 20
|
||||||
- type: Sprite
|
- type: Sprite
|
||||||
sprite: Objects/Consumable/Drinks/limejuice.rsi
|
sprite: Objects/Consumable/Drinks/limejuice.rsi
|
||||||
|
|
||||||
@@ -1100,6 +1160,12 @@
|
|||||||
description: Liquid extract of the orange tree fruit, produced by squeezing or reaming oranges.
|
description: Liquid extract of the orange tree fruit, produced by squeezing or reaming oranges.
|
||||||
components:
|
components:
|
||||||
- type: Drink
|
- type: Drink
|
||||||
|
- type: SolutionContainer
|
||||||
|
maxVol: 20
|
||||||
|
contents:
|
||||||
|
reagents:
|
||||||
|
- ReagentId: chem.OrangeJuice
|
||||||
|
Quantity: 20
|
||||||
- type: Sprite
|
- type: Sprite
|
||||||
sprite: Objects/Consumable/Drinks/orangejuice.rsi
|
sprite: Objects/Consumable/Drinks/orangejuice.rsi
|
||||||
|
|
||||||
@@ -1122,6 +1188,12 @@
|
|||||||
description: A tasty juice blended from various kinds of very deadly and toxic berries.
|
description: A tasty juice blended from various kinds of very deadly and toxic berries.
|
||||||
components:
|
components:
|
||||||
- type: Drink
|
- type: Drink
|
||||||
|
- type: SolutionContainer
|
||||||
|
maxVol: 20
|
||||||
|
contents:
|
||||||
|
reagents:
|
||||||
|
- ReagentId: chem.PoisonBerryJuice
|
||||||
|
Quantity: 20
|
||||||
- type: Sprite
|
- type: Sprite
|
||||||
sprite: Objects/Consumable/Drinks/poisonberryjuice.rsi
|
sprite: Objects/Consumable/Drinks/poisonberryjuice.rsi
|
||||||
|
|
||||||
@@ -1521,9 +1593,15 @@
|
|||||||
parent: DrinkGlassBase
|
parent: DrinkGlassBase
|
||||||
id: DrinkTomatoJuice
|
id: DrinkTomatoJuice
|
||||||
name: tomato juice
|
name: tomato juice
|
||||||
description: Juice made from tomatoes, usually used as a beverage, either plain or in cocktails
|
description: Juice made from tomatoes, usually used as a beverage, either plain or in cocktails.
|
||||||
components:
|
components:
|
||||||
- type: Drink
|
- type: Drink
|
||||||
|
- type: SolutionContainer
|
||||||
|
maxVol: 20
|
||||||
|
contents:
|
||||||
|
reagents:
|
||||||
|
- ReagentId: chem.TomatoJuice
|
||||||
|
Quantity: 20
|
||||||
- type: Sprite
|
- type: Sprite
|
||||||
sprite: Objects/Consumable/Drinks/tomatojuice.rsi
|
sprite: Objects/Consumable/Drinks/tomatojuice.rsi
|
||||||
|
|
||||||
@@ -1612,6 +1690,12 @@
|
|||||||
description: Delicious juice made from watermelon.
|
description: Delicious juice made from watermelon.
|
||||||
components:
|
components:
|
||||||
- type: Drink
|
- type: Drink
|
||||||
|
- type: SolutionContainer
|
||||||
|
maxVol: 20
|
||||||
|
contents:
|
||||||
|
reagents:
|
||||||
|
- ReagentId: chem.WatermelonJuice
|
||||||
|
Quantity: 20
|
||||||
- type: Sprite
|
- type: Sprite
|
||||||
sprite: Objects/Consumable/Drinks/watermelon.rsi
|
sprite: Objects/Consumable/Drinks/watermelon.rsi
|
||||||
|
|
||||||
|
|||||||
File diff suppressed because it is too large
Load Diff
@@ -182,7 +182,7 @@
|
|||||||
- type: reagent
|
- type: reagent
|
||||||
id: chem.Tea
|
id: chem.Tea
|
||||||
name: tea
|
name: tea
|
||||||
desc: A made by boiling leaves of the tea tree, Camellia sinensis.
|
desc: A drink made by boiling leaves of the tea tree, Camellia sinensis.
|
||||||
physicalDesc: aromatic
|
physicalDesc: aromatic
|
||||||
color: "#8a5a3a"
|
color: "#8a5a3a"
|
||||||
metabolism:
|
metabolism:
|
||||||
@@ -253,3 +253,152 @@
|
|||||||
metabolism:
|
metabolism:
|
||||||
- !type:DefaultDrink
|
- !type:DefaultDrink
|
||||||
rate: 1
|
rate: 1
|
||||||
|
|
||||||
|
|
||||||
|
#Juices
|
||||||
|
- type: reagent
|
||||||
|
id: chem.AppleJuice
|
||||||
|
name: apple juice
|
||||||
|
desc: It's a little piece of Eden.
|
||||||
|
physicalDesc: crisp
|
||||||
|
color: "#FDAD01"
|
||||||
|
metabolism:
|
||||||
|
- !type:DefaultDrink
|
||||||
|
rate: 1
|
||||||
|
|
||||||
|
- type: reagent
|
||||||
|
id: chem.BerryJuice
|
||||||
|
name: berry juice
|
||||||
|
desc: A delicious blend of several different kinds of berries.
|
||||||
|
physicalDesc: sweet
|
||||||
|
color: "#660099"
|
||||||
|
metabolism:
|
||||||
|
- !type:DefaultDrink
|
||||||
|
rate: 1
|
||||||
|
|
||||||
|
- type: reagent
|
||||||
|
id: chem.BananaJuice
|
||||||
|
name: banana juice
|
||||||
|
desc: The raw essence of a banana. HONK.
|
||||||
|
physicalDesc: crisp
|
||||||
|
color: "#FFE777"
|
||||||
|
metabolism:
|
||||||
|
- !type:DefaultDrink
|
||||||
|
rate: 1
|
||||||
|
|
||||||
|
#TODO: port on_mob_life: restore eyesight
|
||||||
|
#if(..())
|
||||||
|
#return 1
|
||||||
|
# M.eye_blurry = max(M.eye_blurry - 1 , 0)
|
||||||
|
# M.eye_blind = max(M.eye_blind - 1 , 0)
|
||||||
|
# switch(data)
|
||||||
|
# if(21 to INFINITY)
|
||||||
|
# if(prob(data - 10))
|
||||||
|
# M.disabilities &= ~NEARSIGHTED
|
||||||
|
# data++
|
||||||
|
|
||||||
|
- type: reagent
|
||||||
|
id: chem.CarrotJuice
|
||||||
|
name: carrot juice
|
||||||
|
desc: It's like a carrot, but less crunchy.
|
||||||
|
physicalDesc: crisp
|
||||||
|
color: "#FF8820"
|
||||||
|
metabolism:
|
||||||
|
- !type:DefaultDrink
|
||||||
|
rate: 1
|
||||||
|
|
||||||
|
- type: reagent
|
||||||
|
id: chem.LimeJuice
|
||||||
|
name: lime juice
|
||||||
|
desc: The sweet-sour juice of limes.
|
||||||
|
physicalDesc: citric
|
||||||
|
color: "#99bb43"
|
||||||
|
metabolism:
|
||||||
|
- !type:DefaultDrink
|
||||||
|
rate: 1
|
||||||
|
|
||||||
|
- type: reagent
|
||||||
|
id: chem.LemonJuice
|
||||||
|
name: lemon juice
|
||||||
|
desc: This juice is VERY sour.
|
||||||
|
physicalDesc: citric
|
||||||
|
color: "#fff690"
|
||||||
|
metabolism:
|
||||||
|
- !type:DefaultDrink
|
||||||
|
rate: 1
|
||||||
|
|
||||||
|
- type: reagent
|
||||||
|
id: chem.GrapeJuice
|
||||||
|
name: grape juice
|
||||||
|
desc: Freshly squeezed juice from red grapes. Quite sweet.
|
||||||
|
physicalDesc: crisp
|
||||||
|
color: "#512284"
|
||||||
|
metabolism:
|
||||||
|
- !type:DefaultDrink
|
||||||
|
rate: 1
|
||||||
|
|
||||||
|
|
||||||
|
# /datum/reagent/drink/orangejuice/on_mob_life(var/mob/living/M)
|
||||||
|
|
||||||
|
# if(..())
|
||||||
|
# return 1
|
||||||
|
|
||||||
|
# if(M.getToxLoss() && prob(20))
|
||||||
|
# M.adjustToxLoss(-REM)
|
||||||
|
|
||||||
|
- type: reagent
|
||||||
|
id: chem.OrangeJuice
|
||||||
|
name: orange juice
|
||||||
|
desc: Both delicious AND rich in Vitamin C. What more do you need?
|
||||||
|
physicalDesc: citric
|
||||||
|
color: "#E78108"
|
||||||
|
metabolism:
|
||||||
|
- !type:DefaultDrink
|
||||||
|
rate: 1
|
||||||
|
|
||||||
|
- type: reagent
|
||||||
|
id: chem.TomatoJuice
|
||||||
|
name: tomato juice
|
||||||
|
desc: Tomatoes made into juice. What a waste of good tomatoes, huh?
|
||||||
|
physicalDesc: saucey
|
||||||
|
color: "#731008"
|
||||||
|
metabolism:
|
||||||
|
- !type:DefaultDrink
|
||||||
|
rate: 1
|
||||||
|
|
||||||
|
# /datum/reagent/drink/poisonberryjuice/on_mob_life(var/mob/living/M)
|
||||||
|
|
||||||
|
# if(..())
|
||||||
|
# return 1
|
||||||
|
|
||||||
|
# M.adjustToxLoss(1)
|
||||||
|
|
||||||
|
- type: reagent
|
||||||
|
id: chem.PoisonBerryJuice
|
||||||
|
name: poison berry juice
|
||||||
|
desc: A surprisingly tasty juice blended from various kinds of very deadly and toxic berries.
|
||||||
|
physicalDesc: aromatic #maybe should be 'sickly'?
|
||||||
|
color: "#6600CC"
|
||||||
|
metabolism:
|
||||||
|
- !type:DefaultDrink
|
||||||
|
rate: 1
|
||||||
|
|
||||||
|
- type: reagent
|
||||||
|
id: chem.WatermelonJuice
|
||||||
|
name: water melon juice
|
||||||
|
desc: The delicious juice of a watermelon.
|
||||||
|
physicalDesc: sweet
|
||||||
|
color: "#EF3520"
|
||||||
|
metabolism:
|
||||||
|
- !type:DefaultDrink
|
||||||
|
rate: 1
|
||||||
|
|
||||||
|
- type: reagent
|
||||||
|
id: chem.PotatoJuice
|
||||||
|
name: potato juice
|
||||||
|
desc: Juice of the potato. Bleh.
|
||||||
|
physicalDesc: starchy
|
||||||
|
color: "#302000"
|
||||||
|
metabolism:
|
||||||
|
- !type:DefaultDrink
|
||||||
|
rate: 1
|
||||||
|
|||||||
BIN
Resources/Textures/Constructible/Power/juicer.rsi/juicer0.png
Normal file
BIN
Resources/Textures/Constructible/Power/juicer.rsi/juicer0.png
Normal file
Binary file not shown.
|
After Width: | Height: | Size: 579 B |
BIN
Resources/Textures/Constructible/Power/juicer.rsi/juicer1.png
Normal file
BIN
Resources/Textures/Constructible/Power/juicer.rsi/juicer1.png
Normal file
Binary file not shown.
|
After Width: | Height: | Size: 598 B |
@@ -0,0 +1 @@
|
|||||||
|
{"license": "CC-BY-SA 3.0", "copyright": "https://github.com/tgstation/tgstation/commit/59f2a4e10e5ba36033c9734ddebfbbdc6157472d","version": 1, "size": {"x": 32, "y": 32}, "states": [{"name": "juicer0", "directions": 1, "delays": [[1.0]]}, {"name": "juicer1", "directions": 1, "delays": [[1.0]]}]}
|
||||||
@@ -104,9 +104,11 @@
|
|||||||
<s:Boolean x:Key="/Default/UserDictionary/Words/=freepats/@EntryIndexedValue">True</s:Boolean>
|
<s:Boolean x:Key="/Default/UserDictionary/Words/=freepats/@EntryIndexedValue">True</s:Boolean>
|
||||||
<s:Boolean x:Key="/Default/UserDictionary/Words/=gamemode/@EntryIndexedValue">True</s:Boolean>
|
<s:Boolean x:Key="/Default/UserDictionary/Words/=gamemode/@EntryIndexedValue">True</s:Boolean>
|
||||||
<s:Boolean x:Key="/Default/UserDictionary/Words/=godmode/@EntryIndexedValue">True</s:Boolean>
|
<s:Boolean x:Key="/Default/UserDictionary/Words/=godmode/@EntryIndexedValue">True</s:Boolean>
|
||||||
|
<s:Boolean x:Key="/Default/UserDictionary/Words/=Grindable/@EntryIndexedValue">True</s:Boolean>
|
||||||
<s:Boolean x:Key="/Default/UserDictionary/Words/=hardcode/@EntryIndexedValue">True</s:Boolean>
|
<s:Boolean x:Key="/Default/UserDictionary/Words/=hardcode/@EntryIndexedValue">True</s:Boolean>
|
||||||
<s:Boolean x:Key="/Default/UserDictionary/Words/=hbox/@EntryIndexedValue">True</s:Boolean>
|
<s:Boolean x:Key="/Default/UserDictionary/Words/=hbox/@EntryIndexedValue">True</s:Boolean>
|
||||||
<s:Boolean x:Key="/Default/UserDictionary/Words/=inhand/@EntryIndexedValue">True</s:Boolean>
|
<s:Boolean x:Key="/Default/UserDictionary/Words/=inhand/@EntryIndexedValue">True</s:Boolean>
|
||||||
|
<s:Boolean x:Key="/Default/UserDictionary/Words/=Juiceable/@EntryIndexedValue">True</s:Boolean>
|
||||||
<s:Boolean x:Key="/Default/UserDictionary/Words/=keybind/@EntryIndexedValue">True</s:Boolean>
|
<s:Boolean x:Key="/Default/UserDictionary/Words/=keybind/@EntryIndexedValue">True</s:Boolean>
|
||||||
<s:Boolean x:Key="/Default/UserDictionary/Words/=keybinds/@EntryIndexedValue">True</s:Boolean>
|
<s:Boolean x:Key="/Default/UserDictionary/Words/=keybinds/@EntryIndexedValue">True</s:Boolean>
|
||||||
<s:Boolean x:Key="/Default/UserDictionary/Words/=Kibibyte/@EntryIndexedValue">True</s:Boolean>
|
<s:Boolean x:Key="/Default/UserDictionary/Words/=Kibibyte/@EntryIndexedValue">True</s:Boolean>
|
||||||
|
|||||||
Reference in New Issue
Block a user