]> git.smokeofanarchy.ru Git - space-station-14.git/commitdiff
pAI Software Catalog (#36857)
authorArchRBX <5040911+ArchRBX@users.noreply.github.com>
Wed, 23 Apr 2025 23:55:35 +0000 (00:55 +0100)
committerGitHub <noreply@github.com>
Wed, 23 Apr 2025 23:55:35 +0000 (16:55 -0700)
* 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 <punk.gear5260@fastmail.com>
Content.Server/PAI/PAISystem.cs
Content.Shared/PAI/PAIComponent.cs
Content.Shared/PAI/SharedPAISystem.cs
Resources/Locale/en-US/store/currency.ftl
Resources/Locale/en-US/store/pai-catalog.ftl [new file with mode: 0644]
Resources/Prototypes/Catalog/pai_catalog.yml [new file with mode: 0644]
Resources/Prototypes/Entities/Objects/Fun/pai.yml
Resources/Prototypes/Store/categories.yml
Resources/Prototypes/Store/currency.yml

index fd581f40e43cb2dc12c3713ab36a1dac6405e6f7..289b74b2582627da2844179b26a21d19a1269ff6 100644 (file)
@@ -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!;
 
     /// <summary>
     /// Possible symbols that can be part of a scrambled pai's name.
     /// </summary>
-    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<PAIComponent, MindAddedMessage>(OnMindAdded);
         SubscribeLocalEvent<PAIComponent, MindRemovedMessage>(OnMindRemoved);
         SubscribeLocalEvent<PAIComponent, BeingMicrowavedEvent>(OnMicrowaved);
+
+        SubscribeLocalEvent<PAIComponent, PAIShopActionEvent>(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<PAIComponent> ent, ref PAIShopActionEvent args)
+    {
+        if (!TryComp<StoreComponent>(ent, out var store))
+            return;
+
+        _store.ToggleUi(args.Performer, ent, store);
+    }
+
     public void PAITurningOff(EntityUid uid)
     {
         //  Close the instrument interface if it was open
index 9d5be30275883341c314b5171eb20e87f99a2427..fb9d7150e3c24fdf3f34e041de8ec2d039926200 100644 (file)
@@ -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;
 
     /// <summary>
     /// When microwaved there is this chance to brick the pai, kicking out its player and preventing it from being used again.
index d66365eb8555c9fac8caef42068812e1fb254319..c100e38a764112cb6bda3eee639d674d7b6ad03f 100644 (file)
@@ -1,39 +1,38 @@
 using Content.Shared.Actions;
 
-namespace Content.Shared.PAI
+namespace Content.Shared.PAI;
+
+/// <summary>
+/// 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.
+/// </summary>
+public abstract class SharedPAISystem : EntitySystem
 {
-    /// <summary>
-    /// 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.
-    /// </summary>
-    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<PAIComponent, MapInitEvent>(OnMapInit);
-            SubscribeLocalEvent<PAIComponent, ComponentShutdown>(OnShutdown);
-        }
+        SubscribeLocalEvent<PAIComponent, MapInitEvent>(OnMapInit);
+        SubscribeLocalEvent<PAIComponent, ComponentShutdown>(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<PAIComponent> 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<PAIComponent> ent, ref ComponentShutdown args)
+    {
+        _actions.RemoveAction(ent, ent.Comp.ShopAction);
     }
 }
-
+public sealed partial class PAIShopActionEvent : InstantActionEvent
+{
+}
index ada70b5597a54dae869ae025e6c0eb799f7eb4c6..1ba66e64813d68e7f469df7e6a8cde09bbec940a 100644 (file)
@@ -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 (file)
index 0000000..3054935
--- /dev/null
@@ -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 (file)
index 0000000..913eae5
--- /dev/null
@@ -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
index 19aec6e0e28abe4dcfe4062172200d064d072aec..2a8e0e6a7f46b19173c1a4661b2e1a566e82635f 100644 (file)
     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
     - 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
     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
     checkCanInteract: false
     checkConsciousness: false
     icon: Interface/Actions/pai-midi.png
+    itemIconStyle: NoItem
     event: !type:OpenUiActionEvent
       key: enum.InstrumentUiKey.Key
 
       checkCanInteract: false
       checkConsciousness: false
       icon: { sprite: Interface/Actions/pai-map.rsi, state: icon }
+      itemIconStyle: NoItem
       event: !type:OpenUiActionEvent
         key: enum.StationMapUiKey.Key
index 69cde10020f8bbdfa3544959948e8d2ddc5d5960..b3c358d3889390e04e8ea22778d5d94895d38096 100644 (file)
   id: RevenantAbilities
   name: store-category-abilities
 
+#pai
+- type: storeCategory
+  id: PAIAbilities
+  name: store-category-abilities
+
 - type: storeCategory
   id: DiscountedItems
   name: store-discounted-items
index b1cff06be2d65c548d8c91656f2ac095bd0ec5a5..0173de62f973232aace6f894ee4e999cd0a0d4fb 100644 (file)
   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