Migrate revenant and PAI shops to use ActionGrant instead of hardcoding them (#40475)

* 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>
This commit is contained in:
Jessica M
2025-10-09 14:14:12 -07:00
committed by GitHub
parent 5185df4072
commit 0d97699aae
13 changed files with 43 additions and 116 deletions

View File

@@ -1,8 +0,0 @@
using Content.Shared.PAI;
namespace Content.Client.PAI
{
public sealed class PAISystem : SharedPAISystem
{
}
}

View 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

View 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>();

View 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

View 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>

View File

@@ -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
{
}

View File

@@ -214,6 +214,4 @@ public sealed partial class RevenantComponent : Component
[DataField("harvestingState")]
public string HarvestingState = "harvesting";
#endregion
[DataField] public EntityUid? Action;
}

View File

@@ -42,10 +42,6 @@ public sealed class HarvestDoAfterCancelled : EntityEventArgs
{
}
public sealed partial class RevenantShopActionEvent : InstantActionEvent
{
}
public sealed partial class RevenantDefileActionEvent : InstantActionEvent
{
}

View File

@@ -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
{
}

View 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

View File

@@ -466,3 +466,14 @@
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

View File

@@ -66,6 +66,9 @@
type: StoreBoundUserInterface
- type: Visibility
layer: 2 #ghost vis layer
- type: ActionGrant
actions:
- ActionRevenantShop
- type: Store
categories:
- RevenantAbilities

View File

@@ -58,6 +58,9 @@
- Common
- type: DoAfter
- type: Actions
- type: ActionGrant
actions:
- ActionPAIOpenShop
- type: Store
categories:
- PAIAbilities
@@ -188,15 +191,10 @@
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