From 748ee9c598e5fd88ef581c9dab3f433f0a8b3327 Mon Sep 17 00:00:00 2001 From: TheRealMasterChief117 Date: Mon, 27 Jul 2026 10:33:19 -0400 Subject: [PATCH 01/28] Permit Console: Sprites --- .../Machines/computers.rsi/meta.json | 61 ++++++++++++++++++ .../Machines/computers.rsi/permits.png | Bin 0 -> 4107 bytes 2 files changed, 61 insertions(+) create mode 100644 Resources/Textures/_Triad/Structure/Machines/computers.rsi/meta.json create mode 100644 Resources/Textures/_Triad/Structure/Machines/computers.rsi/permits.png diff --git a/Resources/Textures/_Triad/Structure/Machines/computers.rsi/meta.json b/Resources/Textures/_Triad/Structure/Machines/computers.rsi/meta.json new file mode 100644 index 00000000000..ef5e45bb66d --- /dev/null +++ b/Resources/Textures/_Triad/Structure/Machines/computers.rsi/meta.json @@ -0,0 +1,61 @@ +{ + "version": 1, + "license": "CC-BY-SA-3.0", + "copyright": "Taken from tgstation at commit https://github.com/tgstation/tgstation/commit/bd6873fd4dd6a61d7e46f1d75cd4d90f64c40894.", + "size": { + "x": 32, + "y": 32 + }, + "states": [ + { + "name": "permits", + "directions": 4, + "delays": [ + [ + 1, + 0.1, + 0.1, + 1, + 0.1, + 0.1, + 1, + 0.1, + 0.1 + ], + [ + 1, + 0.1, + 0.1, + 1, + 0.1, + 0.1, + 1, + 0.1, + 0.1 + ], + [ + 1, + 0.1, + 0.1, + 1, + 0.1, + 0.1, + 1, + 0.1, + 0.1 + ], + [ + 1, + 0.1, + 0.1, + 1, + 0.1, + 0.1, + 1, + 0.1, + 0.1 + ] + ] + } + ] +} diff --git a/Resources/Textures/_Triad/Structure/Machines/computers.rsi/permits.png b/Resources/Textures/_Triad/Structure/Machines/computers.rsi/permits.png new file mode 100644 index 0000000000000000000000000000000000000000..66f18e1356227c4afac52a2fd4bce57fb4ee90ca GIT binary patch literal 4107 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 E2d#9-cK`qY literal 0 HcmV?d00001 From 1c750cf8d165f19c34bde436d160b8fd4efad188 Mon Sep 17 00:00:00 2001 From: TheRealMasterChief117 Date: Mon, 27 Jul 2026 10:54:54 -0400 Subject: [PATCH 02/28] Permit Console: Basic Prototype --- .../Structures/Machines/computers.yml | 31 +++++++++++++++++++ .../Machines/computers_tabletop.yml | 19 ++++++++++++ 2 files changed, 50 insertions(+) create mode 100644 Resources/Prototypes/_Triad/Entities/Structures/Machines/computers.yml create mode 100644 Resources/Prototypes/_Triad/Entities/Structures/Machines/computers_tabletop.yml diff --git a/Resources/Prototypes/_Triad/Entities/Structures/Machines/computers.yml b/Resources/Prototypes/_Triad/Entities/Structures/Machines/computers.yml new file mode 100644 index 00000000000..c9667923df9 --- /dev/null +++ b/Resources/Prototypes/_Triad/Entities/Structures/Machines/computers.yml @@ -0,0 +1,31 @@ +- type: entity + parent: [BaseStructureIndestructible, BaseComputerAiAccess, BaseStructureAccessReaderImmuneToEmag] + id: ComputerContrabandPermit + name: contraband permit manager + description: Used to manage, grant, and revoke TDF contraband permits to Triad sector citizens. + components: + - type: Sprite + netsync: false + sprite: Structures/Machines/computers.rsi + layers: + - map: ["computerLayerBody"] + state: computer + - map: ["computerLayerKeyboard"] + state: generic_keyboard + - map: ["computerLayerScreen"] + sprite: _Triad/Structure/Machines/computers.rsi + state: permits + - map: ["computerLayerKeys"] + state: security_key + #- type: ActivatableUI + # key: TODO + #- type: UserInterface + # interfaces: + # enum.TODO.ATM: + # type: StationAdminConsoleBoundUserInterface + #- type: ActivatableUIRequiresAccess + - type: ItemSlots + - type: ContainerContainer + containers: + board: !type:Container + atm: !type:ContainerSlot diff --git a/Resources/Prototypes/_Triad/Entities/Structures/Machines/computers_tabletop.yml b/Resources/Prototypes/_Triad/Entities/Structures/Machines/computers_tabletop.yml new file mode 100644 index 00000000000..470d88c4231 --- /dev/null +++ b/Resources/Prototypes/_Triad/Entities/Structures/Machines/computers_tabletop.yml @@ -0,0 +1,19 @@ +- type: entity + parent: [BaseStructureIndestructible, BaseStructureComputerTabletop, ComputerContrabandPermit] + id: ComputerTabletopContrabandPermit + components: + - type: Sprite + drawdepth: SmallObjects + layers: + - map: ["computerLayerBody"] + sprite: _NF/Structures/Machines/computer_tabletop.rsi + state: computer_tabletop + - map: ["computerLayerKeyboard"] + sprite: _NF/Structures/Machines/computer_tabletop.rsi + state: generic_keyboard_tabletop + - map: ["computerLayerScreen"] + sprite: _Triad/Structure/Machines/computers.rsi + state: permits + - map: ["computerLayerKeys"] + sprite: Structures/Machines/computers.rsi + state: security_key From 4d4cec84dc0cf46ced3df80f51a3da5596967380 Mon Sep 17 00:00:00 2001 From: TheRealMasterChief117 Date: Mon, 27 Jul 2026 18:10:14 -0400 Subject: [PATCH 03/28] UI mockup, FTL files, permit chip prototype and sprite --- ...ntrabandPermitConsoleBoundUserInterface.cs | 19 ++ .../ContrabandPermitConsoleWindow.xaml | 293 ++++++++++++++++++ .../ContrabandPermitConsoleWindow.xaml.cs | 109 +++++++ .../ContrabandPermitConsoleUi.cs | 11 + .../contraband-permit-console.ftl | 27 ++ .../Objects/Devices/Misc/permit_chip.yml | 28 ++ .../Structures/Machines/computers.yml | 27 +- .../Objects/Misc/permit_chip.rsi/icon.png | Bin 0 -> 611 bytes .../Misc/permit_chip.rsi/inhand-left.png | Bin 0 -> 460 bytes .../Misc/permit_chip.rsi/inhand-right.png | Bin 0 -> 456 bytes .../Objects/Misc/permit_chip.rsi/meta.json | 22 ++ 11 files changed, 528 insertions(+), 8 deletions(-) create mode 100644 Content.Client/_Triad/ContrabandPermit/ContrabandPermitConsoleBoundUserInterface.cs create mode 100644 Content.Client/_Triad/ContrabandPermit/ContrabandPermitConsoleWindow.xaml create mode 100644 Content.Client/_Triad/ContrabandPermit/ContrabandPermitConsoleWindow.xaml.cs create mode 100644 Content.Shared/_Triad/ContrabandPermit/ContrabandPermitConsoleUi.cs create mode 100644 Resources/Locale/en-US/_Triad/contraband-permit/contraband-permit-console.ftl create mode 100644 Resources/Prototypes/_Triad/Entities/Objects/Devices/Misc/permit_chip.yml create mode 100644 Resources/Textures/_Triad/Objects/Misc/permit_chip.rsi/icon.png create mode 100644 Resources/Textures/_Triad/Objects/Misc/permit_chip.rsi/inhand-left.png create mode 100644 Resources/Textures/_Triad/Objects/Misc/permit_chip.rsi/inhand-right.png create mode 100644 Resources/Textures/_Triad/Objects/Misc/permit_chip.rsi/meta.json diff --git a/Content.Client/_Triad/ContrabandPermit/ContrabandPermitConsoleBoundUserInterface.cs b/Content.Client/_Triad/ContrabandPermit/ContrabandPermitConsoleBoundUserInterface.cs new file mode 100644 index 00000000000..e091394325d --- /dev/null +++ b/Content.Client/_Triad/ContrabandPermit/ContrabandPermitConsoleBoundUserInterface.cs @@ -0,0 +1,19 @@ +using Content.Shared._Triad.ContrabandPermit; +using Robust.Client.UserInterface; + +namespace Content.Client._Triad.ContrabandPermit; + +public sealed class ContrabandPermitConsoleBoundUserInterface(EntityUid owner, Enum uiKey) : BoundUserInterface(owner, uiKey) +{ + [ViewVariables] + private ContrabandPermitConsoleWindow? _menu; + + protected override void Open() + { + base.Open(); + _menu = this.CreateWindow(); + _menu.SetOwner(Owner); + _menu.OpenCentered(); + _menu.UpdateUI(); + } +} diff --git a/Content.Client/_Triad/ContrabandPermit/ContrabandPermitConsoleWindow.xaml b/Content.Client/_Triad/ContrabandPermit/ContrabandPermitConsoleWindow.xaml new file mode 100644 index 00000000000..0c55c5b7396 --- /dev/null +++ b/Content.Client/_Triad/ContrabandPermit/ContrabandPermitConsoleWindow.xaml @@ -0,0 +1,293 @@ + + + + + + + + + + + + + + + + + + + + + + + diff --git a/Content.Client/_Triad/ContrabandPermit/ContrabandPermitConsoleWindow.xaml.cs b/Content.Client/_Triad/ContrabandPermit/ContrabandPermitConsoleWindow.xaml.cs new file mode 100644 index 00000000000..75acff47cfa --- /dev/null +++ b/Content.Client/_Triad/ContrabandPermit/ContrabandPermitConsoleWindow.xaml.cs @@ -0,0 +1,109 @@ +using Content.Client.Message; +using Content.Client.UserInterface.Controls; +using Content.Shared._Triad.ContrabandPermit; +using Robust.Client.AutoGenerated; +using Robust.Client.UserInterface; +using Robust.Client.UserInterface.Controls; +using Robust.Client.UserInterface.XAML; +using Robust.Shared.Timing; +using System.Diagnostics.CodeAnalysis; +using System.Linq; + +namespace Content.Client._Triad.ContrabandPermit; + +[GenerateTypedNameReferences] +public sealed partial class ContrabandPermitConsoleWindow : FancyWindow +{ + private EntityUid? _owner; + private ContrabandPermitConsoleTab _currentTab = ContrabandPermitConsoleTab.PermitList; + + public ContrabandPermitConsoleWindow() + { + RobustXamlLoader.Load(this); + IoCManager.InjectDependencies(this); // Frontier + + // Mode switching + PermitListTabButton.OnPressed += PermitListTabPressed; + GrantPermitTabButton.OnPressed += GrantPermitTabPressed; + + var tabGroup = new ButtonGroup(); + PermitListTabButton.Group = tabGroup; + GrantPermitTabButton.Group = tabGroup; + + PermitListTabButton.Pressed = true; + SetupTab(_currentTab); + } + + public void SetOwner(EntityUid owner) + { + _owner = owner; + PermitOwnerView.SetEntity(owner); + } + + private void PermitListTabPressed(BaseButton.ButtonEventArgs obj) + { + ChangeTab(ContrabandPermitConsoleTab.PermitList); + } + + private void GrantPermitTabPressed(BaseButton.ButtonEventArgs obj) + { + ChangeTab(ContrabandPermitConsoleTab.PermitGranter); + } + + private void SetupTab(ContrabandPermitConsoleTab tab) + { + // Clear the modes, then set it up + PermitListContainer.Visible = false; + PermitGranterContainer.Visible = false; + + switch (tab) + { + case ContrabandPermitConsoleTab.PermitList: + PermitListContainer.Visible = true; + break; + case ContrabandPermitConsoleTab.PermitGranter: + PermitGranterContainer.Visible = true; + break; + default: + throw new NotImplementedException(); + } + } + + public void ChangeTab(ContrabandPermitConsoleTab tab) + { + if (_currentTab == tab) + return; + + _currentTab = tab; + SetupTab(_currentTab); + } + + public enum ContrabandPermitConsoleTab : byte + { + PermitList, + PermitGranter, + } + + public void UpdateUI() + { + if (_owner == null) + return; + + var activePermitCount = 0; + + if (activePermitCount == 0) + { + var label = new RichTextLabel() + { + HorizontalExpand = true, + VerticalExpand = true, + HorizontalAlignment = HAlignment.Center, + VerticalAlignment = VAlignment.Center, + }; + + label.SetMarkup(Loc.GetString("contraband-permit-no-permits")); + + ActivePermitsTable.AddChild(label); + } + } +} diff --git a/Content.Shared/_Triad/ContrabandPermit/ContrabandPermitConsoleUi.cs b/Content.Shared/_Triad/ContrabandPermit/ContrabandPermitConsoleUi.cs new file mode 100644 index 00000000000..b4afccb9d36 --- /dev/null +++ b/Content.Shared/_Triad/ContrabandPermit/ContrabandPermitConsoleUi.cs @@ -0,0 +1,11 @@ +using Robust.Shared.Prototypes; +using Content.Shared.Roles; +using Robust.Shared.Serialization; + +namespace Content.Shared._Triad.ContrabandPermit; + +[Serializable, NetSerializable] +public enum ContrabandPermitConsoleUi : byte +{ + Key +} diff --git a/Resources/Locale/en-US/_Triad/contraband-permit/contraband-permit-console.ftl b/Resources/Locale/en-US/_Triad/contraband-permit/contraband-permit-console.ftl new file mode 100644 index 00000000000..2bc526dd1e3 --- /dev/null +++ b/Resources/Locale/en-US/_Triad/contraband-permit/contraband-permit-console.ftl @@ -0,0 +1,27 @@ +contraband-permit-console-window-title = TDF Contraband Permit Manager +contraband-permit-station-name = [color=white][font size=14]{$stationName}[/font][/color] +contraband-permit-unknown-location = Unknown location +contraband-permit-no-permits = [font size=16][color=white]No active permits detected[/font] + +contraband-permit-console-search-bar-placeholder = Input text and press "Enter" +contraband-permit-console-print-chip = Print Permit Chip + +contraband-permit-console-window-permit-grant-no-item = No item inserted into console +contraband-permit-console-window-permit-grant-no-access = Unauthorized access + +contraband-permit-console-window-permit-grant = Grant +contraband-permit-console-window-permit-eject = Eject + +contraband-permit-console-window-label-grant-tab-item-name = Item Name: {$name} +contraband-permit-console-window-label-grant-tab-date = Date Granted: {$date} +contraband-permit-console-window-label-grant-tab-reason = Reason: +contraband-permit-console-window-label-grant-tab-reason-placeholder = Reason Here + +contraband-permit-console-window-label-grant-tab-owner-name = Name: {$name} +contraband-permit-console-window-label-grant-tab-owner-species = Species: {$species} +contraband-permit-console-window-label-grant-tab-owner-age = Age: {$age} +contraband-permit-console-window-label-grant-tab-owner-gender = Gender: {$gender} +contraband-permit-console-window-label-grant-tab-owner-eye-color = Eye Color: {$color} + +contraband-permit-console-window-flavor-left = ⚠ Class 3 contraband permits are prohibited +contraband-permit-console-window-flavor-right = v1.9 ⛊[T.D.F.]⛊ diff --git a/Resources/Prototypes/_Triad/Entities/Objects/Devices/Misc/permit_chip.yml b/Resources/Prototypes/_Triad/Entities/Objects/Devices/Misc/permit_chip.yml new file mode 100644 index 00000000000..e371dc10bb8 --- /dev/null +++ b/Resources/Prototypes/_Triad/Entities/Objects/Devices/Misc/permit_chip.yml @@ -0,0 +1,28 @@ +- type: entity + parent: BaseItem + id: PermitChip + name: TDF permit chip + description: A small chip used to store the serial number of a controlled item. Hold against controlled item to scan its serial number. + components: + - type: Item + size: Small + storedRotation: -90 + - type: Sprite + sprite: _Triad/Objects/Misc/permit_chip.rsi + state: icon + - type: EmitSoundOnPickup + sound: + path: /Audio/_Goobstation/Items/handling/card_pickup.ogg + params: + volume: -5 + - type: EmitSoundOnDrop + sound: + path: /Audio/_Goobstation/Items/handling/card_drop.ogg + params: + volume: -5 + - type: EmitSoundOnLand + sound: + path: /Audio/_Goobstation/Items/handling/card_drop.ogg + params: + volume: -5 + - type: SavingContraband diff --git a/Resources/Prototypes/_Triad/Entities/Structures/Machines/computers.yml b/Resources/Prototypes/_Triad/Entities/Structures/Machines/computers.yml index c9667923df9..ee90576b748 100644 --- a/Resources/Prototypes/_Triad/Entities/Structures/Machines/computers.yml +++ b/Resources/Prototypes/_Triad/Entities/Structures/Machines/computers.yml @@ -17,15 +17,26 @@ state: permits - map: ["computerLayerKeys"] state: security_key - #- type: ActivatableUI - # key: TODO - #- type: UserInterface - # interfaces: - # enum.TODO.ATM: - # type: StationAdminConsoleBoundUserInterface - #- type: ActivatableUIRequiresAccess + - type: ActivatableUI + key: enum.ContrabandPermitConsoleUi.Key + singleUser: true + - type: UserInterface + interfaces: + enum.ContrabandPermitConsoleUi.Key: + type: ContrabandPermitConsoleBoundUserInterface + enum.WiresUiKey.Key: + type: WiresBoundUserInterface - type: ItemSlots + slots: + permit_slot: + name: Permit + ejectSound: /Audio/Machines/id_swipe.ogg + insertSound: /Audio/Weapons/Guns/MagIn/batrifle_magin.ogg + priority: 1 + whitelist: + tags: + #- Magazine9x19mmSubMachineGunFMJ todo components - type: ContainerContainer containers: board: !type:Container - atm: !type:ContainerSlot + permit_slot: !type:ContainerSlot diff --git a/Resources/Textures/_Triad/Objects/Misc/permit_chip.rsi/icon.png b/Resources/Textures/_Triad/Objects/Misc/permit_chip.rsi/icon.png new file mode 100644 index 0000000000000000000000000000000000000000..8915a3a97c60ea23b480c0f6d6853681a3894144 GIT binary patch literal 611 zcmeAS@N?(olHy`uVBq!ia0vp^3LwnE3?yBabR7dyjKx9jP7LeL$-D$|SkfJR9T^xl z_H+M9WCil00(?ST4Gj(V&rsMmLv!D3gT1pY_s_T6H{X5VV!yph!}lzU-?uV#X_M@} zIaW8Sl$vS_8`8xDd6^f_?S1p+&GO~T>(gcGGnMMIRT{Fj8gdO9@=WUUtm+FK>I&R| z#y>rq^czUYl?3?(|HlUy-bl#A0abDqctjR6Fz_7$VMb96uLhu?WQl7;NpOBzNqJ&X zDnmeGW?qS&pKFMMsh**pp^-47dkIj{j?@UxG*3@01`Z&Hl|hP;m4Ok+@&aOMC>sab`OUSUd;F27ymyj0`V;p$MbVZDn8pN={&BU;(N%Ffuk^ zTmUf_WGCwah*{HsY!F}qn#=@N8DwbzWI=Tq8W@0No9p#uiY{Ef4`kMRx;Tbd_`kgv zDb%dM(~wxOdX`gD>DsFQ*;aj*HJXkx|FAz~E-7ZnF7&*$nEytS!kQR`B~y&L9;uv- zs|JkvZqwHP>n999M?Mpgz!Aj=DgrJ-z)b2J#4!Q#w7wjm=EgCLNO z0^-be7O;2@kPQNhCo?d-04jpf=(aL203|1|Gq3>F8WQV0J5OE3=IrGvNxU@RGj^?xB$qk@N{tusfc@fYa{Ow10H6F{^eJVLehd) z)qGs*tI+n|OO)m5H7StG8D@lr{bAsdSrN!l3=9d%?)9@}_t(6Vd-!?VE@_XOuksY0zIe)*aE>`R#5X?n RPeKn!nWw9t%Q~loCIH6Ab2|V4 literal 0 HcmV?d00001 diff --git a/Resources/Textures/_Triad/Objects/Misc/permit_chip.rsi/inhand-right.png b/Resources/Textures/_Triad/Objects/Misc/permit_chip.rsi/inhand-right.png new file mode 100644 index 0000000000000000000000000000000000000000..63cf532d20a715bec9bf2106bab82c751545886e GIT binary patch literal 456 zcmeAS@N?(olHy`uVBq!ia0vp^4j|0I1|(Ny7TyC=jKx9jP7LeL$-D$|SkfJR9T^xl z_H+M9WCij$3p^r=85sBugD~Uq{1qucLCF%=h?3y^w370~qEv=}#LT=BJwMkF1yemk zJwwAT4zY7UMLSX>JkvZqwHP>n999M?Mpgz!Aj=DgrJ-z)b2J#4!Q#w7wjm=EgCLNO z0^-be7O;2@kPQNhCo?d-04jpf=(aL203|1|Gq3>F8WQV0J5OE3=IrGvNxU@RGj^?xB$p3@pN$vsfc@fYa{Pr10EKKzT;PIrlcpY zT2io<-RH@=kdGA`Rab-bG%SBN@A>W7uD{%zn3HVZuT~SQ^C&-Gd-Z1D{tGKBKMO3f z-T%r^|9E|#`9Pig0(;+hGxaAmAT^$@ KelF{r5}E+v#dF>O literal 0 HcmV?d00001 diff --git a/Resources/Textures/_Triad/Objects/Misc/permit_chip.rsi/meta.json b/Resources/Textures/_Triad/Objects/Misc/permit_chip.rsi/meta.json new file mode 100644 index 00000000000..768c9f88437 --- /dev/null +++ b/Resources/Textures/_Triad/Objects/Misc/permit_chip.rsi/meta.json @@ -0,0 +1,22 @@ +{ + "version": 1, + "license": "CC-BY-SA-3.0", + "copyright": "Taken from tgstation at commit https://github.com/tgstation/tgstation/commit/d917f4c2a088419d5c3aec7656b7ff8cebd1822e | Resprited for TDF by TheRealMasterChief117", + "size": { + "x": 32, + "y": 32 + }, + "states": [ + { + "name": "inhand-left", + "directions": 4 + }, + { + "name": "inhand-right", + "directions": 4 + }, + { + "name": "icon" + } + ] +} From f4af56eb0484d9d2e48afe205978ce6955f4d13e Mon Sep 17 00:00:00 2001 From: TheRealMasterChief117 Date: Mon, 27 Jul 2026 18:12:47 -0400 Subject: [PATCH 04/28] Fix no item screen text --- .../ContrabandPermit/ContrabandPermitConsoleWindow.xaml | 5 +++-- .../_Triad/contraband-permit/contraband-permit-console.ftl | 2 +- 2 files changed, 4 insertions(+), 3 deletions(-) diff --git a/Content.Client/_Triad/ContrabandPermit/ContrabandPermitConsoleWindow.xaml b/Content.Client/_Triad/ContrabandPermit/ContrabandPermitConsoleWindow.xaml index 0c55c5b7396..30ee9620e89 100644 --- a/Content.Client/_Triad/ContrabandPermit/ContrabandPermitConsoleWindow.xaml +++ b/Content.Client/_Triad/ContrabandPermit/ContrabandPermitConsoleWindow.xaml @@ -71,7 +71,7 @@ Orientation="Horizontal" Name="PermitGranterContainer"> - + + Margin="0 5 0 0" + Name="NoItemInsertedLabel"/> diff --git a/Resources/Locale/en-US/_Triad/contraband-permit/contraband-permit-console.ftl b/Resources/Locale/en-US/_Triad/contraband-permit/contraband-permit-console.ftl index 2bc526dd1e3..8baeca7652f 100644 --- a/Resources/Locale/en-US/_Triad/contraband-permit/contraband-permit-console.ftl +++ b/Resources/Locale/en-US/_Triad/contraband-permit/contraband-permit-console.ftl @@ -6,7 +6,7 @@ contraband-permit-no-permits = [font size=16][color=white]No active permits dete contraband-permit-console-search-bar-placeholder = Input text and press "Enter" contraband-permit-console-print-chip = Print Permit Chip -contraband-permit-console-window-permit-grant-no-item = No item inserted into console +contraband-permit-console-window-permit-grant-no-item = No permit chip inserted into console contraband-permit-console-window-permit-grant-no-access = Unauthorized access contraband-permit-console-window-permit-grant = Grant From c23fd1ca824d66123fe9cafcdbd36c78cec66526 Mon Sep 17 00:00:00 2001 From: TheRealMasterChief117 Date: Tue, 28 Jul 2026 17:09:57 -0400 Subject: [PATCH 05/28] Begin contraband entry XML, functionality for permit chips and data storage --- .../ContrabandPermitConsoleWindow.xaml | 9 - .../ContrabandPermitEntry.xaml | 71 ++++++++ .../ContrabandPermitEntry.xaml.cs | 34 ++++ .../Humanoid/ClientHumanoidViewerSystem.cs | 98 ++++++++++ .../ContrabandPermitChipComponent.cs | 42 +++++ .../ContrabandPermitConsoleComponent.cs | 47 +++++ .../ContrabandPermitItemComponent.cs | 28 +++ .../ContrabandPermitSystem.cs | 170 ++++++++++++++++++ .../ContrabandPermittableComponent.cs | 16 ++ .../SectorContrabandPermitsComponent.cs | 12 ++ .../Humanoid/ClientHumanoidViewerComponent.cs | 15 ++ .../_Triad/Humanoid/HumanoidViewComponent.cs | 10 ++ .../contraband-permit-chip.ftl | 14 ++ .../contraband-permit-console.ftl | 3 + .../Objects/Devices/Misc/permit_chip.yml | 6 +- .../Structures/Machines/computers.yml | 10 +- .../_Triad/SectorServices/services.yml | 5 + 17 files changed, 575 insertions(+), 15 deletions(-) create mode 100644 Content.Client/_Triad/ContrabandPermit/ContrabandPermitEntry.xaml create mode 100644 Content.Client/_Triad/ContrabandPermit/ContrabandPermitEntry.xaml.cs create mode 100644 Content.Server/_Triad/Humanoid/ClientHumanoidViewerSystem.cs create mode 100644 Content.Shared/_Triad/ContrabandPermit/ContrabandPermitChipComponent.cs create mode 100644 Content.Shared/_Triad/ContrabandPermit/ContrabandPermitConsoleComponent.cs create mode 100644 Content.Shared/_Triad/ContrabandPermit/ContrabandPermitItemComponent.cs create mode 100644 Content.Shared/_Triad/ContrabandPermit/ContrabandPermitSystem.cs create mode 100644 Content.Shared/_Triad/ContrabandPermit/ContrabandPermittableComponent.cs create mode 100644 Content.Shared/_Triad/ContrabandPermit/SectorContrabandPermitsComponent.cs create mode 100644 Content.Shared/_Triad/Humanoid/ClientHumanoidViewerComponent.cs create mode 100644 Content.Shared/_Triad/Humanoid/HumanoidViewComponent.cs create mode 100644 Resources/Locale/en-US/_Triad/contraband-permit/contraband-permit-chip.ftl create mode 100644 Resources/Prototypes/_Triad/SectorServices/services.yml diff --git a/Content.Client/_Triad/ContrabandPermit/ContrabandPermitConsoleWindow.xaml b/Content.Client/_Triad/ContrabandPermit/ContrabandPermitConsoleWindow.xaml index 30ee9620e89..f31a595e329 100644 --- a/Content.Client/_Triad/ContrabandPermit/ContrabandPermitConsoleWindow.xaml +++ b/Content.Client/_Triad/ContrabandPermit/ContrabandPermitConsoleWindow.xaml @@ -219,15 +219,6 @@ Scale="4 4"/> - - diff --git a/Content.Client/_Triad/ContrabandPermit/ContrabandPermitEntry.xaml b/Content.Client/_Triad/ContrabandPermit/ContrabandPermitEntry.xaml new file mode 100644 index 00000000000..bf0bc02ab85 --- /dev/null +++ b/Content.Client/_Triad/ContrabandPermit/ContrabandPermitEntry.xaml @@ -0,0 +1,71 @@ + + + + + + + + + + + + + + + + + + + + + + + + diff --git a/Content.Client/_Triad/ContrabandPermit/ContrabandPermitEntry.xaml.cs b/Content.Client/_Triad/ContrabandPermit/ContrabandPermitEntry.xaml.cs new file mode 100644 index 00000000000..8e49f1976b1 --- /dev/null +++ b/Content.Client/_Triad/ContrabandPermit/ContrabandPermitEntry.xaml.cs @@ -0,0 +1,34 @@ +using Robust.Client.AutoGenerated; +using Robust.Client.ResourceManagement; +using Robust.Client.UserInterface.Controls; +using Robust.Client.UserInterface.XAML; +using Robust.Shared.Configuration; + +namespace Content.Client._Triad.ContrabandPermit; + +[GenerateTypedNameReferences] +public sealed partial class ContrabandPermitEntry : BoxContainer +{ + public NetEntity PermitOwner; + + private readonly IConfigurationManager _config; + private readonly IEntityManager _entManager; + private readonly IResourceCache _cache; + + // Colors + private readonly Color _colorGray = Color.Gray; + private readonly Color _colorSlate = Color.LightSlateGray; + + public ContrabandPermitEntry(NetEntity uid) + { + RobustXamlLoader.Load(this); + + _config = IoCManager.Resolve(); + _entManager = IoCManager.Resolve(); + _cache = IoCManager.Resolve(); + + PermitOwner = uid; + + + } +} diff --git a/Content.Server/_Triad/Humanoid/ClientHumanoidViewerSystem.cs b/Content.Server/_Triad/Humanoid/ClientHumanoidViewerSystem.cs new file mode 100644 index 00000000000..007dba7b869 --- /dev/null +++ b/Content.Server/_Triad/Humanoid/ClientHumanoidViewerSystem.cs @@ -0,0 +1,98 @@ +using Content.Shared.GameTicking; +using Content.Server.Station.Systems; +using Content.Shared.Coordinates; +using Content.Shared._Mono.Pvs; +using Content.Shared._Triad.Humanoid; +using Content.Shared.Humanoid; + +namespace Content.Server._Triad.Humanoid; + +public sealed partial class ClientHumanoidViewerSystem : EntitySystem +{ + [Dependency] private SharedMapSystem _map = default!; + [Dependency] private SharedTransformSystem _transform = default!; + [Dependency] private StationSpawningSystem _spawning = default!; + + public EntityUid? PausedMap { get; private set; } + + private EntityQuery _humanoidQuery; + + public override void Initialize() + { + base.Initialize(); + + SubscribeLocalEvent(OnRoundRestart); + SubscribeLocalEvent(OnPlayerSpawnComplete); + + _humanoidQuery = GetEntityQuery(); + } + + private void OnRoundRestart(RoundRestartCleanupEvent _) + { + if (PausedMap == null || !Exists(PausedMap)) + return; + + Del(PausedMap.Value); + } + + private void OnPlayerSpawnComplete(PlayerSpawnCompleteEvent ev) + { + EnsurePausedMap(); + + if (PausedMap == null || !Exists(PausedMap)) + return; + + var mob = ev.Mob; + + EntityUid? viewerMob = null; + + var query = EntityQueryEnumerator(); + while (query.MoveNext(out var uid, out var otherViewer)) + { + // Cryoing and respawning shouldn't make duplicates + if (ev.Player != otherViewer.Session) + continue; + + if (Name(uid) == ev.Profile.Name) + { + viewerMob = uid; + break; + } + + if (_humanoidQuery.TryComp(uid, out var humanoid)) + { + if (humanoid.Age == ev.Profile.Age || humanoid.Gender == ev.Profile.Gender) + { + viewerMob = uid; + break; + } + } + } + + if (viewerMob == null) + { + viewerMob = _spawning.SpawnPlayerMob(mob.ToCoordinates(), null, ev.Profile, null, session: ev.Player); + _transform.SetParent(viewerMob.Value, PausedMap.Value); + + var viewer = EnsureComp(viewerMob.Value); + viewer.Session = ev.Player; + Dirty(viewerMob.Value, viewer); + + EnsureComp(viewerMob.Value); + } + + var humanoidView = EnsureComp(mob); + humanoidView.PvsView = viewerMob; + Dirty(mob, humanoidView); + } + + private void EnsurePausedMap() + { + if (PausedMap != null && Exists(PausedMap)) + return; + + var newmap = _map.CreateMap(); + _map.SetPaused(newmap, true); + PausedMap = newmap; + } +} diff --git a/Content.Shared/_Triad/ContrabandPermit/ContrabandPermitChipComponent.cs b/Content.Shared/_Triad/ContrabandPermit/ContrabandPermitChipComponent.cs new file mode 100644 index 00000000000..58355a38bd4 --- /dev/null +++ b/Content.Shared/_Triad/ContrabandPermit/ContrabandPermitChipComponent.cs @@ -0,0 +1,42 @@ +using Content.Shared.Damage; +using Content.Shared.DoAfter; +using Robust.Shared.Audio; +using Robust.Shared.GameStates; +using Robust.Shared.Serialization; + +namespace Content.Shared._Triad.ContrabandPermit; + +[RegisterComponent, NetworkedComponent, AutoGenerateComponentState] +public sealed partial class ContrabandPermitChipComponent : Component +{ + /// + /// The net ent of the scanned permit chip. + /// + [DataField, AutoNetworkedField] + public NetEntity? ScannedItem; + + /// + /// The net ent of the permit carrier/owner. + /// + [DataField, AutoNetworkedField] + public NetEntity? ScannedPermitCarrier; + + [DataField, AutoNetworkedField] + public TimeSpan ScanIdDelay = TimeSpan.FromSeconds(5); + + [DataField, AutoNetworkedField] + public SoundSpecifier? ScanSound = + new SoundPathSpecifier("/Audio/Machines/high_tech_confirm.ogg") + { + Params = AudioParams.Default.WithVolume(-2f) + }; + + [DataField, AutoNetworkedField] + public SoundSpecifier? ClearSound = new SoundPathSpecifier("/Audio/Machines/custom_deny.ogg"); + + [DataField, AutoNetworkedField] + public DamageSpecifier PrickDamage = new(); +} + +[Serializable, NetSerializable] +public sealed partial class ContrabandPermitChipScanIdentityDoAfterEvent : SimpleDoAfterEvent; diff --git a/Content.Shared/_Triad/ContrabandPermit/ContrabandPermitConsoleComponent.cs b/Content.Shared/_Triad/ContrabandPermit/ContrabandPermitConsoleComponent.cs new file mode 100644 index 00000000000..ad066f8bd73 --- /dev/null +++ b/Content.Shared/_Triad/ContrabandPermit/ContrabandPermitConsoleComponent.cs @@ -0,0 +1,47 @@ +using Content.Shared.Roles; +using Robust.Shared.GameStates; +using Robust.Shared.Prototypes; +using Robust.Shared.Serialization; + +namespace Content.Shared._Triad.ContrabandPermit; + +[RegisterComponent, NetworkedComponent, AutoGenerateComponentState] +public sealed partial class ContrabandPermitConsoleComponent : Component +{ + /// + /// Jobs not in this list will not be able to grant permits to people. + /// + [DataField, AutoNetworkedField] + public List>? GrantPermitRestrictedJobs; + + [DataField, AutoNetworkedField] + public string ChipSlotContainerId = "chip_slot"; + + /// + /// The current selected permit + /// + [ViewVariables, AutoNetworkedField] + public PermitFocusData? FocusPermit; +} + +[Serializable, NetSerializable] +public struct PermitFocusData( + NetEntity permitOwner, + EntProtoId itemEntProtoId, + NetEntity itemNetEntity) +{ + /// + /// permit owner + /// + public NetEntity PermitOwner = permitOwner; + + /// + /// Entity prototype of the permitted item + /// + public EntProtoId ItemEntProtoId = itemEntProtoId; + + /// + /// Net entity of the permitted item + /// + public NetEntity ItemNetEntity = itemNetEntity; +} diff --git a/Content.Shared/_Triad/ContrabandPermit/ContrabandPermitItemComponent.cs b/Content.Shared/_Triad/ContrabandPermit/ContrabandPermitItemComponent.cs new file mode 100644 index 00000000000..1fff4e77271 --- /dev/null +++ b/Content.Shared/_Triad/ContrabandPermit/ContrabandPermitItemComponent.cs @@ -0,0 +1,28 @@ +using Robust.Shared.GameStates; + +namespace Content.Shared._Triad.ContrabandPermit; + +[RegisterComponent, NetworkedComponent, AutoGenerateComponentState] +public sealed partial class ContrabandPermitItemComponent : Component +{ + /// + /// The name of the permit owner. + /// + [DataField, AutoNetworkedField] + public string PermitOwnerName = string.Empty; + + [DataField, AutoNetworkedField] + public string PermitReason = string.Empty; + + /// + /// The UID of the permit owner. + /// + [DataField, AutoNetworkedField] + public EntityUid? PermitOwner; + + /// + /// Flavor RP date of whenever the contraband permit was granted. + /// + [DataField, AutoNetworkedField] + public string DateGranted; +} diff --git a/Content.Shared/_Triad/ContrabandPermit/ContrabandPermitSystem.cs b/Content.Shared/_Triad/ContrabandPermit/ContrabandPermitSystem.cs new file mode 100644 index 00000000000..cccb9fbc29c --- /dev/null +++ b/Content.Shared/_Triad/ContrabandPermit/ContrabandPermitSystem.cs @@ -0,0 +1,170 @@ +using Content.Shared.Damage; +using Content.Shared.DoAfter; +using Content.Shared.Examine; +using Content.Shared.Forensics.Components; +using Content.Shared.IdentityManagement; +using Content.Shared.Interaction; +using Content.Shared.Popups; +using Content.Shared.Verbs; +using Robust.Shared.Audio.Systems; +using Robust.Shared.Utility; + +namespace Content.Shared._Triad.ContrabandPermit; + +public sealed partial class ContrabandPermitSystem : EntitySystem +{ + [Dependency] private SharedAudioSystem _audio = default!; + [Dependency] private DamageableSystem _damageable = default!; + [Dependency] private SharedDoAfterSystem _doAfter = default!; + [Dependency] private SharedPopupSystem _popup = default!; + + public override void Initialize() + { + base.Initialize(); + + SubscribeLocalEvent(OnPermitChipActivate); + SubscribeLocalEvent(OnPermitChipScanDoAfter); + SubscribeLocalEvent(OnPermitChipInteract); + SubscribeLocalEvent(OnPermitChipExamine); + SubscribeLocalEvent>(OnPermitChipGetVerbs); + } + + private void OnPermitChipActivate(Entity ent, ref ActivateInWorldEvent args) + { + if (args.Handled || !args.Complex) + return; + + // Need to scan the item first + if (ent.Comp.ScannedPermitCarrier != null || ent.Comp.ScannedItem == null) + return; + + var user = args.User; + + var ev = new ContrabandPermitChipScanIdentityDoAfterEvent(); + var doAfter = new DoAfterArgs(EntityManager, user, ent.Comp.ScanIdDelay, ev, ent.Owner, user) + { + BreakOnMove = true, + CancelDuplicate = true, + DuplicateCondition = DuplicateConditions.SameEvent, + NeedHand = true, + BreakOnHandChange = true, + }; + + if (_doAfter.TryStartDoAfter(doAfter)) + { + _popup.PopupClient(Loc.GetString("contraband-permit-chip-scan-id-start"), user, user); + args.Handled = true; + } + } + + private void OnPermitChipScanDoAfter(Entity ent, ref ContrabandPermitChipScanIdentityDoAfterEvent args) + { + if (args.Handled || args.Cancelled) + return; + + var user = args.User; + + if (HasComp(user)) + { + _damageable.TryChangeDamage(ent.Owner, ent.Comp.PrickDamage, true, false); + _popup.PopupClient(Loc.GetString("contraband-permit-chip-scan-id-dna-end"), user, user); + } + else + { + _popup.PopupClient(Loc.GetString("contraband-permit-chip-scan-id-no-dna-end"), user, user); + } + + ent.Comp.ScannedPermitCarrier = GetNetEntity(user); + Dirty(ent); + + _audio.PlayPredicted(ent.Comp.ScanSound, ent.Owner, user); + args.Handled = true; + } + + private void OnPermitChipInteract(Entity ent, ref AfterInteractEvent args) + { + if (args.Handled) + return; + + if (!args.CanReach || args.Target is not { Valid: true } target) + return; + + if (TryScan(ent, target, args.User)) + args.Handled = true; + } + + private bool TryScan(Entity ent, EntityUid target, EntityUid actor) + { + if (HasComp(target)) + { + _popup.PopupClient(Loc.GetString("contraband-permit-chip-failure"), actor, actor, PopupType.SmallCaution); + return false; + } + + if (!TryComp(target, out var permittable) || !permittable.Permittable) + return false; + + ent.Comp.ScannedItem = GetNetEntity(target); + Dirty(ent); + + _audio.PlayPredicted(ent.Comp.ScanSound, target, actor); + _popup.PopupClient(Loc.GetString("contraband-permit-chip-success", ("item", Identity.Entity(target, EntityManager))), actor, actor, PopupType.Medium); + return true; + } + + private void OnPermitChipExamine(Entity ent, ref ExaminedEvent args) + { + if (ent.Comp.ScannedItem is { } item) + { + var fromNetEnt = GetEntity(item); + args.PushMarkup(Loc.GetString("contraband-permit-chip-examine-signature", ("item", Identity.Entity(fromNetEnt, EntityManager)))); + } + else + { + args.PushMarkup(Loc.GetString("contraband-permit-chip-examine-help")); + } + + if (ent.Comp.ScannedPermitCarrier is { } carrier) + { + var fromNetEnt = GetEntity(carrier); + args.PushMarkup(Loc.GetString("contraband-permit-chip-examine-owner", ("owner", Identity.Entity(fromNetEnt, EntityManager))), -1); + } + else if (ent.Comp.ScannedItem != null) + { + args.PushMarkup(Loc.GetString("contraband-permit-chip-examine-help-id")); + } + } + + private void OnPermitChipGetVerbs(Entity ent, ref GetVerbsEvent args) + { + if (!args.CanAccess || !args.CanInteract) + return; + + var user = args.User; + + if (ent.Comp.ScannedItem != null || ent.Comp.ScannedPermitCarrier != null) + { + Verb verb = new() + { + Act = () => ClearScannedItem(ent, user), + Text = Loc.GetString("contraband-permit-chip-clear-verb"), + Icon = new SpriteSpecifier.Texture(new("/Textures/Interface/VerbIcons/delete.svg.192dpi.png")), + Priority = -3, + DoContactInteraction = true + }; + args.Verbs.Add(verb); + } + } + + private void ClearScannedItem(Entity ent, EntityUid user) + { + ent.Comp.ScannedItem = null; + Dirty(ent); + + ent.Comp.ScannedPermitCarrier = null; + Dirty(ent); + + _audio.PlayPredicted(ent.Comp.ClearSound, ent.Owner, user); + _popup.PopupClient(Loc.GetString("contraband-permit-chip-cleared"), user, user); + } +} diff --git a/Content.Shared/_Triad/ContrabandPermit/ContrabandPermittableComponent.cs b/Content.Shared/_Triad/ContrabandPermit/ContrabandPermittableComponent.cs new file mode 100644 index 00000000000..310c0ce7fe5 --- /dev/null +++ b/Content.Shared/_Triad/ContrabandPermit/ContrabandPermittableComponent.cs @@ -0,0 +1,16 @@ +using Robust.Shared.GameStates; + +namespace Content.Shared._Triad.ContrabandPermit; + +/// +/// Items with this component can be permitted for use, which allows them to be saved on ships. +/// +[RegisterComponent, NetworkedComponent, AutoGenerateComponentState] +public sealed partial class ContrabandPermittableComponent : Component +{ + /// + /// This purely exists for parenting + /// + [DataField, AutoNetworkedField] + public bool Permittable = true; +} diff --git a/Content.Shared/_Triad/ContrabandPermit/SectorContrabandPermitsComponent.cs b/Content.Shared/_Triad/ContrabandPermit/SectorContrabandPermitsComponent.cs new file mode 100644 index 00000000000..8f8451af870 --- /dev/null +++ b/Content.Shared/_Triad/ContrabandPermit/SectorContrabandPermitsComponent.cs @@ -0,0 +1,12 @@ +namespace Content.Shared._Triad.ContrabandPermit; + +[RegisterComponent] +public sealed partial class SectorContrabandPermitsComponent : Component +{ + /// + /// Stores all permit entries. + /// Key is the permit owner, the list is the permitted items. + /// + [DataField] + public Dictionary> Records = new(); +} diff --git a/Content.Shared/_Triad/Humanoid/ClientHumanoidViewerComponent.cs b/Content.Shared/_Triad/Humanoid/ClientHumanoidViewerComponent.cs new file mode 100644 index 00000000000..d17a5b43ff3 --- /dev/null +++ b/Content.Shared/_Triad/Humanoid/ClientHumanoidViewerComponent.cs @@ -0,0 +1,15 @@ +using Robust.Shared.GameStates; +using Robust.Shared.Player; + +namespace Content.Shared._Triad.Humanoid; + +/// +/// Used so clients can see humanoid appearance data from players across the map, such as for photographs. +/// Probably a hacky way of doing this. +/// Client humanoids are stored in a paused map. +/// +[RegisterComponent, NetworkedComponent] +public sealed partial class ClientHumanoidViewerComponent : Component +{ + public ICommonSession? Session; +} diff --git a/Content.Shared/_Triad/Humanoid/HumanoidViewComponent.cs b/Content.Shared/_Triad/Humanoid/HumanoidViewComponent.cs new file mode 100644 index 00000000000..1e43ca32674 --- /dev/null +++ b/Content.Shared/_Triad/Humanoid/HumanoidViewComponent.cs @@ -0,0 +1,10 @@ +using Robust.Shared.GameStates; + +namespace Content.Shared._Triad.Humanoid; + +[RegisterComponent, NetworkedComponent, AutoGenerateComponentState] +public sealed partial class HumanoidViewComponent : Component +{ + [DataField, AutoNetworkedField] + public EntityUid? PvsView; +} diff --git a/Resources/Locale/en-US/_Triad/contraband-permit/contraband-permit-chip.ftl b/Resources/Locale/en-US/_Triad/contraband-permit/contraband-permit-chip.ftl new file mode 100644 index 00000000000..4c903a8c905 --- /dev/null +++ b/Resources/Locale/en-US/_Triad/contraband-permit/contraband-permit-chip.ftl @@ -0,0 +1,14 @@ +contraband-permit-chip-failure = Could not scan item. Item already has a valid contraband permit. +contraband-permit-chip-success = Successfully scanned {$item}! + +contraband-permit-chip-examine-help = [bold][color=green]Tap the chip onto contraband to scan it.[/color][/bold] +contraband-permit-chip-examine-help-id = [bold][color=green]Now, interact with the item to scan your identity.[/color][/bold] +contraband-permit-chip-examine-signature = Scanned item: {$item} +contraband-permit-chip-examine-owner = Scanned owner: {$owner} + +contraband-permit-chip-clear-verb = Clear data +contraband-permit-chip-cleared = Cleared data + +contraband-permit-chip-scan-id-start = You put your finger on the chip... +contraband-permit-chip-scan-id-dna-end = A small needle pricked your finger! Ow! +contraband-permit-chip-scan-id-no-dna-end = A small blue glow shined over your finger as the chip scanned you. diff --git a/Resources/Locale/en-US/_Triad/contraband-permit/contraband-permit-console.ftl b/Resources/Locale/en-US/_Triad/contraband-permit/contraband-permit-console.ftl index 8baeca7652f..e0e3b534918 100644 --- a/Resources/Locale/en-US/_Triad/contraband-permit/contraband-permit-console.ftl +++ b/Resources/Locale/en-US/_Triad/contraband-permit/contraband-permit-console.ftl @@ -6,6 +6,9 @@ contraband-permit-no-permits = [font size=16][color=white]No active permits dete contraband-permit-console-search-bar-placeholder = Input text and press "Enter" contraband-permit-console-print-chip = Print Permit Chip +contraband-permit-console-window-permit-owner-entries-placeholder = Permits on file: N/A +contraband-permit-console-window-permit-owner-entries = Permit(s) on file: {$number} + contraband-permit-console-window-permit-grant-no-item = No permit chip inserted into console contraband-permit-console-window-permit-grant-no-access = Unauthorized access diff --git a/Resources/Prototypes/_Triad/Entities/Objects/Devices/Misc/permit_chip.yml b/Resources/Prototypes/_Triad/Entities/Objects/Devices/Misc/permit_chip.yml index e371dc10bb8..8e6be9c0d12 100644 --- a/Resources/Prototypes/_Triad/Entities/Objects/Devices/Misc/permit_chip.yml +++ b/Resources/Prototypes/_Triad/Entities/Objects/Devices/Misc/permit_chip.yml @@ -2,7 +2,7 @@ parent: BaseItem id: PermitChip name: TDF permit chip - description: A small chip used to store the serial number of a controlled item. Hold against controlled item to scan its serial number. + description: A small chip used to store the serial number of a controlled item, along with the permit carrier's DNA signature for use in a permit manager console. components: - type: Item size: Small @@ -26,3 +26,7 @@ params: volume: -5 - type: SavingContraband + - type: ContrabandPermitChip + prickDamage: + types: + Piercing: 1 diff --git a/Resources/Prototypes/_Triad/Entities/Structures/Machines/computers.yml b/Resources/Prototypes/_Triad/Entities/Structures/Machines/computers.yml index ee90576b748..cc4cfa23b45 100644 --- a/Resources/Prototypes/_Triad/Entities/Structures/Machines/computers.yml +++ b/Resources/Prototypes/_Triad/Entities/Structures/Machines/computers.yml @@ -28,15 +28,15 @@ type: WiresBoundUserInterface - type: ItemSlots slots: - permit_slot: - name: Permit + chip_slot: + name: Chip ejectSound: /Audio/Machines/id_swipe.ogg insertSound: /Audio/Weapons/Guns/MagIn/batrifle_magin.ogg priority: 1 whitelist: - tags: - #- Magazine9x19mmSubMachineGunFMJ todo components + components: + - ContrabandPermitChip - type: ContainerContainer containers: board: !type:Container - permit_slot: !type:ContainerSlot + chip_slot: !type:ContainerSlot diff --git a/Resources/Prototypes/_Triad/SectorServices/services.yml b/Resources/Prototypes/_Triad/SectorServices/services.yml new file mode 100644 index 00000000000..4e838fc9fa6 --- /dev/null +++ b/Resources/Prototypes/_Triad/SectorServices/services.yml @@ -0,0 +1,5 @@ +# Stores contraband permit data +- type: sectorService + id: ContrabandPermits + components: + - type: SectorContrabandPermits From a00e17e5d14fcdc1ff2d6a833116fba4a76363c8 Mon Sep 17 00:00:00 2001 From: TheRealMasterChief117 Date: Wed, 29 Jul 2026 12:01:43 -0400 Subject: [PATCH 06/28] yo --- .../ContrabandPermit/ContrabandPermitItemComponent.cs | 2 +- ...tSystem.cs => ContrabandPermitSystem.PermitChip.cs} | 10 +++++++--- .../_Triad/Entities/Structures/Machines/computers.yml | 3 +++ 3 files changed, 11 insertions(+), 4 deletions(-) rename Content.Shared/_Triad/ContrabandPermit/{ContrabandPermitSystem.cs => ContrabandPermitSystem.PermitChip.cs} (95%) diff --git a/Content.Shared/_Triad/ContrabandPermit/ContrabandPermitItemComponent.cs b/Content.Shared/_Triad/ContrabandPermit/ContrabandPermitItemComponent.cs index 1fff4e77271..8eae25a55bf 100644 --- a/Content.Shared/_Triad/ContrabandPermit/ContrabandPermitItemComponent.cs +++ b/Content.Shared/_Triad/ContrabandPermit/ContrabandPermitItemComponent.cs @@ -24,5 +24,5 @@ public sealed partial class ContrabandPermitItemComponent : Component /// Flavor RP date of whenever the contraband permit was granted. /// [DataField, AutoNetworkedField] - public string DateGranted; + public string DateGranted = string.Empty; } diff --git a/Content.Shared/_Triad/ContrabandPermit/ContrabandPermitSystem.cs b/Content.Shared/_Triad/ContrabandPermit/ContrabandPermitSystem.PermitChip.cs similarity index 95% rename from Content.Shared/_Triad/ContrabandPermit/ContrabandPermitSystem.cs rename to Content.Shared/_Triad/ContrabandPermit/ContrabandPermitSystem.PermitChip.cs index cccb9fbc29c..284f575deda 100644 --- a/Content.Shared/_Triad/ContrabandPermit/ContrabandPermitSystem.cs +++ b/Content.Shared/_Triad/ContrabandPermit/ContrabandPermitSystem.PermitChip.cs @@ -2,6 +2,7 @@ using Content.Shared.DoAfter; using Content.Shared.Examine; using Content.Shared.Forensics.Components; +using Content.Shared.Humanoid; using Content.Shared.IdentityManagement; using Content.Shared.Interaction; using Content.Shared.Popups; @@ -40,6 +41,10 @@ private void OnPermitChipActivate(Entity ent, ref var user = args.User; + // Only mobs that are humanoid! + if (!HasComp(user)) + return; + var ev = new ContrabandPermitChipScanIdentityDoAfterEvent(); var doAfter = new DoAfterArgs(EntityManager, user, ent.Comp.ScanIdDelay, ev, ent.Owner, user) { @@ -64,9 +69,10 @@ private void OnPermitChipScanDoAfter(Entity ent, var user = args.User; + // Your finger gets pricked if you're not a robot if (HasComp(user)) { - _damageable.TryChangeDamage(ent.Owner, ent.Comp.PrickDamage, true, false); + _damageable.TryChangeDamage(user, ent.Comp.PrickDamage, true, false); _popup.PopupClient(Loc.GetString("contraband-permit-chip-scan-id-dna-end"), user, user); } else @@ -159,8 +165,6 @@ private void OnPermitChipGetVerbs(Entity ent, ref private void ClearScannedItem(Entity ent, EntityUid user) { ent.Comp.ScannedItem = null; - Dirty(ent); - ent.Comp.ScannedPermitCarrier = null; Dirty(ent); diff --git a/Resources/Prototypes/_Triad/Entities/Structures/Machines/computers.yml b/Resources/Prototypes/_Triad/Entities/Structures/Machines/computers.yml index cc4cfa23b45..d8460a4595e 100644 --- a/Resources/Prototypes/_Triad/Entities/Structures/Machines/computers.yml +++ b/Resources/Prototypes/_Triad/Entities/Structures/Machines/computers.yml @@ -36,6 +36,9 @@ whitelist: components: - ContrabandPermitChip + - type: ContrabandPermitConsole + grantPermitRestrictedJobs: + - TdfChiefEnforcer - type: ContainerContainer containers: board: !type:Container From 44f7a7cbef25f90fc0c51fd0193a7541f0207e4c Mon Sep 17 00:00:00 2001 From: TheRealMasterChief117 Date: Wed, 29 Jul 2026 12:42:28 -0400 Subject: [PATCH 07/28] Update ContrabandPermitSystem.PermitChip.cs --- .../ContrabandPermit/ContrabandPermitSystem.PermitChip.cs | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/Content.Shared/_Triad/ContrabandPermit/ContrabandPermitSystem.PermitChip.cs b/Content.Shared/_Triad/ContrabandPermit/ContrabandPermitSystem.PermitChip.cs index 284f575deda..d016168c3dc 100644 --- a/Content.Shared/_Triad/ContrabandPermit/ContrabandPermitSystem.PermitChip.cs +++ b/Content.Shared/_Triad/ContrabandPermit/ContrabandPermitSystem.PermitChip.cs @@ -137,7 +137,7 @@ private void OnPermitChipExamine(Entity ent, ref } else if (ent.Comp.ScannedItem != null) { - args.PushMarkup(Loc.GetString("contraband-permit-chip-examine-help-id")); + args.PushMarkup(Loc.GetString("contraband-permit-chip-examine-help-id"), -1); } } From 967254373d1ef754d20f4f2fb85e64c347bb379a Mon Sep 17 00:00:00 2001 From: TheRealMasterChief117 Date: Thu, 30 Jul 2026 21:24:16 -0400 Subject: [PATCH 08/28] Fix viewer entity code, permit granting with the UI, CE grant whitelist --- ...ntrabandPermitConsoleBoundUserInterface.cs | 48 ++++- .../ContrabandPermitConsoleWindow.xaml | 24 ++- .../ContrabandPermitConsoleWindow.xaml.cs | 142 ++++++++++++- .../ContrabandPermitSystem.cs | 5 + .../ContrabandPermitSystem.cs | 94 ++++++++ .../Humanoid/ClientHumanoidViewerSystem.cs | 56 ++--- Content.Shared/_DV/CCVars/DCCVars.cs | 2 +- .../ContrabandPermitConsoleComponent.cs | 49 ++++- .../ContrabandPermitConsoleUi.cs | 21 +- .../ContrabandPermitGranterComponent.cs | 9 + .../ContrabandPermitItemComponent.cs | 6 + .../SharedContrabandPermitSystem.Console.cs | 200 ++++++++++++++++++ ...haredContrabandPermitSystem.PermitChip.cs} | 6 +- .../SharedContrabandPermitSystem.cs | 12 ++ ...nt.cs => HumanoidViewerEntityComponent.cs} | 5 +- .../contraband-permit-console.ftl | 13 ++ .../Entities/Mobs/Player/admin_ghost.yml | 1 + .../_Triad/Entities/Mobs/humanoid_view.yml | 53 +++++ .../Objects/Devices/Misc/permit_chip.yml | 3 +- .../Structures/Machines/computers.yml | 13 +- .../_Triad/Roles/Jobs/Tdf/chief_enforcer.yml | 1 + .../Prototypes/_Triad/base_contraband.yml | 15 ++ 22 files changed, 718 insertions(+), 60 deletions(-) create mode 100644 Content.Client/_Triad/ContrabandPermit/ContrabandPermitSystem.cs create mode 100644 Content.Server/_Triad/ContrabandPermit/ContrabandPermitSystem.cs create mode 100644 Content.Shared/_Triad/ContrabandPermit/ContrabandPermitGranterComponent.cs create mode 100644 Content.Shared/_Triad/ContrabandPermit/SharedContrabandPermitSystem.Console.cs rename Content.Shared/_Triad/ContrabandPermit/{ContrabandPermitSystem.PermitChip.cs => SharedContrabandPermitSystem.PermitChip.cs} (97%) create mode 100644 Content.Shared/_Triad/ContrabandPermit/SharedContrabandPermitSystem.cs rename Content.Shared/_Triad/Humanoid/{ClientHumanoidViewerComponent.cs => HumanoidViewerEntityComponent.cs} (73%) create mode 100644 Resources/Prototypes/_Triad/Entities/Mobs/humanoid_view.yml diff --git a/Content.Client/_Triad/ContrabandPermit/ContrabandPermitConsoleBoundUserInterface.cs b/Content.Client/_Triad/ContrabandPermit/ContrabandPermitConsoleBoundUserInterface.cs index e091394325d..cbc800b4f48 100644 --- a/Content.Client/_Triad/ContrabandPermit/ContrabandPermitConsoleBoundUserInterface.cs +++ b/Content.Client/_Triad/ContrabandPermit/ContrabandPermitConsoleBoundUserInterface.cs @@ -1,19 +1,61 @@ using Content.Shared._Triad.ContrabandPermit; -using Robust.Client.UserInterface; +using Content.Shared.Containers.ItemSlots; +using Robust.Client.Player; namespace Content.Client._Triad.ContrabandPermit; -public sealed class ContrabandPermitConsoleBoundUserInterface(EntityUid owner, Enum uiKey) : BoundUserInterface(owner, uiKey) +public sealed partial class ContrabandPermitConsoleBoundUserInterface(EntityUid owner, Enum uiKey) : BoundUserInterface(owner, uiKey) { + [Dependency] private IPlayerManager _playerManager = default!; + [ViewVariables] private ContrabandPermitConsoleWindow? _menu; protected override void Open() { base.Open(); - _menu = this.CreateWindow(); + + _menu = new(_playerManager); _menu.SetOwner(Owner); _menu.OpenCentered(); _menu.UpdateUI(); + + if (!EntMan.TryGetComponent(Owner, out var consoleComp)) + return; + + _menu.EjectButton.OnPressed += _ => SendPredictedMessage(new ItemSlotButtonPressedEvent(consoleComp.ChipSlotContainerId)); + + _menu.OnReasonChanged += OnJobChanged; + _menu.OnGrantButtonPressed += OnGrantButtonPressed; + _menu.OnPrintButtonPressed += OnPrintButtonPressed; + } + + protected override void UpdateState(BoundUserInterfaceState state) + { + base.UpdateState(state); + var castState = (ContrabandPermitConsoleBuiState) state; + _menu?.UpdateState(castState); + } + + private void OnJobChanged(string reason) + { + SendPredictedMessage(new ContrabandPermitConsoleReasonUpdatedMessage(reason)); + } + + private void OnGrantButtonPressed() + { + SendPredictedMessage(new ContrabandPermitConsoleGrantButtonPressedMessage()); + } + + private void OnPrintButtonPressed() + { + SendPredictedMessage(new ContrabandPermitConsolePrintButtonPressedMessage()); + } + + protected override void Dispose(bool disposing) + { + base.Dispose(disposing); + + _menu?.Close(); } } diff --git a/Content.Client/_Triad/ContrabandPermit/ContrabandPermitConsoleWindow.xaml b/Content.Client/_Triad/ContrabandPermit/ContrabandPermitConsoleWindow.xaml index f31a595e329..0c38305562c 100644 --- a/Content.Client/_Triad/ContrabandPermit/ContrabandPermitConsoleWindow.xaml +++ b/Content.Client/_Triad/ContrabandPermit/ContrabandPermitConsoleWindow.xaml @@ -76,7 +76,7 @@ VerticalExpand="True" HorizontalExpand="True" Orientation="Vertical" - Visible="False" + Visible="True" ReservesSpace="False"> + Margin="20 15 20 20" + Name="PermitGranterLeft" + Visible="False"> @@ -122,7 +124,7 @@