]> git.smokeofanarchy.ru Git - space-station-14.git/commitdiff
Migrate revenant and PAI shops to use ActionGrant instead of hardcoding them (#40475)
authorJessica M <jessica@jessicamaybe.com>
Thu, 9 Oct 2025 21:14:12 +0000 (14:14 -0700)
committerGitHub <noreply@github.com>
Thu, 9 Oct 2025 21:14:12 +0000 (21:14 +0000)
* add intrinsic store, replace revenant store with it.

* migrate PAI and also move to shared where possible

* fix typos and clean up... intrinisic

* oops, hopefully fixes test

* Move to StoreSystem and ActionGrant

* documentation and remove thing

* review

---------

Co-authored-by: Jessica M <jessica@maybe.sh>
Co-authored-by: slarticodefast <161409025+slarticodefast@users.noreply.github.com>
13 files changed:
Content.Client/PAI/PAISystem.cs [deleted file]
Content.Server/PAI/PAISystem.cs
Content.Server/Revenant/EntitySystems/RevenantSystem.cs
Content.Server/Store/Systems/StoreSystem.cs
Content.Shared/PAI/PAIComponent.cs
Content.Shared/PAI/SharedPAISystem.cs [deleted file]
Content.Shared/Revenant/Components/RevenantComponent.cs
Content.Shared/Revenant/SharedRevenant.cs
Content.Shared/Store/Events/IntrinsicStoreActionEvent.cs [new file with mode: 0644]
Resources/Prototypes/Actions/revenant.yml
Resources/Prototypes/Actions/types.yml
Resources/Prototypes/Entities/Mobs/NPCs/revenant.yml
Resources/Prototypes/Entities/Objects/Fun/pai.yml

diff --git a/Content.Client/PAI/PAISystem.cs b/Content.Client/PAI/PAISystem.cs
deleted file mode 100644 (file)
index a28cf6a..0000000
+++ /dev/null
@@ -1,8 +0,0 @@
-using Content.Shared.PAI;
-
-namespace Content.Client.PAI
-{
-    public sealed class PAISystem : SharedPAISystem
-    {
-    }
-}
index 289b74b2582627da2844179b26a21d19a1269ff6..7fd58f15728cb110888115bf6f8b667da3cb251c 100644 (file)
@@ -2,27 +2,22 @@ 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;
 
 namespace Content.Server.PAI;
 
-public sealed class PAISystem : SharedPAISystem
+public sealed class PAISystem : EntitySystem
 {
     [Dependency] private readonly InstrumentSystem _instrumentSystem = default!;
     [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>
@@ -38,8 +33,6 @@ 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)
@@ -106,15 +99,6 @@ public sealed class PAISystem : SharedPAISystem
         var val = Loc.GetString("pai-system-pai-name-raw", ("name", name.ToString()));
         _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 b89f10934d98f67690633d30690be9dda11503b4..6c8972be58d7919ef5b5b2bf1a3a33c52b78671e 100644 (file)
@@ -1,7 +1,6 @@
 using System.Numerics;
 using Content.Server.Actions;
 using Content.Server.GameTicking;
-using Content.Server.Store.Components;
 using Content.Server.Store.Systems;
 using Content.Shared.Alert;
 using Content.Shared.Damage;
@@ -21,7 +20,6 @@ using Content.Shared.Store.Components;
 using Content.Shared.Stunnable;
 using Content.Shared.Tag;
 using Robust.Server.GameObjects;
-using Robust.Shared.Prototypes;
 using Robust.Shared.Random;
 
 namespace Content.Server.Revenant.EntitySystems;
@@ -46,17 +44,12 @@ public sealed partial class RevenantSystem : EntitySystem
     [Dependency] private readonly TagSystem _tag = default!;
     [Dependency] private readonly VisibilitySystem _visibility = default!;
     [Dependency] private readonly TurfSystem _turf = default!;
-
-    private static readonly EntProtoId RevenantShopId = "ActionRevenantShop";
-
     public override void Initialize()
     {
         base.Initialize();
 
         SubscribeLocalEvent<RevenantComponent, ComponentStartup>(OnStartup);
-        SubscribeLocalEvent<RevenantComponent, MapInitEvent>(OnMapInit);
 
-        SubscribeLocalEvent<RevenantComponent, RevenantShopActionEvent>(OnShop);
         SubscribeLocalEvent<RevenantComponent, DamageChangedEvent>(OnDamage);
         SubscribeLocalEvent<RevenantComponent, ExaminedEvent>(OnExamine);
         SubscribeLocalEvent<RevenantComponent, StatusEffectAddedEvent>(OnStatusAdded);
@@ -94,11 +87,6 @@ public sealed partial class RevenantSystem : EntitySystem
         _eye.RefreshVisibilityMask(uid);
     }
 
-    private void OnMapInit(EntityUid uid, RevenantComponent component, MapInitEvent args)
-    {
-        _action.AddAction(uid, ref component.Action, RevenantShopId);
-    }
-
     private void OnStatusAdded(EntityUid uid, RevenantComponent component, StatusEffectAddedEvent args)
     {
         if (args.Key == "Stun")
@@ -182,13 +170,6 @@ public sealed partial class RevenantSystem : EntitySystem
         return true;
     }
 
-    private void OnShop(EntityUid uid, RevenantComponent component, RevenantShopActionEvent args)
-    {
-        if (!TryComp<StoreComponent>(uid, out var store))
-            return;
-        _store.ToggleUi(uid, uid, store);
-    }
-
     public void MakeVisible(bool visible)
     {
         var query = EntityQueryEnumerator<RevenantComponent, VisibilityComponent>();
index 0625ced08769aabcf74c050849e6167ed3926728..10060dc7d3844e45af366a9ad5d095193c005ea6 100644 (file)
@@ -1,17 +1,16 @@
+using System.Linq;
 using Content.Server.Store.Components;
-using Content.Shared.UserInterface;
 using Content.Shared.FixedPoint;
 using Content.Shared.Implants.Components;
 using Content.Shared.Interaction;
 using Content.Shared.Popups;
 using Content.Shared.Stacks;
 using Content.Shared.Store.Components;
-using JetBrains.Annotations;
+using Content.Shared.Store.Events;
+using Content.Shared.UserInterface;
 using Robust.Shared.Prototypes;
-using Robust.Shared.Utility;
-using System.Linq;
 using Robust.Shared.Timing;
-using Content.Shared.Mind;
+using Robust.Shared.Utility;
 
 namespace Content.Server.Store.Systems;
 
@@ -37,6 +36,7 @@ public sealed partial class StoreSystem : EntitySystem
         SubscribeLocalEvent<StoreComponent, ComponentStartup>(OnStartup);
         SubscribeLocalEvent<StoreComponent, ComponentShutdown>(OnShutdown);
         SubscribeLocalEvent<StoreComponent, OpenUplinkImplantEvent>(OnImplantActivate);
+        SubscribeLocalEvent<StoreComponent, IntrinsicStoreActionEvent>(OnIntrinsicStoreAction);
 
         InitializeUi();
         InitializeCommand();
@@ -187,6 +187,12 @@ public sealed partial class StoreSystem : EntitySystem
         UpdateUserInterface(null, uid, store);
         return true;
     }
+
+    private void OnIntrinsicStoreAction(Entity<StoreComponent> ent, ref IntrinsicStoreActionEvent args)
+    {
+        ToggleUi(args.Performer, ent.Owner, ent.Comp);
+    }
+
 }
 
 public sealed class CurrencyInsertAttemptEvent : CancellableEntityEventArgs
index fb9d7150e3c24fdf3f34e041de8ec2d039926200..541172ffe01d32e084e4b4e1a6fdb94a40da860b 100644 (file)
@@ -1,8 +1,4 @@
-using Content.Shared.FixedPoint;
-using Content.Shared.Store;
 using Robust.Shared.GameStates;
-using Robust.Shared.Prototypes;
-using Robust.Shared.Serialization.TypeSerializers.Implementations.Custom.Prototype;
 
 namespace Content.Shared.PAI;
 
@@ -16,7 +12,7 @@ namespace Content.Shared.PAI;
 ///  and there's not always enough players and ghost roles to justify it.
 /// All logic in PAISystem.
 /// </summary>
-[RegisterComponent, NetworkedComponent, AutoGenerateComponentState]
+[RegisterComponent, NetworkedComponent]
 public sealed partial class PAIComponent : Component
 {
     /// <summary>
@@ -26,12 +22,6 @@ public sealed partial class PAIComponent : Component
     [DataField, ViewVariables(VVAccess.ReadWrite)]
     public EntityUid? LastUser;
 
-    [DataField]
-    public EntProtoId ShopActionId = "ActionPAIOpenShop";
-
-    [DataField, AutoNetworkedField]
-    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.
     /// </summary>
diff --git a/Content.Shared/PAI/SharedPAISystem.cs b/Content.Shared/PAI/SharedPAISystem.cs
deleted file mode 100644 (file)
index 00d3e23..0000000
+++ /dev/null
@@ -1,38 +0,0 @@
-using Content.Shared.Actions;
-
-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
-{
-    [Dependency] private readonly SharedActionsSystem _actions = default!;
-
-    public override void Initialize()
-    {
-        base.Initialize();
-
-        SubscribeLocalEvent<PAIComponent, MapInitEvent>(OnMapInit);
-        SubscribeLocalEvent<PAIComponent, ComponentShutdown>(OnShutdown);
-    }
-
-    private void OnMapInit(Entity<PAIComponent> ent, ref MapInitEvent args)
-    {
-        _actions.AddAction(ent, ent.Comp.ShopActionId);
-    }
-
-    private void OnShutdown(Entity<PAIComponent> ent, ref ComponentShutdown args)
-    {
-        _actions.RemoveAction(ent.Owner, ent.Comp.ShopAction);
-    }
-}
-public sealed partial class PAIShopActionEvent : InstantActionEvent
-{
-}
index e6543f1906961491063b8b542f7b56fe1e096c56..e434bba1d9a19268fbc90e7faa9011932c0d6362 100644 (file)
@@ -214,6 +214,4 @@ public sealed partial class RevenantComponent : Component
     [DataField("harvestingState")]
     public string HarvestingState = "harvesting";
     #endregion
-
-    [DataField] public EntityUid? Action;
 }
index c44e4408aaf31fea5c0590639c9184f6ee81bcae..b1023f43e2823ebab54227fe4b50ac088c03b69a 100644 (file)
@@ -42,10 +42,6 @@ public sealed class HarvestDoAfterCancelled : EntityEventArgs
 {
 }
 
-public sealed partial class RevenantShopActionEvent : InstantActionEvent
-{
-}
-
 public sealed partial class RevenantDefileActionEvent : InstantActionEvent
 {
 }
diff --git a/Content.Shared/Store/Events/IntrinsicStoreActionEvent.cs b/Content.Shared/Store/Events/IntrinsicStoreActionEvent.cs
new file mode 100644 (file)
index 0000000..dea2c25
--- /dev/null
@@ -0,0 +1,11 @@
+using Content.Shared.Actions;
+
+namespace Content.Shared.Store.Events;
+
+/// <summary>
+/// Opens a store specified by <see cref="StoreComponent"/>
+/// Used for entities with a store built into themselves like Revenant or PAI
+/// </summary>
+public sealed partial class IntrinsicStoreActionEvent : InstantActionEvent
+{
+}
index 5904908a75bc5a8451e752f3b69c1e114282d6ff..3ac425a56782b2f0789868cdc5b8ff979927ceab 100644 (file)
@@ -1,13 +1,8 @@
 - type: entity
-  parent: BaseAction
+  parent: ActionIntrinsicStore
   id: ActionRevenantShop
   name: Shop
   description: Opens the ability shop.
-  components:
-  - type: Action
-    icon: Interface/Actions/shop.png
-  - type: InstantAction
-    event: !type:RevenantShopActionEvent
 
 - type: entity
   parent: BaseAction
index 61babbfcea7a0ca1ef0bd0a68e09971476534e68..752aeb13f8887a34cce1bb95a5d8746da2d94699 100644 (file)
     itemIconStyle: BigAction
   - type: InstantAction
     event: !type:ChameleonControllerOpenMenuEvent
+
+- type: entity
+  parent: BaseMentalAction
+  id: ActionIntrinsicStore
+  name: Store
+  description: Opens the store
+  components:
+  - type: Action
+    icon: Interface/Actions/shop.png
+  - type: InstantAction
+    event: !type:IntrinsicStoreActionEvent
index 9b0bfb05ca9ca4efe6765abc6234bca37854ce93..04b1554cefe080fe941a4f2b395a4b1ee878e9f3 100644 (file)
@@ -66,6 +66,9 @@
         type: StoreBoundUserInterface
   - type: Visibility
     layer: 2 #ghost vis layer
+  - type: ActionGrant
+    actions:
+    - ActionRevenantShop
   - type: Store
     categories:
     - RevenantAbilities
index 6aec812b77b968108badef20c142d82c2df0e935..2ba5acfbf18cb468b21f58b324a8d590e3def7a7 100644 (file)
@@ -58,6 +58,9 @@
     - Common
   - type: DoAfter
   - type: Actions
+  - type: ActionGrant
+    actions:
+    - ActionPAIOpenShop
   - type: Store
     categories:
     - PAIAbilities
     node: potatoai
 
 - type: entity
-  parent: BaseMentalAction
+  parent: ActionIntrinsicStore
   id: ActionPAIOpenShop
   name: Software Catalog
   description: Install new software to assist your owner.
-  components:
-  - type: Action
-    icon: Interface/Actions/shop.png
-  - type: InstantAction
-    event: !type:PAIShopActionEvent
 
 - type: entity
   parent: BaseMentalAction