Exosuit: Ripley (#12668)

* mechs

* interaction relay

* atmos handling

* fuck around with interaction events

SPAGHETTI CODE OH MY GOD

* more sprites and whatever the hell

* more mech shit

* more shit for equipment

* starting equipment (for nukie mechs and such)

* equipment cycling

* starting with some of the ui

* a fat chunk of ui prototyping

* done tinkering with ui

* a bunch of ui stuff and what have yous

* cleaning up grabber and state handling

* make the ui actually functional + watch me port a million icons

I swear i'll prune the sprites later blease

* start on construction

* construction yo mamma

* remove some unused files

* fix a silly

* make the graph sane

* make it actually constructible.

* print the boards as well, bozo

* rebalance part prices

* eject action

also i appease the russians by remembering to localize

* Punch Shit

* make mech integrity and repairs work

* Make the UI more based

STOMP STOMP STOMP STOMP

* make equipment even more based

* batteries and other such delights

* make the ui look pimpin af

* make the construction mega based

* UI but so epic

* equipment

* some sweat tweaks

* damage rebalancing

* restructure tech

* fix some shit

* mechs inherit access

* make icons actually use sprite specifiers

* TRAILING COMMAA!!!!!

* fix a mild indentation sin

* undo this change because it isn't needed

* actually fix this

* secret webeditting shhhh

* place this tech here

* comments

* foo
This commit is contained in:
Nemanja
2022-12-10 12:05:39 -05:00
committed by GitHub
parent 11d81aa155
commit 913e1ee676
218 changed files with 3956 additions and 34 deletions

View File

@@ -0,0 +1,24 @@
using Content.Shared.Mech;
using Robust.Client.GameObjects;
namespace Content.Client.Mech;
/// <summary>
/// Handles the sprite state changes while
/// constructing mech assemblies.
/// </summary>
public sealed class MechAssemblyVisualizerSystem : VisualizerSystem<MechAssemblyVisualsComponent>
{
protected override void OnAppearanceChange(EntityUid uid, MechAssemblyVisualsComponent component,
ref AppearanceChangeEvent args)
{
base.OnAppearanceChange(uid, component, ref args);
if (!args.Component.TryGetData(MechAssemblyVisuals.State, out int stage))
return;
var state = component.StatePrefix + stage;
args.Sprite?.LayerSetState(0, state);
}
}

View File

@@ -0,0 +1,15 @@
namespace Content.Client.Mech;
/// <summary>
/// This is used for visualizing mech constructions
/// </summary>
[RegisterComponent]
public sealed class MechAssemblyVisualsComponent : Component
{
/// <summary>
/// The prefix that is followed by the number which
/// denotes the current state to use.
/// </summary>
[DataField("statePrefix", required: true)]
public string StatePrefix = string.Empty;
}

View File

@@ -0,0 +1,12 @@
using Content.Shared.Mech.Components;
using Robust.Shared.GameStates;
namespace Content.Client.Mech;
/// <inheritdoc/>
[RegisterComponent, NetworkedComponent]
[ComponentReference(typeof(SharedMechComponent))]
public sealed class MechComponent : SharedMechComponent
{
}

View File

@@ -0,0 +1,43 @@
using Content.Shared.Mech;
using Content.Shared.Mech.EntitySystems;
using Robust.Client.GameObjects;
using DrawDepth = Content.Shared.DrawDepth.DrawDepth;
namespace Content.Client.Mech;
/// <inheritdoc/>
public sealed class MechSystem : SharedMechSystem
{
/// <inheritdoc/>
public override void Initialize()
{
base.Initialize();
SubscribeLocalEvent<MechComponent, AppearanceChangeEvent>(OnAppearanceChanged);
}
private void OnAppearanceChanged(EntityUid uid, MechComponent component, ref AppearanceChangeEvent args)
{
if (args.Sprite == null)
return;
if (!args.Sprite.TryGetLayer((int) MechVisualLayers.Base, out var layer))
return;
var state = component.BaseState;
var drawDepth = DrawDepth.Mobs;
if (component.BrokenState != null && args.Component.TryGetData(MechVisuals.Broken, out bool broken) && broken)
{
state = component.BrokenState;
drawDepth = DrawDepth.SmallMobs;
}
else if (component.OpenState != null && args.Component.TryGetData(MechVisuals.Open, out bool open) && open)
{
state = component.OpenState;
drawDepth = DrawDepth.SmallMobs;
}
layer.SetState(state);
args.Sprite.DrawDepth = (int) drawDepth;
}
}

View File

@@ -0,0 +1,36 @@
using Content.Client.UserInterface.Fragments;
using Content.Shared.Mech;
using Robust.Client.GameObjects;
using Robust.Client.UserInterface;
namespace Content.Client.Mech.Ui.Equipment;
public sealed class MechGrabberUi : UIFragment
{
private MechGrabberUiFragment? _fragment;
public override Control GetUIFragmentRoot()
{
return _fragment!;
}
public override void Setup(BoundUserInterface userInterface, EntityUid? fragmentOwner)
{
if (fragmentOwner == null)
return;
_fragment = new MechGrabberUiFragment();
_fragment.OnEjectAction += e =>
{
userInterface.SendMessage(new MechGrabberEjectMessage(fragmentOwner.Value, e));
};
}
public override void UpdateState(BoundUserInterfaceState state)
{
if (state is not MechGrabberUiState grabberState)
return;
_fragment?.UpdateContents(grabberState);
}
}

View File

@@ -0,0 +1,15 @@
<equipment:MechGrabberUiFragment
xmlns:equipment="clr-namespace:Content.Client.Mech.Ui.Equipment"
xmlns="https://spacestation14.io" Margin="1 0 2 0" HorizontalExpand="True" VerticalExpand="True">
<BoxContainer Orientation="Vertical"
HorizontalExpand="True"
VerticalExpand="True">
<ItemList Name="ItemList"
VerticalExpand="True"
MinHeight="120"
HorizontalExpand="True"
SelectMode="Button">
</ItemList>
<Label Name="SpaceLabel" HorizontalAlignment="Right" StyleClasses="LabelSubText"></Label>
</BoxContainer>
</equipment:MechGrabberUiFragment>

View File

@@ -0,0 +1,35 @@
using Content.Shared.Mech;
using Robust.Client.AutoGenerated;
using Robust.Client.UserInterface.Controls;
using Robust.Client.UserInterface.XAML;
namespace Content.Client.Mech.Ui.Equipment;
[GenerateTypedNameReferences]
public sealed partial class MechGrabberUiFragment : BoxContainer
{
[Dependency] private readonly IEntityManager _entity = default!;
public event Action<EntityUid>? OnEjectAction;
public MechGrabberUiFragment()
{
RobustXamlLoader.Load(this);
IoCManager.InjectDependencies(this);
}
public void UpdateContents(MechGrabberUiState state)
{
SpaceLabel.Text = $"{state.Contents.Count}/{state.MaxContents}";
for (var i = 0; i < state.Contents.Count; i++)
{
var ent = state.Contents[i];
if (!_entity.TryGetComponent<MetaDataComponent>(ent, out var meta))
continue;
ItemList.AddItem(meta.EntityName);
ItemList[i].OnSelected += _ => OnEjectAction?.Invoke(ent);
}
}
}

View File

@@ -0,0 +1,84 @@
using Content.Client.UserInterface.Fragments;
using Content.Shared.Mech;
using JetBrains.Annotations;
using Robust.Client.GameObjects;
namespace Content.Client.Mech.Ui;
[UsedImplicitly]
public sealed class MechBoundUserInterface : BoundUserInterface
{
[Dependency] private readonly IEntityManager _ent = default!;
private readonly EntityUid _mech;
private MechMenu? _menu;
public MechBoundUserInterface(ClientUserInterfaceComponent owner, Enum uiKey) : base(owner, uiKey)
{
IoCManager.InjectDependencies(this);
_mech = owner.Owner;
}
protected override void Open()
{
base.Open();
_menu = new(_mech);
_menu.OnClose += Close;
_menu.OpenCenteredLeft();
_menu.OnRemoveButtonPressed += uid =>
{
SendMessage(new MechEquipmentRemoveMessage(uid));
};
}
protected override void UpdateState(BoundUserInterfaceState state)
{
base.UpdateState(state);
if (state is not MechBoundUiState msg)
return;
UpdateEquipmentControls(msg);
_menu?.UpdateMechStats();
_menu?.UpdateEquipmentView();
}
public void UpdateEquipmentControls(MechBoundUiState state)
{
if (!_ent.TryGetComponent<MechComponent>(_mech, out var mechComp))
return;
foreach (var ent in mechComp.EquipmentContainer.ContainedEntities)
{
var ui = GetEquipmentUi(ent);
if (ui == null)
continue;
foreach (var (attached, estate) in state.EquipmentStates)
{
if (ent == attached)
ui.UpdateState(estate);
}
}
}
protected override void Dispose(bool disposing)
{
base.Dispose(disposing);
if (!disposing)
return;
_menu?.Close();
}
public UIFragment? GetEquipmentUi(EntityUid? uid)
{
var component = _ent.GetComponentOrNull<UIFragmentComponent>(uid);
component?.Ui?.Setup(this, uid);
return component?.Ui;
}
}

View File

@@ -0,0 +1,26 @@
<Control xmlns="https://spacestation14.io"
xmlns:customControls="clr-namespace:Content.Client.Administration.UI.CustomControls">
<Button Disabled="True"
Margin="0 0 0 0"
HorizontalExpand="True"
VerticalExpand="True"
StyleClasses="ButtonSquare">
<BoxContainer Orientation="Vertical" HorizontalExpand="True" VerticalExpand="True" VerticalAlignment="Top">
<BoxContainer HorizontalExpand="True" VerticalExpand="True" Orientation="Horizontal">
<SpriteView
Name="EquipmentView"
OverrideDirection="South"
MinSize="32 32"
SetSize="32 32"
Scale="1 1"
RectClipContent="True"/>
<RichTextLabel Name="EquipmentName" VerticalAlignment="Center"/>
<BoxContainer Orientation="Vertical" HorizontalExpand="True" HorizontalAlignment="Right" VerticalAlignment="Center">
<TextureButton Name="RemoveButton" Scale="0.5 0.5"></TextureButton>
</BoxContainer>
</BoxContainer>
<customControls:HSeparator Name="Separator" StyleClasses="LowDivider" Visible="False"/>
<BoxContainer Name="CustomControlContainer" Margin="0 10 0 0" HorizontalExpand="True" VerticalExpand="True"></BoxContainer>
</BoxContainer>
</Button>
</Control>

View File

@@ -0,0 +1,28 @@
using Robust.Client.AutoGenerated;
using Robust.Client.GameObjects;
using Robust.Client.UserInterface;
using Robust.Client.UserInterface.XAML;
namespace Content.Client.Mech.Ui;
[GenerateTypedNameReferences]
public sealed partial class MechEquipmentControl : Control
{
public event Action? OnRemoveButtonPressed;
public MechEquipmentControl(string itemName, SpriteComponent? sprite, Control? fragment)
{
RobustXamlLoader.Load(this);
EquipmentName.SetMessage(itemName);
EquipmentView.Sprite = sprite;
RemoveButton.TexturePath = "/Textures/Interface/Nano/cross.svg.png";
if (fragment != null)
{
Separator.Visible = true;
CustomControlContainer.AddChild(fragment);
}
RemoveButton.OnPressed += _ => OnRemoveButtonPressed?.Invoke();
}
}

View File

@@ -0,0 +1,71 @@
<controls:FancyWindow xmlns="https://spacestation14.io"
xmlns:gfx="clr-namespace:Robust.Client.Graphics;assembly=Robust.Client"
xmlns:controls="clr-namespace:Content.Client.UserInterface.Controls"
Title="{Loc 'mech-menu-title'}"
MinSize="350 440"
SetSize="350 440">
<BoxContainer Orientation="Vertical" HorizontalExpand="True" VerticalExpand="True">
<BoxContainer Margin="10 10 10 10" Orientation="Horizontal" HorizontalExpand="True">
<BoxContainer Orientation="Vertical" HorizontalExpand="True">
<BoxContainer Orientation="Horizontal" HorizontalExpand="True">
<ProgressBar Name="IntegrityDisplayBar"
HorizontalExpand="True"
SetHeight="25"
MaxValue="1"
Value="0">
<Label Name="IntegrityDisplay"
HorizontalAlignment="Left"
Margin="5 0 0 0"
VerticalAlignment="Center" />
</ProgressBar>
</BoxContainer>
<BoxContainer Orientation="Horizontal" HorizontalExpand="True" Margin="0 5 0 0">
<ProgressBar Name="EnergyDisplayBar"
HorizontalExpand="True"
SetHeight="25"
MaxValue="1"
Value="0">
<Label Name="EnergyDisplay"
Margin="5 0 0 0"
HorizontalAlignment="Left"
VerticalAlignment="Center"></Label>
</ProgressBar>
</BoxContainer>
<Label Name="SlotDisplay"
HorizontalAlignment="Left"
Access="Public"
HorizontalExpand="True" />
</BoxContainer>
<SpriteView Name="MechView"
Margin="10 0 0 0"
VerticalAlignment="Center"
HorizontalAlignment="Right"
OverrideDirection="South"
SetSize="64 64"
MaxSize="64 64"
Scale="2 2">
</SpriteView>
</BoxContainer>
<BoxContainer VerticalExpand="True" Margin="10 0 10 10" Orientation="Vertical">
<PanelContainer VerticalExpand="True" MinSize="0 200">
<PanelContainer.PanelOverride>
<gfx:StyleBoxFlat BackgroundColor="#1B1B1E" />
</PanelContainer.PanelOverride>
<ScrollContainer
HScrollEnabled="False"
HorizontalExpand="True"
MinSize="100 256"
SizeFlagsStretchRatio="2"
VerticalExpand="True">
<BoxContainer
Name="EquipmentControlContainer"
MinSize="100 256"
Orientation="Vertical"
SizeFlagsStretchRatio="2"
VerticalExpand="True">
</BoxContainer>
</ScrollContainer>
</PanelContainer>
</BoxContainer>
</BoxContainer>
</controls:FancyWindow>

View File

@@ -0,0 +1,72 @@
using Content.Client.UserInterface.Controls;
using Content.Client.UserInterface.Fragments;
using Content.Shared.Mech.Components;
using Robust.Client.AutoGenerated;
using Robust.Client.GameObjects;
using Robust.Client.UserInterface.XAML;
namespace Content.Client.Mech.Ui;
[GenerateTypedNameReferences]
public sealed partial class MechMenu : FancyWindow
{
[Dependency] private readonly IEntityManager _ent = default!;
private readonly EntityUid _mech;
public event Action<EntityUid>? OnRemoveButtonPressed;
public MechMenu(EntityUid mech)
{
RobustXamlLoader.Load(this);
IoCManager.InjectDependencies(this);
_mech = mech;
if (!_ent.TryGetComponent<SpriteComponent>(mech, out var sprite))
return;
MechView.Sprite = sprite;
}
public void UpdateMechStats()
{
if (!_ent.TryGetComponent<SharedMechComponent>(_mech, out var mechComp))
return;
var integrityPercent = mechComp.Integrity / mechComp.MaxIntegrity;
IntegrityDisplayBar.Value = integrityPercent.Float();
IntegrityDisplay.Text = Loc.GetString("mech-integrity-display", ("amount", (integrityPercent*100).Int()));
var energyPercent = mechComp.Energy / mechComp.MaxEnergy;
EnergyDisplayBar.Value = energyPercent.Float();
EnergyDisplay.Text = Loc.GetString("mech-energy-display", ("amount", (energyPercent*100).Int()));
SlotDisplay.Text = Loc.GetString("mech-slot-display",
("amount", mechComp.MaxEquipmentAmount - mechComp.EquipmentContainer.ContainedEntities.Count));
}
public void UpdateEquipmentView()
{
if (!_ent.TryGetComponent<MechComponent>(_mech, out var mechComp))
return;
EquipmentControlContainer.Children.Clear();
foreach (var ent in mechComp.EquipmentContainer.ContainedEntities)
{
if (!_ent.TryGetComponent<SpriteComponent>(ent, out var sprite) ||
!_ent.TryGetComponent<MetaDataComponent>(ent, out var metaData))
continue;
var uicomp = _ent.GetComponentOrNull<UIFragmentComponent>(ent);
var ui = uicomp?.Ui?.GetUIFragmentRoot();
var control = new MechEquipmentControl(metaData.EntityName, sprite, ui);
control.OnRemoveButtonPressed += () => OnRemoveButtonPressed?.Invoke(ent);
EquipmentControlContainer.AddChild(control);
}
}
}