From 8045373197e825fab784773564d863e0bb3ed437 Mon Sep 17 00:00:00 2001 From: ArchRBX <5040911+ArchRBX@users.noreply.github.com> Date: Thu, 24 Apr 2025 00:55:35 +0100 Subject: [PATCH] pAI Software Catalog (#36857) * initial commit * add the shop and make it work * add existing pai actions to the software shop * added power monitor app * killed the power and crew monitor software, too powercreepy * fix test failures * fix more test failures * fix merge conflicts * code changes to conform with review * fix unintentional submodule update * submodule update * remove unused currency prototype ref --------- Co-authored-by: archrbx --- Content.Server/PAI/PAISystem.cs | 20 ++++++- Content.Shared/PAI/PAIComponent.cs | 12 ++-- Content.Shared/PAI/SharedPAISystem.cs | 59 +++++++++---------- Resources/Locale/en-US/store/currency.ftl | 1 + Resources/Locale/en-US/store/pai-catalog.ftl | 8 +++ Resources/Prototypes/Catalog/pai_catalog.yml | 43 ++++++++++++++ .../Prototypes/Entities/Objects/Fun/pai.yml | 43 ++++++++++++++ Resources/Prototypes/Store/categories.yml | 5 ++ Resources/Prototypes/Store/currency.yml | 5 ++ 9 files changed, 155 insertions(+), 41 deletions(-) create mode 100644 Resources/Locale/en-US/store/pai-catalog.ftl create mode 100644 Resources/Prototypes/Catalog/pai_catalog.yml diff --git a/Content.Server/PAI/PAISystem.cs b/Content.Server/PAI/PAISystem.cs index fd581f40e4..289b74b258 100644 --- a/Content.Server/PAI/PAISystem.cs +++ b/Content.Server/PAI/PAISystem.cs @@ -2,14 +2,17 @@ using Content.Server.Ghost.Roles; using Content.Server.Ghost.Roles.Components; using Content.Server.Instruments; using Content.Server.Kitchen.Components; +using Content.Server.Store.Systems; using Content.Shared.Interaction.Events; using Content.Shared.Mind.Components; using Content.Shared.PAI; using Content.Shared.Popups; +using Content.Shared.Store; +using Content.Shared.Store.Components; +using Content.Shared.Instruments; using Robust.Shared.Random; +using Robust.Shared.Prototypes; using System.Text; -using Content.Shared.Instruments; -using Robust.Shared.Player; namespace Content.Server.PAI; @@ -19,12 +22,13 @@ public sealed class PAISystem : SharedPAISystem [Dependency] private readonly IRobustRandom _random = default!; [Dependency] private readonly MetaDataSystem _metaData = default!; [Dependency] private readonly SharedPopupSystem _popup = default!; + [Dependency] private readonly StoreSystem _store = default!; [Dependency] private readonly ToggleableGhostRoleSystem _toggleableGhostRole = default!; /// /// Possible symbols that can be part of a scrambled pai's name. /// - private static readonly char[] SYMBOLS = new[] { '#', '~', '-', '@', '&', '^', '%', '$', '*', ' '}; + private static readonly char[] SYMBOLS = new[] { '#', '~', '-', '@', '&', '^', '%', '$', '*', ' ' }; public override void Initialize() { @@ -34,6 +38,8 @@ public sealed class PAISystem : SharedPAISystem SubscribeLocalEvent(OnMindAdded); SubscribeLocalEvent(OnMindRemoved); SubscribeLocalEvent(OnMicrowaved); + + SubscribeLocalEvent(OnShop); } private void OnUseInHand(EntityUid uid, PAIComponent component, UseInHandEvent args) @@ -101,6 +107,14 @@ public sealed class PAISystem : SharedPAISystem _metaData.SetEntityName(uid, val); } + private void OnShop(Entity ent, ref PAIShopActionEvent args) + { + if (!TryComp(ent, out var store)) + return; + + _store.ToggleUi(args.Performer, ent, store); + } + public void PAITurningOff(EntityUid uid) { // Close the instrument interface if it was open diff --git a/Content.Shared/PAI/PAIComponent.cs b/Content.Shared/PAI/PAIComponent.cs index 9d5be30275..fb9d7150e3 100644 --- a/Content.Shared/PAI/PAIComponent.cs +++ b/Content.Shared/PAI/PAIComponent.cs @@ -1,3 +1,5 @@ +using Content.Shared.FixedPoint; +using Content.Shared.Store; using Robust.Shared.GameStates; using Robust.Shared.Prototypes; using Robust.Shared.Serialization.TypeSerializers.Implementations.Custom.Prototype; @@ -24,17 +26,11 @@ public sealed partial class PAIComponent : Component [DataField, ViewVariables(VVAccess.ReadWrite)] public EntityUid? LastUser; - [DataField(serverOnly: true)] - public EntProtoId? MidiActionId = "ActionPAIPlayMidi"; - - [DataField(serverOnly: true)] // server only, as it uses a server-BUI event !type - public EntityUid? MidiAction; - [DataField] - public EntProtoId MapActionId = "ActionPAIOpenMap"; + public EntProtoId ShopActionId = "ActionPAIOpenShop"; [DataField, AutoNetworkedField] - public EntityUid? MapAction; + public EntityUid? ShopAction; /// /// When microwaved there is this chance to brick the pai, kicking out its player and preventing it from being used again. diff --git a/Content.Shared/PAI/SharedPAISystem.cs b/Content.Shared/PAI/SharedPAISystem.cs index d66365eb85..c100e38a76 100644 --- a/Content.Shared/PAI/SharedPAISystem.cs +++ b/Content.Shared/PAI/SharedPAISystem.cs @@ -1,39 +1,38 @@ using Content.Shared.Actions; -namespace Content.Shared.PAI +namespace Content.Shared.PAI; + +/// +/// pAIs, or Personal AIs, are essentially portable ghost role generators. +/// In their current implementation, they create a ghost role anyone can access, +/// and that a player can also "wipe" (reset/kick out player). +/// Theoretically speaking pAIs are supposed to use a dedicated "offer and select" system, +/// with the player holding the pAI being able to choose one of the ghosts in the round. +/// This seems too complicated for an initial implementation, though, +/// and there's not always enough players and ghost roles to justify it. +/// +public abstract class SharedPAISystem : EntitySystem { - /// - /// pAIs, or Personal AIs, are essentially portable ghost role generators. - /// In their current implementation, they create a ghost role anyone can access, - /// and that a player can also "wipe" (reset/kick out player). - /// Theoretically speaking pAIs are supposed to use a dedicated "offer and select" system, - /// with the player holding the pAI being able to choose one of the ghosts in the round. - /// This seems too complicated for an initial implementation, though, - /// and there's not always enough players and ghost roles to justify it. - /// - public abstract class SharedPAISystem : EntitySystem - { - [Dependency] private readonly SharedActionsSystem _actionsSystem = default!; + [Dependency] private readonly SharedActionsSystem _actions = default!; - public override void Initialize() - { - base.Initialize(); + public override void Initialize() + { + base.Initialize(); - SubscribeLocalEvent(OnMapInit); - SubscribeLocalEvent(OnShutdown); - } + SubscribeLocalEvent(OnMapInit); + SubscribeLocalEvent(OnShutdown); + } - private void OnMapInit(EntityUid uid, PAIComponent component, MapInitEvent args) - { - _actionsSystem.AddAction(uid, ref component.MidiAction, component.MidiActionId); - _actionsSystem.AddAction(uid, ref component.MapAction, component.MapActionId); - } + private void OnMapInit(Entity ent, ref MapInitEvent args) + { + _actions.AddAction(ent, ent.Comp.ShopActionId); + } - private void OnShutdown(EntityUid uid, PAIComponent component, ComponentShutdown args) - { - _actionsSystem.RemoveAction(uid, component.MidiAction); - _actionsSystem.RemoveAction(uid, component.MapAction); - } + private void OnShutdown(Entity ent, ref ComponentShutdown args) + { + _actions.RemoveAction(ent, ent.Comp.ShopAction); } } - +public sealed partial class PAIShopActionEvent : InstantActionEvent +{ +} diff --git a/Resources/Locale/en-US/store/currency.ftl b/Resources/Locale/en-US/store/currency.ftl index ada70b5597..1ba66e6481 100644 --- a/Resources/Locale/en-US/store/currency.ftl +++ b/Resources/Locale/en-US/store/currency.ftl @@ -9,4 +9,5 @@ store-currency-display-debugdollar = {$amount -> } store-currency-display-telecrystal = TC store-currency-display-stolen-essence = Stolen Essence +store-currency-display-silicon-memory = Memory store-currency-display-wizcoin = Wiz€oin™ diff --git a/Resources/Locale/en-US/store/pai-catalog.ftl b/Resources/Locale/en-US/store/pai-catalog.ftl new file mode 100644 index 0000000000..3054935614 --- /dev/null +++ b/Resources/Locale/en-US/store/pai-catalog.ftl @@ -0,0 +1,8 @@ +pai-mass-scanner-name = Mass Scanner +pai-mass-scanner-desc = Enables you to scan nearby masses to assist in navigation. + +pai-midi-player-name = MIDI Player +pai-midi-player-desc = Enables you to play music to entertain your owner. + +pai-station-map-name = Station Map +pai-station-map-desc = Enables you to view the station map to assist in navigation. diff --git a/Resources/Prototypes/Catalog/pai_catalog.yml b/Resources/Prototypes/Catalog/pai_catalog.yml new file mode 100644 index 0000000000..913eae5d0b --- /dev/null +++ b/Resources/Prototypes/Catalog/pai_catalog.yml @@ -0,0 +1,43 @@ +# Some things might seem like great ideas on paper for pAI apps, but have deliberately been excluded. +# e.g. Monitoring (Power/Atmos/Crew), Cameras, etc. are excluded as apps for performance and balance reasons. +# Generally speaking, if you're adding an application, it needs to *not* be round-impacting. +# Remember that pAI's are *assistants*, not players. + +- type: listing + id: PAIMassScanner + name: pai-mass-scanner-name + description: pai-mass-scanner-desc + productAction: ActionPAIMassScanner + cost: + SiliconMemory: 10 + categories: + - PAIAbilities + conditions: + - !type:ListingLimitedStockCondition + stock: 1 + +- type: listing + id: PAIMIDIPlayer + name: pai-midi-player-name + description: pai-midi-player-desc + productAction: ActionPAIPlayMidi + cost: + SiliconMemory: 5 + categories: + - PAIAbilities + conditions: + - !type:ListingLimitedStockCondition + stock: 1 + +- type: listing + id: PAIStationMap + name: pai-station-map-name + description: pai-station-map-desc + productAction: ActionPAIOpenMap + cost: + SiliconMemory: 5 + categories: + - PAIAbilities + conditions: + - !type:ListingLimitedStockCondition + stock: 1 diff --git a/Resources/Prototypes/Entities/Objects/Fun/pai.yml b/Resources/Prototypes/Entities/Objects/Fun/pai.yml index 19aec6e0e2..2a8e0e6a7f 100644 --- a/Resources/Prototypes/Entities/Objects/Fun/pai.yml +++ b/Resources/Prototypes/Entities/Objects/Fun/pai.yml @@ -13,6 +13,13 @@ program: 2 - type: UserInterface interfaces: + enum.StoreUiKey.Key: + type: StoreBoundUserInterface + requireInputValidation: false + # available in pai shop + enum.RadarConsoleUiKey.Key: + type: RadarConsoleBoundUserInterface + requireInputValidation: false enum.InstrumentUiKey.Key: type: InstrumentBoundUserInterface requireInputValidation: false @@ -51,6 +58,16 @@ - Common - type: DoAfter - type: Actions + - type: Store + categories: + - PAIAbilities + currencyWhitelist: + - SiliconMemory + balance: + SiliconMemory: 30 + - type: RadarConsole + maxRange: 256 + followEntity: true - type: TypingIndicator proto: robot - type: Speech @@ -141,6 +158,30 @@ graph: PotatoAI node: potatoai +- type: entity + id: ActionPAIOpenShop + name: Software Catalog + description: Install new software to assist your owner. + components: + - type: InstantAction + checkCanInteract: false + checkConsciousness: false + icon: Interface/Actions/shop.png + event: !type:PAIShopActionEvent + +- type: entity + id: ActionPAIMassScanner + name: Mass Scanner + description: View a mass scanner interface. + components: + - type: InstantAction + checkCanInteract: false + checkConsciousness: false + icon: { sprite: Interface/Actions/actions_ai.rsi, state: mass_scanner } + itemIconStyle: NoItem + event: !type:OpenUiActionEvent + key: enum.RadarConsoleUiKey.Key + - type: entity id: ActionPAIPlayMidi name: Play MIDI @@ -150,6 +191,7 @@ checkCanInteract: false checkConsciousness: false icon: Interface/Actions/pai-midi.png + itemIconStyle: NoItem event: !type:OpenUiActionEvent key: enum.InstrumentUiKey.Key @@ -162,5 +204,6 @@ checkCanInteract: false checkConsciousness: false icon: { sprite: Interface/Actions/pai-map.rsi, state: icon } + itemIconStyle: NoItem event: !type:OpenUiActionEvent key: enum.StationMapUiKey.Key diff --git a/Resources/Prototypes/Store/categories.yml b/Resources/Prototypes/Store/categories.yml index 69cde10020..b3c358d388 100644 --- a/Resources/Prototypes/Store/categories.yml +++ b/Resources/Prototypes/Store/categories.yml @@ -94,6 +94,11 @@ id: RevenantAbilities name: store-category-abilities +#pai +- type: storeCategory + id: PAIAbilities + name: store-category-abilities + - type: storeCategory id: DiscountedItems name: store-discounted-items diff --git a/Resources/Prototypes/Store/currency.yml b/Resources/Prototypes/Store/currency.yml index b1cff06be2..0173de62f9 100644 --- a/Resources/Prototypes/Store/currency.yml +++ b/Resources/Prototypes/Store/currency.yml @@ -10,6 +10,11 @@ displayName: store-currency-display-stolen-essence canWithdraw: false +- type: currency + id: SiliconMemory + displayName: store-currency-display-silicon-memory + canWithdraw: false + - type: currency id: WizCoin displayName: store-currency-display-wizcoin -- 2.51.2