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:
@@ -275,6 +275,9 @@ namespace Content.Client.Entry
|
|||||||
"Advertise",
|
"Advertise",
|
||||||
"PowerNetworkBattery",
|
"PowerNetworkBattery",
|
||||||
"BatteryCharger",
|
"BatteryCharger",
|
||||||
|
"UnpoweredFlashlight",
|
||||||
|
"Uplink",
|
||||||
|
"PDA",
|
||||||
"SpawnItemsOnUse",
|
"SpawnItemsOnUse",
|
||||||
"Wieldable",
|
"Wieldable",
|
||||||
"IncreaseDamageOnWield",
|
"IncreaseDamageOnWield",
|
||||||
|
|||||||
@@ -1,19 +1,13 @@
|
|||||||
using System;
|
|
||||||
using Content.Client.Examine;
|
|
||||||
using Content.Client.Message;
|
using Content.Client.Message;
|
||||||
using Content.Shared.PDA;
|
using Content.Shared.PDA;
|
||||||
using JetBrains.Annotations;
|
using JetBrains.Annotations;
|
||||||
using Robust.Client.GameObjects;
|
using Robust.Client.GameObjects;
|
||||||
using Robust.Client.Graphics;
|
|
||||||
using Robust.Client.UserInterface;
|
|
||||||
using Robust.Client.UserInterface.Controls;
|
using Robust.Client.UserInterface.Controls;
|
||||||
using Robust.Client.UserInterface.CustomControls;
|
using Robust.Client.UserInterface.CustomControls;
|
||||||
using Robust.Shared.GameObjects;
|
using Robust.Shared.GameObjects;
|
||||||
using Robust.Shared.IoC;
|
using Robust.Shared.IoC;
|
||||||
using Robust.Shared.Localization;
|
using Robust.Shared.Localization;
|
||||||
using Robust.Shared.Maths;
|
|
||||||
using Robust.Shared.Prototypes;
|
using Robust.Shared.Prototypes;
|
||||||
using static Robust.Client.UserInterface.Controls.BaseButton;
|
|
||||||
using static Robust.Client.UserInterface.Controls.BoxContainer;
|
using static Robust.Client.UserInterface.Controls.BoxContainer;
|
||||||
|
|
||||||
namespace Content.Client.PDA
|
namespace Content.Client.PDA
|
||||||
@@ -21,11 +15,7 @@ namespace Content.Client.PDA
|
|||||||
[UsedImplicitly]
|
[UsedImplicitly]
|
||||||
public class PDABoundUserInterface : BoundUserInterface
|
public class PDABoundUserInterface : BoundUserInterface
|
||||||
{
|
{
|
||||||
[Dependency] private readonly IPrototypeManager _prototypeManager = default!;
|
|
||||||
[Dependency] private readonly IUserInterfaceManager _userInterfaceManager = default!;
|
|
||||||
|
|
||||||
private PDAMenu? _menu;
|
private PDAMenu? _menu;
|
||||||
private PDAMenuPopup? _failPopup;
|
|
||||||
|
|
||||||
public PDABoundUserInterface(ClientUserInterfaceComponent owner, object uiKey) : base(owner, uiKey)
|
public PDABoundUserInterface(ClientUserInterfaceComponent owner, object uiKey) : base(owner, uiKey)
|
||||||
{
|
{
|
||||||
@@ -35,7 +25,7 @@ namespace Content.Client.PDA
|
|||||||
{
|
{
|
||||||
base.Open();
|
base.Open();
|
||||||
SendMessage(new PDARequestUpdateInterfaceMessage());
|
SendMessage(new PDARequestUpdateInterfaceMessage());
|
||||||
_menu = new PDAMenu(this, _prototypeManager);
|
_menu = new PDAMenu();
|
||||||
_menu.OpenToLeft();
|
_menu.OpenToLeft();
|
||||||
_menu.OnClose += Close;
|
_menu.OnClose += Close;
|
||||||
_menu.FlashLightToggleButton.OnToggled += _ =>
|
_menu.FlashLightToggleButton.OnToggled += _ =>
|
||||||
@@ -43,7 +33,7 @@ namespace Content.Client.PDA
|
|||||||
SendMessage(new PDAToggleFlashlightMessage());
|
SendMessage(new PDAToggleFlashlightMessage());
|
||||||
};
|
};
|
||||||
|
|
||||||
_menu.EjectIDButton.OnPressed += _ =>
|
_menu.EjectIdButton.OnPressed += _ =>
|
||||||
{
|
{
|
||||||
SendMessage(new PDAEjectIDMessage());
|
SendMessage(new PDAEjectIDMessage());
|
||||||
};
|
};
|
||||||
@@ -53,37 +43,11 @@ namespace Content.Client.PDA
|
|||||||
SendMessage(new PDAEjectPenMessage());
|
SendMessage(new PDAEjectPenMessage());
|
||||||
};
|
};
|
||||||
|
|
||||||
_menu.MasterTabContainer.OnTabChanged += i =>
|
_menu.ActivateUplinkButton.OnPressed += _ =>
|
||||||
{
|
{
|
||||||
var tab = _menu.MasterTabContainer.GetChild(i);
|
SendMessage(new PDAShowUplinkMessage());
|
||||||
if (tab == _menu.UplinkTabContainer)
|
|
||||||
{
|
|
||||||
SendMessage(new PDARequestUpdateInterfaceMessage());
|
|
||||||
}
|
|
||||||
};
|
};
|
||||||
|
|
||||||
_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)
|
protected override void UpdateState(BoundUserInterfaceState state)
|
||||||
@@ -103,45 +67,26 @@ namespace Content.Client.PDA
|
|||||||
|
|
||||||
if (msg.PDAOwnerInfo.ActualOwnerName != null)
|
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)));
|
("ActualOwnerName", msg.PDAOwnerInfo.ActualOwnerName)));
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
if (msg.PDAOwnerInfo.IdOwner != null || msg.PDAOwnerInfo.JobTitle != null)
|
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"),
|
("Owner",msg.PDAOwnerInfo.IdOwner ?? "Unknown"),
|
||||||
("JobTitle",msg.PDAOwnerInfo.JobTitle ?? "Unassigned")));
|
("JobTitle",msg.PDAOwnerInfo.JobTitle ?? "Unassigned")));
|
||||||
}
|
}
|
||||||
else
|
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.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;
|
break;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@@ -156,410 +101,5 @@ namespace Content.Client.PDA
|
|||||||
|
|
||||||
_menu?.Dispose();
|
_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;
|
|
||||||
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -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;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
32
Content.Client/PDA/PDAMenu.xaml
Normal file
32
Content.Client/PDA/PDAMenu.xaml
Normal 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>
|
||||||
28
Content.Client/PDA/PDAMenu.xaml.cs
Normal file
28
Content.Client/PDA/PDAMenu.xaml.cs
Normal 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"));
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
@@ -1,4 +1,5 @@
|
|||||||
using Content.Shared.PDA;
|
using Content.Shared.Light;
|
||||||
|
using Content.Shared.PDA;
|
||||||
using JetBrains.Annotations;
|
using JetBrains.Annotations;
|
||||||
using Robust.Client.GameObjects;
|
using Robust.Client.GameObjects;
|
||||||
using Robust.Shared.GameObjects;
|
using Robust.Shared.GameObjects;
|
||||||
@@ -46,9 +47,9 @@ namespace Content.Client.PDA
|
|||||||
|
|
||||||
var sprite = component.Owner.GetComponent<ISpriteComponent>();
|
var sprite = component.Owner.GetComponent<ISpriteComponent>();
|
||||||
sprite.LayerSetVisible(PDAVisualLayers.Flashlight, false);
|
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))
|
if (component.TryGetData(PDAVisuals.IDCardInserted, out bool isCardInserted))
|
||||||
|
|||||||
112
Content.Client/Traitor/Uplink/UplinkBoundUserInterface.cs
Normal file
112
Content.Client/Traitor/Uplink/UplinkBoundUserInterface.cs
Normal 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 }
|
||||||
|
});
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
43
Content.Client/Traitor/Uplink/UplinkMenu.xaml
Normal file
43
Content.Client/Traitor/Uplink/UplinkMenu.xaml
Normal 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>
|
||||||
166
Content.Client/Traitor/Uplink/UplinkMenu.xaml.cs
Normal file
166
Content.Client/Traitor/Uplink/UplinkMenu.xaml.cs
Normal 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;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
@@ -1,6 +1,7 @@
|
|||||||
using System.Linq;
|
using System.Linq;
|
||||||
using System.Threading.Tasks;
|
using System.Threading.Tasks;
|
||||||
using Content.Server.Access.Components;
|
using Content.Server.Access.Components;
|
||||||
|
using Content.Shared.Containers.ItemSlots;
|
||||||
using Content.Server.Hands.Components;
|
using Content.Server.Hands.Components;
|
||||||
using Content.Server.Inventory.Components;
|
using Content.Server.Inventory.Components;
|
||||||
using Content.Server.Items;
|
using Content.Server.Items;
|
||||||
@@ -28,8 +29,13 @@ namespace Content.IntegrationTests.Tests.PDA
|
|||||||
id: {PdaDummy}
|
id: {PdaDummy}
|
||||||
name: {PdaDummy}
|
name: {PdaDummy}
|
||||||
components:
|
components:
|
||||||
|
- type: ItemSlots
|
||||||
|
slots:
|
||||||
|
pda_id_slot:
|
||||||
|
whitelist:
|
||||||
|
components:
|
||||||
|
- IdCard
|
||||||
- type: PDA
|
- type: PDA
|
||||||
idCard: {IdCardDummy}
|
|
||||||
- type: Item";
|
- type: Item";
|
||||||
|
|
||||||
[Test]
|
[Test]
|
||||||
@@ -69,13 +75,17 @@ namespace Content.IntegrationTests.Tests.PDA
|
|||||||
player.GetComponent<IHandsComponent>().PutInHand(pdaItemComponent);
|
player.GetComponent<IHandsComponent>().PutInHand(pdaItemComponent);
|
||||||
|
|
||||||
var pdaComponent = dummyPda.GetComponent<PDAComponent>();
|
var pdaComponent = dummyPda.GetComponent<PDAComponent>();
|
||||||
var pdaIdCard = sEntityManager.SpawnEntity(IdCardDummy, player.Transform.MapPosition).GetComponent<IdCardComponent>();
|
var pdaIdCard = sEntityManager.SpawnEntity(IdCardDummy, player.Transform.MapPosition);
|
||||||
pdaComponent.InsertIdCard(pdaIdCard);
|
|
||||||
|
var itemSlots = dummyPda.GetComponent<SharedItemSlotsComponent>();
|
||||||
|
sEntityManager.EntitySysManager.GetEntitySystem<SharedItemSlotsSystem>()
|
||||||
|
.TryInsertContent(itemSlots, pdaIdCard, PDAComponent.IDSlotName);
|
||||||
var pdaContainedId = pdaComponent.ContainedID;
|
var pdaContainedId = pdaComponent.ContainedID;
|
||||||
|
|
||||||
// The PDA in the hand should be found first
|
// The PDA in the hand should be found first
|
||||||
Assert.NotNull(player.GetHeldId());
|
Assert.NotNull(player.GetHeldId());
|
||||||
Assert.True(player.TryGetHeldId(out id));
|
Assert.True(player.TryGetHeldId(out id));
|
||||||
|
|
||||||
Assert.NotNull(id);
|
Assert.NotNull(id);
|
||||||
Assert.That(id, Is.EqualTo(pdaContainedId));
|
Assert.That(id, Is.EqualTo(pdaContainedId));
|
||||||
|
|
||||||
|
|||||||
@@ -87,7 +87,7 @@ namespace Content.Server.Entry
|
|||||||
IoCManager.Resolve<ActionManager>().Initialize();
|
IoCManager.Resolve<ActionManager>().Initialize();
|
||||||
IoCManager.Resolve<BlackboardManager>().Initialize();
|
IoCManager.Resolve<BlackboardManager>().Initialize();
|
||||||
IoCManager.Resolve<ConsiderationsManager>().Initialize();
|
IoCManager.Resolve<ConsiderationsManager>().Initialize();
|
||||||
IoCManager.Resolve<IPDAUplinkManager>().Initialize();
|
IoCManager.Resolve<IUplinkManager>().Initialize();
|
||||||
IoCManager.Resolve<IAdminManager>().Initialize();
|
IoCManager.Resolve<IAdminManager>().Initialize();
|
||||||
IoCManager.Resolve<INpcBehaviorManager>().Initialize();
|
IoCManager.Resolve<INpcBehaviorManager>().Initialize();
|
||||||
IoCManager.Resolve<IAfkManager>().Initialize();
|
IoCManager.Resolve<IAfkManager>().Initialize();
|
||||||
|
|||||||
@@ -234,7 +234,8 @@ namespace Content.Server.GameTicking
|
|||||||
var access = card.Owner.GetComponent<AccessComponent>();
|
var access = card.Owner.GetComponent<AccessComponent>();
|
||||||
var accessTags = access.Tags;
|
var accessTags = access.Tags;
|
||||||
accessTags.UnionWith(jobPrototype.Access);
|
accessTags.UnionWith(jobPrototype.Access);
|
||||||
pdaComponent.SetPDAOwner(characterName);
|
EntityManager.EntitySysManager.GetEntitySystem<PDASystem>()
|
||||||
|
.SetOwner(pdaComponent, characterName);
|
||||||
}
|
}
|
||||||
#endregion
|
#endregion
|
||||||
|
|
||||||
|
|||||||
@@ -1,17 +1,19 @@
|
|||||||
using System.Collections.Generic;
|
using System.Collections.Generic;
|
||||||
using Content.Server.Chat.Managers;
|
using Content.Server.Chat.Managers;
|
||||||
using Content.Server.GameTicking.Rules;
|
using Content.Server.GameTicking.Rules;
|
||||||
using Content.Server.Inventory.Components;
|
using Content.Server.Inventory.Components;
|
||||||
using Content.Server.Items;
|
using Content.Server.Items;
|
||||||
using Content.Server.PDA;
|
using Content.Server.PDA.Managers;
|
||||||
using Content.Server.Players;
|
using Content.Server.Players;
|
||||||
using Content.Server.Suspicion;
|
using Content.Server.Suspicion;
|
||||||
using Content.Server.Suspicion.Roles;
|
using Content.Server.Suspicion.Roles;
|
||||||
using Content.Shared;
|
using Content.Server.Traitor.Uplink;
|
||||||
|
using Content.Server.Traitor.Uplink.Components;
|
||||||
|
using Content.Server.Traitor.Uplink.Systems;
|
||||||
using Content.Shared.CCVar;
|
using Content.Shared.CCVar;
|
||||||
using Content.Shared.Inventory;
|
using Content.Shared.Inventory;
|
||||||
using Content.Shared.PDA;
|
|
||||||
using Content.Shared.Roles;
|
using Content.Shared.Roles;
|
||||||
|
using Content.Shared.Traitor.Uplink;
|
||||||
using Robust.Server.Player;
|
using Robust.Server.Player;
|
||||||
using Robust.Shared.Configuration;
|
using Robust.Shared.Configuration;
|
||||||
using Robust.Shared.GameObjects;
|
using Robust.Shared.GameObjects;
|
||||||
@@ -31,6 +33,8 @@ namespace Content.Server.GameTicking.Presets
|
|||||||
[Dependency] private readonly IRobustRandom _random = default!;
|
[Dependency] private readonly IRobustRandom _random = default!;
|
||||||
[Dependency] private readonly IConfigurationManager _cfg = default!;
|
[Dependency] private readonly IConfigurationManager _cfg = default!;
|
||||||
[Dependency] private readonly IPrototypeManager _prototypeManager = default!;
|
[Dependency] private readonly IPrototypeManager _prototypeManager = default!;
|
||||||
|
[Dependency] protected readonly IEntityManager EntityManager = default!;
|
||||||
|
[Dependency] private readonly IUplinkManager _uplinkManager = default!;
|
||||||
|
|
||||||
public int MinPlayers { get; set; }
|
public int MinPlayers { get; set; }
|
||||||
public int MinTraitors { get; set; }
|
public int MinTraitors { get; set; }
|
||||||
@@ -109,28 +113,17 @@ namespace Content.Server.GameTicking.Presets
|
|||||||
var traitorRole = new SuspicionTraitorRole(mind!, antagPrototype);
|
var traitorRole = new SuspicionTraitorRole(mind!, antagPrototype);
|
||||||
mind!.AddRole(traitorRole);
|
mind!.AddRole(traitorRole);
|
||||||
traitors.Add(traitorRole);
|
traitors.Add(traitorRole);
|
||||||
|
|
||||||
// creadth: we need to create uplink for the antag.
|
// creadth: we need to create uplink for the antag.
|
||||||
// PDA should be in place already, so we just need to
|
// PDA should be in place already, so we just need to
|
||||||
// initiate uplink account.
|
// initiate uplink account.
|
||||||
var uplinkAccount =
|
var uplinkAccount = new UplinkAccount(mind.OwnedEntity!.Uid, TraitorStartingBalance);
|
||||||
new UplinkAccount(mind.OwnedEntity!.Uid,
|
_uplinkManager.AddNewAccount(uplinkAccount);
|
||||||
TraitorStartingBalance);
|
|
||||||
var inventory = mind.OwnedEntity.GetComponent<InventoryComponent>();
|
// try to place uplink
|
||||||
if (!inventory.TryGetSlotItem(EquipmentSlotDefines.Slots.IDCARD, out ItemComponent? pdaItem))
|
if (!EntityManager.EntitySysManager.GetEntitySystem<UplinkSystem>()
|
||||||
{
|
.AddUplink(mind.OwnedEntity, uplinkAccount))
|
||||||
continue;
|
continue;
|
||||||
}
|
|
||||||
|
|
||||||
var pda = pdaItem.Owner;
|
|
||||||
|
|
||||||
var pdaComponent = pda.GetComponent<PDAComponent>();
|
|
||||||
if (pdaComponent.IdSlotEmpty)
|
|
||||||
{
|
|
||||||
continue;
|
|
||||||
}
|
|
||||||
|
|
||||||
pdaComponent.InitUplinkAccount(uplinkAccount);
|
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|
||||||
foreach (var player in list)
|
foreach (var player in list)
|
||||||
|
|||||||
@@ -7,13 +7,16 @@ using Content.Server.Inventory.Components;
|
|||||||
using Content.Server.Items;
|
using Content.Server.Items;
|
||||||
using Content.Server.Objectives.Interfaces;
|
using Content.Server.Objectives.Interfaces;
|
||||||
using Content.Server.PDA;
|
using Content.Server.PDA;
|
||||||
|
using Content.Server.PDA.Managers;
|
||||||
using Content.Server.Players;
|
using Content.Server.Players;
|
||||||
using Content.Server.Traitor;
|
using Content.Server.Traitor;
|
||||||
using Content.Shared;
|
using Content.Server.Traitor.Uplink;
|
||||||
|
using Content.Server.Traitor.Uplink.Components;
|
||||||
|
using Content.Server.Traitor.Uplink.Systems;
|
||||||
using Content.Shared.CCVar;
|
using Content.Shared.CCVar;
|
||||||
using Content.Shared.Dataset;
|
using Content.Shared.Dataset;
|
||||||
using Content.Shared.Inventory;
|
using Content.Shared.Inventory;
|
||||||
using Content.Shared.PDA;
|
using Content.Shared.Traitor.Uplink;
|
||||||
using Robust.Server.Player;
|
using Robust.Server.Player;
|
||||||
using Robust.Shared.Configuration;
|
using Robust.Shared.Configuration;
|
||||||
using Robust.Shared.GameObjects;
|
using Robust.Shared.GameObjects;
|
||||||
@@ -34,6 +37,8 @@ namespace Content.Server.GameTicking.Presets
|
|||||||
[Dependency] private readonly IRobustRandom _random = default!;
|
[Dependency] private readonly IRobustRandom _random = default!;
|
||||||
[Dependency] private readonly IConfigurationManager _cfg = default!;
|
[Dependency] private readonly IConfigurationManager _cfg = default!;
|
||||||
[Dependency] private readonly IPrototypeManager _prototypeManager = default!;
|
[Dependency] private readonly IPrototypeManager _prototypeManager = default!;
|
||||||
|
[Dependency] protected readonly IEntityManager EntityManager = default!;
|
||||||
|
[Dependency] private readonly IUplinkManager _uplinkManager = default!;
|
||||||
|
|
||||||
public override string ModeTitle => Loc.GetString("traitor-title");
|
public override string ModeTitle => Loc.GetString("traitor-title");
|
||||||
|
|
||||||
@@ -120,27 +125,15 @@ namespace Content.Server.GameTicking.Presets
|
|||||||
DebugTools.AssertNotNull(mind.OwnedEntity);
|
DebugTools.AssertNotNull(mind.OwnedEntity);
|
||||||
|
|
||||||
var uplinkAccount = new UplinkAccount(mind.OwnedEntity!.Uid, StartingBalance);
|
var uplinkAccount = new UplinkAccount(mind.OwnedEntity!.Uid, StartingBalance);
|
||||||
var inventory = mind.OwnedEntity.GetComponent<InventoryComponent>();
|
_uplinkManager.AddNewAccount(uplinkAccount);
|
||||||
if (!inventory.TryGetSlotItem(EquipmentSlotDefines.Slots.IDCARD, out ItemComponent? pdaItem))
|
|
||||||
{
|
|
||||||
Logger.ErrorS("preset", "Failed getting pda for picked traitor.");
|
|
||||||
continue;
|
|
||||||
}
|
|
||||||
|
|
||||||
var pda = pdaItem.Owner;
|
if (!EntityManager.EntitySysManager.GetEntitySystem<UplinkSystem>()
|
||||||
|
.AddUplink(mind.OwnedEntity, uplinkAccount))
|
||||||
var pdaComponent = pda.GetComponent<PDAComponent>();
|
|
||||||
if (pdaComponent.IdSlotEmpty)
|
|
||||||
{
|
|
||||||
Logger.ErrorS("preset","PDA had no id for picked traitor");
|
|
||||||
continue;
|
continue;
|
||||||
}
|
|
||||||
|
|
||||||
var traitorRole = new TraitorRole(mind);
|
var traitorRole = new TraitorRole(mind);
|
||||||
|
|
||||||
mind.AddRole(traitorRole);
|
mind.AddRole(traitorRole);
|
||||||
_traitors.Add(traitorRole);
|
_traitors.Add(traitorRole);
|
||||||
pdaComponent.InitUplinkAccount(uplinkAccount);
|
|
||||||
}
|
}
|
||||||
|
|
||||||
var adjectives = _prototypeManager.Index<DatasetPrototype>("adjectives").Values;
|
var adjectives = _prototypeManager.Index<DatasetPrototype>("adjectives").Values;
|
||||||
|
|||||||
@@ -1,7 +1,6 @@
|
|||||||
using System;
|
using System;
|
||||||
using System.Collections.Generic;
|
using System.Collections.Generic;
|
||||||
using System.Linq;
|
using System.Linq;
|
||||||
using Content.Server.Atmos;
|
|
||||||
using Content.Server.Atmos.EntitySystems;
|
using Content.Server.Atmos.EntitySystems;
|
||||||
using Content.Server.Chat.Managers;
|
using Content.Server.Chat.Managers;
|
||||||
using Content.Server.GameTicking.Rules;
|
using Content.Server.GameTicking.Rules;
|
||||||
@@ -17,7 +16,6 @@ using Content.Shared.CCVar;
|
|||||||
using Content.Shared.Damage;
|
using Content.Shared.Damage;
|
||||||
using Content.Shared.Inventory;
|
using Content.Shared.Inventory;
|
||||||
using Content.Shared.MobState;
|
using Content.Shared.MobState;
|
||||||
using Content.Shared.PDA;
|
|
||||||
using Robust.Server.Player;
|
using Robust.Server.Player;
|
||||||
using Robust.Shared.Configuration;
|
using Robust.Shared.Configuration;
|
||||||
using Robust.Shared.GameObjects;
|
using Robust.Shared.GameObjects;
|
||||||
@@ -27,6 +25,11 @@ using Robust.Shared.Localization;
|
|||||||
using Robust.Shared.Log;
|
using Robust.Shared.Log;
|
||||||
using Robust.Shared.Map;
|
using Robust.Shared.Map;
|
||||||
using Robust.Shared.Random;
|
using Robust.Shared.Random;
|
||||||
|
using Content.Server.Traitor.Uplink.Components;
|
||||||
|
using Content.Shared.Traitor.Uplink;
|
||||||
|
using Content.Server.PDA.Managers;
|
||||||
|
using Content.Server.Traitor.Uplink;
|
||||||
|
using Content.Server.Traitor.Uplink.Systems;
|
||||||
using Content.Shared.Damage.Prototypes;
|
using Content.Shared.Damage.Prototypes;
|
||||||
|
|
||||||
namespace Content.Server.GameTicking.Presets
|
namespace Content.Server.GameTicking.Presets
|
||||||
@@ -40,6 +43,7 @@ namespace Content.Server.GameTicking.Presets
|
|||||||
[Dependency] private readonly IChatManager _chatManager = default!;
|
[Dependency] private readonly IChatManager _chatManager = default!;
|
||||||
[Dependency] private readonly IRobustRandom _robustRandom = default!;
|
[Dependency] private readonly IRobustRandom _robustRandom = default!;
|
||||||
[Dependency] private readonly IPrototypeManager _prototypeManager = default!;
|
[Dependency] private readonly IPrototypeManager _prototypeManager = default!;
|
||||||
|
[Dependency] private readonly IUplinkManager _uplinkManager = default!;
|
||||||
|
|
||||||
public string PDAPrototypeName => "CaptainPDA";
|
public string PDAPrototypeName => "CaptainPDA";
|
||||||
public string BeltPrototypeName => "ClothingBeltJanitorFilled";
|
public string BeltPrototypeName => "ClothingBeltJanitorFilled";
|
||||||
@@ -103,12 +107,16 @@ namespace Content.Server.GameTicking.Presets
|
|||||||
|
|
||||||
// Like normal traitors, they need access to a traitor account.
|
// Like normal traitors, they need access to a traitor account.
|
||||||
var uplinkAccount = new UplinkAccount(mind.OwnedEntity.Uid, startingBalance);
|
var uplinkAccount = new UplinkAccount(mind.OwnedEntity.Uid, startingBalance);
|
||||||
var pdaComponent = newPDA.GetComponent<PDAComponent>();
|
_uplinkManager.AddNewAccount(uplinkAccount);
|
||||||
pdaComponent.InitUplinkAccount(uplinkAccount);
|
_entityManager.EntitySysManager.GetEntitySystem<UplinkSystem>()
|
||||||
|
.AddUplink(mind.OwnedEntity, uplinkAccount, newPDA);
|
||||||
|
|
||||||
_allOriginalNames[uplinkAccount] = mind.OwnedEntity.Name;
|
_allOriginalNames[uplinkAccount] = mind.OwnedEntity.Name;
|
||||||
|
|
||||||
// The PDA needs to be marked with the correct owner.
|
// The PDA needs to be marked with the correct owner.
|
||||||
pdaComponent.SetPDAOwner(mind.OwnedEntity.Name);
|
var pda = newPDA.GetComponent<PDAComponent>();
|
||||||
|
_entityManager.EntitySysManager.GetEntitySystem<PDASystem>()
|
||||||
|
.SetOwner(pda, mind.OwnedEntity.Name);
|
||||||
newPDA.AddComponent<TraitorDeathMatchReliableOwnerTagComponent>().UserId = mind.UserId;
|
newPDA.AddComponent<TraitorDeathMatchReliableOwnerTagComponent>().UserId = mind.UserId;
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -217,14 +225,14 @@ namespace Content.Server.GameTicking.Presets
|
|||||||
{
|
{
|
||||||
var lines = new List<string>();
|
var lines = new List<string>();
|
||||||
lines.Add("traitor-death-match-end-round-description-first-line");
|
lines.Add("traitor-death-match-end-round-description-first-line");
|
||||||
foreach (var pda in _entityManager.EntityQuery<PDAComponent>())
|
foreach (var uplink in _entityManager.EntityQuery<UplinkComponent>(true))
|
||||||
{
|
{
|
||||||
var uplink = pda.SyndicateUplinkAccount;
|
var uplinkAcc = uplink.UplinkAccount;
|
||||||
if (uplink != null && _allOriginalNames.ContainsKey(uplink))
|
if (uplinkAcc != null && _allOriginalNames.ContainsKey(uplinkAcc))
|
||||||
{
|
{
|
||||||
lines.Add(Loc.GetString("traitor-death-match-end-round-description-entry",
|
lines.Add(Loc.GetString("traitor-death-match-end-round-description-entry",
|
||||||
("originalName", _allOriginalNames[uplink]),
|
("originalName", _allOriginalNames[uplinkAcc]),
|
||||||
("tcBalance", uplink.Balance)));
|
("tcBalance", uplinkAcc.Balance)));
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
return string.Join('\n', lines);
|
return string.Join('\n', lines);
|
||||||
|
|||||||
@@ -42,7 +42,7 @@ namespace Content.Server.IoC
|
|||||||
IoCManager.Register<RecipeManager, RecipeManager>();
|
IoCManager.Register<RecipeManager, RecipeManager>();
|
||||||
IoCManager.Register<AlertManager, AlertManager>();
|
IoCManager.Register<AlertManager, AlertManager>();
|
||||||
IoCManager.Register<ActionManager, ActionManager>();
|
IoCManager.Register<ActionManager, ActionManager>();
|
||||||
IoCManager.Register<IPDAUplinkManager,PDAUplinkManager>();
|
IoCManager.Register<IUplinkManager,UplinkManager>();
|
||||||
IoCManager.Register<INodeGroupFactory, NodeGroupFactory>();
|
IoCManager.Register<INodeGroupFactory, NodeGroupFactory>();
|
||||||
IoCManager.Register<BlackboardManager, BlackboardManager>();
|
IoCManager.Register<BlackboardManager, BlackboardManager>();
|
||||||
IoCManager.Register<ConsiderationsManager, ConsiderationsManager>();
|
IoCManager.Register<ConsiderationsManager, ConsiderationsManager>();
|
||||||
|
|||||||
@@ -0,0 +1,44 @@
|
|||||||
|
using Content.Server.Light.EntitySystems;
|
||||||
|
using Content.Shared.ActionBlocker;
|
||||||
|
using Content.Shared.Sound;
|
||||||
|
using Content.Shared.Verbs;
|
||||||
|
using Robust.Shared.GameObjects;
|
||||||
|
using Robust.Shared.Localization;
|
||||||
|
using Robust.Shared.Serialization.Manager.Attributes;
|
||||||
|
using Robust.Shared.ViewVariables;
|
||||||
|
|
||||||
|
namespace Content.Server.Light.Components
|
||||||
|
{
|
||||||
|
/// <summary>
|
||||||
|
/// This is simplified version of <see cref="HandheldLightComponent"/>.
|
||||||
|
/// It doesn't consume any power and can be toggle only by verb.
|
||||||
|
/// </summary>
|
||||||
|
[RegisterComponent]
|
||||||
|
public class UnpoweredFlashlightComponent : Component
|
||||||
|
{
|
||||||
|
public override string Name => "UnpoweredFlashlight";
|
||||||
|
|
||||||
|
[DataField("toggleFlashlightSound")]
|
||||||
|
public SoundSpecifier ToggleSound = new SoundPathSpecifier("/Audio/Items/flashlight_pda.ogg");
|
||||||
|
|
||||||
|
[ViewVariables] public bool LightOn = false;
|
||||||
|
|
||||||
|
[Verb]
|
||||||
|
public sealed class ToggleFlashlightVerb : Verb<UnpoweredFlashlightComponent>
|
||||||
|
{
|
||||||
|
protected override void GetData(IEntity user, UnpoweredFlashlightComponent component, VerbData data)
|
||||||
|
{
|
||||||
|
var canInteract = EntitySystem.Get<ActionBlockerSystem>().CanInteract(user);
|
||||||
|
|
||||||
|
data.Visibility = canInteract ? VerbVisibility.Visible : VerbVisibility.Invisible;
|
||||||
|
data.Text = Loc.GetString("toggle-flashlight-verb-get-data-text");
|
||||||
|
data.IconTexture = "/Textures/Interface/VerbIcons/light.svg.192dpi.png";
|
||||||
|
}
|
||||||
|
|
||||||
|
protected override void Activate(IEntity user, UnpoweredFlashlightComponent component)
|
||||||
|
{
|
||||||
|
EntitySystem.Get<UnpoweredFlashlightSystem>().ToggleLight(component);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
@@ -0,0 +1,31 @@
|
|||||||
|
using Content.Server.Light.Components;
|
||||||
|
using Content.Server.Light.Events;
|
||||||
|
using Content.Shared.Light;
|
||||||
|
using Robust.Server.GameObjects;
|
||||||
|
using Robust.Shared.Audio;
|
||||||
|
using Robust.Shared.GameObjects;
|
||||||
|
using Robust.Shared.Player;
|
||||||
|
using System;
|
||||||
|
|
||||||
|
namespace Content.Server.Light.EntitySystems
|
||||||
|
{
|
||||||
|
public class UnpoweredFlashlightSystem : EntitySystem
|
||||||
|
{
|
||||||
|
public void ToggleLight(UnpoweredFlashlightComponent flashlight)
|
||||||
|
{
|
||||||
|
if (!flashlight.Owner.TryGetComponent(out PointLightComponent? light))
|
||||||
|
return;
|
||||||
|
|
||||||
|
flashlight.LightOn = !flashlight.LightOn;
|
||||||
|
light.Enabled = flashlight.LightOn;
|
||||||
|
|
||||||
|
if (flashlight.Owner.TryGetComponent(out AppearanceComponent? appearance))
|
||||||
|
appearance.SetData(UnpoweredFlashlightVisuals.LightOn, flashlight.LightOn);
|
||||||
|
|
||||||
|
SoundSystem.Play(Filter.Pvs(light.Owner), flashlight.ToggleSound.GetSound(), flashlight.Owner);
|
||||||
|
|
||||||
|
RaiseLocalEvent(flashlight.Owner.Uid, new LightToggleEvent(flashlight.LightOn));
|
||||||
|
}
|
||||||
|
|
||||||
|
}
|
||||||
|
}
|
||||||
14
Content.Server/Light/Events/LightToggleEvent.cs
Normal file
14
Content.Server/Light/Events/LightToggleEvent.cs
Normal file
@@ -0,0 +1,14 @@
|
|||||||
|
using Robust.Shared.GameObjects;
|
||||||
|
|
||||||
|
namespace Content.Server.Light.Events
|
||||||
|
{
|
||||||
|
public class LightToggleEvent : EntityEventArgs
|
||||||
|
{
|
||||||
|
public bool IsOn;
|
||||||
|
|
||||||
|
public LightToggleEvent(bool isOn)
|
||||||
|
{
|
||||||
|
IsOn = isOn;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
@@ -1,443 +1,44 @@
|
|||||||
using System;
|
using System;
|
||||||
using System.Collections;
|
|
||||||
using System.Collections.Generic;
|
using System.Collections.Generic;
|
||||||
using System.Linq;
|
|
||||||
using System.Threading.Tasks;
|
|
||||||
using Content.Server.Access.Components;
|
using Content.Server.Access.Components;
|
||||||
using Content.Server.Hands.Components;
|
using Content.Shared.Containers.ItemSlots;
|
||||||
using Content.Server.Items;
|
|
||||||
using Content.Server.PDA.Managers;
|
|
||||||
using Content.Server.UserInterface;
|
|
||||||
using Content.Shared.ActionBlocker;
|
using Content.Shared.ActionBlocker;
|
||||||
using Content.Shared.Interaction;
|
|
||||||
using Content.Shared.PDA;
|
using Content.Shared.PDA;
|
||||||
using Content.Shared.Popups;
|
|
||||||
using Content.Shared.Sound;
|
|
||||||
using Content.Shared.Tag;
|
|
||||||
using Content.Shared.Verbs;
|
using Content.Shared.Verbs;
|
||||||
using Robust.Server.GameObjects;
|
|
||||||
using Robust.Shared.Audio;
|
|
||||||
using Robust.Shared.Containers;
|
|
||||||
using Robust.Shared.GameObjects;
|
using Robust.Shared.GameObjects;
|
||||||
using Robust.Shared.IoC;
|
|
||||||
using Robust.Shared.Localization;
|
using Robust.Shared.Localization;
|
||||||
using Robust.Shared.Player;
|
|
||||||
using Robust.Shared.Serialization.Manager.Attributes;
|
using Robust.Shared.Serialization.Manager.Attributes;
|
||||||
using Robust.Shared.ViewVariables;
|
using Robust.Shared.ViewVariables;
|
||||||
|
|
||||||
namespace Content.Server.PDA
|
namespace Content.Server.PDA
|
||||||
{
|
{
|
||||||
[RegisterComponent]
|
[RegisterComponent]
|
||||||
[ComponentReference(typeof(IActivate))]
|
|
||||||
[ComponentReference(typeof(IAccess))]
|
[ComponentReference(typeof(IAccess))]
|
||||||
public class PDAComponent : SharedPDAComponent, IInteractUsing, IActivate, IUse, IAccess, IMapInit
|
public class PDAComponent : Component, IAccess
|
||||||
{
|
{
|
||||||
[Dependency] private readonly IPDAUplinkManager _uplinkManager = default!;
|
public override string Name => "PDA";
|
||||||
[Dependency] private readonly IEntityManager _entityManager = default!;
|
|
||||||
|
|
||||||
[ViewVariables] private ContainerSlot _idSlot = default!;
|
public const string IDSlotName = "pda_id_slot";
|
||||||
[ViewVariables] private ContainerSlot _penSlot = default!;
|
public const string PenSlotName = "pda_pen_slot";
|
||||||
|
|
||||||
[ViewVariables] private bool _lightOn;
|
[ViewVariables] [DataField("idCard")] public string? StartingIdCard;
|
||||||
|
|
||||||
[ViewVariables] [DataField("idCard")] private string? _startingIdCard = "AssistantIDCard";
|
[ViewVariables] public IdCardComponent? ContainedID;
|
||||||
[ViewVariables] [DataField("pen")] private string? _startingPen = "Pen";
|
[ViewVariables] public bool PenInserted;
|
||||||
|
[ViewVariables] public bool FlashlightOn;
|
||||||
|
|
||||||
[ViewVariables] public string? OwnerName { get; private set; }
|
[ViewVariables] public string? OwnerName;
|
||||||
|
|
||||||
[ViewVariables] public IdCardComponent? ContainedID { get; private set; }
|
// TODO: Move me to ECS after Access refactoring
|
||||||
[ViewVariables] public bool IdSlotEmpty => _idSlot.ContainedEntity == null;
|
#region Acces Logic
|
||||||
[ViewVariables] public bool PenSlotEmpty => _penSlot.ContainedEntity == null;
|
[ViewVariables] private readonly PDAAccessSet _accessSet;
|
||||||
|
|
||||||
private UplinkAccount? _syndicateUplinkAccount;
|
|
||||||
|
|
||||||
[ViewVariables] public UplinkAccount? SyndicateUplinkAccount => _syndicateUplinkAccount;
|
|
||||||
|
|
||||||
[ViewVariables] private readonly PdaAccessSet _accessSet;
|
|
||||||
|
|
||||||
[ViewVariables] private BoundUserInterface? UserInterface => Owner.GetUIOrNull(PDAUiKey.Key);
|
|
||||||
|
|
||||||
[DataField("insertIdSound")] private SoundSpecifier _insertIdSound = new SoundPathSpecifier("/Audio/Weapons/Guns/MagIn/batrifle_magin.ogg");
|
|
||||||
[DataField("toggleFlashlightSound")] private SoundSpecifier _toggleFlashlightSound = new SoundPathSpecifier("/Audio/Items/flashlight_pda.ogg");
|
|
||||||
[DataField("ejectIdSound")] private SoundSpecifier _ejectIdSound = new SoundPathSpecifier("/Audio/Machines/id_swipe.ogg");
|
|
||||||
|
|
||||||
public PDAComponent()
|
public PDAComponent()
|
||||||
{
|
{
|
||||||
_accessSet = new PdaAccessSet(this);
|
_accessSet = new PDAAccessSet(this);
|
||||||
}
|
}
|
||||||
|
|
||||||
protected override void Initialize()
|
public ISet<string>? GetContainedAccess()
|
||||||
{
|
|
||||||
base.Initialize();
|
|
||||||
_idSlot = ContainerHelpers.EnsureContainer<ContainerSlot>(Owner, "pda_entity_container");
|
|
||||||
_penSlot = ContainerHelpers.EnsureContainer<ContainerSlot>(Owner, "pda_pen_slot");
|
|
||||||
|
|
||||||
if (UserInterface != null)
|
|
||||||
{
|
|
||||||
UserInterface.OnReceiveMessage += UserInterfaceOnReceiveMessage;
|
|
||||||
}
|
|
||||||
|
|
||||||
UpdatePDAAppearance();
|
|
||||||
}
|
|
||||||
|
|
||||||
public void MapInit()
|
|
||||||
{
|
|
||||||
if (!string.IsNullOrEmpty(_startingIdCard))
|
|
||||||
{
|
|
||||||
var idCard = _entityManager.SpawnEntity(_startingIdCard, Owner.Transform.Coordinates);
|
|
||||||
var idCardComponent = idCard.GetComponent<IdCardComponent>();
|
|
||||||
_idSlot.Insert(idCardComponent.Owner);
|
|
||||||
ContainedID = idCardComponent;
|
|
||||||
}
|
|
||||||
|
|
||||||
if (!string.IsNullOrEmpty(_startingPen))
|
|
||||||
{
|
|
||||||
var pen = _entityManager.SpawnEntity(_startingPen, Owner.Transform.Coordinates);
|
|
||||||
_penSlot.Insert(pen);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
private void UserInterfaceOnReceiveMessage(ServerBoundUserInterfaceMessage message)
|
|
||||||
{
|
|
||||||
switch (message.Message)
|
|
||||||
{
|
|
||||||
case PDARequestUpdateInterfaceMessage _:
|
|
||||||
{
|
|
||||||
UpdatePDAUserInterface();
|
|
||||||
break;
|
|
||||||
}
|
|
||||||
case PDAToggleFlashlightMessage _:
|
|
||||||
{
|
|
||||||
ToggleLight();
|
|
||||||
break;
|
|
||||||
}
|
|
||||||
|
|
||||||
case PDAEjectIDMessage _:
|
|
||||||
{
|
|
||||||
HandleIDEjection(message.Session.AttachedEntity!);
|
|
||||||
break;
|
|
||||||
}
|
|
||||||
|
|
||||||
case PDAEjectPenMessage _:
|
|
||||||
{
|
|
||||||
HandlePenEjection(message.Session.AttachedEntity!);
|
|
||||||
break;
|
|
||||||
}
|
|
||||||
|
|
||||||
case PDAUplinkBuyListingMessage buyMsg:
|
|
||||||
{
|
|
||||||
var player = message.Session.AttachedEntity;
|
|
||||||
if (player == null) break;
|
|
||||||
|
|
||||||
if (!_uplinkManager.TryPurchaseItem(_syndicateUplinkAccount, buyMsg.ItemId,
|
|
||||||
player.Transform.Coordinates, out var entity))
|
|
||||||
{
|
|
||||||
SendNetworkMessage(new PDAUplinkInsufficientFundsMessage(), message.Session.ConnectedClient);
|
|
||||||
break;
|
|
||||||
}
|
|
||||||
|
|
||||||
if (!player.TryGetComponent(out HandsComponent? hands) ||
|
|
||||||
!entity.TryGetComponent(out ItemComponent? item))
|
|
||||||
break;
|
|
||||||
|
|
||||||
hands.PutInHandOrDrop(item);
|
|
||||||
|
|
||||||
SendNetworkMessage(new PDAUplinkBuySuccessMessage(), message.Session.ConnectedClient);
|
|
||||||
break;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
private void UpdatePDAUserInterface()
|
|
||||||
{
|
|
||||||
var ownerInfo = new PDAIdInfoText
|
|
||||||
{
|
|
||||||
ActualOwnerName = OwnerName,
|
|
||||||
IdOwner = ContainedID?.FullName,
|
|
||||||
JobTitle = ContainedID?.JobTitle
|
|
||||||
};
|
|
||||||
|
|
||||||
//Do we have an account? If so provide the info.
|
|
||||||
if (_syndicateUplinkAccount != null)
|
|
||||||
{
|
|
||||||
var accData = new UplinkAccountData(_syndicateUplinkAccount.AccountHolder,
|
|
||||||
_syndicateUplinkAccount.Balance);
|
|
||||||
var listings = _uplinkManager.FetchListings.Values.ToArray();
|
|
||||||
UserInterface?.SetState(new PDAUpdateState(_lightOn, !PenSlotEmpty, ownerInfo, accData, listings));
|
|
||||||
}
|
|
||||||
else
|
|
||||||
{
|
|
||||||
UserInterface?.SetState(new PDAUpdateState(_lightOn, !PenSlotEmpty, ownerInfo));
|
|
||||||
}
|
|
||||||
|
|
||||||
UpdatePDAAppearance();
|
|
||||||
}
|
|
||||||
|
|
||||||
private void UpdatePDAAppearance()
|
|
||||||
{
|
|
||||||
if (Owner.TryGetComponent(out AppearanceComponent? appearance))
|
|
||||||
{
|
|
||||||
appearance.SetData(PDAVisuals.FlashlightLit, _lightOn);
|
|
||||||
appearance.SetData(PDAVisuals.IDCardInserted, !IdSlotEmpty);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
private bool TryInsertIdCard(InteractUsingEventArgs eventArgs, IdCardComponent idCardComponent)
|
|
||||||
{
|
|
||||||
var item = eventArgs.Using;
|
|
||||||
if (_idSlot.Contains(item))
|
|
||||||
return false;
|
|
||||||
|
|
||||||
if (!eventArgs.User.TryGetComponent(out IHandsComponent? hands))
|
|
||||||
{
|
|
||||||
Owner.PopupMessage(eventArgs.User, Loc.GetString("comp-pda-ui-try-insert-id-card-no-hands"));
|
|
||||||
return true;
|
|
||||||
}
|
|
||||||
|
|
||||||
IEntity? swap = null;
|
|
||||||
if (!IdSlotEmpty)
|
|
||||||
{
|
|
||||||
// Swap
|
|
||||||
swap = _idSlot.ContainedEntities[0];
|
|
||||||
}
|
|
||||||
|
|
||||||
if (!hands.Drop(item))
|
|
||||||
{
|
|
||||||
return true;
|
|
||||||
}
|
|
||||||
|
|
||||||
if (swap != null)
|
|
||||||
{
|
|
||||||
hands.PutInHand(swap.GetComponent<ItemComponent>());
|
|
||||||
}
|
|
||||||
|
|
||||||
InsertIdCard(idCardComponent);
|
|
||||||
|
|
||||||
UpdatePDAUserInterface();
|
|
||||||
return true;
|
|
||||||
}
|
|
||||||
|
|
||||||
private bool TryInsertPen(InteractUsingEventArgs eventArgs)
|
|
||||||
{
|
|
||||||
var item = eventArgs.Using;
|
|
||||||
if (_penSlot.Contains(item))
|
|
||||||
return false;
|
|
||||||
|
|
||||||
if (!eventArgs.User.TryGetComponent(out IHandsComponent? hands))
|
|
||||||
{
|
|
||||||
Owner.PopupMessage(eventArgs.User, Loc.GetString("comp-pda-ui-try-insert-pen-no-hands"));
|
|
||||||
return true;
|
|
||||||
}
|
|
||||||
|
|
||||||
IEntity? swap = null;
|
|
||||||
if (!PenSlotEmpty)
|
|
||||||
{
|
|
||||||
// Swap
|
|
||||||
swap = _penSlot.ContainedEntities[0];
|
|
||||||
}
|
|
||||||
|
|
||||||
if (!hands.Drop(item))
|
|
||||||
{
|
|
||||||
return true;
|
|
||||||
}
|
|
||||||
|
|
||||||
if (swap != null)
|
|
||||||
{
|
|
||||||
hands.PutInHand(swap.GetComponent<ItemComponent>());
|
|
||||||
}
|
|
||||||
|
|
||||||
// Insert Pen
|
|
||||||
_penSlot.Insert(item);
|
|
||||||
|
|
||||||
UpdatePDAUserInterface();
|
|
||||||
return true;
|
|
||||||
}
|
|
||||||
|
|
||||||
async Task<bool> IInteractUsing.InteractUsing(InteractUsingEventArgs eventArgs)
|
|
||||||
{
|
|
||||||
var item = eventArgs.Using;
|
|
||||||
|
|
||||||
if (item.TryGetComponent<IdCardComponent>(out var idCardComponent))
|
|
||||||
{
|
|
||||||
return TryInsertIdCard(eventArgs, idCardComponent);
|
|
||||||
}
|
|
||||||
|
|
||||||
if (item.HasTag("Write"))
|
|
||||||
{
|
|
||||||
return TryInsertPen(eventArgs);
|
|
||||||
}
|
|
||||||
|
|
||||||
return false;
|
|
||||||
}
|
|
||||||
|
|
||||||
void IActivate.Activate(ActivateEventArgs eventArgs)
|
|
||||||
{
|
|
||||||
if (!eventArgs.User.TryGetComponent(out ActorComponent? actor))
|
|
||||||
{
|
|
||||||
return;
|
|
||||||
}
|
|
||||||
|
|
||||||
UserInterface?.Toggle(actor.PlayerSession);
|
|
||||||
UpdatePDAAppearance();
|
|
||||||
}
|
|
||||||
|
|
||||||
bool IUse.UseEntity(UseEntityEventArgs eventArgs)
|
|
||||||
{
|
|
||||||
if (!eventArgs.User.TryGetComponent(out ActorComponent? actor))
|
|
||||||
{
|
|
||||||
return false;
|
|
||||||
}
|
|
||||||
|
|
||||||
UserInterface?.Toggle(actor.PlayerSession);
|
|
||||||
UpdatePDAAppearance();
|
|
||||||
return true;
|
|
||||||
}
|
|
||||||
|
|
||||||
public void SetPDAOwner(string name)
|
|
||||||
{
|
|
||||||
OwnerName = name;
|
|
||||||
UpdatePDAUserInterface();
|
|
||||||
}
|
|
||||||
|
|
||||||
public void InsertIdCard(IdCardComponent card)
|
|
||||||
{
|
|
||||||
_idSlot.Insert(card.Owner);
|
|
||||||
ContainedID = card;
|
|
||||||
SoundSystem.Play(Filter.Pvs(Owner), _insertIdSound.GetSound(), Owner);
|
|
||||||
}
|
|
||||||
|
|
||||||
/// <summary>
|
|
||||||
/// Initialize the PDA's syndicate uplink account.
|
|
||||||
/// </summary>
|
|
||||||
/// <param name="acc"></param>
|
|
||||||
public void InitUplinkAccount(UplinkAccount acc)
|
|
||||||
{
|
|
||||||
_syndicateUplinkAccount = acc;
|
|
||||||
_uplinkManager.AddNewAccount(_syndicateUplinkAccount);
|
|
||||||
|
|
||||||
_syndicateUplinkAccount.BalanceChanged += account =>
|
|
||||||
{
|
|
||||||
UpdatePDAUserInterface();
|
|
||||||
};
|
|
||||||
|
|
||||||
UpdatePDAUserInterface();
|
|
||||||
}
|
|
||||||
|
|
||||||
private void ToggleLight()
|
|
||||||
{
|
|
||||||
if (!Owner.TryGetComponent(out PointLightComponent? light))
|
|
||||||
{
|
|
||||||
return;
|
|
||||||
}
|
|
||||||
|
|
||||||
_lightOn = !_lightOn;
|
|
||||||
light.Enabled = _lightOn;
|
|
||||||
SoundSystem.Play(Filter.Pvs(Owner), _toggleFlashlightSound.GetSound(), Owner);
|
|
||||||
UpdatePDAUserInterface();
|
|
||||||
}
|
|
||||||
|
|
||||||
private void HandleIDEjection(IEntity pdaUser)
|
|
||||||
{
|
|
||||||
if (ContainedID == null)
|
|
||||||
{
|
|
||||||
return;
|
|
||||||
}
|
|
||||||
|
|
||||||
var cardEntity = ContainedID.Owner;
|
|
||||||
_idSlot.Remove(cardEntity);
|
|
||||||
|
|
||||||
var hands = pdaUser.GetComponent<HandsComponent>();
|
|
||||||
var cardItemComponent = cardEntity.GetComponent<ItemComponent>();
|
|
||||||
hands.PutInHandOrDrop(cardItemComponent);
|
|
||||||
ContainedID = null;
|
|
||||||
|
|
||||||
SoundSystem.Play(Filter.Pvs(Owner), _ejectIdSound.GetSound(), Owner);
|
|
||||||
UpdatePDAUserInterface();
|
|
||||||
}
|
|
||||||
|
|
||||||
private void HandlePenEjection(IEntity pdaUser)
|
|
||||||
{
|
|
||||||
if (PenSlotEmpty)
|
|
||||||
return;
|
|
||||||
|
|
||||||
var pen = _penSlot.ContainedEntities[0];
|
|
||||||
_penSlot.Remove(pen);
|
|
||||||
|
|
||||||
var hands = pdaUser.GetComponent<HandsComponent>();
|
|
||||||
var itemComponent = pen.GetComponent<ItemComponent>();
|
|
||||||
hands.PutInHandOrDrop(itemComponent);
|
|
||||||
|
|
||||||
UpdatePDAUserInterface();
|
|
||||||
}
|
|
||||||
|
|
||||||
[Verb]
|
|
||||||
public sealed class EjectIDVerb : Verb<PDAComponent>
|
|
||||||
{
|
|
||||||
public override bool AlternativeInteraction => true;
|
|
||||||
|
|
||||||
protected override void GetData(IEntity user, PDAComponent component, VerbData data)
|
|
||||||
{
|
|
||||||
if (!EntitySystem.Get<ActionBlockerSystem>().CanInteract(user))
|
|
||||||
{
|
|
||||||
data.Visibility = VerbVisibility.Invisible;
|
|
||||||
return;
|
|
||||||
}
|
|
||||||
|
|
||||||
data.Text = Loc.GetString("eject-id-verb-get-data-text");
|
|
||||||
data.Visibility = component.IdSlotEmpty ? VerbVisibility.Invisible : VerbVisibility.Visible;
|
|
||||||
data.IconTexture = "/Textures/Interface/VerbIcons/eject.svg.192dpi.png";
|
|
||||||
}
|
|
||||||
|
|
||||||
protected override void Activate(IEntity user, PDAComponent component)
|
|
||||||
{
|
|
||||||
component.HandleIDEjection(user);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
[Verb]
|
|
||||||
public sealed class EjectPenVerb : Verb<PDAComponent>
|
|
||||||
{
|
|
||||||
protected override void GetData(IEntity user, PDAComponent component, VerbData data)
|
|
||||||
{
|
|
||||||
if (!EntitySystem.Get<ActionBlockerSystem>().CanInteract(user))
|
|
||||||
{
|
|
||||||
data.Visibility = VerbVisibility.Invisible;
|
|
||||||
return;
|
|
||||||
}
|
|
||||||
|
|
||||||
data.Text = Loc.GetString("eject-pen-verb-get-data-text");
|
|
||||||
data.Visibility = component.PenSlotEmpty ? VerbVisibility.Invisible : VerbVisibility.Visible;
|
|
||||||
data.IconTexture = "/Textures/Interface/VerbIcons/eject.svg.192dpi.png";
|
|
||||||
}
|
|
||||||
|
|
||||||
protected override void Activate(IEntity user, PDAComponent component)
|
|
||||||
{
|
|
||||||
component.HandlePenEjection(user);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
[Verb]
|
|
||||||
public sealed class ToggleFlashlightVerb : Verb<PDAComponent>
|
|
||||||
{
|
|
||||||
protected override void GetData(IEntity user, PDAComponent component, VerbData data)
|
|
||||||
{
|
|
||||||
if (!EntitySystem.Get<ActionBlockerSystem>().CanInteract(user))
|
|
||||||
{
|
|
||||||
data.Visibility = VerbVisibility.Invisible;
|
|
||||||
return;
|
|
||||||
}
|
|
||||||
|
|
||||||
data.Text = Loc.GetString("toggle-flashlight-verb-get-data-text");
|
|
||||||
data.IconTexture = "/Textures/Interface/VerbIcons/light.svg.192dpi.png";
|
|
||||||
}
|
|
||||||
|
|
||||||
protected override void Activate(IEntity user, PDAComponent component)
|
|
||||||
{
|
|
||||||
component.ToggleLight();
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
private ISet<string>? GetContainedAccess()
|
|
||||||
{
|
{
|
||||||
return ContainedID?.Owner?.GetComponent<AccessComponent>()?.Tags;
|
return ContainedID?.Owner?.GetComponent<AccessComponent>()?.Tags;
|
||||||
}
|
}
|
||||||
@@ -450,117 +51,77 @@ namespace Content.Server.PDA
|
|||||||
{
|
{
|
||||||
throw new NotSupportedException("PDA access list is read-only.");
|
throw new NotSupportedException("PDA access list is read-only.");
|
||||||
}
|
}
|
||||||
|
#endregion
|
||||||
|
|
||||||
private sealed class PdaAccessSet : ISet<string>
|
// TODO: replace me with dynamic verbs for ItemSlotsSystem
|
||||||
|
#region Verbs
|
||||||
|
[Verb]
|
||||||
|
public sealed class EjectPenVerb : Verb<PDAComponent>
|
||||||
{
|
{
|
||||||
private readonly PDAComponent _pdaComponent;
|
protected override void GetData(IEntity user, PDAComponent component, VerbData data)
|
||||||
private static readonly HashSet<string> EmptySet = new();
|
|
||||||
|
|
||||||
public PdaAccessSet(PDAComponent pdaComponent)
|
|
||||||
{
|
{
|
||||||
_pdaComponent = pdaComponent;
|
data.Visibility = VerbVisibility.Invisible;
|
||||||
|
|
||||||
|
if (!component.Owner.TryGetComponent(out SharedItemSlotsComponent? slots))
|
||||||
|
return;
|
||||||
|
|
||||||
|
if (!EntitySystem.Get<ActionBlockerSystem>().CanInteract(user))
|
||||||
|
return;
|
||||||
|
|
||||||
|
var item = EntitySystem.Get<SharedItemSlotsSystem>().PeekItemInSlot(slots, PenSlotName);
|
||||||
|
if (item == null)
|
||||||
|
return;
|
||||||
|
|
||||||
|
data.Visibility = VerbVisibility.Visible;
|
||||||
|
data.Text = Loc.GetString("eject-item-verb-text-default", ("item", item.Name));
|
||||||
|
data.IconTexture = "/Textures/Interface/VerbIcons/eject.svg.192dpi.png";
|
||||||
}
|
}
|
||||||
|
|
||||||
public IEnumerator<string> GetEnumerator()
|
protected override void Activate(IEntity user, PDAComponent pda)
|
||||||
{
|
{
|
||||||
var contained = _pdaComponent.GetContainedAccess() ?? EmptySet;
|
var entityManager = pda.Owner.EntityManager;
|
||||||
return contained.GetEnumerator();
|
if (pda.Owner.TryGetComponent(out SharedItemSlotsComponent? itemSlots))
|
||||||
|
{
|
||||||
|
entityManager.EntitySysManager.GetEntitySystem<SharedItemSlotsSystem>().
|
||||||
|
TryEjectContent(itemSlots, PenSlotName, user);
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
IEnumerator IEnumerable.GetEnumerator()
|
|
||||||
{
|
|
||||||
return GetEnumerator();
|
|
||||||
}
|
|
||||||
|
|
||||||
void ICollection<string>.Add(string item)
|
|
||||||
{
|
|
||||||
throw new NotSupportedException("PDA access list is read-only.");
|
|
||||||
}
|
|
||||||
|
|
||||||
public void ExceptWith(IEnumerable<string> other)
|
|
||||||
{
|
|
||||||
throw new NotSupportedException("PDA access list is read-only.");
|
|
||||||
}
|
|
||||||
|
|
||||||
public void IntersectWith(IEnumerable<string> other)
|
|
||||||
{
|
|
||||||
throw new NotSupportedException("PDA access list is read-only.");
|
|
||||||
}
|
|
||||||
|
|
||||||
public bool IsProperSubsetOf(IEnumerable<string> other)
|
|
||||||
{
|
|
||||||
var set = _pdaComponent.GetContainedAccess() ?? EmptySet;
|
|
||||||
return set.IsProperSubsetOf(other);
|
|
||||||
}
|
|
||||||
|
|
||||||
public bool IsProperSupersetOf(IEnumerable<string> other)
|
|
||||||
{
|
|
||||||
var set = _pdaComponent.GetContainedAccess() ?? EmptySet;
|
|
||||||
return set.IsProperSupersetOf(other);
|
|
||||||
}
|
|
||||||
|
|
||||||
public bool IsSubsetOf(IEnumerable<string> other)
|
|
||||||
{
|
|
||||||
var set = _pdaComponent.GetContainedAccess() ?? EmptySet;
|
|
||||||
return set.IsSubsetOf(other);
|
|
||||||
}
|
|
||||||
|
|
||||||
public bool IsSupersetOf(IEnumerable<string> other)
|
|
||||||
{
|
|
||||||
var set = _pdaComponent.GetContainedAccess() ?? EmptySet;
|
|
||||||
return set.IsSupersetOf(other);
|
|
||||||
}
|
|
||||||
|
|
||||||
public bool Overlaps(IEnumerable<string> other)
|
|
||||||
{
|
|
||||||
var set = _pdaComponent.GetContainedAccess() ?? EmptySet;
|
|
||||||
return set.Overlaps(other);
|
|
||||||
}
|
|
||||||
|
|
||||||
public bool SetEquals(IEnumerable<string> other)
|
|
||||||
{
|
|
||||||
var set = _pdaComponent.GetContainedAccess() ?? EmptySet;
|
|
||||||
return set.SetEquals(other);
|
|
||||||
}
|
|
||||||
|
|
||||||
public void SymmetricExceptWith(IEnumerable<string> other)
|
|
||||||
{
|
|
||||||
throw new NotSupportedException("PDA access list is read-only.");
|
|
||||||
}
|
|
||||||
|
|
||||||
public void UnionWith(IEnumerable<string> other)
|
|
||||||
{
|
|
||||||
throw new NotSupportedException("PDA access list is read-only.");
|
|
||||||
}
|
|
||||||
|
|
||||||
bool ISet<string>.Add(string item)
|
|
||||||
{
|
|
||||||
throw new NotSupportedException("PDA access list is read-only.");
|
|
||||||
}
|
|
||||||
|
|
||||||
public void Clear()
|
|
||||||
{
|
|
||||||
throw new NotSupportedException("PDA access list is read-only.");
|
|
||||||
}
|
|
||||||
|
|
||||||
public bool Contains(string item)
|
|
||||||
{
|
|
||||||
return _pdaComponent.GetContainedAccess()?.Contains(item) ?? false;
|
|
||||||
}
|
|
||||||
|
|
||||||
public void CopyTo(string[] array, int arrayIndex)
|
|
||||||
{
|
|
||||||
var set = _pdaComponent.GetContainedAccess() ?? EmptySet;
|
|
||||||
set.CopyTo(array, arrayIndex);
|
|
||||||
}
|
|
||||||
|
|
||||||
public bool Remove(string item)
|
|
||||||
{
|
|
||||||
throw new NotSupportedException("PDA access list is read-only.");
|
|
||||||
}
|
|
||||||
|
|
||||||
public int Count => _pdaComponent.GetContainedAccess()?.Count ?? 0;
|
|
||||||
public bool IsReadOnly => true;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
|
[Verb]
|
||||||
|
public sealed class EjectIDVerb : Verb<PDAComponent>
|
||||||
|
{
|
||||||
|
public override bool AlternativeInteraction => true;
|
||||||
|
|
||||||
|
protected override void GetData(IEntity user, PDAComponent component, VerbData data)
|
||||||
|
{
|
||||||
|
data.Visibility = VerbVisibility.Invisible;
|
||||||
|
|
||||||
|
if (!component.Owner.TryGetComponent(out SharedItemSlotsComponent? slots))
|
||||||
|
return;
|
||||||
|
|
||||||
|
if (!EntitySystem.Get<ActionBlockerSystem>().CanInteract(user))
|
||||||
|
return;
|
||||||
|
|
||||||
|
var item = EntitySystem.Get<SharedItemSlotsSystem>().PeekItemInSlot(slots, IDSlotName);
|
||||||
|
if (item == null)
|
||||||
|
return;
|
||||||
|
|
||||||
|
data.Visibility = VerbVisibility.Visible;
|
||||||
|
data.Text = Loc.GetString("eject-item-verb-text-default", ("item", item.Name));
|
||||||
|
data.IconTexture = "/Textures/Interface/VerbIcons/eject.svg.192dpi.png";
|
||||||
|
}
|
||||||
|
|
||||||
|
protected override void Activate(IEntity user, PDAComponent pda)
|
||||||
|
{
|
||||||
|
var entityManager = pda.Owner.EntityManager;
|
||||||
|
if (pda.Owner.TryGetComponent(out SharedItemSlotsComponent? itemSlots))
|
||||||
|
{
|
||||||
|
entityManager.EntitySysManager.GetEntitySystem<SharedItemSlotsSystem>().
|
||||||
|
TryEjectContent(itemSlots, IDSlotName, user);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
#endregion
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
183
Content.Server/PDA/PDASystem.cs
Normal file
183
Content.Server/PDA/PDASystem.cs
Normal file
@@ -0,0 +1,183 @@
|
|||||||
|
using Content.Server.Access.Components;
|
||||||
|
using Content.Shared.Containers.ItemSlots;
|
||||||
|
using Content.Server.Light.Components;
|
||||||
|
using Content.Server.Light.EntitySystems;
|
||||||
|
using Content.Server.Light.Events;
|
||||||
|
using Content.Server.Traitor.Uplink;
|
||||||
|
using Content.Server.Traitor.Uplink.Components;
|
||||||
|
using Content.Server.Traitor.Uplink.Systems;
|
||||||
|
using Content.Server.UserInterface;
|
||||||
|
using Content.Shared.Interaction;
|
||||||
|
using Content.Shared.PDA;
|
||||||
|
using Robust.Server.GameObjects;
|
||||||
|
using Robust.Shared.GameObjects;
|
||||||
|
using Robust.Shared.IoC;
|
||||||
|
|
||||||
|
namespace Content.Server.PDA
|
||||||
|
{
|
||||||
|
public class PDASystem : EntitySystem
|
||||||
|
{
|
||||||
|
[Dependency] private readonly SharedItemSlotsSystem _slotsSystem = default!;
|
||||||
|
[Dependency] private readonly UplinkSystem _uplinkSystem = default!;
|
||||||
|
[Dependency] private readonly UnpoweredFlashlightSystem _unpoweredFlashlight = default!;
|
||||||
|
|
||||||
|
public override void Initialize()
|
||||||
|
{
|
||||||
|
base.Initialize();
|
||||||
|
SubscribeLocalEvent<PDAComponent, ComponentInit>(OnComponentInit);
|
||||||
|
SubscribeLocalEvent<PDAComponent, MapInitEvent>(OnMapInit);
|
||||||
|
SubscribeLocalEvent<PDAComponent, ActivateInWorldEvent>(OnActivateInWorld);
|
||||||
|
SubscribeLocalEvent<PDAComponent, UseInHandEvent>(OnUse);
|
||||||
|
SubscribeLocalEvent<PDAComponent, ItemSlotChanged>(OnItemSlotChanged);
|
||||||
|
SubscribeLocalEvent<PDAComponent, LightToggleEvent>(OnLightToggle);
|
||||||
|
|
||||||
|
SubscribeLocalEvent<PDAComponent, UplinkInitEvent>(OnUplinkInit);
|
||||||
|
SubscribeLocalEvent<PDAComponent, UplinkRemovedEvent>(OnUplinkRemoved);
|
||||||
|
}
|
||||||
|
|
||||||
|
private void OnComponentInit(EntityUid uid, PDAComponent pda, ComponentInit args)
|
||||||
|
{
|
||||||
|
var ui = pda.Owner.GetUIOrNull(PDAUiKey.Key);
|
||||||
|
if (ui != null)
|
||||||
|
ui.OnReceiveMessage += (msg) => OnUIMessage(pda, msg);
|
||||||
|
|
||||||
|
UpdatePDAAppearance(pda);
|
||||||
|
}
|
||||||
|
|
||||||
|
private void OnMapInit(EntityUid uid, PDAComponent pda, MapInitEvent args)
|
||||||
|
{
|
||||||
|
// try to place ID inside item slot
|
||||||
|
if (!string.IsNullOrEmpty(pda.StartingIdCard))
|
||||||
|
{
|
||||||
|
// if pda prototype doesn't have slots, ID will drop down on ground
|
||||||
|
var idCard = EntityManager.SpawnEntity(pda.StartingIdCard, pda.Owner.Transform.Coordinates);
|
||||||
|
if (EntityManager.TryGetComponent(uid, out SharedItemSlotsComponent? itemSlots))
|
||||||
|
_slotsSystem.TryInsertContent(itemSlots, idCard, PDAComponent.IDSlotName);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
private void OnUse(EntityUid uid, PDAComponent pda, UseInHandEvent args)
|
||||||
|
{
|
||||||
|
if (args.Handled)
|
||||||
|
return;
|
||||||
|
args.Handled = OpenUI(pda, args.User);
|
||||||
|
}
|
||||||
|
|
||||||
|
private void OnActivateInWorld(EntityUid uid, PDAComponent pda, ActivateInWorldEvent args)
|
||||||
|
{
|
||||||
|
if (args.Handled)
|
||||||
|
return;
|
||||||
|
args.Handled = OpenUI(pda, args.User);
|
||||||
|
}
|
||||||
|
|
||||||
|
private void OnItemSlotChanged(EntityUid uid, PDAComponent pda, ItemSlotChanged args)
|
||||||
|
{
|
||||||
|
// check if ID slot changed
|
||||||
|
if (args.SlotName == PDAComponent.IDSlotName)
|
||||||
|
{
|
||||||
|
var item = args.ContainedItem;
|
||||||
|
if (item == null || !EntityManager.TryGetComponent(item.Value, out IdCardComponent ? idCard))
|
||||||
|
pda.ContainedID = null;
|
||||||
|
else
|
||||||
|
pda.ContainedID = idCard;
|
||||||
|
}
|
||||||
|
else if (args.SlotName == PDAComponent.PenSlotName)
|
||||||
|
{
|
||||||
|
var item = args.ContainedItem;
|
||||||
|
pda.PenInserted = item != null;
|
||||||
|
}
|
||||||
|
|
||||||
|
UpdatePDAAppearance(pda);
|
||||||
|
UpdatePDAUserInterface(pda);
|
||||||
|
}
|
||||||
|
|
||||||
|
private void OnLightToggle(EntityUid uid, PDAComponent pda, LightToggleEvent args)
|
||||||
|
{
|
||||||
|
pda.FlashlightOn = args.IsOn;
|
||||||
|
UpdatePDAUserInterface(pda);
|
||||||
|
}
|
||||||
|
|
||||||
|
public void SetOwner(PDAComponent pda, string ownerName)
|
||||||
|
{
|
||||||
|
pda.OwnerName = ownerName;
|
||||||
|
UpdatePDAUserInterface(pda);
|
||||||
|
}
|
||||||
|
|
||||||
|
private void OnUplinkInit(EntityUid uid, PDAComponent pda, UplinkInitEvent args)
|
||||||
|
{
|
||||||
|
UpdatePDAUserInterface(pda);
|
||||||
|
}
|
||||||
|
|
||||||
|
private void OnUplinkRemoved(EntityUid uid, PDAComponent pda, UplinkRemovedEvent args)
|
||||||
|
{
|
||||||
|
UpdatePDAUserInterface(pda);
|
||||||
|
}
|
||||||
|
|
||||||
|
private bool OpenUI(PDAComponent pda, IEntity user)
|
||||||
|
{
|
||||||
|
if (!user.TryGetComponent(out ActorComponent? actor))
|
||||||
|
return false;
|
||||||
|
|
||||||
|
var ui = pda.Owner.GetUIOrNull(PDAUiKey.Key);
|
||||||
|
ui?.Toggle(actor.PlayerSession);
|
||||||
|
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
|
||||||
|
private void UpdatePDAAppearance(PDAComponent pda)
|
||||||
|
{
|
||||||
|
if (pda.Owner.TryGetComponent(out AppearanceComponent? appearance))
|
||||||
|
appearance.SetData(PDAVisuals.IDCardInserted, pda.ContainedID != null);
|
||||||
|
}
|
||||||
|
|
||||||
|
private void UpdatePDAUserInterface(PDAComponent pda)
|
||||||
|
{
|
||||||
|
var ownerInfo = new PDAIdInfoText
|
||||||
|
{
|
||||||
|
ActualOwnerName = pda.OwnerName,
|
||||||
|
IdOwner = pda.ContainedID?.FullName,
|
||||||
|
JobTitle = pda.ContainedID?.JobTitle
|
||||||
|
};
|
||||||
|
|
||||||
|
var hasUplink = pda.Owner.HasComponent<UplinkComponent>();
|
||||||
|
|
||||||
|
var ui = pda.Owner.GetUIOrNull(PDAUiKey.Key);
|
||||||
|
ui?.SetState(new PDAUpdateState(pda.FlashlightOn, pda.PenInserted, ownerInfo, hasUplink));
|
||||||
|
}
|
||||||
|
|
||||||
|
private void OnUIMessage(PDAComponent pda, ServerBoundUserInterfaceMessage msg)
|
||||||
|
{
|
||||||
|
switch (msg.Message)
|
||||||
|
{
|
||||||
|
case PDARequestUpdateInterfaceMessage _:
|
||||||
|
UpdatePDAUserInterface(pda);
|
||||||
|
break;
|
||||||
|
case PDAToggleFlashlightMessage _:
|
||||||
|
{
|
||||||
|
if (pda.Owner.TryGetComponent(out UnpoweredFlashlightComponent? flashlight))
|
||||||
|
_unpoweredFlashlight.ToggleLight(flashlight);
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
|
||||||
|
case PDAEjectIDMessage _:
|
||||||
|
{
|
||||||
|
if (pda.Owner.TryGetComponent(out SharedItemSlotsComponent? itemSlots))
|
||||||
|
_slotsSystem.TryEjectContent(itemSlots, PDAComponent.IDSlotName, msg.Session.AttachedEntity);
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
case PDAEjectPenMessage _:
|
||||||
|
{
|
||||||
|
if (pda.Owner.TryGetComponent(out SharedItemSlotsComponent? itemSlots))
|
||||||
|
_slotsSystem.TryEjectContent(itemSlots, PDAComponent.PenSlotName, msg.Session.AttachedEntity);
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
case PDAShowUplinkMessage _:
|
||||||
|
{
|
||||||
|
if (pda.Owner.TryGetComponent(out UplinkComponent? uplink))
|
||||||
|
_uplinkSystem.ToggleUplinkUI(uplink, msg.Session);
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
118
Content.Server/PDA/PdaAccessSet.cs
Normal file
118
Content.Server/PDA/PdaAccessSet.cs
Normal file
@@ -0,0 +1,118 @@
|
|||||||
|
using System;
|
||||||
|
using System.Collections;
|
||||||
|
using System.Collections.Generic;
|
||||||
|
|
||||||
|
namespace Content.Server.PDA
|
||||||
|
{
|
||||||
|
public sealed class PDAAccessSet : ISet<string>
|
||||||
|
{
|
||||||
|
private readonly PDAComponent _pdaComponent;
|
||||||
|
private static readonly HashSet<string> EmptySet = new();
|
||||||
|
|
||||||
|
public PDAAccessSet(PDAComponent pdaComponent)
|
||||||
|
{
|
||||||
|
_pdaComponent = pdaComponent;
|
||||||
|
}
|
||||||
|
|
||||||
|
public IEnumerator<string> GetEnumerator()
|
||||||
|
{
|
||||||
|
var contained = _pdaComponent.GetContainedAccess() ?? EmptySet;
|
||||||
|
return contained.GetEnumerator();
|
||||||
|
}
|
||||||
|
|
||||||
|
IEnumerator IEnumerable.GetEnumerator()
|
||||||
|
{
|
||||||
|
return GetEnumerator();
|
||||||
|
}
|
||||||
|
|
||||||
|
void ICollection<string>.Add(string item)
|
||||||
|
{
|
||||||
|
throw new NotSupportedException("PDA access list is read-only.");
|
||||||
|
}
|
||||||
|
|
||||||
|
public void ExceptWith(IEnumerable<string> other)
|
||||||
|
{
|
||||||
|
throw new NotSupportedException("PDA access list is read-only.");
|
||||||
|
}
|
||||||
|
|
||||||
|
public void IntersectWith(IEnumerable<string> other)
|
||||||
|
{
|
||||||
|
throw new NotSupportedException("PDA access list is read-only.");
|
||||||
|
}
|
||||||
|
|
||||||
|
public bool IsProperSubsetOf(IEnumerable<string> other)
|
||||||
|
{
|
||||||
|
var set = _pdaComponent.GetContainedAccess() ?? EmptySet;
|
||||||
|
return set.IsProperSubsetOf(other);
|
||||||
|
}
|
||||||
|
|
||||||
|
public bool IsProperSupersetOf(IEnumerable<string> other)
|
||||||
|
{
|
||||||
|
var set = _pdaComponent.GetContainedAccess() ?? EmptySet;
|
||||||
|
return set.IsProperSupersetOf(other);
|
||||||
|
}
|
||||||
|
|
||||||
|
public bool IsSubsetOf(IEnumerable<string> other)
|
||||||
|
{
|
||||||
|
var set = _pdaComponent.GetContainedAccess() ?? EmptySet;
|
||||||
|
return set.IsSubsetOf(other);
|
||||||
|
}
|
||||||
|
|
||||||
|
public bool IsSupersetOf(IEnumerable<string> other)
|
||||||
|
{
|
||||||
|
var set = _pdaComponent.GetContainedAccess() ?? EmptySet;
|
||||||
|
return set.IsSupersetOf(other);
|
||||||
|
}
|
||||||
|
|
||||||
|
public bool Overlaps(IEnumerable<string> other)
|
||||||
|
{
|
||||||
|
var set = _pdaComponent.GetContainedAccess() ?? EmptySet;
|
||||||
|
return set.Overlaps(other);
|
||||||
|
}
|
||||||
|
|
||||||
|
public bool SetEquals(IEnumerable<string> other)
|
||||||
|
{
|
||||||
|
var set = _pdaComponent.GetContainedAccess() ?? EmptySet;
|
||||||
|
return set.SetEquals(other);
|
||||||
|
}
|
||||||
|
|
||||||
|
public void SymmetricExceptWith(IEnumerable<string> other)
|
||||||
|
{
|
||||||
|
throw new NotSupportedException("PDA access list is read-only.");
|
||||||
|
}
|
||||||
|
|
||||||
|
public void UnionWith(IEnumerable<string> other)
|
||||||
|
{
|
||||||
|
throw new NotSupportedException("PDA access list is read-only.");
|
||||||
|
}
|
||||||
|
|
||||||
|
bool ISet<string>.Add(string item)
|
||||||
|
{
|
||||||
|
throw new NotSupportedException("PDA access list is read-only.");
|
||||||
|
}
|
||||||
|
|
||||||
|
public void Clear()
|
||||||
|
{
|
||||||
|
throw new NotSupportedException("PDA access list is read-only.");
|
||||||
|
}
|
||||||
|
|
||||||
|
public bool Contains(string item)
|
||||||
|
{
|
||||||
|
return _pdaComponent.GetContainedAccess()?.Contains(item) ?? false;
|
||||||
|
}
|
||||||
|
|
||||||
|
public void CopyTo(string[] array, int arrayIndex)
|
||||||
|
{
|
||||||
|
var set = _pdaComponent.GetContainedAccess() ?? EmptySet;
|
||||||
|
set.CopyTo(array, arrayIndex);
|
||||||
|
}
|
||||||
|
|
||||||
|
public bool Remove(string item)
|
||||||
|
{
|
||||||
|
throw new NotSupportedException("PDA access list is read-only.");
|
||||||
|
}
|
||||||
|
|
||||||
|
public int Count => _pdaComponent.GetContainedAccess()?.Count ?? 0;
|
||||||
|
public bool IsReadOnly => true;
|
||||||
|
}
|
||||||
|
}
|
||||||
@@ -1,5 +1,6 @@
|
|||||||
using System.Linq;
|
using System.Linq;
|
||||||
using Content.Server.Access.Components;
|
using Content.Server.Access.Components;
|
||||||
|
using Content.Shared.Containers.ItemSlots;
|
||||||
using Content.Server.GameTicking;
|
using Content.Server.GameTicking;
|
||||||
using Content.Server.Hands.Components;
|
using Content.Server.Hands.Components;
|
||||||
using Content.Server.Inventory.Components;
|
using Content.Server.Inventory.Components;
|
||||||
@@ -133,7 +134,12 @@ namespace Content.Server.Sandbox
|
|||||||
{
|
{
|
||||||
if (pda.ContainedID == null)
|
if (pda.ContainedID == null)
|
||||||
{
|
{
|
||||||
pda.InsertIdCard(CreateFreshId().GetComponent<IdCardComponent>());
|
var newID = CreateFreshId();
|
||||||
|
if (pda.Owner.TryGetComponent(out SharedItemSlotsComponent? itemSlots))
|
||||||
|
{
|
||||||
|
_entityManager.EntitySysManager.GetEntitySystem<SharedItemSlotsSystem>().
|
||||||
|
TryInsertContent(itemSlots, newID, PDAComponent.IDSlotName);
|
||||||
|
}
|
||||||
}
|
}
|
||||||
else
|
else
|
||||||
{
|
{
|
||||||
|
|||||||
93
Content.Server/Traitor/Uplink/Commands/AddUplinkCommand.cs
Normal file
93
Content.Server/Traitor/Uplink/Commands/AddUplinkCommand.cs
Normal file
@@ -0,0 +1,93 @@
|
|||||||
|
using Content.Server.Administration;
|
||||||
|
using Content.Server.PDA.Managers;
|
||||||
|
using Content.Server.Traitor.Uplink.Components;
|
||||||
|
using Content.Server.Traitor.Uplink.Systems;
|
||||||
|
using Content.Shared.Administration;
|
||||||
|
using Content.Shared.CCVar;
|
||||||
|
using Content.Shared.Traitor.Uplink;
|
||||||
|
using Robust.Server.Player;
|
||||||
|
using Robust.Shared.Configuration;
|
||||||
|
using Robust.Shared.Console;
|
||||||
|
using Robust.Shared.GameObjects;
|
||||||
|
using Robust.Shared.IoC;
|
||||||
|
using Robust.Shared.Localization;
|
||||||
|
|
||||||
|
namespace Content.Server.Traitor.Uplink.Commands
|
||||||
|
{
|
||||||
|
[AdminCommand(AdminFlags.Fun)]
|
||||||
|
public class AddUplinkCommand : IConsoleCommand
|
||||||
|
{
|
||||||
|
public string Command => "adduplink";
|
||||||
|
|
||||||
|
public string Description => "Creates uplink on selected item and link it to users account";
|
||||||
|
|
||||||
|
public string Help => "Usage: adduplink <username> <item-id>";
|
||||||
|
|
||||||
|
public void Execute(IConsoleShell shell, string argStr, string[] args)
|
||||||
|
{
|
||||||
|
if (args.Length < 1)
|
||||||
|
{
|
||||||
|
shell.WriteError(Loc.GetString("shell-wrong-arguments-number"));
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
// Get player entity
|
||||||
|
if (!IoCManager.Resolve<IPlayerManager>().TryGetSessionByUsername(args[0], out var session))
|
||||||
|
{
|
||||||
|
shell.WriteLine(Loc.GetString("shell-target-player-does-not-exist"));
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
if (session.AttachedEntity == null)
|
||||||
|
{
|
||||||
|
shell.WriteLine(Loc.GetString("Selected player doesn't controll any entity"));
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
var user = session.AttachedEntity;
|
||||||
|
|
||||||
|
// Get target item
|
||||||
|
IEntity? uplinkEntity = null;
|
||||||
|
var entityManager = IoCManager.Resolve<IEntityManager>();
|
||||||
|
if (args.Length >= 2)
|
||||||
|
{
|
||||||
|
if (!int.TryParse(args[1], out var itemID))
|
||||||
|
{
|
||||||
|
shell.WriteLine(Loc.GetString("shell-entity-uid-must-be-number"));
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
var eUid = new EntityUid(itemID);
|
||||||
|
if (!eUid.IsValid() || !entityManager.EntityExists(eUid))
|
||||||
|
{
|
||||||
|
shell.WriteLine(Loc.GetString("shell-invalid-entity-id"));
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
uplinkEntity = entityManager.GetEntity(eUid);
|
||||||
|
}
|
||||||
|
|
||||||
|
// Get TC count
|
||||||
|
var configManager = IoCManager.Resolve<IConfigurationManager>();
|
||||||
|
var tcCount = configManager.GetCVar(CCVars.TraitorStartingBalance);
|
||||||
|
|
||||||
|
// Get account
|
||||||
|
var uplinkManager = IoCManager.Resolve<IUplinkManager>();
|
||||||
|
if (!uplinkManager.TryGetAccount(user.Uid, out UplinkAccount? uplinkAccount))
|
||||||
|
{
|
||||||
|
uplinkAccount = new UplinkAccount(user.Uid, tcCount);
|
||||||
|
if (!uplinkManager.AddNewAccount(uplinkAccount))
|
||||||
|
{
|
||||||
|
shell.WriteLine(Loc.GetString("Can't create new uplink account"));
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
// Finally add uplink
|
||||||
|
if (!entityManager.EntitySysManager.GetEntitySystem<UplinkSystem>()
|
||||||
|
.AddUplink(user, uplinkAccount!, uplinkEntity))
|
||||||
|
{
|
||||||
|
shell.WriteLine(Loc.GetString("Failed to add uplink to the player"));
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
@@ -1,12 +1,13 @@
|
|||||||
using System.Collections.Generic;
|
using System.Collections.Generic;
|
||||||
using System.Diagnostics.CodeAnalysis;
|
using System.Diagnostics.CodeAnalysis;
|
||||||
using Content.Shared.PDA;
|
using Content.Shared.PDA;
|
||||||
|
using Content.Shared.Traitor.Uplink;
|
||||||
using Robust.Shared.GameObjects;
|
using Robust.Shared.GameObjects;
|
||||||
using Robust.Shared.Map;
|
using Robust.Shared.Map;
|
||||||
|
|
||||||
namespace Content.Server.PDA.Managers
|
namespace Content.Server.PDA.Managers
|
||||||
{
|
{
|
||||||
public interface IPDAUplinkManager
|
public interface IUplinkManager
|
||||||
{
|
{
|
||||||
public IReadOnlyDictionary<string, UplinkListingData> FetchListings { get; }
|
public IReadOnlyDictionary<string, UplinkListingData> FetchListings { get; }
|
||||||
|
|
||||||
@@ -16,6 +17,8 @@ namespace Content.Server.PDA.Managers
|
|||||||
|
|
||||||
public bool ChangeBalance(UplinkAccount acc, int amt);
|
public bool ChangeBalance(UplinkAccount acc, int amt);
|
||||||
|
|
||||||
|
public bool TryGetAccount(EntityUid owner, out UplinkAccount? acc);
|
||||||
|
|
||||||
public bool TryPurchaseItem(
|
public bool TryPurchaseItem(
|
||||||
UplinkAccount? acc,
|
UplinkAccount? acc,
|
||||||
string itemId,
|
string itemId,
|
||||||
@@ -2,19 +2,21 @@ using System.Collections.Generic;
|
|||||||
using System.Diagnostics.CodeAnalysis;
|
using System.Diagnostics.CodeAnalysis;
|
||||||
using Content.Server.Mind.Components;
|
using Content.Server.Mind.Components;
|
||||||
using Content.Shared.PDA;
|
using Content.Shared.PDA;
|
||||||
|
using Content.Shared.Traitor.Uplink;
|
||||||
using Robust.Shared.GameObjects;
|
using Robust.Shared.GameObjects;
|
||||||
using Robust.Shared.IoC;
|
using Robust.Shared.IoC;
|
||||||
using Robust.Shared.Map;
|
using Robust.Shared.Map;
|
||||||
using Robust.Shared.Prototypes;
|
using Robust.Shared.Prototypes;
|
||||||
|
using System.Linq;
|
||||||
|
|
||||||
namespace Content.Server.PDA.Managers
|
namespace Content.Server.PDA.Managers
|
||||||
{
|
{
|
||||||
public class PDAUplinkManager : IPDAUplinkManager
|
public class UplinkManager : IUplinkManager
|
||||||
{
|
{
|
||||||
[Dependency] private readonly IPrototypeManager _prototypeManager = default!;
|
[Dependency] private readonly IPrototypeManager _prototypeManager = default!;
|
||||||
[Dependency] private readonly IEntityManager _entityManager = default!;
|
[Dependency] private readonly IEntityManager _entityManager = default!;
|
||||||
|
|
||||||
private readonly List<UplinkAccount> _accounts = new();
|
private readonly Dictionary<EntityUid, UplinkAccount> _accounts = new();
|
||||||
private readonly Dictionary<string, UplinkListingData> _listings = new();
|
private readonly Dictionary<string, UplinkListingData> _listings = new();
|
||||||
|
|
||||||
public IReadOnlyDictionary<string, UplinkListingData> FetchListings => _listings;
|
public IReadOnlyDictionary<string, UplinkListingData> FetchListings => _listings;
|
||||||
@@ -52,18 +54,23 @@ namespace Content.Server.PDA.Managers
|
|||||||
return false;
|
return false;
|
||||||
}
|
}
|
||||||
|
|
||||||
if (_accounts.Contains(acc))
|
if (_accounts.ContainsKey(acc.AccountHolder))
|
||||||
{
|
{
|
||||||
return false;
|
return false;
|
||||||
}
|
}
|
||||||
|
|
||||||
_accounts.Add(acc);
|
_accounts.Add(acc.AccountHolder, acc);
|
||||||
return true;
|
return true;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
public bool TryGetAccount(EntityUid owner, out UplinkAccount? acc)
|
||||||
|
{
|
||||||
|
return _accounts.TryGetValue(owner, out acc);
|
||||||
|
}
|
||||||
|
|
||||||
public bool ChangeBalance(UplinkAccount acc, int amt)
|
public bool ChangeBalance(UplinkAccount acc, int amt)
|
||||||
{
|
{
|
||||||
var account = _accounts.Find(uplinkAccount => uplinkAccount.AccountHolder == acc.AccountHolder);
|
var account = _accounts.GetValueOrDefault(acc.AccountHolder);
|
||||||
|
|
||||||
if (account == null)
|
if (account == null)
|
||||||
{
|
{
|
||||||
24
Content.Server/Traitor/Uplink/UplinkComponent.cs
Normal file
24
Content.Server/Traitor/Uplink/UplinkComponent.cs
Normal file
@@ -0,0 +1,24 @@
|
|||||||
|
using Content.Shared.Sound;
|
||||||
|
using Content.Shared.Traitor.Uplink;
|
||||||
|
using Robust.Shared.GameObjects;
|
||||||
|
using Robust.Shared.Serialization.Manager.Attributes;
|
||||||
|
using Robust.Shared.ViewVariables;
|
||||||
|
|
||||||
|
namespace Content.Server.Traitor.Uplink.Components
|
||||||
|
{
|
||||||
|
[RegisterComponent]
|
||||||
|
public class UplinkComponent : Component
|
||||||
|
{
|
||||||
|
public override string Name => "Uplink";
|
||||||
|
|
||||||
|
[ViewVariables]
|
||||||
|
[DataField("buySuccessSound")]
|
||||||
|
public SoundSpecifier BuySuccessSound = new SoundPathSpecifier("/Audio/Effects/kaching.ogg");
|
||||||
|
|
||||||
|
[ViewVariables]
|
||||||
|
[DataField("insufficientFundsSound")]
|
||||||
|
public SoundSpecifier InsufficientFundsSound = new SoundPathSpecifier("/Audio/Effects/error.ogg");
|
||||||
|
|
||||||
|
[ViewVariables] public UplinkAccount? UplinkAccount;
|
||||||
|
}
|
||||||
|
}
|
||||||
21
Content.Server/Traitor/Uplink/UplinkEvents.cs
Normal file
21
Content.Server/Traitor/Uplink/UplinkEvents.cs
Normal file
@@ -0,0 +1,21 @@
|
|||||||
|
using Content.Server.Traitor.Uplink.Components;
|
||||||
|
using Content.Shared.Traitor.Uplink;
|
||||||
|
using Robust.Server.Player;
|
||||||
|
using Robust.Shared.GameObjects;
|
||||||
|
|
||||||
|
namespace Content.Server.Traitor.Uplink
|
||||||
|
{
|
||||||
|
public class UplinkInitEvent : EntityEventArgs
|
||||||
|
{
|
||||||
|
public UplinkComponent Uplink;
|
||||||
|
|
||||||
|
public UplinkInitEvent(UplinkComponent uplink)
|
||||||
|
{
|
||||||
|
Uplink = uplink;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
public class UplinkRemovedEvent : EntityEventArgs
|
||||||
|
{
|
||||||
|
}
|
||||||
|
}
|
||||||
166
Content.Server/Traitor/Uplink/UplinkSystem.cs
Normal file
166
Content.Server/Traitor/Uplink/UplinkSystem.cs
Normal file
@@ -0,0 +1,166 @@
|
|||||||
|
using Content.Server.Hands.Components;
|
||||||
|
using Content.Server.Inventory.Components;
|
||||||
|
using Content.Server.Items;
|
||||||
|
using Content.Server.PDA;
|
||||||
|
using Content.Server.PDA.Managers;
|
||||||
|
using Content.Server.Traitor.Uplink.Components;
|
||||||
|
using Content.Server.UserInterface;
|
||||||
|
using Content.Shared.Traitor.Uplink;
|
||||||
|
using Robust.Server.GameObjects;
|
||||||
|
using Robust.Server.Player;
|
||||||
|
using Robust.Shared.Audio;
|
||||||
|
using Robust.Shared.GameObjects;
|
||||||
|
using Robust.Shared.IoC;
|
||||||
|
using Robust.Shared.Log;
|
||||||
|
using Robust.Shared.Player;
|
||||||
|
using System;
|
||||||
|
using System.Linq;
|
||||||
|
|
||||||
|
namespace Content.Server.Traitor.Uplink.Systems
|
||||||
|
{
|
||||||
|
public class UplinkSystem : EntitySystem
|
||||||
|
{
|
||||||
|
[Dependency] private readonly IUplinkManager _uplinkManager = default!;
|
||||||
|
|
||||||
|
public override void Initialize()
|
||||||
|
{
|
||||||
|
base.Initialize();
|
||||||
|
|
||||||
|
SubscribeLocalEvent<UplinkComponent, ComponentInit>(OnInit);
|
||||||
|
SubscribeLocalEvent<UplinkComponent, ComponentRemove>(OnRemove);
|
||||||
|
}
|
||||||
|
|
||||||
|
public void SetAccount(UplinkComponent component, UplinkAccount account)
|
||||||
|
{
|
||||||
|
if (component.UplinkAccount != null)
|
||||||
|
{
|
||||||
|
Logger.Error("Can't init one uplink with different account!");
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
component.UplinkAccount = account;
|
||||||
|
component.UplinkAccount.BalanceChanged += (acc) =>
|
||||||
|
{
|
||||||
|
UpdateUserInterface(component);
|
||||||
|
};
|
||||||
|
|
||||||
|
}
|
||||||
|
|
||||||
|
private void OnInit(EntityUid uid, UplinkComponent component, ComponentInit args)
|
||||||
|
{
|
||||||
|
var ui = component.Owner.GetUIOrNull(UplinkUiKey.Key);
|
||||||
|
if (ui != null)
|
||||||
|
ui.OnReceiveMessage += (msg) => OnUIMessage(component, msg);
|
||||||
|
|
||||||
|
RaiseLocalEvent(uid, new UplinkInitEvent(component));
|
||||||
|
}
|
||||||
|
|
||||||
|
private void OnRemove(EntityUid uid, UplinkComponent component, ComponentRemove args)
|
||||||
|
{
|
||||||
|
RaiseLocalEvent(uid, new UplinkRemovedEvent());
|
||||||
|
}
|
||||||
|
|
||||||
|
public void ToggleUplinkUI(UplinkComponent component, IPlayerSession session)
|
||||||
|
{
|
||||||
|
var ui = component.Owner.GetUIOrNull(UplinkUiKey.Key);
|
||||||
|
ui?.Toggle(session);
|
||||||
|
|
||||||
|
UpdateUserInterface(component);
|
||||||
|
}
|
||||||
|
|
||||||
|
private void OnUIMessage(UplinkComponent uplink, ServerBoundUserInterfaceMessage message)
|
||||||
|
{
|
||||||
|
switch (message.Message)
|
||||||
|
{
|
||||||
|
case UplinkRequestUpdateInterfaceMessage _:
|
||||||
|
UpdateUserInterface(uplink);
|
||||||
|
break;
|
||||||
|
case UplinkBuyListingMessage buyMsg:
|
||||||
|
{
|
||||||
|
var player = message.Session.AttachedEntity;
|
||||||
|
if (player == null) break;
|
||||||
|
|
||||||
|
if (!_uplinkManager.TryPurchaseItem(uplink.UplinkAccount, buyMsg.ItemId,
|
||||||
|
player.Transform.Coordinates, out var entity))
|
||||||
|
{
|
||||||
|
SoundSystem.Play(Filter.SinglePlayer(message.Session), uplink.InsufficientFundsSound.GetSound(),
|
||||||
|
uplink.Owner, AudioParams.Default);
|
||||||
|
RaiseNetworkEvent(new UplinkInsufficientFundsMessage(), message.Session.ConnectedClient);
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (player.TryGetComponent(out HandsComponent? hands) &&
|
||||||
|
entity.TryGetComponent(out ItemComponent? item))
|
||||||
|
{
|
||||||
|
hands.PutInHandOrDrop(item);
|
||||||
|
}
|
||||||
|
|
||||||
|
SoundSystem.Play(Filter.SinglePlayer(message.Session), uplink.BuySuccessSound.GetSound(),
|
||||||
|
uplink.Owner, AudioParams.Default.WithVolume(-2f));
|
||||||
|
|
||||||
|
RaiseNetworkEvent(new UplinkBuySuccessMessage(), message.Session.ConnectedClient);
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
private void UpdateUserInterface(UplinkComponent component)
|
||||||
|
{
|
||||||
|
var ui = component.Owner.GetUIOrNull(UplinkUiKey.Key);
|
||||||
|
if (ui == null)
|
||||||
|
return;
|
||||||
|
|
||||||
|
var listings = _uplinkManager.FetchListings.Values.ToArray();
|
||||||
|
var acc = component.UplinkAccount;
|
||||||
|
|
||||||
|
UplinkAccountData accData;
|
||||||
|
if (acc != null)
|
||||||
|
accData = new UplinkAccountData(acc.AccountHolder, acc.Balance);
|
||||||
|
else
|
||||||
|
accData = new UplinkAccountData(null, 0);
|
||||||
|
|
||||||
|
ui.SetState(new UplinkUpdateState(accData, listings));
|
||||||
|
}
|
||||||
|
|
||||||
|
public bool AddUplink(IEntity user, UplinkAccount account, IEntity? uplinkEntity = null)
|
||||||
|
{
|
||||||
|
// Try to find target item
|
||||||
|
if (uplinkEntity == null)
|
||||||
|
{
|
||||||
|
uplinkEntity = FindUplinkTarget(user);
|
||||||
|
if (uplinkEntity == null)
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
|
||||||
|
var uplink = uplinkEntity.EnsureComponent<UplinkComponent>();
|
||||||
|
SetAccount(uplink, account);
|
||||||
|
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
|
||||||
|
private IEntity? FindUplinkTarget(IEntity user)
|
||||||
|
{
|
||||||
|
// Try to find PDA in inventory
|
||||||
|
if (user.TryGetComponent(out InventoryComponent? inventory))
|
||||||
|
{
|
||||||
|
var foundPDA = inventory.LookupItems<PDAComponent>().FirstOrDefault();
|
||||||
|
if (foundPDA != null)
|
||||||
|
return foundPDA.Owner;
|
||||||
|
}
|
||||||
|
|
||||||
|
// Also check hands
|
||||||
|
if (user.TryGetComponent(out IHandsComponent? hands))
|
||||||
|
{
|
||||||
|
var heldItems = hands.GetAllHeldItems();
|
||||||
|
foreach (var item in heldItems)
|
||||||
|
{
|
||||||
|
if (item.Owner.HasComponent<PDAComponent>())
|
||||||
|
return item.Owner;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
return null;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
@@ -2,6 +2,7 @@ using System.Threading.Tasks;
|
|||||||
using Content.Server.Inventory.Components;
|
using Content.Server.Inventory.Components;
|
||||||
using Content.Server.Mind.Components;
|
using Content.Server.Mind.Components;
|
||||||
using Content.Server.PDA;
|
using Content.Server.PDA;
|
||||||
|
using Content.Server.Traitor.Uplink.Components;
|
||||||
using Content.Shared.Interaction;
|
using Content.Shared.Interaction;
|
||||||
using Content.Shared.Inventory;
|
using Content.Shared.Inventory;
|
||||||
using Content.Shared.Popups;
|
using Content.Shared.Popups;
|
||||||
@@ -40,7 +41,7 @@ namespace Content.Server.TraitorDeathMatch.Components
|
|||||||
return false;
|
return false;
|
||||||
}
|
}
|
||||||
|
|
||||||
if (!eventArgs.Using.TryGetComponent<PDAComponent>(out var victimPDA))
|
if (!eventArgs.Using.TryGetComponent<UplinkComponent>(out var victimUplink))
|
||||||
{
|
{
|
||||||
Owner.PopupMessage(eventArgs.User, Loc.GetString("traitor-death-match-redemption-component-interact-using-main-message",
|
Owner.PopupMessage(eventArgs.User, Loc.GetString("traitor-death-match-redemption-component-interact-using-main-message",
|
||||||
("secondMessage", Loc.GetString("traitor-death-match-redemption-component-interact-using-no-pda-message"))));
|
("secondMessage", Loc.GetString("traitor-death-match-redemption-component-interact-using-no-pda-message"))));
|
||||||
@@ -62,13 +63,13 @@ namespace Content.Server.TraitorDeathMatch.Components
|
|||||||
}
|
}
|
||||||
|
|
||||||
var userPDAEntity = userInv.GetSlotItem(EquipmentSlotDefines.Slots.IDCARD)?.Owner;
|
var userPDAEntity = userInv.GetSlotItem(EquipmentSlotDefines.Slots.IDCARD)?.Owner;
|
||||||
PDAComponent? userPDA = null;
|
UplinkComponent? userUplink = null;
|
||||||
|
|
||||||
if (userPDAEntity != null)
|
if (userPDAEntity != null)
|
||||||
if (userPDAEntity.TryGetComponent<PDAComponent>(out var userPDAComponent))
|
if (userPDAEntity.TryGetComponent<UplinkComponent>(out var userUplinkComponent))
|
||||||
userPDA = userPDAComponent;
|
userUplink = userUplinkComponent;
|
||||||
|
|
||||||
if (userPDA == null)
|
if (userUplink == null)
|
||||||
{
|
{
|
||||||
Owner.PopupMessage(eventArgs.User, Loc.GetString("traitor-death-match-redemption-component-interact-using-main-message",
|
Owner.PopupMessage(eventArgs.User, Loc.GetString("traitor-death-match-redemption-component-interact-using-main-message",
|
||||||
("secondMessage", Loc.GetString("traitor-death-match-redemption-component-interact-using-no-pda-in-pocket-message"))));
|
("secondMessage", Loc.GetString("traitor-death-match-redemption-component-interact-using-no-pda-in-pocket-message"))));
|
||||||
@@ -77,8 +78,8 @@ namespace Content.Server.TraitorDeathMatch.Components
|
|||||||
|
|
||||||
// We have finally determined both PDA components. FINALLY.
|
// We have finally determined both PDA components. FINALLY.
|
||||||
|
|
||||||
var userAccount = userPDA.SyndicateUplinkAccount;
|
var userAccount = userUplink.UplinkAccount;
|
||||||
var victimAccount = victimPDA.SyndicateUplinkAccount;
|
var victimAccount = victimUplink.UplinkAccount;
|
||||||
|
|
||||||
if (userAccount == null)
|
if (userAccount == null)
|
||||||
{
|
{
|
||||||
@@ -107,7 +108,7 @@ namespace Content.Server.TraitorDeathMatch.Components
|
|||||||
victimAccount.ModifyAccountBalance(0);
|
victimAccount.ModifyAccountBalance(0);
|
||||||
userAccount.ModifyAccountBalance(userAccount.Balance + transferAmount);
|
userAccount.ModifyAccountBalance(userAccount.Balance + transferAmount);
|
||||||
|
|
||||||
victimPDA.Owner.Delete();
|
victimUplink.Owner.Delete();
|
||||||
|
|
||||||
Owner.PopupMessage(eventArgs.User, Loc.GetString("traitor-death-match-redemption-component-interact-using-success-message", ("tcAmount", transferAmount)));
|
Owner.PopupMessage(eventArgs.User, Loc.GetString("traitor-death-match-redemption-component-interact-using-success-message", ("tcAmount", transferAmount)));
|
||||||
return true;
|
return true;
|
||||||
|
|||||||
23
Content.Shared/Containers/ItemSlot/ItemSlotEvents.cs
Normal file
23
Content.Shared/Containers/ItemSlot/ItemSlotEvents.cs
Normal file
@@ -0,0 +1,23 @@
|
|||||||
|
using Robust.Shared.GameObjects;
|
||||||
|
|
||||||
|
namespace Content.Shared.Containers.ItemSlots
|
||||||
|
{
|
||||||
|
/// <summary>
|
||||||
|
/// Item was placed in or removed from one of the slots in <see cref="SharedItemSlotsComponent"/>
|
||||||
|
/// </summary>
|
||||||
|
public class ItemSlotChanged : EntityEventArgs
|
||||||
|
{
|
||||||
|
public SharedItemSlotsComponent SlotsComponent;
|
||||||
|
public string SlotName;
|
||||||
|
public ItemSlot Slot;
|
||||||
|
public readonly EntityUid? ContainedItem;
|
||||||
|
|
||||||
|
public ItemSlotChanged(SharedItemSlotsComponent slotsComponent, string slotName, ItemSlot slot)
|
||||||
|
{
|
||||||
|
SlotsComponent = slotsComponent;
|
||||||
|
SlotName = slotName;
|
||||||
|
Slot = slot;
|
||||||
|
ContainedItem = slot.ContainerSlot.ContainedEntity?.Uid;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
@@ -0,0 +1,39 @@
|
|||||||
|
using Content.Shared.Sound;
|
||||||
|
using Content.Shared.Whitelist;
|
||||||
|
using Robust.Shared.Containers;
|
||||||
|
using Robust.Shared.GameObjects;
|
||||||
|
using Robust.Shared.Prototypes;
|
||||||
|
using Robust.Shared.Serialization.Manager.Attributes;
|
||||||
|
using Robust.Shared.Serialization.TypeSerializers.Implementations.Custom.Prototype;
|
||||||
|
using Robust.Shared.ViewVariables;
|
||||||
|
using System;
|
||||||
|
using System.Collections.Generic;
|
||||||
|
|
||||||
|
namespace Content.Shared.Containers.ItemSlots
|
||||||
|
{
|
||||||
|
/// <summary>
|
||||||
|
/// Used for entities that can hold items in different slots
|
||||||
|
/// Allows basic insert/eject interaction
|
||||||
|
/// </summary>
|
||||||
|
[RegisterComponent]
|
||||||
|
public class SharedItemSlotsComponent : Component
|
||||||
|
{
|
||||||
|
public override string Name => "ItemSlots";
|
||||||
|
|
||||||
|
[ViewVariables] [DataField("slots")] public Dictionary<string, ItemSlot> Slots = new();
|
||||||
|
}
|
||||||
|
|
||||||
|
[Serializable]
|
||||||
|
[DataDefinition]
|
||||||
|
public class ItemSlot
|
||||||
|
{
|
||||||
|
[ViewVariables] [DataField("whitelist")] public EntityWhitelist? Whitelist;
|
||||||
|
[ViewVariables] [DataField("insertSound")] public SoundSpecifier? InsertSound;
|
||||||
|
[ViewVariables] [DataField("ejectSound")] public SoundSpecifier? EjectSound;
|
||||||
|
|
||||||
|
[DataField("item", customTypeSerializer: typeof(PrototypeIdSerializer<EntityPrototype>))]
|
||||||
|
[ViewVariables] public string? StartingItem;
|
||||||
|
|
||||||
|
[ViewVariables] public ContainerSlot ContainerSlot = default!;
|
||||||
|
}
|
||||||
|
}
|
||||||
187
Content.Shared/Containers/ItemSlot/SharedItemSlotsSystem.cs
Normal file
187
Content.Shared/Containers/ItemSlot/SharedItemSlotsSystem.cs
Normal file
@@ -0,0 +1,187 @@
|
|||||||
|
using Content.Shared.Hands.Components;
|
||||||
|
using Content.Shared.Interaction;
|
||||||
|
using Content.Shared.Item;
|
||||||
|
using Content.Shared.Popups;
|
||||||
|
using Robust.Shared.Audio;
|
||||||
|
using Robust.Shared.Containers;
|
||||||
|
using Robust.Shared.GameObjects;
|
||||||
|
using Robust.Shared.Localization;
|
||||||
|
using Robust.Shared.Player;
|
||||||
|
|
||||||
|
namespace Content.Shared.Containers.ItemSlots
|
||||||
|
{
|
||||||
|
public class SharedItemSlotsSystem : EntitySystem
|
||||||
|
{
|
||||||
|
public override void Initialize()
|
||||||
|
{
|
||||||
|
base.Initialize();
|
||||||
|
|
||||||
|
SubscribeLocalEvent<SharedItemSlotsComponent, ComponentInit>(OnComponentInit);
|
||||||
|
SubscribeLocalEvent<SharedItemSlotsComponent, MapInitEvent>(OnMapInit);
|
||||||
|
SubscribeLocalEvent<SharedItemSlotsComponent, InteractUsingEvent>(OnInteractUsing);
|
||||||
|
}
|
||||||
|
|
||||||
|
private void OnComponentInit(EntityUid uid, SharedItemSlotsComponent itemSlots, ComponentInit args)
|
||||||
|
{
|
||||||
|
// create container for each slot
|
||||||
|
foreach (var pair in itemSlots.Slots)
|
||||||
|
{
|
||||||
|
var slotName = pair.Key;
|
||||||
|
var slot = pair.Value;
|
||||||
|
|
||||||
|
slot.ContainerSlot = ContainerHelpers.EnsureContainer<ContainerSlot>(itemSlots.Owner, slotName);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
private void OnMapInit(EntityUid uid, SharedItemSlotsComponent itemSlots, MapInitEvent args)
|
||||||
|
{
|
||||||
|
foreach (var pair in itemSlots.Slots)
|
||||||
|
{
|
||||||
|
var slot = pair.Value;
|
||||||
|
var slotName = pair.Key;
|
||||||
|
|
||||||
|
// Check if someone already put item inside container
|
||||||
|
if (slot.ContainerSlot.ContainedEntity != null)
|
||||||
|
continue;
|
||||||
|
|
||||||
|
// Try to spawn item inside each slot
|
||||||
|
if (!string.IsNullOrEmpty(slot.StartingItem))
|
||||||
|
{
|
||||||
|
var item = EntityManager.SpawnEntity(slot.StartingItem, itemSlots.Owner.Transform.Coordinates);
|
||||||
|
slot.ContainerSlot.Insert(item);
|
||||||
|
|
||||||
|
RaiseLocalEvent(uid, new ItemSlotChanged(itemSlots, slotName, slot));
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
private void OnInteractUsing(EntityUid uid, SharedItemSlotsComponent itemSlots, InteractUsingEvent args)
|
||||||
|
{
|
||||||
|
if (args.Handled)
|
||||||
|
return;
|
||||||
|
|
||||||
|
args.Handled = TryInsertContent(itemSlots, args.Used, args.User);
|
||||||
|
}
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// Tries to insert item in any fitting item slot from users hand
|
||||||
|
/// </summary>
|
||||||
|
/// <returns>False if failed to insert item</returns>
|
||||||
|
public bool TryInsertContent(SharedItemSlotsComponent itemSlots, IEntity item, IEntity user)
|
||||||
|
{
|
||||||
|
foreach (var pair in itemSlots.Slots)
|
||||||
|
{
|
||||||
|
var slotName = pair.Key;
|
||||||
|
var slot = pair.Value;
|
||||||
|
|
||||||
|
// check if item allowed in whitelist
|
||||||
|
if (slot.Whitelist != null && !slot.Whitelist.IsValid(item))
|
||||||
|
continue;
|
||||||
|
|
||||||
|
// check if slot is empty
|
||||||
|
if (slot.ContainerSlot.Contains(item))
|
||||||
|
continue;
|
||||||
|
|
||||||
|
if (!user.TryGetComponent(out SharedHandsComponent? hands))
|
||||||
|
{
|
||||||
|
itemSlots.Owner.PopupMessage(user, Loc.GetString("item-slots-try-insert-no-hands"));
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
|
||||||
|
// get item inside container
|
||||||
|
IEntity? swap = null;
|
||||||
|
if (slot.ContainerSlot.ContainedEntity != null)
|
||||||
|
swap = slot.ContainerSlot.ContainedEntity;
|
||||||
|
|
||||||
|
// return if user can't drop active item in hand
|
||||||
|
if (!hands.TryDropEntityToFloor(item))
|
||||||
|
return true;
|
||||||
|
|
||||||
|
// swap item in hand and item in slot
|
||||||
|
if (swap != null)
|
||||||
|
hands.TryPutInAnyHand(swap);
|
||||||
|
|
||||||
|
// insert item
|
||||||
|
slot.ContainerSlot.Insert(item);
|
||||||
|
RaiseLocalEvent(itemSlots.Owner.Uid, new ItemSlotChanged(itemSlots, slotName, slot));
|
||||||
|
|
||||||
|
// play sound
|
||||||
|
if (slot.InsertSound != null)
|
||||||
|
SoundSystem.Play(Filter.Pvs(itemSlots.Owner), slot.InsertSound.GetSound(), itemSlots.Owner);
|
||||||
|
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// Tries to insert item in known slot. Doesn't interact with user
|
||||||
|
/// </summary>
|
||||||
|
/// <returns>False if failed to insert item</returns>
|
||||||
|
public bool TryInsertContent(SharedItemSlotsComponent itemSlots, IEntity item, string slotName)
|
||||||
|
{
|
||||||
|
if (!itemSlots.Slots.TryGetValue(slotName, out var slot))
|
||||||
|
return false;
|
||||||
|
|
||||||
|
if (slot.ContainerSlot.ContainedEntity != null)
|
||||||
|
return false;
|
||||||
|
|
||||||
|
// check if item allowed in whitelist
|
||||||
|
if (slot.Whitelist != null && !slot.Whitelist.IsValid(item))
|
||||||
|
return false;
|
||||||
|
|
||||||
|
slot.ContainerSlot.Insert(item);
|
||||||
|
RaiseLocalEvent(itemSlots.Owner.Uid, new ItemSlotChanged(itemSlots, slotName, slot));
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// Check if slot has some content in it (without ejecting item)
|
||||||
|
/// </summary>
|
||||||
|
/// <returns>Null if doesn't have any content</returns>
|
||||||
|
public IEntity? PeekItemInSlot(SharedItemSlotsComponent itemSlots, string slotName)
|
||||||
|
{
|
||||||
|
if (!itemSlots.Slots.TryGetValue(slotName, out var slot))
|
||||||
|
return null;
|
||||||
|
|
||||||
|
var item = slot.ContainerSlot.ContainedEntity;
|
||||||
|
return item;
|
||||||
|
}
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// Try to eject item from slot to users hands
|
||||||
|
/// </summary>
|
||||||
|
public bool TryEjectContent(SharedItemSlotsComponent itemSlots, string slotName, IEntity? user)
|
||||||
|
{
|
||||||
|
if (!itemSlots.Slots.TryGetValue(slotName, out var slot))
|
||||||
|
return false;
|
||||||
|
|
||||||
|
if (slot.ContainerSlot.ContainedEntity == null)
|
||||||
|
return false;
|
||||||
|
|
||||||
|
var item = slot.ContainerSlot.ContainedEntity;
|
||||||
|
if (!slot.ContainerSlot.Remove(item))
|
||||||
|
return false;
|
||||||
|
|
||||||
|
// try eject item to users hand
|
||||||
|
if (user != null)
|
||||||
|
{
|
||||||
|
if (user.TryGetComponent(out SharedHandsComponent? hands))
|
||||||
|
{
|
||||||
|
hands.TryPutInAnyHand(item);
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
itemSlots.Owner.PopupMessage(user, Loc.GetString("item-slots-try-insert-no-hands"));
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
if (slot.EjectSound != null)
|
||||||
|
SoundSystem.Play(Filter.Pvs(itemSlots.Owner), slot.EjectSound.GetSound(), itemSlots.Owner);
|
||||||
|
|
||||||
|
RaiseLocalEvent(itemSlots.Owner.Uid, new ItemSlotChanged(itemSlots, slotName, slot));
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
11
Content.Shared/Light/SharedUnpoweredFlashlightVisuals.cs
Normal file
11
Content.Shared/Light/SharedUnpoweredFlashlightVisuals.cs
Normal file
@@ -0,0 +1,11 @@
|
|||||||
|
using Robust.Shared.Serialization;
|
||||||
|
using System;
|
||||||
|
|
||||||
|
namespace Content.Shared.Light
|
||||||
|
{
|
||||||
|
[Serializable, NetSerializable]
|
||||||
|
public enum UnpoweredFlashlightVisuals : byte
|
||||||
|
{
|
||||||
|
LightOn
|
||||||
|
}
|
||||||
|
}
|
||||||
52
Content.Shared/PDA/PDAMessagesUI.cs
Normal file
52
Content.Shared/PDA/PDAMessagesUI.cs
Normal file
@@ -0,0 +1,52 @@
|
|||||||
|
using Robust.Shared.GameObjects;
|
||||||
|
using Robust.Shared.Serialization;
|
||||||
|
using System;
|
||||||
|
|
||||||
|
namespace Content.Shared.PDA
|
||||||
|
{
|
||||||
|
[Serializable, NetSerializable]
|
||||||
|
public sealed class PDAToggleFlashlightMessage : BoundUserInterfaceMessage
|
||||||
|
{
|
||||||
|
public PDAToggleFlashlightMessage()
|
||||||
|
{
|
||||||
|
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
[Serializable, NetSerializable]
|
||||||
|
public sealed class PDAEjectIDMessage : BoundUserInterfaceMessage
|
||||||
|
{
|
||||||
|
public PDAEjectIDMessage()
|
||||||
|
{
|
||||||
|
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
[Serializable, NetSerializable]
|
||||||
|
public sealed class PDAEjectPenMessage : BoundUserInterfaceMessage
|
||||||
|
{
|
||||||
|
public PDAEjectPenMessage()
|
||||||
|
{
|
||||||
|
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
[Serializable, NetSerializable]
|
||||||
|
public sealed class PDAShowUplinkMessage : BoundUserInterfaceMessage
|
||||||
|
{
|
||||||
|
public PDAShowUplinkMessage()
|
||||||
|
{
|
||||||
|
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
[Serializable, NetSerializable]
|
||||||
|
public sealed class PDARequestUpdateInterfaceMessage : BoundUserInterfaceMessage
|
||||||
|
{
|
||||||
|
public PDARequestUpdateInterfaceMessage()
|
||||||
|
{
|
||||||
|
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
33
Content.Shared/PDA/PDAUpdateState.cs
Normal file
33
Content.Shared/PDA/PDAUpdateState.cs
Normal file
@@ -0,0 +1,33 @@
|
|||||||
|
using Content.Shared.Traitor.Uplink;
|
||||||
|
using Robust.Shared.GameObjects;
|
||||||
|
using Robust.Shared.Serialization;
|
||||||
|
using System;
|
||||||
|
|
||||||
|
|
||||||
|
namespace Content.Shared.PDA
|
||||||
|
{
|
||||||
|
[Serializable, NetSerializable]
|
||||||
|
public sealed class PDAUpdateState : BoundUserInterfaceState
|
||||||
|
{
|
||||||
|
public bool FlashlightEnabled;
|
||||||
|
public bool HasPen;
|
||||||
|
public PDAIdInfoText PDAOwnerInfo;
|
||||||
|
public bool HasUplink;
|
||||||
|
|
||||||
|
public PDAUpdateState(bool flashlightEnabled, bool hasPen, PDAIdInfoText pDAOwnerInfo, bool hasUplink = false)
|
||||||
|
{
|
||||||
|
FlashlightEnabled = flashlightEnabled;
|
||||||
|
HasPen = hasPen;
|
||||||
|
PDAOwnerInfo = pDAOwnerInfo;
|
||||||
|
HasUplink = hasUplink;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
[Serializable, NetSerializable]
|
||||||
|
public struct PDAIdInfoText
|
||||||
|
{
|
||||||
|
public string? ActualOwnerName;
|
||||||
|
public string? IdOwner;
|
||||||
|
public string? JobTitle;
|
||||||
|
}
|
||||||
|
}
|
||||||
18
Content.Shared/PDA/PDAVisuals.cs
Normal file
18
Content.Shared/PDA/PDAVisuals.cs
Normal file
@@ -0,0 +1,18 @@
|
|||||||
|
using System;
|
||||||
|
using Robust.Shared.Serialization;
|
||||||
|
|
||||||
|
namespace Content.Shared.PDA
|
||||||
|
{
|
||||||
|
[Serializable, NetSerializable]
|
||||||
|
public enum PDAVisuals
|
||||||
|
{
|
||||||
|
IDCardInserted
|
||||||
|
}
|
||||||
|
|
||||||
|
[Serializable, NetSerializable]
|
||||||
|
public enum PDAUiKey
|
||||||
|
{
|
||||||
|
Key
|
||||||
|
}
|
||||||
|
|
||||||
|
}
|
||||||
@@ -1,197 +0,0 @@
|
|||||||
using System;
|
|
||||||
using Robust.Shared.GameObjects;
|
|
||||||
using Robust.Shared.GameStates;
|
|
||||||
using Robust.Shared.Serialization;
|
|
||||||
using Robust.Shared.ViewVariables;
|
|
||||||
|
|
||||||
namespace Content.Shared.PDA
|
|
||||||
{
|
|
||||||
[NetworkedComponent()]
|
|
||||||
public class SharedPDAComponent : Component
|
|
||||||
{
|
|
||||||
public override string Name => "PDA";
|
|
||||||
}
|
|
||||||
|
|
||||||
[Serializable, NetSerializable]
|
|
||||||
public sealed class PDAToggleFlashlightMessage : BoundUserInterfaceMessage
|
|
||||||
{
|
|
||||||
public PDAToggleFlashlightMessage()
|
|
||||||
{
|
|
||||||
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
[Serializable, NetSerializable]
|
|
||||||
public sealed class PDAEjectIDMessage : BoundUserInterfaceMessage
|
|
||||||
{
|
|
||||||
public PDAEjectIDMessage()
|
|
||||||
{
|
|
||||||
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
[Serializable, NetSerializable]
|
|
||||||
public sealed class PDAEjectPenMessage : BoundUserInterfaceMessage
|
|
||||||
{
|
|
||||||
public PDAEjectPenMessage()
|
|
||||||
{
|
|
||||||
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
[Serializable, NetSerializable]
|
|
||||||
public class PDAUBoundUserInterfaceState : BoundUserInterfaceState
|
|
||||||
{
|
|
||||||
|
|
||||||
}
|
|
||||||
|
|
||||||
[Serializable, NetSerializable]
|
|
||||||
public sealed class PDAUpdateState : PDAUBoundUserInterfaceState
|
|
||||||
{
|
|
||||||
public bool FlashlightEnabled;
|
|
||||||
public bool HasPen;
|
|
||||||
public PDAIdInfoText PDAOwnerInfo;
|
|
||||||
public UplinkAccountData Account = default!;
|
|
||||||
public UplinkListingData[] Listings = default!;
|
|
||||||
|
|
||||||
public PDAUpdateState(bool isFlashlightOn, bool hasPen, PDAIdInfoText ownerInfo)
|
|
||||||
{
|
|
||||||
FlashlightEnabled = isFlashlightOn;
|
|
||||||
HasPen = hasPen;
|
|
||||||
PDAOwnerInfo = ownerInfo;
|
|
||||||
}
|
|
||||||
|
|
||||||
public PDAUpdateState(bool isFlashlightOn, bool hasPen, PDAIdInfoText ownerInfo, UplinkAccountData accountData)
|
|
||||||
: this(isFlashlightOn, hasPen, ownerInfo)
|
|
||||||
{
|
|
||||||
Account = accountData;
|
|
||||||
}
|
|
||||||
|
|
||||||
public PDAUpdateState(bool isFlashlightOn, bool hasPen, PDAIdInfoText ownerInfo, UplinkAccountData accountData, UplinkListingData[] listings)
|
|
||||||
: this(isFlashlightOn, hasPen, ownerInfo, accountData)
|
|
||||||
{
|
|
||||||
Listings = listings;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
[Serializable, NetSerializable]
|
|
||||||
public sealed class PDAUplinkBuyListingMessage : BoundUserInterfaceMessage
|
|
||||||
{
|
|
||||||
public string ItemId;
|
|
||||||
|
|
||||||
public PDAUplinkBuyListingMessage(string itemId)
|
|
||||||
{
|
|
||||||
ItemId = itemId;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
[Serializable, NetSerializable]
|
|
||||||
public sealed class PDAUplinkBuySuccessMessage : ComponentMessage
|
|
||||||
{
|
|
||||||
}
|
|
||||||
|
|
||||||
[Serializable, NetSerializable]
|
|
||||||
public sealed class PDAUplinkInsufficientFundsMessage : ComponentMessage
|
|
||||||
{
|
|
||||||
}
|
|
||||||
|
|
||||||
[Serializable, NetSerializable]
|
|
||||||
public sealed class PDARequestUpdateInterfaceMessage : BoundUserInterfaceMessage
|
|
||||||
{
|
|
||||||
public PDARequestUpdateInterfaceMessage()
|
|
||||||
{
|
|
||||||
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
[Serializable, NetSerializable]
|
|
||||||
public struct PDAIdInfoText
|
|
||||||
{
|
|
||||||
public string? ActualOwnerName;
|
|
||||||
public string? IdOwner;
|
|
||||||
public string? JobTitle;
|
|
||||||
}
|
|
||||||
|
|
||||||
[Serializable, NetSerializable]
|
|
||||||
public enum PDAVisuals
|
|
||||||
{
|
|
||||||
FlashlightLit,
|
|
||||||
IDCardInserted
|
|
||||||
}
|
|
||||||
|
|
||||||
[Serializable, NetSerializable]
|
|
||||||
public enum PDAUiKey
|
|
||||||
{
|
|
||||||
Key
|
|
||||||
}
|
|
||||||
|
|
||||||
public class UplinkAccount
|
|
||||||
{
|
|
||||||
public event Action<UplinkAccount>? BalanceChanged;
|
|
||||||
public EntityUid AccountHolder;
|
|
||||||
private int _balance;
|
|
||||||
[ViewVariables]
|
|
||||||
public int Balance => _balance;
|
|
||||||
|
|
||||||
public UplinkAccount(EntityUid uid, int startingBalance)
|
|
||||||
{
|
|
||||||
AccountHolder = uid;
|
|
||||||
_balance = startingBalance;
|
|
||||||
}
|
|
||||||
|
|
||||||
public bool ModifyAccountBalance(int newBalance)
|
|
||||||
{
|
|
||||||
if (newBalance < 0)
|
|
||||||
{
|
|
||||||
return false;
|
|
||||||
}
|
|
||||||
_balance = newBalance;
|
|
||||||
BalanceChanged?.Invoke(this);
|
|
||||||
return true;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
[Serializable, NetSerializable]
|
|
||||||
public class UplinkAccountData
|
|
||||||
{
|
|
||||||
public EntityUid DataAccountHolder;
|
|
||||||
public int DataBalance;
|
|
||||||
|
|
||||||
public UplinkAccountData(EntityUid dataAccountHolder, int dataBalance)
|
|
||||||
{
|
|
||||||
DataAccountHolder = dataAccountHolder;
|
|
||||||
DataBalance = dataBalance;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
[Serializable, NetSerializable]
|
|
||||||
public class UplinkListingData : ComponentState, IEquatable<UplinkListingData>
|
|
||||||
{
|
|
||||||
public string ItemId;
|
|
||||||
public int Price;
|
|
||||||
public UplinkCategory Category;
|
|
||||||
public string Description;
|
|
||||||
public string ListingName;
|
|
||||||
|
|
||||||
public UplinkListingData(string listingName,string itemId,
|
|
||||||
int price, UplinkCategory category,
|
|
||||||
string description)
|
|
||||||
{
|
|
||||||
ListingName = listingName;
|
|
||||||
Price = price;
|
|
||||||
Category = category;
|
|
||||||
Description = description;
|
|
||||||
ItemId = itemId;
|
|
||||||
}
|
|
||||||
|
|
||||||
public bool Equals(UplinkListingData? other)
|
|
||||||
{
|
|
||||||
if (other == null)
|
|
||||||
{
|
|
||||||
return false;
|
|
||||||
}
|
|
||||||
|
|
||||||
return ItemId == other.ItemId;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
32
Content.Shared/Traitor/Uplink/UplinkAccount.cs
Normal file
32
Content.Shared/Traitor/Uplink/UplinkAccount.cs
Normal file
@@ -0,0 +1,32 @@
|
|||||||
|
using Robust.Shared.GameObjects;
|
||||||
|
using Robust.Shared.ViewVariables;
|
||||||
|
using System;
|
||||||
|
|
||||||
|
namespace Content.Shared.Traitor.Uplink
|
||||||
|
{
|
||||||
|
public class UplinkAccount
|
||||||
|
{
|
||||||
|
public event Action<UplinkAccount>? BalanceChanged;
|
||||||
|
public EntityUid AccountHolder;
|
||||||
|
private int _balance;
|
||||||
|
[ViewVariables]
|
||||||
|
public int Balance => _balance;
|
||||||
|
|
||||||
|
public UplinkAccount(EntityUid uid, int startingBalance)
|
||||||
|
{
|
||||||
|
AccountHolder = uid;
|
||||||
|
_balance = startingBalance;
|
||||||
|
}
|
||||||
|
|
||||||
|
public bool ModifyAccountBalance(int newBalance)
|
||||||
|
{
|
||||||
|
if (newBalance < 0)
|
||||||
|
{
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
_balance = newBalance;
|
||||||
|
BalanceChanged?.Invoke(this);
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
19
Content.Shared/Traitor/Uplink/UplinkAccountData.cs
Normal file
19
Content.Shared/Traitor/Uplink/UplinkAccountData.cs
Normal file
@@ -0,0 +1,19 @@
|
|||||||
|
using Robust.Shared.GameObjects;
|
||||||
|
using Robust.Shared.Serialization;
|
||||||
|
using System;
|
||||||
|
|
||||||
|
namespace Content.Shared.Traitor.Uplink
|
||||||
|
{
|
||||||
|
[Serializable, NetSerializable]
|
||||||
|
public class UplinkAccountData
|
||||||
|
{
|
||||||
|
public EntityUid? DataAccountHolder;
|
||||||
|
public int DataBalance;
|
||||||
|
|
||||||
|
public UplinkAccountData(EntityUid? dataAccountHolder, int dataBalance)
|
||||||
|
{
|
||||||
|
DataAccountHolder = dataAccountHolder;
|
||||||
|
DataBalance = dataBalance;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
38
Content.Shared/Traitor/Uplink/UplinkListingData.cs
Normal file
38
Content.Shared/Traitor/Uplink/UplinkListingData.cs
Normal file
@@ -0,0 +1,38 @@
|
|||||||
|
using Content.Shared.PDA;
|
||||||
|
using Robust.Shared.GameObjects;
|
||||||
|
using Robust.Shared.Serialization;
|
||||||
|
using System;
|
||||||
|
|
||||||
|
namespace Content.Shared.Traitor.Uplink
|
||||||
|
{
|
||||||
|
[Serializable, NetSerializable]
|
||||||
|
public class UplinkListingData : ComponentState, IEquatable<UplinkListingData>
|
||||||
|
{
|
||||||
|
public string ItemId;
|
||||||
|
public int Price;
|
||||||
|
public UplinkCategory Category;
|
||||||
|
public string Description;
|
||||||
|
public string ListingName;
|
||||||
|
|
||||||
|
public UplinkListingData(string listingName, string itemId,
|
||||||
|
int price, UplinkCategory category,
|
||||||
|
string description)
|
||||||
|
{
|
||||||
|
ListingName = listingName;
|
||||||
|
Price = price;
|
||||||
|
Category = category;
|
||||||
|
Description = description;
|
||||||
|
ItemId = itemId;
|
||||||
|
}
|
||||||
|
|
||||||
|
public bool Equals(UplinkListingData? other)
|
||||||
|
{
|
||||||
|
if (other == null)
|
||||||
|
{
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
|
||||||
|
return ItemId == other.ItemId;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
26
Content.Shared/Traitor/Uplink/UplinkMessagesUI.cs
Normal file
26
Content.Shared/Traitor/Uplink/UplinkMessagesUI.cs
Normal file
@@ -0,0 +1,26 @@
|
|||||||
|
using Robust.Shared.GameObjects;
|
||||||
|
using Robust.Shared.Serialization;
|
||||||
|
using System;
|
||||||
|
|
||||||
|
namespace Content.Shared.Traitor.Uplink
|
||||||
|
{
|
||||||
|
[Serializable, NetSerializable]
|
||||||
|
public sealed class UplinkBuyListingMessage : BoundUserInterfaceMessage
|
||||||
|
{
|
||||||
|
public string ItemId;
|
||||||
|
|
||||||
|
public UplinkBuyListingMessage(string itemId)
|
||||||
|
{
|
||||||
|
ItemId = itemId;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
[Serializable, NetSerializable]
|
||||||
|
public sealed class UplinkRequestUpdateInterfaceMessage : BoundUserInterfaceMessage
|
||||||
|
{
|
||||||
|
public UplinkRequestUpdateInterfaceMessage()
|
||||||
|
{
|
||||||
|
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
16
Content.Shared/Traitor/Uplink/UplinkNetworkEvents.cs
Normal file
16
Content.Shared/Traitor/Uplink/UplinkNetworkEvents.cs
Normal file
@@ -0,0 +1,16 @@
|
|||||||
|
using Robust.Shared.GameObjects;
|
||||||
|
using Robust.Shared.Serialization;
|
||||||
|
using System;
|
||||||
|
|
||||||
|
namespace Content.Shared.Traitor.Uplink
|
||||||
|
{
|
||||||
|
[Serializable, NetSerializable]
|
||||||
|
public sealed class UplinkBuySuccessMessage : EntityEventArgs
|
||||||
|
{
|
||||||
|
}
|
||||||
|
|
||||||
|
[Serializable, NetSerializable]
|
||||||
|
public sealed class UplinkInsufficientFundsMessage : EntityEventArgs
|
||||||
|
{
|
||||||
|
}
|
||||||
|
}
|
||||||
19
Content.Shared/Traitor/Uplink/UplinkUpdateState.cs
Normal file
19
Content.Shared/Traitor/Uplink/UplinkUpdateState.cs
Normal file
@@ -0,0 +1,19 @@
|
|||||||
|
using Robust.Shared.GameObjects;
|
||||||
|
using Robust.Shared.Serialization;
|
||||||
|
using System;
|
||||||
|
|
||||||
|
namespace Content.Shared.Traitor.Uplink
|
||||||
|
{
|
||||||
|
[Serializable, NetSerializable]
|
||||||
|
public class UplinkUpdateState : BoundUserInterfaceState
|
||||||
|
{
|
||||||
|
public UplinkAccountData Account;
|
||||||
|
public UplinkListingData[] Listings;
|
||||||
|
|
||||||
|
public UplinkUpdateState(UplinkAccountData account, UplinkListingData[] listings)
|
||||||
|
{
|
||||||
|
Account = account;
|
||||||
|
Listings = listings;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
11
Content.Shared/Traitor/Uplink/UplinkVisuals.cs
Normal file
11
Content.Shared/Traitor/Uplink/UplinkVisuals.cs
Normal file
@@ -0,0 +1,11 @@
|
|||||||
|
using Robust.Shared.Serialization;
|
||||||
|
using System;
|
||||||
|
|
||||||
|
namespace Content.Shared.Traitor.Uplink
|
||||||
|
{
|
||||||
|
[Serializable, NetSerializable]
|
||||||
|
public enum UplinkUiKey : byte
|
||||||
|
{
|
||||||
|
Key
|
||||||
|
}
|
||||||
|
}
|
||||||
@@ -0,0 +1,4 @@
|
|||||||
|
item-slots-try-insert-no-hands = You have no hands.
|
||||||
|
|
||||||
|
# EjectItemVerb
|
||||||
|
eject-item-verb-text-default = Eject {$item}
|
||||||
@@ -0,0 +1,2 @@
|
|||||||
|
# ToggleFlashlightVerb
|
||||||
|
toggle-flashlight-verb-get-data-text = Toggle flashlight
|
||||||
@@ -1,9 +1,6 @@
|
|||||||
|
|
||||||
### UI
|
### UI
|
||||||
|
|
||||||
comp-pda-ui-try-insert-id-card-no-hands = You have no hands.
|
|
||||||
comp-pda-ui-try-insert-pen-no-hands = You have no hands.
|
|
||||||
|
|
||||||
# For the PDA screen
|
# For the PDA screen
|
||||||
comp-pda-ui = ID: [color=white]{$Owner}[/color], [color=yellow]{$JobTitle}[/color]
|
comp-pda-ui = ID: [color=white]{$Owner}[/color], [color=yellow]{$JobTitle}[/color]
|
||||||
|
|
||||||
@@ -11,10 +8,6 @@ comp-pda-ui-blank = ID:
|
|||||||
|
|
||||||
comp-pda-ui-owner = Owner: [color=white]{$ActualOwnerName}[/color]
|
comp-pda-ui-owner = Owner: [color=white]{$ActualOwnerName}[/color]
|
||||||
|
|
||||||
pda-bound-user-interface-insufficient-funds-popup = Insufficient funds!
|
|
||||||
|
|
||||||
pda-bound-user-interface-tc-balance-popup = TC Balance: [color={$weightedColor}]{$balance}[/color]
|
|
||||||
|
|
||||||
pda-bound-user-interface-main-menu-tab-title = Main Menu
|
pda-bound-user-interface-main-menu-tab-title = Main Menu
|
||||||
|
|
||||||
pda-bound-user-interface-uplink-tab-title = Uplink
|
pda-bound-user-interface-uplink-tab-title = Uplink
|
||||||
@@ -26,12 +19,3 @@ comp-pda-ui-eject-id-button = Eject ID
|
|||||||
comp-pda-ui-eject-pen-button = Eject Pen
|
comp-pda-ui-eject-pen-button = Eject Pen
|
||||||
|
|
||||||
comp-pda-ui-toggle-flashlight-button = Toggle Flashlight
|
comp-pda-ui-toggle-flashlight-button = Toggle Flashlight
|
||||||
|
|
||||||
# EjectIDVerb
|
|
||||||
eject-id-verb-get-data-text = Eject ID
|
|
||||||
|
|
||||||
# EjectPenVerb
|
|
||||||
eject-pen-verb-get-data-text = Eject Pen
|
|
||||||
|
|
||||||
# ToggleFlashlightVerb
|
|
||||||
toggle-flashlight-verb-get-data-text = Toggle flashlight
|
|
||||||
@@ -0,0 +1,3 @@
|
|||||||
|
uplink-bound-user-interface-insufficient-funds-popup = Insufficient funds!
|
||||||
|
|
||||||
|
uplink-bound-user-interface-tc-balance-popup = TC Balance: [color={$weightedColor}]{$balance}[/color]
|
||||||
@@ -21,6 +21,7 @@
|
|||||||
Slots:
|
Slots:
|
||||||
- idcard
|
- idcard
|
||||||
- Belt
|
- Belt
|
||||||
|
- type: UnpoweredFlashlight
|
||||||
- type: PointLight
|
- type: PointLight
|
||||||
enabled: false
|
enabled: false
|
||||||
radius: 1.4
|
radius: 1.4
|
||||||
@@ -30,6 +31,24 @@
|
|||||||
interfaces:
|
interfaces:
|
||||||
- key: enum.PDAUiKey.Key
|
- key: enum.PDAUiKey.Key
|
||||||
type: PDABoundUserInterface
|
type: PDABoundUserInterface
|
||||||
|
- key: enum.UplinkUiKey.Key
|
||||||
|
type: UplinkBoundUserInterface
|
||||||
|
- type: ItemSlots
|
||||||
|
slots:
|
||||||
|
pda_pen_slot:
|
||||||
|
item: "Pen"
|
||||||
|
whitelist:
|
||||||
|
tags:
|
||||||
|
- Write
|
||||||
|
pda_id_slot:
|
||||||
|
insertSound:
|
||||||
|
path: /Audio/Weapons/Guns/MagIn/batrifle_magin.ogg
|
||||||
|
ejectSound:
|
||||||
|
path: /Audio/Machines/id_swipe.ogg
|
||||||
|
whitelist:
|
||||||
|
components:
|
||||||
|
- IdCard
|
||||||
|
- type: PDA
|
||||||
- type: DoorBumpOpener
|
- type: DoorBumpOpener
|
||||||
|
|
||||||
- type: entity
|
- type: entity
|
||||||
|
|||||||
Reference in New Issue
Block a user