diff --git a/Content.Server/Abilities/Borgs/FabricateActionsComponent.cs b/Content.Server/Abilities/Borgs/FabricateActionsComponent.cs
new file mode 100644
index 0000000000..c9a693562f
--- /dev/null
+++ b/Content.Server/Abilities/Borgs/FabricateActionsComponent.cs
@@ -0,0 +1,19 @@
+using Robust.Shared.Prototypes;
+
+namespace Content.Server.Abilities.Borgs;
+
+[RegisterComponent]
+public sealed partial class FabricateActionsComponent : Component
+{
+ ///
+ /// IDs of fabrication actions that the entity should receive with this component.
+ ///
+ [DataField]
+ public List> Actions = new();
+
+ ///
+ /// Action entities added by this component.
+ ///
+ [DataField]
+ public Dictionary, EntityUid> ActionEntities = new();
+}
diff --git a/Content.Server/Abilities/Borgs/FabricateActionsSystem.cs b/Content.Server/Abilities/Borgs/FabricateActionsSystem.cs
new file mode 100644
index 0000000000..c73b46c0b8
--- /dev/null
+++ b/Content.Server/Abilities/Borgs/FabricateActionsSystem.cs
@@ -0,0 +1,53 @@
+using Content.Shared.ActionBlocker;
+using Content.Shared.Actions;
+using Content.Shared.Actions.Events;
+
+namespace Content.Server.Abilities.Borgs;
+
+public sealed partial class FabricateActionsSystem : EntitySystem
+{
+ [Dependency] private readonly ActionBlockerSystem _actionBlocker = default!;
+ [Dependency] private readonly SharedActionsSystem _actions = default!;
+
+
+ public override void Initialize()
+ {
+ base.Initialize();
+
+ SubscribeLocalEvent(OnStartup);
+ SubscribeLocalEvent(OnShutdown);
+ SubscribeLocalEvent(OnFabricate);
+ }
+
+
+ private void OnStartup(Entity entity, ref ComponentStartup args)
+ {
+ foreach (var actionId in entity.Comp.Actions)
+ {
+ EntityUid? actionEntity = null;
+ if (_actions.AddAction(entity, ref actionEntity, actionId))
+ entity.Comp.ActionEntities[actionId] = actionEntity.Value;
+ }
+ }
+
+ private void OnShutdown(Entity entity, ref ComponentShutdown args)
+ {
+ foreach (var (actionId, actionEntity) in entity.Comp.ActionEntities)
+ {
+ if (actionEntity is not { Valid: true })
+ continue;
+
+ _actions.RemoveAction(entity, actionEntity);
+ entity.Comp.ActionEntities.Remove(actionId);
+ }
+ }
+
+ private void OnFabricate(Entity entity, ref FabricateActionEvent args)
+ {
+ if (args.Handled || !_actionBlocker.CanConsciouslyPerformAction(entity))
+ return;
+
+ SpawnNextToOrDrop(args.Fabrication, entity);
+ args.Handled = true;
+ }
+}
diff --git a/Content.Server/Nyanotrasen/Abilities/Borgs/FabricateCandyComponent.cs b/Content.Server/Nyanotrasen/Abilities/Borgs/FabricateCandyComponent.cs
deleted file mode 100644
index d0a399c1fe..0000000000
--- a/Content.Server/Nyanotrasen/Abilities/Borgs/FabricateCandyComponent.cs
+++ /dev/null
@@ -1,11 +0,0 @@
-namespace Content.Server.Abilities.Borgs;
-
-[RegisterComponent]
-public sealed partial class FabricateCandyComponent : Component
-{
- [DataField("lollipopAction")]
- public EntityUid? LollipopAction;
-
- [DataField("gumballAction")]
- public EntityUid? GumballAction;
-}
diff --git a/Content.Server/Nyanotrasen/Abilities/Borgs/FabricateCandySystem.cs b/Content.Server/Nyanotrasen/Abilities/Borgs/FabricateCandySystem.cs
deleted file mode 100644
index 6451c7cbb2..0000000000
--- a/Content.Server/Nyanotrasen/Abilities/Borgs/FabricateCandySystem.cs
+++ /dev/null
@@ -1,37 +0,0 @@
-using Content.Shared.Actions;
-using Content.Shared.Actions.Events;
-
-namespace Content.Server.Abilities.Borgs;
-
-public sealed partial class FabricateCandySystem : EntitySystem
-{
- [Dependency] private readonly SharedActionsSystem _actionsSystem = default!;
- public override void Initialize()
- {
- base.Initialize();
- SubscribeLocalEvent(OnInit);
- SubscribeLocalEvent(OnLollipop);
- SubscribeLocalEvent(OnGumball);
- }
-
- private void OnInit(EntityUid uid, FabricateCandyComponent component, ComponentInit args)
- {
- if (component.LollipopAction != null || component.GumballAction != null)
- return;
-
- _actionsSystem.AddAction(uid, ref component.LollipopAction, "ActionFabricateLollipop");
- _actionsSystem.AddAction(uid, ref component.GumballAction, "ActionFabricateGumball");
- }
-
- private void OnLollipop(FabricateLollipopActionEvent args)
- {
- Spawn("FoodLollipop", Transform(args.Performer).Coordinates);
- args.Handled = true;
- }
-
- private void OnGumball(FabricateGumballActionEvent args)
- {
- Spawn("FoodGumball", Transform(args.Performer).Coordinates);
- args.Handled = true;
- }
-}
diff --git a/Content.Shared/Actions/Events/FabricateActionEvent.cs b/Content.Shared/Actions/Events/FabricateActionEvent.cs
new file mode 100644
index 0000000000..7483cb04d9
--- /dev/null
+++ b/Content.Shared/Actions/Events/FabricateActionEvent.cs
@@ -0,0 +1,9 @@
+using Robust.Shared.Prototypes;
+
+namespace Content.Shared.Actions.Events;
+
+public sealed partial class FabricateActionEvent : InstantActionEvent
+{
+ [DataField(required: true)]
+ public ProtoId Fabrication;
+}
diff --git a/Content.Shared/Nyanotrasen/Actions/FabricateCandyEvent.cs b/Content.Shared/Nyanotrasen/Actions/FabricateCandyEvent.cs
deleted file mode 100644
index 3c9371d27e..0000000000
--- a/Content.Shared/Nyanotrasen/Actions/FabricateCandyEvent.cs
+++ /dev/null
@@ -1,4 +0,0 @@
-namespace Content.Shared.Actions.Events;
-
-public sealed partial class FabricateLollipopActionEvent : InstantActionEvent {}
-public sealed partial class FabricateGumballActionEvent : InstantActionEvent {}
diff --git a/Resources/Prototypes/Actions/types.yml b/Resources/Prototypes/Actions/types.yml
index 22f16bd956..f55f59daaa 100644
--- a/Resources/Prototypes/Actions/types.yml
+++ b/Resources/Prototypes/Actions/types.yml
@@ -350,3 +350,29 @@
itemIconStyle: NoItem
useDelay: 1 # emote spam
event: !type:ToggleActionEvent
+
+- type: entity
+ id: ActionFabricateLollipop
+ name: action-name-fabricate-lollipop
+ description: action-description-fabricate-lollipop
+ noSpawn: true
+ components:
+ - type: InstantAction
+ icon: { sprite: Nyanotrasen/Objects/Consumable/Food/candy.rsi, state: lollipop }
+ useDelay: 120
+ event:
+ !type:FabricateActionEvent
+ fabrication: FoodLollipop
+
+- type: entity
+ id: ActionFabricateGumball
+ name: action-name-fabricate-gumball
+ description: action-description-fabricate-gumball
+ noSpawn: true
+ components:
+ - type: InstantAction
+ icon: { sprite: Nyanotrasen/Objects/Consumable/Food/candy.rsi, state: gumball }
+ useDelay: 40
+ event:
+ !type:FabricateActionEvent
+ fabrication: FoodGumball
diff --git a/Resources/Prototypes/Entities/Mobs/Cyborgs/borg_chassis.yml b/Resources/Prototypes/Entities/Mobs/Cyborgs/borg_chassis.yml
index 6191e61250..5056fda4c0 100644
--- a/Resources/Prototypes/Entities/Mobs/Cyborgs/borg_chassis.yml
+++ b/Resources/Prototypes/Entities/Mobs/Cyborgs/borg_chassis.yml
@@ -119,7 +119,7 @@
- type: Inventory
templateId: borgShort
- type: SiliconLawProvider # Delta-V - Adds custom lawset for Engineering Cyborg
- laws: Engineer
+ laws: Engineer
- type: entity
id: BorgChassisJanitor
@@ -224,7 +224,10 @@
access: [["Medical"], ["Command"], ["Research"]]
- type: Inventory
templateId: borgDutch
- - type: FabricateCandy # Nyanotrasen - The medical cyborg can generate candies filled with medicine.
+ - type: FabricateActions
+ actions:
+ - ActionFabricateLollipop
+ - ActionFabricateGumball
- type: SiliconLawProvider # Delta-V - Adds custom lawset for Medical cyborg
laws: Medical
diff --git a/Resources/Prototypes/Nyanotrasen/Actions/types.yml b/Resources/Prototypes/Nyanotrasen/Actions/types.yml
index e6e4bdc5a7..04002f5755 100644
--- a/Resources/Prototypes/Nyanotrasen/Actions/types.yml
+++ b/Resources/Prototypes/Nyanotrasen/Actions/types.yml
@@ -156,24 +156,3 @@
icon: Nyanotrasen/Interface/VerbIcons/psionic_invisibility_off.png
event: !type:RemovePsionicInvisibilityOffPowerActionEvent
-- type: entity
- id: ActionFabricateLollipop
- name: action-name-fabricate-lollipop
- description: action-description-fabricate-lollipop
- noSpawn: true
- components:
- - type: InstantAction
- icon: { sprite: Nyanotrasen/Objects/Consumable/Food/candy.rsi, state: lollipop }
- useDelay: 120
- event: !type:FabricateLollipopActionEvent
-
-- type: entity
- id: ActionFabricateGumball
- name: action-name-fabricate-gumball
- description: action-description-fabricate-gumball
- noSpawn: true
- components:
- - type: InstantAction
- icon: { sprite: Nyanotrasen/Objects/Consumable/Food/candy.rsi, state: gumball }
- useDelay: 40
- event: !type:FabricateGumballActionEvent