--- /dev/null
+using Content.Client.Chemistry.EntitySystems;
+using Content.Client.Chemistry.UI;
+
+namespace Content.Client.Chemistry.Components;
+
+/// <summary>
+/// Exposes a solution container's contents via a basic item status control.
+/// </summary>
+/// <remarks>
+/// Shows the solution volume, max volume, and transfer amount.
+/// </remarks>
+/// <seealso cref="SolutionItemStatusSystem"/>
+/// <seealso cref="SolutionStatusControl"/>
+[RegisterComponent]
+public sealed partial class SolutionItemStatusComponent : Component
+{
+ /// <summary>
+ /// The ID of the solution that will be shown on the item status control.
+ /// </summary>
+ [DataField, ViewVariables(VVAccess.ReadWrite)]
+ public string Solution = "default";
+}
--- /dev/null
+using Content.Client.Chemistry.Components;
+using Content.Client.Chemistry.UI;
+using Content.Client.Items;
+using Content.Shared.Chemistry.EntitySystems;
+
+namespace Content.Client.Chemistry.EntitySystems;
+
+/// <summary>
+/// Wires up item status logic for <see cref="SolutionItemStatusComponent"/>.
+/// </summary>
+/// <seealso cref="SolutionStatusControl"/>
+public sealed class SolutionItemStatusSystem : EntitySystem
+{
+ [Dependency] private readonly SharedSolutionContainerSystem _solutionContainerSystem = default!;
+
+ public override void Initialize()
+ {
+ base.Initialize();
+ Subs.ItemStatus<SolutionItemStatusComponent>(
+ entity => new SolutionStatusControl(entity, EntityManager, _solutionContainerSystem));
+ }
+}
--- /dev/null
+using Content.Client.Chemistry.Components;
+using Content.Client.Chemistry.EntitySystems;
+using Content.Client.Items.UI;
+using Content.Client.Message;
+using Content.Client.Stylesheets;
+using Content.Shared.Chemistry.Components;
+using Content.Shared.Chemistry.EntitySystems;
+using Content.Shared.FixedPoint;
+using Robust.Client.UserInterface.Controls;
+
+namespace Content.Client.Chemistry.UI;
+
+/// <summary>
+/// Displays basic solution information for <see cref="SolutionItemStatusComponent"/>.
+/// </summary>
+/// <seealso cref="SolutionItemStatusSystem"/>
+public sealed class SolutionStatusControl : PollingItemStatusControl<SolutionStatusControl.Data>
+{
+ private readonly Entity<SolutionItemStatusComponent> _parent;
+ private readonly IEntityManager _entityManager;
+ private readonly SharedSolutionContainerSystem _solutionContainers;
+ private readonly RichTextLabel _label;
+
+ public SolutionStatusControl(
+ Entity<SolutionItemStatusComponent> parent,
+ IEntityManager entityManager,
+ SharedSolutionContainerSystem solutionContainers)
+ {
+ _parent = parent;
+ _entityManager = entityManager;
+ _solutionContainers = solutionContainers;
+ _label = new RichTextLabel { StyleClasses = { StyleNano.StyleClassItemStatus } };
+ AddChild(_label);
+ }
+
+ protected override Data PollData()
+ {
+ if (!_solutionContainers.TryGetSolution(_parent.Owner, _parent.Comp.Solution, out _, out var solution))
+ return default;
+
+ FixedPoint2? transferAmount = null;
+ if (_entityManager.TryGetComponent(_parent.Owner, out SolutionTransferComponent? transfer))
+ transferAmount = transfer.TransferAmount;
+
+ return new Data(solution.Volume, solution.MaxVolume, transferAmount);
+ }
+
+ protected override void Update(in Data data)
+ {
+ var markup = Loc.GetString("solution-status-volume",
+ ("currentVolume", data.Volume),
+ ("maxVolume", data.MaxVolume));
+ if (data.TransferVolume is { } transferVolume)
+ markup += "\n" + Loc.GetString("solution-status-transfer", ("volume", transferVolume));
+ _label.SetMarkup(markup);
+ }
+
+ public readonly record struct Data(FixedPoint2 Volume, FixedPoint2 MaxVolume, FixedPoint2? TransferVolume);
+}
--- /dev/null
+using Robust.Client.UserInterface;
+using Robust.Shared.Timing;
+
+namespace Content.Client.Items.UI;
+
+/// <summary>
+/// A base for item status controls that poll data every frame. Avoids UI updates if data didn't change.
+/// </summary>
+/// <typeparam name="TData">The full status control data that is polled every frame.</typeparam>
+public abstract class PollingItemStatusControl<TData> : Control where TData : struct, IEquatable<TData>
+{
+ private TData _lastData;
+
+ protected override void FrameUpdate(FrameEventArgs args)
+ {
+ base.FrameUpdate(args);
+
+ var newData = PollData();
+ if (newData.Equals(_lastData))
+ return;
+
+ _lastData = newData;
+ Update(newData);
+ }
+
+ protected abstract TData PollData();
+ protected abstract void Update(in TData data);
+}
new StyleProperty("font", notoSans10),
}),
+ Element<RichTextLabel>()
+ .Class(StyleClassItemStatus)
+ .Prop(nameof(RichTextLabel.LineHeightScale), 0.7f)
+ .Prop(nameof(Control.Margin), new Thickness(0, 0, 0, -6)),
+
// Slider
new StyleRule(SelectorElement.Type(typeof(Slider)), new []
{
{
base.Initialize();
- Subs.ItemStatus<WelderComponent>(ent => new WelderStatusControl(ent));
+ Subs.ItemStatus<WelderComponent>(ent => new WelderStatusControl(ent, EntityManager, this));
Subs.ItemStatus<MultipleToolComponent>(ent => new MultipleToolStatusControl(ent));
}
+using Content.Client.Items.UI;
using Content.Client.Message;
using Content.Client.Stylesheets;
+using Content.Shared.FixedPoint;
using Content.Shared.Tools.Components;
-using Robust.Client.UserInterface;
+using Content.Shared.Tools.Systems;
using Robust.Client.UserInterface.Controls;
-using Robust.Shared.Timing;
namespace Content.Client.Tools.UI;
-public sealed class WelderStatusControl : Control
+public sealed class WelderStatusControl : PollingItemStatusControl<WelderStatusControl.Data>
{
- [Dependency] private readonly IGameTiming _gameTiming = default!;
-
- private readonly ToolSystem _tool;
-
private readonly Entity<WelderComponent> _parent;
+ private readonly IEntityManager _entityManager;
+ private readonly SharedToolSystem _toolSystem;
private readonly RichTextLabel _label;
- public WelderStatusControl(Entity<WelderComponent> parent)
+ public WelderStatusControl(Entity<WelderComponent> parent, IEntityManager entityManager, SharedToolSystem toolSystem)
{
- IoCManager.InjectDependencies(this);
-
_parent = parent;
- var entMan = IoCManager.Resolve<IEntityManager>();
- _tool = entMan.System<ToolSystem>();
-
+ _entityManager = entityManager;
+ _toolSystem = toolSystem;
_label = new RichTextLabel { StyleClasses = { StyleNano.StyleClassItemStatus } };
AddChild(_label);
UpdateDraw();
}
- /// <inheritdoc />
- protected override void FrameUpdate(FrameEventArgs args)
+ protected override Data PollData()
{
- base.FrameUpdate(args);
-
- Update();
+ var (fuel, capacity) = _toolSystem.GetWelderFuelAndCapacity(_parent, _parent.Comp);
+ return new Data(fuel, capacity, _parent.Comp.Enabled);
}
- public void Update()
+ protected override void Update(in Data data)
{
- if (!_gameTiming.IsFirstTimePredicted)
- return;
-
- var (fuel, fuelCap) = _tool.GetWelderFuelAndCapacity(_parent, _parent);
- var lit = _parent.Comp.Enabled;
-
_label.SetMarkup(Loc.GetString("welder-component-on-examine-detailed-message",
- ("colorName", fuel < fuelCap / 4f ? "darkorange" : "orange"),
- ("fuelLeft", Math.Round(fuel.Float(), 1)),
- ("fuelCapacity", fuelCap),
- ("status", Loc.GetString(lit ? "welder-component-on-examine-welder-lit-message" : "welder-component-on-examine-welder-not-lit-message"))));
+ ("colorName", data.Fuel < data.FuelCapacity / 4f ? "darkorange" : "orange"),
+ ("fuelLeft", data.Fuel),
+ ("fuelCapacity", data.FuelCapacity),
+ ("status", Loc.GetString(data.Lit ? "welder-component-on-examine-welder-lit-message" : "welder-component-on-examine-welder-not-lit-message"))));
}
+
+ public record struct Data(FixedPoint2 Fuel, FixedPoint2 FuelCapacity, bool Lit);
}
private readonly Dictionary<string, HandButton> _handLookup = new();
private HandsComponent? _playerHandsComponent;
private HandButton? _activeHand = null;
+
+ // We only have two item status controls (left and right hand),
+ // but we may have more than two hands.
+ // We handle this by having the item status be the *last active* hand of that side.
+ // These variables store which that is.
+ // ("middle" hands are hardcoded as right, whatever)
+ private HandButton? _statusHandLeft;
+ private HandButton? _statusHandRight;
+
private int _backupSuffix = 0; //this is used when autogenerating container names if they don't have names
private HotbarGui? HandsGui => UIManager.GetActiveUIWidgetOrNull<HotbarGui>();
hand.Blocked = false;
}
- if (_playerHandsComponent?.ActiveHand?.Name == name)
- HandsGui?.UpdatePanelEntity(entity);
+ UpdateHandStatus(hand, entity);
}
private void OnItemRemoved(string name, EntityUid entity)
return;
hand.SetEntity(null);
- if (_playerHandsComponent?.ActiveHand?.Name == name)
- HandsGui?.UpdatePanelEntity(null);
+ UpdateHandStatus(hand, null);
}
private HandsContainer GetFirstAvailableContainer()
if (_activeHand != null)
_activeHand.Highlight = false;
- HandsGui?.UpdatePanelEntity(null);
return;
}
_player.LocalSession?.AttachedEntity is { } playerEntity &&
_handsSystem.TryGetHand(playerEntity, handName, out var hand, _playerHandsComponent))
{
- HandsGui.UpdatePanelEntity(hand.HeldEntity);
+ if (hand.Location == HandLocation.Left)
+ {
+ _statusHandLeft = handControl;
+ HandsGui.UpdatePanelEntityLeft(hand.HeldEntity);
+ }
+ else
+ {
+ // Middle or right
+ _statusHandRight = handControl;
+ HandsGui.UpdatePanelEntityRight(hand.HeldEntity);
+ }
+
+ HandsGui.SetHighlightHand(hand.Location);
}
}
GetFirstAvailableContainer().AddButton(button);
}
+ // If we don't have a status for this hand type yet, set it.
+ // This means we have status filled by default in most scenarios,
+ // otherwise the user'd need to switch hands to "activate" the hands the first time.
+ if (location == HandLocation.Left)
+ _statusHandLeft ??= button;
+ else
+ _statusHandRight ??= button;
+
return button;
}
handContainer.RemoveButton(handButton);
}
+ if (_statusHandLeft == handButton)
+ _statusHandLeft = null;
+ if (_statusHandRight == handButton)
+ _statusHandRight = null;
+
_handLookup.Remove(handName);
handButton.Dispose();
return true;
}
}
}
+
+ private void UpdateHandStatus(HandButton hand, EntityUid? entity)
+ {
+ if (hand == _statusHandLeft)
+ HandsGui?.UpdatePanelEntityLeft(entity);
+
+ if (hand == _statusHandRight)
+ HandsGui?.UpdatePanelEntityRight(entity);
+ }
}
ReloadHotbar();
}
- public void Setup(HandsContainer handsContainer, ItemStatusPanel handStatus, StorageContainer storageContainer)
+ public void Setup(HandsContainer handsContainer, StorageContainer storageContainer)
{
_inventory = UIManager.GetUIController<InventoryUIController>();
_hands = UIManager.GetUIController<HandsUIController>();
Orientation="Vertical"
HorizontalAlignment="Center">
<BoxContainer Orientation="Vertical">
- <Control HorizontalAlignment="Center">
- <inventory:ItemStatusPanel
- Name="StatusPanel"
- Visible="False"
- HorizontalAlignment="Center"
- />
- <BoxContainer Name="StorageContainer"
- Access="Public"
- HorizontalAlignment="Center"
- Margin="10">
- <storage:StorageContainer
- Name="StoragePanel"
- Visible="False"/>
- </BoxContainer>
- </Control>
+ <BoxContainer Name="StorageContainer"
+ Access="Public"
+ HorizontalAlignment="Center"
+ Margin="10">
+ <storage:StorageContainer
+ Name="StoragePanel"
+ Visible="False"/>
+ </BoxContainer>
<BoxContainer Orientation="Horizontal" Name="Hotbar" HorizontalAlignment="Center">
<inventory:ItemSlotButtonContainer
Name="SecondHotbar"
ExpandBackwards="True"
Columns="6"
HorizontalExpand="False"/>
+ <inventory:ItemStatusPanel
+ Name="StatusPanelRight"
+ HorizontalAlignment="Center" Margin="0 0 -2 2"
+ SetWidth="125"
+ MaxHeight="60"/>
<hands:HandsContainer
Name="HandContainer"
Access="Public"
HorizontalAlignment="Center"
HorizontalExpand="False"
- ColumnLimit="6"
- Margin="4 0 4 0"/>
+ ColumnLimit="6"/>
+ <inventory:ItemStatusPanel
+ Name="StatusPanelLeft"
+ HorizontalAlignment="Center" Margin="-2 0 0 2"
+ SetWidth="125"
+ MaxHeight="60"/>
<inventory:ItemSlotButtonContainer
Name="MainHotbar"
SlotGroup="MainHotbar"
-using Robust.Client.AutoGenerated;
+using Content.Shared.Hands.Components;
+using Robust.Client.AutoGenerated;
using Robust.Client.UserInterface.Controls;
using Robust.Client.UserInterface.XAML;
public HotbarGui()
{
RobustXamlLoader.Load(this);
- StatusPanel.Update(null);
+ StatusPanelRight.SetSide(HandLocation.Right);
+ StatusPanelLeft.SetSide(HandLocation.Left);
var hotbarController = UserInterfaceManager.GetUIController<HotbarUIController>();
- hotbarController.Setup(HandContainer, StatusPanel, StoragePanel);
+ hotbarController.Setup(HandContainer, StoragePanel);
LayoutContainer.SetGrowVertical(this, LayoutContainer.GrowDirection.Begin);
}
- public void UpdatePanelEntity(EntityUid? entity)
+ public void UpdatePanelEntityLeft(EntityUid? entity)
{
- StatusPanel.Update(entity);
- if (entity == null)
- {
- StatusPanel.Visible = false;
- return;
- }
+ StatusPanelLeft.Update(entity);
+ }
- StatusPanel.Visible = true;
+ public void UpdatePanelEntityRight(EntityUid? entity)
+ {
+ StatusPanelRight.Update(entity);
+ }
+
+ public void SetHighlightHand(HandLocation? hand)
+ {
+ StatusPanelLeft.UpdateHighlight(hand is HandLocation.Left);
+ StatusPanelRight.UpdateHighlight(hand is HandLocation.Middle or HandLocation.Right);
}
}
xmlns:controls="clr-namespace:Content.Client.UserInterface.Systems.Inventory.Controls"
xmlns:graphics="clr-namespace:Robust.Client.Graphics;assembly=Robust.Client"
VerticalAlignment="Bottom"
- HorizontalAlignment="Center"
- MinSize="150 0">
- <PanelContainer
- Name="Panel"
- ModulateSelfOverride="#FFFFFFE6"
- HorizontalExpand="True">
- <PanelContainer.PanelOverride>
- <graphics:StyleBoxTexture
- ContentMarginLeftOverride="6"
- ContentMarginRightOverride="6"
- ContentMarginTopOverride="4"
- ContentMarginBottomOverride="4" />
- </PanelContainer.PanelOverride>
- <BoxContainer Orientation="Vertical" SeparationOverride="0">
- <BoxContainer Name="StatusContents" Orientation="Vertical"/>
- <Label Name="ItemNameLabel" StyleClasses="ItemStatus"/>
+ HorizontalAlignment="Center">
+ <Control Name="VisWrapper" Visible="False">
+ <PanelContainer Name="Panel">
+ <PanelContainer.PanelOverride>
+ <graphics:StyleBoxTexture
+ PatchMarginBottom="4"
+ PatchMarginTop="6"
+ TextureScale="2 2"
+ Mode="Tile"/>
+ </PanelContainer.PanelOverride>
+ </PanelContainer>
+ <PanelContainer Name="HighlightPanel">
+ <PanelContainer.PanelOverride>
+ <graphics:StyleBoxTexture PatchMarginBottom="4" PatchMarginTop="6" TextureScale="2 2">
+ </graphics:StyleBoxTexture>
+ </PanelContainer.PanelOverride>
+ </PanelContainer>
+ <BoxContainer Name="Contents" Orientation="Vertical" Margin="0 6 0 4">
+ <BoxContainer Name="StatusContents" Orientation="Vertical" />
+ <Label Name="ItemNameLabel" ClipText="True" StyleClasses="ItemStatus" Align="Left" />
</BoxContainer>
- </PanelContainer>
+ </Control>
</controls:ItemStatusPanel>
+using System.Numerics;
using Content.Client.Items;
using Content.Client.Resources;
using Content.Shared.Hands.Components;
using Content.Shared.Inventory.VirtualItem;
using Robust.Client.AutoGenerated;
using Robust.Client.Graphics;
+using Robust.Client.UserInterface;
using Robust.Client.UserInterface.Controls;
using Robust.Client.UserInterface.XAML;
using Robust.Shared.Timing;
namespace Content.Client.UserInterface.Systems.Inventory.Controls;
[GenerateTypedNameReferences]
-public sealed partial class ItemStatusPanel : BoxContainer
+public sealed partial class ItemStatusPanel : Control
{
[Dependency] private readonly IEntityManager _entityManager = default!;
[ViewVariables] private EntityUid? _entity;
+ // Tracked so we can re-run SetSide() if the theme changes.
+ private HandLocation _side;
+
public ItemStatusPanel()
{
RobustXamlLoader.Load(this);
public void SetSide(HandLocation location)
{
- string texture;
+ // AN IMPORTANT REMINDER ABOUT THIS CODE:
+ // In the UI, the RIGHT hand is on the LEFT on the screen.
+ // So that a character facing DOWN matches the hand positions.
+
+ Texture? texture;
+ Texture? textureHighlight;
StyleBox.Margin cutOut;
StyleBox.Margin flat;
- Label.AlignMode textAlign;
+ Thickness contentMargin;
switch (location)
{
- case HandLocation.Left:
- texture = "/Textures/Interface/Nano/item_status_right.svg.96dpi.png";
- cutOut = StyleBox.Margin.Left | StyleBox.Margin.Top;
- flat = StyleBox.Margin.Right | StyleBox.Margin.Bottom;
- textAlign = Label.AlignMode.Right;
+ case HandLocation.Right:
+ texture = Theme.ResolveTexture("item_status_right");
+ textureHighlight = Theme.ResolveTexture("item_status_right_highlight");
+ cutOut = StyleBox.Margin.Left;
+ flat = StyleBox.Margin.Right;
+ contentMargin = MarginFromThemeColor("_itemstatus_content_margin_right");
break;
case HandLocation.Middle:
- texture = "/Textures/Interface/Nano/item_status_middle.svg.96dpi.png";
- cutOut = StyleBox.Margin.Right | StyleBox.Margin.Top;
- flat = StyleBox.Margin.Left | StyleBox.Margin.Bottom;
- textAlign = Label.AlignMode.Left;
- break;
- case HandLocation.Right:
- texture = "/Textures/Interface/Nano/item_status_left.svg.96dpi.png";
- cutOut = StyleBox.Margin.Right | StyleBox.Margin.Top;
- flat = StyleBox.Margin.Left | StyleBox.Margin.Bottom;
- textAlign = Label.AlignMode.Left;
+ case HandLocation.Left:
+ texture = Theme.ResolveTexture("item_status_left");
+ textureHighlight = Theme.ResolveTexture("item_status_left_highlight");
+ cutOut = StyleBox.Margin.Right;
+ flat = StyleBox.Margin.Left;
+ contentMargin = MarginFromThemeColor("_itemstatus_content_margin_left");
break;
default:
throw new ArgumentOutOfRangeException(nameof(location), location, null);
}
+ Contents.Margin = contentMargin;
+
var panel = (StyleBoxTexture) Panel.PanelOverride!;
- panel.Texture = ResC.GetTexture(texture);
- panel.SetPatchMargin(flat, 2);
- panel.SetPatchMargin(cutOut, 13);
+ panel.Texture = texture;
+ panel.SetPatchMargin(flat, 4);
+ panel.SetPatchMargin(cutOut, 7);
- ItemNameLabel.Align = textAlign;
+ var panelHighlight = (StyleBoxTexture) HighlightPanel.PanelOverride!;
+ panelHighlight.Texture = textureHighlight;
+ panelHighlight.SetPatchMargin(flat, 4);
+ panelHighlight.SetPatchMargin(cutOut, 7);
+
+ _side = location;
+ }
+
+ private Thickness MarginFromThemeColor(string itemName)
+ {
+ // This is the worst thing I've ever programmed
+ // (can you tell I'm a graphics programmer?)
+ // (the margin needs to change depending on the UI theme, so we use a fake color entry to store the value)
+
+ var color = Theme.ResolveColorOrSpecified(itemName);
+ return new Thickness(color.RByte, color.GByte, color.BByte, color.AByte);
+ }
+
+ protected override void OnThemeUpdated()
+ {
+ SetSide(_side);
}
protected override void FrameUpdate(FrameEventArgs args)
{
ClearOldStatus();
_entity = null;
- Panel.Visible = false;
+ VisWrapper.Visible = false;
return;
}
UpdateItemName();
}
- Panel.Visible = true;
+ VisWrapper.Visible = true;
+ }
+
+ public void UpdateHighlight(bool highlight)
+ {
+ HighlightPanel.Visible = highlight;
}
private void UpdateItemName()
--- /dev/null
+using System.Numerics;
+using Content.Client.Resources;
+using Robust.Client.Graphics;
+using Robust.Client.ResourceManagement;
+using Robust.Client.UserInterface;
+
+namespace Content.Client.Weapons.Ranged.ItemStatus;
+
+/// <summary>
+/// Renders one or more rows of bullets for item status.
+/// </summary>
+/// <remarks>
+/// This is a custom control to allow complex responsive layout logic.
+/// </remarks>
+public sealed class BulletRender : Control
+{
+ private static readonly Color ColorA = Color.FromHex("#b68f0e");
+ private static readonly Color ColorB = Color.FromHex("#d7df60");
+ private static readonly Color ColorGoneA = Color.FromHex("#000000");
+ private static readonly Color ColorGoneB = Color.FromHex("#222222");
+
+ /// <summary>
+ /// Try to ensure there's at least this many bullets on one row.
+ /// </summary>
+ /// <remarks>
+ /// For example, if there are two rows and the second row has only two bullets,
+ /// we "steal" some bullets from the row below it to make it look nicer.
+ /// </remarks>
+ public const int MinCountPerRow = 7;
+
+ public const int BulletHeight = 12;
+ public const int BulletSeparationNormal = 3;
+ public const int BulletSeparationTiny = 2;
+ public const int BulletWidthNormal = 5;
+ public const int BulletWidthTiny = 2;
+ public const int VerticalSeparation = 2;
+
+ private readonly Texture _bulletTiny;
+ private readonly Texture _bulletNormal;
+
+ private int _capacity;
+ private BulletType _type = BulletType.Normal;
+
+ public int Rows { get; set; } = 2;
+ public int Count { get; set; }
+
+ public int Capacity
+ {
+ get => _capacity;
+ set
+ {
+ _capacity = value;
+ InvalidateMeasure();
+ }
+ }
+
+ public BulletType Type
+ {
+ get => _type;
+ set
+ {
+ _type = value;
+ InvalidateMeasure();
+ }
+ }
+
+ public BulletRender()
+ {
+ var resC = IoCManager.Resolve<IResourceCache>();
+ _bulletTiny = resC.GetTexture("/Textures/Interface/ItemStatus/Bullets/tiny.png");
+ _bulletNormal = resC.GetTexture("/Textures/Interface/ItemStatus/Bullets/normal.png");
+ }
+
+ protected override Vector2 MeasureOverride(Vector2 availableSize)
+ {
+ var countPerRow = Math.Min(Capacity, CountPerRow(availableSize.X));
+
+ var rows = Math.Min((int) MathF.Ceiling(Capacity / (float) countPerRow), Rows);
+
+ var height = BulletHeight * rows + (BulletSeparationNormal * rows - 1);
+ var width = RowWidth(countPerRow);
+
+ return new Vector2(width, height);
+ }
+
+ protected override void Draw(DrawingHandleScreen handle)
+ {
+ // Scale rendering in this control by UIScale.
+ var currentTransform = handle.GetTransform();
+ handle.SetTransform(Matrix3.CreateScale(new Vector2(UIScale)) * currentTransform);
+
+ var countPerRow = CountPerRow(Size.X);
+
+ var (separation, _) = BulletParams();
+ var texture = Type == BulletType.Normal ? _bulletNormal : _bulletTiny;
+
+ var pos = new Vector2();
+
+ var altColor = false;
+
+ var spent = Capacity - Count;
+
+ var bulletsDone = 0;
+
+ // Draw by rows, bottom to top.
+ for (var row = 0; row < Rows; row++)
+ {
+ altColor = false;
+
+ var thisRowCount = Math.Min(countPerRow, Capacity - bulletsDone);
+ if (thisRowCount <= 0)
+ break;
+
+ // Handle MinCountPerRow
+ // We only do this if:
+ // 1. The next row would have less than MinCountPerRow bullets.
+ // 2. The next row is actually visible (we aren't the last row).
+ // 3. MinCountPerRow is actually smaller than the count per row (avoid degenerate cases).
+ var nextRowCount = Capacity - bulletsDone - thisRowCount;
+ if (nextRowCount < MinCountPerRow && row != Rows - 1 && MinCountPerRow < countPerRow)
+ thisRowCount -= MinCountPerRow - nextRowCount;
+
+ // Account for row width to right-align.
+ var rowWidth = RowWidth(thisRowCount);
+ pos.X += Size.X - rowWidth;
+
+ // Draw row left to right (so overlapping works)
+ for (var bullet = 0; bullet < thisRowCount; bullet++)
+ {
+ var absIdx = Capacity - bulletsDone - thisRowCount + bullet;
+ Color color;
+ if (absIdx >= spent)
+ color = altColor ? ColorA : ColorB;
+ else
+ color = altColor ? ColorGoneA : ColorGoneB;
+
+ var renderPos = pos;
+ renderPos.Y = Size.Y - renderPos.Y - BulletHeight;
+ handle.DrawTexture(texture, renderPos, color);
+ pos.X += separation;
+ altColor ^= true;
+ }
+
+ bulletsDone += thisRowCount;
+ pos.X = 0;
+ pos.Y += BulletHeight + VerticalSeparation;
+ }
+ }
+
+ private int CountPerRow(float width)
+ {
+ var (separation, bulletWidth) = BulletParams();
+ return (int) ((width - bulletWidth + separation) / separation);
+ }
+
+ private (int separation, int width) BulletParams()
+ {
+ return Type switch
+ {
+ BulletType.Normal => (BulletSeparationNormal, BulletWidthNormal),
+ BulletType.Tiny => (BulletSeparationTiny, BulletWidthTiny),
+ _ => throw new ArgumentOutOfRangeException()
+ };
+ }
+
+ private int RowWidth(int count)
+ {
+ var (separation, bulletWidth) = BulletParams();
+
+ return (count - 1) * separation + bulletWidth;
+ }
+
+ public enum BulletType
+ {
+ Normal,
+ Tiny
+ }
+}
using Content.Client.Resources;
using Content.Client.Stylesheets;
using Content.Client.Weapons.Ranged.Components;
+using Content.Client.Weapons.Ranged.ItemStatus;
using Robust.Client.Animations;
using Robust.Client.Graphics;
using Robust.Client.UserInterface;
using Robust.Client.UserInterface.Controls;
-using Robust.Shared.Graphics;
namespace Content.Client.Weapons.Ranged.Systems;
private sealed class DefaultStatusControl : Control
{
- private readonly BoxContainer _bulletsListTop;
- private readonly BoxContainer _bulletsListBottom;
+ private readonly BulletRender _bulletRender;
public DefaultStatusControl()
{
MinHeight = 15;
HorizontalExpand = true;
- VerticalAlignment = Control.VAlignment.Center;
- AddChild(new BoxContainer
+ VerticalAlignment = VAlignment.Center;
+ AddChild(_bulletRender = new BulletRender
{
- Orientation = BoxContainer.LayoutOrientation.Vertical,
- HorizontalExpand = true,
- VerticalAlignment = VAlignment.Center,
- SeparationOverride = 0,
- Children =
- {
- (_bulletsListTop = new BoxContainer
- {
- Orientation = BoxContainer.LayoutOrientation.Horizontal,
- SeparationOverride = 0
- }),
- new BoxContainer
- {
- Orientation = BoxContainer.LayoutOrientation.Horizontal,
- HorizontalExpand = true,
- Children =
- {
- new Control
- {
- HorizontalExpand = true,
- Children =
- {
- (_bulletsListBottom = new BoxContainer
- {
- Orientation = BoxContainer.LayoutOrientation.Horizontal,
- VerticalAlignment = VAlignment.Center,
- SeparationOverride = 0
- }),
- }
- },
- }
- }
- }
+ HorizontalAlignment = HAlignment.Right,
+ VerticalAlignment = VAlignment.Bottom
});
}
public void Update(int count, int capacity)
{
- _bulletsListTop.RemoveAllChildren();
- _bulletsListBottom.RemoveAllChildren();
-
- string texturePath;
- if (capacity <= 20)
- {
- texturePath = "/Textures/Interface/ItemStatus/Bullets/normal.png";
- }
- else if (capacity <= 30)
- {
- texturePath = "/Textures/Interface/ItemStatus/Bullets/small.png";
- }
- else
- {
- texturePath = "/Textures/Interface/ItemStatus/Bullets/tiny.png";
- }
-
- var texture = StaticIoC.ResC.GetTexture(texturePath);
+ _bulletRender.Count = count;
+ _bulletRender.Capacity = capacity;
- const int tinyMaxRow = 60;
-
- if (capacity > tinyMaxRow)
- {
- FillBulletRow(_bulletsListBottom, Math.Min(tinyMaxRow, count), tinyMaxRow, texture);
- FillBulletRow(_bulletsListTop, Math.Max(0, count - tinyMaxRow), capacity - tinyMaxRow, texture);
- }
- else
- {
- FillBulletRow(_bulletsListBottom, count, capacity, texture);
- }
- }
-
- private static void FillBulletRow(Control container, int count, int capacity, Texture texture)
- {
- var colorA = Color.FromHex("#b68f0e");
- var colorB = Color.FromHex("#d7df60");
- var colorGoneA = Color.FromHex("#000000");
- var colorGoneB = Color.FromHex("#222222");
-
- var altColor = false;
-
- for (var i = count; i < capacity; i++)
- {
- container.AddChild(new TextureRect
- {
- Texture = texture,
- ModulateSelfOverride = altColor ? colorGoneA : colorGoneB
- });
-
- altColor ^= true;
- }
-
- for (var i = 0; i < count; i++)
- {
- container.AddChild(new TextureRect
- {
- Texture = texture,
- ModulateSelfOverride = altColor ? colorA : colorB
- });
-
- altColor ^= true;
- }
+ _bulletRender.Type = capacity > 50 ? BulletRender.BulletType.Tiny : BulletRender.BulletType.Normal;
}
}
private sealed class ChamberMagazineStatusControl : Control
{
- private readonly BoxContainer _bulletsList;
+ private readonly BulletRender _bulletRender;
private readonly TextureRect _chamberedBullet;
private readonly Label _noMagazineLabel;
private readonly Label _ammoCount;
HorizontalExpand = true,
Children =
{
- (_chamberedBullet = new TextureRect
- {
- Texture = StaticIoC.ResC.GetTexture("/Textures/Interface/ItemStatus/Bullets/chambered_rotated.png"),
- VerticalAlignment = VAlignment.Center,
- HorizontalAlignment = HAlignment.Right,
- }),
- new Control() { MinSize = new Vector2(5,0) },
new Control
{
HorizontalExpand = true,
+ Margin = new Thickness(0, 0, 5, 0),
Children =
{
- (_bulletsList = new BoxContainer
+ (_bulletRender = new BulletRender
{
- Orientation = BoxContainer.LayoutOrientation.Horizontal,
- VerticalAlignment = VAlignment.Center,
- SeparationOverride = 0
+ HorizontalAlignment = HAlignment.Right,
+ VerticalAlignment = VAlignment.Bottom
}),
(_noMagazineLabel = new Label
{
})
}
},
- new Control() { MinSize = new Vector2(5,0) },
- (_ammoCount = new Label
+ new BoxContainer
{
- StyleClasses = {StyleNano.StyleClassItemStatus},
- HorizontalAlignment = HAlignment.Right,
- }),
+ Orientation = BoxContainer.LayoutOrientation.Vertical,
+ VerticalAlignment = VAlignment.Bottom,
+ Margin = new Thickness(0, 0, 0, 2),
+ Children =
+ {
+ (_ammoCount = new Label
+ {
+ StyleClasses = {StyleNano.StyleClassItemStatus},
+ HorizontalAlignment = HAlignment.Right,
+ }),
+ (_chamberedBullet = new TextureRect
+ {
+ Texture = StaticIoC.ResC.GetTexture("/Textures/Interface/ItemStatus/Bullets/chambered.png"),
+ HorizontalAlignment = HAlignment.Left,
+ }),
+ }
+ }
}
});
}
_chamberedBullet.ModulateSelfOverride =
chambered ? Color.FromHex("#d7df60") : Color.Black;
- _bulletsList.RemoveAllChildren();
-
if (!magazine)
{
+ _bulletRender.Visible = false;
_noMagazineLabel.Visible = true;
_ammoCount.Visible = false;
return;
}
+ _bulletRender.Visible = true;
_noMagazineLabel.Visible = false;
_ammoCount.Visible = true;
- var texturePath = "/Textures/Interface/ItemStatus/Bullets/normal.png";
- var texture = StaticIoC.ResC.GetTexture(texturePath);
+ _bulletRender.Count = count;
+ _bulletRender.Capacity = capacity;
- _ammoCount.Text = $"x{count:00}";
- capacity = Math.Min(capacity, 20);
- FillBulletRow(_bulletsList, count, capacity, texture);
- }
-
- private static void FillBulletRow(Control container, int count, int capacity, Texture texture)
- {
- var colorA = Color.FromHex("#b68f0e");
- var colorB = Color.FromHex("#d7df60");
- var colorGoneA = Color.FromHex("#000000");
- var colorGoneB = Color.FromHex("#222222");
-
- var altColor = false;
-
- // Draw the empty ones
- for (var i = count; i < capacity; i++)
- {
- container.AddChild(new TextureRect
- {
- Texture = texture,
- ModulateSelfOverride = altColor ? colorGoneA : colorGoneB,
- Stretch = TextureRect.StretchMode.KeepCentered
- });
-
- altColor ^= true;
- }
-
- // Draw the full ones, but limit the count to the capacity
- count = Math.Min(count, capacity);
- for (var i = 0; i < count; i++)
- {
- container.AddChild(new TextureRect
- {
- Texture = texture,
- ModulateSelfOverride = altColor ? colorA : colorB,
- Stretch = TextureRect.StretchMode.KeepCentered
- });
+ _bulletRender.Type = capacity > 50 ? BulletRender.BulletType.Tiny : BulletRender.BulletType.Normal;
- altColor ^= true;
- }
+ _ammoCount.Text = $"x{count:00}";
}
public void PlayAlarmAnimation(Animation animation)
</ItemGroup>
<ItemGroup>
<Folder Include="Objectives\Interfaces\" />
- <Folder Include="Tools\Systems\" />
</ItemGroup>
<Import Project="..\RobustToolbox\MSBuild\Robust.Properties.targets" />
</Project>
"Icon",
"HandheldGPS",
"CableVisualizer",
+ "SolutionItemStatus",
"UIFragment",
"PdaBorderColor",
"InventorySlots",
"LightFade",
"HolidayRsiSwap",
- "OptionsVisualizer",
+ "OptionsVisualizer"
};
}
}
if (welder.WelderTimer < welder.WelderUpdateTimer)
continue;
- if (!SolutionContainerSystem.ResolveSolution((uid, solutionContainer), welder.FuelSolutionName, ref welder.FuelSolution, out var solution))
+ if (!SolutionContainerSystem.TryGetSolution((uid, solutionContainer), welder.FuelSolutionName, out var solutionComp, out var solution))
continue;
- SolutionContainerSystem.RemoveReagent(welder.FuelSolution.Value, welder.FuelReagent, welder.FuelConsumption * welder.WelderTimer);
+ SolutionContainerSystem.RemoveReagent(solutionComp.Value, welder.FuelReagent, welder.FuelConsumption * welder.WelderTimer);
if (solution.GetTotalPrototypeQuantity(welder.FuelReagent) <= FixedPoint2.Zero)
{
[DataField]
public string FuelSolutionName = "Welder";
- /// <summary>
- /// Solution on the entity that contains the fuel.
- /// </summary>
- [ViewVariables(VVAccess.ReadWrite)]
- public Entity<SolutionComponent>? FuelSolution;
-
/// <summary>
/// Reagent that will be used as fuel for welding.
/// </summary>
public virtual void TurnOn(Entity<WelderComponent> entity, EntityUid? user)
{
- if (!SolutionContainerSystem.ResolveSolution(entity.Owner, entity.Comp.FuelSolutionName, ref entity.Comp.FuelSolution))
+ if (!SolutionContainerSystem.TryGetSolution(entity.Owner, entity.Comp.FuelSolutionName, out var solutionComp, out _))
return;
- SolutionContainerSystem.RemoveReagent(entity.Comp.FuelSolution.Value, entity.Comp.FuelReagent, entity.Comp.FuelLitCost);
+ SolutionContainerSystem.RemoveReagent(solutionComp.Value, entity.Comp.FuelReagent, entity.Comp.FuelLitCost);
AdminLogger.Add(LogType.InteractActivate, LogImpact.Low,
$"{ToPrettyString(user):user} toggled {ToPrettyString(entity.Owner):welder} on");
public (FixedPoint2 fuel, FixedPoint2 capacity) GetWelderFuelAndCapacity(EntityUid uid, WelderComponent? welder = null, SolutionContainerManagerComponent? solutionContainer = null)
{
- if (!Resolve(uid, ref welder, ref solutionContainer)
- || !SolutionContainerSystem.ResolveSolution((uid, solutionContainer), welder.FuelSolutionName, ref welder.FuelSolution, out var fuelSolution))
- return (FixedPoint2.Zero, FixedPoint2.Zero);
+ if (!Resolve(uid, ref welder, ref solutionContainer))
+ return default;
+
+ if (!SolutionContainer.TryGetSolution(
+ (uid, solutionContainer),
+ welder.FuelSolutionName,
+ out _,
+ out var fuelSolution))
+ {
+ return default;
+ }
return (fuelSolution.GetTotalPrototypeQuantity(welder.FuelReagent), fuelSolution.MaxVolume);
}
if (TryComp(target, out ReagentTankComponent? tank)
&& tank.TankType == ReagentTankType.Fuel
&& SolutionContainerSystem.TryGetDrainableSolution(target, out var targetSoln, out var targetSolution)
- && SolutionContainerSystem.ResolveSolution(entity.Owner, entity.Comp.FuelSolutionName, ref entity.Comp.FuelSolution, out var welderSolution))
+ && SolutionContainerSystem.TryGetSolution(entity.Owner, entity.Comp.FuelSolutionName, out var solutionComp, out var welderSolution))
{
var trans = FixedPoint2.Min(welderSolution.AvailableVolume, targetSolution.Volume);
if (trans > 0)
{
var drained = SolutionContainerSystem.Drain(target, targetSoln.Value, trans);
- SolutionContainerSystem.TryAddSolution(entity.Comp.FuelSolution.Value, drained);
+ SolutionContainerSystem.TryAddSolution(solutionComp.Value, drained);
_audioSystem.PlayPredicted(entity.Comp.WelderRefill, entity, user: args.User);
_popup.PopupClient(Loc.GetString("welder-component-after-interact-refueled-message"), entity, args.User);
}
private void OnActivateAttempt(Entity<WelderComponent> entity, ref ItemToggleActivateAttemptEvent args)
{
- if (!SolutionContainerSystem.ResolveSolution(entity.Owner, entity.Comp.FuelSolutionName, ref entity.Comp.FuelSolution, out var solution))
+ if (!SolutionContainerSystem.TryGetSolution(entity.Owner, entity.Comp.FuelSolutionName, out _, out var solution))
{
args.Cancelled = true;
args.Popup = Loc.GetString("welder-component-no-fuel-message");
[Dependency] private readonly SharedTransformSystem _transformSystem = default!;
[Dependency] private readonly TileSystem _tiles = default!;
[Dependency] private readonly TurfSystem _turfs = default!;
+ [Dependency] protected readonly SharedSolutionContainerSystem SolutionContainer = default!;
public override void Initialize()
{
--- /dev/null
+solution-status-volume = Volume: [color=white]{$currentVolume}/{$maxVolume}u[/color]
+solution-status-transfer = Transfer: [color=white]{$volume}u[/color]
welder-component-no-fuel-in-tank = The {$owner} is empty.
welder-component-on-examine-welder-lit-message = [color=orange]Lit[/color]
welder-component-on-examine-welder-not-lit-message = Not lit
-welder-component-on-examine-detailed-message = Fuel: [color={$colorName}]{$fuelLeft}/{$fuelCapacity}[/color]. {$status}
+welder-component-on-examine-detailed-message = Fuel: [color={$colorName}]{$fuelLeft}/{$fuelCapacity}[/color]
+ {$status}
welder-component-suicide-lit-others-message = {$victim} welds their every orifice closed! It looks like they are trying to commit suicide!
welder-component-suicide-lit-message = You weld your every orifice closed!
welder-component-suicide-unlit-others-message = {$victim} bashes themselves with the unlit welding torch!
solution: spray
- type: SolutionTransfer
canChangeTransferAmount: true
+ - type: SolutionItemStatus
+ solution: spray
- type: UseDelay
- type: Spray
transferAmount: 10
solution: beaker
- type: SolutionTransfer
canChangeTransferAmount: true
+ - type: SolutionItemStatus
+ solution: beaker
- type: UserInterface
interfaces:
- key: enum.TransferAmountUiKey.Key
solution: beaker
- type: SolutionTransfer
canChangeTransferAmount: true
+ - type: SolutionItemStatus
+ solution: beaker
- type: UserInterface
interfaces:
- key: enum.TransferAmountUiKey.Key
solution: bucket
- type: DrainableSolution
solution: bucket
+ - type: SolutionItemStatus
+ solution: bucket
- type: Appearance
- type: SolutionContainerVisuals
maxFillLevels: 3
concerningOrangeFore: "#A5762F"
dangerousRedFore: "#BB3232"
disabledFore: "#5A5A5A"
+ _itemstatus_content_margin_right: "#06060404"
+ _itemstatus_content_margin_left: "#04060604"
- type: uiTheme
id: SS14PlasmafireTheme
path: /Textures/Interface/Plasmafire/
concerningOrangeFore: "#FFF5EE"
dangerousRedFore: "#FFF5EE"
disabledFore: "#FFF5EE"
+ _itemstatus_content_margin_right: "#06060404"
+ _itemstatus_content_margin_left: "#04060604"
- type: uiTheme
id: SS14SlimecoreTheme
path: /Textures/Interface/Slimecore/
concerningOrangeFore: "#FFF5EE"
dangerousRedFore: "#FFF5EE"
disabledFore: "#FFF5EE"
+ _itemstatus_content_margin_right: "#06060404"
+ _itemstatus_content_margin_left: "#04060604"
- type: uiTheme
id: SS14ClockworkTheme
path: /Textures/Interface/Clockwork/
concerningOrangeFore: "#FFF5EE"
dangerousRedFore: "#FFF5EE"
disabledFore: "#FFF5EE"
+ _itemstatus_content_margin_right: "#06060404"
+ _itemstatus_content_margin_left: "#04060604"
- type: uiTheme
id: SS14RetroTheme
path: /Textures/Interface/Retro/
concerningOrangeFore: "#FFF5EE"
dangerousRedFore: "#FFF5EE"
disabledFore: "#FFF5EE"
+ _itemstatus_content_margin_right: "#06060404"
+ _itemstatus_content_margin_left: "#04060604"
- type: uiTheme
id: SS14MinimalistTheme
path: /Textures/Interface/Minimalist/
concerningOrangeFore: "#A5762F"
dangerousRedFore: "#BB3232"
disabledFore: "#5A5A5A"
+ _itemstatus_content_margin_right: "#06060604"
+ _itemstatus_content_margin_left: "#06060604"
- type: uiTheme
id: SS14AshenTheme
path: /Textures/Interface/Ashen/
concerningOrangeFore: "#FFF5EE"
dangerousRedFore: "#FFF5EE"
disabledFore: "#FFF5EE"
+ _itemstatus_content_margin_right: "#06060604"
+ _itemstatus_content_margin_left: "#06060604"
+++ /dev/null
-<?xml version="1.0" encoding="UTF-8" standalone="no"?>
-<svg
- xmlns:dc="http://purl.org/dc/elements/1.1/"
- xmlns:cc="http://creativecommons.org/ns#"
- xmlns:rdf="http://www.w3.org/1999/02/22-rdf-syntax-ns#"
- xmlns:svg="http://www.w3.org/2000/svg"
- xmlns="http://www.w3.org/2000/svg"
- xmlns:sodipodi="http://sodipodi.sourceforge.net/DTD/sodipodi-0.dtd"
- xmlns:inkscape="http://www.inkscape.org/namespaces/inkscape"
- width="17.700001"
- height="17.700001"
- viewBox="0 0 4.6831256 4.6831253"
- version="1.1"
- id="svg8"
- inkscape:version="1.0.1 (3bc2e813f5, 2020-09-07)"
- sodipodi:docname="item_status_left.svg"
- inkscape:export-filename="C:\ss14\space-station-14\Resources\Textures\Interface\Nano\item_status_left.svg.96dpi.png"
- inkscape:export-xdpi="96"
- inkscape:export-ydpi="96">
- <defs
- id="defs2" />
- <sodipodi:namedview
- id="base"
- pagecolor="#ffffff"
- bordercolor="#666666"
- borderopacity="1.0"
- inkscape:pageopacity="0.0"
- inkscape:pageshadow="2"
- inkscape:zoom="45.254834"
- inkscape:cx="2.2968017"
- inkscape:cy="9.7979333"
- inkscape:document-units="px"
- inkscape:current-layer="layer1"
- showgrid="false"
- inkscape:pagecheckerboard="true"
- units="px"
- showguides="true"
- inkscape:window-width="2560"
- inkscape:window-height="1377"
- inkscape:window-x="1912"
- inkscape:window-y="-8"
- inkscape:window-maximized="1"
- inkscape:guide-bbox="true"
- inkscape:snap-intersection-paths="true"
- inkscape:snap-bbox="true"
- inkscape:snap-page="true"
- inkscape:document-rotation="0"
- fit-margin-top="0"
- fit-margin-left="0"
- fit-margin-right="0"
- fit-margin-bottom="0">
- <inkscape:grid
- type="xygrid"
- id="grid817"
- originx="0.44979165"
- originy="1.5931808" />
- </sodipodi:namedview>
- <metadata
- id="metadata5">
- <rdf:RDF>
- <cc:Work
- rdf:about="">
- <dc:format>image/svg+xml</dc:format>
- <dc:type
- rdf:resource="http://purl.org/dc/dcmitype/StillImage" />
- <dc:title />
- </cc:Work>
- </rdf:RDF>
- </metadata>
- <g
- inkscape:label="Layer 1"
- inkscape:groupmode="layer"
- id="layer1"
- transform="translate(-26.372785,-208.49171)">
- <path
- style="color:#000000;font-style:normal;font-variant:normal;font-weight:normal;font-stretch:normal;font-size:medium;line-height:normal;font-family:sans-serif;font-variant-ligatures:normal;font-variant-position:normal;font-variant-caps:normal;font-variant-numeric:normal;font-variant-alternates:normal;font-feature-settings:normal;text-indent:0;text-align:start;text-decoration:none;text-decoration-line:none;text-decoration-style:solid;text-decoration-color:#000000;letter-spacing:normal;word-spacing:normal;text-transform:none;writing-mode:lr-tb;direction:ltr;text-orientation:mixed;dominant-baseline:auto;baseline-shift:baseline;text-anchor:start;white-space:normal;shape-padding:0;clip-rule:nonzero;display:inline;overflow:visible;visibility:visible;opacity:1;isolation:auto;mix-blend-mode:normal;color-interpolation:sRGB;color-interpolation-filters:linearRGB;solid-color:#000000;solid-opacity:1;vector-effect:none;fill:#474747;fill-opacity:1;fill-rule:nonzero;stroke:none;stroke-width:0.264583;stroke-linecap:butt;stroke-linejoin:miter;stroke-miterlimit:4;stroke-dasharray:none;stroke-dashoffset:0;stroke-opacity:1;color-rendering:auto;image-rendering:auto;shape-rendering:auto;text-rendering:auto;enable-background:accumulate"
- d="m 45.902791,212.76114 v 3.23047 l 1.003906,1.00195 h 3.228516 v -3.22852 l -1.001953,-1.0039 h -0.05469 z m 0.263672,0.26367 h 2.855469 l 0.849609,0.84961 v 2.85547 h -2.855468 l -0.84961,-0.84961 z"
- id="rect815-3"
- inkscape:connector-curvature="0" />
- <path
- style="color:#000000;font-style:normal;font-variant:normal;font-weight:normal;font-stretch:normal;font-size:medium;line-height:normal;font-family:sans-serif;font-variant-ligatures:normal;font-variant-position:normal;font-variant-caps:normal;font-variant-numeric:normal;font-variant-alternates:normal;font-feature-settings:normal;text-indent:0;text-align:start;text-decoration:none;text-decoration-line:none;text-decoration-style:solid;text-decoration-color:#000000;letter-spacing:normal;word-spacing:normal;text-transform:none;writing-mode:lr-tb;direction:ltr;text-orientation:mixed;dominant-baseline:auto;baseline-shift:baseline;text-anchor:start;white-space:normal;shape-padding:0;clip-rule:nonzero;display:inline;overflow:visible;visibility:visible;opacity:1;isolation:auto;mix-blend-mode:normal;color-interpolation:sRGB;color-interpolation-filters:linearRGB;solid-color:#000000;solid-opacity:1;vector-effect:none;fill:#474747;fill-opacity:1;fill-rule:nonzero;stroke:none;stroke-width:0.264583;stroke-linecap:butt;stroke-linejoin:miter;stroke-miterlimit:4;stroke-dasharray:none;stroke-dashoffset:0;stroke-opacity:1;color-rendering:auto;image-rendering:auto;shape-rendering:auto;text-rendering:auto;enable-background:accumulate"
- d="m 46.344997,207.34832 -0.290893,0.17906 1.133594,1.1102 v 2.91047 h 0.264579 v -3.04271 z"
- id="rect815-6"
- inkscape:connector-curvature="0"
- sodipodi:nodetypes="ccccccc" />
- <path
- style="fill:none;stroke:#474747;stroke-width:0.529167;stroke-linecap:butt;stroke-linejoin:miter;stroke-miterlimit:4;stroke-dasharray:none;stroke-opacity:1"
- d="m 38.473823,212.26371 v -3.175 l -1.058333,-1.05833"
- id="path856-6"
- inkscape:connector-curvature="0"
- sodipodi:nodetypes="ccc" />
- <path
- id="rect815-9"
- style="opacity:1;vector-effect:none;fill:#24242b;fill-opacity:0.95;fill-rule:nonzero;stroke:#3a4051;stroke-width:0.449792;stroke-linecap:butt;stroke-linejoin:miter;stroke-miterlimit:4;stroke-dasharray:none;stroke-dashoffset:0;stroke-opacity:1"
- d="m 26.373445,212.94994 h 3.704167 0.753402 v -1.5875 l -2.870068,-2.64583 h -0.748275 -0.839226"
- inkscape:export-xdpi="96.000008"
- inkscape:export-ydpi="96.000008"
- sodipodi:nodetypes="ccccccc" />
- </g>
-</svg>
+++ /dev/null
-<?xml version="1.0" encoding="UTF-8" standalone="no"?>
-<svg
- xmlns:dc="http://purl.org/dc/elements/1.1/"
- xmlns:cc="http://creativecommons.org/ns#"
- xmlns:rdf="http://www.w3.org/1999/02/22-rdf-syntax-ns#"
- xmlns:svg="http://www.w3.org/2000/svg"
- xmlns="http://www.w3.org/2000/svg"
- xmlns:sodipodi="http://sodipodi.sourceforge.net/DTD/sodipodi-0.dtd"
- xmlns:inkscape="http://www.inkscape.org/namespaces/inkscape"
- width="17.700001"
- height="17.700001"
- viewBox="0 0 4.6831256 4.6831253"
- version="1.1"
- id="svg8"
- inkscape:version="1.0.1 (3bc2e813f5, 2020-09-07)"
- sodipodi:docname="item_status_middle.svg"
- inkscape:export-filename="C:\ss14\space-station-14\Resources\Textures\Interface\Nano\item_status_left.svg.96dpi.png"
- inkscape:export-xdpi="96"
- inkscape:export-ydpi="96">
- <defs
- id="defs2" />
- <sodipodi:namedview
- id="base"
- pagecolor="#ffffff"
- bordercolor="#666666"
- borderopacity="1.0"
- inkscape:pageopacity="0.0"
- inkscape:pageshadow="2"
- inkscape:zoom="256"
- inkscape:cx="0.27981532"
- inkscape:cy="1.9876937"
- inkscape:document-units="px"
- inkscape:current-layer="layer1"
- showgrid="false"
- inkscape:pagecheckerboard="true"
- units="px"
- showguides="true"
- inkscape:window-width="2560"
- inkscape:window-height="1377"
- inkscape:window-x="1912"
- inkscape:window-y="-8"
- inkscape:window-maximized="1"
- inkscape:guide-bbox="true"
- inkscape:snap-intersection-paths="true"
- inkscape:snap-bbox="true"
- inkscape:snap-page="true"
- inkscape:document-rotation="0"
- fit-margin-top="0"
- fit-margin-left="0"
- fit-margin-right="0"
- fit-margin-bottom="0">
- <inkscape:grid
- type="xygrid"
- id="grid817"
- originx="0.44979165"
- originy="1.5931808" />
- </sodipodi:namedview>
- <metadata
- id="metadata5">
- <rdf:RDF>
- <cc:Work
- rdf:about="">
- <dc:format>image/svg+xml</dc:format>
- <dc:type
- rdf:resource="http://purl.org/dc/dcmitype/StillImage" />
- <dc:title />
- </cc:Work>
- </rdf:RDF>
- </metadata>
- <g
- inkscape:label="Layer 1"
- inkscape:groupmode="layer"
- id="layer1"
- transform="translate(-26.372785,-208.49171)">
- <path
- style="color:#000000;font-style:normal;font-variant:normal;font-weight:normal;font-stretch:normal;font-size:medium;line-height:normal;font-family:sans-serif;font-variant-ligatures:normal;font-variant-position:normal;font-variant-caps:normal;font-variant-numeric:normal;font-variant-alternates:normal;font-feature-settings:normal;text-indent:0;text-align:start;text-decoration:none;text-decoration-line:none;text-decoration-style:solid;text-decoration-color:#000000;letter-spacing:normal;word-spacing:normal;text-transform:none;writing-mode:lr-tb;direction:ltr;text-orientation:mixed;dominant-baseline:auto;baseline-shift:baseline;text-anchor:start;white-space:normal;shape-padding:0;clip-rule:nonzero;display:inline;overflow:visible;visibility:visible;opacity:1;isolation:auto;mix-blend-mode:normal;color-interpolation:sRGB;color-interpolation-filters:linearRGB;solid-color:#000000;solid-opacity:1;vector-effect:none;fill:#474747;fill-opacity:1;fill-rule:nonzero;stroke:none;stroke-width:0.264583;stroke-linecap:butt;stroke-linejoin:miter;stroke-miterlimit:4;stroke-dasharray:none;stroke-dashoffset:0;stroke-opacity:1;color-rendering:auto;image-rendering:auto;shape-rendering:auto;text-rendering:auto;enable-background:accumulate"
- d="m 45.902791,212.76114 v 3.23047 l 1.003906,1.00195 h 3.228516 v -3.22852 l -1.001953,-1.0039 h -0.05469 z m 0.263672,0.26367 h 2.855469 l 0.849609,0.84961 v 2.85547 h -2.855468 l -0.84961,-0.84961 z"
- id="rect815-3"
- inkscape:connector-curvature="0" />
- <path
- style="color:#000000;font-style:normal;font-variant:normal;font-weight:normal;font-stretch:normal;font-size:medium;line-height:normal;font-family:sans-serif;font-variant-ligatures:normal;font-variant-position:normal;font-variant-caps:normal;font-variant-numeric:normal;font-variant-alternates:normal;font-feature-settings:normal;text-indent:0;text-align:start;text-decoration:none;text-decoration-line:none;text-decoration-style:solid;text-decoration-color:#000000;letter-spacing:normal;word-spacing:normal;text-transform:none;writing-mode:lr-tb;direction:ltr;text-orientation:mixed;dominant-baseline:auto;baseline-shift:baseline;text-anchor:start;white-space:normal;shape-padding:0;clip-rule:nonzero;display:inline;overflow:visible;visibility:visible;opacity:1;isolation:auto;mix-blend-mode:normal;color-interpolation:sRGB;color-interpolation-filters:linearRGB;solid-color:#000000;solid-opacity:1;vector-effect:none;fill:#474747;fill-opacity:1;fill-rule:nonzero;stroke:none;stroke-width:0.264583;stroke-linecap:butt;stroke-linejoin:miter;stroke-miterlimit:4;stroke-dasharray:none;stroke-dashoffset:0;stroke-opacity:1;color-rendering:auto;image-rendering:auto;shape-rendering:auto;text-rendering:auto;enable-background:accumulate"
- d="m 46.344997,207.34832 -0.290893,0.17906 1.133594,1.1102 v 2.91047 h 0.264579 v -3.04271 z"
- id="rect815-6"
- inkscape:connector-curvature="0"
- sodipodi:nodetypes="ccccccc" />
- <path
- style="fill:none;stroke:#474747;stroke-width:0.529167;stroke-linecap:butt;stroke-linejoin:miter;stroke-miterlimit:4;stroke-dasharray:none;stroke-opacity:1"
- d="m 38.473823,212.26371 v -3.175 l -1.058333,-1.05833"
- id="path856-6"
- inkscape:connector-curvature="0"
- sodipodi:nodetypes="ccc" />
- <path
- id="rect815-9"
- style="opacity:1;vector-effect:none;fill:#24242b;fill-opacity:0.95;fill-rule:nonzero;stroke:#3a4051;stroke-width:0.449792;stroke-linecap:butt;stroke-linejoin:miter;stroke-miterlimit:4;stroke-dasharray:none;stroke-dashoffset:0;stroke-opacity:1"
- d="m 26.598004,212.94994 h 3.479608 0.753402 v -1.5875 l -2.870068,-2.64583 h -0.748275 -0.614667 z"
- inkscape:export-xdpi="96.000008"
- inkscape:export-ydpi="96.000008"
- sodipodi:nodetypes="cccccccc" />
- </g>
-</svg>
+++ /dev/null
-<?xml version="1.0" encoding="UTF-8" standalone="no"?>
-<svg
- xmlns:dc="http://purl.org/dc/elements/1.1/"
- xmlns:cc="http://creativecommons.org/ns#"
- xmlns:rdf="http://www.w3.org/1999/02/22-rdf-syntax-ns#"
- xmlns:svg="http://www.w3.org/2000/svg"
- xmlns="http://www.w3.org/2000/svg"
- xmlns:sodipodi="http://sodipodi.sourceforge.net/DTD/sodipodi-0.dtd"
- xmlns:inkscape="http://www.inkscape.org/namespaces/inkscape"
- width="17.700001"
- height="17.700001"
- viewBox="0 0 4.6831256 4.6831253"
- version="1.1"
- id="svg8"
- inkscape:version="1.0.1 (3bc2e813f5, 2020-09-07)"
- sodipodi:docname="item_status_right.svg"
- inkscape:export-filename="C:\ss14\space-station-14\Resources\Textures\Interface\Nano\item_status_right.svg.96dpi.png"
- inkscape:export-xdpi="96"
- inkscape:export-ydpi="96">
- <defs
- id="defs2" />
- <sodipodi:namedview
- id="base"
- pagecolor="#ffffff"
- bordercolor="#666666"
- borderopacity="1.0"
- inkscape:pageopacity="0.0"
- inkscape:pageshadow="2"
- inkscape:zoom="45.254834"
- inkscape:cx="2.2968017"
- inkscape:cy="9.7979333"
- inkscape:document-units="px"
- inkscape:current-layer="layer1"
- showgrid="false"
- inkscape:pagecheckerboard="true"
- units="px"
- showguides="true"
- inkscape:window-width="2560"
- inkscape:window-height="1377"
- inkscape:window-x="1912"
- inkscape:window-y="-8"
- inkscape:window-maximized="1"
- inkscape:guide-bbox="true"
- inkscape:snap-intersection-paths="true"
- inkscape:snap-bbox="true"
- inkscape:snap-page="true"
- inkscape:document-rotation="0"
- fit-margin-top="0"
- fit-margin-left="0"
- fit-margin-right="0"
- fit-margin-bottom="0">
- <inkscape:grid
- type="xygrid"
- id="grid817"
- originx="0.44979165"
- originy="1.5931808" />
- </sodipodi:namedview>
- <metadata
- id="metadata5">
- <rdf:RDF>
- <cc:Work
- rdf:about="">
- <dc:format>image/svg+xml</dc:format>
- <dc:type
- rdf:resource="http://purl.org/dc/dcmitype/StillImage" />
- <dc:title />
- </cc:Work>
- </rdf:RDF>
- </metadata>
- <g
- inkscape:label="Layer 1"
- inkscape:groupmode="layer"
- id="layer1"
- transform="translate(-26.372785,-208.49171)">
- <path
- style="color:#000000;font-style:normal;font-variant:normal;font-weight:normal;font-stretch:normal;font-size:medium;line-height:normal;font-family:sans-serif;font-variant-ligatures:normal;font-variant-position:normal;font-variant-caps:normal;font-variant-numeric:normal;font-variant-alternates:normal;font-feature-settings:normal;text-indent:0;text-align:start;text-decoration:none;text-decoration-line:none;text-decoration-style:solid;text-decoration-color:#000000;letter-spacing:normal;word-spacing:normal;text-transform:none;writing-mode:lr-tb;direction:ltr;text-orientation:mixed;dominant-baseline:auto;baseline-shift:baseline;text-anchor:start;white-space:normal;shape-padding:0;clip-rule:nonzero;display:inline;overflow:visible;visibility:visible;opacity:1;isolation:auto;mix-blend-mode:normal;color-interpolation:sRGB;color-interpolation-filters:linearRGB;solid-color:#000000;solid-opacity:1;vector-effect:none;fill:#474747;fill-opacity:1;fill-rule:nonzero;stroke:none;stroke-width:0.264583;stroke-linecap:butt;stroke-linejoin:miter;stroke-miterlimit:4;stroke-dasharray:none;stroke-dashoffset:0;stroke-opacity:1;color-rendering:auto;image-rendering:auto;shape-rendering:auto;text-rendering:auto;enable-background:accumulate"
- d="m 45.902791,212.76114 v 3.23047 l 1.003906,1.00195 h 3.228516 v -3.22852 l -1.001953,-1.0039 h -0.05469 z m 0.263672,0.26367 h 2.855469 l 0.849609,0.84961 v 2.85547 h -2.855468 l -0.84961,-0.84961 z"
- id="rect815-3"
- inkscape:connector-curvature="0" />
- <path
- style="color:#000000;font-style:normal;font-variant:normal;font-weight:normal;font-stretch:normal;font-size:medium;line-height:normal;font-family:sans-serif;font-variant-ligatures:normal;font-variant-position:normal;font-variant-caps:normal;font-variant-numeric:normal;font-variant-alternates:normal;font-feature-settings:normal;text-indent:0;text-align:start;text-decoration:none;text-decoration-line:none;text-decoration-style:solid;text-decoration-color:#000000;letter-spacing:normal;word-spacing:normal;text-transform:none;writing-mode:lr-tb;direction:ltr;text-orientation:mixed;dominant-baseline:auto;baseline-shift:baseline;text-anchor:start;white-space:normal;shape-padding:0;clip-rule:nonzero;display:inline;overflow:visible;visibility:visible;opacity:1;isolation:auto;mix-blend-mode:normal;color-interpolation:sRGB;color-interpolation-filters:linearRGB;solid-color:#000000;solid-opacity:1;vector-effect:none;fill:#474747;fill-opacity:1;fill-rule:nonzero;stroke:none;stroke-width:0.264583;stroke-linecap:butt;stroke-linejoin:miter;stroke-miterlimit:4;stroke-dasharray:none;stroke-dashoffset:0;stroke-opacity:1;color-rendering:auto;image-rendering:auto;shape-rendering:auto;text-rendering:auto;enable-background:accumulate"
- d="m 46.344997,207.34832 -0.290893,0.17906 1.133594,1.1102 v 2.91047 h 0.264579 v -3.04271 z"
- id="rect815-6"
- inkscape:connector-curvature="0"
- sodipodi:nodetypes="ccccccc" />
- <path
- style="fill:none;stroke:#474747;stroke-width:0.529167;stroke-linecap:butt;stroke-linejoin:miter;stroke-miterlimit:4;stroke-dasharray:none;stroke-opacity:1"
- d="m 38.473823,212.26371 v -3.175 l -1.058333,-1.05833"
- id="path856-6"
- inkscape:connector-curvature="0"
- sodipodi:nodetypes="ccc" />
- <path
- id="rect815-9"
- style="opacity:1;vector-effect:none;fill:#24242b;fill-opacity:0.95;fill-rule:nonzero;stroke:#3a4051;stroke-width:0.449792;stroke-linecap:butt;stroke-linejoin:miter;stroke-miterlimit:4;stroke-dasharray:none;stroke-dashoffset:0;stroke-opacity:1"
- d="m 31.05591,212.94994 h -3.704167 -0.753402 v -1.5875 l 2.870068,-2.64583 h 0.748275 0.839226"
- inkscape:export-xdpi="96.000008"
- inkscape:export-ydpi="96.000008"
- sodipodi:nodetypes="ccccccc" />
- </g>
-</svg>