diff --git a/Content.Packaging/Properties/launchSettings.json b/Content.Packaging/Properties/launchSettings.json
deleted file mode 100644
index 33504c948ad..00000000000
--- a/Content.Packaging/Properties/launchSettings.json
+++ /dev/null
@@ -1,8 +0,0 @@
-{
- "profiles": {
- "WSL": {
- "commandName": "WSL2",
- "distributionName": ""
- }
- }
-}
\ No newline at end of file
diff --git a/Content.Server/DeltaV/GlimmerWisp/LifeDrainerSystem.cs b/Content.Server/DeltaV/GlimmerWisp/LifeDrainerSystem.cs
index ec800db2a30..079ec77bbf3 100644
--- a/Content.Server/DeltaV/GlimmerWisp/LifeDrainerSystem.cs
+++ b/Content.Server/DeltaV/GlimmerWisp/LifeDrainerSystem.cs
@@ -1,5 +1,6 @@
using Content.Shared.ActionBlocker;
using Content.Shared.Damage;
+using Content.Shared.DeltaV.Carrying;
using Content.Shared.DoAfter;
using Content.Shared.Interaction;
using Content.Shared.Mobs.Systems;
@@ -11,7 +12,6 @@
using Content.Shared.Verbs;
using Content.Shared.Whitelist;
using Content.Server.NPC.Components;
-using Content.Server.Carrying;
using Robust.Shared.Audio.Systems;
using Robust.Shared.Player;
using Robust.Shared.Utility;
diff --git a/Content.Server/Nyanotrasen/Carrying/BeingCarriedComponent.cs b/Content.Server/Nyanotrasen/Carrying/BeingCarriedComponent.cs
deleted file mode 100644
index afc78978c86..00000000000
--- a/Content.Server/Nyanotrasen/Carrying/BeingCarriedComponent.cs
+++ /dev/null
@@ -1,11 +0,0 @@
-namespace Content.Server.Carrying
-{
- ///
- /// Stores the carrier of an entity being carried.
- ///
- [RegisterComponent]
- public sealed partial class BeingCarriedComponent : Component
- {
- public EntityUid Carrier = default!;
- }
-}
diff --git a/Content.Server/Nyanotrasen/Carrying/CarriableComponent.cs b/Content.Server/Nyanotrasen/Carrying/CarriableComponent.cs
deleted file mode 100644
index f4fd1fa6d56..00000000000
--- a/Content.Server/Nyanotrasen/Carrying/CarriableComponent.cs
+++ /dev/null
@@ -1,17 +0,0 @@
-using System.Threading;
-
-namespace Content.Server.Carrying
-{
- [RegisterComponent]
- public sealed partial class CarriableComponent : Component
- {
- ///
- /// Number of free hands required
- /// to carry the entity
- ///
- [DataField("freeHandsRequired")]
- public int FreeHandsRequired = 2;
-
- public CancellationTokenSource? CancelToken;
- }
-}
diff --git a/Content.Server/Nyanotrasen/Carrying/CarryingComponent.cs b/Content.Server/Nyanotrasen/Carrying/CarryingComponent.cs
deleted file mode 100644
index e79460595b9..00000000000
--- a/Content.Server/Nyanotrasen/Carrying/CarryingComponent.cs
+++ /dev/null
@@ -1,11 +0,0 @@
-namespace Content.Server.Carrying
-{
- ///
- /// Added to an entity when they are carrying somebody.
- ///
- [RegisterComponent]
- public sealed partial class CarryingComponent : Component
- {
- public EntityUid Carried = default!;
- }
-}
diff --git a/Content.Server/Nyanotrasen/Carrying/CarryingSystem.cs b/Content.Server/Nyanotrasen/Carrying/CarryingSystem.cs
deleted file mode 100644
index 0faff7d8078..00000000000
--- a/Content.Server/Nyanotrasen/Carrying/CarryingSystem.cs
+++ /dev/null
@@ -1,432 +0,0 @@
-using System.Numerics;
-using System.Threading;
-using Content.Server.DoAfter;
-using Content.Server.Body.Systems;
-using Content.Server.Hands.Systems;
-using Content.Server.Resist;
-using Content.Server.Popups;
-using Content.Server.Inventory;
-using Content.Server.Nyanotrasen.Item.PseudoItem;
-using Content.Shared.Climbing; // Shared instead of Server
-using Content.Shared.Mobs;
-using Content.Shared.DoAfter;
-using Content.Shared.Buckle.Components;
-using Content.Shared.Hands.Components;
-using Content.Shared.Hands;
-using Content.Shared.Stunnable;
-using Content.Shared.Interaction.Events;
-using Content.Shared.Verbs;
-using Content.Shared.Climbing.Events; // Added this.
-using Content.Shared.Carrying;
-using Content.Shared.Movement.Events;
-using Content.Shared.Movement.Systems;
-using Content.Shared.Pulling;
-using Content.Shared.Standing;
-using Content.Shared.ActionBlocker;
-using Content.Shared.Inventory.VirtualItem;
-using Content.Shared.Item;
-using Content.Shared.Throwing;
-using Content.Shared.Mobs.Systems;
-using Content.Shared.Movement.Pulling.Components;
-using Content.Shared.Movement.Pulling.Events;
-using Content.Shared.Movement.Pulling.Systems;
-using Content.Shared.Nyanotrasen.Item.PseudoItem;
-using Content.Shared.Storage;
-using Robust.Shared.Map.Components;
-using Robust.Shared.Physics.Components;
-
-namespace Content.Server.Carrying
-{
- public sealed class CarryingSystem : EntitySystem
- {
- [Dependency] private readonly VirtualItemSystem _virtualItemSystem = default!;
- [Dependency] private readonly CarryingSlowdownSystem _slowdown = default!;
- [Dependency] private readonly DoAfterSystem _doAfterSystem = default!;
- [Dependency] private readonly StandingStateSystem _standingState = default!;
- [Dependency] private readonly ActionBlockerSystem _actionBlockerSystem = default!;
- [Dependency] private readonly PullingSystem _pullingSystem = default!;
- [Dependency] private readonly MobStateSystem _mobStateSystem = default!;
- [Dependency] private readonly EscapeInventorySystem _escapeInventorySystem = default!;
- [Dependency] private readonly PopupSystem _popupSystem = default!;
- [Dependency] private readonly MovementSpeedModifierSystem _movementSpeed = default!;
- [Dependency] private readonly RespiratorSystem _respirator = default!;
- [Dependency] private readonly SharedTransformSystem _transform = default!;
- [Dependency] private readonly PseudoItemSystem _pseudoItem = default!; // Needed for fitting check
-
- public override void Initialize()
- {
- base.Initialize();
- SubscribeLocalEvent>(AddCarryVerb);
- SubscribeLocalEvent>(AddInsertCarriedVerb);
- SubscribeLocalEvent(OnVirtualItemDeleted);
- SubscribeLocalEvent(OnThrow);
- SubscribeLocalEvent(OnParentChanged);
- SubscribeLocalEvent(OnMobStateChanged);
- SubscribeLocalEvent(OnInteractionAttempt);
- SubscribeLocalEvent(OnMoveInput);
- SubscribeLocalEvent(OnMoveAttempt);
- SubscribeLocalEvent(OnStandAttempt);
- SubscribeLocalEvent(OnInteractedWith);
- SubscribeLocalEvent(OnPullAttempt);
- SubscribeLocalEvent(OnStartClimb);
- SubscribeLocalEvent(OnBuckleChange);
- SubscribeLocalEvent(OnBuckleChange);
- SubscribeLocalEvent(OnBuckleChange);
- SubscribeLocalEvent(OnBuckleChange);
- SubscribeLocalEvent(OnDoAfter);
- }
-
- private void AddCarryVerb(EntityUid uid, CarriableComponent component, GetVerbsEvent args)
- {
- if (!args.CanInteract || !args.CanAccess)
- return;
-
- if (!CanCarry(args.User, uid, component))
- return;
-
- if (HasComp(args.User)) // yeah not dealing with that
- return;
-
- if (HasComp(args.User) || HasComp(args.Target))
- return;
-
- if (!_mobStateSystem.IsAlive(args.User))
- return;
-
- if (args.User == args.Target)
- return;
-
- AlternativeVerb verb = new()
- {
- Act = () =>
- {
- StartCarryDoAfter(args.User, uid, component);
- },
- Text = Loc.GetString("carry-verb"),
- Priority = 2
- };
- args.Verbs.Add(verb);
- }
-
- private void AddInsertCarriedVerb(EntityUid uid, CarryingComponent component, GetVerbsEvent args)
- {
- // If the person is carrying someone, and the carried person is a pseudo-item, and the target entity is a storage,
- // then add an action to insert the carried entity into the target
- var toInsert = args.Using;
- if (toInsert is not { Valid: true } || !args.CanAccess || !TryComp(toInsert, out var pseudoItem))
- return;
-
- if (!TryComp(args.Target, out var storageComp))
- return;
-
- if (!_pseudoItem.CheckItemFits((toInsert.Value, pseudoItem), (args.Target, storageComp)))
- return;
-
- InnateVerb verb = new()
- {
- Act = () =>
- {
- DropCarried(uid, toInsert.Value);
- _pseudoItem.TryInsert(args.Target, toInsert.Value, pseudoItem, storageComp);
- },
- Text = Loc.GetString("action-name-insert-other", ("target", toInsert)),
- Priority = 2
- };
- args.Verbs.Add(verb);
- }
-
- ///
- /// Since the carried entity is stored as 2 virtual items, when deleted we want to drop them.
- ///
- private void OnVirtualItemDeleted(EntityUid uid, CarryingComponent component, VirtualItemDeletedEvent args)
- {
- if (!HasComp(args.BlockingEntity))
- return;
-
- DropCarried(uid, args.BlockingEntity);
- }
-
- ///
- /// Basically using virtual item passthrough to throw the carried person. A new age!
- /// Maybe other things besides throwing should use virt items like this...
- ///
- private void OnThrow(EntityUid uid, CarryingComponent component, BeforeThrowEvent args)
- {
- if (!TryComp(args.ItemUid, out var virtItem) || !HasComp(virtItem.BlockingEntity))
- return;
-
- args.ItemUid = virtItem.BlockingEntity;
-
- var multiplier = MassContest(uid, virtItem.BlockingEntity);
- args.ThrowSpeed = 5f * multiplier;
- }
-
- private void OnParentChanged(EntityUid uid, CarryingComponent component, ref EntParentChangedMessage args)
- {
- var xform = Transform(uid);
- if (xform.MapUid != args.OldMapId)
- return;
-
- // Do not drop the carried entity if the new parent is a grid
- if (xform.ParentUid == xform.GridUid)
- return;
-
- DropCarried(uid, component.Carried);
- }
-
- private void OnMobStateChanged(EntityUid uid, CarryingComponent component, MobStateChangedEvent args)
- {
- DropCarried(uid, component.Carried);
- }
-
- ///
- /// Only let the person being carried interact with their carrier and things on their person.
- ///
- private void OnInteractionAttempt(EntityUid uid, BeingCarriedComponent component, InteractionAttemptEvent args)
- {
- if (args.Target == null)
- return;
-
- var targetParent = Transform(args.Target.Value).ParentUid;
-
- if (args.Target.Value != component.Carrier && targetParent != component.Carrier && targetParent != uid)
- args.Cancelled = true;
- }
-
- ///
- /// Try to escape via the escape inventory system.
- ///
- private void OnMoveInput(EntityUid uid, BeingCarriedComponent component, ref MoveInputEvent args)
- {
- if (!TryComp(uid, out var escape))
- return;
-
- if (!args.HasDirectionalMovement)
- return;
-
- if (_actionBlockerSystem.CanInteract(uid, component.Carrier))
- {
- // Note: the mass contest is inverted because weaker entities are supposed to take longer to escape
- _escapeInventorySystem.AttemptEscape(uid, component.Carrier, escape, MassContest(component.Carrier, uid));
- }
- }
-
- private void OnMoveAttempt(EntityUid uid, BeingCarriedComponent component, UpdateCanMoveEvent args)
- {
- args.Cancel();
- }
-
- private void OnStandAttempt(EntityUid uid, BeingCarriedComponent component, StandAttemptEvent args)
- {
- args.Cancel();
- }
-
- private void OnInteractedWith(EntityUid uid, BeingCarriedComponent component, GettingInteractedWithAttemptEvent args)
- {
- if (args.Uid != component.Carrier)
- args.Cancelled = true;
- }
-
- private void OnPullAttempt(EntityUid uid, BeingCarriedComponent component, PullAttemptEvent args)
- {
- args.Cancelled = true;
- }
-
- private void OnStartClimb(EntityUid uid, BeingCarriedComponent component, ref StartClimbEvent args)
- {
- DropCarried(component.Carrier, uid);
- }
-
- private void OnBuckleChange(EntityUid uid, BeingCarriedComponent component, TEvent args) // Augh
- {
- DropCarried(component.Carrier, uid);
- }
-
- private void OnDoAfter(EntityUid uid, CarriableComponent component, CarryDoAfterEvent args)
- {
- component.CancelToken = null;
- if (args.Handled || args.Cancelled)
- return;
-
- if (!CanCarry(args.Args.User, uid, component))
- return;
-
- Carry(args.Args.User, uid);
- args.Handled = true;
- }
- private void StartCarryDoAfter(EntityUid carrier, EntityUid carried, CarriableComponent component)
- {
- TimeSpan length = GetPickupDuration(carrier, carried);
-
- if (length >= TimeSpan.FromSeconds(9))
- {
- _popupSystem.PopupEntity(Loc.GetString("carry-too-heavy"), carried, carrier, Shared.Popups.PopupType.SmallCaution);
- return;
- }
-
- if (!HasComp(carried))
- length *= 2f;
-
- component.CancelToken = new CancellationTokenSource();
-
- var ev = new CarryDoAfterEvent();
- var args = new DoAfterArgs(EntityManager, carrier, length, ev, carried, target: carried)
- {
- BreakOnMove = true,
- NeedHand = true
- };
-
- _doAfterSystem.TryStartDoAfter(args);
-
- // Show a popup to the person getting picked up
- _popupSystem.PopupEntity(Loc.GetString("carry-started", ("carrier", carrier)), carried, carried);
- }
-
- private void Carry(EntityUid carrier, EntityUid carried)
- {
- if (TryComp(carried, out var pullable))
- _pullingSystem.TryStopPull(carried, pullable);
-
- var carrierXform = Transform(carrier);
- var xform = Transform(carried);
- _transform.AttachToGridOrMap(carrier, carrierXform);
- _transform.AttachToGridOrMap(carried, xform);
- xform.Coordinates = carrierXform.Coordinates;
- _transform.SetParent(carried, xform, carrier, carrierXform);
-
- _virtualItemSystem.TrySpawnVirtualItemInHand(carried, carrier);
- _virtualItemSystem.TrySpawnVirtualItemInHand(carried, carrier);
- var carryingComp = EnsureComp(carrier);
- ApplyCarrySlowdown(carrier, carried);
- var carriedComp = EnsureComp(carried);
- EnsureComp(carried);
-
- carryingComp.Carried = carried;
- carriedComp.Carrier = carrier;
-
- _actionBlockerSystem.UpdateCanMove(carried);
- }
-
- public bool TryCarry(EntityUid carrier, EntityUid toCarry, CarriableComponent? carriedComp = null)
- {
- if (!Resolve(toCarry, ref carriedComp, false))
- return false;
-
- if (!CanCarry(carrier, toCarry, carriedComp))
- return false;
-
- // The second one means that carrier is a pseudo-item and is inside a bag.
- if (HasComp(carrier) || HasComp(carrier))
- return false;
-
- if (GetPickupDuration(carrier, toCarry) > TimeSpan.FromSeconds(9))
- return false;
-
- Carry(carrier, toCarry);
-
- return true;
- }
-
- public void DropCarried(EntityUid carrier, EntityUid carried)
- {
- RemComp(carrier); // get rid of this first so we don't recusrively fire that event
- RemComp(carrier);
- RemComp(carried);
- RemComp(carried);
- _actionBlockerSystem.UpdateCanMove(carried);
- _virtualItemSystem.DeleteInHandsMatching(carrier, carried);
- Transform(carried).AttachToGridOrMap();
- _standingState.Stand(carried);
- _movementSpeed.RefreshMovementSpeedModifiers(carrier);
- }
-
- private void ApplyCarrySlowdown(EntityUid carrier, EntityUid carried)
- {
- var massRatio = MassContest(carrier, carried);
-
- if (massRatio == 0)
- massRatio = 1;
-
- var massRatioSq = Math.Pow(massRatio, 2);
- var modifier = (1 - (0.15 / massRatioSq));
- modifier = Math.Max(0.1, modifier);
- var slowdownComp = EnsureComp(carrier);
- _slowdown.SetModifier(carrier, (float) modifier, (float) modifier, slowdownComp);
- }
-
- public bool CanCarry(EntityUid carrier, EntityUid carried, CarriableComponent? carriedComp = null)
- {
- if (!Resolve(carried, ref carriedComp, false))
- return false;
-
- if (carriedComp.CancelToken != null)
- return false;
-
- if (!HasComp(Transform(carrier).ParentUid))
- return false;
-
- if (HasComp(carrier) || HasComp(carried))
- return false;
-
- // if (_respirator.IsReceivingCPR(carried))
- // return false;
-
- if (!TryComp(carrier, out var hands))
- return false;
-
- if (hands.CountFreeHands() < carriedComp.FreeHandsRequired)
- return false;
-
- return true;
- }
-
- private float MassContest(EntityUid roller, EntityUid target, PhysicsComponent? rollerPhysics = null, PhysicsComponent? targetPhysics = null)
- {
- if (!Resolve(roller, ref rollerPhysics, false) || !Resolve(target, ref targetPhysics, false))
- return 1f;
-
- if (targetPhysics.FixturesMass == 0)
- return 1f;
-
- return rollerPhysics.FixturesMass / targetPhysics.FixturesMass;
- }
-
- private TimeSpan GetPickupDuration(EntityUid carrier, EntityUid carried)
- {
- var length = TimeSpan.FromSeconds(3);
-
- var mod = MassContest(carrier, carried);
- if (mod != 0)
- length /= mod;
-
- return length;
- }
-
- public override void Update(float frameTime)
- {
- var query = EntityQueryEnumerator();
- while (query.MoveNext(out var carried, out var comp))
- {
- var carrier = comp.Carrier;
- if (carrier is not { Valid: true } || carried is not { Valid: true })
- continue;
-
- // SOMETIMES - when an entity is inserted into disposals, or a cryosleep chamber - it can get re-parented without a proper reparent event
- // when this happens, it needs to be dropped because it leads to weird behavior
- if (Transform(carried).ParentUid != carrier)
- {
- DropCarried(carrier, carried);
- continue;
- }
-
- // Make sure the carried entity is always centered relative to the carrier, as gravity pulls can offset it otherwise
- var xform = Transform(carried);
- if (!xform.LocalPosition.Equals(Vector2.Zero))
- {
- xform.LocalPosition = Vector2.Zero;
- }
- }
- query.Dispose();
- }
- }
-}
diff --git a/Content.Server/Nyanotrasen/Item/PseudoItem/PseudoItemSystem.cs b/Content.Server/Nyanotrasen/Item/PseudoItem/PseudoItemSystem.cs
index 6df387e6ba8..7437d293da6 100644
--- a/Content.Server/Nyanotrasen/Item/PseudoItem/PseudoItemSystem.cs
+++ b/Content.Server/Nyanotrasen/Item/PseudoItem/PseudoItemSystem.cs
@@ -1,9 +1,9 @@
-using Content.Server.Carrying;
using Content.Server.DoAfter;
using Content.Server.Item;
using Content.Server.Popups;
using Content.Server.Storage.EntitySystems;
using Content.Shared.Bed.Sleep;
+using Content.Shared.DeltaV.Carrying;
using Content.Shared.DoAfter;
using Content.Shared.IdentityManagement;
using Content.Shared.Item;
diff --git a/Content.Server/Nyanotrasen/Kitchen/Components/DeepFryerComponent.cs b/Content.Server/Nyanotrasen/Kitchen/Components/DeepFryerComponent.cs
index d77bec6b1ae..faf27484ce9 100644
--- a/Content.Server/Nyanotrasen/Kitchen/Components/DeepFryerComponent.cs
+++ b/Content.Server/Nyanotrasen/Kitchen/Components/DeepFryerComponent.cs
@@ -11,230 +11,184 @@
using Robust.Shared.Containers;
using Robust.Shared.Prototypes;
using Robust.Shared.Serialization.TypeSerializers.Implementations.Custom;
-using Robust.Shared.Serialization.TypeSerializers.Implementations.Custom.Prototype;
-using Robust.Shared.Serialization.TypeSerializers.Implementations.Custom.Prototype.Set;
-namespace Content.Server.Nyanotrasen.Kitchen.Components
+namespace Content.Server.Nyanotrasen.Kitchen.Components;
+
+// TODO: move to shared and get rid of SharedDeepFryerComponent
+[RegisterComponent, Access(typeof(SharedDeepfryerSystem))]
+public sealed partial class DeepFryerComponent : SharedDeepFryerComponent
{
- [RegisterComponent]
- [Access(typeof(SharedDeepfryerSystem))]
- // This line appears to be depracted: [ComponentReference(typeof(SharedDeepFryerComponent))]
- public sealed partial class DeepFryerComponent : SharedDeepFryerComponent
- {
- // There are three levels to how the deep fryer treats entities.
- //
- // 1. An entity can be rejected by the blacklist and be untouched by
- // anything other than heat damage.
- //
- // 2. An entity can be deep-fried but not turned into an edible. The
- // change will be mostly cosmetic. Any entity that does not match
- // the blacklist will fall into this category.
- //
- // 3. An entity can be deep-fried and turned into something edible. The
- // change will permit the item to be permanently destroyed by eating
- // it.
-
- ///
- /// When will the deep fryer layer on the next stage of crispiness?
- ///
- [DataField("nextFryTime", customTypeSerializer: typeof(TimeOffsetSerializer))]
- public TimeSpan NextFryTime { get; set; }
-
- ///
- /// How much waste needs to be added at the next update interval?
- ///
- public FixedPoint2 WasteToAdd { get; set; } = FixedPoint2.Zero;
-
- ///
- /// How often are items in the deep fryer fried?
- ///
- [ViewVariables(VVAccess.ReadWrite)]
- [DataField("fryInterval")]
- public TimeSpan FryInterval { get; set; } = TimeSpan.FromSeconds(5);
-
- ///
- /// What entities cannot be deep-fried no matter what?
- ///
- [ViewVariables(VVAccess.ReadWrite)]
- [DataField("blacklist")]
- public EntityWhitelist? Blacklist { get; set; }
-
- ///
- /// What entities can be deep-fried into being edible?
- ///
- [ViewVariables(VVAccess.ReadWrite)]
- [DataField("whitelist")]
- public EntityWhitelist? Whitelist { get; set; }
-
- ///
- /// What are over-cooked and burned entities turned into?
- ///
- ///
- /// To prevent unwanted destruction of items, only food can be turned
- /// into this.
- ///
- [ViewVariables(VVAccess.ReadWrite)]
- [DataField("charredPrototype", customTypeSerializer: typeof(PrototypeIdSerializer))]
- public string? CharredPrototype { get; set; }
-
- ///
- /// What reagents are considered valid cooking oils?
- ///
- [ViewVariables(VVAccess.ReadWrite)]
- [DataField("fryingOils", customTypeSerializer: typeof(PrototypeIdHashSetSerializer))]
- public HashSet FryingOils { get; set; } = new();
-
- ///
- /// What reagents are added to tasty deep-fried food?
- /// JJ Comment: I removed Solution from this. Unsure if I need to replace it with something.
- ///
- [ViewVariables(VVAccess.ReadWrite)]
- [DataField("goodReagents")]
- public List GoodReagents { get; set; } = new();
-
- ///
- /// What reagents are added to terrible deep-fried food?
- /// JJ Comment: I removed Solution from this. Unsure if I need to replace it with something.
- ///
- [ViewVariables(VVAccess.ReadWrite)]
- [DataField("badReagents")]
- public List BadReagents { get; set; } = new();
-
- ///
- /// What reagents replace every 1 unit of oil spent on frying?
- /// JJ Comment: I removed Solution from this. Unsure if I need to replace it with something.
- ///
- [ViewVariables(VVAccess.ReadWrite)]
- [DataField("wasteReagents")]
- public List WasteReagents { get; set; } = new();
-
- ///
- /// What flavors go well with deep frying?
- ///
- [ViewVariables(VVAccess.ReadWrite)]
- [DataField("goodFlavors", customTypeSerializer: typeof(PrototypeIdHashSetSerializer))]
- public HashSet GoodFlavors { get; set; } = new();
-
- ///
- /// What flavors don't go well with deep frying?
- ///
- [ViewVariables(VVAccess.ReadWrite)]
- [DataField("badFlavors", customTypeSerializer: typeof(PrototypeIdHashSetSerializer))]
- public HashSet BadFlavors { get; set; } = new();
-
- ///
- /// How much is the price coefficiency of a food changed for each good flavor?
- ///
- [ViewVariables(VVAccess.ReadWrite)]
- [DataField("goodFlavorPriceBonus")]
- public float GoodFlavorPriceBonus { get; set; } = 0.2f;
-
- ///
- /// How much is the price coefficiency of a food changed for each bad flavor?
- ///
- [ViewVariables(VVAccess.ReadWrite)]
- [DataField("badFlavorPriceMalus")]
- public float BadFlavorPriceMalus { get; set; } = -0.3f;
-
- ///
- /// What is the name of the solution container for the fryer's oil?
- ///
- [ViewVariables(VVAccess.ReadWrite)]
- [DataField("solution")]
- public string SolutionName { get; set; } = "vat_oil";
-
- public Solution Solution { get; set; } = default!;
-
- ///
- /// What is the name of the entity container for items inside the deep fryer?
- ///
- [DataField("storage")]
- public string StorageName { get; set; } = "vat_entities";
-
- public BaseContainer Storage { get; set; } = default!;
-
- ///
- /// How much solution should be imparted based on an item's size?
- ///
- [ViewVariables(VVAccess.ReadWrite)]
- [DataField("solutionSizeCoefficient")]
- public FixedPoint2 SolutionSizeCoefficient { get; set; } = 1f;
-
- ///
- /// What's the maximum amount of solution that should ever be imparted?
- ///
- [ViewVariables(VVAccess.ReadWrite)]
- [DataField("solutionSplitMax")]
- public FixedPoint2 SolutionSplitMax { get; set; } = 10f;
-
- ///
- /// What percent of the fryer's solution has to be oil in order for it to fry?
- ///
- ///
- /// The chef will have to clean it out occasionally, and if too much
- /// non-oil reagents are added, the vat will have to be drained.
- ///
- [ViewVariables(VVAccess.ReadWrite)]
- [DataField("fryingOilThreshold")]
- public FixedPoint2 FryingOilThreshold { get; set; } = 0.5f;
-
- ///
- /// What is the bare minimum number of oil units to prevent the fryer
- /// from unsafe operation?
- ///
- [ViewVariables(VVAccess.ReadWrite)]
- [DataField("safeOilVolume")]
- public FixedPoint2 SafeOilVolume { get; set; } = 10f;
-
- [ViewVariables(VVAccess.ReadWrite)]
- [DataField("unsafeOilVolumeEffects")]
- public List UnsafeOilVolumeEffects = new();
-
- ///
- /// What is the temperature of the vat when the deep fryer is powered?
- ///
- [ViewVariables(VVAccess.ReadWrite)]
- [DataField("poweredTemperature")]
- public float PoweredTemperature = 550.0f;
-
- ///
- /// How many entities can this deep fryer hold?
- ///
- [ViewVariables(VVAccess.ReadWrite)]
- public int StorageMaxEntities = 4;
-
- ///
- /// How many entities can be held, at a minimum?
- ///
- [ViewVariables(VVAccess.ReadWrite)]
- [DataField("baseStorageMaxEntities")]
- public int BaseStorageMaxEntities = 4;
-
- // ///
- // /// What upgradeable machine part dictates the quality of the storage size?
- // ///
- // [DataField("machinePartStorageMax", customTypeSerializer: typeof(PrototypeIdSerializer))]
- // public string MachinePartStorageMax = "MatterBin";
-
- ///
- /// How much extra storage is added per part rating?
- ///
- [ViewVariables(VVAccess.ReadWrite)]
- [DataField("storagePerPartRating")]
- public int StoragePerPartRating = 4;
-
- ///
- /// What sound is played when an item is inserted into hot oil?
- ///
- [ViewVariables(VVAccess.ReadWrite)]
- [DataField("soundInsertItem")]
- public SoundSpecifier SoundInsertItem = new SoundPathSpecifier("/Audio/Nyanotrasen/Machines/deepfryer_basket_add_item.ogg");
-
- ///
- /// What sound is played when an item is removed?
- ///
- [ViewVariables(VVAccess.ReadWrite)]
- [DataField("soundRemoveItem")]
- public SoundSpecifier SoundRemoveItem = new SoundPathSpecifier("/Audio/Nyanotrasen/Machines/deepfryer_basket_remove_item.ogg");
- }
+ // There are three levels to how the deep fryer treats entities.
+ //
+ // 1. An entity can be rejected by the blacklist and be untouched by
+ // anything other than heat damage.
+ //
+ // 2. An entity can be deep-fried but not turned into an edible. The
+ // change will be mostly cosmetic. Any entity that does not match
+ // the blacklist will fall into this category.
+ //
+ // 3. An entity can be deep-fried and turned into something edible. The
+ // change will permit the item to be permanently destroyed by eating
+ // it.
+
+ ///
+ /// When will the deep fryer layer on the next stage of crispiness?
+ ///
+ [DataField(customTypeSerializer: typeof(TimeOffsetSerializer))]
+ public TimeSpan NextFryTime;
+
+ ///
+ /// How much waste needs to be added at the next update interval?
+ ///
+ [DataField]
+ public FixedPoint2 WasteToAdd = FixedPoint2.Zero;
+
+ ///
+ /// How often are items in the deep fryer fried?
+ ///
+ [DataField]
+ public TimeSpan FryInterval = TimeSpan.FromSeconds(5);
+
+ ///
+ /// What entities cannot be deep-fried no matter what?
+ ///
+ [DataField]
+ public EntityWhitelist? Blacklist;
+
+ ///
+ /// What entities can be deep-fried into being edible?
+ ///
+ [DataField]
+ public EntityWhitelist? Whitelist;
+
+ ///
+ /// What are over-cooked and burned entities turned into?
+ ///
+ ///
+ /// To prevent unwanted destruction of items, only food can be turned
+ /// into this.
+ ///
+ [DataField]
+ public EntProtoId? CharredPrototype;
+
+ ///
+ /// What reagents are considered valid cooking oils?
+ ///
+ [DataField]
+ public HashSet> FryingOils = new();
+
+ ///
+ /// What reagents are added to tasty deep-fried food?
+ ///
+ [DataField]
+ public List GoodReagents = new();
+
+ ///
+ /// What reagents are added to terrible deep-fried food?
+ ///
+ [DataField]
+ public List BadReagents = new();
+
+ ///
+ /// What reagents replace every 1 unit of oil spent on frying?
+ ///
+ [DataField]
+ public List WasteReagents = new();
+
+ ///
+ /// What flavors go well with deep frying?
+ ///
+ [DataField]
+ public HashSet> GoodFlavors = new();
+
+ ///
+ /// What flavors don't go well with deep frying?
+ ///
+ [DataField]
+ public HashSet> BadFlavors = new();
+
+ ///
+ /// How much is the price coefficiency of a food changed for each good flavor?
+ ///
+ [DataField]
+ public float GoodFlavorPriceBonus = 0.2f;
+
+ ///
+ /// How much is the price coefficiency of a food changed for each bad flavor?
+ ///
+ [DataField]
+ public float BadFlavorPriceMalus = -0.3f;
+
+ ///
+ /// What is the name of the solution container for the fryer's oil?
+ ///
+ [DataField]
+ public string SolutionName = "vat_oil";
+
+ // TODO: Entity
+ public Solution Solution = default!;
+
+ ///
+ /// What is the name of the entity container for items inside the deep fryer?
+ ///
+ [DataField("storage")]
+ public string StorageName = "vat_entities";
+
+ public BaseContainer Storage = default!;
+
+ ///
+ /// How much solution should be imparted based on an item's size?
+ ///
+ [DataField]
+ public FixedPoint2 SolutionSizeCoefficient = 1f;
+
+ ///
+ /// What's the maximum amount of solution that should ever be imparted?
+ ///
+ [DataField]
+ public FixedPoint2 SolutionSplitMax = 10f;
+
+ ///
+ /// What percent of the fryer's solution has to be oil in order for it to fry?
+ ///
+ ///
+ /// The chef will have to clean it out occasionally, and if too much
+ /// non-oil reagents are added, the vat will have to be drained.
+ ///
+ [DataField]
+ public FixedPoint2 FryingOilThreshold = 0.5f;
+
+ ///
+ /// What is the bare minimum number of oil units to prevent the fryer
+ /// from unsafe operation?
+ ///
+ [DataField]
+ public FixedPoint2 SafeOilVolume = 10f;
+
+ [DataField]
+ public List UnsafeOilVolumeEffects = new();
+
+ ///
+ /// What is the temperature of the vat when the deep fryer is powered?
+ ///
+ [DataField]
+ public float PoweredTemperature = 550.0f;
+
+ ///
+ /// How many entities can this deep fryer hold?
+ ///
+ [DataField]
+ public int StorageMaxEntities = 4;
+
+ ///
+ /// What sound is played when an item is inserted into hot oil?
+ ///
+ [DataField]
+ public SoundSpecifier SoundInsertItem = new SoundPathSpecifier("/Audio/Nyanotrasen/Machines/deepfryer_basket_add_item.ogg");
+
+ ///
+ /// What sound is played when an item is removed?
+ ///
+ [DataField]
+ public SoundSpecifier SoundRemoveItem = new SoundPathSpecifier("/Audio/Nyanotrasen/Machines/deepfryer_basket_remove_item.ogg");
}
diff --git a/Content.Server/Nyanotrasen/Kitchen/EntitySystems/DeepFryerSystem.Results.cs b/Content.Server/Nyanotrasen/Kitchen/EntitySystems/DeepFryerSystem.Results.cs
index 3f93787934c..fa2807509a6 100644
--- a/Content.Server/Nyanotrasen/Kitchen/EntitySystems/DeepFryerSystem.Results.cs
+++ b/Content.Server/Nyanotrasen/Kitchen/EntitySystems/DeepFryerSystem.Results.cs
@@ -11,15 +11,20 @@
using Content.Shared.FixedPoint;
using Content.Shared.Mobs.Components;
using Content.Shared.NPC;
+using Content.Shared.Nutrition;
using Content.Shared.Nutrition.Components;
using Content.Shared.Nyanotrasen.Kitchen.Components;
using Content.Shared.Paper;
+using Robust.Shared.Prototypes;
using Robust.Shared.Random;
namespace Content.Server.Nyanotrasen.Kitchen.EntitySystems;
public sealed partial class DeepFryerSystem
{
+ private HashSet> _badFlavors = new();
+ private HashSet> _goodFlavors = new();
+
///
/// Make an item look deep-fried.
///
@@ -129,33 +134,33 @@ private void MakeEdible(EntityUid uid, DeepFryerComponent component, EntityUid i
var extraSolution = new Solution();
if (TryComp(item, out FlavorProfileComponent? flavorProfileComponent))
{
- HashSet goodFlavors = new(flavorProfileComponent.Flavors);
- goodFlavors.IntersectWith(component.GoodFlavors);
+ _goodFlavors.Clear();
+ _goodFlavors.IntersectWith(component.GoodFlavors);
- HashSet badFlavors = new(flavorProfileComponent.Flavors);
- badFlavors.IntersectWith(component.BadFlavors);
+ _badFlavors.Clear();
+ _badFlavors.IntersectWith(component.BadFlavors);
deepFriedComponent.PriceCoefficient = Math.Max(0.01f,
1.0f
- + goodFlavors.Count * component.GoodFlavorPriceBonus
- - badFlavors.Count * component.BadFlavorPriceMalus);
+ + _goodFlavors.Count * component.GoodFlavorPriceBonus
+ - _badFlavors.Count * component.BadFlavorPriceMalus);
- if (goodFlavors.Count > 0)
+ if (_goodFlavors.Count > 0)
{
foreach (var reagent in component.GoodReagents)
{
- extraSolution.AddReagent(reagent.Reagent.ToString(), reagent.Quantity * goodFlavors.Count);
+ extraSolution.AddReagent(reagent.Reagent.ToString(), reagent.Quantity * _goodFlavors.Count);
// Mask the taste of "medicine."
flavorProfileComponent.IgnoreReagents.Add(reagent.Reagent.ToString());
}
}
- if (badFlavors.Count > 0)
+ if (_badFlavors.Count > 0)
{
foreach (var reagent in component.BadReagents)
{
- extraSolution.AddReagent(reagent.Reagent.ToString(), reagent.Quantity * badFlavors.Count);
+ extraSolution.AddReagent(reagent.Reagent.ToString(), reagent.Quantity * _badFlavors.Count);
}
}
}
diff --git a/Content.Server/Nyanotrasen/Kitchen/EntitySystems/DeepFryerSystem.cs b/Content.Server/Nyanotrasen/Kitchen/EntitySystems/DeepFryerSystem.cs
index 40a658f0c44..4ac8684a7a3 100644
--- a/Content.Server/Nyanotrasen/Kitchen/EntitySystems/DeepFryerSystem.cs
+++ b/Content.Server/Nyanotrasen/Kitchen/EntitySystems/DeepFryerSystem.cs
@@ -105,7 +105,6 @@ public override void Initialize()
SubscribeLocalEvent(OnInitDeepFryer);
SubscribeLocalEvent(OnPowerChange);
- // SubscribeLocalEvent(OnRefreshParts);
SubscribeLocalEvent(OnDeconstruct);
SubscribeLocalEvent(OnDestruction);
SubscribeLocalEvent(OnThrowHitBy);
@@ -437,14 +436,6 @@ private void OnDestruction(EntityUid uid, DeepFryerComponent component, Destruct
_containerSystem.EmptyContainer(component.Storage, true);
}
- // private void OnRefreshParts(EntityUid uid, DeepFryerComponent component, RefreshPartsEvent args)
- // {
- // var ratingStorage = args.PartRatings[component.MachinePartStorageMax];
- //
- // component.StorageMaxEntities = component.BaseStorageMaxEntities +
- // (int) (component.StoragePerPartRating * (ratingStorage - 1));
- // }
-
///
/// Allow thrown items to land in a basket.
///
diff --git a/Content.Server/Resist/EscapeInventorySystem.cs b/Content.Server/Resist/EscapeInventorySystem.cs
index 93a83465861..eec8ebb5072 100644
--- a/Content.Server/Resist/EscapeInventorySystem.cs
+++ b/Content.Server/Resist/EscapeInventorySystem.cs
@@ -1,6 +1,5 @@
using Content.Server.Popups;
using Content.Shared.Storage;
-using Content.Server.Carrying; // Carrying system from Nyanotrasen.
using Content.Shared.Inventory;
using Content.Shared.Hands.EntitySystems;
using Content.Shared.Storage.Components;
@@ -25,7 +24,6 @@ public sealed class EscapeInventorySystem : EntitySystem
[Dependency] private readonly SharedContainerSystem _containerSystem = default!;
[Dependency] private readonly ActionBlockerSystem _actionBlockerSystem = default!;
[Dependency] private readonly SharedHandsSystem _handsSystem = default!;
- [Dependency] private readonly CarryingSystem _carryingSystem = default!; // Carrying system from Nyanotrasen.
[Dependency] private readonly SharedActionsSystem _actions = default!; // DeltaV
///
@@ -109,13 +107,6 @@ private void OnEscape(EntityUid uid, CanEscapeInventoryComponent component, Esca
if (args.Handled || args.Cancelled)
return;
- if (TryComp(uid, out var carried)) // Start of carrying system of nyanotrasen.
- {
- _carryingSystem.DropCarried(carried.Carrier, uid);
- return;
- } // End of carrying system of nyanotrasen.
-
-
_containerSystem.AttachParentToContainerOrGrid((uid, Transform(uid)));
args.Handled = true;
}
diff --git a/Content.Shared/DeltaV/Carrying/BeingCarriedComponent.cs b/Content.Shared/DeltaV/Carrying/BeingCarriedComponent.cs
new file mode 100644
index 00000000000..7e519e7e04b
--- /dev/null
+++ b/Content.Shared/DeltaV/Carrying/BeingCarriedComponent.cs
@@ -0,0 +1,14 @@
+using Robust.Shared.GameStates;
+
+namespace Content.Shared.DeltaV.Carrying;
+
+///
+/// Stores the carrier of an entity being carried.
+///
+[RegisterComponent, NetworkedComponent, Access(typeof(CarryingSystem))]
+[AutoGenerateComponentState]
+public sealed partial class BeingCarriedComponent : Component
+{
+ [DataField, AutoNetworkedField]
+ public EntityUid Carrier;
+}
diff --git a/Content.Shared/DeltaV/Carrying/CarriableComponent.cs b/Content.Shared/DeltaV/Carrying/CarriableComponent.cs
new file mode 100644
index 00000000000..ad1968aec62
--- /dev/null
+++ b/Content.Shared/DeltaV/Carrying/CarriableComponent.cs
@@ -0,0 +1,14 @@
+using Robust.Shared.GameStates;
+
+namespace Content.Shared.DeltaV.Carrying;
+
+[RegisterComponent, NetworkedComponent, Access(typeof(CarryingSystem))]
+public sealed partial class CarriableComponent : Component
+{
+ ///
+ /// Number of free hands required
+ /// to carry the entity
+ ///
+ [DataField]
+ public int FreeHandsRequired = 2;
+}
diff --git a/Content.Shared/DeltaV/Carrying/CarryDoAfterEvent.cs b/Content.Shared/DeltaV/Carrying/CarryDoAfterEvent.cs
new file mode 100644
index 00000000000..7ea0375518a
--- /dev/null
+++ b/Content.Shared/DeltaV/Carrying/CarryDoAfterEvent.cs
@@ -0,0 +1,7 @@
+using Content.Shared.DoAfter;
+using Robust.Shared.Serialization;
+
+namespace Content.Shared.DeltaV.Carrying;
+
+[Serializable, NetSerializable]
+public sealed partial class CarryDoAfterEvent : SimpleDoAfterEvent;
diff --git a/Content.Shared/DeltaV/Carrying/CarryingComponent.cs b/Content.Shared/DeltaV/Carrying/CarryingComponent.cs
new file mode 100644
index 00000000000..e6661da0e04
--- /dev/null
+++ b/Content.Shared/DeltaV/Carrying/CarryingComponent.cs
@@ -0,0 +1,14 @@
+using Robust.Shared.GameStates;
+
+namespace Content.Shared.DeltaV.Carrying;
+
+///
+/// Added to an entity when they are carrying somebody.
+///
+[RegisterComponent, NetworkedComponent, Access(typeof(CarryingSystem))]
+[AutoGenerateComponentState]
+public sealed partial class CarryingComponent : Component
+{
+ [DataField, AutoNetworkedField]
+ public EntityUid Carried;
+}
diff --git a/Content.Shared/DeltaV/Carrying/CarryingSlowdownComponent.cs b/Content.Shared/DeltaV/Carrying/CarryingSlowdownComponent.cs
new file mode 100644
index 00000000000..9e1be89370c
--- /dev/null
+++ b/Content.Shared/DeltaV/Carrying/CarryingSlowdownComponent.cs
@@ -0,0 +1,14 @@
+using Robust.Shared.GameStates;
+
+namespace Content.Shared.DeltaV.Carrying;
+
+[RegisterComponent, NetworkedComponent, Access(typeof(CarryingSlowdownSystem))]
+[AutoGenerateComponentState]
+public sealed partial class CarryingSlowdownComponent : Component
+{
+ ///
+ /// Modifier for both walk and sprint speed.
+ ///
+ [DataField, AutoNetworkedField]
+ public float Modifier = 1.0f;
+}
diff --git a/Content.Shared/DeltaV/Carrying/CarryingSlowdownSystem.cs b/Content.Shared/DeltaV/Carrying/CarryingSlowdownSystem.cs
new file mode 100644
index 00000000000..677c53eedc0
--- /dev/null
+++ b/Content.Shared/DeltaV/Carrying/CarryingSlowdownSystem.cs
@@ -0,0 +1,29 @@
+using Content.Shared.Movement.Systems;
+
+namespace Content.Shared.DeltaV.Carrying;
+
+public sealed class CarryingSlowdownSystem : EntitySystem
+{
+ [Dependency] private readonly MovementSpeedModifierSystem _movementSpeed = default!;
+
+ public override void Initialize()
+ {
+ base.Initialize();
+
+ SubscribeLocalEvent(OnRefreshMoveSpeed);
+ }
+
+ public void SetModifier(Entity ent, float modifier)
+ {
+ ent.Comp ??= EnsureComp(ent);
+ ent.Comp.Modifier = modifier;
+ Dirty(ent, ent.Comp);
+
+ _movementSpeed.RefreshMovementSpeedModifiers(ent);
+ }
+
+ private void OnRefreshMoveSpeed(Entity ent, ref RefreshMovementSpeedModifiersEvent args)
+ {
+ args.ModifySpeed(ent.Comp.Modifier, ent.Comp.Modifier);
+ }
+}
diff --git a/Content.Shared/DeltaV/Carrying/CarryingSystem.cs b/Content.Shared/DeltaV/Carrying/CarryingSystem.cs
new file mode 100644
index 00000000000..2b47c49abd1
--- /dev/null
+++ b/Content.Shared/DeltaV/Carrying/CarryingSystem.cs
@@ -0,0 +1,384 @@
+using Content.Shared.ActionBlocker;
+using Content.Shared.Buckle.Components;
+using Content.Shared.Climbing.Events;
+using Content.Shared.DoAfter;
+using Content.Shared.Hands;
+using Content.Shared.Hands.Components;
+using Content.Shared.Interaction.Events;
+using Content.Shared.Inventory.VirtualItem;
+using Content.Shared.Item;
+using Content.Shared.Mobs;
+using Content.Shared.Movement.Events;
+using Content.Shared.Movement.Pulling.Components;
+using Content.Shared.Movement.Pulling.Events;
+using Content.Shared.Movement.Pulling.Systems;
+using Content.Shared.Movement.Systems;
+using Content.Shared.Nyanotrasen.Item.PseudoItem;
+using Content.Shared.Popups;
+using Content.Shared.Pulling;
+using Content.Shared.Resist;
+using Content.Shared.Standing;
+using Content.Shared.Storage;
+using Content.Shared.Stunnable;
+using Content.Shared.Throwing;
+using Content.Shared.Verbs;
+using Robust.Shared.Map.Components;
+using Robust.Shared.Network;
+using Robust.Shared.Physics.Components;
+using System.Numerics;
+
+namespace Content.Shared.DeltaV.Carrying;
+
+public sealed class CarryingSystem : EntitySystem
+{
+ [Dependency] private readonly ActionBlockerSystem _actionBlocker = default!;
+ [Dependency] private readonly CarryingSlowdownSystem _slowdown = default!;
+ [Dependency] private readonly INetManager _net = default!;
+ [Dependency] private readonly MovementSpeedModifierSystem _movementSpeed = default!;
+ [Dependency] private readonly PullingSystem _pulling = default!;
+ [Dependency] private readonly SharedDoAfterSystem _doAfter = default!;
+ [Dependency] private readonly SharedPopupSystem _popup = default!;
+ [Dependency] private readonly SharedPseudoItemSystem _pseudoItem = default!;
+ [Dependency] private readonly SharedTransformSystem _transform = default!;
+ [Dependency] private readonly StandingStateSystem _standingState = default!;
+ [Dependency] private readonly SharedVirtualItemSystem _virtualItem = default!;
+
+ private EntityQuery _physicsQuery;
+
+ public override void Initialize()
+ {
+ base.Initialize();
+
+ _physicsQuery = GetEntityQuery();
+
+ SubscribeLocalEvent>(AddCarryVerb);
+ SubscribeLocalEvent>(AddInsertCarriedVerb);
+ SubscribeLocalEvent(OnVirtualItemDeleted);
+ SubscribeLocalEvent(OnThrow);
+ SubscribeLocalEvent(OnParentChanged);
+ SubscribeLocalEvent(OnMobStateChanged);
+ SubscribeLocalEvent(OnInteractionAttempt);
+ SubscribeLocalEvent(OnMoveAttempt);
+ SubscribeLocalEvent(OnStandAttempt);
+ SubscribeLocalEvent(OnInteractedWith);
+ SubscribeLocalEvent(OnPullAttempt);
+ SubscribeLocalEvent(OnDrop);
+ SubscribeLocalEvent(OnDrop);
+ SubscribeLocalEvent(OnDrop);
+ SubscribeLocalEvent(OnDrop);
+ SubscribeLocalEvent(OnDrop);
+ SubscribeLocalEvent(OnDrop);
+ SubscribeLocalEvent(OnDoAfter);
+ }
+
+ private void AddCarryVerb(Entity ent, ref GetVerbsEvent args)
+ {
+ var user = args.User;
+ var target = args.Target;
+ if (!args.CanInteract || !args.CanAccess || user == target)
+ return;
+
+ if (!CanCarry(user, ent))
+ return;
+
+ args.Verbs.Add(new AlternativeVerb()
+ {
+ Act = () => StartCarryDoAfter(user, ent),
+ Text = Loc.GetString("carry-verb"),
+ Priority = 2
+ });
+ }
+
+ private void AddInsertCarriedVerb(Entity ent, ref GetVerbsEvent args)
+ {
+ // If the person is carrying someone, and the carried person is a pseudo-item, and the target entity is a storage,
+ // then add an action to insert the carried entity into the target
+ // AKA put carried felenid into a duffelbag
+ if (args.Using is not {} carried || !args.CanAccess || !TryComp(carried, out var pseudoItem))
+ return;
+
+ var target = args.Target;
+ if (!TryComp(target, out var storageComp))
+ return;
+
+ if (!_pseudoItem.CheckItemFits((carried, pseudoItem), (target, storageComp)))
+ return;
+
+ args.Verbs.Add(new InnateVerb()
+ {
+ Act = () =>
+ {
+ DropCarried(ent, carried);
+ _pseudoItem.TryInsert(target, carried, pseudoItem, storageComp);
+ },
+ Text = Loc.GetString("action-name-insert-other", ("target", carried)),
+ Priority = 2
+ });
+ }
+
+ ///
+ /// Since the carried entity is stored as 2 virtual items, when deleted we want to drop them.
+ ///
+ private void OnVirtualItemDeleted(Entity ent, ref VirtualItemDeletedEvent args)
+ {
+ if (HasComp(args.BlockingEntity))
+ DropCarried(ent, args.BlockingEntity);
+ }
+
+ ///
+ /// Basically using virtual item passthrough to throw the carried person. A new age!
+ /// Maybe other things besides throwing should use virt items like this...
+ ///
+ private void OnThrow(Entity ent, ref BeforeThrowEvent args)
+ {
+ if (!TryComp(args.ItemUid, out var virtItem) || !HasComp(virtItem.BlockingEntity))
+ return;
+
+ var carried = virtItem.BlockingEntity;
+ args.ItemUid = carried;
+
+ args.ThrowSpeed = 5f * MassContest(ent, carried);
+ }
+
+ private void OnParentChanged(Entity ent, ref EntParentChangedMessage args)
+ {
+ var xform = Transform(ent);
+ if (xform.MapUid != args.OldMapId)
+ return;
+
+ // Do not drop the carried entity if the new parent is a grid
+ if (xform.ParentUid == xform.GridUid)
+ return;
+
+ DropCarried(ent, ent.Comp.Carried);
+ }
+
+ private void OnMobStateChanged(Entity ent, ref MobStateChangedEvent args)
+ {
+ DropCarried(ent, ent.Comp.Carried);
+ }
+
+ ///
+ /// Only let the person being carried interact with their carrier and things on their person.
+ ///
+ private void OnInteractionAttempt(Entity ent, ref InteractionAttemptEvent args)
+ {
+ if (args.Target is not {} target)
+ return;
+
+ var targetParent = Transform(target).ParentUid;
+
+ var carrier = ent.Comp.Carrier;
+ if (target != carrier && targetParent != carrier && targetParent != ent.Owner)
+ args.Cancelled = true;
+ }
+
+ private void OnMoveAttempt(Entity ent, ref UpdateCanMoveEvent args)
+ {
+ args.Cancel();
+ }
+
+ private void OnStandAttempt(Entity ent, ref StandAttemptEvent args)
+ {
+ args.Cancel();
+ }
+
+ private void OnInteractedWith(Entity ent, ref GettingInteractedWithAttemptEvent args)
+ {
+ if (args.Uid != ent.Comp.Carrier)
+ args.Cancelled = true;
+ }
+
+ private void OnPullAttempt(Entity ent, ref PullAttemptEvent args)
+ {
+ args.Cancelled = true;
+ }
+
+ private void OnDrop(Entity ent, ref TEvent args) // Augh
+ {
+ DropCarried(ent.Comp.Carrier, ent);
+ }
+
+ private void OnDoAfter(Entity ent, ref CarryDoAfterEvent args)
+ {
+ if (args.Handled || args.Cancelled)
+ return;
+
+ if (!CanCarry(args.Args.User, ent))
+ return;
+
+ Carry(args.Args.User, ent);
+ args.Handled = true;
+ }
+
+ private void StartCarryDoAfter(EntityUid carrier, Entity carried)
+ {
+ TimeSpan length = GetPickupDuration(carrier, carried);
+
+ if (length.TotalSeconds >= 9f)
+ {
+ _popup.PopupClient(Loc.GetString("carry-too-heavy"), carried, carrier, PopupType.SmallCaution);
+ return;
+ }
+
+ if (!HasComp(carried))
+ length *= 2f;
+
+ var ev = new CarryDoAfterEvent();
+ var args = new DoAfterArgs(EntityManager, carrier, length, ev, carried, target: carried)
+ {
+ BreakOnMove = true,
+ NeedHand = true
+ };
+
+ _doAfter.TryStartDoAfter(args);
+
+ // Show a popup to the person getting picked up
+ _popup.PopupEntity(Loc.GetString("carry-started", ("carrier", carrier)), carried, carried);
+ }
+
+ private void Carry(EntityUid carrier, EntityUid carried)
+ {
+ if (TryComp(carried, out var pullable))
+ _pulling.TryStopPull(carried, pullable);
+
+ var carrierXform = Transform(carrier);
+ var xform = Transform(carried);
+ _transform.AttachToGridOrMap(carrier, carrierXform);
+ _transform.AttachToGridOrMap(carried, xform);
+ _transform.SetParent(carried, xform, carrier, carrierXform);
+
+ var carryingComp = EnsureComp(carrier);
+ carryingComp.Carried = carried;
+ Dirty(carrier, carryingComp);
+ var carriedComp = EnsureComp(carried);
+ carriedComp.Carrier = carrier;
+ Dirty(carried, carriedComp);
+ EnsureComp(carried);
+
+ ApplyCarrySlowdown(carrier, carried);
+
+ _actionBlocker.UpdateCanMove(carried);
+
+ if (_net.IsClient) // no spawning prediction
+ return;
+
+ _virtualItem.TrySpawnVirtualItemInHand(carried, carrier);
+ _virtualItem.TrySpawnVirtualItemInHand(carried, carrier);
+ }
+
+ public bool TryCarry(EntityUid carrier, Entity toCarry)
+ {
+ if (!Resolve(toCarry, ref toCarry.Comp, false))
+ return false;
+
+ if (!CanCarry(carrier, (toCarry, toCarry.Comp)))
+ return false;
+
+ // The second one means that carrier is a pseudo-item and is inside a bag.
+ if (HasComp(carrier) || HasComp(carrier))
+ return false;
+
+ if (GetPickupDuration(carrier, toCarry).TotalSeconds > 9f)
+ return false;
+
+ Carry(carrier, toCarry);
+ return true;
+ }
+
+ public void DropCarried(EntityUid carrier, EntityUid carried)
+ {
+ Drop(carried);
+ RemComp(carrier); // get rid of this first so we don't recursively fire that event
+ RemComp(carrier);
+ _virtualItem.DeleteInHandsMatching(carrier, carried);
+ _movementSpeed.RefreshMovementSpeedModifiers(carrier);
+ }
+
+ private void Drop(EntityUid carried)
+ {
+ RemComp(carried);
+ RemComp(carried); // TODO SHITMED: make sure this doesnt let you make someone with no legs walk
+ _actionBlocker.UpdateCanMove(carried);
+ Transform(carried).AttachToGridOrMap();
+ _standingState.Stand(carried);
+ }
+
+ private void ApplyCarrySlowdown(EntityUid carrier, EntityUid carried)
+ {
+ var massRatio = MassContest(carrier, carried);
+
+ if (massRatio == 0)
+ massRatio = 1;
+
+ var massRatioSq = Math.Pow(massRatio, 2);
+ var modifier = (1 - (0.15 / massRatioSq));
+ modifier = Math.Max(0.1, modifier);
+ _slowdown.SetModifier(carrier, (float) modifier);
+ }
+
+ public bool CanCarry(EntityUid carrier, Entity carried)
+ {
+ return
+ carrier != carried.Owner &&
+ // can't carry multiple people, even if you have 4 hands it will break invariants when removing carryingcomponent for first carried person
+ !HasComp(carrier) &&
+ // can't carry someone in a locker, buckled, etc
+ HasComp(Transform(carrier).ParentUid) &&
+ // no tower of spacemen or stack overflow
+ !HasComp(carrier) &&
+ !HasComp(carried) &&
+ // finally check that there are enough free hands
+ TryComp(carrier, out var hands) &&
+ hands.CountFreeHands() >= carried.Comp.FreeHandsRequired;
+ }
+
+ private float MassContest(EntityUid roller, EntityUid target)
+ {
+ if (!_physicsQuery.TryComp(roller, out var rollerPhysics) || !_physicsQuery.TryComp(target, out var targetPhysics))
+ return 1f;
+
+ if (targetPhysics.FixturesMass == 0)
+ return 1f;
+
+ return rollerPhysics.FixturesMass / targetPhysics.FixturesMass;
+ }
+
+ private TimeSpan GetPickupDuration(EntityUid carrier, EntityUid carried)
+ {
+ var length = TimeSpan.FromSeconds(3);
+
+ var mod = MassContest(carrier, carried);
+ if (mod != 0)
+ length /= mod;
+
+ return length;
+ }
+
+ public override void Update(float frameTime)
+ {
+ base.Update(frameTime);
+
+ var query = EntityQueryEnumerator();
+ while (query.MoveNext(out var carried, out var comp, out var xform))
+ {
+ var carrier = comp.Carrier;
+ if (TerminatingOrDeleted(carrier))
+ {
+ RemCompDeferred(carried);
+ continue;
+ }
+
+ // SOMETIMES - when an entity is inserted into disposals, or a cryosleep chamber - it can get re-parented without a proper reparent event
+ // when this happens, it needs to be dropped because it leads to weird behavior
+ if (xform.ParentUid != carrier)
+ {
+ DropCarried(carrier, carried);
+ continue;
+ }
+
+ // Make sure the carried entity is always centered relative to the carrier, as gravity pulls can offset it otherwise
+ _transform.SetLocalPosition(carried, Vector2.Zero);
+ }
+ }
+}
diff --git a/Content.Shared/Nyanotrasen/Carrying/CarryingDoAfterEvent.cs b/Content.Shared/Nyanotrasen/Carrying/CarryingDoAfterEvent.cs
deleted file mode 100644
index 6acd6b775f3..00000000000
--- a/Content.Shared/Nyanotrasen/Carrying/CarryingDoAfterEvent.cs
+++ /dev/null
@@ -1,10 +0,0 @@
-using Robust.Shared.Serialization;
-using Content.Shared.DoAfter;
-
-namespace Content.Shared.Carrying
-{
- [Serializable, NetSerializable]
- public sealed partial class CarryDoAfterEvent : SimpleDoAfterEvent
- {
- }
-}
diff --git a/Content.Shared/Nyanotrasen/Carrying/CarryingSlowdownComponent.cs b/Content.Shared/Nyanotrasen/Carrying/CarryingSlowdownComponent.cs
deleted file mode 100644
index aabde66af0d..00000000000
--- a/Content.Shared/Nyanotrasen/Carrying/CarryingSlowdownComponent.cs
+++ /dev/null
@@ -1,28 +0,0 @@
-using Robust.Shared.GameStates;
-using Robust.Shared.Serialization;
-
-namespace Content.Shared.Carrying
-{
- [RegisterComponent, NetworkedComponent, Access(typeof(CarryingSlowdownSystem))]
-
- public sealed partial class CarryingSlowdownComponent : Component
- {
- [DataField("walkModifier", required: true)] [ViewVariables(VVAccess.ReadWrite)]
- public float WalkModifier = 1.0f;
-
- [DataField("sprintModifier", required: true)] [ViewVariables(VVAccess.ReadWrite)]
- public float SprintModifier = 1.0f;
- }
-
- [Serializable, NetSerializable]
- public sealed class CarryingSlowdownComponentState : ComponentState
- {
- public float WalkModifier;
- public float SprintModifier;
- public CarryingSlowdownComponentState(float walkModifier, float sprintModifier)
- {
- WalkModifier = walkModifier;
- SprintModifier = sprintModifier;
- }
- }
-}
diff --git a/Content.Shared/Nyanotrasen/Carrying/CarryingSlowdownSystem.cs b/Content.Shared/Nyanotrasen/Carrying/CarryingSlowdownSystem.cs
deleted file mode 100644
index 9b9c8cec10f..00000000000
--- a/Content.Shared/Nyanotrasen/Carrying/CarryingSlowdownSystem.cs
+++ /dev/null
@@ -1,47 +0,0 @@
-using Content.Shared.Movement.Systems;
-using Robust.Shared.GameStates;
-
-namespace Content.Shared.Carrying
-{
- public sealed class CarryingSlowdownSystem : EntitySystem
- {
- [Dependency] private readonly MovementSpeedModifierSystem _movementSpeed = default!;
-
- public override void Initialize()
- {
- base.Initialize();
- SubscribeLocalEvent(OnGetState);
- SubscribeLocalEvent(OnHandleState);
- SubscribeLocalEvent(OnRefreshMoveSpeed);
- }
-
- public void SetModifier(EntityUid uid, float walkSpeedModifier, float sprintSpeedModifier, CarryingSlowdownComponent? component = null)
- {
- if (!Resolve(uid, ref component))
- return;
-
- component.WalkModifier = walkSpeedModifier;
- component.SprintModifier = sprintSpeedModifier;
- _movementSpeed.RefreshMovementSpeedModifiers(uid);
- }
- private void OnGetState(EntityUid uid, CarryingSlowdownComponent component, ref ComponentGetState args)
- {
- args.State = new CarryingSlowdownComponentState(component.WalkModifier, component.SprintModifier);
- }
-
- private void OnHandleState(EntityUid uid, CarryingSlowdownComponent component, ref ComponentHandleState args)
- {
- if (args.Current is CarryingSlowdownComponentState state)
- {
- component.WalkModifier = state.WalkModifier;
- component.SprintModifier = state.SprintModifier;
-
- _movementSpeed.RefreshMovementSpeedModifiers(uid);
- }
- }
- private void OnRefreshMoveSpeed(EntityUid uid, CarryingSlowdownComponent component, RefreshMovementSpeedModifiersEvent args)
- {
- args.ModifySpeed(component.WalkModifier, component.SprintModifier);
- }
- }
-}
diff --git a/Resources/Locale/en-US/deltav/fugitive/sets.ftl b/Resources/Locale/en-US/deltav/fugitive/sets.ftl
index cb4bb4e735f..e353fd38de7 100644
--- a/Resources/Locale/en-US/deltav/fugitive/sets.ftl
+++ b/Resources/Locale/en-US/deltav/fugitive/sets.ftl
@@ -27,4 +27,3 @@ fugitive-set-disruptor-name = disruptor's kit
fugitive-set-disruptor-description =
Hack the stations various systems and use them to your advantage.
Comes with a cryptographic sequencer and camera bug.
-
diff --git a/Resources/Prototypes/DeltaV/Catalog/Cargo/cargo_food.yml b/Resources/Prototypes/DeltaV/Catalog/Cargo/cargo_food.yml
index 7c4e08cfcf0..325eb6e078a 100644
--- a/Resources/Prototypes/DeltaV/Catalog/Cargo/cargo_food.yml
+++ b/Resources/Prototypes/DeltaV/Catalog/Cargo/cargo_food.yml
@@ -87,4 +87,3 @@
cost: 500
category: Food
group: market
-
\ No newline at end of file
diff --git a/Resources/Prototypes/DeltaV/Catalog/fugitive_sets.yml b/Resources/Prototypes/DeltaV/Catalog/fugitive_sets.yml
index aad6f781bd0..b2e2328693a 100644
--- a/Resources/Prototypes/DeltaV/Catalog/fugitive_sets.yml
+++ b/Resources/Prototypes/DeltaV/Catalog/fugitive_sets.yml
@@ -70,4 +70,3 @@
content:
- Emag
- CameraBug
-
diff --git a/Resources/Prototypes/DeltaV/Entities/Objects/Specific/fugitive.yml b/Resources/Prototypes/DeltaV/Entities/Objects/Specific/fugitive.yml
index 7558a322c00..b23f4635421 100644
--- a/Resources/Prototypes/DeltaV/Entities/Objects/Specific/fugitive.yml
+++ b/Resources/Prototypes/DeltaV/Entities/Objects/Specific/fugitive.yml
@@ -14,4 +14,3 @@
- FugitiveLeverage
- FugitiveInfiltrator
- FugitiveDisruptor
-
diff --git a/Resources/Textures/DeltaV/Objects/Storage/barrel.rsi/meta.json b/Resources/Textures/DeltaV/Objects/Storage/barrel.rsi/meta.json
index 2ed4c3638b9..30f4889fd7e 100644
--- a/Resources/Textures/DeltaV/Objects/Storage/barrel.rsi/meta.json
+++ b/Resources/Textures/DeltaV/Objects/Storage/barrel.rsi/meta.json
@@ -1,20 +1,20 @@
{
- "version": 1,
- "license": "CC-BY-SA-3.0",
- "copyright": "Taken from tgstation PR https://github.com/tgstation/tgstation/blob/master/icons/obj/objects.dmi, modified by rosieposieeee",
- "size": {
- "x": 32,
- "y": 32
- },
- "states": [
- {
- "name": "base"
+ "version": 1,
+ "license": "CC-BY-SA-3.0",
+ "copyright": "Taken from tgstation PR https://github.com/tgstation/tgstation/blob/master/icons/obj/objects.dmi, modified by rosieposieeee",
+ "size": {
+ "x": 32,
+ "y": 32
},
- {
- "name": "open"
- },
- {
- "name": "closed"
- }
- ]
+ "states": [
+ {
+ "name": "base"
+ },
+ {
+ "name": "open"
+ },
+ {
+ "name": "closed"
+ }
+ ]
}
diff --git a/Resources/Textures/DeltaV/Objects/Storage/keg.rsi/meta.json b/Resources/Textures/DeltaV/Objects/Storage/keg.rsi/meta.json
index cbbc0d6e89f..ef539daf601 100644
--- a/Resources/Textures/DeltaV/Objects/Storage/keg.rsi/meta.json
+++ b/Resources/Textures/DeltaV/Objects/Storage/keg.rsi/meta.json
@@ -1,15 +1,15 @@
{
- "version": 1,
- "license": "CC-BY-SA-3.0",
- "copyright": "Made by rosieposieeee",
- "size": {
- "x": 32,
- "y": 32
- },
- "states": [
- {
- "name": "base",
- "directions": 4
- }
- ]
+ "version": 1,
+ "license": "CC-BY-SA-3.0",
+ "copyright": "Made by rosieposieeee",
+ "size": {
+ "x": 32,
+ "y": 32
+ },
+ "states": [
+ {
+ "name": "base",
+ "directions": 4
+ }
+ ]
}