From 4c20a504a5661213e03ec3a73adb2f31a2d44f73 Mon Sep 17 00:00:00 2001 From: FL-OZ <58238103+FL-OZ@users.noreply.github.com> Date: Thu, 28 May 2020 06:22:47 -0500 Subject: [PATCH] Add basic PDA/Syndicate Uplink. (#942) Co-authored-by: FL-OZ Co-authored-by: Pieter-Jan Briers --- .../Components/PDA/PDABoundUserInterface.cs | 432 ++++++++++++++++++ .../Components/PDA/PDAComponent.cs | 11 + .../Components/PDA/PDAVisualizer.cs | 38 ++ Content.Server/EntryPoint.cs | 2 + .../Components/Access/AccessComponent.cs | 17 +- .../Access/AccessReaderComponent.cs | 26 +- .../Access/IdCardConsoleComponent.cs | 4 +- .../Components/PDA/PDAComponent.cs | 254 ++++++++++ Content.Server/GameTicking/GameTicker.cs | 36 +- Content.Server/Interfaces/IAccess.cs | 11 + .../Interfaces/PDA/IPDAUplinkManager.cs | 19 + Content.Server/PDA/PDAUplinkManager.cs | 107 +++++ Content.Server/ServerContentIoC.cs | 3 + .../Components/PDA/SharedPDAComponent.cs | 184 ++++++++ .../Components/PDA/UplinkCategory.cs | 8 + Content.Shared/GameObjects/ContentNetIDs.cs | 1 + .../PDA/UplinkStoreListingPrototype.cs | 42 ++ Resources/Prototypes/Entities/Items/pda.yml | 353 ++++++++++++++ .../Prototypes/Jobs/Cargo/CargoTechnician.yml | 2 +- .../Prototypes/Jobs/Civilian/Assistant.yml | 2 +- .../Prototypes/Jobs/Civilian/Bartender.yml | 2 +- Resources/Prototypes/Jobs/Civilian/Chef.yml | 2 +- Resources/Prototypes/Jobs/Civilian/Clown.yml | 2 +- .../Prototypes/Jobs/Civilian/Janitor.yml | 2 +- Resources/Prototypes/Jobs/Command/Captain.yml | 2 +- .../Jobs/Command/HeadOfPersonnel.yml | 2 +- .../Jobs/Engineering/ChiefEngineer.yml | 2 +- .../Jobs/Engineering/StationEngineer.yml | 2 +- .../Jobs/Medical/ChiefMedicalOfficer.yml | 2 +- .../Prototypes/Jobs/Medical/MedicalDoctor.yml | 2 +- .../Jobs/Science/ResearchDirector.yml | 2 +- .../Prototypes/Jobs/Science/Scientist.yml | 2 +- .../Jobs/Security/HeadOfSecurity.yml | 2 +- .../Jobs/Security/SecurityOfficer.yml | 2 +- Resources/Prototypes/PDA/uplink_catalog.yml | 29 ++ .../Objects/Devices/pda.rsi/aicard-404.png | Bin 0 -> 478 bytes .../Objects/Devices/pda.rsi/aicard-full.png | Bin 0 -> 702 bytes .../Objects/Devices/pda.rsi/aicard-on.png | Bin 0 -> 104 bytes .../Objects/Devices/pda.rsi/aicard.png | Bin 0 -> 404 bytes .../Objects/Devices/pda.rsi/cart-a.png | Bin 0 -> 248 bytes .../Objects/Devices/pda.rsi/cart-b.png | Bin 0 -> 298 bytes .../Objects/Devices/pda.rsi/cart-c.png | Bin 0 -> 277 bytes .../Objects/Devices/pda.rsi/cart-ce.png | Bin 0 -> 278 bytes .../Objects/Devices/pda.rsi/cart-chem.png | Bin 0 -> 246 bytes .../Objects/Devices/pda.rsi/cart-clown.png | Bin 0 -> 268 bytes .../Objects/Devices/pda.rsi/cart-cmo.png | Bin 0 -> 316 bytes .../Objects/Devices/pda.rsi/cart-e.png | Bin 0 -> 257 bytes .../Objects/Devices/pda.rsi/cart-eye.png | Bin 0 -> 301 bytes .../Objects/Devices/pda.rsi/cart-h.png | Bin 0 -> 279 bytes .../Objects/Devices/pda.rsi/cart-hos.png | Bin 0 -> 291 bytes .../Objects/Devices/pda.rsi/cart-j.png | Bin 0 -> 278 bytes .../Objects/Devices/pda.rsi/cart-lib.png | Bin 0 -> 244 bytes .../Objects/Devices/pda.rsi/cart-m.png | Bin 0 -> 276 bytes .../Objects/Devices/pda.rsi/cart-mi.png | Bin 0 -> 275 bytes .../Objects/Devices/pda.rsi/cart-q.png | Bin 0 -> 259 bytes .../Objects/Devices/pda.rsi/cart-rd.png | Bin 0 -> 312 bytes .../Objects/Devices/pda.rsi/cart-s.png | Bin 0 -> 277 bytes .../Objects/Devices/pda.rsi/cart-tear.png | Bin 0 -> 315 bytes .../Objects/Devices/pda.rsi/cart-tox.png | Bin 0 -> 299 bytes .../Textures/Objects/Devices/pda.rsi/cart.png | Bin 0 -> 242 bytes .../Textures/Objects/Devices/pda.rsi/crap.png | Bin 0 -> 434 bytes .../Objects/Devices/pda.rsi/meta.json | 1 + .../Objects/Devices/pda.rsi/morecrap.png | Bin 0 -> 325 bytes .../Objects/Devices/pda.rsi/pai-angry.png | Bin 0 -> 428 bytes .../Objects/Devices/pda.rsi/pai-cat.png | Bin 0 -> 469 bytes .../Devices/pda.rsi/pai-exclamation.png | Bin 0 -> 377 bytes .../Devices/pda.rsi/pai-extremely-happy.png | Bin 0 -> 447 bytes .../Objects/Devices/pda.rsi/pai-face.png | Bin 0 -> 534 bytes .../Objects/Devices/pda.rsi/pai-happy.png | Bin 0 -> 427 bytes .../Objects/Devices/pda.rsi/pai-laugh.png | Bin 0 -> 484 bytes .../Objects/Devices/pda.rsi/pai-neutral.png | Bin 0 -> 397 bytes .../Objects/Devices/pda.rsi/pai-nose.png | Bin 0 -> 269 bytes .../Objects/Devices/pda.rsi/pai-off.png | Bin 0 -> 171 bytes .../Objects/Devices/pda.rsi/pai-question.png | Bin 0 -> 402 bytes .../Objects/Devices/pda.rsi/pai-sad.png | Bin 0 -> 704 bytes .../Objects/Devices/pda.rsi/pai-silly.png | Bin 0 -> 499 bytes .../Objects/Devices/pda.rsi/pai-smirk.png | Bin 0 -> 464 bytes .../Objects/Devices/pda.rsi/pai-what.png | Bin 0 -> 487 bytes .../Textures/Objects/Devices/pda.rsi/pai.png | Bin 0 -> 354 bytes .../Objects/Devices/pda.rsi/pda-atmo.png | Bin 0 -> 500 bytes .../Objects/Devices/pda.rsi/pda-bar.png | Bin 0 -> 403 bytes .../Objects/Devices/pda.rsi/pda-c.png | Bin 0 -> 442 bytes .../Objects/Devices/pda.rsi/pda-cargo.png | Bin 0 -> 417 bytes .../Objects/Devices/pda.rsi/pda-ce.png | Bin 0 -> 482 bytes .../Objects/Devices/pda.rsi/pda-chef.png | Bin 0 -> 420 bytes .../Objects/Devices/pda.rsi/pda-chem.png | Bin 0 -> 478 bytes .../Objects/Devices/pda.rsi/pda-clown.png | Bin 0 -> 526 bytes .../Objects/Devices/pda.rsi/pda-cmo.png | Bin 0 -> 450 bytes .../Objects/Devices/pda.rsi/pda-det.png | Bin 0 -> 434 bytes .../Objects/Devices/pda.rsi/pda-e.png | Bin 0 -> 500 bytes .../Objects/Devices/pda.rsi/pda-h.png | Bin 0 -> 452 bytes .../Objects/Devices/pda.rsi/pda-holy.png | Bin 0 -> 408 bytes .../Objects/Devices/pda.rsi/pda-hop.png | Bin 0 -> 462 bytes .../Objects/Devices/pda.rsi/pda-hos.png | Bin 0 -> 561 bytes .../Objects/Devices/pda.rsi/pda-hydro.png | Bin 0 -> 478 bytes .../Objects/Devices/pda.rsi/pda-j.png | Bin 0 -> 415 bytes .../Devices/pda.rsi/pda-lawyer-old.png | Bin 0 -> 462 bytes .../Objects/Devices/pda.rsi/pda-lawyer.png | Bin 0 -> 436 bytes .../Objects/Devices/pda.rsi/pda-libb.png | Bin 0 -> 456 bytes .../Objects/Devices/pda.rsi/pda-libc.png | Bin 0 -> 902 bytes .../Objects/Devices/pda.rsi/pda-m.png | Bin 0 -> 465 bytes .../Objects/Devices/pda.rsi/pda-mime.png | Bin 0 -> 492 bytes .../Objects/Devices/pda.rsi/pda-miner.png | Bin 0 -> 489 bytes .../Objects/Devices/pda.rsi/pda-q.png | Bin 0 -> 461 bytes .../Objects/Devices/pda.rsi/pda-r.png | Bin 0 -> 555 bytes .../Objects/Devices/pda.rsi/pda-rd.png | Bin 0 -> 472 bytes .../Objects/Devices/pda.rsi/pda-robot.png | Bin 0 -> 480 bytes .../Objects/Devices/pda.rsi/pda-s.png | Bin 0 -> 575 bytes .../Objects/Devices/pda.rsi/pda-syn.png | Bin 0 -> 435 bytes .../Objects/Devices/pda.rsi/pda-tox.png | Bin 0 -> 463 bytes .../Objects/Devices/pda.rsi/pda-transp.png | Bin 0 -> 534 bytes .../Objects/Devices/pda.rsi/pda-v.png | Bin 0 -> 472 bytes .../Objects/Devices/pda.rsi/pda-warden.png | Bin 0 -> 591 bytes .../Textures/Objects/Devices/pda.rsi/pda.png | Bin 0 -> 416 bytes .../Objects/Devices/pda.rsi/pda_pen.png | Bin 0 -> 129 bytes .../Objects/Devices/pda.rsi/pdabox.png | Bin 0 -> 403 bytes .../Devices/pda.rsi/unlit_pda_screen.png | Bin 0 -> 5834 bytes 117 files changed, 1569 insertions(+), 41 deletions(-) create mode 100644 Content.Client/GameObjects/Components/PDA/PDABoundUserInterface.cs create mode 100644 Content.Client/GameObjects/Components/PDA/PDAComponent.cs create mode 100644 Content.Client/GameObjects/Components/PDA/PDAVisualizer.cs create mode 100644 Content.Server/GameObjects/Components/PDA/PDAComponent.cs create mode 100644 Content.Server/Interfaces/IAccess.cs create mode 100644 Content.Server/Interfaces/PDA/IPDAUplinkManager.cs create mode 100644 Content.Server/PDA/PDAUplinkManager.cs create mode 100644 Content.Shared/GameObjects/Components/PDA/SharedPDAComponent.cs create mode 100644 Content.Shared/GameObjects/Components/PDA/UplinkCategory.cs create mode 100644 Content.Shared/Prototypes/PDA/UplinkStoreListingPrototype.cs create mode 100644 Resources/Prototypes/Entities/Items/pda.yml create mode 100644 Resources/Prototypes/PDA/uplink_catalog.yml create mode 100644 Resources/Textures/Objects/Devices/pda.rsi/aicard-404.png create mode 100644 Resources/Textures/Objects/Devices/pda.rsi/aicard-full.png create mode 100644 Resources/Textures/Objects/Devices/pda.rsi/aicard-on.png create mode 100644 Resources/Textures/Objects/Devices/pda.rsi/aicard.png create mode 100644 Resources/Textures/Objects/Devices/pda.rsi/cart-a.png create mode 100644 Resources/Textures/Objects/Devices/pda.rsi/cart-b.png create mode 100644 Resources/Textures/Objects/Devices/pda.rsi/cart-c.png create mode 100644 Resources/Textures/Objects/Devices/pda.rsi/cart-ce.png create mode 100644 Resources/Textures/Objects/Devices/pda.rsi/cart-chem.png create mode 100644 Resources/Textures/Objects/Devices/pda.rsi/cart-clown.png create mode 100644 Resources/Textures/Objects/Devices/pda.rsi/cart-cmo.png create mode 100644 Resources/Textures/Objects/Devices/pda.rsi/cart-e.png create mode 100644 Resources/Textures/Objects/Devices/pda.rsi/cart-eye.png create mode 100644 Resources/Textures/Objects/Devices/pda.rsi/cart-h.png create mode 100644 Resources/Textures/Objects/Devices/pda.rsi/cart-hos.png create mode 100644 Resources/Textures/Objects/Devices/pda.rsi/cart-j.png create mode 100644 Resources/Textures/Objects/Devices/pda.rsi/cart-lib.png create mode 100644 Resources/Textures/Objects/Devices/pda.rsi/cart-m.png create mode 100644 Resources/Textures/Objects/Devices/pda.rsi/cart-mi.png create mode 100644 Resources/Textures/Objects/Devices/pda.rsi/cart-q.png create mode 100644 Resources/Textures/Objects/Devices/pda.rsi/cart-rd.png create mode 100644 Resources/Textures/Objects/Devices/pda.rsi/cart-s.png create mode 100644 Resources/Textures/Objects/Devices/pda.rsi/cart-tear.png create mode 100644 Resources/Textures/Objects/Devices/pda.rsi/cart-tox.png create mode 100644 Resources/Textures/Objects/Devices/pda.rsi/cart.png create mode 100644 Resources/Textures/Objects/Devices/pda.rsi/crap.png create mode 100644 Resources/Textures/Objects/Devices/pda.rsi/meta.json create mode 100644 Resources/Textures/Objects/Devices/pda.rsi/morecrap.png create mode 100644 Resources/Textures/Objects/Devices/pda.rsi/pai-angry.png create mode 100644 Resources/Textures/Objects/Devices/pda.rsi/pai-cat.png create mode 100644 Resources/Textures/Objects/Devices/pda.rsi/pai-exclamation.png create mode 100644 Resources/Textures/Objects/Devices/pda.rsi/pai-extremely-happy.png create mode 100644 Resources/Textures/Objects/Devices/pda.rsi/pai-face.png create mode 100644 Resources/Textures/Objects/Devices/pda.rsi/pai-happy.png create mode 100644 Resources/Textures/Objects/Devices/pda.rsi/pai-laugh.png create mode 100644 Resources/Textures/Objects/Devices/pda.rsi/pai-neutral.png create mode 100644 Resources/Textures/Objects/Devices/pda.rsi/pai-nose.png create mode 100644 Resources/Textures/Objects/Devices/pda.rsi/pai-off.png create mode 100644 Resources/Textures/Objects/Devices/pda.rsi/pai-question.png create mode 100644 Resources/Textures/Objects/Devices/pda.rsi/pai-sad.png create mode 100644 Resources/Textures/Objects/Devices/pda.rsi/pai-silly.png create mode 100644 Resources/Textures/Objects/Devices/pda.rsi/pai-smirk.png create mode 100644 Resources/Textures/Objects/Devices/pda.rsi/pai-what.png create mode 100644 Resources/Textures/Objects/Devices/pda.rsi/pai.png create mode 100644 Resources/Textures/Objects/Devices/pda.rsi/pda-atmo.png create mode 100644 Resources/Textures/Objects/Devices/pda.rsi/pda-bar.png create mode 100644 Resources/Textures/Objects/Devices/pda.rsi/pda-c.png create mode 100644 Resources/Textures/Objects/Devices/pda.rsi/pda-cargo.png create mode 100644 Resources/Textures/Objects/Devices/pda.rsi/pda-ce.png create mode 100644 Resources/Textures/Objects/Devices/pda.rsi/pda-chef.png create mode 100644 Resources/Textures/Objects/Devices/pda.rsi/pda-chem.png create mode 100644 Resources/Textures/Objects/Devices/pda.rsi/pda-clown.png create mode 100644 Resources/Textures/Objects/Devices/pda.rsi/pda-cmo.png create mode 100644 Resources/Textures/Objects/Devices/pda.rsi/pda-det.png create mode 100644 Resources/Textures/Objects/Devices/pda.rsi/pda-e.png create mode 100644 Resources/Textures/Objects/Devices/pda.rsi/pda-h.png create mode 100644 Resources/Textures/Objects/Devices/pda.rsi/pda-holy.png create mode 100644 Resources/Textures/Objects/Devices/pda.rsi/pda-hop.png create mode 100644 Resources/Textures/Objects/Devices/pda.rsi/pda-hos.png create mode 100644 Resources/Textures/Objects/Devices/pda.rsi/pda-hydro.png create mode 100644 Resources/Textures/Objects/Devices/pda.rsi/pda-j.png create mode 100644 Resources/Textures/Objects/Devices/pda.rsi/pda-lawyer-old.png create mode 100644 Resources/Textures/Objects/Devices/pda.rsi/pda-lawyer.png create mode 100644 Resources/Textures/Objects/Devices/pda.rsi/pda-libb.png create mode 100644 Resources/Textures/Objects/Devices/pda.rsi/pda-libc.png create mode 100644 Resources/Textures/Objects/Devices/pda.rsi/pda-m.png create mode 100644 Resources/Textures/Objects/Devices/pda.rsi/pda-mime.png create mode 100644 Resources/Textures/Objects/Devices/pda.rsi/pda-miner.png create mode 100644 Resources/Textures/Objects/Devices/pda.rsi/pda-q.png create mode 100644 Resources/Textures/Objects/Devices/pda.rsi/pda-r.png create mode 100644 Resources/Textures/Objects/Devices/pda.rsi/pda-rd.png create mode 100644 Resources/Textures/Objects/Devices/pda.rsi/pda-robot.png create mode 100644 Resources/Textures/Objects/Devices/pda.rsi/pda-s.png create mode 100644 Resources/Textures/Objects/Devices/pda.rsi/pda-syn.png create mode 100644 Resources/Textures/Objects/Devices/pda.rsi/pda-tox.png create mode 100644 Resources/Textures/Objects/Devices/pda.rsi/pda-transp.png create mode 100644 Resources/Textures/Objects/Devices/pda.rsi/pda-v.png create mode 100644 Resources/Textures/Objects/Devices/pda.rsi/pda-warden.png create mode 100644 Resources/Textures/Objects/Devices/pda.rsi/pda.png create mode 100644 Resources/Textures/Objects/Devices/pda.rsi/pda_pen.png create mode 100644 Resources/Textures/Objects/Devices/pda.rsi/pdabox.png create mode 100644 Resources/Textures/Objects/Devices/pda.rsi/unlit_pda_screen.png diff --git a/Content.Client/GameObjects/Components/PDA/PDABoundUserInterface.cs b/Content.Client/GameObjects/Components/PDA/PDABoundUserInterface.cs new file mode 100644 index 0000000000..6b30c82036 --- /dev/null +++ b/Content.Client/GameObjects/Components/PDA/PDABoundUserInterface.cs @@ -0,0 +1,432 @@ +using System; +using Content.Client.Utility; +using Content.Shared.GameObjects.Components.PDA; +using Robust.Client.GameObjects.Components.UserInterface; +using Robust.Client.Graphics.Drawing; +using Robust.Client.UserInterface.Controls; +using Robust.Client.UserInterface.CustomControls; +using Robust.Shared.GameObjects; +using Robust.Shared.GameObjects.Components.UserInterface; +using Robust.Shared.IoC; +using Robust.Shared.Localization; +using Robust.Shared.Maths; +using Robust.Shared.Prototypes; +using Robust.Shared.Utility; + +namespace Content.Client.GameObjects.Components.PDA +{ + public class PDABoundUserInterface : BoundUserInterface + { +#pragma warning disable 649 + [Dependency] private readonly IPrototypeManager _prototypeManager; +#pragma warning restore 649 + private PDAMenu _menu; + private ClientUserInterfaceComponent Owner; + + public PDABoundUserInterface(ClientUserInterfaceComponent owner, object uiKey) : base(owner, uiKey) + { + Owner = owner; + } + + protected override void Open() + { + base.Open(); + SendMessage(new PDARequestUpdateInterfaceMessage()); + _menu = new PDAMenu(this, _prototypeManager); + _menu.OpenToLeft(); + _menu.OnClose += Close; + _menu.FlashLightToggleButton.OnToggled += args => + { + SendMessage(new PDAToggleFlashlightMessage()); + }; + + _menu.EjectIDButton.OnPressed += args => + { + SendMessage(new PDAEjectIDMessage()); + }; + + _menu.MasterTabContainer.OnTabChanged += i => + { + var tab = _menu.MasterTabContainer.GetChild(i); + if (tab == _menu.UplinkTabContainer) + { + SendMessage(new PDARequestUpdateInterfaceMessage()); + } + }; + + _menu.OnListingButtonPressed += (args, listing) => + { + SendMessage(new PDAUplinkBuyListingMessage(listing)); + }; + + _menu.OnCategoryButtonPressed += (args, category) => + { + _menu.CurrentFilterCategory = category; + SendMessage(new PDARequestUpdateInterfaceMessage()); + + }; + } + + + protected override void UpdateState(BoundUserInterfaceState state) + { + base.UpdateState(state); + DebugTools.Assert((state is PDAUBoundUserInterfaceState)); + + var cstate = (PDAUBoundUserInterfaceState) state; + switch (state) + { + case PDAUpdateState msg: + { + _menu.FlashLightToggleButton.Pressed = msg.FlashlightEnabled; + _menu.PDAOwnerLabel.SetMarkup(Loc.GetString("Owner: [color=white]{0}[/color]", + msg.PDAOwnerInfo.ActualOwnerName)); + + if (msg.PDAOwnerInfo.JobTitle == null || msg.PDAOwnerInfo.IdOwner == null) + { + _menu.IDInfoLabel.SetMarkup(Loc.GetString("ID:")); + } + else + { + _menu.IDInfoLabel.SetMarkup(Loc.GetString( + "ID: [color=white]{0}[/color], [color=yellow]{1}[/color]", + msg.PDAOwnerInfo.IdOwner, + msg.PDAOwnerInfo.JobTitle)); + } + + _menu.EjectIDButton.Visible = msg.PDAOwnerInfo.IdOwner != null; + if (msg.Account != null) + { + _menu.CurrentLoggedInAccount = msg.Account; + } + + 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); + } + } + break; + } + + } + } + + protected override void Dispose(bool disposing) + { + base.Dispose(disposing); + _menu?.Dispose(); + } + + private class PDAMenu : SS14Window + { + protected override Vector2? CustomSize => (512, 256); + + private PDABoundUserInterface _owner { get; } + + public Button FlashLightToggleButton { get; } + public Button EjectIDButton { get; } + + public TabContainer MasterTabContainer; + + public RichTextLabel PDAOwnerLabel { get; } + public PanelContainer IDInfoContainer { get; } + public RichTextLabel IDInfoLabel { get; } + + public VBoxContainer UplinkTabContainer { get; } + + protected HSplitContainer CategoryAndListingsContainer; + + private IPrototypeManager _prototypeManager; + + public VBoxContainer UplinkListingsContainer; + + public VBoxContainer CategoryListContainer; + public event Action OnListingButtonPressed; + public event Action 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) + { + _owner = owner; + _prototypeManager = prototypeManager; + Title = Loc.GetString("PDA"); + + #region MAIN_MENU_TAB + //Main menu + PDAOwnerLabel = new RichTextLabel + { + }; + + IDInfoLabel = new RichTextLabel() + { + SizeFlagsHorizontal = SizeFlags.FillExpand, + }; + + EjectIDButton = new Button + { + Text = Loc.GetString("Eject ID"), + SizeFlagsHorizontal = SizeFlags.ShrinkCenter, + SizeFlagsVertical = SizeFlags.ShrinkCenter + }; + + var innerHBoxContainer = new HBoxContainer + { + Children = + { + IDInfoLabel, + EjectIDButton + } + }; + + IDInfoContainer = new PanelContainer + { + SizeFlagsHorizontal = SizeFlags.Fill, + Children = + { + innerHBoxContainer, + } + }; + + FlashLightToggleButton = new Button + { + Text = Loc.GetString("Toggle Flashlight"), + ToggleMode = true, + }; + + var mainMenuTabContainer = new VBoxContainer + { + SizeFlagsVertical = SizeFlags.FillExpand, + SizeFlagsHorizontal = SizeFlags.FillExpand, + CustomMinimumSize = (50, 50), + + Children = + { + PDAOwnerLabel, + IDInfoContainer, + FlashLightToggleButton + } + }; + + #endregion + + #region UPLINK_TAB + //Uplink Tab + CategoryListContainer = new VBoxContainer + { + }; + var uplinkStoreHeader = new Label + { + Align = Label.AlignMode.Center, + Text = Loc.GetString("Uplink Listings"), + }; + + //Red background container. + var masterPanelContainer = new PanelContainer + { + PanelOverride = new StyleBoxFlat {BackgroundColor = Color.DarkRed.WithAlpha(0.6f)}, + SizeFlagsVertical = SizeFlags.FillExpand + }; + + //This contains both the panel of the category buttons and the listings box. + CategoryAndListingsContainer = new HSplitContainer + { + SizeFlagsVertical = SizeFlags.FillExpand, + }; + + + var uplinkShopScrollContainer = new ScrollContainer + { + SizeFlagsHorizontal = SizeFlags.FillExpand, + SizeFlagsVertical = SizeFlags.FillExpand, + SizeFlagsStretchRatio = 2, + CustomMinimumSize = (100, 256) + }; + + //Add the category list to the left side. The store items to center. + var categoryListContainerBackground = new PanelContainer + { + PanelOverride = new StyleBoxFlat {BackgroundColor = Color.Black.WithAlpha(0.4f)}, + SizeFlagsVertical = SizeFlags.FillExpand, + Children = + { + CategoryListContainer + } + }; + + CategoryAndListingsContainer.AddChild(categoryListContainerBackground); + CategoryAndListingsContainer.AddChild(uplinkShopScrollContainer); + masterPanelContainer.AddChild(CategoryAndListingsContainer); + + //Actual list of buttons for buying a listing from the uplink. + UplinkListingsContainer = new VBoxContainer + { + SizeFlagsHorizontal = SizeFlags.FillExpand, + SizeFlagsVertical = SizeFlags.FillExpand, + SizeFlagsStretchRatio = 2, + CustomMinimumSize = (100, 256), + }; + uplinkShopScrollContainer.AddChild(UplinkListingsContainer); + + var innerVboxContainer = new VBoxContainer + { + SizeFlagsVertical = SizeFlags.FillExpand, + + Children = + { + uplinkStoreHeader, + masterPanelContainer + } + }; + + UplinkTabContainer = new VBoxContainer + { + 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("Main Menu")); + MasterTabContainer.AddChild(UplinkTabContainer); + MasterTabContainer.SetTabTitle(1, Loc.GetString("Uplink")); + 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 + + }; + + 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 itemLabel = new Label + { + Text = listing.ListingName == string.Empty ? prototype.Name : listing.ListingName, + ToolTip = listing.Description == string.Empty ? prototype.Description : listing.Description, + SizeFlagsHorizontal = SizeFlags.FillExpand, + }; + + var priceLabel = new Label + { + Text = $"{listing.Price} TC", + Align = Label.AlignMode.Right, + }; + + + //Can the account afford this item? If so use the item's color, else gray it out. + var itemColor = _loggedInUplinkAccount.DataBalance >= listing.Price + ? listing.DisplayColor + : Color.Gray.WithAlpha(0.25f); + + //Contains the name of the item and its price. Used for spacing price and name. + var listingButtonHbox = new HBoxContainer + { + Modulate = itemColor, + Children = + { + itemLabel, + priceLabel + } + }; + + var listingButtonPanelContainer = new PanelContainer + { + Children = + { + listingButtonHbox + } + }; + + var pdaUplinkListingButton = new PDAUplinkItemButton + { + ButtonListing = listing, + SizeFlagsVertical = SizeFlags.Fill, + 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 UplinkListingData ButtonListing; + } + + private sealed class PDAUplinkCategoryButton : Button + { + public UplinkCategory ButtonCategory; + + } + } + } +} diff --git a/Content.Client/GameObjects/Components/PDA/PDAComponent.cs b/Content.Client/GameObjects/Components/PDA/PDAComponent.cs new file mode 100644 index 0000000000..8118d7ee33 --- /dev/null +++ b/Content.Client/GameObjects/Components/PDA/PDAComponent.cs @@ -0,0 +1,11 @@ +using Content.Shared.GameObjects.Components.PDA; +using Robust.Shared.GameObjects; + +namespace Content.Client.GameObjects.Components.PDA +{ + [RegisterComponent] + public class PDAComponent : SharedPDAComponent + { + + } +} diff --git a/Content.Client/GameObjects/Components/PDA/PDAVisualizer.cs b/Content.Client/GameObjects/Components/PDA/PDAVisualizer.cs new file mode 100644 index 0000000000..019bd03ae1 --- /dev/null +++ b/Content.Client/GameObjects/Components/PDA/PDAVisualizer.cs @@ -0,0 +1,38 @@ +using Content.Shared.GameObjects.Components.PDA; +using Robust.Client.GameObjects; +using Robust.Client.Interfaces.GameObjects.Components; + +namespace Content.Client.GameObjects.Components.PDA +{ + public class PDAVisualizer : AppearanceVisualizer + { + + private enum PDAVisualLayers + { + Base, + Unlit + } + + + public override void OnChangeData(AppearanceComponent component) + { + base.OnChangeData(component); + if (component.Owner.Deleted) + { + return; + } + var sprite = component.Owner.GetComponent(); + sprite.LayerSetVisible(PDAVisualLayers.Unlit, false); + if(!component.TryGetData(PDAVisuals.ScreenLit, out var isScreenLit)) + { + return; + } + sprite.LayerSetState(PDAVisualLayers.Unlit, "unlit_pda_screen"); + sprite.LayerSetVisible(PDAVisualLayers.Unlit, isScreenLit); + + + } + + + } +} diff --git a/Content.Server/EntryPoint.cs b/Content.Server/EntryPoint.cs index 6add00daed..885405dc93 100644 --- a/Content.Server/EntryPoint.cs +++ b/Content.Server/EntryPoint.cs @@ -2,6 +2,7 @@ using Content.Server.Interfaces; using Content.Server.Interfaces.Chat; using Content.Server.Interfaces.GameTicking; +using Content.Server.Interfaces.PDA; using Content.Server.Preferences; using Content.Server.Sandbox; using Content.Shared.Kitchen; @@ -84,6 +85,7 @@ namespace Content.Server IoCManager.Resolve().Initialize(); IoCManager.Resolve().FinishInit(); IoCManager.Resolve().Initialize(); + IoCManager.Resolve().Initialize(); } public override void Update(ModUpdateLevel level, FrameEventArgs frameEventArgs) diff --git a/Content.Server/GameObjects/Components/Access/AccessComponent.cs b/Content.Server/GameObjects/Components/Access/AccessComponent.cs index fa122346b7..829f47ed0e 100644 --- a/Content.Server/GameObjects/Components/Access/AccessComponent.cs +++ b/Content.Server/GameObjects/Components/Access/AccessComponent.cs @@ -1,4 +1,5 @@ using System.Collections.Generic; +using Content.Server.Interfaces; using Robust.Shared.GameObjects; using Robust.Shared.Serialization; using Robust.Shared.ViewVariables; @@ -6,16 +7,26 @@ using Robust.Shared.ViewVariables; namespace Content.Server.GameObjects.Components.Access { [RegisterComponent] - public class AccessComponent : Component + [ComponentReference(typeof(IAccess))] + public class AccessComponent : Component, IAccess { public override string Name => "Access"; [ViewVariables] - public List Tags; + private List _tags; public override void ExposeData(ObjectSerializer serializer) { base.ExposeData(serializer); + serializer.DataField(ref _tags, "tags", new List()); + } - serializer.DataField(ref Tags, "tags", new List()); + public List GetTags() + { + return _tags; + } + + public void SetTags(List newTags) + { + _tags = newTags; } } } diff --git a/Content.Server/GameObjects/Components/Access/AccessReaderComponent.cs b/Content.Server/GameObjects/Components/Access/AccessReaderComponent.cs index 6eba78317f..8f1e89da30 100644 --- a/Content.Server/GameObjects/Components/Access/AccessReaderComponent.cs +++ b/Content.Server/GameObjects/Components/Access/AccessReaderComponent.cs @@ -1,4 +1,6 @@ +using System; using System.Collections.Generic; +using Content.Server.Interfaces; using Content.Server.Interfaces.GameObjects; using Content.Shared.GameObjects.Components.Inventory; using JetBrains.Annotations; @@ -26,22 +28,22 @@ namespace Content.Server.GameObjects.Components.Access /// The entity to be searched for access. public bool IsAllowed(IEntity entity) { - var accessProvider = FindAccessProvider(entity); - return accessProvider != null && IsAllowed(accessProvider); + var tags = FindAccessTags(entity); + return tags != null && IsAllowed(tags); } - private bool IsAllowed(AccessComponent accessProvider) + private bool IsAllowed(List accessTags) { foreach (var sufficient in _sufficientTags) { - if (accessProvider.Tags.Contains(sufficient)) + if (accessTags.Contains(sufficient)) { return true; } } foreach (var necessary in _necessaryTags) { - if (!accessProvider.Tags.Contains(necessary)) + if (!accessTags.Contains(necessary)) { return false; } @@ -50,20 +52,20 @@ namespace Content.Server.GameObjects.Components.Access } [CanBeNull] - private static AccessComponent FindAccessProvider(IEntity entity) + private static List FindAccessTags(IEntity entity) { - if (entity.TryGetComponent(out AccessComponent accessComponent)) + if (entity.TryGetComponent(out IAccess accessComponent)) { - return accessComponent; + return accessComponent.GetTags(); } if (entity.TryGetComponent(out IHandsComponent handsComponent)) { var activeHandEntity = handsComponent.GetActiveHand?.Owner; if (activeHandEntity != null && - activeHandEntity.TryGetComponent(out AccessComponent handAccessComponent)) + activeHandEntity.TryGetComponent(out IAccess handAccessComponent)) { - return handAccessComponent; + return handAccessComponent.GetTags(); } } else @@ -74,10 +76,10 @@ namespace Content.Server.GameObjects.Components.Access { if (inventoryComponent.HasSlot(EquipmentSlotDefines.Slots.IDCARD) && inventoryComponent.TryGetSlotItem(EquipmentSlotDefines.Slots.IDCARD, out ItemComponent item) && - item.Owner.TryGetComponent(out AccessComponent idAccessComponent) + item.Owner.TryGetComponent(out IAccess idAccessComponent) ) { - return idAccessComponent; + return idAccessComponent.GetTags(); } } return null; diff --git a/Content.Server/GameObjects/Components/Access/IdCardConsoleComponent.cs b/Content.Server/GameObjects/Components/Access/IdCardConsoleComponent.cs index 12c7ac72ee..868c46a0db 100644 --- a/Content.Server/GameObjects/Components/Access/IdCardConsoleComponent.cs +++ b/Content.Server/GameObjects/Components/Access/IdCardConsoleComponent.cs @@ -101,7 +101,7 @@ namespace Content.Server.GameObjects.Components.Access return; } var targetIdAccess = targetIdEntity.GetComponent(); - targetIdAccess.Tags = newAccessList; + targetIdAccess.SetTags(newAccessList); } /// @@ -180,7 +180,7 @@ namespace Content.Server.GameObjects.Components.Access true, targetIdComponent.FullName, targetIdComponent.JobTitle, - targetAccessComponent.Tags, + targetAccessComponent.GetTags(), _privilegedIdContainer.ContainedEntity?.Name ?? "", _targetIdContainer.ContainedEntity?.Name ?? ""); } diff --git a/Content.Server/GameObjects/Components/PDA/PDAComponent.cs b/Content.Server/GameObjects/Components/PDA/PDAComponent.cs new file mode 100644 index 0000000000..9fb8ead381 --- /dev/null +++ b/Content.Server/GameObjects/Components/PDA/PDAComponent.cs @@ -0,0 +1,254 @@ +using System.Collections.Generic; +using System.Linq; +using Content.Server.GameObjects.Components.Access; +using Content.Server.GameObjects.EntitySystems; +using Content.Server.Interfaces; +using Content.Server.Interfaces.PDA; +using Content.Shared.GameObjects; +using Content.Shared.GameObjects.Components.PDA; +using JetBrains.Annotations; +using Robust.Server.GameObjects; +using Robust.Server.GameObjects.Components.Container; +using Robust.Server.GameObjects.Components.UserInterface; +using Robust.Server.Interfaces.GameObjects; +using Robust.Shared.GameObjects; +using Robust.Shared.Interfaces.GameObjects; +using Robust.Shared.Interfaces.Network; +using Robust.Shared.IoC; +using Robust.Shared.Localization; +using Robust.Shared.Players; +using Robust.Shared.Serialization; + +namespace Content.Server.GameObjects.Components.PDA +{ + [RegisterComponent] + [ComponentReference(typeof(IActivate))] + [ComponentReference(typeof(IAccess))] + public class PDAComponent : SharedPDAComponent, IInteractUsing, IActivate, IUse, IAccess + { +#pragma warning disable 649 + [Dependency] protected readonly IPDAUplinkManager _uplinkManager; + [Dependency] protected readonly IEntityManager _entityManager; +#pragma warning restore 649 + + private Container _idSlot; + private PointLightComponent _pdaLight; + private bool _lightOn = false; + private BoundUserInterface _interface; + private string _startingIdCard; + public bool IdSlotEmpty => _idSlot.ContainedEntities.Count < 1; + public IEntity OwnerMob { get; private set; } + + public IdCardComponent ContainedID { get; private set; } + + private AppearanceComponent _appearance; + + private UplinkAccount _syndicateUplinkAccount; + + public override void ExposeData(ObjectSerializer serializer) + { + base.ExposeData(serializer); + serializer.DataField(ref _startingIdCard, "idCard", "AssistantIDCard"); + } + + public override void Initialize() + { + base.Initialize(); + _idSlot = ContainerManagerComponent.Ensure("pda_entity_container", Owner, out var existed); + _pdaLight = Owner.GetComponent(); + _appearance = Owner.GetComponent(); + _interface = Owner.GetComponent() + .GetBoundUserInterface(PDAUiKey.Key); + _interface.OnReceiveMessage += UserInterfaceOnReceiveMessage; + var idCard = _entityManager.SpawnEntity(_startingIdCard, Owner.Transform.GridPosition); + var idCardComponent = idCard.GetComponent(); + InsertIdCard(idCardComponent); + UpdatePDAAppearance(); + } + + private void UserInterfaceOnReceiveMessage(ServerBoundUserInterfaceMessage message) + { + switch (message.Message) + { + case PDARequestUpdateInterfaceMessage msg: + { + UpdatePDAUserInterface(); + break; + } + case PDAToggleFlashlightMessage msg: + { + ToggleLight(); + break; + } + + case PDAEjectIDMessage msg: + { + HandleIDEjection(message.Session.AttachedEntity); + break; + } + + case PDAUplinkBuyListingMessage buyMsg: + { + + if (!_uplinkManager.TryPurchaseItem(_syndicateUplinkAccount, buyMsg.ListingToBuy)) + { + //TODO: Send a message that tells the buyer they are too poor or something. + } + + break; + } + } + } + + private void UpdatePDAUserInterface() + { + var ownerInfo = new PDAIdInfoText + { + ActualOwnerName = OwnerMob?.Name, + 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.ToArray(); + _interface.SetState(new PDAUpdateState(_lightOn,ownerInfo,accData,listings)); + } + else + { + _interface.SetState(new PDAUpdateState(_lightOn,ownerInfo)); + } + + UpdatePDAAppearance(); + } + + private void UpdatePDAAppearance() + { + _appearance?.SetData(PDAVisuals.ScreenLit, _lightOn); + } + + public bool InteractUsing(InteractUsingEventArgs eventArgs) + { + var item = eventArgs.Using; + if (!IdSlotEmpty) + { + return false; + } + + if (!item.TryGetComponent(out var idCardComponent) || _idSlot.Contains(item)) + { + return false; + } + InsertIdCard(idCardComponent); + UpdatePDAUserInterface(); + return true; + + } + + void IActivate.Activate(ActivateEventArgs eventArgs) + { + if (!eventArgs.User.TryGetComponent(out IActorComponent actor)) + { + return; + } + _interface.Open(actor.playerSession); + UpdatePDAAppearance(); + } + + public bool UseEntity(UseEntityEventArgs eventArgs) + { + if (!eventArgs.User.TryGetComponent(out IActorComponent actor)) + { + return false; + } + _interface.Open(actor.playerSession); + UpdatePDAAppearance(); + return true; + } + + public void SetPDAOwner(IEntity mob) + { + if (mob == OwnerMob) + { + return; + } + + OwnerMob = mob; + UpdatePDAUserInterface(); + } + + private void InsertIdCard(IdCardComponent card) + { + _idSlot.Insert(card.Owner); + ContainedID = card; + } + + /// + /// Initialize the PDA's syndicate uplink account. + /// + /// + public void InitUplinkAccount(UplinkAccount acc) + { + _syndicateUplinkAccount = acc; + _uplinkManager.AddNewAccount(_syndicateUplinkAccount); + + _syndicateUplinkAccount.BalanceChanged += account => + { + UpdatePDAUserInterface(); + }; + + UpdatePDAUserInterface(); + } + + private void ToggleLight() + { + _lightOn = !_lightOn; + _pdaLight.Enabled = _lightOn; + UpdatePDAUserInterface(); + } + + private void HandleIDEjection(IEntity pdaUser) + { + if (IdSlotEmpty) + { + return; + } + + var cardEntity = ContainedID.Owner; + _idSlot.Remove(cardEntity); + + var hands = pdaUser.GetComponent(); + var cardItemComponent = cardEntity.GetComponent(); + hands.PutInHandOrDrop(cardItemComponent); + ContainedID = null; + UpdatePDAUserInterface(); + } + + [Verb] + public sealed class EjectIDVerb : Verb + { + protected override void GetData(IEntity user, PDAComponent component, VerbData data) + { + data.Text = Loc.GetString("Eject ID"); + data.Visibility = component.IdSlotEmpty ? VerbVisibility.Invisible : VerbVisibility.Visible; + } + + protected override void Activate(IEntity user, PDAComponent component) + { + component.HandleIDEjection(user); + } + } + + List IAccess.GetTags() + { + return ContainedID?.Owner.GetComponent()?.GetTags(); + } + + void IAccess.SetTags(List newTags) + { + ContainedID?.Owner.GetComponent().SetTags(newTags); + } + } +} diff --git a/Content.Server/GameTicking/GameTicker.cs b/Content.Server/GameTicking/GameTicker.cs index 9f3b8cc536..796e2e5c0a 100644 --- a/Content.Server/GameTicking/GameTicker.cs +++ b/Content.Server/GameTicking/GameTicker.cs @@ -7,6 +7,7 @@ using Content.Server.GameObjects.Components.Access; using Content.Server.GameObjects.Components.Markers; using Content.Server.GameObjects.Components.Mobs; using Content.Server.GameObjects.Components.Observer; +using Content.Server.GameObjects.Components.PDA; using Content.Server.GameObjects.EntitySystems; using Content.Server.GameTicking.GamePresets; using Content.Server.Interfaces; @@ -17,6 +18,7 @@ using Content.Server.Mobs.Roles; using Content.Server.Players; using Content.Shared; using Content.Shared.Chat; +using Content.Shared.GameObjects.Components.PDA; using Content.Shared.Jobs; using Content.Shared.Preferences; using Robust.Server.Interfaces; @@ -627,20 +629,38 @@ namespace Content.Server.GameTicking { var inventory = mob.GetComponent(); - if (!inventory.TryGetSlotItem(Slots.IDCARD, out ItemComponent cardItem)) + if (!inventory.TryGetSlotItem(Slots.IDCARD, out ItemComponent pdaItem)) { return; } - var card = cardItem.Owner; + var pda = pdaItem.Owner; - var cardComponent = card.GetComponent(); - cardComponent.FullName = characterName; - cardComponent.JobTitle = jobPrototype.Name; + var pdaComponent = pda.GetComponent(); + if (pdaComponent.IdSlotEmpty) + { + return; + } + + var card = pdaComponent.ContainedID; + card.FullName = characterName; + card.JobTitle = jobPrototype.Name; + + var access = card.Owner.GetComponent(); + var accessTags = access.GetTags(); + accessTags.AddRange(jobPrototype.Access); + access.SetTags(accessTags); + pdaComponent.SetPDAOwner(mob); + var mindComponent = mob.GetComponent(); + if (mindComponent.HasMind)//Redundancy checks. + { + if (mindComponent.Mind.AllRoles.Any(role => role.Antag)) //Give antags a new uplinkaccount. + { + var uplinkAccount = new UplinkAccount(mob.Uid, 20); //TODO: make me into a variable based on server pop or something. + pdaComponent.InitUplinkAccount(uplinkAccount); + } + } - var access = card.GetComponent(); - access.Tags.Clear(); - access.Tags.AddRange(jobPrototype.Access); } private void AddManifestEntry(string characterName, string jobId) diff --git a/Content.Server/Interfaces/IAccess.cs b/Content.Server/Interfaces/IAccess.cs new file mode 100644 index 0000000000..1729f99d3f --- /dev/null +++ b/Content.Server/Interfaces/IAccess.cs @@ -0,0 +1,11 @@ +using System.Collections.Generic; + +namespace Content.Server.Interfaces +{ + public interface IAccess + { + public List GetTags(); + + public void SetTags(List newTags); + } +} diff --git a/Content.Server/Interfaces/PDA/IPDAUplinkManager.cs b/Content.Server/Interfaces/PDA/IPDAUplinkManager.cs new file mode 100644 index 0000000000..34bc3d3c71 --- /dev/null +++ b/Content.Server/Interfaces/PDA/IPDAUplinkManager.cs @@ -0,0 +1,19 @@ +using System; +using System.Collections.Generic; +using Content.Shared.GameObjects.Components.PDA; +using Content.Shared.Prototypes.PDA; + +namespace Content.Server.Interfaces.PDA +{ + public interface IPDAUplinkManager + { + public IReadOnlyList FetchListings => null; + void Initialize(); + public bool AddNewAccount(UplinkAccount acc); + + public bool ChangeBalance(UplinkAccount acc, int amt); + + public bool TryPurchaseItem(UplinkAccount acc, UplinkListingData listing); + + } +} diff --git a/Content.Server/PDA/PDAUplinkManager.cs b/Content.Server/PDA/PDAUplinkManager.cs new file mode 100644 index 0000000000..52c503ebea --- /dev/null +++ b/Content.Server/PDA/PDAUplinkManager.cs @@ -0,0 +1,107 @@ +using System; +using System.Collections.Generic; +using System.Diagnostics; +using System.Linq; +using Content.Server.GameObjects; +using Content.Server.GameObjects.Components.Mobs; +using Content.Server.Interfaces.PDA; +using Content.Shared.GameObjects.Components.PDA; +using Content.Shared.Prototypes.PDA; +using Robust.Shared.Interfaces.GameObjects; +using Robust.Shared.IoC; +using Robust.Shared.Prototypes; + +namespace Content.Server.PDA +{ + public class PDAUplinkManager : IPDAUplinkManager + { +#pragma warning disable 649 + [Dependency] private readonly IPrototypeManager _prototypeManager; + [Dependency] private readonly IEntityManager _entityManager; +#pragma warning restore 649 + + private List _accounts; + private List _listings; + + public IReadOnlyList FetchListings => _listings; + + public void Initialize() + { + _listings = new List(); + foreach (var item in _prototypeManager.EnumeratePrototypes()) + { + var newListing = new UplinkListingData(item.ListingName, item.ItemId, item.Price, item.Category, + item.Description, item.DisplayColor); + + RegisterUplinkListing(newListing); + } + + _accounts = new List(); + } + + private void RegisterUplinkListing(UplinkListingData listing) + { + if (!ContainsListing(listing)) + { + _listings.Add(listing); + } + + } + + private bool ContainsListing(UplinkListingData listing) + { + return _listings.Any(otherListing => listing.Equals(otherListing)); + } + + public bool AddNewAccount(UplinkAccount acc) + { + var entity = _entityManager.GetEntity(acc.AccountHolder); + if (entity.TryGetComponent(out MindComponent mindComponent)) + { + if (mindComponent.Mind.AllRoles.Any(role => !role.Antag)) + { + return false; + } + } + if (_accounts.Contains(acc)) + { + return false; + } + + _accounts.Add(acc); + return true; + } + + public bool ChangeBalance(UplinkAccount acc, int amt) + { + var account = _accounts.Find(uplinkAccount => uplinkAccount.AccountHolder == acc.AccountHolder); + if (account != null && account.Balance + amt < 0) + { + return false; + } + account.ModifyAccountBalance(account.Balance + amt); + return true; + } + + public bool TryPurchaseItem(UplinkAccount acc, UplinkListingData listing) + { + if (acc == null || listing == null) + { + return false; + } + if (!ContainsListing(listing) || acc.Balance < listing.Price) + { + return false; + } + + var player = _entityManager.GetEntity(acc.AccountHolder); + var hands = player.GetComponent(); + hands.PutInHandOrDrop(_entityManager.SpawnEntity(listing.ItemId, + player.Transform.GridPosition).GetComponent()); + return ChangeBalance(acc, -listing.Price); + + } + + + } +} diff --git a/Content.Server/ServerContentIoC.cs b/Content.Server/ServerContentIoC.cs index 7ca422e4c4..54b61d71c7 100644 --- a/Content.Server/ServerContentIoC.cs +++ b/Content.Server/ServerContentIoC.cs @@ -4,6 +4,8 @@ using Content.Server.GameTicking; using Content.Server.Interfaces; using Content.Server.Interfaces.Chat; using Content.Server.Interfaces.GameTicking; +using Content.Server.Interfaces.PDA; +using Content.Server.PDA; using Content.Server.Preferences; using Content.Server.Sandbox; using Content.Server.Utility; @@ -30,6 +32,7 @@ namespace Content.Server IoCManager.Register(); IoCManager.Register(); IoCManager.Register(); + IoCManager.Register(); } } } diff --git a/Content.Shared/GameObjects/Components/PDA/SharedPDAComponent.cs b/Content.Shared/GameObjects/Components/PDA/SharedPDAComponent.cs new file mode 100644 index 0000000000..16515d3f9d --- /dev/null +++ b/Content.Shared/GameObjects/Components/PDA/SharedPDAComponent.cs @@ -0,0 +1,184 @@ +using System; +using System.Collections.Generic; +using JetBrains.Annotations; +using Robust.Shared.GameObjects; +using Robust.Shared.GameObjects.Components.UserInterface; +using Robust.Shared.Maths; +using Robust.Shared.Serialization; + +namespace Content.Shared.GameObjects.Components.PDA +{ + public class SharedPDAComponent : Component + { + public override string Name => "PDA"; + public override uint? NetID => ContentNetIDs.PDA; + + } + + [Serializable, NetSerializable] + public sealed class PDAToggleFlashlightMessage : BoundUserInterfaceMessage + { + public PDAToggleFlashlightMessage() + { + + } + } + + [Serializable, NetSerializable] + public sealed class PDAEjectIDMessage : BoundUserInterfaceMessage + { + public PDAEjectIDMessage() + { + + } + } + + + [Serializable, NetSerializable] + public class PDAUBoundUserInterfaceState : BoundUserInterfaceState + { + + } + + [Serializable, NetSerializable] + public sealed class PDAUpdateState : PDAUBoundUserInterfaceState + { + public bool FlashlightEnabled; + public PDAIdInfoText PDAOwnerInfo; + public UplinkAccountData Account; + public UplinkListingData[] Listings; + + public PDAUpdateState(bool isFlashlightOn, PDAIdInfoText ownerInfo) + { + FlashlightEnabled = isFlashlightOn; + PDAOwnerInfo = ownerInfo; + } + + public PDAUpdateState(bool isFlashlightOn, PDAIdInfoText ownerInfo, UplinkAccountData accountData) + { + FlashlightEnabled = isFlashlightOn; + PDAOwnerInfo = ownerInfo; + Account = accountData; + } + + public PDAUpdateState(bool isFlashlightOn, PDAIdInfoText ownerInfo, UplinkAccountData accountData, UplinkListingData[] listings) + { + FlashlightEnabled = isFlashlightOn; + PDAOwnerInfo = ownerInfo; + Account = accountData; + Listings = listings; + } + } + + [Serializable, NetSerializable] + public sealed class PDAUplinkBuyListingMessage : BoundUserInterfaceMessage + { + public UplinkListingData ListingToBuy; + public PDAUplinkBuyListingMessage(UplinkListingData itemToBuy) + { + ListingToBuy = itemToBuy; + } + } + + [Serializable, NetSerializable] + public sealed class PDARequestUpdateInterfaceMessage : BoundUserInterfaceMessage + { + public PDARequestUpdateInterfaceMessage() + { + + } + } + + + [NetSerializable, Serializable] + public struct PDAIdInfoText + { + public string ActualOwnerName; + public string IdOwner; + public string JobTitle; + } + + [NetSerializable, Serializable] + public enum PDAVisuals + { + ScreenLit, + } + + [NetSerializable, Serializable] + public enum PDAUiKey + { + Key + } + + public class UplinkAccount + { + public event Action BalanceChanged; + public EntityUid AccountHolder; + public int Balance { get; private set; } + + 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; + + } + } + + [NetSerializable, Serializable] + public class UplinkAccountData + { + public EntityUid DataAccountHolder; + public int DataBalance; + + public UplinkAccountData(EntityUid dataAccountHolder, int dataBalance) + { + DataAccountHolder = dataAccountHolder; + DataBalance = dataBalance; + } + } + + [NetSerializable, Serializable] + public class UplinkListingData : ComponentState, IEquatable + { + public string ItemId; + public int Price; + public UplinkCategory Category; + public string Description; + public string ListingName; + public Color DisplayColor; + + public UplinkListingData(string listingName,string itemId, + int price, UplinkCategory category, + string description, Color displayColor) : base(ContentNetIDs.PDA) + { + ListingName = listingName; + Price = price; + Category = category; + Description = description; + ItemId = itemId; + DisplayColor = displayColor; + } + + public bool Equals(UplinkListingData other) + { + if (other == null) + { + return false; + } + + return ItemId == other.ItemId; + } + } + +} diff --git a/Content.Shared/GameObjects/Components/PDA/UplinkCategory.cs b/Content.Shared/GameObjects/Components/PDA/UplinkCategory.cs new file mode 100644 index 0000000000..9dca94d517 --- /dev/null +++ b/Content.Shared/GameObjects/Components/PDA/UplinkCategory.cs @@ -0,0 +1,8 @@ +namespace Content.Shared.GameObjects.Components.PDA +{ + public enum UplinkCategory + { + Weapon, + Utility, + } +} diff --git a/Content.Shared/GameObjects/ContentNetIDs.cs b/Content.Shared/GameObjects/ContentNetIDs.cs index d8a53eb727..9e5b7e71a5 100644 --- a/Content.Shared/GameObjects/ContentNetIDs.cs +++ b/Content.Shared/GameObjects/ContentNetIDs.cs @@ -46,5 +46,6 @@ public const uint GRAVITY_GENERATOR = 1041; public const uint SURGERY = 1042; public const uint MULTITOOLS = 1043; + public const uint PDA = 1044; } } diff --git a/Content.Shared/Prototypes/PDA/UplinkStoreListingPrototype.cs b/Content.Shared/Prototypes/PDA/UplinkStoreListingPrototype.cs new file mode 100644 index 0000000000..50f7097127 --- /dev/null +++ b/Content.Shared/Prototypes/PDA/UplinkStoreListingPrototype.cs @@ -0,0 +1,42 @@ +using Content.Shared.GameObjects.Components.PDA; +using Robust.Shared.Maths; +using Robust.Shared.Prototypes; +using Robust.Shared.Serialization; +using YamlDotNet.RepresentationModel; + +namespace Content.Shared.Prototypes.PDA +{ + [Prototype("uplinkListing")] + public class UplinkStoreListingPrototype : IPrototype, IIndexedPrototype + { + + private string _id; + private string _itemId; + private int _price; + private UplinkCategory _category; + private string _desc; + private string _name; + private Color _displayColor; + + public string ID => _id; + + public string ItemId => _itemId; + public int Price => _price; + public UplinkCategory Category => _category; + public string Description => _desc; + public string ListingName => _name; + public Color DisplayColor => _displayColor; + public void LoadFrom(YamlMappingNode mapping) + { + var serializer = YamlObjectSerializer.NewReader(mapping); + serializer.DataField(ref _id, "id", string.Empty); + serializer.DataField(ref _itemId, "itemId", string.Empty); + serializer.DataField(ref _price, "price", 5); + serializer.DataField(ref _category, "category", UplinkCategory.Utility); + serializer.DataField(ref _desc, "description", string.Empty); + serializer.DataField(ref _name, "listingName", string.Empty); + serializer.DataField(ref _displayColor, "displayColor", Color.White); + + } + } +} diff --git a/Resources/Prototypes/Entities/Items/pda.yml b/Resources/Prototypes/Entities/Items/pda.yml new file mode 100644 index 0000000000..95a399130f --- /dev/null +++ b/Resources/Prototypes/Entities/Items/pda.yml @@ -0,0 +1,353 @@ +- type: entity + name: PDA + parent: BaseItem + id: BasePDA + abstract: true + description: Personal Data Assistant + components: + - type: Appearance + visuals: + - type: PDAVisualizer + - type: Clothing + QuickEquip: false + Slots: + - idcard + - type: PointLight + enabled: false + radius: 3 + - type: UserInterface + interfaces: + - key: enum.PDAUiKey.Key + type: PDABoundUserInterface + - type: Sound + + +- type: entity + name: Assistant PDA + parent: BasePDA + id: AssistantPDA + description: Why isn't it gray? + components: + - type: PDA + idCard: AssistantIDCard + - type: Icon + sprite: Objects/Devices/pda.rsi + state: pda + - type: Sprite + sprite: Objects/Devices/pda.rsi + netsync: false + layers: + - state: pda + map: ["enum.PDAVisualLayers.Base"] + - state: unlit_pda_screen + shader: unshaded + map: ["enum.PDAVisualLayers.Unlit"] + +- type: entity + name: Chef PDA + parent: BasePDA + id: ChefPDA + description: Why isn't it gray? + components: + - type: PDA + idCard: ChefIDCard + - type: Icon + sprite: Objects/Devices/pda.rsi + state: pda-chef + - type: Sprite + sprite: Objects/Devices/pda.rsi + netsync: false + layers: + - state: pda-chef + map: ["enum.PDAVisualLayers.Base"] + - state: unlit_pda_screen + shader: unshaded + map: ["enum.PDAVisualLayers.Unlit"] + +- type: entity + name: Clown PDA + parent: BasePDA + id: ClownPDA + description: Looks can be deceiving. + components: + - type: PDA + idCard: ClownIDCard + - type: Icon + sprite: Objects/Devices/pda.rsi + state: pda-clown + - type: Sprite + sprite: Objects/Devices/pda.rsi + netsync: false + layers: + - state: pda-clown + map: ["enum.PDAVisualLayers.Base"] + - state: unlit_pda_screen + shader: unshaded + map: ["enum.PDAVisualLayers.Unlit"] + +- type: entity + name: Cargo PDA + parent: BasePDA + id: CargoPDA + description: PDA for the guys that order the pizzas. + components: + - type: PDA + idCard: CargoIDCard + - type: Icon + sprite: Objects/Devices/pda.rsi + state: pda-cargo + - type: Sprite + sprite: Objects/Devices/pda.rsi + netsync: false + layers: + - state: pda-cargo + map: ["enum.PDAVisualLayers.Base"] + - state: unlit_pda_screen + shader: unshaded + map: ["enum.PDAVisualLayers.Unlit"] + +- type: entity + name: Bartender PDA + parent: BasePDA + id: BartenderPDA + description: Smells like beer. + components: + - type: PDA + idCard: BartenderIDCard + - type: Icon + sprite: Objects/Devices/pda.rsi + state: pda-bar + - type: Sprite + sprite: Objects/Devices/pda.rsi + netsync: false + layers: + - state: pda-bar + map: ["enum.PDAVisualLayers.Base"] + - state: unlit_pda_screen + shader: unshaded + map: ["enum.PDAVisualLayers.Unlit"] + + +- type: entity + name: Janitor PDA + parent: BasePDA + id: JanitorPDA + description: Smells like bleach. + components: + - type: PDA + idCard: JanitorIDCard + - type: Icon + sprite: Objects/Devices/pda.rsi + state: pda-j + - type: Sprite + sprite: Objects/Devices/pda.rsi + netsync: false + layers: + - state: pda-j + map: ["enum.PDAVisualLayers.Base"] + - state: unlit_pda_screen + shader: unshaded + map: ["enum.PDAVisualLayers.Unlit"] + +- type: entity + name: Captain PDA + parent: BasePDA + id: CaptainPDA + description: Surprisingly no different than your PDA. + components: + - type: PDA + idCard: CaptainIDCard + - type: Icon + sprite: Objects/Devices/pda.rsi + state: pda-c + - type: Sprite + sprite: Objects/Devices/pda.rsi + netsync: false + layers: + - state: pda-c + map: ["enum.PDAVisualLayers.Base"] + - state: unlit_pda_screen + shader: unshaded + map: ["enum.PDAVisualLayers.Unlit"] + +- type: entity + name: HoP PDA + parent: BasePDA + id: HoPPDA + components: + - type: PDA + idCard: HoPIDCard + - type: Icon + sprite: Objects/Devices/pda.rsi + state: pda-hop + - type: Sprite + sprite: Objects/Devices/pda.rsi + netsync: false + layers: + - state: pda-hop + map: ["enum.PDAVisualLayers.Base"] + - state: unlit_pda_screen + shader: unshaded + map: ["enum.PDAVisualLayers.Unlit"] + +- type: entity + name: CE PDA + parent: BasePDA + id: CEPDA + components: + - type: PDA + idCard: CEIDCard + - type: Icon + sprite: Objects/Devices/pda.rsi + state: pda-ce + - type: Sprite + sprite: Objects/Devices/pda.rsi + netsync: false + layers: + - state: pda-ce + map: ["enum.PDAVisualLayers.Base"] + - state: unlit_pda_screen + shader: unshaded + map: ["enum.PDAVisualLayers.Unlit"] + + +- type: entity + name: Engineer PDA + parent: BasePDA + id: EngineerPDA + components: + - type: PDA + idCard: EngineeringIDCard + - type: Icon + sprite: Objects/Devices/pda.rsi + state: pda-e + - type: Sprite + sprite: Objects/Devices/pda.rsi + netsync: false + layers: + - state: pda-e + map: ["enum.PDAVisualLayers.Base"] + - state: unlit_pda_screen + shader: unshaded + map: ["enum.PDAVisualLayers.Unlit"] + +- type: entity + name: CMO PDA + parent: BasePDA + id: CMOPDA + components: + - type: PDA + idCard: CMOIDCard + - type: Icon + sprite: Objects/Devices/pda.rsi + state: pda-cmo + - type: Sprite + sprite: Objects/Devices/pda.rsi + netsync: false + layers: + - state: pda-cmo + map: ["enum.PDAVisualLayers.Base"] + - state: unlit_pda_screen + shader: unshaded + map: ["enum.PDAVisualLayers.Unlit"] + + +- type: entity + name: Medical PDA + parent: BasePDA + id: MedicalPDA + components: + - type: PDA + idCard: MedicalIDCard + - type: Icon + sprite: Objects/Devices/pda.rsi + state: pda-m + - type: Sprite + sprite: Objects/Devices/pda.rsi + netsync: false + layers: + - state: pda-m + map: ["enum.PDAVisualLayers.Base"] + - state: unlit_pda_screen + shader: unshaded + map: ["enum.PDAVisualLayers.Unlit"] + +- type: entity + name: RnD PDA + parent: BasePDA + id: RnDPDA + components: + - type: PDA + idCard: RDIDCard + - type: Icon + sprite: Objects/Devices/pda.rsi + state: pda-rd + - type: Sprite + sprite: Objects/Devices/pda.rsi + netsync: false + layers: + - state: pda-rd + map: ["enum.PDAVisualLayers.Base"] + - state: unlit_pda_screen + shader: unshaded + map: ["enum.PDAVisualLayers.Unlit"] + +- type: entity + name: Science PDA + parent: BasePDA + id: SciencePDA + components: + - type: PDA + idCard: ResearchIDCard + - type: Icon + sprite: Objects/Devices/pda.rsi + state: pda-rd + - type: Sprite + sprite: Objects/Devices/pda.rsi + netsync: false + layers: + - state: pda-rd + map: ["enum.PDAVisualLayers.Base"] + - state: unlit_pda_screen + shader: unshaded + map: ["enum.PDAVisualLayers.Unlit"] + +- type: entity + name: HoS PDA + parent: BasePDA + id: HoSPDA + components: + - type: PDA + idCard: HoSIDCard + - type: Icon + sprite: Objects/Devices/pda.rsi + state: pda-hos + - type: Sprite + sprite: Objects/Devices/pda.rsi + netsync: false + layers: + - state: pda-hos + map: ["enum.PDAVisualLayers.Base"] + - state: unlit_pda_screen + shader: unshaded + map: ["enum.PDAVisualLayers.Unlit"] + +- type: entity + name: Security PDA + parent: BasePDA + id: SecurityPDA + components: + - type: PDA + idCard: SecurityIDCard + - type: Icon + sprite: Objects/Devices/pda.rsi + state: pda-s + - type: Sprite + sprite: Objects/Devices/pda.rsi + netsync: false + layers: + - state: pda-s + map: ["enum.PDAVisualLayers.Base"] + - state: unlit_pda_screen + shader: unshaded + map: ["enum.PDAVisualLayers.Unlit"] diff --git a/Resources/Prototypes/Jobs/Cargo/CargoTechnician.yml b/Resources/Prototypes/Jobs/Cargo/CargoTechnician.yml index c26ab2d0f5..c74fb14d65 100644 --- a/Resources/Prototypes/Jobs/Cargo/CargoTechnician.yml +++ b/Resources/Prototypes/Jobs/Cargo/CargoTechnician.yml @@ -17,4 +17,4 @@ innerclothing: UniformCargoTech backpack: BackpackClothing shoes: ShoesBlack - idcard: CargoIDCard + idcard: CargoPDA diff --git a/Resources/Prototypes/Jobs/Civilian/Assistant.yml b/Resources/Prototypes/Jobs/Civilian/Assistant.yml index 9e64c1a098..c3b355fa28 100644 --- a/Resources/Prototypes/Jobs/Civilian/Assistant.yml +++ b/Resources/Prototypes/Jobs/Civilian/Assistant.yml @@ -16,5 +16,5 @@ innerclothing: UniformColorGrey backpack: BackpackClothing shoes: ShoesBlack - idcard: AssistantIDCard + idcard: AssistantPDA diff --git a/Resources/Prototypes/Jobs/Civilian/Bartender.yml b/Resources/Prototypes/Jobs/Civilian/Bartender.yml index f71f705a3c..05d3ca32e8 100644 --- a/Resources/Prototypes/Jobs/Civilian/Bartender.yml +++ b/Resources/Prototypes/Jobs/Civilian/Bartender.yml @@ -16,4 +16,4 @@ outerclothing: OuterclothingArmorVest backpack: BackpackClothing shoes: ShoesBlack - idcard: BartenderIDCard + idcard: BartenderPDA diff --git a/Resources/Prototypes/Jobs/Civilian/Chef.yml b/Resources/Prototypes/Jobs/Civilian/Chef.yml index 81bbab1123..649f66e0e1 100644 --- a/Resources/Prototypes/Jobs/Civilian/Chef.yml +++ b/Resources/Prototypes/Jobs/Civilian/Chef.yml @@ -16,4 +16,4 @@ innerclothing: UniformChef backpack: BackpackClothing shoes: ShoesBlack - idcard: ChefIDCard + idcard: ChefPDA diff --git a/Resources/Prototypes/Jobs/Civilian/Clown.yml b/Resources/Prototypes/Jobs/Civilian/Clown.yml index 506a728cda..79de53d5ad 100644 --- a/Resources/Prototypes/Jobs/Civilian/Clown.yml +++ b/Resources/Prototypes/Jobs/Civilian/Clown.yml @@ -18,4 +18,4 @@ shoes: ShoesClown mask: MaskClown pocket1: BikeHorn - idcard: ClownIDCard + idcard: ClownPDA diff --git a/Resources/Prototypes/Jobs/Civilian/Janitor.yml b/Resources/Prototypes/Jobs/Civilian/Janitor.yml index 2cc0156944..a6842cc5d6 100644 --- a/Resources/Prototypes/Jobs/Civilian/Janitor.yml +++ b/Resources/Prototypes/Jobs/Civilian/Janitor.yml @@ -17,4 +17,4 @@ backpack: BackpackClothing shoes: ShoesGaloshes head: HatPurplesoft - idcard: JanitorIDCard + idcard: JanitorPDA diff --git a/Resources/Prototypes/Jobs/Command/Captain.yml b/Resources/Prototypes/Jobs/Command/Captain.yml index e100b0d27c..6127f0879c 100644 --- a/Resources/Prototypes/Jobs/Command/Captain.yml +++ b/Resources/Prototypes/Jobs/Command/Captain.yml @@ -32,4 +32,4 @@ eyes: SunGlasses gloves: GlovesCaptain outerclothing: OuterclothingCaparmor - idcard: CaptainIDCard + idcard: CaptainPDA diff --git a/Resources/Prototypes/Jobs/Command/HeadOfPersonnel.yml b/Resources/Prototypes/Jobs/Command/HeadOfPersonnel.yml index 9eb839edf5..15b4379af7 100644 --- a/Resources/Prototypes/Jobs/Command/HeadOfPersonnel.yml +++ b/Resources/Prototypes/Jobs/Command/HeadOfPersonnel.yml @@ -24,4 +24,4 @@ backpack: BackpackClothing shoes: ShoesBrown head: HatHopcap - idcard: HoPIDCard + idcard: HoPPDA diff --git a/Resources/Prototypes/Jobs/Engineering/ChiefEngineer.yml b/Resources/Prototypes/Jobs/Engineering/ChiefEngineer.yml index 4545866751..b9df28c533 100644 --- a/Resources/Prototypes/Jobs/Engineering/ChiefEngineer.yml +++ b/Resources/Prototypes/Jobs/Engineering/ChiefEngineer.yml @@ -21,4 +21,4 @@ innerclothing: UniformChiefEngineer backpack: BackpackEngineering shoes: ShoesBrown - idcard: CEIDCard + idcard: CEPDA diff --git a/Resources/Prototypes/Jobs/Engineering/StationEngineer.yml b/Resources/Prototypes/Jobs/Engineering/StationEngineer.yml index 1d217dc8d1..f3bcae49a3 100644 --- a/Resources/Prototypes/Jobs/Engineering/StationEngineer.yml +++ b/Resources/Prototypes/Jobs/Engineering/StationEngineer.yml @@ -19,4 +19,4 @@ backpack: BackpackEngineering shoes: ShoesWorkboots outerclothing: OuterclothingHazard - idcard: EngineeringIDCard + idcard: EngineerPDA diff --git a/Resources/Prototypes/Jobs/Medical/ChiefMedicalOfficer.yml b/Resources/Prototypes/Jobs/Medical/ChiefMedicalOfficer.yml index f1bbdfc3c4..7d80df9ead 100644 --- a/Resources/Prototypes/Jobs/Medical/ChiefMedicalOfficer.yml +++ b/Resources/Prototypes/Jobs/Medical/ChiefMedicalOfficer.yml @@ -22,4 +22,4 @@ backpack: BackpackMedical shoes: ShoesBrown outerclothing: OuterclothingLabcoatcmo - idcard: CMOIDCard + idcard: CMOPDA diff --git a/Resources/Prototypes/Jobs/Medical/MedicalDoctor.yml b/Resources/Prototypes/Jobs/Medical/MedicalDoctor.yml index 411b2cc1e3..b2747a76e3 100644 --- a/Resources/Prototypes/Jobs/Medical/MedicalDoctor.yml +++ b/Resources/Prototypes/Jobs/Medical/MedicalDoctor.yml @@ -17,4 +17,4 @@ backpack: BackpackMedical shoes: ShoesWhite outerclothing: OuterclothingLabcoatmedspecopen - idcard: MedicalIDCard + idcard: MedicalPDA diff --git a/Resources/Prototypes/Jobs/Science/ResearchDirector.yml b/Resources/Prototypes/Jobs/Science/ResearchDirector.yml index 886733d28e..a54a646b46 100644 --- a/Resources/Prototypes/Jobs/Science/ResearchDirector.yml +++ b/Resources/Prototypes/Jobs/Science/ResearchDirector.yml @@ -20,4 +20,4 @@ backpack: BackpackClothing shoes: ShoesBrown outerclothing: OuterclothingLabcoatgenopen - idcard: RDIDCard + idcard: RnDPDA diff --git a/Resources/Prototypes/Jobs/Science/Scientist.yml b/Resources/Prototypes/Jobs/Science/Scientist.yml index 686aeb9acf..0c97f5e039 100644 --- a/Resources/Prototypes/Jobs/Science/Scientist.yml +++ b/Resources/Prototypes/Jobs/Science/Scientist.yml @@ -17,4 +17,4 @@ backpack: BackpackClothing shoes: ShoesWhite outerclothing: OuterclothingLabcoattoxopen - idcard: ResearchIDCard + idcard: SciencePDA diff --git a/Resources/Prototypes/Jobs/Security/HeadOfSecurity.yml b/Resources/Prototypes/Jobs/Security/HeadOfSecurity.yml index 8d88c1bd0b..96460d5899 100644 --- a/Resources/Prototypes/Jobs/Security/HeadOfSecurity.yml +++ b/Resources/Prototypes/Jobs/Security/HeadOfSecurity.yml @@ -23,4 +23,4 @@ outerclothing: OuterclothingHoSTrenchcoat eyes: SecGlasses head: HatBeretHoS - idcard: HoSIDCard + idcard: HoSPDA diff --git a/Resources/Prototypes/Jobs/Security/SecurityOfficer.yml b/Resources/Prototypes/Jobs/Security/SecurityOfficer.yml index a9c5fd43e4..20b1ca1d9b 100644 --- a/Resources/Prototypes/Jobs/Security/SecurityOfficer.yml +++ b/Resources/Prototypes/Jobs/Security/SecurityOfficer.yml @@ -20,4 +20,4 @@ shoes: ShoesJackboots eyes: SecGlasses outerclothing: OuterclothingArmorVestAlt - idcard: SecurityIDCard + idcard: SecurityPDA diff --git a/Resources/Prototypes/PDA/uplink_catalog.yml b/Resources/Prototypes/PDA/uplink_catalog.yml new file mode 100644 index 0000000000..11cced4cef --- /dev/null +++ b/Resources/Prototypes/PDA/uplink_catalog.yml @@ -0,0 +1,29 @@ + +- type: uplinkListing + id: UplinkPen + category: Utility + itemId: Pen + price: 2 + displayColor: Blue + +- type: uplinkListing + id: UplinkPistolClarissa + category: Weapon + itemId: PistolClarissa + price: 15 + displayColor: Yellow + +# - type: uplinkListing +# id: UplinkPistolDeagle +# category: Weapon +# itemId: PistolDeagle +# price: 30 +# displayColor: Red + +# - type: uplinkListing +# id: UplinkMagazineFedShotgun +# category: Weapon +# itemId: MagazineFedShotgun +# price: 50 +# description: For when you want ZERO evidence left behind. +# displayColor: Red diff --git a/Resources/Textures/Objects/Devices/pda.rsi/aicard-404.png b/Resources/Textures/Objects/Devices/pda.rsi/aicard-404.png new file mode 100644 index 0000000000000000000000000000000000000000..645d236997cf9e39863f496947ac73db7161499d GIT binary patch literal 478 zcmV<40U`d0P)x1iyhbv|CGDjUPfMOeCO-F($gOIG7kF76%s%gKmBXLs$$U!L1$2 zM<8xG$a3d^J=#M1u7OVWzr4F^@7}xLy>~5;>%U7`*FptN<8jY^rqftI8|!jpcX|K- z&vnGu`o7x^?Ufc*9{W@gsnH4!g{WQ^XpS6-=Cy&fJj0g`FPkT7mDiSvW54-0G{jM zt9ucfh~yD?t^)=Vs3rWraq6~p~sWAq?QovZa4NF;Q2j@|eCNMi^ z9yo6<#t?W8AVh$YG=bnw;|Pd8G9cjRKr(^9ehLDa-2=K|VziC`mQ?{`vmHmRP}T(0 zDgbNIM(1TlfK(O)%C)w90FWm@mf?8V$Ijk9c(Ihq%6`Jh)L!L}h`NSz<;n#BzW`*> U7zPt1od5s;07*qoM6N<$f}!Hk;{X5v literal 0 HcmV?d00001 diff --git a/Resources/Textures/Objects/Devices/pda.rsi/aicard-full.png b/Resources/Textures/Objects/Devices/pda.rsi/aicard-full.png new file mode 100644 index 0000000000000000000000000000000000000000..4786cc0faaf2b7d55adb0bf65dad5c30281ac686 GIT binary patch literal 702 zcmV;v0zv(WP)_8Cal~4oS^J5{87dml5JA zgif`?M0ThRK`*g|+o4Mk8kUn{B}i`veV%x=?S04AseR$)`R(^UzvuVw`+N363I98k zVjWa&v+3F1{oLQr>Zhz&j@oBe0Z1m|Quq1kD78Zm;KhACTM&5#P;Rs7?X#-}Cjvs} zXl{{mWTnaUOw#~zmDUVb7q6jL*mLeVW#;_cm3y?$u5#A%1d+X?xdlM39`CSRlZiOK zJ0mFHcTAmw2?<5XQ)>~^gO20o?J3^IVk8rBz6Eb(C8B8yl8HFV(ScTQS^@2`pP&}7 zwBIxUM{^6QwFsL#Klt$GwbT#X7?ASv^JOX5b@c&Nd#C&@vd`rlEVMw3np<c#i8U&;QX2J2P13Kqjpl zp83hcshFRflDfUG`iTk@9DvBAEVFCK);Hs4JM|9VjNhOy%j_EL%wU-V2WmA3Y2&SY z`TD4V4*;mu(yk~0h$#@g6$po->}`Ldvi1TlxAU)d>lOmA%z2yO{SB{Ih?<#*QA=CwdFNh*E128asN>E9`l#R)aSE kC@tiR$SnI3N+|fQ%=~r>#O&<7mYHp><_r3oD^yTbq?3d3GT_7!4Y{*JnVP^$TagzA?7pR zU){3e0fGW6O;u69`+KTd6_=~@Hhw%U-89YEK)|DAgTnsOPYjOD7aWruRS#c$d|Waw zZttNFm2q^nw5vABjK4)f(qB>&(1cp zrcC0x-pwx{%XHsv!Zfi?UdATAfa}*1cL2?1p3ab&I&IfBzQZ$<)Y;hBxVV*yoEgHz z9&DbY!5$#OFQZAwu%5Rb_+Y**lF7?fW@A vO*V#F9PC)S#MNbmgdFSQ1Q7!uU|`6}-?W{bCH6Tmv>7~I{an^LB{Ts5{=cC& literal 0 HcmV?d00001 diff --git a/Resources/Textures/Objects/Devices/pda.rsi/cart-a.png b/Resources/Textures/Objects/Devices/pda.rsi/cart-a.png new file mode 100644 index 0000000000000000000000000000000000000000..c3c65c95e8128d2473d0fd9527aab73fc078764d GIT binary patch literal 248 zcmVU^%M!*>J#jA2Z`7_Ygn33MG}0)vPzQ|W`tsExUBrIb?tT}iSz=-lMT)|ZPnQ9Xc)W#Xz6aZ!E3)!%Z9~u%nBe665(EJGWrvd!XV56AQYmMM#jg4ab z&|EG+;cm5ZK6ID(8vuA1J+X}9?elMlZ{Q=D0`NI*F(1_S=3Izx!0V-ak@5&|3(&_4 w050?wRG*s%M^|SzjZpF07*qoM6N<$fxLkKpVDynwSu=waN%MGw%iw8H~IicSs@674;e7zcy#L>%oRX1$OZd!@21ptyb;u0Nj zF3d$BiRZvovz%T4pe&{w%Vm)HG{=wBy#eTJe<;c&&beR|PePpvxaa+UlXWH_B41^l z2vl{0Pjf^h7(UIZ>ZX-|`Vyx8#CWm^G7-3xvsMD?BX~4?_1y;54s3TD5^bc+e#%~7C4Zmi<^04^3qX$0>1r z0H+HiNsKjp3O2`R^kD%2VzdE2G$N->e#(%V8p_7jcAY1?E<&->(BRJA>e+UD2`MSA3w?ckCF}nF zaoTYMV*| r1t*9wsr$<mqPJ;LDW>gTe~DWM4fx5`;G literal 0 HcmV?d00001 diff --git a/Resources/Textures/Objects/Devices/pda.rsi/cart-clown.png b/Resources/Textures/Objects/Devices/pda.rsi/cart-clown.png new file mode 100644 index 0000000000000000000000000000000000000000..45e2da7aff5f787bda38544a3c9b7de637d81746 GIT binary patch literal 268 zcmV+n0rUQeP)69Kc$IZfXZoTIq`88=`n#`r`up0Kg5AwD18et|w|EA(025q9?JqSU>_tfh9hG z<;8}CgyN_mF+pY4hz0Xivoo{v|CwD-6h%??odZd8sgz5;t4GnBXdXaHB3>@nerijk zCbl-PB91>c=8Z{9N7)%LCQT;euFv(`fadk3l{mnm^n&kSP^p~ZI1V@60D!B7uCh@oG6N-{1;0tU^z1iT8V@J O0000#_X}%OLw#dY1(&cmHpnV)JUe;w=N_Ll$3PL+ zpXF7GCpX{RQu}4z^WzKZ7@8+M{QUD#WR$el$4w6Ip;yZv2byr@stR{35d*tM!eo|&GYnnmiz_ErzdT1?`GMfpCQ$e z{C&3cidD0&W>pGXGJJ|x*w^SUxTW!L-FH=9*T5U5Jmq+kqDM04nU9Oj>fm}H8>hK;1-cA*W2d+)~-wyPYSYGp^!vFc9kOY8qAD6 z^BMdBK@bGt-TB~bwzi>r`ThQrRgWdW+J+8?Z&X#an2#}{t~Fc4mb3Y%xl(EtPbr;q zM@~7u0ATvkzVBx-=iJT7{2A6ZWQ-y2J>{HfR}{1>3d%W?_nwR~^yrQ(!Ja_dwoqkx zc~@nLG>+Ud7dG4jA%t1OG>!-%tQNp_0RRlcFv~gT0O0>!08CEky6!3#W8{_su;Ld0 zlkJw)YhX>Ft~GwW{sjQg8t12eN{Ao`!pk@Th00VYrfKXC00000NkvXXu0mjfGtq*f literal 0 HcmV?d00001 diff --git a/Resources/Textures/Objects/Devices/pda.rsi/cart-h.png b/Resources/Textures/Objects/Devices/pda.rsi/cart-h.png new file mode 100644 index 0000000000000000000000000000000000000000..8ec45a49081b0cbedb13eeca22a8add0ce538528 GIT binary patch literal 279 zcmV+y0qFjTP)tmupcyfP$pC@3%i)J4q!H3tWlg?bEn1MQN#Y z0>%_+O=q|BrrRNk!c@&u36x3}fUw^KpfU;|gG65X!1KIBv9Ad@=Mu$|B3ePSK4-T- z0$@i0aQOq)Oeos|i^Z1(0E}JX1^2Vh0Ow#I*W}$vu>yd{iD#HTAe_K(d;qF1vWILY dilQjL;tV6%Hs1<$*R=ou002ovPDHLkV1nR$bngHF literal 0 HcmV?d00001 diff --git a/Resources/Textures/Objects/Devices/pda.rsi/cart-hos.png b/Resources/Textures/Objects/Devices/pda.rsi/cart-hos.png new file mode 100644 index 0000000000000000000000000000000000000000..9daffbecaac4fe309c767fb26c829184f6ca1350 GIT binary patch literal 291 zcmV+;0o?wHP)YU6o)@0+g-x#67DQr+=SAl1;NROaBy?z=HOGf3HkI}czQI}hOjENp_kkl5Iy2^iu9qJ@eeqRxt1 zIImflot^*ry94ExaN|8ncCLu5hMH=eXpm8;0fj9v(^Km+D_VWgCdIM(Wf6qXc<@n1gP(2l5fZX~QynO}lB1#|(7ay{r cD2nn!jz!xvTifddIsgCw07*qoM6N<$g40`VTL1t6 literal 0 HcmV?d00001 diff --git a/Resources/Textures/Objects/Devices/pda.rsi/cart-lib.png b/Resources/Textures/Objects/Devices/pda.rsi/cart-lib.png new file mode 100644 index 0000000000000000000000000000000000000000..6ba64526da37935aab9b397bec3a26bcd46d3266 GIT binary patch literal 244 zcmeAS@N?(olHy`uVBq!ia0vp^3LwnE1|*BCs=ffJ-JULvAr*6y6C_v{Cy4Yk1sYsp zRMzbB^}YJ<@nrkjUt*rm3=IqnHcUwRd1`^no~%QX&;F}l6?Cy?V7vGB-q`?!$1O@` z4^P^$DTap!^(vibJnft<*|q+Ou|)Rj14q@2t{J7&TR2W*o^j%mtERsNGO&x*WVDNPHb6Mw<&;$T&Bv|zT literal 0 HcmV?d00001 diff --git a/Resources/Textures/Objects/Devices/pda.rsi/cart-m.png b/Resources/Textures/Objects/Devices/pda.rsi/cart-m.png new file mode 100644 index 0000000000000000000000000000000000000000..1420c062fb425ebd43ac491838a23e21d87f46f7 GIT binary patch literal 276 zcmeAS@N?(olHy`uVBq!ia0vp^3LwnE1|*BCs=ffJ+nz3tAr*6y6C_v{Cy4Yk1sYsp zRMzbB^}YJ<@nrkjUt*rm3=IqnHcUv`xpOD8V(Nd-QkIK+4UOgR?Gi-Ag@hEYYJ8GW zP*FLcps2|Doc+3qfzMe_<f(0HI3oJCaY1phvB;X-1Q0keeO&!Y5| z#Nk%%bO{hhJ6>vhLdwYC&5QTT<};r;vqpl4$LGPD%eB8xZkyBC*kiJx=BHDI)Q$c1 z=FC8FxLf@Ei{}j>H=N~s@{DQH;)YudO9U(`KQZ*qG30VPs3F11%)!ty)8NF}{v}~R PZ!&ng`njxgN@xNA7}94} literal 0 HcmV?d00001 diff --git a/Resources/Textures/Objects/Devices/pda.rsi/cart-mi.png b/Resources/Textures/Objects/Devices/pda.rsi/cart-mi.png new file mode 100644 index 0000000000000000000000000000000000000000..04b1dc1ec7f65832a30b1c9e48f7291fed1ef304 GIT binary patch literal 275 zcmV+u0qp*XP){5w0zV(*LiD&Dq7Q9h9Y?~B;?XXJUl7-wc!Ys4lFlEw4kS(YXGFbucYMUqZ# z0GMuC*L9*1(bLL&4DXBRoQolZIF4g7LI}}07vKGnCHB${Wm&G$zGk57x>ed*M1O#p zK}2YpCeeuq0AP&yt^r``gsQ3@G-ehb4s3V=U~0Ri`4&VKu-4$->n8xfT=gyGR}@A0 Z39c6dPI!yQ1ttIh002ovPDHLkV1iwHb&mi5 literal 0 HcmV?d00001 diff --git a/Resources/Textures/Objects/Devices/pda.rsi/cart-q.png b/Resources/Textures/Objects/Devices/pda.rsi/cart-q.png new file mode 100644 index 0000000000000000000000000000000000000000..2f55aecdd52f2f2d1a9cb13d5a3caa9ee66e3725 GIT binary patch literal 259 zcmeAS@N?(olHy`uVBq!ia0vp^3LwnE1|*BCs=ffJQ=Tr4Ar*6y6C_v{Cy4Yk1sYsp zRMzbB^}YJ<@nrkjUt*rm3=IqnHcUwRxl1K?PgawJ#J|a}I2Oq=Fn^b`Nt*F9LefN7C7UQkRT_ufs&<1VzVkcAL{D8IArZyQk_+?sfxgFGyU}ffF@bff`Tq%&I2J{t!r>mdKI;Vst E0C-AO!2kdN literal 0 HcmV?d00001 diff --git a/Resources/Textures/Objects/Devices/pda.rsi/cart-rd.png b/Resources/Textures/Objects/Devices/pda.rsi/cart-rd.png new file mode 100644 index 0000000000000000000000000000000000000000..15966051e1620f126ce8217d762478f31ad8fb52 GIT binary patch literal 312 zcmV-80muG{P)3-r5JsO8Q(9PwU?IXbf{k1&SX;*4CY@j(#3o>wBG-smrMLA*EXNfJBBl|sR}c;Y z7chlzc#s5k#j|i;HOx26JeCDP5Cq}gNtp~gjynFAd)}wfJ|h9gQAgMP03g%r#j6Y4b%c1O{wKiR2FHl|dX}Ecq19ND&d8&(kastuur!~B; zBZG!275JlM=qFiNwg+18NFa(sOO zfLvk4{$&;K1@N`2SP5ADfgt$3w!!EH-i9Hd{z${iOaws?Zp9BPB1gOATK_=+0000< KMNUMnLSTY94u$OHxkh6b`?>KzQc!Ui74z{4n*in4*B2N(t#nlY$Y1C>o=*Dm}7 z)=QeIuC96%G#G|q7@tlprFbyt9{;-EZ1ze002(R7hr`i-Wye&By9KVqSl!HLSu?ej zP9V#g^tU@)2mpxp{CxFP!&L&UR*nlxis|=nPK2^7UL)X~L%b)S&4KdVYI}V7*>FNy9J< buDBYzQRUWtLawjkosYmDx$?YqoODo z*|jhSLc&eRJCHocWHOn|f9D|O@O*y!{N4U~eV=q6z+p;p=K>+jK8(d`Q-?6ax$vXl zR}?9SjWLvE3BdXF-Lfz=Q5iFMO0AzJ0N}mn^2RL-Lv!|U3(#G8k1-~>I3zs5K-;ze z7XTuHhz!|&1Vn_wa0<|rM`N}(0q5Mfj=Gh2pY2pYRk7B7%B{7i>h1+#+X+#rqe5XI zD)rP42ot&hV6`~uhSux*zMEVNg&lOeXVpya3OkPSuTQ=d1t# N002ovPDHLkV1kP#jOqXY literal 0 HcmV?d00001 diff --git a/Resources/Textures/Objects/Devices/pda.rsi/cart-tox.png b/Resources/Textures/Objects/Devices/pda.rsi/cart-tox.png new file mode 100644 index 0000000000000000000000000000000000000000..23f4f49f4564a77f8112a577e3c4fac099170312 GIT binary patch literal 299 zcmV+`0o4A9P)>JChQwbSiud# zphY~FWelD#T{!2S|ATuupeTx>ygLO+v+sMCNA>mkD4Hh{@O|$RMH2wZVR%>j9S#8q zg1%UyBxwe))^bjg`ytk1jFFCV6EMb*9=>QrRR9*j4;9C7fTHw5I&NRX_rM-nQI&Mu z&QBl<@0{TKlu6_!09=Csb~k57#D5^(PHD`0Y<4pM>K|R=?KB^Oau~8q671&yhyhr| x1J0v9&05V#!0ieC5z!)grq5*?DvF}Klt0CfL#vX^=t=+p002ovPDHLkV1k%0do%z5 literal 0 HcmV?d00001 diff --git a/Resources/Textures/Objects/Devices/pda.rsi/cart.png b/Resources/Textures/Objects/Devices/pda.rsi/cart.png new file mode 100644 index 0000000000000000000000000000000000000000..b9e61ec5bfca5bffbca51d983fd988f1fb3d7a36 GIT binary patch literal 242 zcmV>kK6p!+ZQttUv5)0Z?9MNtOi0*KZq`!S*Hn*aa+07*qoM6N<$g3a$_PXGV_ literal 0 HcmV?d00001 diff --git a/Resources/Textures/Objects/Devices/pda.rsi/crap.png b/Resources/Textures/Objects/Devices/pda.rsi/crap.png new file mode 100644 index 0000000000000000000000000000000000000000..d5d805f8a8297fca4a297f04dfa5fd860d37b674 GIT binary patch literal 434 zcmV;j0ZsmiP)-302l^>wRsU`0TZz} z*@V>VRumwz%9TlkFN??vn5q#;?OehcQB^p&-C%G8>r)Y10V{IVtpZ_3z&h;V>|jlv z7eGq>;Xk>zhSN1HYv-D}0A0BhIRL4UR6x|lF}VY1$M5*oFbt0t@WAOBcyAxYS!>3h zP98}m2dbsa6?@<^t-0rWYq(sqeVKLOX#uhA&#bek4LqFBKX9P5cCNu&v-$j29OzsF zJ@ieT1VMYvAGwJfK)oVv z%(d1m@#F%loPzw2h%O_Q%taKDFPB!K5EO<{907*qoM6N<$g57JsGynhq literal 0 HcmV?d00001 diff --git a/Resources/Textures/Objects/Devices/pda.rsi/meta.json b/Resources/Textures/Objects/Devices/pda.rsi/meta.json new file mode 100644 index 0000000000..d1c3e6d61a --- /dev/null +++ b/Resources/Textures/Objects/Devices/pda.rsi/meta.json @@ -0,0 +1 @@ +{"version":1,"size":{"x":32,"y":32},"states":[{"name":"aicard","directions":1,"delays":[[1]]},{"name":"aicard-404","directions":1,"delays":[[1]]},{"name":"aicard-full","directions":1,"delays":[[1]]},{"name":"aicard-on","directions":1,"delays":[[1]]},{"name":"cart","directions":1,"delays":[[1]]},{"name":"cart-a","directions":1,"delays":[[1]]},{"name":"cart-b","directions":1,"delays":[[1]]},{"name":"cart-c","directions":1,"delays":[[1]]},{"name":"cart-ce","directions":1,"delays":[[1]]},{"name":"cart-chem","directions":1,"delays":[[1]]},{"name":"cart-clown","directions":1,"delays":[[1]]},{"name":"cart-cmo","directions":1,"delays":[[1]]},{"name":"cart-e","directions":1,"delays":[[1]]},{"name":"cart-eye","directions":1,"delays":[[1]]},{"name":"cart-h","directions":1,"delays":[[1]]},{"name":"cart-hos","directions":1,"delays":[[1]]},{"name":"cart-j","directions":1,"delays":[[1]]},{"name":"cart-lib","directions":1,"delays":[[1]]},{"name":"cart-m","directions":1,"delays":[[1]]},{"name":"cart-mi","directions":1,"delays":[[1]]},{"name":"cart-q","directions":1,"delays":[[1]]},{"name":"cart-rd","directions":1,"delays":[[1]]},{"name":"cart-s","directions":1,"delays":[[1]]},{"name":"cart-tear","directions":1,"delays":[[1]]},{"name":"cart-tox","directions":1,"delays":[[1]]},{"name":"crap","directions":1,"delays":[[1]]},{"name":"morecrap","directions":1,"delays":[[1]]},{"name":"pai","directions":1,"delays":[[1]]},{"name":"pai-angry","directions":1,"delays":[[0.1,0.1,0.1,0.1]]},{"name":"pai-cat","directions":1,"delays":[[1,0.1,0.1,10]]},{"name":"pai-exclamation","directions":1,"delays":[[1,0.5,1,0.5]]},{"name":"pai-extremely-happy","directions":1,"delays":[[1,0.1,5]]},{"name":"pai-face","directions":1,"delays":[[5,0.1,0.1,10]]},{"name":"pai-happy","directions":1,"delays":[[1,0.1,0.1,10]]},{"name":"pai-laugh","directions":1,"delays":[[0.1,0.1,0.1]]},{"name":"pai-neutral","directions":1,"delays":[[5,0.1,0.1,0.1,4,0.1]]},{"name":"pai-nose","directions":1,"delays":[[1]]},{"name":"pai-off","directions":1,"delays":[[1]]},{"name":"pai-question","directions":1,"delays":[[1,0.5,1,0.5]]},{"name":"pai-sad","directions":1,"delays":[[0.1,0.1,0.1,0.1,0.1,0.1,0.1,0.1,0.1,0.1,0.1,0.1,0.1,0.1,0.1,0.1]]},{"name":"pai-silly","directions":1,"delays":[[5,0.1,0.1,0.1,0.1,0.1,0.5,0.1]]},{"name":"pai-smirk","directions":1,"delays":[[2,0.5,0.5,0.5,0.5,0.5,0.5,5]]},{"name":"pai-what","directions":1,"delays":[[2,0.1,0.1,5]]},{"name":"pda","directions":1,"delays":[[1]]},{"name":"unlit_pda_screen","directions":1,"delays":[[1]]},{"name":"pda-atmo","directions":1,"delays":[[1]]},{"name":"pda-bar","directions":1,"delays":[[1]]},{"name":"pda-c","directions":1,"delays":[[1]]},{"name":"pda-cargo","directions":1,"delays":[[1]]},{"name":"pda-ce","directions":1,"delays":[[1]]},{"name":"pda-chef","directions":1,"delays":[[1]]},{"name":"pda-chem","directions":1,"delays":[[1]]},{"name":"pda-clown","directions":1,"delays":[[1]]},{"name":"pda-cmo","directions":1,"delays":[[1]]},{"name":"pda-det","directions":1,"delays":[[1]]},{"name":"pda-e","directions":1,"delays":[[1]]},{"name":"pda-h","directions":1,"delays":[[1]]},{"name":"pda-holy","directions":1,"delays":[[1]]},{"name":"pda-hop","directions":1,"delays":[[1]]},{"name":"pda-hos","directions":1,"delays":[[1]]},{"name":"pda-hydro","directions":1,"delays":[[1]]},{"name":"pda-j","directions":1,"delays":[[1]]},{"name":"pda-lawyer","directions":1,"delays":[[1]]},{"name":"pda-lawyer-old","directions":1,"delays":[[1]]},{"name":"pda-libb","directions":1,"delays":[[1]]},{"name":"pda-libc","directions":1,"delays":[[0.1,0.1,0.1,0.1]]},{"name":"pda-m","directions":1,"delays":[[1]]},{"name":"pda-mime","directions":1,"delays":[[1]]},{"name":"pda-miner","directions":1,"delays":[[1]]},{"name":"pda-q","directions":1,"delays":[[1]]},{"name":"pda-r","directions":1,"delays":[[0.8,0.8]]},{"name":"pda-rd","directions":1,"delays":[[1]]},{"name":"pda-robot","directions":1,"delays":[[1]]},{"name":"pda-s","directions":1,"delays":[[1]]},{"name":"pda-syn","directions":1,"delays":[[1]]},{"name":"pda-tox","directions":1,"delays":[[1]]},{"name":"pda-transp","directions":1,"delays":[[1]]},{"name":"pda-v","directions":1,"delays":[[1]]},{"name":"pda-warden","directions":1,"delays":[[1]]},{"name":"pda_pen","directions":1,"delays":[[1]]},{"name":"pdabox","directions":1,"delays":[[1]]}]} diff --git a/Resources/Textures/Objects/Devices/pda.rsi/morecrap.png b/Resources/Textures/Objects/Devices/pda.rsi/morecrap.png new file mode 100644 index 0000000000000000000000000000000000000000..24097c2edf08762080e2e644da3790e1b05ad962 GIT binary patch literal 325 zcmV-L0lNN)P)9*}z_);NI7Qac`e!U}L&JQM zi=7$!J$ptAD2k#ekB%8o>$3=h65sANQQ&j`RZ)s>+85@~`ihy7 z0Zd+|@{WMRUvFmy%$2%J-9Tvw{r69P;_BTZ8pHr)rMXc6a1@>=(kvSISS~OgKmP~b z=C5@VEeHlmEik9!IT^g(Ot2enLJ*e>q=o)=yOs}aMGzN*1;UG%71v Xf<#EB28B{C00000NkvXXu0mjf4b+1N literal 0 HcmV?d00001 diff --git a/Resources/Textures/Objects/Devices/pda.rsi/pai-angry.png b/Resources/Textures/Objects/Devices/pda.rsi/pai-angry.png new file mode 100644 index 0000000000000000000000000000000000000000..6d3f5d0115ad944e1d0513b3fc77e158c90bc321 GIT binary patch literal 428 zcmV;d0aN~oP)A~@JJQ=xPUbm-`C$<~MIJM;E3hIPpnPcNX2t~&SmURZDAt^N;>(Sz3< zpzqxEl{DVPDdzy~LAQDj7G6)l=0{|)%p3dA?|!|$h*Y(eZx7ycz_IgcsyU$Rw@K!J zxr|-k{JDC{=V*w};8^Md00000008*k$Ol-PARo|^3((_`qR0mft06 literal 0 HcmV?d00001 diff --git a/Resources/Textures/Objects/Devices/pda.rsi/pai-cat.png b/Resources/Textures/Objects/Devices/pda.rsi/pai-cat.png new file mode 100644 index 0000000000000000000000000000000000000000..a25e96f19d171326a0465ee3b86233803fa19ce0 GIT binary patch literal 469 zcmV;`0V@89P)h!DCmG(SyOz4n?ZtxUNs= ztfu)t2)R>a{X#k`f;%Dr00017D>t0ZclVDUbNjwMJ+Q_Or5|x8u~vs)`@EOW++l<1 z-*P9=v>m0HqBK*~w4MF*+a&R=&yIj3j_CEJw6>w&cH|BkP~Ry6%!&_pz}S-b)^~~k zqOTPn?tt;7BfzIVdjX_(cxip-2uL$^_M3SRr6VBCl+_xu7m0wpD7cS$p=mqHi-I;g zZRgRqxj09_6ib`|b@hGf_ie8J)t>?E>*}2AsKhn+ujm5+0000000000001r<)CX`U zu~rA06*3taB06c4t`G33@01r9%fKv^DOzpSr2b~7WeX&dIHDwuXs@-khrT3rRZi-g zEYVz?>jUzlILXiVeMy?Ovr(|xs!^ZAMdk)g6#VqPNQH=5?J-{x-}+8xz+UUKcd@QY zYfIu=-}zs_SAIUUzVjL2D?cAvAN2v;2SVrPL+b+o000000R9J`+WCE_n{5V>00000 LNkvXXu0mjfkG0p? literal 0 HcmV?d00001 diff --git a/Resources/Textures/Objects/Devices/pda.rsi/pai-exclamation.png b/Resources/Textures/Objects/Devices/pda.rsi/pai-exclamation.png new file mode 100644 index 0000000000000000000000000000000000000000..52a088b3116bf797f0b118e625f4ff641d32c428 GIT binary patch literal 377 zcmV-<0fzpGP)#M<6m}w{2zDOEJ9q-`;96v06?mal)d%cd3L9MHd?;C z09jtBue7S|{A2Zn;GG5U>|#1?tij7``mg-)u-{nK{Ea%Ge6H3mePs-KtLJJJ$qVp( zh0Et^eU+yXFP{!jUnp1k;eKYpyIM8dP6x~vOAFrBs+uqV31)d=Szg%L`J}OS-34XF z=<^q^Ry9BQ4oH395E=m1WKSNY>%-=1FHYE?xCs1w+g4rmMa0{{R303_)H X!iN$VxcAKP00000NkvXXu0mjfjykM2 literal 0 HcmV?d00001 diff --git a/Resources/Textures/Objects/Devices/pda.rsi/pai-extremely-happy.png b/Resources/Textures/Objects/Devices/pda.rsi/pai-extremely-happy.png new file mode 100644 index 0000000000000000000000000000000000000000..321b46c41204d7a11b0c0a8976fe5d5c4292f427 GIT binary patch literal 447 zcmV;w0YLtVP)@?YZJd(ucS*x4+)=UOq{e zoh|;k^Z}Z-Lz)?+nL*Qb!)H7flJEH93Ro^8ygZk~wKbmmkS;o7e5VSq8QR02M`ev5fKsj@CAnC`e}0_ysiKM002ovPDHLkV1oR{%*g-% literal 0 HcmV?d00001 diff --git a/Resources/Textures/Objects/Devices/pda.rsi/pai-face.png b/Resources/Textures/Objects/Devices/pda.rsi/pai-face.png new file mode 100644 index 0000000000000000000000000000000000000000..523077242f784a238d23a34f503db2107d5236cd GIT binary patch literal 534 zcmV+x0_pvUP)p&O&Q?-HZYrEg+DU9?l-CTX>)T|2RTWs|`9~F4Zw_zfMee=| z7(G)3>Y8z?;0&;;0wVi2Zr_~CDo_?$!X)b~!+mjmhV?nX7u9wr)qv*>__+F=c z@L$mTOZzl zwlmyzYEf^_x4u;dv_1KDkAO>t)`#B#<`;-l)%YKp>)*1pw6b9hG#o)nr=-$m3JP2<+Oz+SW^bR>pw~`@Hx^?f~(SyOz3`L3%uHz@3th)Zc z$rg5g;k+mYJ%EUai1zA6a`FA+^Y_wgKMqf#&(4)!NGEaEK3u)#^YkM9SW$l6v;ctj zx04(9$0YgU2ha~AI%5C;ug9YspBhV{AI8ay*j(`gsLH}U`Kr9!?vH&%O=WrhHIn>W z=>+;=L_dtEo7NqN=P7CDM^ymu^NoiUV9(d60ImF}H6SPL{OAg>tFF(k1F0)uD%+pK zDix4=wV%t^%#N;rIa~S{*!>zHeqCMiI-24&_^;#>5fKp)5fKp)(YCQaKspKS{rTMa zQTqa#`}0zD)6V91#)uw(cze7m3shx+&KP$bo~LAYfq%>Qt6~YYy}`9AKs$f;dxKFO zB4Kw%*rkz@c7Ak^kZp?c+23dC3ee2oWPgBW{_fWR_6JCB$h|+GJD-S%h=_>(hcjgg VA$fOaHrfCH002ovPDHLkV1i1l&v*a; literal 0 HcmV?d00001 diff --git a/Resources/Textures/Objects/Devices/pda.rsi/pai-laugh.png b/Resources/Textures/Objects/Devices/pda.rsi/pai-laugh.png new file mode 100644 index 0000000000000000000000000000000000000000..7f709032535cf7418666c0a7189d0bd80be537c0 GIT binary patch literal 484 zcmVYU6bA5531oFH_UT!4s(h|bl8i~sC9E<4 z`1;1%8KB2LGoTss7)gAq8Zaguf4)?meXo0Y{jtt~*&^xe)4#tVGN8yaQ~3e=47ARG za-W*Y5BRVC?f9-@T4w-o_&?m7XASVkb$s#b>M5_IK3;?WOMD_CA|fIpA|fK1wn?oI z@WE<*fXn{;*u)ROb$@JE6*`-)4^v{jMyRg_46#PYwaKjyaBXty16-Tj`T!y#A|fIp a7d`b{05NII7(#lJ3Z0hFA%HRF|Jb9H>*~*{HZ$0;z<(GetTyM9vUDxb?WHr<6yK$>_ zOHvr_`YSW~}N@3dp}ZMW(RO`m<06=FW#mJ^s3%q6+_@Dr{5 zd+)i{t@$?Ft>MJauKV8_Hq6__-qrEv)F+tCYJG=Sa$!;XDp^8GKR@4HApd3&`?E>; za*UskI{m(^QFPk8zu|w$Mdsp@&m|wsSzi}h|D@FB=zWGK%piwDz^}Gn49{y`G0*wD zlE2{Ga=QbT_haNIoc>dj4YK-q+cP8k`?KU%|2@N73YMJ@Q(nnt@jO`m!sZ%?IbW`G XvhZB|B)((OS&)FItDnm{r-UW|ui3SK literal 0 HcmV?d00001 diff --git a/Resources/Textures/Objects/Devices/pda.rsi/pai-nose.png b/Resources/Textures/Objects/Devices/pda.rsi/pai-nose.png new file mode 100644 index 0000000000000000000000000000000000000000..7325e5afa1b095df75dd8d51a2f6ce8362dae812 GIT binary patch literal 269 zcmV+o0rLKdP)!Nb^v6boW!Z*RFpU_q;d=nCcswsIaUWRuD8 z=Q9~V5QKkc#RPBn$7gBm?Q|&0tr!6Sura%zG56tIoNvtv7{i3NGiW=5F-+;p_ZVmg zbfa*+3~3$7_Z~#PDhFc4pAN(|11&%|D!HH=h2Gk?|J;>D1msnZVS@91<_1Gm59G9+ zN!3Rd?}5Bx=l!e?7^+`EZ|&?XI>9(V3y2ju@7b$gp++%KHjYcjupkJ6AOOG%BZYb5 Ty8W%F00000NkvXXu0mjfRzYt= literal 0 HcmV?d00001 diff --git a/Resources/Textures/Objects/Devices/pda.rsi/pai-off.png b/Resources/Textures/Objects/Devices/pda.rsi/pai-off.png new file mode 100644 index 0000000000000000000000000000000000000000..7f3a7ec1a66734c3f62cbe6cb9e7d998eb6f2e11 GIT binary patch literal 171 zcmeAS@N?(olHy`uVBq!ia0vp^3LwnE1|*BCs=ffJB2O2`kcv6U2@70d#J~mwW@cd)zfUheA93~1zrV9HK6{ig*ma*|^a(NUjN@Cd z?ET3ihOGxzFuTbbJm6DUsgahDknn-OTPZ>&KW1xBO0oMv4TuFX3=CJc2(S21z7)t} OVDNPHb6Mw<&;$TbMm~uE literal 0 HcmV?d00001 diff --git a/Resources/Textures/Objects/Devices/pda.rsi/pai-question.png b/Resources/Textures/Objects/Devices/pda.rsi/pai-question.png new file mode 100644 index 0000000000000000000000000000000000000000..32d1bf2aeb686a8acb0e48eb47d7a4faa3000bdd GIT binary patch literal 402 zcmV;D0d4+?P)|?6^DShb#Uw8R3{M;3wDrRYz%46 zy?T;z|G(+pOT1r*Cnn$#0RRB8y3ibaH+tSRJ@)g1sTIc!$szlWvV2%C&`U3y}005l8H{tEqkYo29xBvhE07*qoM6N<$f{CHJkN^Mx literal 0 HcmV?d00001 diff --git a/Resources/Textures/Objects/Devices/pda.rsi/pai-sad.png b/Resources/Textures/Objects/Devices/pda.rsi/pai-sad.png new file mode 100644 index 0000000000000000000000000000000000000000..1f040034b1bd3f000f206844b03a7ab4b3d2166f GIT binary patch literal 704 zcmeAS@N?(olHy`uVBq!ia0vp^4Is?H1|$#LC7xzrU~2btaSW-L^Y-ppFX=#uhKHAx zc63CCJH7OJu}Hy5%(-mujC;=O7kt0a{nBp}2g||M2VPu}p5=vs8e6z${ty>_ZZUK6 zneR3VFBViTPC3WZ_<5!f&}@ODyVdUhdHMQ#{rbQ6PRrkyvfWlU^IzO$^^b`^ROim& z3-;2S>#yGZn7{w;tUo!wHvDS+)f>;ye*AEWnVh|Koc!+}J8!*^ci4aT-|uDq51wUB zV*6d484{YgVgL3YEB5c(IcrV*1oI2|+wWJf?)dxJeCd>Vd%33X)iPiB?)I`}GIwey=upnZBMu^KNW@)^+i_^B9-@ zPJdi@@!yJ7mvZXrZMM(f%VcBA>=wH9$F3ui5^LuNRh8^L|MvYG+lIOi)eL{je&z3C z*Kpi_x9;(F?fB1SPt@+QUA^CD2lO`tY?yn7o#URlyh6qOnuZ6ppBbCJzvbn*x82+T zEbw=Y=z|XxGy3>~Ui|%8`!ank!*=ndk*a^*6a@oUUQ0g;~b1fE~lOYGe5Xv-fG&FKqkwZ{asKz2Nzh zOMmfy=We?xeWU&F$K0>G;~3|C>*xD4&-okIh3S7k*1nXV%eOh~z`Z-nFWC39UpW7I zHow50e7gpOr!Fu*V`g~|5q9{n?%{@i`* z{Z(6s+5bbWm)~do&Y=D4`Q_c#PlEpbTEkP!A8^R*`|b$Vu&>2o4xbsnFoOKiAorX9 Wlcn920O_O{5Z}|)&t;ucLK6VA2wqnJ literal 0 HcmV?d00001 diff --git a/Resources/Textures/Objects/Devices/pda.rsi/pai-silly.png b/Resources/Textures/Objects/Devices/pda.rsi/pai-silly.png new file mode 100644 index 0000000000000000000000000000000000000000..cf0279e88c8c4873cbfe4f323c294cb9d9a1ea9f GIT binary patch literal 499 zcmeAS@N?(olHy`uVBq!ia0vp^2_VeD1|%QND7Ro>VBF>D;uumf=j~m4FJ?y(_6LDX zV)qW-(_;x@vF3j)YtvZ%!Jtgh)#1&Xx4OYBEV?O&CrOlkJ8!e;cdf#)9q;m|&E4*t z5v~q8C%u4(3^LAerd~Uv~;Z@K3^9`>G=eJF} zzk(^~m)+yv#tVM!d@pIShER0 zE1&blx*t7W5$+(KoDsvgU(=8|*lG{o^fUF9am!~PeRSL~f|=`Sd0_2L{pV4Uvh;uumf=j~nFEG9<@wg;XZ zOHRmMS}vT(z43HnQTrT)@)L=dSh*eFTw3m*smS3e80J)W<>s4r$KTlTbNpNLTg&?K zqBGr^j0_CP#nU!_JbU->@0GXr+1yKiTfOF|_)h&tyLQ>`I{W&QX8HETXYJ3|GR}Uh z=esO)me1-fH{X4mzW#e@X2#E(#t&Y7Qd%2+`tR3U*MHwDDz|#{$IWN4z+u| zk8k>YBLDMW^I43VwQ?WdD=*l0_c+HN?cM!`r-?U_%o0|NpG7MT2E zJopnC_x@&VzjmTLGvjYd{aW6?*}XNMuRqUzvi+w21~U_jczXpnzHbR)FW686F^b{T zLU{ondxaTw4hDZ45?ue)JEYXz?)vk;;l!V9qC3q>>}I#F?aPav__yI}*34&{BR%SF re_?KV$1pw7=>R;phL4}3KUO)4hCb;AhPu^y+cpXJM=K!f(JtgbSQW#g-)hhGXw(d;3~*T zX#FdaoV4$QfTY-d;`g&LydNNh5JJd*0m-}+()TwV;Yn3tQe!CrfpUbIJjCkL2{Z{Gnk z4vBAlCkFsc#kcQ(nTK|OPknI#Lf_%o`pyo>a<%iHc@ASZz?Z(W17<}bJ=F`gev<0V z`pc8sew-cf6EPeB0CiRFUFSPMfcSH@%jal_&){RxCxj3}2qA?R03Wo0R75BWwXi6SX&$GHXey!xo^fO4Q%ueffN7 z>Z(bBvs~>sU@!54B0O+~i}${+v$002ovPDHLkV1j+b-3Zt~5Ji8YWSc1|Mo4riXj7!(0`7fK_gui$7TdZ=gOHF5nj};dq>4orM8+HMrU+j` zX6)h510;KZUH@Hou@5lwG>^Ua(H?U>#1<~g@_Z@GJLkeEg%i;;^Hf#UW=`Mt$g(Vq z0AQ{C5kmY00HA4_&GlgzzKs$^0hG@#;#_w+rUw9k!{IU9f4se~=8WSg_KODCDtw9V zlR4cAAm!U%1dv)gzz*=|08tx}I~`FxEl$IQ+E;fS03s5ZGc&yRBG2ewKt#}5gNRly zt#y=NG=NeHd7eWlwU`G0W6X5{j4|lCZc*qfCZZ_6=+lshP}enxD70R{YO5xaxS?d` zsVIsNw{44gn`W)W`FgURa1J5O{cX3rYuC;63E%@|*q*0-+5i9m07*qoM6N<$f+6>s AasU7T literal 0 HcmV?d00001 diff --git a/Resources/Textures/Objects/Devices/pda.rsi/pda-atmo.png b/Resources/Textures/Objects/Devices/pda.rsi/pda-atmo.png new file mode 100644 index 0000000000000000000000000000000000000000..b3977d4b429ff6d3f3d3fbda9511bd49115b3051 GIT binary patch literal 500 zcmV$+Y%0RV|aLiUrw3UCb61F-JZc&+RB#+l8Pn8HWJ6|nBr zQu~@Ge+D0ytS3ALNjL`TQ!b3v`cmsyt&hQ)bJ=qFIj|k;{k9sA^B^Y&;Oo@s`;t14 ze(HQ2$Y~0aBJ_st48EjOQ1x(}!OKoTUiU!B9nf{1wZr?Io8>KFM!5iBCA?$AO`}=k zq6x5C&0Jo&czk{V;Ep*oP2;iJh*fQb{+?alBz^?pdmt1F0T7GKGwE>|A1^J@xVHzu zq{oHTVmwR&fk5E}Y;P{&R~2mS7G~{J07R7tQ6&PvtbGbwy9K|haIn82EI|5AI5a%* qYhJQ>LEnVgg!}~2#$}Z8Z}0)K?WT-mIe?u20000P)BE{Q*zm@Cv2k6~jH!EPi zNQ-#*oRsqKOg{D$Ovhf~!eq28&dF$r^WiO*uAT#zuV-85CwLxIasXK0dNXd-fz4aj zaiG!^)k+*=dncx5b002ovPDHLkV1k0=wr2nU literal 0 HcmV?d00001 diff --git a/Resources/Textures/Objects/Devices/pda.rsi/pda-c.png b/Resources/Textures/Objects/Devices/pda.rsi/pda-c.png new file mode 100644 index 0000000000000000000000000000000000000000..67dd6789678719ea293cf2574ef9a07b735819a4 GIT binary patch literal 442 zcmV;r0Y(0aP)XKrmX{JY<&)AbG$r+A^(>| z^O#6=K!&#@JQNbScERaHu3Zd%94AOMjxcV2ZOi-f}MMR1%eM{lLCl#!1e2p#>iwz4@6_+#|OB4*zpw%lNBM2l9MM- z672wzT13GS=?qeg1q?4=Kz#i21w-( k-66ODu@;YlQ7~u#0Q29GN+2DAl>h($07*qoM6N<$f&s#}Gynhq literal 0 HcmV?d00001 diff --git a/Resources/Textures/Objects/Devices/pda.rsi/pda-cargo.png b/Resources/Textures/Objects/Devices/pda.rsi/pda-cargo.png new file mode 100644 index 0000000000000000000000000000000000000000..f43bcb24816a23ab18af3d1249dfca3443042827 GIT binary patch literal 417 zcmV;S0bc%zP)M&P1g`W_BACTKvph*IpVjJ6NWrpa{=qKeHikj<^qb!0lJ64 z@87=}rfzydwq+DMpjP`4QR3=PA{%!U|=AwSw?c3&@{FYuR2mJC&>Zm4#5S8wRjYaf3V( zmWGt1!7W61cr_e%dT90Dom#_v%lq-Z?|#4U{T{#L0XA&>F(zn*D@zNXEQ#-mGF5IW zkyiXT=Fs<|<)lFq6SwtvC#q1JaQr6Fuzz?)D`nC;sg(c<_aA!vTzxWfoi4X1(&uC{ za9du}<5d&}a)gl482|u9QCL42u7QZ(4FHH|8)(n?3>?Qf;iz4Y)<8Vl(BrB1d>`Lo z%tt*18X|tT-UZ2((^tur!{$_xHJ!B%q+1(?RRvoQOmzV0p1L<4YX^EyZKVUIra&`6 zX4m`pu};C{+f5(OIt7;g17q(1Ap|E^b<@Qx8`up!>hV$S+{n#snKHmMhCI(<@1+W! z=g@2s)QO0CQAD#vRPI9MMq)sgWdMNG77$8R)Xj%3A4*jqc?1AJsZ^piKz#-2<7CLCnsJJ1%kVdLN6 Y3orzhWr+FmUjP6A07*qoM6N<$f(0?oYybcN literal 0 HcmV?d00001 diff --git a/Resources/Textures/Objects/Devices/pda.rsi/pda-chef.png b/Resources/Textures/Objects/Devices/pda.rsi/pda-chef.png new file mode 100644 index 0000000000000000000000000000000000000000..00e98af42713ede9693a9124c2c9419f2529ca12 GIT binary patch literal 420 zcmV;V0bBlwP)TN`FA=+l72U9UKH7!KL7kwNtlNaB%A<_ye}x975LzRk~D&;M7p}fU9C~ z%^i~e^#Krs0 z;YzMtuAuaEo2`K1#0}%>>wPT$q1aD(3Odbt=t8?T4cB&Uij(S0wOu*~uHKGU)-R}e zkjMdGx$9`0s{_$pr*Ri&3+#Qfo;_~`AFz4J3t zoo(CXo=RiL7=zKcHzEOw$AaxbE^mnx+ZP<7Z+W$e&;^xPa$* zFbpFkiV||p!5D)O0;5r%EI|2A*lL~rS{IO0?}TIl--Y}HDsh1V{|28oe1p4`R5pwN O000021H<=)3R?|Z)Y%RQF^CQSS>21FCR-tn>w@x{fh5VuXV zcq9_T@Am^>-*mOiD{d43P*oL3ltn~XLOs4^OyK6)C8Sj~Z)9htsGrHV5 zA$y6g>&(qe_C^3esZ^5v<#z>y7n}ejk2H!Svkft;)rRH%q_+Z+M_P4ne>!W5zf1B- zcR_f;S#=>abX;9SL&q%Iv$AyEIk5ja->_C7=RrpfK<(7^`@T9*f9h@==%@<}5&EdF zDc;vE7<|k$#bvvot9PL94(Phh&cQ>+#kv*{TU!O-Wox=+e0cpFfLtyo%qi7|ilUIu z=kYke;{a`GkL#&;^*fWvpeTwArTjbKcDvafivyr(wF|jB7RTpnz7sz|XlydZv0yMt zAQ0eY#f8TKSI?EWv7gv3psFgVR00qi%cN(*U@-b^o=kBm0bhl*gJ@wBCjJdR0FKC! UB@#n?QUCw|07*qoM6N<$g3(ve{r~^~ literal 0 HcmV?d00001 diff --git a/Resources/Textures/Objects/Devices/pda.rsi/pda-clown.png b/Resources/Textures/Objects/Devices/pda.rsi/pda-clown.png new file mode 100644 index 0000000000000000000000000000000000000000..7f31664a00928899ee72e3d4502ac808b4a56266 GIT binary patch literal 526 zcmV+p0`dKcP)!6c^&?!?kaS)+fT$~jpO9h8Q!Nu9d zQbcL!P-ur1A=o<9yQIk_xoe9E_Ce{Fd_Ug1FW)5xEb!kE33B$-?8teYQd@!X)8sK7 z?g9X?r*86aQ{1bso_j1Io*RDTSA_=F&px=wn#w#^`0*Ec!ry&5Sp%z-7OMqKM5Jbp@1h|FxftPrJ1^x`a0Zo+58pNYa Q+5i9m07*qoM6N<$f(#Ml!TC?A}GMj~1%bk-07>@k$M-iW3Va>q6z`!6T_6SA1aeh4m z0|Uc zv~d6f0|UdqfB#6;LR|-BcuO)cFfcI8*!rB|hqxVz95XWu1JmQ(v~|FYtES)Kyo=CARxf7c=2Ke1_lO(=g$!da`EED z44Rsnq#8$j6zrY5f#LPb*9`TEjc_q!3pF)08B9z}7#io-GhEtolxPQ#+$PlXvBs+o sW;wBKLZTgj?hssnSc^x&C>S&V0FJkevm&?L9{>OV07*qoM6N<$g2v>%fdBvi literal 0 HcmV?d00001 diff --git a/Resources/Textures/Objects/Devices/pda.rsi/pda-det.png b/Resources/Textures/Objects/Devices/pda.rsi/pda-det.png new file mode 100644 index 0000000000000000000000000000000000000000..e93ec473b476cf650016c51773a1763ce004218b GIT binary patch literal 434 zcmV;j0ZsmiP)C?A}GMj~1%QG`87=E5CAj>ASf#1J>Gfds|glx+wc7Q3%W+GLZ5p5<(*-)65kwMC3B7-n5Bb?2sT>DOPt7I-`vz*vAA!!lDK)7*Ati_{X c6bu>w0K*Y~Tm@W*1iHj%*K0ucYE-r#Y6+{$j z+rdGEjv_vau1cvyQ-{*{h}C;rTOIN*_ax`P=lu64CtPsg;E&-FC3dzq=VS^W$5TSJ zg-C_wi%SXs=1e^RXW=jaeq9GZnY#mEe9ROUp@;|om|xhiz4Pn3)%+)JG1Le%f!N6- z0NHEf%e?3034oS1@tRTs4wGH^ptT4g35H=*P5^*unzCDdSHNg*0{|<#X|nZ!4>`BH z2IXqMvI16i(^l-cJF?|pB?$^4VDWL@1C_rynFO{;kE`my`%{q6z`(HPOc{!}#1AQk znGCc46XOUbVjMtAKvW38z|E^yQ26hm0rKd{GZb+N5h>a@!2Z)Q6#mQw@fd1;|NhOu zAVR#EBsqYAfq~)Qzkj4^p{@fmyd@bJ7#J94Y<safV40mD+CxA5WYrc z(=`N;eN9OSkd+Hyj`%I*gdtDYT)_HlABH@sxqzZ_fbJpi`}c2#shggVZ5hQ55HaMY z*g}dNASx)x!26b;;j{2Z1_lNO1~oPfhUd?p!})NzAH$n=$_TfAn`+rK~6>rZqe26*HPGVGE$J%(2ChaJAmXiVR}R= uUUe|biER@S?ErL#-~z;2JPJm^paB3$>X9eV0FmAR0000T^z{O1(67I-p%Ao?Sj*n`%IqN1y28g(j73y;O6c*cQI!HZ^5H;!9$SRP-~6Z zYz?h-98V_6a}*aQ008>^_V>U61VQp%N+08Kn@VRll11Z~5DG$cptS~LEIw@%GsYmL z4=Hz-l+8p$o(YA>UO;J3ijxE!3i%1Pg)3C}H~0b#%97B2r`=Ql0000+^jSWqKi-ki&I5hUK8X8Kx zG)PpSk1jnM%%`_U@m*h9!#m6U?)~mN-?@kPT`pk5#vfydx^Xfw)s!JFmsAqBi&}hR zbshWl31NLFF#`ZNzT6bnLz;pta!rZ|2Sq?XL2{st8}&+$>bGzbhb}3(P>E;t@e`zs)mXGZLKJU8Xv zCHbVgAe{^wE~LB#V@!DqSoD-+>8v?$P+t(n7UVqW$pN5q>h5@;4s@T|iUU1$L0be@ z=1uv5cEND9Xv)iWfu(z3;0|!kv3pYKxtL`E!RZmp1uY2}3j`2z$8r014FHI_<6w;8 zb@Ukk;H&vtu}0^Vz6Z|kityF^00721KcuhbhuSF1($NKM?QJ8ZDTqcCqmbGt3vo1} zv|d9;IkEuhH{sgS%8&cn#i?&XvVgBbz5}(e4IBRk9|4Mx+}hs(d;kCd07*qoM6N<$ Ef{Jm+CIA2c literal 0 HcmV?d00001 diff --git a/Resources/Textures/Objects/Devices/pda.rsi/pda-hos.png b/Resources/Textures/Objects/Devices/pda.rsi/pda-hos.png new file mode 100644 index 0000000000000000000000000000000000000000..1346ac1d2c95c4298b634eb9eecce4a71db189e7 GIT binary patch literal 561 zcmV-10?z%3P)nhorVX!q^{I95eU?j}<(_lyx!?KjdGEY;fWG{9vGD{2gTZ>Ut*UCrbBdyv z;u47j6Q3DCl9$V6>Z_*H9b-oV0jiUD76}K700CPml@QxFF!{G<%xOIp55-iz{80Uo-l#kc#i7B&u4A> zAA)$oU9i67rd3#zj_JB49bp(tM5S1E1>H-c4Aq}$+{-6ai8LfI}*TTwxQqer&EqB%h;b9 zg)GZd-x{w|o9La+S|-pci^&2a_7?y^q3}xm5&H|mxr!(p-y?ANd^r3X!$KYp!nr)) zLL=dqKJ9WLn#th2ScJppLq*e=*v#Lhq9}Du(;!I_s_8W5#>Re(C&|ef)=bDX6%!Hw zFqF;y7+djp0DvnwHvvMT*=_~5GLrYDF97ffVMfKk5>gqS00000NkvXXu0mjf$Tb7b literal 0 HcmV?d00001 diff --git a/Resources/Textures/Objects/Devices/pda.rsi/pda-hydro.png b/Resources/Textures/Objects/Devices/pda.rsi/pda-hydro.png new file mode 100644 index 0000000000000000000000000000000000000000..1cca5cea173301e2775b34fbf363b35daf9b7bb7 GIT binary patch literal 478 zcmV<40U`d0P)C?A}GMj~1%QG`87?wSo2N&Dp@e@Uj%MNxp+lMEFfq`M# ze_|ZLM2rJy35W^-7>ASf#1J>Gfds|glx+wcEAVm`*8Lb-Qy^7JeMtzc!cW= z7$7MdvWhb^EY_4{U=?R(IBR6eu>MaFL*E@^hOC-zHe0V|_SjCy)78R+SWhhcP%fP_E zz)<&{je%91nZbuAgkkB@X+%4KvK4p6PNCKTqRk{J8}hRYGUUgvV&G>NgtK!!o8f#In-oBDInXrQ zl_Aclh=GBDf#KgPMC};oRK(D-F^5#+h;I=wFfcIe&brO8XkQ=0qtEvk`;i&Vs+=nxP}?UEwd{7W2MyQv^_5J5p`2ZuT;xH`M3*eOevDxEr1 zv|usRDz!1R2z7{;YNfe5%w~RY5Z?QE@8i8o0{Hm&2(Xe)_q?t->UBX;MmTjnMUj~z zU9SlDU>Z;qxu+&Fu9|N518u8`PN$7vFa!VyNm10E$~eC~aqTn4GC;YxJBDdmL-T}4 zSejq^5t|4`n02`gn5KoT{Y_NvZ-3?FcoMm69?!22I6Z1%dpG6e6h$7k8ZiR^py@^D zc_tPG05psy8b&|fzPJLA0xv=aBGX}JY){(|DJk|EwqD+xGZ>>B?39EIcs>ET0;Ti_V10qenhTt|Bg9zf9c`l%t(4u!&9x&(@^(TAu{pp&zU`YwHhI=M&|mx7Q%3MrJJ7i-L- z)FDj@mFDK!fJ=V3kbCasKYz|i{sSdSlrX?qzrQS+bH8XpQ|#rux67Mn=Fkd|QZ8$? znl_74iYSTzuq+E91hd%;-}f`~9B7$WuHTimHb5 zPfi$rc=6gq(gMeI5uT^zG7`{j_kg(UwrHf~_owr@&FLus0000!T>nHoH4w)!0R3ZD+dva^Z>M(y(k&o_Aj>k|as!mYwrx;Kc|T24K4yI# zq$^;WrZ5hIfcL{NL>$MMOeXwN!sh6TOAW9(sKy^3?s0l{F2u@$lu{5vU>F8oo}ZKr yDBatDpL=4}L=`5kdM8viP&HDAs_?+T%CG=FtEkOimEX7k0000{O$-@27+T7KPzoU?NEeHXgM%Ory16)ri-S&`o!Y@g9Q*^?K|~h? z7wce$RtPu-DO91ukzO<*6mo@gNZ*&suY2!#d+(hM?+1=I?|ZrT`|$L6-}lnz0W=zo zMxzmOy;5<W=ptm!Fx%p3sEw^u70k>ib7PAL&eL(0CdAHHFJrF-@$K-kE=wauY3>aKV}$-3sQkZMuooA zCa8L?k0O`P_JqH81N62O$eW;_0Z}k)ouB6TCC5(K22iM5Hqx0CnvE838U6jBkQ|`G z01C{}-nQd7d`ZguAxI8TVE`4j(+_igB*$RKanNy`lOG{Ae*>&rHb16RVHTEpc~#-o<0gZDf{nC z_j!4u&>!i5+D;YIrMZ(Yb=TeD#z$O!au0{E-VU_W5ANXa#s}cq;=nvI#I4V80k~$R z=mK!dWiwFQcb#Q@jYgxODZDuY3;> z<>yuJ0V4g#a)WW=mz-4|0XjQ8hS_2ADG;^+GTKbjOFENMe+;THfJ*<{VBN9@YKJJ0 zj={x+5}J(`zY>Pg(=INQq>P~Gr!y&jbsVRsT`sSX=Nzm0fKT|M>jS9zx;{Wa-1+&q c^)+M9KenkZKyBE5q5uE@07*qoM6N<$g2EHC>Hq)$ literal 0 HcmV?d00001 diff --git a/Resources/Textures/Objects/Devices/pda.rsi/pda-m.png b/Resources/Textures/Objects/Devices/pda.rsi/pda-m.png new file mode 100644 index 0000000000000000000000000000000000000000..3adb51ab574fa04281d89a73a722262abb8f32c7 GIT binary patch literal 465 zcmV;?0WSWDP)?LLZ>ittA^TRMb#l(4^=tgcwvP z4y_WrrVXWOn%t{t4L-{~FVA_;dG5nKmkSe2@W+@^P4svc8ajou*?XnhX4U55a1@`< z2SDuVuxDOma~A+9B@k<#0&df}&&br9f5>4N2J5TK zqY(g5uh(^d`CS1a|2zPR%QCOCYaN`)WM=y5X0!qlm*rM$soZt(Z<_VAry%5?Z@Cb( zUANYt?V2r1TDRPA4jflEI@S;9c`%Rz@U`pqc&rYz?|K*q2AYDV2*c&=;>S7#Go@4) zuR8@p-2-EHz%UGs&YuTvHnf1~{vH6Q>64!P_R07FiJ`=wtARa$JN{JAHVyyr`u~z7a zg%C(7NhV{;0<_4)$Gbg?+qZ%{$dK~d1j!8!@z z;BtyVii3lP5ZZIlJ3I<)(m%TNfg|scCr_S)_e}yr4Drtxao~o7(6%)YRw@+=g@P5i zTCGwn7OnKH4M-_Tr_)wsV+^%g%}PIIX#jwFy>7+J<#N`V)&@M!Ks0fL%;C?A}GMj~1%QG`87zDqbfQvm?oPeT6A$9?r{qV0A0|Udf z|HL?gi5Lga5)c&vFmV3#5jgwGDPa`3_ZkQ}AtNo?IN;h}Q#hL``WaTa-@kt|IFeu{ zNe*COU|{(7?;ojJsOx|XZ%GCQ1_p*1Tc0!h5Vu2-V`gSyV0yfpwhoxF^*Nl)@$wLc z{9h8yBRLmjcuT@VA(3kroKEE0#o)(r0-si_fT9qX|IH1Bh5*vSfUFQ;U_kg9nN8Oa zK=w5yAwX6xfH~r~loN(LU2_5Jvwaxyq~-#O$^p8E!0+F`8K!P}LbhcTJHSir6P$gq zB@jhUzh*t0{hb6eNy>&|;!+F;?|o$u6PIF8HPdAH5VeHiw(C>|RWnTnF>xt|H7B1j zh>1&)VkGJ1fV~no!?aCj7#J8B7+$~r2p6BW=?p`NIcb)Y1Q#II f;!!XP1`PlJqZ*I{uDahD00000NkvXXu0mjf=5@*p literal 0 HcmV?d00001 diff --git a/Resources/Textures/Objects/Devices/pda.rsi/pda-q.png b/Resources/Textures/Objects/Devices/pda.rsi/pda-q.png new file mode 100644 index 0000000000000000000000000000000000000000..d90ee0c144b7e46d0ab551c131e895a61418c32c GIT binary patch literal 461 zcmV;;0W$uHP)M(a~T*I7#JSD`aqnil2mrU-sO`Sl&bp~CO^?3sP^~o-wck_b^tQ?_wOI6S}1n_ zED9JH7#K3VA>Ny@^*O^2aXS=s%*-qdOpkX{-vO{FfLRO!94`-HsQpWl^1hBt1m=HpL!lvnv@jqm1Q-|)zD8!#H3X1-O-Trl?0^h! zNw_0^OF3c4(WtPp@Xgzh2m`}c2#shggVZ5hQ5sMUT%l)57f zW<;AwQZ^LfVQ07`o5Uc(!wzTfWbuUaVQf+W$>o6Z&8ZBBO7}A`FfcH%q@*y&*48pG zFfcG2D&5au^JyKa#u3*fgEhy(a~l}~{%&S?`04|LyqEyIeE?(2iwQ7nVD@ELIk}#J zfq}SY8Od$J@Z3hc>PWGiBnO~71Q#II;!!XP1`PlJ1XGRGGU&pf00000NkvXXu0mjf DkMF?L literal 0 HcmV?d00001 diff --git a/Resources/Textures/Objects/Devices/pda.rsi/pda-r.png b/Resources/Textures/Objects/Devices/pda.rsi/pda-r.png new file mode 100644 index 0000000000000000000000000000000000000000..8382078b265f67970725b84965004de1508d1677 GIT binary patch literal 555 zcmV+`0@VG9P)kA8vHjoyAQM=hy7)zQ=#w|IG&r9*@W4@pwG{DdLiR z?!ra;ryQ*{PnI4!=@zAVamjyL{Sw&)DG^0N%ZR%*4^Nqxfd)8FA8Z(sXVBY&Tl9=`3k)3;p#A8>^2H zlY%vLUOWI%SXCpgHwePmNz=Ijm-amUZG7?LjH_f}1eibaitdNEx$$^>l3SfqPMWGr zA@@Jej-J_Z)!4zAZ?>n2$0up7PtjbT>W|yg!z3roQbz##hKIXhC(Hw6tzCP0kUJ;d zjK(PWDW?df8vr|J{6{Q;MYy_p01yz_7IVS50oj$$i$UrtSr}`DxwT^~9Lk@6Zf%yv zSj7#1U0iulSQOXWC&8o`YXA^Yh^kRf6jt1>wNeeZd}d$n_q!{dGIE76^bKA)e>^vS zZ@GnW)GXD2s*V1NAPfoX35&}utTo?nJn8R(sGbniA~#K!WUaN6_}@p7Bzp;?fyvCT tFcyL!CWyk_E6?Nccsw4D$K&~T_y*k{nsEkE{rCU?002ovPDHLkV1fcm`F;QZ literal 0 HcmV?d00001 diff --git a/Resources/Textures/Objects/Devices/pda.rsi/pda-rd.png b/Resources/Textures/Objects/Devices/pda.rsi/pda-rd.png new file mode 100644 index 0000000000000000000000000000000000000000..99669734b1ca06390a12278b74a0b365cf5a7d8b GIT binary patch literal 472 zcmV;}0Vn>6P)NklB3OK2}Ej zZ^V4$DoDnIh6)K^$ruy95;nb;)O6MqIO=SeMjbQ_#!>(n+V=QudMANw%N1on1!005PxuZt&op+D2LT1_}7sSIUV zMzh(3gs}dp4ZJF4W3Fi$WLc)9q`w1xzaLD=0{|Es{E$q^BNB;F(}{OP0FY7Bh{a+! znPZR;MjJPMziw}}f<`w4h_z+po^U^#`Z11jIElb#BHuyuULrPv|pw;cx_@hpY7ykQJ!6OyQ3X3{UO{slDPQ zrC1yJ=nb*`iVB&1ux%TecuLs55deT{wTfoG2mmn6>4j|Oi)b_&)N*Po*<`yZ z^bMTG(l~nS;(RMDre%x?-|?`Ei*5IlQd!H$J7J;k{eWapnv)336Zr|MjROSuH~0dZ WZoWN%Sgn%)0000J%=P)14=YnjtQf zQew#BsRgG)iAzI`(=LK=I1#Zs1j&-^_$2>mhx&og_jFJ1o}NzV3rqa(xD$qy&1U=l zalKw2d!Jz#0bZlg(CTXm?&95U*SnTzwZ?Mo%}uX%`8pG;Is>klWm!Df+q=1t$xP%Q znI@G=C1CnCtb{SJNQ6qj#h3H*e{0}f#?W#c$KhE7P3S2z+5c0%F2)Tk@O-P*ga@_^;+lC$ozFgy~tldA)oY8*bz1F zyd!FuYsXRLW=r6;+6tU+5G{kL5`e)|`|IHZ-rS98^`=h1|J1i7@Z$G1ALnhLkWYFh zoO{nl=KWv6LK6Up|NJmA@81CnOTabq*As9YhjR67>|*0E_XJ*j`x=V(`SC*l&gStu zzPK2~D5d1PWg(^X>f`NgZ|v4C-p1pz8yLp@a+$+i4uE!huptj~IUeorN0rmJWa)Ie zFN7e`YOz%;@}yeDwr!-8*tQMe)ly21Op{uvL?@L(DMho{oUJ7jLZFnQlS)x5m7rLh z$oDTUgwV-{>xvD-=qsfF*wA!Er|avU@ws%xeiQ!ju=q4B`4US2`~mYn;WZXEQ{eyr N002ovPDHLkV1j4nBeDPh literal 0 HcmV?d00001 diff --git a/Resources/Textures/Objects/Devices/pda.rsi/pda-syn.png b/Resources/Textures/Objects/Devices/pda.rsi/pda-syn.png new file mode 100644 index 0000000000000000000000000000000000000000..cf21c285e77200f898270183fb1fefbcb42a29b6 GIT binary patch literal 435 zcmV;k0ZjghP)wx9ZZx1XbD(I zQGEONF9sbpb`%;LP^XmxUVHlzRP+1yZ`wJ4fq{YH-@kvPYN4(JGQ1@j7#J8BW^8@V z@I%}VMUI)7g@NhuZrVCv#@6R>Hpk0D81jEfG>_z5kl`%}4~0aoU2r;)YZrqb#|cu6 zqbvmGe{(~jA%L_nAS(nI7!bZjX45qUkbO-_2#}QvV2=1L<%A(m*IdB*Y#)X^skwln za)9n3@cZ{~hN+vLkZl>o4hT7fS@2*3Z>`LTHj|`m`1oN8 d3P!=80RZoHo~Xqfge3p~002ovPDHLkV1jQ6z5M_H literal 0 HcmV?d00001 diff --git a/Resources/Textures/Objects/Devices/pda.rsi/pda-tox.png b/Resources/Textures/Objects/Devices/pda.rsi/pda-tox.png new file mode 100644 index 0000000000000000000000000000000000000000..1425d9e5ae7fc88a72ddbe7281709d50964b053f GIT binary patch literal 463 zcmV;=0WkiFP)AP6?L2^KCU1}-T?TR0XL z9pPTWl{Q?R+MV_LDO!VHIDYT=KHmGj$M5}ku)qR;j3rS=grDD8YDfkj$tVV78T&H09 zsb=G4r(mjgVD23-41?pd$BC0oE#P2(4}ki*^YBEj%xAjUYzoJe8bei8X|-A?gv_sS z%bQlU{%f@ws;bI_lz#`p;V`c7gE>qM5FdQ@f(CUB7jUbO(K!tG@zppqQl)M zZ`wO;zqJj4*jgsN6K1mMAN^#KO9}WcWE?~jFR;MB!3QSZjvtM^aiRbK002ovPDHLk FV1hE@)QbQB literal 0 HcmV?d00001 diff --git a/Resources/Textures/Objects/Devices/pda.rsi/pda-transp.png b/Resources/Textures/Objects/Devices/pda.rsi/pda-transp.png new file mode 100644 index 0000000000000000000000000000000000000000..e140da7f0424359cef9766547892c1761e358226 GIT binary patch literal 534 zcmV+x0_pvUP)(Yz|-a;EbS&7br@=${=WgzS|W5l(GL)K3y^A`n2PV)@1IR;rbF0c0BB3z zQz~6CHV#dHIQRJ)D8z&ICv!SLsr16vrCF};&Z^FOI(zv(w+sRnb}pHp41)k#tm`@w zVdmrzp%oEYQN@H-By)18_OH1d2>2Wrl|xv-HUj|u=4$dQW8aoX0Jsp_?lYi2J*!n2 zGqA9JDPL?fhj(D$HJ1azWDim@Fk}83I%42MeZ5+hF$2aGgrYG*(HNvPQ{VU}Cp3ik zs~8O!SCBnONfs=O$k6~joxOmhz3F44qW>YUsT_F)_8F+L>?)mbN*dA2U(`^C=`v!LB4DxT(M$>@)xcqI{@ea zR+I9X59je8`O!~x7{)~-Di^xB{k^Do6jgcpCtbZ~2RGKNN?U6HEQMqWi@(5w2M->8 Y0$SXrcYKGE!2kdN07*qoM6N<$g2zqa^Z)<= literal 0 HcmV?d00001 diff --git a/Resources/Textures/Objects/Devices/pda.rsi/pda-v.png b/Resources/Textures/Objects/Devices/pda.rsi/pda-v.png new file mode 100644 index 0000000000000000000000000000000000000000..b5c169dde3b8487f355ab34a63a608ceffbbea57 GIT binary patch literal 472 zcmV;}0Vn>6P)NklTCyq#L{}lSV{?`-c&@mR0Q-BN)FU2D zV%s(gb2I%B08p#dbhrGjfVIdZ0DIXo&lB@4oZIce^>EQ&0eji9Gxt`m+W1$^eA->G z7MXNhi22T)G3GmG*_+c%*P8GU>IN`w&HzT5y{ z7=}~y_T>g41X4;enUt~s?LT2On)q>Dy}0V1P+7oNA>To@@DM}%8@vM-JDDZtW2@2t O0000r+1l|WsN;9<_eyw^J~_1??1S3Y2@_s7hP+n4+>5hGy&WU^wh$eU(?=c%i} zWdNQuKlyl5oi>*&Q7)H#qR+yRihzrRk^>TN_kl6%bbQjCm%DjE0yKLO?fV1I%wm9J z+ct3f`~(<=k$9L&xx2gFZYw3ea(IZ*Y=&;~NDcrjEldKiv2D^y-}A+WhesItyb~#3 zWC0u7rrRHFybi>FMa&oZ6f7-Fx-Jw%#cd0s!lTjMsOjQ4uxZWv+CPZqK~E0A=~sLE zeRaV5)o~o?=@dv2_S9S;-q%x*{Q4>ok9rDX-2;7hz_xAHUw-MiSZo0w#S0F`CfxD0 zlW$#l_bHv908P^zj*kJjdmRo^!i_y;6Vo&~y0ij7_UALVFW1&;wfGMbAKqKsvKs8& z$+Eut7=YR772bVFz_b&xI0&VSsFBIAwY*F&S%MpaJ(2Ddc9`uHm2ECrqO!I|Ba=}Q z5c<2+b=|Qn3n2vQdY$>z)qnD3ak(b!O{nxLmLdSMo&9hYj>g9Ul!_}0kRrU}zmxa! dBp+Y^fZw3|#x~H~QnUa7002ovPDHLkV1n&W9Pt1E literal 0 HcmV?d00001 diff --git a/Resources/Textures/Objects/Devices/pda.rsi/pda.png b/Resources/Textures/Objects/Devices/pda.rsi/pda.png new file mode 100644 index 0000000000000000000000000000000000000000..0f0abfbe1e1eb7dff368e26d477a7e8716b33c99 GIT binary patch literal 416 zcmV;R0bl-!P)C?A}GMj~1%QG`87#=-1M3m(MLIw;B4AcG-;|M0AOr#+o zDg-J+rsf&&_pp66M)hr3B`ThGhDMpg!00ssIhJXM5k*bBd4#@D9WME)mV3@J> zIl~WeI}|x)W)=pf$Gd6kfEin#!`U1!F>}RV63rty7i4%#!b2gEYZshOky2n_=pvCuCbju>-uEq={1Z{Ri=8l9UafKYPu<%BIQi{Ml!U=R>8U=ZNvfm`(Y)p-=Q06!0d zfRF*h(xuagb^yt3!szHMyy{?<6Wb;v+5zYe!3Bu5cod9+K?49wWR0GUf6T@J0000< KMNUMnLSTYh9!N$^q4pl8X8tJzKfGyu*&>B cBSX5+*)?n{wH?%(fo3vzy85}Sb4q9e0REOJJpcdz literal 0 HcmV?d00001 diff --git a/Resources/Textures/Objects/Devices/pda.rsi/pdabox.png b/Resources/Textures/Objects/Devices/pda.rsi/pdabox.png new file mode 100644 index 0000000000000000000000000000000000000000..4f5012c89655abedf6834b5c145fba97306ee123 GIT binary patch literal 403 zcmV;E0c`$>P)?SD*0a*#CA+hoE7ze^&9E^Sfzk;)qap(eJA<;lgTG4?;f@L8w zrEkQk27^5M2jkMS_1*XG@4U9jg@lBJgnwp3RxFnCvpCJWPtVf+09&%~bb2RJu;Yvg zdiGa=Vktj6JURftwrsN5J!zAE{}nx_<4s*Uokt4A0w1GMbOGPqwro^YVK{u3Hc?dt z+p^KLOyHYK1?C$!>KB0;U0$7|Y^$NdR|@zvn@wrmFpSW_p#%V0ZF6C*Qmz3Yg!o&5 zR@-F%So?k!g9+K|Tkhs0qOuwFptw1W73>rE6NtfNErFp0QmGV`a&6%sczOGb{rXo5 zxUPo~f@-z8bdO(iU2pvYdQPX_I73yHrF&X!6W8_7bNY{U#~H^L@X73I(z_$i6{w5ELSKf%1_J8NmVGR zEJ#&It;kGcV5qqDHav2Ysyfe~=OT7YlLVR`ceo1fYwUl&Gbsbzi&%CE&6LGx9fkav&hz z?{1$*f386xgX+#{p(cmtKf1f_+Qq1EHY=Y@O_$4aSZmiK6|e35H(mKeukH?N^ZMu+a>Ru zlcEewm0kbD;!|F4I2JxdWX@WHHWra5UW-CBr8f(TK4fc>nYLL(E}_2+9pvXs=F%c>XyuK|In9^!ji0X21UDn}n^s%YEH;t+Puhzoxsluh82~1rtB)T%l34iuL+! zE*+Q9>fK83wKglWJ8>tKTU@#^@sEd~kGtyc(*KwKKAmAuaP4fxI@g52DZG!P-ds%9 z?YPYKHGJVKhTV-AlVE5@DoOR>YZnSQ?73pC^lAV8 zrtN#TR;MWE{w=bq-|OE${lYuC|O8i@JwW#gaD* zMQzV%y|cByzPw*v&OvM{lkVlpq!%((t8DTrwKgn_4Lq7_@~66ymGw)xZIO9lVCCi} zH9d`gKjsv^eo)vyFU)?{)O}Cf|82fFzxUteUY!EYcQ4~Vb~Bm@xcn<)U|?*?baoE# zbasXnR}2gq6Kf}0dmIiBY5TuS%=H!X8-+&`7FtCLh!$Sa5?Sc9LNuz>VCPHjStcr) zdVNjV2M-=kx_a<7c#NT zZ`9uVbp4ganf{lub#<#)zT`5CU)S}$$*fo2a8TXZEH#`fi1Vk-hdQ_WQ&`#Z8sC}b z=bbH{W5=xNdUHSC3|Nb>C3(BM0BIoj z>AbrhNO2Z;L>4nJ=qZCRW5rT?V6+Knd%8G=L~t@H2;6@URy<0KhQMeDjE2BKh5#ce zmWM>g|0ksW_wU~f8&@qO+FTYw2BORV`}YrBh$2484#@D91Y0;`>vM)5;&v#OGc&U= zFg@OlB1VWqvI9UC!vM$2LogZP$DFh2LAs2OHv{vD+EA}f%zJlJtRYb$bK*&HMn8=M(NQI7!85Z5Eu=CK@|e4vwal~&617= OIm*-3&t;ucLK6U6_+|_M literal 0 HcmV?d00001