diff --git a/Content.Client/_DV/Augments/AugmentToolPanelMenu.xaml b/Content.Client/_DV/Augments/AugmentToolPanelMenu.xaml
new file mode 100644
index 0000000000..eeff0b0863
--- /dev/null
+++ b/Content.Client/_DV/Augments/AugmentToolPanelMenu.xaml
@@ -0,0 +1,10 @@
+
+
+
+
diff --git a/Content.Client/_DV/Augments/AugmentToolPanelMenu.xaml.cs b/Content.Client/_DV/Augments/AugmentToolPanelMenu.xaml.cs
new file mode 100644
index 0000000000..7a8ad72bff
--- /dev/null
+++ b/Content.Client/_DV/Augments/AugmentToolPanelMenu.xaml.cs
@@ -0,0 +1,72 @@
+using Content.Client.UserInterface.Controls;
+using JetBrains.Annotations;
+using Robust.Client.AutoGenerated;
+using Robust.Client.UserInterface.Controls;
+using Robust.Client.UserInterface.XAML;
+using Robust.Client.UserInterface;
+using Content.Shared.Storage;
+using System.Numerics;
+using Robust.Shared.GameObjects;
+
+namespace Content.Client._DV.Augments;
+
+[GenerateTypedNameReferences]
+public sealed partial class AugmentToolPanelMenu : RadialMenu
+{
+ [Dependency] private readonly EntityManager _entManager = default!;
+
+ public event Action? SendAugmentToolPanelSystemMessageAction;
+
+ private EntityUid _owner;
+
+ public AugmentToolPanelMenu()
+ {
+ IoCManager.InjectDependencies(this);
+ RobustXamlLoader.Load(this);
+ }
+
+ public void SetEntity(EntityUid uid)
+ {
+ _owner = uid;
+ Refresh();
+ }
+
+ public void Refresh()
+ {
+ if (!_entManager.TryGetComponent(_owner, out var storage))
+ return;
+
+ foreach (var (entity, _) in storage.StoredItems)
+ {
+ var button = new RadialMenuTextureButtonWithSector()
+ {
+ SetSize = new Vector2(64f, 64f),
+ };
+
+ button.AddChild(new SpriteView(entity, _entManager)
+ {
+ Scale = new Vector2(3f, 3f),
+ });
+ Main.AddChild(button);
+
+ button.OnButtonUp += _ =>
+ {
+ SendAugmentToolPanelSystemMessageAction?.Invoke(entity);
+ Close();
+ };
+ }
+
+ var nilButton = new RadialMenuTextureButtonWithSector()
+ {
+ SetSize = new Vector2(64f, 64f),
+ };
+
+ Main.AddChild(nilButton);
+
+ nilButton.OnButtonUp += _ =>
+ {
+ SendAugmentToolPanelSystemMessageAction?.Invoke(null);
+ Close();
+ };
+ }
+}
diff --git a/Content.Client/_DV/Augments/AugmentToolPanelMenuBoundUserInterface.cs b/Content.Client/_DV/Augments/AugmentToolPanelMenuBoundUserInterface.cs
new file mode 100644
index 0000000000..4d5af73e10
--- /dev/null
+++ b/Content.Client/_DV/Augments/AugmentToolPanelMenuBoundUserInterface.cs
@@ -0,0 +1,39 @@
+using Robust.Client.Graphics;
+using Robust.Client.Input;
+using Robust.Client.UserInterface;
+using Robust.Shared.Prototypes;
+using Content.Shared._DV.Augments;
+
+namespace Content.Client._DV.Augments;
+
+public sealed class AugmentToolPanelMenuBoundUserInterface : BoundUserInterface
+{
+ [Dependency] private readonly IClyde _displayManager = default!;
+ [Dependency] private readonly IInputManager _inputManager = default!;
+ [Dependency] private readonly IEntityManager _entMan = default!;
+
+ private AugmentToolPanelMenu? _menu;
+
+ public AugmentToolPanelMenuBoundUserInterface(EntityUid owner, Enum uiKey) : base(owner, uiKey)
+ {
+ IoCManager.InjectDependencies(this);
+ }
+
+ protected override void Open()
+ {
+ base.Open();
+
+ _menu = this.CreateWindow();
+ _menu.SetEntity(Owner);
+ _menu.SendAugmentToolPanelSystemMessageAction += SendAugmentToolPanelSystemMessage;
+
+ // Open the menu, centered on the mouse
+ var vpSize = _displayManager.ScreenSize;
+ _menu.OpenCenteredAt(_inputManager.MouseScreenPosition.Position / vpSize);
+ }
+
+ public void SendAugmentToolPanelSystemMessage(EntityUid? desiredTool)
+ {
+ SendMessage(new AugmentToolPanelSystemMessage(_entMan.GetNetEntity(desiredTool)));
+ }
+}
diff --git a/Content.Server/Power/EntitySystems/ChargerSystem.cs b/Content.Server/Power/EntitySystems/ChargerSystem.cs
index 09b598d262..fbd4e723ba 100644
--- a/Content.Server/Power/EntitySystems/ChargerSystem.cs
+++ b/Content.Server/Power/EntitySystems/ChargerSystem.cs
@@ -11,6 +11,7 @@ using System.Diagnostics.CodeAnalysis;
using Content.Shared.Storage.Components;
using Robust.Server.Containers;
using Content.Shared.Whitelist;
+using Content.Server._DV.Augments; // DeltaV - bodies can have an augment power cell
namespace Content.Server.Power.EntitySystems;
@@ -22,6 +23,7 @@ internal sealed class ChargerSystem : EntitySystem
[Dependency] private readonly BatterySystem _battery = default!;
[Dependency] private readonly SharedAppearanceSystem _appearance = default!;
[Dependency] private readonly EntityWhitelistSystem _whitelistSystem = default!;
+ [Dependency] private readonly AugmentPowerCellSystem _augments = default!; // DeltaV - bodies can have an augment power cell
public override void Initialize()
{
@@ -250,15 +252,45 @@ internal sealed class ChargerSystem : EntitySystem
UpdateStatus(uid, component);
}
- private bool SearchForBattery(EntityUid uid, [NotNullWhen(true)] out EntityUid? batteryUid, [NotNullWhen(true)] out BatteryComponent? component)
+ // Begin DeltaV - event-based search for battery
+ public bool SearchForBattery(EntityUid uid, [NotNullWhen(true)] out EntityUid? batteryUid, [NotNullWhen(true)] out BatteryComponent? component)
{
// try get a battery directly on the inserted entity
- if (!TryComp(uid, out component))
+ if (TryComp(uid, out component))
{
- // or by checking for a power cell slot on the inserted entity
- return _powerCell.TryGetBatteryFromSlot(uid, out batteryUid, out component);
+ batteryUid = uid;
+ return true;
}
- batteryUid = uid;
- return true;
+
+ var evt = new SearchForBatteryEvent();
+ RaiseLocalEvent(uid, ref evt);
+ if (evt.Handled)
+ {
+ batteryUid = evt.Uid;
+ component = evt.Component;
+ return evt.Handled;
+ }
+
+ batteryUid = null;
+ component = null;
+ return false;
}
+ // End DeltaV - event-based search for battery
}
+
+// Begin DeltaV - event-based search for battery
+
+///
+/// Event raised to search for batteries within an entity
+///
+[ByRefEvent]
+public struct SearchForBatteryEvent
+{
+ public EntityUid? Uid;
+
+ public BatteryComponent? Component;
+
+ public bool Handled;
+}
+
+// End DeltaV - event-based search for battery
diff --git a/Content.Server/PowerCell/PowerCellSystem.cs b/Content.Server/PowerCell/PowerCellSystem.cs
index dfbb02e73d..0a1443b761 100644
--- a/Content.Server/PowerCell/PowerCellSystem.cs
+++ b/Content.Server/PowerCell/PowerCellSystem.cs
@@ -42,8 +42,16 @@ public sealed partial class PowerCellSystem : SharedPowerCellSystem
SubscribeLocalEvent(OnCellSlotExamined);
// funny
SubscribeLocalEvent(OnSlotMicrowaved);
+ SubscribeLocalEvent(OnSearchForBattery); // DeltaV - event-based search for battery
}
+ // Begin DeltaV - event-based search for battery
+ private void OnSearchForBattery(Entity ent, ref SearchForBatteryEvent args)
+ {
+ args.Handled = TryGetBatteryFromSlot(ent, out args.Uid, out args.Component);
+ }
+ // End DeltaV - event-based search for battery
+
private void OnSlotMicrowaved(EntityUid uid, PowerCellSlotComponent component, BeingMicrowavedEvent args)
{
if (!_itemSlotsSystem.TryGetSlot(uid, component.CellSlotId, out var slot))
diff --git a/Content.Server/_DV/Augments/AugmentPowerCellSystem.cs b/Content.Server/_DV/Augments/AugmentPowerCellSystem.cs
new file mode 100644
index 0000000000..347661f6d8
--- /dev/null
+++ b/Content.Server/_DV/Augments/AugmentPowerCellSystem.cs
@@ -0,0 +1,128 @@
+using Content.Server.Power.Components; // ough BatteryComponent why are you in server
+using Content.Server.Power.EntitySystems;
+using Content.Server.PowerCell;
+using Content.Shared._DV.Augments;
+using Content.Shared.Alert;
+using Content.Shared.Body.Organ;
+using Content.Shared.Body.Systems;
+using Content.Shared.Mobs.Systems;
+using Content.Shared.Popups;
+using Content.Shared.PowerCell.Components;
+
+namespace Content.Server._DV.Augments;
+
+public sealed class AugmentPowerCellSystem : EntitySystem
+{
+ [Dependency] private readonly AlertsSystem _alerts = default!;
+ [Dependency] private readonly BatterySystem _battery = default!;
+ [Dependency] private readonly MobStateSystem _mobState = default!;
+ [Dependency] private readonly PowerCellSystem _powerCell = default!;
+ [Dependency] private readonly SharedBodySystem _body = default!;
+ [Dependency] private readonly SharedPopupSystem _popup = default!;
+
+ public override void Initialize()
+ {
+ base.Initialize();
+
+ SubscribeLocalEvent(OnSearchForBattery);
+ }
+
+ private void OnSearchForBattery(Entity ent, ref SearchForBatteryEvent args)
+ {
+ // or by checking for an augment power cell
+ if (TryGetAugmentPowerCell(ent) is (_, var insertedBattery) && insertedBattery is {} battery)
+ {
+ args.Uid = battery.Owner;
+ args.Component = battery.Comp;
+ args.Handled = true;
+ return;
+ }
+ }
+
+ public (Entity Organ, Entity? Battery)? TryGetAugmentPowerCell(EntityUid body)
+ {
+ foreach (var organ in _body.GetBodyOrganEntityComps(body))
+ {
+ if (!TryComp(organ, out var powerCellSlot))
+ continue;
+
+ var entity = new Entity(organ.Owner, organ.Comp1, organ.Comp2, powerCellSlot);
+
+ if (_powerCell.TryGetBatteryFromSlot(organ, out var batteryUid, out var batteryComp))
+ {
+ return (entity, new(batteryUid.Value, batteryComp));
+ }
+ return (entity, null);
+ }
+ return null;
+ }
+
+ public (Entity Organ, Entity? Battery)? TryGetAugmentPowerCellFromAugment(EntityUid augment)
+ {
+ if (!TryComp(augment, out var organ) || organ.Body is not {} uid)
+ return null;
+
+ return TryGetAugmentPowerCell(uid);
+ }
+
+ public bool TryDrawPower(EntityUid augment, float amount)
+ {
+ if (!TryComp(augment, out var organ) || organ.Body is not {} body)
+ return false;
+
+ if (TryGetAugmentPowerCellFromAugment(augment) is not (_, var battery))
+ {
+ _popup.PopupEntity(Loc.GetString("augments-no-power-cell-slot"), body, body);
+ return false;
+ }
+
+ if (battery is not {} insertedBattery)
+ {
+ _popup.PopupEntity(Loc.GetString("power-cell-no-battery"), body, body);
+ return false;
+ }
+
+ if (!_battery.TryUseCharge(insertedBattery.Owner, amount))
+ {
+ _popup.PopupEntity(Loc.GetString("power-cell-insufficient"), body, body);
+ return false;
+ }
+
+ return true;
+ }
+
+ public override void Update(float frameTime)
+ {
+ base.Update(frameTime);
+
+ var query = EntityQueryEnumerator();
+ while (query.MoveNext(out var owner, out _))
+ {
+ if (_mobState.IsDead(owner))
+ continue;
+
+ var powerCell = TryGetAugmentPowerCell(owner);
+ if (powerCell is not {} power)
+ continue;
+ var augment = power.Organ;
+
+ if (power.Battery is not {} insertedBattery)
+ {
+ if (_alerts.IsShowingAlert(owner, augment.Comp1.BatteryAlert))
+ {
+ _alerts.ClearAlert(owner, augment.Comp1.BatteryAlert);
+ _alerts.ShowAlert(owner, augment.Comp1.NoBatteryAlert);
+ }
+ continue;
+ }
+
+ if (_alerts.IsShowingAlert(owner, augment.Comp1.NoBatteryAlert))
+ {
+ _alerts.ClearAlert(owner, augment.Comp1.NoBatteryAlert);
+ }
+
+ var chargePercent = (short) MathF.Round(insertedBattery.Comp.CurrentCharge / insertedBattery.Comp.MaxCharge * 10f);
+ _alerts.ShowAlert(owner, augment.Comp1.BatteryAlert, chargePercent);
+ }
+ }
+}
diff --git a/Content.Server/_DV/Augments/AugmentToolPanelSystem.cs b/Content.Server/_DV/Augments/AugmentToolPanelSystem.cs
new file mode 100644
index 0000000000..8aeb0f6cd6
--- /dev/null
+++ b/Content.Server/_DV/Augments/AugmentToolPanelSystem.cs
@@ -0,0 +1,93 @@
+using System.Linq;
+using Content.Server.Power.EntitySystems;
+using Content.Shared._DV.Augments;
+using Content.Shared.Body.Organ;
+using Content.Shared.Body.Part;
+using Content.Shared.Body.Systems;
+using Content.Shared.Hands.Components;
+using Content.Shared.Hands.EntitySystems;
+using Content.Shared.Popups;
+using Content.Shared.Storage.EntitySystems;
+using Robust.Shared.Containers;
+
+namespace Content.Server._DV.Augments;
+
+public sealed class AugmentToolPanelSystem : EntitySystem
+{
+ [Dependency] private readonly SharedHandsSystem _hands = default!;
+ [Dependency] private readonly SharedPopupSystem _popup = default!;
+ [Dependency] private readonly SharedBodySystem _body = default!;
+ [Dependency] private readonly SharedContainerSystem _container = default!;
+ [Dependency] private readonly SharedStorageSystem _storage = default!;
+ [Dependency] private readonly AugmentPowerCellSystem _augmentPowerCell = default!;
+
+ public override void Initialize()
+ {
+ base.Initialize();
+
+ Subs.BuiEvents(AugmentToolPanelUiKey.Key, subs =>
+ {
+ subs.Event(OnSwitchTool);
+ });
+ }
+
+ private void OnSwitchTool(Entity augment, ref AugmentToolPanelSystemMessage args)
+ {
+ if (!TryComp(augment, out var organ) || organ.Body is not {} body)
+ return;
+
+ if (!TryComp(body, out var hands))
+ return;
+
+ if (!_container.TryGetContainingContainer(augment.Owner, out var container))
+ return;
+
+ if (!_augmentPowerCell.TryDrawPower(augment, augment.Comp.PowerDrawOnSwitch))
+ return;
+
+ foreach (var part in _body.GetBodyPartChildren(container.Owner))
+ {
+ if (part.Component.PartType != BodyPartType.Hand)
+ continue;
+
+ var handLocation = part.Component.Symmetry switch {
+ BodyPartSymmetry.None => HandLocation.Middle,
+ BodyPartSymmetry.Left => HandLocation.Left,
+ BodyPartSymmetry.Right => HandLocation.Right,
+ _ => throw new InvalidOperationException(),
+ };
+
+ var desiredHand = hands.Hands.Values.FirstOrDefault(hand => hand.Location == handLocation);
+ if (desiredHand == null)
+ continue;
+
+ // if we have a tool that's currently out
+ if (HasComp(desiredHand.HeldEntity))
+ {
+ // deposit it back into the storage
+ RemComp(desiredHand.HeldEntity!.Value);
+
+ if (!_storage.PlayerInsertEntityInWorld(augment.Owner, body, desiredHand.HeldEntity!.Value))
+ {
+ EnsureComp(desiredHand.HeldEntity!.Value);
+ return;
+ }
+ }
+ else if (desiredHand.HeldEntity is not null)
+ {
+ _popup.PopupCursor(Loc.GetString("augment-tool-panel-hand-full"), body);
+ return;
+ }
+
+ if (GetEntity(args.DesiredTool) is not {} desiredTool)
+ return;
+
+ if (!_hands.TryPickup(body, desiredTool, desiredHand))
+ {
+ _popup.PopupCursor(Loc.GetString("augment-tool-panel-cannot-pick-up"), body);
+ return;
+ }
+ EnsureComp(desiredTool);
+ }
+ }
+}
diff --git a/Content.Server/_EE/Power/Systems/BatteryDrinkerSystem.cs b/Content.Server/_EE/Power/Systems/BatteryDrinkerSystem.cs
index 6e2307181e..5e2601c40c 100644
--- a/Content.Server/_EE/Power/Systems/BatteryDrinkerSystem.cs
+++ b/Content.Server/_EE/Power/Systems/BatteryDrinkerSystem.cs
@@ -28,6 +28,7 @@ public sealed class BatteryDrinkerSystem : EntitySystem
[Dependency] private readonly PopupSystem _popup = default!;
[Dependency] private readonly PowerCellSystem _powerCell = default!;
[Dependency] private readonly SharedContainerSystem _container = default!;
+ [Dependency] private readonly ChargerSystem _chargers = default!; // DeltaV - people with augment power cells can drink batteries
public override void Initialize()
{
@@ -45,7 +46,8 @@ public sealed class BatteryDrinkerSystem : EntitySystem
if (!TryComp(args.User, out var drinkerComp) ||
!TestDrinkableBattery(uid, drinkerComp) ||
- !_silicon.TryGetSiliconBattery(args.User, out var drinkerBattery))
+ // DeltaV - people with augment power cells can drink batteries
+ !_chargers.SearchForBattery(args.User, out _, out _))
return;
AlternativeVerb verb = new()
@@ -97,21 +99,13 @@ public sealed class BatteryDrinkerSystem : EntitySystem
var drinker = uid;
var sourceBattery = Comp(source);
- _silicon.TryGetSiliconBattery(drinker, out var drinkerBatteryComponent);
-
- if (!TryComp(uid, out PowerCellSlotComponent? batterySlot))
+ // DeltaV - people with augment power cells can drink batteries
+ if (!_chargers.SearchForBattery(drinker, out var drinkerBattery, out var drinkerBatteryComponent))
return;
- var container = _container.GetContainer(uid, batterySlot.CellSlotId);
- var drinkerBattery = container.ContainedEntities.First();
-
+ // DeltaV - people with augment power cells can drink batteries
TryComp(source, out var sourceComp);
- DebugTools.AssertNotNull(drinkerBattery);
-
- if (drinkerBattery == null)
- return;
-
var amountToDrink = drinkerComp.DrinkMultiplier * 1000;
amountToDrink = MathF.Min(amountToDrink, sourceBattery.CurrentCharge);
@@ -127,10 +121,10 @@ public sealed class BatteryDrinkerSystem : EntitySystem
}
if (_battery.TryUseCharge(source, amountToDrink))
- _battery.SetCharge(drinkerBattery, drinkerBatteryComponent.CurrentCharge + amountToDrink, drinkerBatteryComponent);
+ _battery.SetCharge(drinkerBattery.Value, drinkerBatteryComponent.CurrentCharge + amountToDrink, drinkerBatteryComponent); // DeltaV - people with augment power cells can drink batteries
else
{
- _battery.SetCharge(drinkerBattery, sourceBattery.CurrentCharge + drinkerBatteryComponent.CurrentCharge, drinkerBatteryComponent);
+ _battery.SetCharge(drinkerBattery.Value, sourceBattery.CurrentCharge + drinkerBatteryComponent.CurrentCharge, drinkerBatteryComponent); // DeltaV - people with augment power cells can drink batteries
_battery.SetCharge(source, 0);
}
diff --git a/Content.Shared/_DV/Augments/AugmentActionComponent.cs b/Content.Shared/_DV/Augments/AugmentActionComponent.cs
new file mode 100644
index 0000000000..181823eea8
--- /dev/null
+++ b/Content.Shared/_DV/Augments/AugmentActionComponent.cs
@@ -0,0 +1,9 @@
+using Robust.Shared.GameStates;
+
+namespace Content.Shared._DV.Augments;
+
+///
+/// Component that allows an augment to have actions
+///
+[RegisterComponent, NetworkedComponent]
+public sealed partial class AugmentActionComponent : Component;
diff --git a/Content.Shared/_DV/Augments/AugmentActionSystem.cs b/Content.Shared/_DV/Augments/AugmentActionSystem.cs
new file mode 100644
index 0000000000..c157d18215
--- /dev/null
+++ b/Content.Shared/_DV/Augments/AugmentActionSystem.cs
@@ -0,0 +1,38 @@
+using Content.Shared._Shitmed.Body.Organ;
+using Content.Shared.Actions;
+using Content.Shared.Body.Organ;
+
+namespace Content.Shared._DV.Augments;
+
+public sealed class AugmentActionSystem : EntitySystem
+{
+ [Dependency] private readonly SharedActionsSystem _actions = default!;
+ [Dependency] private readonly ActionContainerSystem _actionContainer = default!;
+
+ public override void Initialize()
+ {
+ base.Initialize();
+
+ SubscribeLocalEvent(OnOrganEnableChanged);
+ }
+
+ private void OnOrganEnableChanged(Entity augment, ref OrganEnableChangedEvent args)
+ {
+ if (!TryComp(augment, out var organ) || organ.Body is not {} body)
+ return;
+
+ var actionsComponent = EnsureComp(body);
+
+ if (args.Enabled)
+ {
+ var ev = new GetItemActionsEvent(_actionContainer, body, augment);
+ RaiseLocalEvent(augment, ev);
+
+ _actions.GrantActions(body, ev.Actions, augment, actionsComponent);
+ }
+ else
+ {
+ _actions.RemoveProvidedActions(body, augment, actionsComponent);
+ }
+ }
+}
diff --git a/Content.Shared/_DV/Augments/AugmentActivatableUIComponent.cs b/Content.Shared/_DV/Augments/AugmentActivatableUIComponent.cs
new file mode 100644
index 0000000000..40b64496e3
--- /dev/null
+++ b/Content.Shared/_DV/Augments/AugmentActivatableUIComponent.cs
@@ -0,0 +1,27 @@
+using Content.Shared.Actions;
+using Robust.Shared.GameStates;
+using Robust.Shared.Prototypes;
+using Robust.Shared.Serialization.TypeSerializers.Implementations;
+
+namespace Content.Shared._DV.Augments;
+
+///
+/// Component that allows an augment to have a user interface
+///
+[RegisterComponent, NetworkedComponent, AutoGenerateComponentState]
+public sealed partial class AugmentActivatableUIComponent : Component
+{
+ [DataField(required: true, customTypeSerializer: typeof(EnumSerializer))]
+ public Enum? Key;
+
+ [DataField]
+ public EntProtoId OpenAction = "ActionOpenAugmentInterface";
+
+ [DataField, AutoNetworkedField]
+ public EntityUid? OpenActionEntity;
+}
+
+///
+/// Event that should be dispatched by the to open the UI
+///
+public sealed partial class AugmentUIOpenEvent : InstantActionEvent;
diff --git a/Content.Shared/_DV/Augments/AugmentActivatableUISystem.cs b/Content.Shared/_DV/Augments/AugmentActivatableUISystem.cs
new file mode 100644
index 0000000000..46f2e41e93
--- /dev/null
+++ b/Content.Shared/_DV/Augments/AugmentActivatableUISystem.cs
@@ -0,0 +1,39 @@
+using Content.Shared._Shitmed.Body.Organ;
+using Content.Shared.Actions;
+using Content.Shared.Body.Organ;
+using Robust.Shared.GameObjects;
+
+namespace Content.Shared._DV.Augments;
+
+public sealed class AugmentActivatableUISystem : EntitySystem
+{
+ [Dependency] private readonly SharedUserInterfaceSystem _uiSystem = default!;
+
+ public override void Initialize()
+ {
+ base.Initialize();
+
+ SubscribeLocalEvent(OnOpen);
+ SubscribeLocalEvent(OnGetActions);
+ }
+
+ private void OnOpen(Entity augment, ref AugmentUIOpenEvent args)
+ {
+ if (!TryComp(augment, out var organ) || organ.Body is not {} body)
+ return;
+
+ if (augment.Comp.Key == null || !_uiSystem.HasUi(augment, augment.Comp.Key))
+ return;
+
+ _uiSystem.OpenUi(augment.Owner, augment.Comp.Key, body);
+ args.Handled = true;
+ }
+
+ private void OnGetActions(Entity ent, ref GetItemActionsEvent args)
+ {
+ if (!TryComp(ent, out var organ) || organ.Body is not {} body)
+ return;
+
+ args.AddAction(ref ent.Comp.OpenActionEntity, ent.Comp.OpenAction);
+ }
+}
diff --git a/Content.Shared/_DV/Augments/AugmentArmComponent.cs b/Content.Shared/_DV/Augments/AugmentArmComponent.cs
new file mode 100644
index 0000000000..3268176a38
--- /dev/null
+++ b/Content.Shared/_DV/Augments/AugmentArmComponent.cs
@@ -0,0 +1,9 @@
+using Robust.Shared.GameStates;
+
+namespace Content.Shared._DV.Augments;
+
+///
+/// Marker component to indicate that an entity serves as an AugmentArm organ
+///
+[RegisterComponent, NetworkedComponent]
+public sealed partial class AugmentArmComponent : Component;
diff --git a/Content.Shared/_DV/Augments/AugmentChargerComponent.cs b/Content.Shared/_DV/Augments/AugmentChargerComponent.cs
new file mode 100644
index 0000000000..5e2ecef486
--- /dev/null
+++ b/Content.Shared/_DV/Augments/AugmentChargerComponent.cs
@@ -0,0 +1,16 @@
+using Robust.Shared.GameStates;
+
+namespace Content.Shared._DV.Augments;
+
+///
+/// Marker component to indicate that an entity serves as an AugmentCharger organ
+///
+[RegisterComponent, NetworkedComponent]
+public sealed partial class AugmentChargerComponent : Component;
+
+///
+/// Marker component to indicate that an entity will recharge its augment power cell from borg charging stations
+///
+[RegisterComponent, NetworkedComponent]
+public sealed partial class AugmentStationRechargeComponent : Component;
+
diff --git a/Content.Shared/_DV/Augments/AugmentComponent.cs b/Content.Shared/_DV/Augments/AugmentComponent.cs
new file mode 100644
index 0000000000..a8fd1364ca
--- /dev/null
+++ b/Content.Shared/_DV/Augments/AugmentComponent.cs
@@ -0,0 +1,19 @@
+using Robust.Shared.GameStates;
+
+namespace Content.Shared._DV.Augments;
+
+///
+/// Component that indicates an entity is an augment
+///
+[RegisterComponent, NetworkedComponent]
+public sealed partial class AugmentComponent : Component;
+
+///
+/// Component that tracks which augments are installed on this body
+///
+[RegisterComponent, NetworkedComponent]
+public sealed partial class InstalledAugmentsComponent : Component
+{
+ [DataField]
+ public HashSet InstalledAugments = new();
+}
diff --git a/Content.Shared/_DV/Augments/AugmentPowerCellSlot.cs b/Content.Shared/_DV/Augments/AugmentPowerCellSlot.cs
new file mode 100644
index 0000000000..3a4a1cdd15
--- /dev/null
+++ b/Content.Shared/_DV/Augments/AugmentPowerCellSlot.cs
@@ -0,0 +1,24 @@
+using Robust.Shared.GameStates;
+using Robust.Shared.Prototypes;
+using Content.Shared.Alert;
+
+namespace Content.Shared._DV.Augments;
+
+///
+/// Component for entitie that serve as AugmentPowerCellSlot organs
+///
+[RegisterComponent, NetworkedComponent]
+public sealed partial class AugmentPowerCellSlotComponent : Component
+{
+ [DataField]
+ public ProtoId BatteryAlert = "BorgBattery";
+
+ [DataField]
+ public ProtoId NoBatteryAlert = "BorgBatteryNone";
+}
+
+///
+/// Marker component to indicate that an entity currently has an AugmentPowerCellSlot organ
+///
+[RegisterComponent, NetworkedComponent]
+public sealed partial class HasAugmentPowerCellSlotComponent : Component;
diff --git a/Content.Shared/_DV/Augments/AugmentSystem.cs b/Content.Shared/_DV/Augments/AugmentSystem.cs
new file mode 100644
index 0000000000..f54cd84555
--- /dev/null
+++ b/Content.Shared/_DV/Augments/AugmentSystem.cs
@@ -0,0 +1,42 @@
+using Content.Shared.Body.Events;
+using Content.Shared.Body.Organ;
+using Content.Shared.Interaction;
+
+namespace Content.Shared._DV.Augments;
+
+public sealed class AugmentSystem : EntitySystem
+{
+ public override void Initialize()
+ {
+ base.Initialize();
+
+ SubscribeLocalEvent(OnOrganOrganAddedToBody);
+ SubscribeLocalEvent(OnOrganOrganRemovedFromBody);
+ SubscribeLocalEvent(OnAccessibleOverride);
+ }
+
+ private void OnOrganOrganAddedToBody(Entity augment, ref OrganAddedToBodyEvent args)
+ {
+ var installed = EnsureComp(args.Body);
+ installed.InstalledAugments.Add(GetNetEntity(augment));
+ }
+
+ private void OnOrganOrganRemovedFromBody(Entity augment, ref OrganRemovedFromBodyEvent args)
+ {
+ if (!TryComp(args.OldBody, out var installed))
+ return;
+
+ installed.InstalledAugments.Remove(GetNetEntity(augment));
+ if (installed.InstalledAugments.Count == 0)
+ RemComp(args.OldBody);
+ }
+
+ private void OnAccessibleOverride(Entity augment, ref AccessibleOverrideEvent args)
+ {
+ if (!TryComp(args.Target, out var organ))
+ return;
+
+ args.Handled = true;
+ args.Accessible = organ.Body == args.User;
+ }
+}
diff --git a/Content.Shared/_DV/Augments/AugmentToolPanelComponent.cs b/Content.Shared/_DV/Augments/AugmentToolPanelComponent.cs
new file mode 100644
index 0000000000..51b9ae2b58
--- /dev/null
+++ b/Content.Shared/_DV/Augments/AugmentToolPanelComponent.cs
@@ -0,0 +1,38 @@
+using Robust.Shared.GameStates;
+using Robust.Shared.Serialization;
+using Robust.Shared.Prototypes;
+
+namespace Content.Shared._DV.Augments;
+
+///
+/// Marker component to indicate that an entity will allow access to its storage via a radial menu once implanted
+///
+[RegisterComponent, NetworkedComponent]
+public sealed partial class AugmentToolPanelComponent : Component
+{
+ [DataField]
+ public float PowerDrawOnSwitch = 10f;
+}
+
+///
+/// Marker component to indicate that an entity is the active tool of an augment tool panel
+///
+[RegisterComponent, NetworkedComponent]
+public sealed partial class AugmentToolPanelActiveItemComponent : Component;
+
+[Serializable, NetSerializable]
+public sealed class AugmentToolPanelSystemMessage : BoundUserInterfaceMessage
+{
+ public NetEntity? DesiredTool;
+
+ public AugmentToolPanelSystemMessage(NetEntity? desiredTool)
+ {
+ DesiredTool = desiredTool;
+ }
+}
+
+[Serializable, NetSerializable]
+public enum AugmentToolPanelUiKey : byte
+{
+ Key
+}
diff --git a/Content.Shared/_DV/Augments/SharedAugmentToolPanelSystem.cs b/Content.Shared/_DV/Augments/SharedAugmentToolPanelSystem.cs
new file mode 100644
index 0000000000..b0b5aaa0ea
--- /dev/null
+++ b/Content.Shared/_DV/Augments/SharedAugmentToolPanelSystem.cs
@@ -0,0 +1,19 @@
+using Content.Shared.Hands;
+using Robust.Shared.Containers;
+
+namespace Content.Shared._DV.Augments;
+
+public sealed class SharedAugmentToolPanelSystem : EntitySystem
+{
+ public override void Initialize()
+ {
+ base.Initialize();
+
+ SubscribeLocalEvent(OnDropAttempt);
+ }
+
+ private void OnDropAttempt(Entity ent, ref ContainerGettingRemovedAttemptEvent args)
+ {
+ args.Cancel();
+ }
+}
diff --git a/Content.Shared/_Shitmed/Surgery/Conditions/SurgeryBodyConditionComponent.cs b/Content.Shared/_Shitmed/Surgery/Conditions/SurgeryBodyConditionComponent.cs
new file mode 100644
index 0000000000..8dd3d2a4d6
--- /dev/null
+++ b/Content.Shared/_Shitmed/Surgery/Conditions/SurgeryBodyConditionComponent.cs
@@ -0,0 +1,18 @@
+using Robust.Shared.GameStates;
+using Robust.Shared.Prototypes;
+using Content.Shared.Body.Prototypes;
+
+namespace Content.Shared._Shitmed.Medical.Surgery.Conditions;
+
+///
+/// Requires that this surgery is (not) done on one of the provided body prototypes
+///
+[RegisterComponent, NetworkedComponent]
+public sealed partial class SurgeryBodyConditionComponent : Component
+{
+ [DataField(required: true)]
+ public HashSet> Accepted = default!;
+
+ [DataField]
+ public bool Inverse;
+}
diff --git a/Content.Shared/_Shitmed/Surgery/Conditions/SurgeryOrganSlotConditionComponent.cs b/Content.Shared/_Shitmed/Surgery/Conditions/SurgeryOrganSlotConditionComponent.cs
new file mode 100644
index 0000000000..67ebe0546f
--- /dev/null
+++ b/Content.Shared/_Shitmed/Surgery/Conditions/SurgeryOrganSlotConditionComponent.cs
@@ -0,0 +1,13 @@
+using Robust.Shared.GameStates;
+
+namespace Content.Shared._Shitmed.Medical.Surgery.Conditions;
+
+[RegisterComponent, NetworkedComponent]
+public sealed partial class SurgeryOrganSlotConditionComponent : Component
+{
+ [DataField(required: true)]
+ public string OrganSlot = default!;
+
+ [DataField]
+ public bool Inverse;
+}
diff --git a/Content.Shared/_Shitmed/Surgery/SharedSurgerySystem.Steps.cs b/Content.Shared/_Shitmed/Surgery/SharedSurgerySystem.Steps.cs
index dd0d28600f..868ea862d3 100644
--- a/Content.Shared/_Shitmed/Surgery/SharedSurgerySystem.Steps.cs
+++ b/Content.Shared/_Shitmed/Surgery/SharedSurgerySystem.Steps.cs
@@ -55,6 +55,7 @@ public abstract partial class SharedSurgerySystem
SubSurgery(OnAffixOrganStep, OnAffixOrganCheck);
SubSurgery(OnAddMarkingStep, OnAddMarkingCheck);
SubSurgery(OnRemoveMarkingStep, OnRemoveMarkingCheck);
+ SubSurgery(OnAddOrganSlotStep, OnAddOrganSlotCheck);
Subs.BuiEvents(SurgeryUIKey.Key, subs =>
{
subs.Event(OnSurgeryTargetStepChosen);
@@ -449,6 +450,22 @@ public abstract partial class SharedSurgerySystem
}
}
+ private void OnAddOrganSlotStep(Entity ent, ref SurgeryStepEvent args)
+ {
+ if (!TryComp(args.Surgery, out SurgeryOrganSlotConditionComponent? condition))
+ return;
+
+ _body.TryCreateOrganSlot(args.Part, condition.OrganSlot, out _);
+ }
+
+ private void OnAddOrganSlotCheck(Entity ent, ref SurgeryStepCompleteCheckEvent args)
+ {
+ if (!TryComp(args.Surgery, out SurgeryOrganSlotConditionComponent? condition))
+ return;
+
+ args.Cancelled = !_body.CanInsertOrgan(args.Part, condition.OrganSlot);
+ }
+
private void OnAffixPartStep(Entity ent, ref SurgeryStepEvent args)
{
if (!TryComp(args.Surgery, out SurgeryPartRemovedConditionComponent? removedComp))
diff --git a/Content.Shared/_Shitmed/Surgery/SharedSurgerySystem.cs b/Content.Shared/_Shitmed/Surgery/SharedSurgerySystem.cs
index 58638bd4df..94117932ad 100644
--- a/Content.Shared/_Shitmed/Surgery/SharedSurgerySystem.cs
+++ b/Content.Shared/_Shitmed/Surgery/SharedSurgerySystem.cs
@@ -79,6 +79,8 @@ public abstract partial class SharedSurgerySystem : EntitySystem
SubscribeLocalEvent(OnOrganConditionValid);
SubscribeLocalEvent(OnWoundedValid);
SubscribeLocalEvent(OnPartRemovedConditionValid);
+ SubscribeLocalEvent(OnBodyConditionValid);
+ SubscribeLocalEvent(OnOrganSlotConditionValid);
SubscribeLocalEvent(OnPartPresentConditionValid);
SubscribeLocalEvent(OnMarkingPresentValid);
SubscribeLocalEvent(OnBodyComponentConditionValid);
@@ -278,6 +280,17 @@ public abstract partial class SharedSurgerySystem : EntitySystem
}
}
+ private void OnBodyConditionValid(Entity ent, ref SurgeryValidEvent args)
+ {
+ if (TryComp(args.Body, out var body) && body.Prototype is {} bodyId)
+ args.Cancelled = ent.Comp.Accepted.Contains(bodyId) ^ !ent.Comp.Inverse;
+ }
+
+ private void OnOrganSlotConditionValid(Entity ent, ref SurgeryValidEvent args)
+ {
+ args.Cancelled = _body.CanInsertOrgan(args.Part, ent.Comp.OrganSlot) ^ !ent.Comp.Inverse;
+ }
+
private void OnPartRemovedConditionValid(Entity ent, ref SurgeryValidEvent args)
{
if (!_body.CanAttachToSlot(args.Part, ent.Comp.Connection))
diff --git a/Content.Shared/_Shitmed/Surgery/Steps/SurgeryAddOrganSlotStepComponent.cs b/Content.Shared/_Shitmed/Surgery/Steps/SurgeryAddOrganSlotStepComponent.cs
new file mode 100644
index 0000000000..b77c886a1a
--- /dev/null
+++ b/Content.Shared/_Shitmed/Surgery/Steps/SurgeryAddOrganSlotStepComponent.cs
@@ -0,0 +1,6 @@
+using Robust.Shared.GameStates;
+
+namespace Content.Shared._Shitmed.Medical.Surgery.Steps;
+
+[RegisterComponent, NetworkedComponent]
+public sealed partial class SurgeryAddOrganSlotStepComponent : Component;
diff --git a/Resources/Locale/en-US/_DV/augments/augments.ftl b/Resources/Locale/en-US/_DV/augments/augments.ftl
new file mode 100644
index 0000000000..c7888db493
--- /dev/null
+++ b/Resources/Locale/en-US/_DV/augments/augments.ftl
@@ -0,0 +1,3 @@
+augments-no-power-cell-slot = You don't have a power cell slot installed
+augment-tool-panel-hand-full = There's something in your hand
+augment-tool-panel-cannot-pick-up = Your hand isn't capable of holding that
diff --git a/Resources/Locale/en-US/_DV/augments/surgeries.ftl b/Resources/Locale/en-US/_DV/augments/surgeries.ftl
new file mode 100644
index 0000000000..aa048db176
--- /dev/null
+++ b/Resources/Locale/en-US/_DV/augments/surgeries.ftl
@@ -0,0 +1,3 @@
+surgery-popup-step-SurgeryStepInsertAugmentPowerCellSlot = {$user} is inserting a power cell slot into {$target}'s {$part}.
+surgery-popup-step-SurgeryStepInsertAugmentPowerCellCharger = {$user} is inserting a power cell recharger into {$target}'s {$part}.
+surgery-popup-step-SurgeryStepInsertAugmentArm = {$user} is inserting an augment into {$target}'s {$part}.
diff --git a/Resources/Locale/en-US/_DV/research/technologies.ftl b/Resources/Locale/en-US/_DV/research/technologies.ftl
index 4c94820670..42e87c7f5f 100644
--- a/Resources/Locale/en-US/_DV/research/technologies.ftl
+++ b/Resources/Locale/en-US/_DV/research/technologies.ftl
@@ -7,6 +7,8 @@ research-technology-cloning = Cloning
# Civilian
research-technology-syringe-gun = Syringe Gun
+research-technology-basic-augmentation = Basic Augmentation
+research-technology-implanted-tools = Implanted Tools
# Arsenal
research-technology-exotic-ammunition = Exotic Ammunition
diff --git a/Resources/Locale/en-US/_Shitmed/surgery/surgery-popup.ftl b/Resources/Locale/en-US/_Shitmed/surgery/surgery-popup.ftl
index 5d5c062f09..b8374074c5 100644
--- a/Resources/Locale/en-US/_Shitmed/surgery/surgery-popup.ftl
+++ b/Resources/Locale/en-US/_Shitmed/surgery/surgery-popup.ftl
@@ -35,6 +35,8 @@ surgery-popup-step-SurgeryStepRemoveItem = {$user} is removing something from {$
surgery-popup-step-SurgeryStepRemoveOrgan = {$user} is removing an organ from {$target}'s {$part}!
surgery-popup-step-SurgeryStepInsertOrgan = {$user} is inserting an organ into {$target}'s {$part}!
+surgery-popup-step-SurgeryStepOpenOrganSlot = {$user} is opening a cavity in {$target}'s {$part}!
+
surgery-popup-procedure-SurgeryRemoveBrain-step-SurgeryStepRemoveOrgan = {$user} is removing the brain from {$target}'s {$part}!
surgery-popup-procedure-SurgeryRemoveHeart-step-SurgeryStepRemoveOrgan = {$user} is removing the heart from {$target}'s {$part}!
surgery-popup-procedure-SurgeryRemoveLiver-step-SurgeryStepRemoveOrgan = {$user} is removing the liver from {$target}'s {$part}!
diff --git a/Resources/Prototypes/Entities/Objects/Devices/Circuitboards/Machine/production.yml b/Resources/Prototypes/Entities/Objects/Devices/Circuitboards/Machine/production.yml
index d72e9b7eb7..43dd19a24e 100644
--- a/Resources/Prototypes/Entities/Objects/Devices/Circuitboards/Machine/production.yml
+++ b/Resources/Prototypes/Entities/Objects/Devices/Circuitboards/Machine/production.yml
@@ -701,6 +701,8 @@
Plastic: 30
- type: StaticPrice
price: 15
+ - type: Tag # DeltaV - augment construction
+ tags: [ AugmentAPCBoard ]
- type: entity
id: PowerCageRechargerCircuitboard
@@ -744,6 +746,8 @@
Plastic: 30
- type: StaticPrice
price: 15
+ - type: Tag # DeltaV - augment construction
+ tags: [ AugmentStationBoard ]
- type: entity
id: WeaponCapacitorRechargerCircuitboard
diff --git a/Resources/Prototypes/Entities/Structures/Machines/lathe.yml b/Resources/Prototypes/Entities/Structures/Machines/lathe.yml
index 45359ec4eb..26b8ca83b8 100644
--- a/Resources/Prototypes/Entities/Structures/Machines/lathe.yml
+++ b/Resources/Prototypes/Entities/Structures/Machines/lathe.yml
@@ -325,6 +325,8 @@
- MechParts
- MechEquipment
- Cybernetics # Shitmed change
+ - PowerAugments # DeltaV - augments
+ - ToolAugments # DeltaV - augments
- type: EmagLatheRecipes # DeltaV
emagStaticPacks:
- RoboticsEmagStatic
diff --git a/Resources/Prototypes/Entities/Structures/Power/chargers.yml b/Resources/Prototypes/Entities/Structures/Power/chargers.yml
index b6f67ba7bf..9bacbd3c30 100644
--- a/Resources/Prototypes/Entities/Structures/Power/chargers.yml
+++ b/Resources/Prototypes/Entities/Structures/Power/chargers.yml
@@ -248,6 +248,7 @@
components:
- BorgChassis
- Silicon # EE IPCs
+ - AugmentStationRecharge # DeltaV augment power cells
- type: Construction
containers:
- machine_parts
@@ -291,6 +292,8 @@
whitelist:
components:
- BorgChassis
+ - Silicon # EE IPCs
+ - AugmentStationRecharge # DeltaV augment power cells
- type: ContainerContainer
containers:
entity_storage: !type:Container
diff --git a/Resources/Prototypes/_DV/Augments/arm.yml b/Resources/Prototypes/_DV/Augments/arm.yml
new file mode 100644
index 0000000000..31dbe15bea
--- /dev/null
+++ b/Resources/Prototypes/_DV/Augments/arm.yml
@@ -0,0 +1,241 @@
+- type: entity
+ parent: BaseAugment
+ id: AugmentBaseArm
+ name: base arm augment
+ abstract: true
+ components:
+ - type: Organ
+ slotId: armImplant
+ - type: AugmentArm
+
+- type: entity
+ parent: ActionOpenAugmentInterface
+ id: ActionOpenToolsPanel
+ name: Open tools panel
+ description: Access the tools implanted within you
+ components:
+ - type: InstantAction
+ icon: { sprite: Clothing/Belt/utility.rsi, state: icon }
+
+- type: entity
+ parent: AugmentBaseArm
+ id: AugmentBaseToolPanel
+ name: base tool panel augment
+ abstract: true
+ components:
+ - type: Sprite
+ sprite: _DV/Objects/Augments/arm.rsi
+ state: base
+ - type: Storage
+ maxItemSize: Normal
+ defaultStorageOrientation: Vertical
+ grid:
+ - 0,0,9,1
+ - type: Item
+ size: Ginormous
+ - type: ContainerContainer
+ containers:
+ storagebase: !type:Container
+ ents: []
+ - type: AugmentToolPanel
+ - type: UserInterface
+ interfaces:
+ enum.StorageUiKey.Key:
+ type: StorageBoundUserInterface
+ enum.AugmentToolPanelUiKey.Key:
+ type: AugmentToolPanelMenuBoundUserInterface
+ interactionRange: 0
+ - type: AugmentActivatableUI
+ key: enum.AugmentToolPanelUiKey.Key
+ openAction: ActionOpenToolsPanel
+ - type: AugmentAction
+ - type: Construction
+ graph: CreateToolsPanel
+
+- type: entity
+ parent: BaseElectronics
+ id: AugmentBaseElectronics
+ abstract: true
+ components:
+ - type: PhysicalComposition
+ materialComposition:
+ Glass: 100
+ Steel: 100
+ chemicalComposition:
+ Silicon: 20
+ - type: Sprite
+ sprite: Objects/Misc/module.rsi
+ state: mainboard
+
+- type: entity
+ parent: AugmentBaseElectronics
+ id: AugmentUtilityPanelElectronics
+ name: utility tools panel electronics
+ description: An electronics board that programs a tool panel to hold a specific type of item. This one holds utility tools.
+ components:
+ - type: Item
+ storedRotation: 0
+ - type: Tag
+ tags: [ AugmentToolBelt ]
+
+- type: entity
+ parent: AugmentBaseElectronics
+ id: AugmentBotanyPanelElectronics
+ name: botany tools panel electronics
+ description: An electronics board that programs a tool panel to hold a specific type of item. This one holds botanical tools.
+ components:
+ - type: Item
+ storedRotation: 0
+ - type: Tag
+ tags: [ AugmentBotanyToolBelt ]
+
+- type: entity
+ parent: AugmentBaseElectronics
+ id: AugmentSurgeryPanelElectronics
+ name: surgery tools panel electronics
+ description: An electronics board that programs a tool panel to hold a specific type of item. This one holds surgical tools.
+ components:
+ - type: Item
+ storedRotation: 0
+ - type: Tag
+ tags: [ AugmentSurgeryToolBelt ]
+
+- type: entity
+ parent: AugmentBaseElectronics
+ id: AugmentPaperworkPanelElectronics
+ name: paperwork tools panel electronics
+ description: An electronics board that programs a tool panel to hold a specific type of item. This one holds paperwork tools.
+ components:
+ - type: Item
+ storedRotation: 0
+ - type: Tag
+ tags: [ AugmentPaperworkToolBelt ]
+
+- type: entity
+ parent: BaseItem
+ id: BaseIncompleteAugmentToolPanel
+ abstract: true
+ components:
+ - type: Sprite
+ sprite: _DV/Objects/Augments/arm.rsi
+ - type: Item
+ size: Ginormous
+ - type: Construction
+ graph: CreateToolsPanel
+
+- type: entity
+ parent: BaseIncompleteAugmentToolPanel
+ id: AugmentToolPanelCasing
+ name: tools panel augment casing
+ description: Can be implanted into a body to provide access to specific tools. This one is incomplete.
+ components:
+ - type: Sprite
+ state: base
+ - type: Construction
+ node: casing
+ - type: Tag
+ tags: [ AugmentToolPanelCasing ]
+
+- type: entity
+ parent: BaseIncompleteAugmentToolPanel
+ id: AugmentToolPanelCasingCables
+ name: tools panel augment casing with cables
+ description: Can be implanted into a body to provide access to specific tools. This one is incomplete.
+ components:
+ - type: Sprite
+ state: base_cables
+ - type: Construction
+ node: cables
+
+- type: entity
+ parent: AugmentBaseToolPanel
+ id: AugmentToolsPanel
+ name: tools panel augment
+ description: A panel that can be augmented into a patient's arm to provide them access to its contents. This one can hold tools.
+ components:
+ - type: Sprite
+ state: engineering
+ - type: Storage
+ whitelist:
+ tags:
+ - Wirecutter
+ - Crowbar
+ - Screwdriver
+ - Wrench
+ - GeigerCounter
+ - Powerdrill
+ - JawsOfLife
+ - HolofanProjector
+ - Multitool
+ - AppraisalTool
+ components:
+ - StationMap
+ - SprayPainter
+ - NetworkConfigurator
+ - RCD
+ - RCDAmmo
+ - Welder
+ - PowerCell
+ - Geiger
+ - TrayScanner
+ - GasAnalyzer
+ - type: Construction
+ node: "utility tools panel"
+
+- type: entity
+ parent: AugmentBaseToolPanel
+ id: AugmentBotanyPanel
+ name: botanical tools panel augment
+ description: A panel that can be augmented into a patient's arm to provide them access to its contents. This one can hold botanical tools.
+ components:
+ - type: Sprite
+ state: botany
+ - type: Storage
+ whitelist:
+ tags:
+ - PlantSampleTaker
+ - BotanyShovel
+ - BotanyHoe
+ - BotanyHatchet
+ - Dropper
+ components:
+ - HandLabeler
+ - type: Construction
+ node: "botany tools panel"
+
+- type: entity
+ parent: AugmentBaseToolPanel
+ id: AugmentPaperworkPanel
+ name: paperwork tools panel augment
+ description: A panel that can be augmented into a patient's arm to provide them access to its contents. This one can hold paperwork tools.
+ components:
+ - type: Sprite
+ state: paperwork
+ - type: Storage
+ whitelist:
+ tags:
+ - Folder
+ - HandLabeler
+ components:
+ - Stamp
+ - TapeRecorder
+ - type: Construction
+ node: "paperwork tools panel"
+
+- type: entity
+ parent: AugmentBaseToolPanel
+ id: AugmentSurgicalPanel
+ name: surgical tools panel augment
+ description: A panel that can be augmented into a patient's arm to provide them access to its contents. This one can hold surgical tools.
+ components:
+ - type: Sprite
+ state: surgical
+ - type: Storage
+ whitelist:
+ requireAll: true
+ tags:
+ - SurgeryTool
+ components:
+ - SurgeryTool
+ - type: Construction
+ node: "surgery tools panel"
diff --git a/Resources/Prototypes/_DV/Augments/base.yml b/Resources/Prototypes/_DV/Augments/base.yml
new file mode 100644
index 0000000000..019ce8272b
--- /dev/null
+++ b/Resources/Prototypes/_DV/Augments/base.yml
@@ -0,0 +1,6 @@
+- type: entity
+ parent: BaseItem
+ id: BaseAugment
+ abstract: true
+ components:
+ - type: Augment
diff --git a/Resources/Prototypes/_DV/Augments/power.yml b/Resources/Prototypes/_DV/Augments/power.yml
new file mode 100644
index 0000000000..411a04bc95
--- /dev/null
+++ b/Resources/Prototypes/_DV/Augments/power.yml
@@ -0,0 +1,137 @@
+- type: entity
+ id: ActionOpenAugmentInterface
+ abstract: true
+ # name: Open augment UI
+ # description: This is a developer placeholder and should not be seen
+ components:
+ - type: InstantAction
+ icon: { sprite: Clothing/Mask/gas.rsi, state: icon }
+ iconOn: Interface/Default/blocked.png
+ event: !type:AugmentUIOpenEvent
+
+- type: entity
+ parent: BaseItem
+ id: AugmentPowerCellSlotCasing
+ name: augment power cell slot casing
+ description: Can be implanted into a body to provide power to other implants. This one is incomplete.
+ components:
+ - type: Sprite
+ sprite: _DV/Objects/Augments/power.rsi
+ state: incomplete_cell
+ - type: Construction
+ graph: CreatePowerCellAugment
+ node: casing
+ defaultTarget: augment
+ - type: Tag
+ tags: [ AugmentCellCasing ]
+
+- type: entity
+ parent: BaseItem
+ id: AugmentPowerCellSlotCasingCables
+ name: augment power cell slot casing with cables
+ description: Can be implanted into a body to provide power to other implants. This one is incomplete.
+ components:
+ - type: Sprite
+ sprite: _DV/Objects/Augments/power.rsi
+ state: incomplete_cell_cables
+ - type: Construction
+ graph: CreatePowerCellAugment
+ node: cables
+
+- type: entity
+ parent: BaseAugment
+ id: AugmentPowerCellSlot
+ name: augment power cell slot
+ description: Can be implanted into a body to provide power to other implants.
+ components:
+ - type: Sprite
+ sprite: _DV/Objects/Augments/power.rsi
+ state: cell
+ - type: Organ
+ slotId: powerCell
+ onAdd:
+ - type: HasAugmentPowerCellSlot
+ - type: AugmentPowerCellSlot
+ - type: Construction
+ graph: CreatePowerCellAugment
+ node: augment
+ - type: ContainerContainer
+ containers:
+ cell_slot: !type:ContainerSlot { }
+ - type: PowerCellSlot
+ cellSlotId: cell_slot
+ - type: ItemSlots
+ slots:
+ cell_slot:
+ name: power-cell-slot-component-slot-name-default
+
+- type: entity
+ parent: BaseAugment
+ id: AugmentBaseCharger
+ name: base charger augment
+ abstract: true
+ components:
+ - type: Sprite
+ sprite: _DV/Objects/Augments/power.rsi
+ state: cell
+ - type: Organ
+ slotId: charger
+ - type: AugmentCharger
+
+- type: entity
+ parent: BaseItem
+ id: AugmentRechargerCasing
+ name: augment recharger casing
+ description: Can be implanted into a body to recharge an internal power cell. This one is incomplete.
+ components:
+ - type: Sprite
+ sprite: _DV/Objects/Augments/power.rsi
+ state: incomplete_charger
+ - type: Construction
+ graph: CreatePowerCellChargerAugment
+ node: casing
+ - type: Tag
+ tags: [ AugmentChargerCasing ]
+
+- type: entity
+ parent: BaseItem
+ id: AugmentRechargerCasingCables
+ name: augment recharger casing with cables
+ description: Can be implanted into a body to recharge an internal power cell. This one is incomplete.
+ components:
+ - type: Sprite
+ sprite: _DV/Objects/Augments/power.rsi
+ state: incomplete_charger_cables
+ - type: Construction
+ graph: CreatePowerCellChargerAugment
+ node: cables
+
+- type: entity
+ parent: AugmentBaseCharger
+ id: AugmentRechargerAPC
+ name: augment apc recharger
+ description: Allows the implantee to recharge their power cell via APCs.
+ components:
+ - type: Sprite
+ state: apc
+ - type: Organ
+ onAdd:
+ - type: BatteryDrinker
+ - type: Construction
+ graph: CreatePowerCellChargerAugment
+ node: apc
+
+- type: entity
+ parent: AugmentBaseCharger
+ id: AugmentRechargerStation
+ name: augment station recharger
+ description: Allows the implantee to recharge their power cell via cyborg recharging stations.
+ components:
+ - type: Sprite
+ state: station
+ - type: Organ
+ onAdd:
+ - type: AugmentStationRecharge
+ - type: Construction
+ graph: CreatePowerCellChargerAugment
+ node: station
diff --git a/Resources/Prototypes/_DV/Entities/Surgery/surgeries.yml b/Resources/Prototypes/_DV/Entities/Surgery/surgeries.yml
new file mode 100644
index 0000000000..ed27995327
--- /dev/null
+++ b/Resources/Prototypes/_DV/Entities/Surgery/surgeries.yml
@@ -0,0 +1,179 @@
+- type: entity
+ parent: SurgeryBase
+ id: SurgeryInsertPowerCellSlot
+ name: Insert Power Cell Slot
+ categories: [ HideSpawnMenu ]
+ components:
+ - type: Surgery
+ requirement: SurgeryOpenRibcage
+ steps:
+ - SurgeryStepSawBones
+ - SurgeryStepInsertAugmentPowerCellSlot
+ - SurgeryStepSealOrganWound
+ - type: SurgeryPartCondition
+ part: Torso
+ - type: SurgeryOrganCondition
+ organ:
+ - type: AugmentPowerCellSlot
+ inverse: true
+ reattaching: true
+ - type: SurgeryOrganSlotCondition
+ organSlot: powerCell
+
+- type: entity
+ parent: SurgeryBase
+ id: SurgeryOpenPowerCellSlot
+ name: Open Cavity For Power Cell Slot
+ categories: [ HideSpawnMenu ]
+ components:
+ - type: Surgery
+ requirement: SurgeryOpenRibcage
+ steps:
+ - SurgeryStepSawBones
+ - SurgeryStepOpenOrganSlot
+ - SurgeryStepSealOrganWound
+ - type: SurgeryPartCondition
+ part: Torso
+ - type: SurgeryOrganSlotCondition
+ organSlot: powerCell
+ inverse: true
+ - type: SurgeryBodyCondition
+ accepted: [ IPC ]
+ inverse: true
+
+- type: entity
+ parent: SurgeryBase
+ id: SurgeryRemovePowerCellSlot
+ name: Remove Power Cell Slot
+ categories: [ HideSpawnMenu ]
+ components:
+ - type: Surgery
+ requirement: SurgeryOpenRibcage
+ steps:
+ - SurgeryStepSawBones
+ - SurgeryStepClampInternalBleeders
+ - SurgeryStepRemoveOrgan
+ - type: SurgeryPartCondition
+ part: Torso
+ - type: SurgeryOrganCondition
+ organ:
+ - type: AugmentPowerCellSlot
+
+- type: entity
+ parent: SurgeryBase
+ id: SurgeryInsertPowerCellCharger
+ name: Insert Internal Power Cell Charger
+ categories: [ HideSpawnMenu ]
+ components:
+ - type: Surgery
+ requirement: SurgeryOpenRibcage
+ steps:
+ - SurgeryStepSawBones
+ - SurgeryStepInsertAugmentPowerCellCharger
+ - SurgeryStepSealOrganWound
+ - type: SurgeryPartCondition
+ part: Torso
+ - type: SurgeryOrganCondition
+ organ:
+ - type: AugmentCharger
+ inverse: true
+ reattaching: true
+ - type: SurgeryOrganSlotCondition
+ organSlot: charger
+
+- type: entity
+ parent: SurgeryBase
+ id: SurgeryOpenPowerCellCharger
+ name: Open Cavity For Power Cell Charger
+ categories: [ HideSpawnMenu ]
+ components:
+ - type: Surgery
+ requirement: SurgeryOpenRibcage
+ steps:
+ - SurgeryStepSawBones
+ - SurgeryStepOpenOrganSlot
+ - SurgeryStepSealOrganWound
+ - type: SurgeryPartCondition
+ part: Torso
+ - type: SurgeryOrganSlotCondition
+ organSlot: charger
+ inverse: true
+ - type: SurgeryBodyCondition
+ accepted: [ IPC ]
+ inverse: true
+
+- type: entity
+ parent: SurgeryBase
+ id: SurgeryRemovePowerCellCharger
+ name: Remove Internal Power Cell Charger
+ categories: [ HideSpawnMenu ]
+ components:
+ - type: Surgery
+ requirement: SurgeryOpenRibcage
+ steps:
+ - SurgeryStepSawBones
+ - SurgeryStepClampInternalBleeders
+ - SurgeryStepRemoveOrgan
+ - type: SurgeryPartCondition
+ part: Torso
+ - type: SurgeryOrganCondition
+ organ:
+ - type: AugmentCharger
+
+- type: entity
+ parent: SurgeryBase
+ id: SurgeryOpenArmAugment
+ name: Open Cavity For Arm Augments
+ categories: [ HideSpawnMenu ]
+ components:
+ - type: Surgery
+ requirement: SurgeryOpenIncision
+ steps:
+ - SurgeryStepSawBones
+ - SurgeryStepOpenOrganSlot
+ - SurgeryStepSealOrganWound
+ - type: SurgeryPartCondition
+ part: Arm
+ - type: SurgeryOrganSlotCondition
+ organSlot: armImplant
+ inverse: true
+
+- type: entity
+ parent: SurgeryBase
+ id: SurgeryInsertArmAugment
+ name: Insert Arm Augment
+ categories: [ HideSpawnMenu ]
+ components:
+ - type: Surgery
+ requirement: SurgeryOpenIncision
+ steps:
+ - SurgeryStepSawBones
+ - SurgeryStepInsertAugmentArm
+ - SurgeryStepSealOrganWound
+ - type: SurgeryPartCondition
+ part: Arm
+ - type: SurgeryOrganCondition
+ organ:
+ - type: AugmentArm
+ inverse: true
+ reattaching: true
+ - type: SurgeryOrganSlotCondition
+ organSlot: armImplant
+
+- type: entity
+ parent: SurgeryBase
+ id: SurgeryRemoveArmAugment
+ name: Remove Arm Augment
+ categories: [ HideSpawnMenu ]
+ components:
+ - type: Surgery
+ requirement: SurgeryOpenIncision
+ steps:
+ - SurgeryStepSawBones
+ - SurgeryStepClampInternalBleeders
+ - SurgeryStepRemoveOrgan
+ - type: SurgeryPartCondition
+ part: Arm
+ - type: SurgeryOrganCondition
+ organ:
+ - type: AugmentArm
diff --git a/Resources/Prototypes/_DV/Entities/Surgery/surgery_steps.yml b/Resources/Prototypes/_DV/Entities/Surgery/surgery_steps.yml
new file mode 100644
index 0000000000..a0f5504e32
--- /dev/null
+++ b/Resources/Prototypes/_DV/Entities/Surgery/surgery_steps.yml
@@ -0,0 +1,17 @@
+- type: entity
+ parent: SurgeryStepInsertOrgan
+ id: SurgeryStepInsertAugmentPowerCellSlot
+ name: Add power cell slot
+ categories: [ HideSpawnMenu ]
+
+- type: entity
+ parent: SurgeryStepInsertOrgan
+ id: SurgeryStepInsertAugmentPowerCellCharger
+ name: Add power cell charger
+ categories: [ HideSpawnMenu ]
+
+- type: entity
+ parent: SurgeryStepInsertOrgan
+ id: SurgeryStepInsertAugmentArm
+ name: Add arm augment
+ categories: [ HideSpawnMenu ]
diff --git a/Resources/Prototypes/_DV/Recipes/Construction/Graphs/augments.yml b/Resources/Prototypes/_DV/Recipes/Construction/Graphs/augments.yml
new file mode 100644
index 0000000000..e93563d641
--- /dev/null
+++ b/Resources/Prototypes/_DV/Recipes/Construction/Graphs/augments.yml
@@ -0,0 +1,131 @@
+- type: constructionGraph
+ id: CreatePowerCellAugment
+ start: start
+ graph:
+ - node: start
+ edges:
+ - to: casing
+ steps:
+ - tag: AugmentCellCasing
+ name: casing
+ icon:
+ sprite: _DV/Objects/Augments/power.rsi
+ state: incomplete_cell
+ - node: casing
+ entity: AugmentPowerCellSlotCasing
+ edges:
+ - to: cables
+ steps:
+ - material: Cable
+ amount: 1
+ - node: cables
+ entity: AugmentPowerCellSlotCasingCables
+ edges:
+ - to: augment
+ steps:
+ - material: Plastic
+ amount: 1
+ - node: augment
+ entity: AugmentPowerCellSlot
+
+- type: constructionGraph
+ id: CreatePowerCellChargerAugment
+ start: start
+ graph:
+ - node: start
+ edges:
+ - to: casing
+ steps:
+ - tag: AugmentChargerCasing
+ name: casing
+ icon:
+ sprite: _DV/Objects/Augments/power.rsi
+ state: incomplete_charger
+ - node: casing
+ entity: AugmentRechargerCasing
+ edges:
+ - to: cables
+ steps:
+ - material: Cable
+ amount: 1
+ - node: cables
+ entity: AugmentRechargerCasingCables
+ edges:
+ - to: apc
+ steps:
+ - tag: AugmentAPCBoard
+ name: "cell recharger machine board"
+ icon:
+ sprite: Objects/Misc/module.rsi
+ state: charger_APC
+ - to: station
+ steps:
+ - tag: AugmentStationBoard
+ name: "cyborg recharging station machine board"
+ icon:
+ sprite: Objects/Misc/module.rsi
+ state: charger_APC
+ - node: apc
+ entity: AugmentRechargerAPC
+ - node: station
+ entity: AugmentRechargerStation
+
+- type: constructionGraph
+ id: CreateToolsPanel
+ start: start
+ graph:
+ - node: start
+ edges:
+ - to: casing
+ steps:
+ - tag: AugmentToolPanelCasing
+ name: casing
+ icon:
+ sprite: _DV/Objects/Augments/arm.rsi
+ state: base
+ - node: casing
+ entity: AugmentToolPanelCasing
+ edges:
+ - to: cables
+ steps:
+ - material: Cable
+ amount: 1
+ - node: cables
+ entity: AugmentToolPanelCasingCables
+ edges:
+ - to: "botany tools panel"
+ steps:
+ - tag: AugmentBotanyToolBelt
+ name: botany tools panel electronics
+ icon:
+ sprite: Objects/Misc/module.rsi
+ state: mainboard
+ - to: "paperwork tools panel"
+ steps:
+ - tag: AugmentPaperworkToolBelt
+ name: paperwork tools panel electronics
+ icon:
+ sprite: Objects/Misc/module.rsi
+ state: mainboard
+ - to: "utility tools panel"
+ steps:
+ - tag: AugmentToolBelt
+ name: utility tools panel electronics
+ icon:
+ sprite: Objects/Misc/module.rsi
+ state: mainboard
+ - to: "surgery tools panel"
+ steps:
+ - tag: AugmentSurgeryToolBelt
+ name: surgery tools panel electronics
+ icon:
+ sprite: Objects/Misc/module.rsi
+ state: mainboard
+ - node: "botany tools panel"
+ entity: AugmentBotanyPanel
+ - node: "paperwork tools panel"
+ entity: AugmentPaperworkPanel
+ - node: "surgery tools panel"
+ entity: AugmentSurgicalPanel
+ - node: "utility tools panel"
+ entity: AugmentToolsPanel
diff --git a/Resources/Prototypes/_DV/Recipes/Construction/augments.yml b/Resources/Prototypes/_DV/Recipes/Construction/augments.yml
new file mode 100644
index 0000000000..76afbb8d82
--- /dev/null
+++ b/Resources/Prototypes/_DV/Recipes/Construction/augments.yml
@@ -0,0 +1,90 @@
+- type: construction
+ name: augment power cell slot
+ description: Can be implanted into a body to provide power to other implants.
+ id: AugmentPowerCellSlot
+ graph: CreatePowerCellAugment
+ startNode: start
+ targetNode: augment
+ category: construction-category-utilities
+ canBuildInImpassable: false
+ icon:
+ sprite: _DV/Objects/Augments/power.rsi
+ state: cell
+
+- type: construction
+ name: augment apc recharger
+ description: Allows the implantee to recharge their power cell via APCs.
+ id: AugmentRechargerAPC
+ graph: CreatePowerCellChargerAugment
+ startNode: start
+ targetNode: apc
+ category: construction-category-utilities
+ canBuildInImpassable: false
+ icon:
+ sprite: _DV/Objects/Augments/power.rsi
+ state: apc
+
+- type: construction
+ name: augment station recharger
+ description: Allows the implantee to recharge their power cell via cyborg recharging stations.
+ id: AugmentRechargerStation
+ graph: CreatePowerCellChargerAugment
+ startNode: start
+ targetNode: station
+ category: construction-category-utilities
+ canBuildInImpassable: false
+ icon:
+ sprite: _DV/Objects/Augments/power.rsi
+ state: station
+
+- type: construction
+ name: tools panel augment
+ description: A panel that can be augmented into a patient's arm to provide them access to its contents. This one can hold tools.
+ id: AugmentToolsPanel
+ graph: CreateToolsPanel
+ startNode: start
+ targetNode: "utility tools panel"
+ category: construction-category-utilities
+ canBuildInImpassable: false
+ icon:
+ sprite: _DV/Objects/Augments/arm.rsi
+ state: engineering
+
+- type: construction
+ name: botanical tools panel augment
+ description: A panel that can be augmented into a patient's arm to provide them access to its contents. This one can hold botanical tools.
+ id: AugmentBotanyPanel
+ graph: CreateToolsPanel
+ startNode: start
+ targetNode: "botany tools panel"
+ category: construction-category-utilities
+ canBuildInImpassable: false
+ icon:
+ sprite: _DV/Objects/Augments/arm.rsi
+ state: botany
+
+- type: construction
+ name: paperwork tools panel augment
+ description: A panel that can be augmented into a patient's arm to provide them access to its contents. This one can hold paperwork tools.
+ id: AugmentPaperworkPanel
+ graph: CreateToolsPanel
+ startNode: start
+ targetNode: "paperwork tools panel"
+ category: construction-category-utilities
+ canBuildInImpassable: false
+ icon:
+ sprite: _DV/Objects/Augments/arm.rsi
+ state: paperwork
+
+- type: construction
+ name: surgical tools panel augment
+ description: A panel that can be augmented into a patient's arm to provide them access to its contents. This one can hold surgical tools.
+ id: AugmentSurgicalPanel
+ graph: CreateToolsPanel
+ startNode: start
+ targetNode: "surgery tools panel"
+ category: construction-category-utilities
+ canBuildInImpassable: false
+ icon:
+ sprite: _DV/Objects/Augments/arm.rsi
+ state: surgical
diff --git a/Resources/Prototypes/_DV/Recipes/Lathes/Packs/robotics.yml b/Resources/Prototypes/_DV/Recipes/Lathes/Packs/robotics.yml
index 7f74ea9424..72b8986ebd 100644
--- a/Resources/Prototypes/_DV/Recipes/Lathes/Packs/robotics.yml
+++ b/Resources/Prototypes/_DV/Recipes/Lathes/Packs/robotics.yml
@@ -38,4 +38,19 @@
recipes:
- BorgModuleSecurityChase
- BorgModuleSecurityEscalate
- - BorgModuleSecurityBastion
\ No newline at end of file
+ - BorgModuleSecurityBastion
+
+- type: latheRecipePack
+ id: PowerAugments
+ recipes:
+ - AugmentPowerCellSlotCasing
+ - AugmentRechargerCasing
+
+- type: latheRecipePack
+ id: ToolAugments
+ recipes:
+ - AugmentToolPanelCasing
+ - AugmentUtilityPanelElectronics
+ - AugmentBotanyPanelElectronics
+ - AugmentSurgeryPanelElectronics
+ - AugmentPaperworkPanelElectronics
diff --git a/Resources/Prototypes/_DV/Recipes/Lathes/robotics.yml b/Resources/Prototypes/_DV/Recipes/Lathes/robotics.yml
index a85e741d17..5372d3fd6e 100644
--- a/Resources/Prototypes/_DV/Recipes/Lathes/robotics.yml
+++ b/Resources/Prototypes/_DV/Recipes/Lathes/robotics.yml
@@ -169,3 +169,38 @@
parent: IdChipSyndie
id: IdChipRoboNeuroticist
result: IdChipRoboNeuroticist
+
+- type: latheRecipe
+ parent: BaseBorgModuleRecipe
+ id: AugmentPowerCellSlotCasing
+ result: AugmentPowerCellSlotCasing
+
+- type: latheRecipe
+ parent: BaseBorgModuleRecipe
+ id: AugmentRechargerCasing
+ result: AugmentRechargerCasing
+
+- type: latheRecipe
+ parent: BaseBorgModuleRecipe
+ id: AugmentToolPanelCasing
+ result: AugmentToolPanelCasing
+
+- type: latheRecipe
+ parent: BaseBorgModuleRecipe
+ id: AugmentUtilityPanelElectronics
+ result: AugmentUtilityPanelElectronics
+
+- type: latheRecipe
+ parent: BaseBorgModuleRecipe
+ id: AugmentBotanyPanelElectronics
+ result: AugmentBotanyPanelElectronics
+
+- type: latheRecipe
+ parent: BaseBorgModuleRecipe
+ id: AugmentSurgeryPanelElectronics
+ result: AugmentSurgeryPanelElectronics
+
+- type: latheRecipe
+ parent: BaseBorgModuleRecipe
+ id: AugmentPaperworkPanelElectronics
+ result: AugmentPaperworkPanelElectronics
diff --git a/Resources/Prototypes/_DV/Research/civilianservices.yml b/Resources/Prototypes/_DV/Research/civilianservices.yml
index 73be7fb5a9..d982aecc44 100644
--- a/Resources/Prototypes/_DV/Research/civilianservices.yml
+++ b/Resources/Prototypes/_DV/Research/civilianservices.yml
@@ -10,3 +10,34 @@
recipeUnlocks:
- LauncherSyringe
- MiniSyringe
+
+- type: technology
+ id: BasicAugmentation
+ name: research-technology-basic-augmentation
+ icon:
+ sprite: _DV/Objects/Augments/power.rsi
+ state: cell
+ discipline: CivilianServices
+ tier: 2
+ cost: 5000
+ recipeUnlocks:
+ - AugmentPowerCellSlotCasing
+ - AugmentRechargerCasing
+
+- type: technology
+ id: ImplantedTools
+ name: research-technology-implanted-tools
+ icon:
+ sprite: _DV/Objects/Augments/arm.rsi
+ state: base
+ discipline: CivilianServices
+ tier: 2
+ cost: 10000
+ technologyPrerequisites: [ BasicAugmentation ]
+ recipeUnlocks:
+ - AugmentToolPanelCasing
+ - AugmentUtilityPanelElectronics
+ - AugmentBotanyPanelElectronics
+ - AugmentSurgeryPanelElectronics
+ - AugmentPaperworkPanelElectronics
+
diff --git a/Resources/Prototypes/_DV/tags.yml b/Resources/Prototypes/_DV/tags.yml
index 5a51ca0819..7da6e7d46a 100644
--- a/Resources/Prototypes/_DV/tags.yml
+++ b/Resources/Prototypes/_DV/tags.yml
@@ -1,5 +1,32 @@
## This is for Nyano and Delta V tags
+- type: Tag
+ id: AugmentAPCBoard
+
+- type: Tag
+ id: AugmentBotanyToolBelt
+
+- type: Tag
+ id: AugmentCellCasing
+
+- type: Tag
+ id: AugmentChargerCasing
+
+- type: Tag
+ id: AugmentPaperworkToolBelt
+
+- type: Tag
+ id: AugmentStationBoard
+
+- type: Tag
+ id: AugmentSurgeryToolBelt
+
+- type: Tag
+ id: AugmentToolBelt
+
+- type: Tag
+ id: AugmentToolPanelCasing
+
- type: Tag
id: Bayonet #Craftable Musket
diff --git a/Resources/Prototypes/_Shitmed/Entities/Surgery/surgery_steps.yml b/Resources/Prototypes/_Shitmed/Entities/Surgery/surgery_steps.yml
index 6358efab1a..9814a0ecf1 100644
--- a/Resources/Prototypes/_Shitmed/Entities/Surgery/surgery_steps.yml
+++ b/Resources/Prototypes/_Shitmed/Entities/Surgery/surgery_steps.yml
@@ -519,6 +519,30 @@
toolDirtiness: 7.5
gloveDirtiness: 7.5
+- type: entity
+ parent: SurgeryStepBase
+ id: SurgeryStepOpenOrganSlot
+ name: Carve out a cavity
+ categories: [ HideSpawnMenu ]
+ components:
+ - type: SurgeryStep
+ tool:
+ - type: Scalpel
+ duration: 6
+ - type: Sprite
+ sprite: _Shitmed/Objects/Specific/Medical/Surgery/manipulation.rsi
+ state: insertion
+ - type: SurgeryAddOrganSlotStep
+ - type: SurgeryStepEmoteEffect
+ - type: SurgeryDamageChangeEffect # DeltaV
+ sleepModifier: 0.5
+ damage:
+ types:
+ Blunt: 5
+ - type: SurgeryStepDirtiness # DeltaV - surgery cross contamination
+ toolDirtiness: 7.5
+ gloveDirtiness: 7.5
+
- type: entity
parent: SurgeryStepInsertOrgan
id: SurgeryStepInsertLungs
diff --git a/Resources/Textures/_DV/Objects/Augments/arm.rsi/base.png b/Resources/Textures/_DV/Objects/Augments/arm.rsi/base.png
new file mode 100644
index 0000000000..ee221aa200
Binary files /dev/null and b/Resources/Textures/_DV/Objects/Augments/arm.rsi/base.png differ
diff --git a/Resources/Textures/_DV/Objects/Augments/arm.rsi/base_cables.png b/Resources/Textures/_DV/Objects/Augments/arm.rsi/base_cables.png
new file mode 100644
index 0000000000..fbda9c7f11
Binary files /dev/null and b/Resources/Textures/_DV/Objects/Augments/arm.rsi/base_cables.png differ
diff --git a/Resources/Textures/_DV/Objects/Augments/arm.rsi/botany.png b/Resources/Textures/_DV/Objects/Augments/arm.rsi/botany.png
new file mode 100644
index 0000000000..b45feed798
Binary files /dev/null and b/Resources/Textures/_DV/Objects/Augments/arm.rsi/botany.png differ
diff --git a/Resources/Textures/_DV/Objects/Augments/arm.rsi/engineering.png b/Resources/Textures/_DV/Objects/Augments/arm.rsi/engineering.png
new file mode 100644
index 0000000000..446eb22eed
Binary files /dev/null and b/Resources/Textures/_DV/Objects/Augments/arm.rsi/engineering.png differ
diff --git a/Resources/Textures/_DV/Objects/Augments/arm.rsi/meta.json b/Resources/Textures/_DV/Objects/Augments/arm.rsi/meta.json
new file mode 100644
index 0000000000..17ac87ffd5
--- /dev/null
+++ b/Resources/Textures/_DV/Objects/Augments/arm.rsi/meta.json
@@ -0,0 +1,29 @@
+{
+ "version": 1,
+ "license": "CC-BY-SA-3.0",
+ "copyright": "taken from /tg/ station at commit https://github.com/tgstation/tgstation/blob/c7e20fe50f0185e7f1898b518ac8715c47ac56b0/icons/obj/medical/organs/organs.dmi",
+ "size": {
+ "x": 32,
+ "y": 32
+ },
+ "states": [
+ {
+ "name": "base"
+ },
+ {
+ "name": "base_cables"
+ },
+ {
+ "name": "botany"
+ },
+ {
+ "name": "paperwork"
+ },
+ {
+ "name": "engineering"
+ },
+ {
+ "name": "surgical"
+ }
+ ]
+}
diff --git a/Resources/Textures/_DV/Objects/Augments/arm.rsi/paperwork.png b/Resources/Textures/_DV/Objects/Augments/arm.rsi/paperwork.png
new file mode 100644
index 0000000000..0c7cb10041
Binary files /dev/null and b/Resources/Textures/_DV/Objects/Augments/arm.rsi/paperwork.png differ
diff --git a/Resources/Textures/_DV/Objects/Augments/arm.rsi/surgical.png b/Resources/Textures/_DV/Objects/Augments/arm.rsi/surgical.png
new file mode 100644
index 0000000000..c66e9e1019
Binary files /dev/null and b/Resources/Textures/_DV/Objects/Augments/arm.rsi/surgical.png differ
diff --git a/Resources/Textures/_DV/Objects/Augments/power.rsi/apc.png b/Resources/Textures/_DV/Objects/Augments/power.rsi/apc.png
new file mode 100644
index 0000000000..add3245ca7
Binary files /dev/null and b/Resources/Textures/_DV/Objects/Augments/power.rsi/apc.png differ
diff --git a/Resources/Textures/_DV/Objects/Augments/power.rsi/cell.png b/Resources/Textures/_DV/Objects/Augments/power.rsi/cell.png
new file mode 100644
index 0000000000..9be6d7980c
Binary files /dev/null and b/Resources/Textures/_DV/Objects/Augments/power.rsi/cell.png differ
diff --git a/Resources/Textures/_DV/Objects/Augments/power.rsi/incomplete_cell.png b/Resources/Textures/_DV/Objects/Augments/power.rsi/incomplete_cell.png
new file mode 100644
index 0000000000..441e1d1c53
Binary files /dev/null and b/Resources/Textures/_DV/Objects/Augments/power.rsi/incomplete_cell.png differ
diff --git a/Resources/Textures/_DV/Objects/Augments/power.rsi/incomplete_cell_cables.png b/Resources/Textures/_DV/Objects/Augments/power.rsi/incomplete_cell_cables.png
new file mode 100644
index 0000000000..01f1e9ffab
Binary files /dev/null and b/Resources/Textures/_DV/Objects/Augments/power.rsi/incomplete_cell_cables.png differ
diff --git a/Resources/Textures/_DV/Objects/Augments/power.rsi/incomplete_charger.png b/Resources/Textures/_DV/Objects/Augments/power.rsi/incomplete_charger.png
new file mode 100644
index 0000000000..609735077c
Binary files /dev/null and b/Resources/Textures/_DV/Objects/Augments/power.rsi/incomplete_charger.png differ
diff --git a/Resources/Textures/_DV/Objects/Augments/power.rsi/incomplete_charger_cables.png b/Resources/Textures/_DV/Objects/Augments/power.rsi/incomplete_charger_cables.png
new file mode 100644
index 0000000000..9ddc292deb
Binary files /dev/null and b/Resources/Textures/_DV/Objects/Augments/power.rsi/incomplete_charger_cables.png differ
diff --git a/Resources/Textures/_DV/Objects/Augments/power.rsi/meta.json b/Resources/Textures/_DV/Objects/Augments/power.rsi/meta.json
new file mode 100644
index 0000000000..ae48e82710
--- /dev/null
+++ b/Resources/Textures/_DV/Objects/Augments/power.rsi/meta.json
@@ -0,0 +1,32 @@
+{
+ "version": 1,
+ "license": "CC-BY-SA-3.0",
+ "copyright": "taken from /tg/ station at commit https://github.com/tgstation/tgstation/commit/02756c2bc2cf3000080d030955e994242bab39b5",
+ "size": {
+ "x": 32,
+ "y": 32
+ },
+ "states": [
+ {
+ "name": "apc"
+ },
+ {
+ "name": "cell"
+ },
+ {
+ "name": "station"
+ },
+ {
+ "name": "incomplete_charger"
+ },
+ {
+ "name": "incomplete_charger_cables"
+ },
+ {
+ "name": "incomplete_cell"
+ },
+ {
+ "name": "incomplete_cell_cables"
+ }
+ ]
+}
diff --git a/Resources/Textures/_DV/Objects/Augments/power.rsi/station.png b/Resources/Textures/_DV/Objects/Augments/power.rsi/station.png
new file mode 100644
index 0000000000..0e6986e791
Binary files /dev/null and b/Resources/Textures/_DV/Objects/Augments/power.rsi/station.png differ