Skip to content
Draft
Show file tree
Hide file tree
Changes from all commits
Commits
Show all changes
26 commits
Select commit Hold shift + click to select a range
f94a6ef
Selectable Containers
Dirius77 Mar 19, 2026
a1dcf85
Specify the ordering.
Dirius77 Mar 20, 2026
cc3f0e9
Feedback and adjustments
Dirius77 Mar 23, 2026
83cbf3b
Forgot to remove this when refactoring, woops.
Dirius77 Mar 25, 2026
ddd09e0
This should be a BUIMessage
Dirius77 Mar 28, 2026
6703908
Toggleable clothing changes from upstream
Dirius77 Mar 23, 2026
a932c5c
Start on sealing
Dirius77 Mar 25, 2026
fc01628
We start doafters
Dirius77 Mar 28, 2026
f832949
Sealing and unsealing functionality
Dirius77 Mar 30, 2026
649f547
Uh, UI I forgor
Dirius77 Apr 1, 2026
a83d74c
UI and prediction whew
Dirius77 Apr 3, 2026
a7da936
Storage modules real
Dirius77 Apr 4, 2026
26c8ecb
so many things tbqh oops
Dirius77 Apr 15, 2026
f389acb
Surely this will get merged upstream.
Dirius77 Apr 15, 2026
bca768e
Lots of modules and netsyncing and UI work
Dirius77 Apr 18, 2026
88e048b
Ui and actions
Dirius77 Apr 19, 2026
575f496
Medicalops
Dirius77 Apr 22, 2026
8bd76de
Those t-ray things I pushed upstream
Dirius77 Apr 22, 2026
a0705f8
Armor and emp and tray stuff
Dirius77 Apr 30, 2026
6ce1553
Toggleable fixes from upmerge.
Dirius77 May 25, 2026
7d60f3d
T-ray needs to check all slots
Dirius77 Jun 10, 2026
c7e4e9d
Dependency queries and removing readonly
Dirius77 Jul 4, 2026
1bd207c
My chud children, and a null pointer
Dirius77 Jul 6, 2026
9e5a0b1
Coloring the chud children
Dirius77 Jul 9, 2026
623a897
Merge branch 'master' into modsuits
Dirius77 Jul 9, 2026
7e9e201
Remove leftover textures.
Dirius77 Jul 10, 2026
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
The table of contents is too big for display.
Diff view
Diff view
  •  
  •  
  •  
2 changes: 1 addition & 1 deletion Content.Client/Clothing/ClientClothingSystem.cs
Original file line number Diff line number Diff line change
Expand Up @@ -186,7 +186,7 @@ private void OnVisualsChanged(EntityUid uid, InventoryComponent component, Visua

if (!TryComp(item, out ClothingComponent? clothing) || clothing.InSlot == null)
return;

RenderEquipment(uid, item, clothing.InSlot, component, null, clothing);
}

Expand Down
18 changes: 12 additions & 6 deletions Content.Client/SubFloor/TrayScannerSystem.cs
Original file line number Diff line number Diff line change
Expand Up @@ -7,6 +7,8 @@
using Content.Shared.Disposal.Tube;
using Content.Shared.Input;
using Content.Shared.Inventory;
using Content.Shared.Item.ItemToggle;
using Content.Shared.Item.ItemToggle.Components;
using Content.Shared.SubFloor;
using Robust.Client.Animations;
using Robust.Client.GameObjects;
Expand All @@ -25,6 +27,7 @@ public sealed partial class TrayScannerSystem : SharedTrayScannerSystem
[Dependency] private AnimationPlayerSystem _animation = default!;
[Dependency] private EntityLookupSystem _lookup = default!;
[Dependency] private InventorySystem _inventory = default!;
[Dependency] private ItemToggleSystem _itemToggle = default!;
[Dependency] private SharedAppearanceSystem _appearance = default!;
[Dependency] private SharedTransformSystem _transform = default!;
[Dependency] private SpriteSystem _sprite = default!;
Expand Down Expand Up @@ -67,9 +70,9 @@ public override void Update(float frameTime)
// API is extremely skrungly. If this ever shows up on dottrace ping me and laugh.
var canSee = false;

foreach (var item in _inventory.GetHandOrInventoryEntities(player.Value, SlotFlags.POCKET))
foreach (var item in _inventory.GetHandOrInventoryEntities(player.Value)) // DEN: TRay in any slot (For modsuits visors)
{
if (!_trayScannerQuery.TryGetComponent(item, out var scanner) || !scanner.Enabled)
if (!_trayScannerQuery.TryGetComponent(item, out var scanner) || !_itemToggle.IsActivated(item))
continue;

range = MathF.Max(scanner.Range, range);
Expand Down Expand Up @@ -194,26 +197,29 @@ private bool MatchesMode(EntityUid uid, TrayScannerMode mode)
private Control OnCollectItemStatus(Entity<TrayScannerComponent> entity)
{
_inputManager.TryGetKeyBinding((ContentKeyFunctions.AltUseItemInHand), out var binding);
return new StatusControl(entity, binding?.GetKeyString() ?? "");
TryComp<ItemToggleComponent>(entity, out var toggle);
return new StatusControl(entity, toggle, binding?.GetKeyString() ?? "");
}

private sealed class StatusControl : PollingItemStatusControl<StatusControl.TRayData>
{
private readonly RichTextLabel _label;
private readonly TrayScannerComponent _scanner;
private readonly ItemToggleComponent? _toggle;
private readonly string _keyBindingName;

public StatusControl(TrayScannerComponent scanner, string keyBindingName)
public StatusControl(TrayScannerComponent scanner, ItemToggleComponent? toggle, string keyBindingName)
{
_scanner = scanner;
_keyBindingName = keyBindingName;
_toggle = toggle;
_label = new RichTextLabel { StyleClasses = { StyleClass.ItemStatus } };
AddChild(_label);
}

protected override TRayData PollData()
{
return new TRayData(_scanner.Enabled, _scanner.Mode);
return new TRayData(_scanner.Mode, _toggle == null || _toggle.Activated);
}

protected override void Update(in TRayData data)
Expand All @@ -237,7 +243,7 @@ protected override void Update(in TRayData data)
("keybinding", _keyBindingName)));
}

public readonly record struct TRayData(bool Enabled, TrayScannerMode Mode);
public readonly record struct TRayData(TrayScannerMode Mode, bool Enabled);
}
#endregion
}
Original file line number Diff line number Diff line change
@@ -0,0 +1,21 @@
using Content.Client._DEN.Clothing.Modsuits.UI;
using Content.Client.Items;
using Content.Shared._DEN.Clothing.Modsuits.Components;
using Content.Shared._DEN.Clothing.Modsuits.EntitySystems;

namespace Content.Client._DEN.Clothing.Modsuits.EntitySystems;

public sealed partial class ModsuitSystem : SharedModsuitSystem
{
[Dependency] private SharedUserInterfaceSystem _uiSystem = default!;

protected override void UpdateUI(Entity<ModsuitControllerComponent> entity)
{
base.UpdateUI(entity);

if (_uiSystem.TryGetOpenUi<ModsuitControllerBoundUserInterface>(entity.Owner, ModsuitControllerUiKey.Key, out var bui))
{
bui.Update();
}
}
}
Original file line number Diff line number Diff line change
@@ -0,0 +1,37 @@
<controls:FancyWindow xmlns="https://spacestation14.io"
xmlns:controls="clr-namespace:Content.Client.UserInterface.Controls"
MinSize="340 167"
Resizable="false"
Title="{Loc 'modsuit-controller-ui-title'}">
<BoxContainer Orientation="Horizontal">
<BoxContainer Orientation="Vertical" HorizontalExpand="True">
<BoxContainer Orientation="Horizontal" Margin="0 5 0 5">
<SpriteView OverrideDirection="South" Scale="2 2" Name="SpriteView" SetSize="64 64" />
<BoxContainer Margin="5 0 0 0" Orientation="Vertical" VerticalAlignment="Top">
<RichTextLabel Name="ControlName"/>
<Label Name="NoCellLabel" Text="{Loc 'modsuit-controller-ui-no-cell'}" Visible="False" StyleClasses="LabelSubText"/>
<ProgressBar Name="ChargeBar"
MinValue="0"
MaxValue="1"
SetHeight="25"
Page="0"
Margin="0 5 0 0"
Value="0.5">
<Label Name="ChargePercentage" Margin="4 0" Text="0 %" />
</ProgressBar>
</BoxContainer>
<RichTextLabel Margin="30 0 10 0" HorizontalExpand="True" HorizontalAlignment="Right" VerticalExpand="True"
VerticalAlignment="Center" Name="UIErrorLabel"
Text="{Loc 'modsuit-controller-ui-malfunction'}"
Visible="False"/>
</BoxContainer>
<PanelContainer StyleClasses="LowDivider" />
<Control MinSize="240 120" VerticalExpand="True" Margin="5 5 5 5">
<PanelContainer Margin="100 0 0 0" StyleClasses="BackgroundPanelDark">
</PanelContainer>
<GridContainer Margin="10 10 10 10" Columns="2" Name="ToggleGrid">
</GridContainer>
</Control>
</BoxContainer>
</BoxContainer>
</controls:FancyWindow>
Original file line number Diff line number Diff line change
@@ -0,0 +1,173 @@
using System.Numerics;
using Content.Client.Power.EntitySystems;
using Content.Client.UserInterface.Controls;
using Content.Shared._DEN.Clothing.Modsuits.Components;
using Content.Shared._DEN.Modules.Components;
using Content.Shared.IdentityManagement;
using Content.Shared.Item.ItemToggle.Components;
using Content.Shared.PowerCell;
using Robust.Client.AutoGenerated;
using Robust.Client.Graphics;
using Robust.Client.UserInterface.XAML;
using Robust.Shared.Prototypes;
using Robust.Shared.Timing;
using Robust.Shared.Utility;

namespace Content.Client._DEN.Clothing.Modsuits.UI.Controls;

[GenerateTypedNameReferences]
public sealed partial class ModsuitControllerWindow : FancyWindow
{
[Dependency] private IEntityManager _entity = default!;

private Entity<ModsuitControllerComponent, ModuleStorageComponent>? _modControlEntity;

private Dictionary<EntityUid, (SwitchButton, ModuleInfoControl)> _gridControls = new();

public Action<EntityUid, bool>? OnModuleToggled;

public ModsuitControllerWindow()
{
IoCManager.InjectDependencies(this);
RobustXamlLoader.Load(this);
}

public void Initialize(Entity<ModsuitControllerComponent, ModuleStorageComponent> entity)
{
_modControlEntity = entity;
SpriteView.SetEntity(_modControlEntity.Value);
var name = new FormattedMessage();
name.PushColor(Color.White);
name.AddText(Identity.Name(_modControlEntity.Value, _entity));
ControlName.SetMessage(name);
Update();
}

public void Update()
{
if (_modControlEntity == null)
return;

var seen = new Dictionary<EntityUid, bool>();
foreach (var entUid in _gridControls.Keys)
{
seen[entUid] = false;
}

foreach (var module in _modControlEntity.Value.Comp2.ModuleSlots.Values)
{
if (module is null)
continue;

if (_entity.TryGetComponent<ItemToggleComponent>(module, out var toggleComp))
{
if (_gridControls.TryGetValue(module.Value, out var controls))
{
controls.Item1.Pressed = toggleComp.Activated;
seen[module.Value] = true;
}
else
{
var button = new SwitchButton
{
ToggleMode = true,
Pressed = toggleComp.Activated,
MinWidth = 100.0f
};
button.OnToggled += e => OnModuleToggled?.Invoke(module.Value, e.Pressed);
var moduleInfo = new ModuleInfoControl(module.Value, _entity);
ToggleGrid.AddChild(button);
ToggleGrid.AddChild(moduleInfo);
_gridControls.Add(module.Value, (button, moduleInfo));
}
}
}

foreach (var entUpdated in seen)
{
if (entUpdated.Value)
continue;

var controls = _gridControls[entUpdated.Key];
ToggleGrid.RemoveChild(controls.Item1);
ToggleGrid.RemoveChild(controls.Item2);
_gridControls.Remove(entUpdated.Key);
}

var uiFunctional = _modControlEntity.Value.Comp1.UIFunctional;
foreach (var controls in _gridControls.Values)
{
controls.Item1.Disabled = !uiFunctional;
controls.Item2.SetScrambled(!uiFunctional);
}
UIErrorLabel.Visible = !uiFunctional;
}

protected override void FrameUpdate(FrameEventArgs args)
{
base.FrameUpdate(args);

if (_modControlEntity == null)
return;

var powerSystem = _entity.System<PowerCellSystem>();
var batterySystem = _entity.System<BatterySystem>();

if (!powerSystem.TryGetBatteryFromSlotOrEntity(_modControlEntity.Value.Owner, out var battery))
{
NoCellLabel.Visible = true;
ChargeBar.Visible = false;
return;
}

NoCellLabel.Visible = false;
ChargeBar.Visible = true;

// These are just all from APC Menu. It'd be neat if they were pulled out into a separate control.
// But I'm done making changes to upstream systems.
var charge = batterySystem.GetChargeLevel(battery.Value.AsNullable());
ChargeBar.Value = charge;
ChargePercentage.Text = Loc.GetString("apc-menu-charge-label", ("percent", charge.ToString("P0")));
UpdateChargeBarColor(charge);
}

private void UpdateChargeBarColor(float charge)
{
if (ChargeBar == null)
{
return;
}

var normalizedCharge = charge / ChargeBar.MaxValue;

const float leftHue = 0.0f; // Red
const float middleHue = 0.066f; // Orange
const float rightHue = 0.33f; // Green
const float saturation = 1.0f; // Uniform saturation
const float value = 0.8f; // Uniform value / brightness
const float alpha = 1.0f; // Uniform alpha

// These should add up to 1.0 or your transition won't be smooth
const float leftSideSize = 0.5f; // Fraction of ChargeBar lerped from leftHue to middleHue
const float rightSideSize = 0.5f; // Fraction of ChargeBar lerped from middleHue to rightHue

float finalHue;
if (normalizedCharge <= leftSideSize)
{
normalizedCharge /= leftSideSize; // Adjust range to 0.0 to 1.0
finalHue = MathHelper.Lerp(leftHue, middleHue, normalizedCharge);
}
else
{
normalizedCharge = (normalizedCharge - leftSideSize) / rightSideSize; // Adjust range to 0.0 to 1.0.
finalHue = MathHelper.Lerp(middleHue, rightHue, normalizedCharge);
}

// Check if null first to avoid repeatedly creating this.
ChargeBar.ForegroundStyleBoxOverride ??= new StyleBoxFlat();

var foregroundStyleBoxOverride = (StyleBoxFlat) ChargeBar.ForegroundStyleBoxOverride;
foregroundStyleBoxOverride.BackgroundColor =
Color.FromHsv(new Vector4(finalHue, saturation, value, alpha));
}
}
Original file line number Diff line number Diff line change
@@ -0,0 +1,10 @@
<BoxContainer
xmlns="https://spacestation14.io"
HorizontalExpand="True"
Orientation="Horizontal">
<Control Margin="0 0 5 0">
<SpriteView Name="SpriteView" SetSize="32 32" Visible="True"/>
<AnimatedTextureRect Name="BrokenIcon" SetSize="32 32" Visible="False"/>
</Control>
<Label Name="ModuleName" HorizontalExpand="True"/>
</BoxContainer>
Loading
Loading