Moving PDA to ECS (#4538)

* Moved pen slot to separate component

* Moved it all to more generic item slot class

* Add sounds

* Item slots now supports many slots

* Some clean-up

* Refactored slots a bit

* Moving ID card out

* Moving pda to system

* Moving PDA owner to ECS

* Moved PDA flashlight to separate component

* Toggle lights work through events

* Fixing UI

* Moving uplink to separate component

* Continue moving uplink to separate component

* More cleaning

* Removing pda shared

* Nuked shared pda component

* Fixed flashlight

* Pen slot now showed in UI

* Light toggle now shows correctly in UI

* Small refactoring of item slots

* Added contained entity

* Fixed tests

* Finished with PDA

* Moving PDA uplink to separate window

* Adding-removing uplink should show new button

* Working on a better debug

* Debug command to add uplink

* Uplink send state to UI

* Almost working UI

* Uplink correcty updates when you buy-sell items

* Ups

* Moved localization to separate file

* Minor fixes

* Removed item slots methods events

* Removed PDA owner name

* Removed one uplink event

* Deleted all uplink events

* Removed flashlight events

* Update Content.Shared/Traitor/Uplink/UplinkVisuals.cs

Co-authored-by: metalgearsloth <31366439+metalgearsloth@users.noreply.github.com>

* Update Content.Server/Containers/ItemSlot/ItemSlotsSystem.cs

Co-authored-by: metalgearsloth <31366439+metalgearsloth@users.noreply.github.com>

* Update Content.Server/Containers/ItemSlot/ItemSlotsSystem.cs

Co-authored-by: metalgearsloth <31366439+metalgearsloth@users.noreply.github.com>

* Update Content.Server/GameTicking/Presets/PresetTraitorDeathMatch.cs

Co-authored-by: metalgearsloth <31366439+metalgearsloth@users.noreply.github.com>

* Item slots system review

* Flashlight review

* PDA to XAML

* Move UplinkMenu to seperate class, fix WeightedColors methods

* Move UI to XAML

* Moved events to entity id

* Address review

* Removed uplink extensions

* Minor fix

* Moved item slots to shared

* My bad Robust...

* Fixed pda sound

* Fixed pda tests

* Fixed pda test again

Co-authored-by: Alexander Evgrashin <evgrashin.adl@gmail.com>
Co-authored-by: metalgearsloth <31366439+metalgearsloth@users.noreply.github.com>
Co-authored-by: Visne <vincefvanwijk@gmail.com>
This commit is contained in:
Alex Evgrashin
2021-10-03 07:05:52 +03:00
committed by GitHub
parent 39270d3ec7
commit e5df8dbee3
50 changed files with 1815 additions and 1313 deletions

View File

@@ -275,6 +275,9 @@ namespace Content.Client.Entry
"Advertise",
"PowerNetworkBattery",
"BatteryCharger",
"UnpoweredFlashlight",
"Uplink",
"PDA",
"SpawnItemsOnUse",
"Wieldable",
"IncreaseDamageOnWield",

View File

@@ -1,19 +1,13 @@
using System;
using Content.Client.Examine;
using Content.Client.Message;
using Content.Shared.PDA;
using JetBrains.Annotations;
using Robust.Client.GameObjects;
using Robust.Client.Graphics;
using Robust.Client.UserInterface;
using Robust.Client.UserInterface.Controls;
using Robust.Client.UserInterface.CustomControls;
using Robust.Shared.GameObjects;
using Robust.Shared.IoC;
using Robust.Shared.Localization;
using Robust.Shared.Maths;
using Robust.Shared.Prototypes;
using static Robust.Client.UserInterface.Controls.BaseButton;
using static Robust.Client.UserInterface.Controls.BoxContainer;
namespace Content.Client.PDA
@@ -21,11 +15,7 @@ namespace Content.Client.PDA
[UsedImplicitly]
public class PDABoundUserInterface : BoundUserInterface
{
[Dependency] private readonly IPrototypeManager _prototypeManager = default!;
[Dependency] private readonly IUserInterfaceManager _userInterfaceManager = default!;
private PDAMenu? _menu;
private PDAMenuPopup? _failPopup;
public PDABoundUserInterface(ClientUserInterfaceComponent owner, object uiKey) : base(owner, uiKey)
{
@@ -35,7 +25,7 @@ namespace Content.Client.PDA
{
base.Open();
SendMessage(new PDARequestUpdateInterfaceMessage());
_menu = new PDAMenu(this, _prototypeManager);
_menu = new PDAMenu();
_menu.OpenToLeft();
_menu.OnClose += Close;
_menu.FlashLightToggleButton.OnToggled += _ =>
@@ -43,7 +33,7 @@ namespace Content.Client.PDA
SendMessage(new PDAToggleFlashlightMessage());
};
_menu.EjectIDButton.OnPressed += _ =>
_menu.EjectIdButton.OnPressed += _ =>
{
SendMessage(new PDAEjectIDMessage());
};
@@ -53,37 +43,11 @@ namespace Content.Client.PDA
SendMessage(new PDAEjectPenMessage());
};
_menu.MasterTabContainer.OnTabChanged += i =>
_menu.ActivateUplinkButton.OnPressed += _ =>
{
var tab = _menu.MasterTabContainer.GetChild(i);
if (tab == _menu.UplinkTabContainer)
{
SendMessage(new PDARequestUpdateInterfaceMessage());
}
SendMessage(new PDAShowUplinkMessage());
};
_menu.OnListingButtonPressed += (_, listing) =>
{
if (_menu.CurrentLoggedInAccount?.DataBalance < listing.Price)
{
_failPopup = new PDAMenuPopup(Loc.GetString("pda-bound-user-interface-insufficient-funds-popup"));
_userInterfaceManager.ModalRoot.AddChild(_failPopup);
_failPopup.Open(UIBox2.FromDimensions(_menu.Position.X + 150, _menu.Position.Y + 60, 156, 24));
_menu.OnClose += () =>
{
_failPopup.Dispose();
};
}
SendMessage(new PDAUplinkBuyListingMessage(listing.ItemId));
};
_menu.OnCategoryButtonPressed += (_, category) =>
{
_menu.CurrentFilterCategory = category;
SendMessage(new PDARequestUpdateInterfaceMessage());
};
}
protected override void UpdateState(BoundUserInterfaceState state)
@@ -103,45 +67,26 @@ namespace Content.Client.PDA
if (msg.PDAOwnerInfo.ActualOwnerName != null)
{
_menu.PDAOwnerLabel.SetMarkup(Loc.GetString("comp-pda-ui-owner",
_menu.PdaOwnerLabel.SetMarkup(Loc.GetString("comp-pda-ui-owner",
("ActualOwnerName", msg.PDAOwnerInfo.ActualOwnerName)));
}
if (msg.PDAOwnerInfo.IdOwner != null || msg.PDAOwnerInfo.JobTitle != null)
{
_menu.IDInfoLabel.SetMarkup(Loc.GetString("comp-pda-ui",
_menu.IdInfoLabel.SetMarkup(Loc.GetString("comp-pda-ui",
("Owner",msg.PDAOwnerInfo.IdOwner ?? "Unknown"),
("JobTitle",msg.PDAOwnerInfo.JobTitle ?? "Unassigned")));
}
else
{
_menu.IDInfoLabel.SetMarkup(Loc.GetString("comp-pda-ui-blank"));
_menu.IdInfoLabel.SetMarkup(Loc.GetString("comp-pda-ui-blank"));
}
_menu.EjectIDButton.Visible = msg.PDAOwnerInfo.IdOwner != null || msg.PDAOwnerInfo.JobTitle != null;
_menu.EjectIdButton.Visible = msg.PDAOwnerInfo.IdOwner != null || msg.PDAOwnerInfo.JobTitle != null;
_menu.EjectPenButton.Visible = msg.HasPen;
_menu.ActivateUplinkButton.Visible = msg.HasUplink;
if (msg.Account != null)
{
_menu.CurrentLoggedInAccount = msg.Account;
var balance = msg.Account.DataBalance;
var weightedColor = GetWeightedColorString(balance);
_menu.BalanceInfo.SetMarkup(Loc.GetString("pda-bound-user-interface-tc-balance-popup",
("weightedColor",weightedColor),
("balance",balance)));
}
if (msg.Listings != null)
{
_menu.ClearListings();
foreach (var item in msg.Listings) //Should probably chunk these out instead. to-do if this clogs the internet tubes.
{
_menu.AddListingGui(item);
}
}
_menu.MasterTabContainer.SetTabVisible(1, msg.Account != null);
break;
}
}
@@ -156,410 +101,5 @@ namespace Content.Client.PDA
_menu?.Dispose();
}
/// <summary>
/// This is shitcode. It is, however, "PJB-approved shitcode".
/// </summary>
/// <param name="x"></param>
/// <returns></returns>
public static Color GetWeightedColor(int x)
{
var weightedColor = Color.Gray;
if (x <= 0)
{
return weightedColor;
}
if (x <= 5)
{
weightedColor = Color.LimeGreen;
}
else if (x > 5 && x < 10)
{
weightedColor = Color.Yellow;
}
else if (x > 10 && x <= 20)
{
weightedColor = Color.Orange;
}
else if (x > 20 && x <= 50)
{
weightedColor = Color.Purple;
}
return weightedColor;
}
public static string GetWeightedColorString(int x)
{
var weightedColor = "gray";
if (x <= 0)
{
return weightedColor;
}
if (x <= 5)
{
weightedColor = "green";
}
else if (x > 5 && x < 10)
{
weightedColor = "yellow";
}
else if (x > 10 && x <= 20)
{
weightedColor = "yellow";
}
else if (x > 20 && x <= 50)
{
weightedColor = "purple";
}
return weightedColor;
}
public sealed class PDAMenuPopup : Popup
{
public PDAMenuPopup(string text)
{
var label = new RichTextLabel();
label.SetMessage(text);
AddChild(new PanelContainer
{
StyleClasses = { ExamineSystem.StyleClassEntityTooltip },
Children = { label }
});
}
}
private class PDAMenu : SS14Window
{
private PDABoundUserInterface _owner { get; }
public Button FlashLightToggleButton { get; }
public Button EjectIDButton { get; }
public Button EjectPenButton { get; }
public readonly TabContainer MasterTabContainer;
public RichTextLabel PDAOwnerLabel { get; }
public PanelContainer IDInfoContainer { get; }
public RichTextLabel IDInfoLabel { get; }
public BoxContainer UplinkTabContainer { get; }
protected readonly SplitContainer CategoryAndListingsContainer;
private readonly IPrototypeManager _prototypeManager;
public readonly BoxContainer UplinkListingsContainer;
public readonly BoxContainer CategoryListContainer;
public readonly RichTextLabel BalanceInfo;
public event Action<ButtonEventArgs, UplinkListingData>? OnListingButtonPressed;
public event Action<ButtonEventArgs, UplinkCategory>? OnCategoryButtonPressed;
public UplinkCategory CurrentFilterCategory
{
get => _currentFilter;
set
{
if (value.GetType() != typeof(UplinkCategory))
{
return;
}
_currentFilter = value;
}
}
public UplinkAccountData? CurrentLoggedInAccount
{
get => _loggedInUplinkAccount;
set => _loggedInUplinkAccount = value;
}
private UplinkCategory _currentFilter;
private UplinkAccountData? _loggedInUplinkAccount;
public PDAMenu(PDABoundUserInterface owner, IPrototypeManager prototypeManager)
{
MinSize = SetSize = (512, 256);
_owner = owner;
_prototypeManager = prototypeManager;
Title = Loc.GetString("comp-pda-ui-menu-title");
#region MAIN_MENU_TAB
//Main menu
PDAOwnerLabel = new RichTextLabel
{
};
IDInfoLabel = new RichTextLabel()
{
HorizontalExpand = true,
};
EjectIDButton = new Button
{
Text = Loc.GetString("comp-pda-ui-eject-id-button"),
HorizontalAlignment = HAlignment.Center,
VerticalAlignment = VAlignment.Center
};
EjectPenButton = new Button
{
Text = Loc.GetString("comp-pda-ui-eject-pen-button"),
HorizontalAlignment = HAlignment.Center,
VerticalAlignment = VAlignment.Center
};
var innerHBoxContainer = new BoxContainer
{
Orientation = LayoutOrientation.Horizontal,
Children =
{
IDInfoLabel,
EjectIDButton,
EjectPenButton
}
};
IDInfoContainer = new PanelContainer
{
Children =
{
innerHBoxContainer,
}
};
FlashLightToggleButton = new Button
{
Text = Loc.GetString("comp-pda-ui-toggle-flashlight-button"),
ToggleMode = true,
};
var mainMenuTabContainer = new BoxContainer
{
Orientation = LayoutOrientation.Vertical,
VerticalExpand = true,
HorizontalExpand = true,
MinSize = (50, 50),
Children =
{
PDAOwnerLabel,
IDInfoContainer,
FlashLightToggleButton
}
};
#endregion
#region UPLINK_TAB
//Uplink Tab
CategoryListContainer = new BoxContainer
{
Orientation = LayoutOrientation.Vertical
};
BalanceInfo = new RichTextLabel
{
HorizontalAlignment = HAlignment.Center,
};
//Red background container.
var masterPanelContainer = new PanelContainer
{
PanelOverride = new StyleBoxFlat { BackgroundColor = Color.Black },
VerticalExpand = true
};
//This contains both the panel of the category buttons and the listings box.
CategoryAndListingsContainer = new SplitContainer
{
Orientation = SplitContainer.SplitOrientation.Horizontal,
VerticalExpand = true,
};
var uplinkShopScrollContainer = new ScrollContainer
{
HorizontalExpand = true,
VerticalExpand = true,
SizeFlagsStretchRatio = 2,
};
//Add the category list to the left side. The store items to center.
var categoryListContainerBackground = new PanelContainer
{
PanelOverride = new StyleBoxFlat { BackgroundColor = Color.Gray.WithAlpha(0.02f) },
VerticalExpand = true,
Children =
{
CategoryListContainer
}
};
CategoryAndListingsContainer.AddChild(categoryListContainerBackground);
CategoryAndListingsContainer.AddChild(uplinkShopScrollContainer);
masterPanelContainer.AddChild(CategoryAndListingsContainer);
//Actual list of buttons for buying a listing from the uplink.
UplinkListingsContainer = new BoxContainer
{
Orientation = LayoutOrientation.Vertical,
HorizontalExpand = true,
VerticalExpand = true,
SizeFlagsStretchRatio = 2,
MinSize = (100, 256),
};
uplinkShopScrollContainer.AddChild(UplinkListingsContainer);
var innerVboxContainer = new BoxContainer
{
Orientation = LayoutOrientation.Vertical,
VerticalExpand = true,
Children =
{
BalanceInfo,
masterPanelContainer
}
};
UplinkTabContainer = new BoxContainer
{
Orientation = LayoutOrientation.Vertical,
Children =
{
innerVboxContainer
}
};
PopulateUplinkCategoryButtons();
#endregion
//The master menu that contains all of the tabs.
MasterTabContainer = new TabContainer
{
Children =
{
mainMenuTabContainer,
}
};
//Add all the tabs to the Master container.
MasterTabContainer.SetTabTitle(0, Loc.GetString("pda-bound-user-interface-main-menu-tab-title"));
MasterTabContainer.AddChild(UplinkTabContainer);
MasterTabContainer.SetTabTitle(1, Loc.GetString("pda-bound-user-interface-uplink-tab-title"));
Contents.AddChild(MasterTabContainer);
}
private void PopulateUplinkCategoryButtons()
{
foreach (UplinkCategory cat in Enum.GetValues(typeof(UplinkCategory)))
{
var catButton = new PDAUplinkCategoryButton
{
Text = Loc.GetString(cat.ToString()),
ButtonCategory = cat
};
//It'd be neat if it could play a cool tech ping sound when you switch categories,
//but right now there doesn't seem to be an easy way to do client-side audio without still having to round trip to the server and
//send to a specific client INetChannel.
catButton.OnPressed += args => OnCategoryButtonPressed?.Invoke(args, catButton.ButtonCategory);
CategoryListContainer.AddChild(catButton);
}
}
public void AddListingGui(UplinkListingData listing)
{
if (!_prototypeManager.TryIndex(listing.ItemId, out EntityPrototype? prototype) || listing.Category != CurrentFilterCategory)
{
return;
}
var weightedColor = GetWeightedColor(listing.Price);
var itemLabel = new Label
{
Text = listing.ListingName == string.Empty ? prototype.Name : listing.ListingName,
ToolTip = listing.Description == string.Empty ? prototype.Description : listing.Description,
HorizontalExpand = true,
Modulate = _loggedInUplinkAccount?.DataBalance >= listing.Price
? Color.White
: Color.Gray.WithAlpha(0.30f)
};
var priceLabel = new Label
{
Text = $"{listing.Price} TC",
HorizontalAlignment = HAlignment.Right,
Modulate = _loggedInUplinkAccount?.DataBalance >= listing.Price
? weightedColor
: Color.Gray.WithAlpha(0.30f)
};
//Padding for the price lable.
var pricePadding = new BoxContainer
{
Orientation = LayoutOrientation.Horizontal,
MinSize = (32, 1),
};
//Contains the name of the item and its price. Used for spacing item name and price.
var listingButtonHbox = new BoxContainer
{
Orientation = LayoutOrientation.Horizontal,
Children =
{
itemLabel,
priceLabel,
pricePadding
}
};
var listingButtonPanelContainer = new PanelContainer
{
Children =
{
listingButtonHbox
}
};
var pdaUplinkListingButton = new PDAUplinkItemButton(listing)
{
Children =
{
listingButtonPanelContainer
}
};
pdaUplinkListingButton.OnPressed += args
=> OnListingButtonPressed?.Invoke(args, pdaUplinkListingButton.ButtonListing);
UplinkListingsContainer.AddChild(pdaUplinkListingButton);
}
public void ClearListings()
{
UplinkListingsContainer.Children.Clear();
}
private sealed class PDAUplinkItemButton : ContainerButton
{
public PDAUplinkItemButton(UplinkListingData data)
{
ButtonListing = data;
}
public UplinkListingData ButtonListing { get; }
}
private sealed class PDAUplinkCategoryButton : Button
{
public UplinkCategory ButtonCategory;
}
}
}
}

View File

@@ -1,39 +0,0 @@
using Content.Shared.PDA;
using Content.Shared.Sound;
using Robust.Shared.Audio;
using Robust.Shared.GameObjects;
using Robust.Shared.Network;
using Robust.Shared.Player;
using Robust.Shared.Players;
using Robust.Shared.Serialization.Manager.Attributes;
using Robust.Shared.ViewVariables;
namespace Content.Client.PDA
{
[RegisterComponent]
public class PDAComponent : SharedPDAComponent
{
[ViewVariables]
[DataField("buySuccessSound")]
private SoundSpecifier BuySuccessSound { get; } = new SoundPathSpecifier("/Audio/Effects/kaching.ogg");
[ViewVariables]
[DataField("insufficientFundsSound")]
private SoundSpecifier InsufficientFundsSound { get; } = new SoundPathSpecifier("/Audio/Effects/error.ogg");
public override void HandleNetworkMessage(ComponentMessage message, INetChannel netChannel, ICommonSession? session = null)
{
base.HandleNetworkMessage(message, netChannel, session);
switch (message)
{
case PDAUplinkBuySuccessMessage:
SoundSystem.Play(Filter.Local(), BuySuccessSound.GetSound(), Owner, AudioParams.Default.WithVolume(-2f));
break;
case PDAUplinkInsufficientFundsMessage:
SoundSystem.Play(Filter.Local(), InsufficientFundsSound.GetSound(), Owner, AudioParams.Default);
break;
}
}
}
}

View File

@@ -0,0 +1,32 @@
<SS14Window xmlns="https://spacestation14.io"
Title="{Loc 'comp-pda-ui-menu-title'}"
MinSize="512 256"
SetSize="512 256">
<TabContainer Name="MasterTabContainer">
<BoxContainer Orientation="Vertical"
VerticalExpand="True"
HorizontalExpand="True"
MinSize="50 50">
<RichTextLabel Name="PdaOwnerLabelProtected" />
<PanelContainer>
<BoxContainer Orientation="Horizontal">
<RichTextLabel Name="IdInfoLabelProtected"
HorizontalExpand="True" />
<Button Name="EjectIdButtonProtected"
Text="{Loc 'comp-pda-ui-eject-id-button'}"
HorizontalAlignment="Center"
VerticalAlignment="Center" />
<Button Name="EjectPenButtonProtected"
Text="{Loc 'comp-pda-ui-eject-pen-button'}"
HorizontalAlignment="Center"
VerticalAlignment="Center" />
</BoxContainer>
</PanelContainer>
<Button Name="FlashLightToggleButtonProtected"
Text="{Loc 'comp-pda-ui-toggle-flashlight-button'}"
ToggleMode="True" />
<Button Name="ActivateUplinkButtonProtected"
Text="{Loc 'pda-bound-user-interface-uplink-tab-title'}" />
</BoxContainer>
</TabContainer>
</SS14Window>

View File

@@ -0,0 +1,28 @@
using Robust.Client.AutoGenerated;
using Robust.Client.UserInterface.Controls;
using Robust.Client.UserInterface.CustomControls;
using Robust.Client.UserInterface.XAML;
using Robust.Shared.Localization;
namespace Content.Client.PDA
{
[GenerateTypedNameReferences]
public partial class PDAMenu : SS14Window
{
public Button FlashLightToggleButton => FlashLightToggleButtonProtected;
public Button EjectIdButton => EjectIdButtonProtected;
public Button EjectPenButton => EjectPenButtonProtected;
public Button ActivateUplinkButton => ActivateUplinkButtonProtected;
public RichTextLabel PdaOwnerLabel => PdaOwnerLabelProtected;
public RichTextLabel IdInfoLabel => IdInfoLabelProtected;
public PDAMenu()
{
RobustXamlLoader.Load(this);
MasterTabContainer.SetTabTitle(0, Loc.GetString("pda-bound-user-interface-main-menu-tab-title"));
}
}
}

View File

@@ -1,4 +1,5 @@
using Content.Shared.PDA;
using Content.Shared.Light;
using Content.Shared.PDA;
using JetBrains.Annotations;
using Robust.Client.GameObjects;
using Robust.Shared.GameObjects;
@@ -46,9 +47,9 @@ namespace Content.Client.PDA
var sprite = component.Owner.GetComponent<ISpriteComponent>();
sprite.LayerSetVisible(PDAVisualLayers.Flashlight, false);
if (component.TryGetData(PDAVisuals.FlashlightLit, out bool isScreenLit))
if (component.TryGetData(UnpoweredFlashlightVisuals.LightOn, out bool isFlashlightOn))
{
sprite.LayerSetVisible(PDAVisualLayers.Flashlight, isScreenLit);
sprite.LayerSetVisible(PDAVisualLayers.Flashlight, isFlashlightOn);
}
if (component.TryGetData(PDAVisuals.IDCardInserted, out bool isCardInserted))

View File

@@ -0,0 +1,112 @@
using Content.Client.Examine;
using Content.Client.Message;
using Content.Shared.Traitor.Uplink;
using JetBrains.Annotations;
using Robust.Client.GameObjects;
using Robust.Client.UserInterface;
using Robust.Client.UserInterface.Controls;
using Robust.Shared.GameObjects;
using Robust.Shared.IoC;
using Robust.Shared.Localization;
using Robust.Shared.Maths;
using Robust.Shared.Prototypes;
namespace Content.Client.Traitor.Uplink
{
[UsedImplicitly]
public class UplinkBoundUserInterface : BoundUserInterface
{
[Dependency] private readonly IPrototypeManager _prototypeManager = default!;
[Dependency] private readonly IUserInterfaceManager _userInterfaceManager = default!;
private UplinkMenu? _menu;
private UplinkMenuPopup? _failPopup;
public UplinkBoundUserInterface(ClientUserInterfaceComponent owner, object uiKey) : base(owner, uiKey)
{
}
protected override void Open()
{
_menu = new UplinkMenu(_prototypeManager);
_menu.OpenCentered();
_menu.OnClose += Close;
_menu.OnListingButtonPressed += (_, listing) =>
{
if (_menu.CurrentLoggedInAccount?.DataBalance < listing.Price)
{
_failPopup = new UplinkMenuPopup(Loc.GetString("uplink-bound-user-interface-insufficient-funds-popup"));
_userInterfaceManager.ModalRoot.AddChild(_failPopup);
_failPopup.Open(UIBox2.FromDimensions(_menu.Position.X + 150, _menu.Position.Y + 60, 156, 24));
_menu.OnClose += () =>
{
_failPopup.Dispose();
};
}
SendMessage(new UplinkBuyListingMessage(listing.ItemId));
};
_menu.OnCategoryButtonPressed += (_, category) =>
{
_menu.CurrentFilterCategory = category;
SendMessage(new UplinkRequestUpdateInterfaceMessage());
};
}
protected override void UpdateState(BoundUserInterfaceState state)
{
base.UpdateState(state);
if (_menu == null)
{
return;
}
switch (state)
{
case UplinkUpdateState msg:
{
_menu.CurrentLoggedInAccount = msg.Account;
var balance = msg.Account.DataBalance;
string weightedColor = balance switch
{
<= 0 => "gray",
<= 5 => "green",
<= 20 => "yellow",
<= 50 => "purple",
_ => "gray"
};
_menu.BalanceInfo.SetMarkup(Loc.GetString("uplink-bound-user-interface-tc-balance-popup",
("weightedColor", weightedColor),
("balance", balance)));
_menu.ClearListings();
foreach (var item in
msg.Listings) //Should probably chunk these out instead. to-do if this clogs the internet tubes.
{
_menu.AddListingGui(item);
}
break;
}
}
}
private sealed class UplinkMenuPopup : Popup
{
public UplinkMenuPopup(string text)
{
var label = new RichTextLabel();
label.SetMessage(text);
AddChild(new PanelContainer
{
StyleClasses = { ExamineSystem.StyleClassEntityTooltip },
Children = { label }
});
}
}
}
}

View File

@@ -0,0 +1,43 @@
<SS14Window xmlns="https://spacestation14.io"
xmlns:gfx="clr-namespace:Robust.Client.Graphics;assembly=Robust.Client"
Title="{Loc 'pda-bound-user-interface-uplink-tab-title'}"
MinSize="512 512"
SetSize="512 512">
<BoxContainer Orientation="Vertical">
<BoxContainer Orientation="Vertical"
VerticalExpand="True">
<RichTextLabel Name="BalanceInfoProtected"
HorizontalAlignment="Center" />
<PanelContainer VerticalExpand="True">
<PanelContainer.PanelOverride>
<gfx:StyleBoxFlat BackgroundColor="#000000FF" />
</PanelContainer.PanelOverride>
<SplitContainer Orientation="Horizontal"
VerticalExpand="True">
<PanelContainer VerticalExpand="True">
<PanelContainer.PanelOverride>
<gfx:StyleBoxFlat BackgroundColor="#80808005" />
</PanelContainer.PanelOverride>
<BoxContainer Name="CategoryListContainer"
Orientation="Vertical">
<!-- Category buttons are added here by code -->
</BoxContainer>
</PanelContainer>
<ScrollContainer HorizontalExpand="True"
VerticalExpand="True"
SizeFlagsStretchRatio="2"
MinSize="100 256">
<BoxContainer Name="UplinkListingsContainer"
Orientation="Vertical"
HorizontalExpand="True"
VerticalExpand="True"
SizeFlagsStretchRatio="2"
MinSize="100 256">
<!-- Listings are added here by code -->
</BoxContainer>
</ScrollContainer>
</SplitContainer>
</PanelContainer>
</BoxContainer>
</BoxContainer>
</SS14Window>

View File

@@ -0,0 +1,166 @@
using System;
using Content.Shared.PDA;
using Content.Shared.Traitor.Uplink;
using Robust.Client.AutoGenerated;
using Robust.Client.UserInterface.Controls;
using Robust.Client.UserInterface.CustomControls;
using Robust.Client.UserInterface.XAML;
using Robust.Shared.Localization;
using Robust.Shared.Maths;
using Robust.Shared.Prototypes;
namespace Content.Client.Traitor.Uplink
{
[GenerateTypedNameReferences]
public partial class UplinkMenu : SS14Window
{
private readonly IPrototypeManager _prototypeManager;
public RichTextLabel BalanceInfo => BalanceInfoProtected;
public event Action<BaseButton.ButtonEventArgs, UplinkListingData>? OnListingButtonPressed;
public event Action<BaseButton.ButtonEventArgs, UplinkCategory>? OnCategoryButtonPressed;
public UplinkMenu(IPrototypeManager prototypeManager)
{
RobustXamlLoader.Load(this);
_prototypeManager = prototypeManager;
PopulateUplinkCategoryButtons();
}
public UplinkCategory CurrentFilterCategory
{
get => _currentFilter;
set
{
if (value.GetType() != typeof(UplinkCategory))
{
return;
}
_currentFilter = value;
}
}
public UplinkAccountData? CurrentLoggedInAccount
{
get => _loggedInUplinkAccount;
set => _loggedInUplinkAccount = value;
}
private UplinkCategory _currentFilter;
private UplinkAccountData? _loggedInUplinkAccount;
public void AddListingGui(UplinkListingData listing)
{
if (!_prototypeManager.TryIndex(listing.ItemId, out EntityPrototype? prototype) || listing.Category != CurrentFilterCategory)
{
return;
}
var weightedColor = listing.Price switch
{
<= 0 => Color.Gray,
<= 5 => Color.Green,
<= 10 => Color.Yellow,
<= 20 => Color.Orange,
<= 50 => Color.Purple,
_ => Color.Gray
};
var itemLabel = new Label
{
Text = listing.ListingName == string.Empty ? prototype.Name : listing.ListingName,
ToolTip = listing.Description == string.Empty ? prototype.Description : listing.Description,
HorizontalExpand = true,
Modulate = _loggedInUplinkAccount?.DataBalance >= listing.Price
? Color.White
: Color.Gray.WithAlpha(0.30f)
};
var priceLabel = new Label
{
Text = $"{listing.Price} TC",
HorizontalAlignment = HAlignment.Right,
Modulate = _loggedInUplinkAccount?.DataBalance >= listing.Price
? weightedColor
: Color.Gray.WithAlpha(0.30f)
};
//Padding for the price lable.
var pricePadding = new BoxContainer
{
Orientation = BoxContainer.LayoutOrientation.Horizontal,
MinSize = (32, 1),
};
//Contains the name of the item and its price. Used for spacing item name and price.
var listingButtonHbox = new BoxContainer
{
Orientation = BoxContainer.LayoutOrientation.Horizontal,
Children =
{
itemLabel,
priceLabel,
pricePadding
}
};
var listingButtonPanelContainer = new PanelContainer
{
Children =
{
listingButtonHbox
}
};
var pdaUplinkListingButton = new PDAUplinkItemButton(listing)
{
Children =
{
listingButtonPanelContainer
}
};
pdaUplinkListingButton.OnPressed += args
=> OnListingButtonPressed?.Invoke(args, pdaUplinkListingButton.ButtonListing);
UplinkListingsContainer.AddChild(pdaUplinkListingButton);
}
public void ClearListings()
{
UplinkListingsContainer.Children.Clear();
}
private void PopulateUplinkCategoryButtons()
{
foreach (UplinkCategory cat in Enum.GetValues(typeof(UplinkCategory)))
{
var catButton = new PDAUplinkCategoryButton
{
Text = Loc.GetString(cat.ToString()),
ButtonCategory = cat
};
//It'd be neat if it could play a cool tech ping sound when you switch categories,
//but right now there doesn't seem to be an easy way to do client-side audio without still having to round trip to the server and
//send to a specific client INetChannel.
catButton.OnPressed += args => OnCategoryButtonPressed?.Invoke(args, catButton.ButtonCategory);
CategoryListContainer.AddChild(catButton);
}
}
private sealed class PDAUplinkItemButton : ContainerButton
{
public PDAUplinkItemButton(UplinkListingData data)
{
ButtonListing = data;
}
public UplinkListingData ButtonListing { get; }
}
private sealed class PDAUplinkCategoryButton : Button
{
public UplinkCategory ButtonCategory;
}
}
}