From edc2b87fa145825884d8a44d43d3542c51a47c49 Mon Sep 17 00:00:00 2001
From: KOTOB <59124164+kotobdev@users.noreply.github.com>
Date: Mon, 20 Jul 2026 10:38:50 -0700
Subject: [PATCH 01/54] Cosmic Censer no longer requires fuel (#5016)
* fun allowed
* guidebook update
* Update Resources/Prototypes/_DV/CosmicCult/Objects/censer.yml
Co-authored-by: Vanessa <908648+ShepardToTheStars@users.noreply.github.com>
Signed-off-by: KOTOB <59124164+kotobdev@users.noreply.github.com>
* Update Resources/Prototypes/_DV/CosmicCult/Objects/censer.yml
Co-authored-by: Vanessa <908648+ShepardToTheStars@users.noreply.github.com>
Signed-off-by: KOTOB <59124164+kotobdev@users.noreply.github.com>
---------
Signed-off-by: KOTOB <59124164+kotobdev@users.noreply.github.com>
Co-authored-by: Vanessa <908648+ShepardToTheStars@users.noreply.github.com>
---
.../Prototypes/_DV/CosmicCult/Objects/censer.yml | 15 ---------------
.../_DV/Antagonist/CosmicCultDeconversion.xml | 5 +----
2 files changed, 1 insertion(+), 19 deletions(-)
diff --git a/Resources/Prototypes/_DV/CosmicCult/Objects/censer.yml b/Resources/Prototypes/_DV/CosmicCult/Objects/censer.yml
index 4b06f308c62..60089e1a648 100644
--- a/Resources/Prototypes/_DV/CosmicCult/Objects/censer.yml
+++ b/Resources/Prototypes/_DV/CosmicCult/Objects/censer.yml
@@ -37,22 +37,7 @@
Cold: 80
- type: Tool
qualities: Censer
- - type: Welder
- fuelSolutionName: Censer
- fuelReagent: MindbreakerToxin
- fuelConsumption: 0.5
- - type: RefillableSolution
- solution: Censer
- - type: SolutionContainerManager
- solutions:
- Censer:
- reagents:
- - ReagentId: MindbreakerToxin
- Quantity: 50
- maxVol: 50
- type: ItemTogglePointLight
- - type: Spillable
- solution: Censer
- type: ToggleableVisuals
spriteLayer: flame
inhandVisuals:
diff --git a/Resources/ServerInfo/Guidebook/_DV/Antagonist/CosmicCultDeconversion.xml b/Resources/ServerInfo/Guidebook/_DV/Antagonist/CosmicCultDeconversion.xml
index dfad0ea10e2..a49ef673f52 100644
--- a/Resources/ServerInfo/Guidebook/_DV/Antagonist/CosmicCultDeconversion.xml
+++ b/Resources/ServerInfo/Guidebook/_DV/Antagonist/CosmicCultDeconversion.xml
@@ -6,10 +6,7 @@
When mounting an effort to thwart the [color=#4cabb3]Cosmic Cult[/color], there are several methods the crew might employ to ensure their survival and safety. One of these methods is [color=Yellow]Deconversion[/color].
- To [color=Yellow]Deconvert[/color] a cosmic cultist, an [bold]Ardent Censer[/bold] must be used. Censers are fueled with Mindbreaker Toxin, which can be brewed at your chemist.
-
-
-
+ To [color=Yellow]Deconvert[/color] a cosmic cultist, an [bold]Ardent Censer[/bold] must be used.
## Suppression Methods
From 0488fcbf8cf44d6cdd2c09b1bf5753b59f58b222 Mon Sep 17 00:00:00 2001
From: Delta-V bot <135767721+DeltaV-Bot@users.noreply.github.com>
Date: Mon, 20 Jul 2026 19:39:15 +0200
Subject: [PATCH 02/54] Automatic changelog update
---
Resources/Changelog/DeltaVChangelog.yml | 14 +++++++-------
1 file changed, 7 insertions(+), 7 deletions(-)
diff --git a/Resources/Changelog/DeltaVChangelog.yml b/Resources/Changelog/DeltaVChangelog.yml
index 7db8fa8be10..9d401901d2d 100644
--- a/Resources/Changelog/DeltaVChangelog.yml
+++ b/Resources/Changelog/DeltaVChangelog.yml
@@ -1,11 +1,4 @@
Entries:
-- author: Toby222
- changes:
- - message: Removed footprint prediction (for now)
- type: Remove
- id: 2074
- time: '2026-01-16T19:07:45.0000000+00:00'
- url: https://github.com/DeltaV-Station/Delta-v/pull/5224
- author: Velcroboy
changes:
- message: Prisoners can find dull bread knives in the ChefVend.
@@ -4369,4 +4362,11 @@
id: 2574
time: '2026-07-20T00:24:43.0000000+00:00'
url: https://github.com/DeltaV-Station/Delta-v/pull/6310
+- author: kotobdev
+ changes:
+ - message: The Ardent Censer no longer requires fuel for deconversions.
+ type: Tweak
+ id: 2575
+ time: '2026-07-20T17:38:51.0000000+00:00'
+ url: https://github.com/DeltaV-Station/Delta-v/pull/5016
Order: 1
From baf36b659d9579a72baee06eaa5741d44f515bdc Mon Sep 17 00:00:00 2001
From: KOTOB <59124164+kotobdev@users.noreply.github.com>
Date: Mon, 20 Jul 2026 13:06:59 -0700
Subject: [PATCH 03/54] Freighter Crew's Jumpsuit (#6331)
* my larp...
* [pre-commit.ci] auto fixes from pre-commit.com hooks
for more information, see https://pre-commit.ci
---------
Co-authored-by: pre-commit-ci[bot] <66853113+pre-commit-ci[bot]@users.noreply.github.com>
---
.../VendingMachines/Inventories/theater.yml | 1 +
.../Entities/Clothing/Uniforms/jumpsuits.yml | 11 +++++++
.../equipped-INNERCLOTHING-monkey.png | Bin 0 -> 9505 bytes
.../equipped-INNERCLOTHING.png | Bin 0 -> 1412 bytes
.../Jumpsuit/freighter_crew.rsi/icon.png | Bin 0 -> 9239 bytes
.../freighter_crew.rsi/inhand-left.png | Bin 0 -> 9280 bytes
.../freighter_crew.rsi/inhand-right.png | Bin 0 -> 9294 bytes
.../Jumpsuit/freighter_crew.rsi/meta.json | 30 ++++++++++++++++++
8 files changed, 42 insertions(+)
create mode 100644 Resources/Textures/_DV/Clothing/Uniforms/Jumpsuit/freighter_crew.rsi/equipped-INNERCLOTHING-monkey.png
create mode 100644 Resources/Textures/_DV/Clothing/Uniforms/Jumpsuit/freighter_crew.rsi/equipped-INNERCLOTHING.png
create mode 100644 Resources/Textures/_DV/Clothing/Uniforms/Jumpsuit/freighter_crew.rsi/icon.png
create mode 100644 Resources/Textures/_DV/Clothing/Uniforms/Jumpsuit/freighter_crew.rsi/inhand-left.png
create mode 100644 Resources/Textures/_DV/Clothing/Uniforms/Jumpsuit/freighter_crew.rsi/inhand-right.png
create mode 100644 Resources/Textures/_DV/Clothing/Uniforms/Jumpsuit/freighter_crew.rsi/meta.json
diff --git a/Resources/Prototypes/Catalog/VendingMachines/Inventories/theater.yml b/Resources/Prototypes/Catalog/VendingMachines/Inventories/theater.yml
index e3805fc310f..2cdb9fee798 100644
--- a/Resources/Prototypes/Catalog/VendingMachines/Inventories/theater.yml
+++ b/Resources/Prototypes/Catalog/VendingMachines/Inventories/theater.yml
@@ -72,6 +72,7 @@
ClothingUniformJumpskirtWaitstaffFormal: 2
ClothingUniformJumpsuitWaitstaffFormal: 2
ClothingUniformJumpsuitWorkvest: 2
+ ClothingUniformJumpsuitFreighterCrew: 2
ClothingOuterDusterCoat: 2
ClothingOuterCoatNavalCoat: 2
ClothingNeckCloakWitchCloak: 2
diff --git a/Resources/Prototypes/_DV/Entities/Clothing/Uniforms/jumpsuits.yml b/Resources/Prototypes/_DV/Entities/Clothing/Uniforms/jumpsuits.yml
index e61f15dfd0b..6794d109102 100644
--- a/Resources/Prototypes/_DV/Entities/Clothing/Uniforms/jumpsuits.yml
+++ b/Resources/Prototypes/_DV/Entities/Clothing/Uniforms/jumpsuits.yml
@@ -240,6 +240,17 @@
- type: Clothing
sprite: Nyanotrasen/Clothing/Uniforms/Jumpsuit/lawyergalaxyblue.rsi
+- type: entity
+ parent: ClothingUniformBase
+ id: ClothingUniformJumpsuitFreighterCrew
+ name: freighter crew's jumpsuit
+ description: Smells minty.
+ components:
+ - type: Sprite
+ sprite: _DV/Clothing/Uniforms/Jumpsuit/freighter_crew.rsi
+ - type: Clothing
+ sprite: _DV/Clothing/Uniforms/Jumpsuit/freighter_crew.rsi
+
# Formal uniforms
- type: entity
diff --git a/Resources/Textures/_DV/Clothing/Uniforms/Jumpsuit/freighter_crew.rsi/equipped-INNERCLOTHING-monkey.png b/Resources/Textures/_DV/Clothing/Uniforms/Jumpsuit/freighter_crew.rsi/equipped-INNERCLOTHING-monkey.png
new file mode 100644
index 0000000000000000000000000000000000000000..c285784e888f766de7008f404455780cf57be8f5
GIT binary patch
literal 9505
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
literal 0
HcmV?d00001
diff --git a/Resources/Textures/_DV/Clothing/Uniforms/Jumpsuit/freighter_crew.rsi/equipped-INNERCLOTHING.png b/Resources/Textures/_DV/Clothing/Uniforms/Jumpsuit/freighter_crew.rsi/equipped-INNERCLOTHING.png
new file mode 100644
index 0000000000000000000000000000000000000000..5f9bb7428f885fa0fd8febb63db5fd4b0cb118dd
GIT binary patch
literal 1412
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
literal 0
HcmV?d00001
diff --git a/Resources/Textures/_DV/Clothing/Uniforms/Jumpsuit/freighter_crew.rsi/meta.json b/Resources/Textures/_DV/Clothing/Uniforms/Jumpsuit/freighter_crew.rsi/meta.json
new file mode 100644
index 00000000000..09e312abc71
--- /dev/null
+++ b/Resources/Textures/_DV/Clothing/Uniforms/Jumpsuit/freighter_crew.rsi/meta.json
@@ -0,0 +1,30 @@
+{
+ "version": 1,
+ "license": "CC-BY-SA-3.0",
+ "copyright": "Sprites by Halo3moth (GitHub)",
+ "size": {
+ "x": 32,
+ "y": 32
+ },
+ "states": [
+ {
+ "name": "icon"
+ },
+ {
+ "name": "equipped-INNERCLOTHING",
+ "directions": 4
+ },
+ {
+ "name": "equipped-INNERCLOTHING-monkey",
+ "directions": 4
+ },
+ {
+ "name": "inhand-left",
+ "directions": 4
+ },
+ {
+ "name": "inhand-right",
+ "directions": 4
+ }
+ ]
+}
From 72f6bff008c549cc39644a023a44fbc45976399b Mon Sep 17 00:00:00 2001
From: Delta-V bot <135767721+DeltaV-Bot@users.noreply.github.com>
Date: Mon, 20 Jul 2026 22:07:19 +0200
Subject: [PATCH 04/54] Automatic changelog update
---
Resources/Changelog/DeltaVChangelog.yml | 15 ++++++++-------
1 file changed, 8 insertions(+), 7 deletions(-)
diff --git a/Resources/Changelog/DeltaVChangelog.yml b/Resources/Changelog/DeltaVChangelog.yml
index 9d401901d2d..ccb9e7f58e6 100644
--- a/Resources/Changelog/DeltaVChangelog.yml
+++ b/Resources/Changelog/DeltaVChangelog.yml
@@ -1,11 +1,4 @@
Entries:
-- author: Velcroboy
- changes:
- - message: Prisoners can find dull bread knives in the ChefVend.
- type: Tweak
- id: 2075
- time: '2026-01-17T21:13:59.0000000+00:00'
- url: https://github.com/DeltaV-Station/Delta-v/pull/5234
- author: Halo3moth
changes:
- message: The T1 armored vest (slim) can now once again be picked in security loadouts.
@@ -4369,4 +4362,12 @@
id: 2575
time: '2026-07-20T17:38:51.0000000+00:00'
url: https://github.com/DeltaV-Station/Delta-v/pull/5016
+- author: Halo3rat, kotobdev
+ changes:
+ - message: The Freighter Crew's Jumpsuit is now available in the AutoDrobe, for
+ those who value their dental hygiene.
+ type: Add
+ id: 2576
+ time: '2026-07-20T20:06:59.0000000+00:00'
+ url: https://github.com/DeltaV-Station/Delta-v/pull/6331
Order: 1
From b67c0290610fd652016082d3198857b6ac76030f Mon Sep 17 00:00:00 2001
From: KOTOB <59124164+kotobdev@users.noreply.github.com>
Date: Mon, 20 Jul 2026 13:13:57 -0700
Subject: [PATCH 05/54] Port Item Offering from Euphoria (#5597)
* Item offering port (#96)
* Offer item system port
* More fixes
* Make the formatting a bit more readable
* Add a missing keybind
* Add missing alert click handler and make some of the code more readable
* Duplicate offer-item-system.ftl
Signed-off-by: Mnemotechnican <69920617+Mnemotechnician@users.noreply.github.com>
* Namespace fix and prediction fixes
* Port various carrying and pseudo-item fixes from floofstation
* Refactor the offer system to hopefully bring more clarity
* Final fixes
* Final final final fixes maybe
* Sike, just do it the proper way
---------
Signed-off-by: Mnemotechnican <69920617+Mnemotechnician@users.noreply.github.com>
* fixes
* empty commit (weird test fail?)
* Moved some stuff to shared. Reorganized a bit. I could be here all day...
---------
Signed-off-by: Mnemotechnican <69920617+Mnemotechnician@users.noreply.github.com>
Co-authored-by: Mnemotechnican <69920617+Mnemotechnician@users.noreply.github.com>
Co-authored-by: Vanessa
---
Content.Client/Input/ContentContexts.cs | 3 +
.../Options/UI/Tabs/KeyRebindTab.xaml.cs | 1 +
.../OfferItem/OfferItemIndicatorsOverlay.cs | 71 +++
.../_Floof/OfferItem/OfferItemSystem.cs | 39 ++
.../Item/PseudoItem/PseudoItemSystem.cs | 6 +-
.../_Floof/OfferItem/OfferItemSystem.cs | 5 +
Content.Shared/Input/ContentKeyFunctions.cs | 1 +
.../Movement/Pulling/Systems/PullingSystem.cs | 4 +-
.../Item/PseudoItem/SharedPseudoItemSystem.cs | 41 +-
Content.Shared/_DV/Carrying/CarryingSystem.cs | 29 +-
.../_Floof/OfferItem/AcceptOfferAlertEvent.cs | 5 +
.../_Floof/OfferItem/OfferItemComponent.cs | 52 +++
.../OfferableVirtualItemComponent.cs | 11 +
.../SharedOfferItemSystem.Interactions.cs | 93 ++++
.../_Floof/OfferItem/SharedOfferItemSystem.cs | 414 ++++++++++++++++++
.../_Floof/interaction/offer-item-system.ftl | 17 +
Resources/Prototypes/Alerts/alerts.yml | 1 +
.../Prototypes/Body/species_appearance.yml | 1 +
Resources/Prototypes/_Floof/alerts.yml | 8 +
.../Interface/Alerts/offer_item.rsi/meta.json | 14 +
.../Alerts/offer_item.rsi/offer_item.png | Bin 0 -> 782 bytes
.../Misc/give_item.rsi/give_item.png | Bin 0 -> 7276 bytes
.../Interface/Misc/give_item.rsi/meta.json | 14 +
Resources/keybinds.yml | 5 +
24 files changed, 810 insertions(+), 25 deletions(-)
create mode 100644 Content.Client/_Floof/OfferItem/OfferItemIndicatorsOverlay.cs
create mode 100644 Content.Client/_Floof/OfferItem/OfferItemSystem.cs
create mode 100644 Content.Server/_Floof/OfferItem/OfferItemSystem.cs
create mode 100644 Content.Shared/_Floof/OfferItem/AcceptOfferAlertEvent.cs
create mode 100644 Content.Shared/_Floof/OfferItem/OfferItemComponent.cs
create mode 100644 Content.Shared/_Floof/OfferItem/OfferableVirtualItemComponent.cs
create mode 100644 Content.Shared/_Floof/OfferItem/SharedOfferItemSystem.Interactions.cs
create mode 100644 Content.Shared/_Floof/OfferItem/SharedOfferItemSystem.cs
create mode 100644 Resources/Locale/en-US/_Floof/interaction/offer-item-system.ftl
create mode 100644 Resources/Prototypes/_Floof/alerts.yml
create mode 100644 Resources/Textures/_Floof/Interface/Alerts/offer_item.rsi/meta.json
create mode 100644 Resources/Textures/_Floof/Interface/Alerts/offer_item.rsi/offer_item.png
create mode 100644 Resources/Textures/_Floof/Interface/Misc/give_item.rsi/give_item.png
create mode 100644 Resources/Textures/_Floof/Interface/Misc/give_item.rsi/meta.json
diff --git a/Content.Client/Input/ContentContexts.cs b/Content.Client/Input/ContentContexts.cs
index 8c8dd1a4748..ac59adc1611 100644
--- a/Content.Client/Input/ContentContexts.cs
+++ b/Content.Client/Input/ContentContexts.cs
@@ -34,6 +34,9 @@ namespace Content.Client.Input
common.AddFunction(ContentKeyFunctions.RotateStoredItem);
common.AddFunction(ContentKeyFunctions.SaveItemLocation);
common.AddFunction(ContentKeyFunctions.Point);
+ // Floofstation section
+ common.AddFunction(ContentKeyFunctions.OfferItem);
+ // Floofstation section end
common.AddFunction(ContentKeyFunctions.ZoomOut);
common.AddFunction(ContentKeyFunctions.ZoomIn);
common.AddFunction(ContentKeyFunctions.ResetZoom);
diff --git a/Content.Client/Options/UI/Tabs/KeyRebindTab.xaml.cs b/Content.Client/Options/UI/Tabs/KeyRebindTab.xaml.cs
index 5e1bcd59857..79c36c969e5 100644
--- a/Content.Client/Options/UI/Tabs/KeyRebindTab.xaml.cs
+++ b/Content.Client/Options/UI/Tabs/KeyRebindTab.xaml.cs
@@ -208,6 +208,7 @@ namespace Content.Client.Options.UI.Tabs
AddButton(ContentKeyFunctions.MovePulledObject);
AddButton(ContentKeyFunctions.ReleasePulledObject);
AddButton(ContentKeyFunctions.Point);
+ AddButton(ContentKeyFunctions.OfferItem); // Floofstation
AddButton(ContentKeyFunctions.RotateObjectClockwise);
AddButton(ContentKeyFunctions.RotateObjectCounterclockwise);
AddButton(ContentKeyFunctions.FlipObject);
diff --git a/Content.Client/_Floof/OfferItem/OfferItemIndicatorsOverlay.cs b/Content.Client/_Floof/OfferItem/OfferItemIndicatorsOverlay.cs
new file mode 100644
index 00000000000..c306303b5b3
--- /dev/null
+++ b/Content.Client/_Floof/OfferItem/OfferItemIndicatorsOverlay.cs
@@ -0,0 +1,71 @@
+using System.Numerics;
+using Robust.Client.GameObjects;
+using Robust.Client.Graphics;
+using Robust.Client.Input;
+using Robust.Client.UserInterface;
+using Robust.Shared.Enums;
+using Robust.Shared.Utility;
+
+namespace Content.Client._Floof.OfferItem;
+
+public sealed class OfferItemIndicatorsOverlay : Overlay
+{
+ private readonly IInputManager _inputManager;
+ private readonly IEntityManager _entMan;
+ private readonly IEyeManager _eye;
+ private readonly OfferItemSystem _offer;
+
+ private readonly Texture _sight;
+
+ public override OverlaySpace Space => OverlaySpace.ScreenSpace;
+
+ private readonly Color _mainColor = Color.White.WithAlpha(0.3f);
+ private readonly Color _strokeColor = Color.Black.WithAlpha(0.5f);
+ private readonly float _scale = 0.6f; // 1 is a little big
+
+ public OfferItemIndicatorsOverlay(IInputManager input, IEntityManager entMan,
+ IEyeManager eye, OfferItemSystem offerSys)
+ {
+ _inputManager = input;
+ _entMan = entMan;
+ _eye = eye;
+ _offer = offerSys;
+
+ var spriteSys = _entMan.EntitySysManager.GetEntitySystem();
+ _sight = spriteSys.Frame0(new SpriteSpecifier.Rsi(new("/Textures/_Floof/Interface/Misc/give_item.rsi"), "give_item"));
+ }
+
+ protected override bool BeforeDraw(in OverlayDrawArgs args)
+ {
+ if (!_offer.IsInOfferMode())
+ return false;
+
+ return base.BeforeDraw(in args);
+ }
+
+ protected override void Draw(in OverlayDrawArgs args)
+ {
+ var mouseScreenPosition = _inputManager.MouseScreenPosition;
+ var mousePosMap = _eye.PixelToMap(mouseScreenPosition);
+ if (mousePosMap.MapId != args.MapId)
+ return;
+
+
+ var mousePos = mouseScreenPosition.Position;
+ var uiScale = (args.ViewportControl as Control)?.UIScale ?? 1f;
+ var limitedScale = uiScale > 1.25f ? 1.25f : uiScale;
+
+ DrawSight(_sight, args.ScreenHandle, mousePos, limitedScale * _scale);
+ }
+
+ private void DrawSight(Texture sight, DrawingHandleScreen screen, Vector2 centerPos, float scale)
+ {
+ var sightSize = sight.Size * scale;
+ var expandedSize = sightSize + new Vector2(7f, 7f);
+
+ screen.DrawTextureRect(sight,
+ UIBox2.FromDimensions(centerPos - sightSize * 0.5f, sightSize), _strokeColor);
+ screen.DrawTextureRect(sight,
+ UIBox2.FromDimensions(centerPos - expandedSize * 0.5f, expandedSize), _mainColor);
+ }
+}
diff --git a/Content.Client/_Floof/OfferItem/OfferItemSystem.cs b/Content.Client/_Floof/OfferItem/OfferItemSystem.cs
new file mode 100644
index 00000000000..0487d361fc0
--- /dev/null
+++ b/Content.Client/_Floof/OfferItem/OfferItemSystem.cs
@@ -0,0 +1,39 @@
+using Content.Shared._Floof.OfferItem;
+using Robust.Client.Graphics;
+using Robust.Client.Input;
+using Robust.Client.Player;
+
+namespace Content.Client._Floof.OfferItem;
+
+public sealed class OfferItemSystem : SharedOfferItemSystem
+{
+ [Dependency] private readonly IOverlayManager _overlayManager = default!;
+ [Dependency] private readonly IPlayerManager _playerManager = default!;
+ [Dependency] private readonly IInputManager _inputManager = default!;
+ [Dependency] private readonly IEyeManager _eye = default!;
+
+ public override void Initialize()
+ {
+ base.Initialize();
+ _overlayManager.AddOverlay(new OfferItemIndicatorsOverlay(
+ _inputManager,
+ EntityManager,
+ _eye,
+ this));
+ }
+ public override void Shutdown()
+ {
+ _overlayManager.RemoveOverlay();
+ base.Shutdown();
+ }
+
+ public bool IsInOfferMode()
+ {
+ var entity = _playerManager.LocalEntity;
+
+ if (entity == null)
+ return false;
+
+ return IsInOfferMode(entity.Value);
+ }
+}
diff --git a/Content.Server/Nyanotrasen/Item/PseudoItem/PseudoItemSystem.cs b/Content.Server/Nyanotrasen/Item/PseudoItem/PseudoItemSystem.cs
index b4a3649c5cb..953370aa9b8 100644
--- a/Content.Server/Nyanotrasen/Item/PseudoItem/PseudoItemSystem.cs
+++ b/Content.Server/Nyanotrasen/Item/PseudoItem/PseudoItemSystem.cs
@@ -55,9 +55,13 @@ public sealed class PseudoItemSystem : SharedPseudoItemSystem
protected override void OnGettingPickedUpAttempt(EntityUid uid, PseudoItemComponent component, GettingPickedUpAttemptEvent args)
{
+ // Floof - changed this a bit to actually start a do-after
// Try to pick the entity up instead first
- if (args.User != args.Item && _carrying.TryCarry(args.User, uid))
+ if (args.User != args.Item
+ && TryComp(uid, out var carriable)
+ && _carrying.CanCarry(args.User, (uid, carriable)))
{
+ _carrying.StartCarryDoAfter(args.User, (uid, carriable));
args.Cancel();
return;
}
diff --git a/Content.Server/_Floof/OfferItem/OfferItemSystem.cs b/Content.Server/_Floof/OfferItem/OfferItemSystem.cs
new file mode 100644
index 00000000000..b72ce2d5849
--- /dev/null
+++ b/Content.Server/_Floof/OfferItem/OfferItemSystem.cs
@@ -0,0 +1,5 @@
+using Content.Shared._Floof.OfferItem;
+
+namespace Content.Server._Floof.OfferItem;
+
+public sealed partial class OfferItemSystem : SharedOfferItemSystem;
diff --git a/Content.Shared/Input/ContentKeyFunctions.cs b/Content.Shared/Input/ContentKeyFunctions.cs
index a7e4164b920..6b633d39b13 100644
--- a/Content.Shared/Input/ContentKeyFunctions.cs
+++ b/Content.Shared/Input/ContentKeyFunctions.cs
@@ -68,6 +68,7 @@ namespace Content.Shared.Input
public static readonly BoundKeyFunction TakeScreenshotNoUI = "TakeScreenshotNoUI";
public static readonly BoundKeyFunction ToggleFullscreen = "ToggleFullscreen";
public static readonly BoundKeyFunction Point = "Point";
+ public static readonly BoundKeyFunction OfferItem = "OfferItem"; // Floofstation
public static readonly BoundKeyFunction ZoomOut = "ZoomOut";
public static readonly BoundKeyFunction ZoomIn = "ZoomIn";
public static readonly BoundKeyFunction ResetZoom = "ResetZoom";
diff --git a/Content.Shared/Movement/Pulling/Systems/PullingSystem.cs b/Content.Shared/Movement/Pulling/Systems/PullingSystem.cs
index 490050553d3..62aaae1e691 100644
--- a/Content.Shared/Movement/Pulling/Systems/PullingSystem.cs
+++ b/Content.Shared/Movement/Pulling/Systems/PullingSystem.cs
@@ -1,4 +1,5 @@
using Content.Shared._ST.Interaction; // Stellar - interaction particles
+using Content.Shared._Floof.OfferItem; // Floof
using Content.Shared.ActionBlocker;
using Content.Shared.Administration.Logs;
using Content.Shared.Alert;
@@ -117,10 +118,11 @@ public sealed class PullingSystem : EntitySystem
if (TryComp(args.PullerUid, out PullerComponent? pullerComp) && !pullerComp.NeedsHands)
return;
- if (!_virtual.TrySpawnVirtualItemInHand(args.PulledUid, uid))
+ if (!_virtual.TrySpawnVirtualItemInHand(args.PulledUid, uid, out var virt)) // Floofstation - store item
{
DebugTools.Assert("Unable to find available hand when starting pulling??");
}
+ EnsureComp(virt.Value); // Floofstation - add a special component to allow offering it
}
private void HandlePullStopped(EntityUid uid, HandsComponent component, PullStoppedMessage args)
diff --git a/Content.Shared/Nyanotrasen/Item/PseudoItem/SharedPseudoItemSystem.cs b/Content.Shared/Nyanotrasen/Item/PseudoItem/SharedPseudoItemSystem.cs
index bcbdd4b8629..c7a4e0f74b6 100644
--- a/Content.Shared/Nyanotrasen/Item/PseudoItem/SharedPseudoItemSystem.cs
+++ b/Content.Shared/Nyanotrasen/Item/PseudoItem/SharedPseudoItemSystem.cs
@@ -1,8 +1,7 @@
using Content.Shared.Actions;
-using Content.Shared.Bed.Sleep;
using Content.Shared.DoAfter;
using Content.Shared.Hands;
-using Content.Shared.IdentityManagement;
+using Content.Shared.Hands.EntitySystems;
using Content.Shared.Interaction.Events;
using Content.Shared.Item;
using Content.Shared.Item.PseudoItem;
@@ -24,7 +23,8 @@ public abstract partial class SharedPseudoItemSystem : EntitySystem
[Dependency] private readonly TagSystem _tag = default!;
[Dependency] private readonly SharedPopupSystem _popupSystem = default!;
[Dependency] private readonly SharedActionsSystem _actions = default!;
- [Dependency] private readonly SharedTransformSystem _transform = default!;
+ [Dependency] private readonly SharedContainerSystem _container = default!; // Floofstation
+ [Dependency] private readonly SharedHandsSystem _hands = default!; // Floofstation
private readonly ProtoId PreventTag = "PreventLabel";
private readonly EntProtoId SleepActionId = "ActionSleep"; // The action used for sleeping inside bags. Currently uses the default sleep action (same as beds)
@@ -116,17 +116,35 @@ public abstract partial class SharedPseudoItemSystem : EntitySystem
protected virtual void OnGettingPickedUpAttempt(EntityUid uid, PseudoItemComponent component,
GettingPickedUpAttemptEvent args)
{
- if (args.User == args.Item)
- return;
+ args.Cancel(); // Floof - this is a terrible idea. This triggers every time ANY system checks if a pseudo-item can be picked up.
+ // WHY DID YOU DO THAT, NYANOTRASEN???
- _transform.AttachToGridOrMap(uid);
- args.Cancel();
+ // if (args.User == args.Item)
+ // return;
+ //
+ // _transform.AttachToGridOrMap(uid);
+ // args.Cancel();
}
private void OnDropAttempt(EntityUid uid, PseudoItemComponent component, DropAttemptEvent args)
{
- if (component.Active)
- args.Cancel();
+ if (!component.Active)
+ return;
+
+ // Floof - we try to get the containing container and try to drop it into it
+ // If possible, we do it, since a bagged cat probably can put things back into the bag just like they can pick them up.
+ string? failReason = null;
+ if (_hands.GetActiveItem(uid) is { Valid: true, } droppedItem
+ && _container.TryGetContainingContainer(Transform(uid).ParentUid, uid, out var pseudoItemContainer)
+ && TryComp(pseudoItemContainer.Owner, out var targetStorage)
+ && _storage.CanInsert(pseudoItemContainer.Owner, droppedItem, out failReason, targetStorage, ignoreStacks: true)
+ )
+ _storage.Insert(pseudoItemContainer.Owner, droppedItem, out _, uid, targetStorage, stackAutomatically: false);
+
+ if (failReason != null)
+ _popupSystem.PopupEntity(Loc.GetString(failReason), uid, uid);
+
+ args.Cancel();
}
private void OnInsertAttempt(EntityUid uid, PseudoItemComponent component,
@@ -141,8 +159,9 @@ public abstract partial class SharedPseudoItemSystem : EntitySystem
// Prevents moving within the bag :)
private void OnInteractAttempt(EntityUid uid, PseudoItemComponent component, InteractionAttemptEvent args)
{
- if (args.Uid == args.Target && component.Active)
- args.Cancelled = true;
+ // Floof - why the fuck.
+ // if (args.Uid == args.Target && component.Active)
+ // args.Cancelled = true;
}
private void OnDoAfter(EntityUid uid, PseudoItemComponent component, DoAfterEvent args)
diff --git a/Content.Shared/_DV/Carrying/CarryingSystem.cs b/Content.Shared/_DV/Carrying/CarryingSystem.cs
index aa836f81cd0..a6a62d7ff66 100644
--- a/Content.Shared/_DV/Carrying/CarryingSystem.cs
+++ b/Content.Shared/_DV/Carrying/CarryingSystem.cs
@@ -28,6 +28,7 @@ using Robust.Shared.Network;
using Robust.Shared.Physics.Components;
using System.Numerics;
using Content.Shared._DV.Polymorph;
+using Content.Shared._Floof.OfferItem;
using Content.Shared.Hands.EntitySystems;
namespace Content.Shared._DV.Carrying;
@@ -181,14 +182,15 @@ public sealed class CarryingSystem : EntitySystem
///
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;
+ // Floofstation - no - this prevents the person from escaping and more.
+ // 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)
@@ -203,8 +205,9 @@ public sealed class CarryingSystem : EntitySystem
private void OnInteractedWith(Entity ent, ref GettingInteractedWithAttemptEvent args)
{
- if (args.Uid != ent.Comp.Carrier)
- args.Cancelled = true;
+ // Floofstation - why?
+ // if (args.Uid != ent.Comp.Carrier)
+ // args.Cancelled = true;
}
private void OnPullAttempt(Entity ent, ref PullAttemptEvent args)
@@ -242,7 +245,8 @@ public sealed class CarryingSystem : EntitySystem
args.Handled = true;
}
- private void StartCarryDoAfter(EntityUid carrier, Entity carried)
+ // Floofstation - made public
+ public void StartCarryDoAfter(EntityUid carrier, Entity carried)
{
TimeSpan length = GetPickupDuration(carrier, carried);
@@ -299,7 +303,8 @@ public sealed class CarryingSystem : EntitySystem
for (var x = 0; x < Comp(carried).FreeHandsRequired; x++)
{
- _virtualItem.TrySpawnVirtualItemInHand(carried, carrier);
+ if (_virtualItem.TrySpawnVirtualItemInHand(carried, carrier, out var virtualItem))
+ EnsureComp(virtualItem.Value);
}
}
diff --git a/Content.Shared/_Floof/OfferItem/AcceptOfferAlertEvent.cs b/Content.Shared/_Floof/OfferItem/AcceptOfferAlertEvent.cs
new file mode 100644
index 00000000000..1f5e2e851ad
--- /dev/null
+++ b/Content.Shared/_Floof/OfferItem/AcceptOfferAlertEvent.cs
@@ -0,0 +1,5 @@
+using Content.Shared.Alert;
+
+namespace Content.Shared._Floof.OfferItem;
+
+public sealed partial class AcceptOfferAlertEvent : BaseAlertEvent;
diff --git a/Content.Shared/_Floof/OfferItem/OfferItemComponent.cs b/Content.Shared/_Floof/OfferItem/OfferItemComponent.cs
new file mode 100644
index 00000000000..926f397ce14
--- /dev/null
+++ b/Content.Shared/_Floof/OfferItem/OfferItemComponent.cs
@@ -0,0 +1,52 @@
+using Content.Shared.Alert;
+using Content.Shared.Inventory.VirtualItem;
+using Robust.Shared.GameStates;
+using Robust.Shared.Prototypes;
+
+namespace Content.Shared._Floof.OfferItem;
+
+[RegisterComponent, NetworkedComponent, AutoGenerateComponentState(true)]
+[Access(typeof(SharedOfferItemSystem))]
+public sealed partial class OfferItemComponent : Component
+{
+ ///
+ /// Apparently this indicates whether the entity is currently choosing an entity to offer (right after pressing F).
+ ///
+ [ViewVariables(VVAccess.ReadWrite), DataField, AutoNetworkedField]
+ public bool IsInOfferMode;
+
+ ///
+ /// If this is true, then someone is currently offering an item to this entity, and
+ /// stores the ID of that entity.
+ ///
+ [DataField, AutoNetworkedField]
+ public bool IsInReceiveMode;
+
+ [DataField, AutoNetworkedField]
+ public string? Hand;
+
+ [DataField, AutoNetworkedField]
+ public EntityUid? Item;
+
+ ///
+ /// Floofstation note. So, this is EE shitcode, so prepare for an emotional rollercoaster.
+ /// This field can mean TWO things. It's either the target entity this entity is offering an item to,
+ /// or an entity that is offering an item to this entity.
+ /// Whether it's one or the other is distinguished by .
+ ///
+ /// In rare cases it can be both. According to my research, if entity A offers an item to entity B, and entity B offers to entity A,
+ /// then both entities will end up in receive mode, and they will have each other as targets. There's a check preventing offer loops
+ /// of length more than 2.
+ ///
+ [DataField, AutoNetworkedField]
+ public EntityUid? ReceivingFrom;
+
+ [DataField]
+ public float MaxOfferDistance = 2f;
+
+ [DataField]
+ public ProtoId OfferAlert = "Offer";
+
+ public EntityUid GetRealEntity(EntityManager entityManager) =>
+ entityManager.GetComponentOrNull(Item)?.BlockingEntity ?? Item ?? EntityUid.Invalid;
+}
diff --git a/Content.Shared/_Floof/OfferItem/OfferableVirtualItemComponent.cs b/Content.Shared/_Floof/OfferItem/OfferableVirtualItemComponent.cs
new file mode 100644
index 00000000000..0c4b994c400
--- /dev/null
+++ b/Content.Shared/_Floof/OfferItem/OfferableVirtualItemComponent.cs
@@ -0,0 +1,11 @@
+using Robust.Shared.GameStates;
+
+namespace Content.Shared._Floof.OfferItem;
+
+///
+/// A marker component that, when applied to a virtual item, allows it to be offered using item offering.
+/// Implementors have to listen on ItemTransferredEvent.
+///
+[RegisterComponent]
+[NetworkedComponent]
+public sealed partial class OfferableVirtualItemComponent : Component;
diff --git a/Content.Shared/_Floof/OfferItem/SharedOfferItemSystem.Interactions.cs b/Content.Shared/_Floof/OfferItem/SharedOfferItemSystem.Interactions.cs
new file mode 100644
index 00000000000..cac0280cd1f
--- /dev/null
+++ b/Content.Shared/_Floof/OfferItem/SharedOfferItemSystem.Interactions.cs
@@ -0,0 +1,93 @@
+using Content.Shared.ActionBlocker;
+using Content.Shared.Alert;
+using Content.Shared.Hands.Components;
+using Content.Shared.Hands.EntitySystems;
+using Content.Shared.Input;
+using Content.Shared.Popups;
+using Robust.Shared.Input.Binding;
+using Robust.Shared.Player;
+
+namespace Content.Shared._Floof.OfferItem;
+
+public abstract partial class SharedOfferItemSystem
+{
+ [Dependency] private readonly ActionBlockerSystem _actionBlocker = default!;
+ [Dependency] private readonly SharedPopupSystem _popup = default!;
+
+
+ private void InitializeInteractions()
+ {
+ base.Initialize();
+
+ CommandBinds.Builder
+ .Bind(ContentKeyFunctions.OfferItem, InputCmdHandler.FromDelegate(SetInOfferMode, handle: false, outsidePrediction: false))
+ .Register();
+ }
+
+ public override void Shutdown()
+ {
+ base.Shutdown();
+
+ CommandBinds.Unregister();
+ }
+
+ ///
+ /// This sets IsInOfferMode to true, allowing the player to select whom to offer an item to with interaction.
+ ///
+ private void SetInOfferMode(ICommonSession? offerer)
+ {
+ if (offerer is not { } playerSession)
+ return;
+
+ if (playerSession.AttachedEntity is not { Valid: true } uid)
+ return;
+
+ if (!Exists(uid))
+ return;
+
+ if (!_actionBlocker.CanInteract(uid, null))
+ return;
+
+ if (!TryComp(uid, out var offerItem))
+ return;
+
+ if (!TryComp(uid, out var hands))
+ return;
+
+ if (_hands.GetActiveHand((uid, hands)) is not { } activeHandName)
+ return;
+
+ if (!_hands.TryGetHeldItem((uid, hands), activeHandName, out var heldItem))
+ return;
+
+ offerItem.Item = heldItem;
+ if (!offerItem.IsInOfferMode)
+ {
+ if (offerItem.Item == null)
+ {
+ _popup.PopupEntity(Loc.GetString("offer-item-empty-hand"), uid, uid);
+ return;
+ }
+
+ if (offerItem.Hand == null || offerItem.ReceivingFrom == null)
+ {
+ offerItem.IsInOfferMode = true;
+ offerItem.Hand = activeHandName;
+
+ Dirty(uid, offerItem);
+ return;
+ }
+ }
+
+ // If we're already offering an item to someone, cancel that offer
+ if (offerItem.ReceivingFrom != null)
+ {
+ UnReceive(offerItem.ReceivingFrom.Value, offererComp: offerItem);
+ offerItem.IsInOfferMode = false;
+ Dirty(uid, offerItem);
+ return;
+ }
+
+ UnOffer(uid, offerItem);
+ }
+}
diff --git a/Content.Shared/_Floof/OfferItem/SharedOfferItemSystem.cs b/Content.Shared/_Floof/OfferItem/SharedOfferItemSystem.cs
new file mode 100644
index 00000000000..9392a226fa2
--- /dev/null
+++ b/Content.Shared/_Floof/OfferItem/SharedOfferItemSystem.cs
@@ -0,0 +1,414 @@
+using Content.Shared._DV.Carrying;
+using Content.Shared.Alert;
+using Content.Shared.Hands.Components;
+using Content.Shared.Hands.EntitySystems;
+using Content.Shared.IdentityManagement;
+using Content.Shared.Interaction;
+using Content.Shared.Movement.Pulling.Components;
+using Content.Shared.Movement.Pulling.Systems;
+using Content.Shared.Nutrition.EntitySystems;
+using Robust.Shared.Network;
+using Robust.Shared.Player;
+using Robust.Shared.Timing;
+
+// Dear contributor.
+// This system is fucking unmaintainable.
+// If you ever happen to touch this again, please do your best to document your changes and try to resolve mysteries surrounding this code.
+// I did what I could to document the parts I managed to understand, but there is still more truth to be unveiled.
+//
+// HOURS_WASTED_HERE_FLOOFSTATION = 10
+// HOURS_WASTED_HERE_DELTAV = 1
+
+namespace Content.Shared._Floof.OfferItem;
+
+public abstract partial class SharedOfferItemSystem : EntitySystem
+{
+ [Dependency] private readonly IGameTiming _timing = default!;
+ [Dependency] private readonly INetManager _net = default!;
+ [Dependency] private readonly SharedTransformSystem _transform = default!;
+ [Dependency] private readonly SharedHandsSystem _hands = default!;
+ [Dependency] private readonly AlertsSystem _alertsSystem = default!;
+ [Dependency] private readonly CarryingSystem _carrying = default!;
+ [Dependency] private readonly PullingSystem _pulling = default!;
+
+ public override void Initialize()
+ {
+ base.Initialize();
+ SubscribeLocalEvent(OnAcceptOffer);
+ SubscribeLocalEvent(OnInteractWithReceiver, before: [typeof(IngestionSystem)]);
+ SubscribeLocalEvent(OnRangedInteractWithReceiver);
+ SubscribeLocalEvent(OnMove);
+
+ SubscribeLocalEvent(OnCarryTransfer);
+ SubscribeLocalEvent(OnPulledTransfer);
+
+ InitializeInteractions();
+ }
+
+ public override void Update(float frameTime)
+ {
+ base.Update(frameTime);
+
+ var query = EntityQueryEnumerator();
+ while (query.MoveNext(out var uid, out var offerItem, out var hands))
+ {
+ // If the mob no longer holds an item in the original offering hand, clear offering mode
+ if (offerItem.Hand != null && !_hands.TryGetHeldItem((uid, hands), offerItem.Hand, out _))
+ {
+ if (offerItem.ReceivingFrom != null)
+ {
+ UnReceive(offerItem.ReceivingFrom.Value, offererComp: offerItem);
+ offerItem.IsInOfferMode = false;
+ Dirty(uid, offerItem);
+ }
+ else
+ UnOffer(uid, offerItem);
+ }
+
+ if (!offerItem.IsInReceiveMode)
+ {
+ _alertsSystem.ClearAlert(uid, offerItem.OfferAlert);
+ continue;
+ }
+
+ _alertsSystem.ShowAlert(uid, offerItem.OfferAlert);
+ }
+ }
+
+ #region Events
+ private void OnAcceptOffer(Entity ent, ref AcceptOfferAlertEvent args)
+ {
+ Receive((ent, ent.Comp));
+ }
+
+ private void OnInteractWithReceiver(Entity receiver, ref InteractUsingEvent args)
+ {
+ if (!_timing.IsFirstTimePredicted || _timing.ApplyingState || args.Handled)
+ return;
+
+ if (!TryComp(args.User, out var offererComponent))
+ return;
+
+ args.Handled = CreateOffer(receiver, (args.User, offererComponent));
+ }
+
+ private void OnRangedInteractWithReceiver(Entity virtItem, ref BeforeRangedInteractEvent args)
+ {
+ // If the entity being offered is a virtual item, InteractUsing will not be raised
+ // because virtual items exclude themselves from being marked as used
+ // If this is the case, InteractHand will be raised instead, which we can use anyway because OfferItem.Item stores the offered item
+ //
+ // We also can't check Handled here because VirtualItemSystem handles it, ffs
+ // This won't lead you to accidentally offering someone your gun
+ //
+ // This is shitcode, this time my shitcode. My changes to the offering system allow you to transfer carrying and pulling,
+ // but in order to handle these, we need to be able to intercept interactions with virtual items.
+ //
+ // Ideally this code should be rewritten to:
+ // a) Have each different virtual item have a distinct component (e.g. CarryingVirtualItem) which would allow to distinguish them from the rest
+ // b) Not rely on the InteractionSystem.
+ // However, I'm not in the mood to do either. And I'm too deep into the rabbit hole of getting this shit to work.
+ if (!_timing.IsFirstTimePredicted || _timing.ApplyingState)
+ return;
+
+ var receiver = args.Target;
+ if (!TryComp(receiver, out var receiverComponent))
+ return;
+
+ var offerer = args.User;
+ if (!TryComp(offerer, out var offererComponent) || offererComponent.Item == null)
+ return;
+
+ // Since this is ranged, we must also check distance, because the interaction system wont check it for us in this case
+ if (!Transform(offerer).Coordinates.TryDistance(EntityManager, _transform, Transform(receiver.Value).Coordinates, out var dst)
+ || dst > offererComponent.MaxOfferDistance)
+ return;
+
+ args.Handled = CreateOffer((receiver.Value, receiverComponent), (offerer, offererComponent));
+ }
+
+ private void OnMove(EntityUid uid, OfferItemComponent component, MoveEvent args)
+ {
+ if (_net.IsClient) // Client often mispredicts movement, we cant trust it here
+ return;
+
+ if (component.ReceivingFrom == null)
+ return;
+
+ if (_transform.InRange(args.NewPosition, Transform(component.ReceivingFrom.Value).Coordinates, component.MaxOfferDistance))
+ return;
+
+ UnOffer(uid, component);
+ }
+
+ private void OnCarryTransfer(Entity ent, ref ItemTransferredEvent args)
+ {
+ if (args.Handled
+ || args.PassedItem == args.RealItem // Means the entity is transferred NOT via carrying
+ || args.RealItem is not { Valid: true } carried
+ || ent.Comp.Carrier is not { Valid: true } oldCarrier)
+ return;
+
+ _carrying.DropCarried(oldCarrier, ent);
+ args.Handled = _carrying.TryCarry(args.Target, carried);
+ }
+
+ private void OnPulledTransfer(Entity ent, ref ItemTransferredEvent args)
+ {
+ if (args.Handled
+ || args.PassedItem == args.RealItem // Means the entity is transferred NOT via pulling
+ || args.RealItem is not { Valid: true } pulled)
+ return;
+
+ _pulling.TryStopPull(pulled, ent);
+ args.Handled = _pulling.TryStartPull(args.Target, ent, null, ent.Comp);
+ }
+
+ #endregion
+
+ #region Offering / Recieving
+ ///
+ /// Attempts to create an offer. Expects offerer.Item to already be set to the offered item, offererComponent.InReceiveMode == true.
+ /// Will fail if offerer == receiver or if receiver already has a set TargetOrOfferer, and that person is not the current offerer
+ ///
+ private bool CreateOffer(Entity receiver, Entity offerer)
+ {
+ var offererComponent = offerer.Comp;
+ var receiverComponent = receiver.Comp;
+ if (offerer == receiver || receiverComponent.IsInReceiveMode || !offererComponent.IsInOfferMode)
+ return false;
+
+ if (offererComponent.IsInReceiveMode && offererComponent.ReceivingFrom != receiver)
+ return false;
+
+ receiverComponent.IsInReceiveMode = true;
+ receiverComponent.ReceivingFrom = offerer;
+
+ Dirty(receiver, receiverComponent);
+
+ offererComponent.ReceivingFrom = receiver; // TODO this is ee shitcode, may not be necessary?
+ offererComponent.IsInOfferMode = false;
+
+ Dirty(offerer, offererComponent);
+
+ if (offererComponent.Item == null)
+ return false;
+
+ // Sender popup (client-side only)
+ _popup.PopupClient(
+ Loc.GetString("offer-item-try-give",
+ ("item", Identity.Entity(offererComponent.GetRealEntity(EntityManager), EntityManager)),
+ ("target", Identity.Entity(receiver, EntityManager))),
+ offerer,
+ offerer);
+ // Receiver popup (server side only, not predicted because recipient != local player)
+ _popup.PopupEntity(
+ Loc.GetString("offer-item-try-give-target",
+ ("user", Identity.Entity(receiverComponent.ReceivingFrom.Value, EntityManager)),
+ ("item", Identity.Entity(offererComponent.GetRealEntity(EntityManager), EntityManager))),
+ offerer,
+ receiver,
+ Popups.PopupType.Medium);
+
+ return true;
+ }
+
+
+
+ ///
+ /// Resets the of the user and the target
+ ///
+ protected void UnOffer(EntityUid thisEntity, OfferItemComponent offererComp)
+ {
+ if (!TryComp(thisEntity, out var hands) || _hands.GetActiveHand((thisEntity, hands)) is null)
+ return;
+
+ if (offererComp.ReceivingFrom is { } otherEntity && TryComp(otherEntity, out var otherOfferer))
+ {
+ // So this tries to figure out which of these entities do what...
+ // if A.OfferItemComponent.Item != null, then A is currently offering an item to A.OfferItemComponent.TargetOrOfferer
+ // If it is null, then it is ONLY being offered an item TO.
+ if (offererComp.Item != null && _net.IsServer)
+ {
+ _popup.PopupEntity(
+ Loc.GetString("offer-item-no-give",
+ ("item", Identity.Entity(offererComp.GetRealEntity(EntityManager), EntityManager)), // Floof - resolve virtual items
+ ("target", Identity.Entity(otherEntity, EntityManager))),
+ thisEntity,
+ thisEntity);
+ _popup.PopupEntity(
+ Loc.GetString("offer-item-no-give-target",
+ ("user", Identity.Entity(thisEntity, EntityManager)),
+ ("item", Identity.Entity(offererComp.GetRealEntity(EntityManager), EntityManager))),
+ thisEntity,
+ otherEntity);
+ }
+
+ else if (otherOfferer.Item != null && _net.IsServer)
+ {
+ _popup.PopupEntity(
+ Loc.GetString("offer-item-no-give",
+ ("item", Identity.Entity(otherOfferer.GetRealEntity(EntityManager), EntityManager)), // Floof - resolve virtual items
+ ("target", Identity.Entity(thisEntity, EntityManager))),
+ otherEntity,
+ otherEntity);
+ _popup.PopupEntity(
+ Loc.GetString("offer-item-no-give-target",
+ ("user", Identity.Entity(otherEntity, EntityManager)),
+ ("item", Identity.Entity(otherOfferer.GetRealEntity(EntityManager), EntityManager))),
+ otherEntity,
+ thisEntity);
+ }
+
+ otherOfferer.IsInOfferMode = false;
+ otherOfferer.IsInReceiveMode = false;
+ otherOfferer.Hand = null;
+ otherOfferer.ReceivingFrom = null;
+ otherOfferer.Item = null;
+
+ Dirty(otherEntity, otherOfferer);
+ }
+
+ offererComp.IsInOfferMode = false;
+ offererComp.IsInReceiveMode = false;
+ offererComp.Hand = null;
+ offererComp.ReceivingFrom = null;
+ offererComp.Item = null;
+
+ Dirty(thisEntity, offererComp);
+ }
+
+
+ ///
+ /// Cancels the transfer of the item
+ ///
+ protected void UnReceive(EntityUid receiver, OfferItemComponent? receiverComp = null, OfferItemComponent? offererComp = null)
+ {
+ if (!Resolve(receiver, ref receiverComp)
+ || receiverComp.ReceivingFrom is not {} offerer
+ || !Resolve(offerer, ref offererComp))
+ return;
+
+ // Idk why this check is here
+ if (!TryComp(receiver, out var hands) || _hands.GetActiveHand((receiver, hands)) == null || receiverComp.ReceivingFrom == null)
+ return;
+
+ // If offererComp.Item != null, then they are actively offering to TargetOrOfferer
+ // Normally this method is called right after a transfer is done, but this part can be called from SetInOfferMode when the player presses F again to cancel an ongoing offer
+ if (offererComp.Item != null)
+ {
+ _popup.PopupClient(
+ Loc.GetString("offer-item-no-give",
+ ("item", Identity.Entity(offererComp.GetRealEntity(EntityManager), EntityManager)), // Floof - resolve virtual items
+ ("target", Identity.Entity(receiver, EntityManager))),
+ offerer,
+ offerer);
+ _popup.PopupEntity(
+ Loc.GetString("offer-item-no-give-target",
+ ("user", Identity.Entity(receiverComp.ReceivingFrom.Value, EntityManager)), // Floof - resolve virtual items
+ ("item", Identity.Entity(offererComp.GetRealEntity(EntityManager), EntityManager))),
+ offerer,
+ receiver);
+ }
+
+ if (!offererComp.IsInReceiveMode)
+ {
+ offererComp.ReceivingFrom = null;
+ receiverComp.ReceivingFrom = null;
+ }
+
+ offererComp.Item = null;
+ offererComp.Hand = null;
+ receiverComp.IsInReceiveMode = false;
+
+ Dirty(receiver, receiverComp);
+ }
+
+ ///
+ /// Accepting the offer and receive item
+ ///
+ public void Receive(Entity receiver)
+ {
+ if (!_timing.IsFirstTimePredicted)
+ return;
+
+ if (!Resolve(receiver, ref receiver.Comp))
+ return;
+
+ if (!TryComp(receiver.Comp.ReceivingFrom, out var offererComponent) ||
+ offererComponent.Hand == null ||
+ receiver.Comp.ReceivingFrom is not {} sender ||
+ !TryComp(receiver, out var hands))
+ return;
+
+ if (offererComponent.Item != null)
+ {
+ // Floof - check if there's something else handling it first
+ var realItem = offererComponent.GetRealEntity(EntityManager);
+ if (!TryHandleExtendedTransfer(sender, receiver, offererComponent.Item.Value, realItem)
+ && !_hands.TryPickup(receiver, offererComponent.Item.Value, handsComp: hands))
+ {
+ _popup.PopupEntity(Loc.GetString("offer-item-full-hand"), receiver, receiver);
+ return;
+ }
+
+ _popup.PopupEntity(
+ Loc.GetString("offer-item-give",
+ ("item", Identity.Entity(realItem, EntityManager)), // FLoof - resolve virtual items
+ ("target", Identity.Entity(receiver, EntityManager))),
+ sender,
+ sender);
+ _popup.PopupEntity(
+ Loc.GetString("offer-item-give-other",
+ ("user", Identity.Entity(receiver.Comp.ReceivingFrom.Value, EntityManager)),
+ ("item", Identity.Entity(realItem, EntityManager)), // FLoof - resolve virtual items
+ ("target", Identity.Entity(receiver, EntityManager))),
+ sender,
+ Filter.PvsExcept(sender, entityManager: EntityManager),
+ true);
+ }
+
+ offererComponent.Item = null;
+ UnReceive(receiver, receiver.Comp, offererComponent);
+ }
+ #endregion
+ ///
+ /// Returns true if = true
+ ///
+ protected bool IsInOfferMode(Entity ent)
+ {
+ return Resolve(ent, ref ent.Comp, false) && ent.Comp.IsInOfferMode;
+ }
+
+ private bool TryHandleExtendedTransfer(EntityUid user, EntityUid target, EntityUid offeredItem, EntityUid realItem)
+ {
+ var ev = new ItemTransferredEvent
+ {
+ User = user,
+ Target = target,
+ PassedItem = offeredItem,
+ RealItem = realItem,
+ };
+ RaiseLocalEvent(realItem, ref ev);
+ return ev.Handled;
+ }
+}
+
+///
+/// Raised on the entity that was transferred via item offering.
+///
+[ByRefEvent]
+public sealed class ItemTransferredEvent : HandledEntityEventArgs
+{
+ public EntityUid User;
+ public EntityUid Target;
+
+ ///
+ /// The actual item being passed around. Can be a virtual item.
+ ///
+ public EntityUid PassedItem;
+ ///
+ /// If is a virtual item, this field contains the real item that was transferred.
+ ///
+ public EntityUid? RealItem;
+}
\ No newline at end of file
diff --git a/Resources/Locale/en-US/_Floof/interaction/offer-item-system.ftl b/Resources/Locale/en-US/_Floof/interaction/offer-item-system.ftl
new file mode 100644
index 00000000000..5c8e2057a22
--- /dev/null
+++ b/Resources/Locale/en-US/_Floof/interaction/offer-item-system.ftl
@@ -0,0 +1,17 @@
+offer-item-empty-hand = You don't have anything in your hand to give!
+
+offer-item-full-hand = Your hand isn't free to receive the item.
+
+offer-item-try-give = You offer {THE($item)} to {$target}.
+offer-item-try-give-target = {CAPITALIZE(THE($user))} offers you {THE($item)}.
+
+offer-item-give = You handed {THE($item)} to {$target}.
+offer-item-give-other = {CAPITALIZE(THE($user))} handed {THE($item)} to {$target}.
+offer-item-give-target = {CAPITALIZE(THE($user))} handed you {THE($item)}.
+
+offer-item-no-give = You stop offering {THE($item)} to {$target}.
+offer-item-no-give-target = {CAPITALIZE(THE($user))} is no longer offering {THE($item)} to you.
+
+
+alerts-offer-name = Accept Offer
+alerts-offer-desc = Click this alert to accept the item offered to you.
diff --git a/Resources/Prototypes/Alerts/alerts.yml b/Resources/Prototypes/Alerts/alerts.yml
index 532d4b436bf..a0ee84b00d8 100644
--- a/Resources/Prototypes/Alerts/alerts.yml
+++ b/Resources/Prototypes/Alerts/alerts.yml
@@ -28,6 +28,7 @@
- alertType: Rooted
- alertType: Pacified
- alertType: Stealthy
+ - alertType: Offer # Floofstation - port from EE
- type: entity
id: AlertSpriteView
diff --git a/Resources/Prototypes/Body/species_appearance.yml b/Resources/Prototypes/Body/species_appearance.yml
index 10c8df10c81..e5812802a00 100644
--- a/Resources/Prototypes/Body/species_appearance.yml
+++ b/Resources/Prototypes/Body/species_appearance.yml
@@ -97,3 +97,4 @@
type: HumanoidMarkingModifierBoundUserInterface
enum.StrippingUiKey.Key:
type: StrippableBoundUserInterface
+ - type: OfferItem # Floofstation
diff --git a/Resources/Prototypes/_Floof/alerts.yml b/Resources/Prototypes/_Floof/alerts.yml
new file mode 100644
index 00000000000..2718ac0fa5b
--- /dev/null
+++ b/Resources/Prototypes/_Floof/alerts.yml
@@ -0,0 +1,8 @@
+- type: alert
+ id: Offer
+ clickEvent: !type:AcceptOfferAlertEvent { }
+ icons:
+ - sprite: /Textures/_Floof/Interface/Alerts/offer_item.rsi
+ state: offer_item
+ name: alerts-offer-name
+ description: alerts-offer-desc
diff --git a/Resources/Textures/_Floof/Interface/Alerts/offer_item.rsi/meta.json b/Resources/Textures/_Floof/Interface/Alerts/offer_item.rsi/meta.json
new file mode 100644
index 00000000000..9b5f9361314
--- /dev/null
+++ b/Resources/Textures/_Floof/Interface/Alerts/offer_item.rsi/meta.json
@@ -0,0 +1,14 @@
+{
+ "version": 1,
+ "license": "CC-BY-SA-3.0",
+ "copyright": "Original icon taken from https://github.com/ss220-space/Paradise/blob/master220/icons/mob/screen_alert.dmi, modified by Mocho",
+ "size": {
+ "x": 32,
+ "y": 32
+ },
+ "states": [
+ {
+ "name": "offer_item"
+ }
+ ]
+}
diff --git a/Resources/Textures/_Floof/Interface/Alerts/offer_item.rsi/offer_item.png b/Resources/Textures/_Floof/Interface/Alerts/offer_item.rsi/offer_item.png
new file mode 100644
index 0000000000000000000000000000000000000000..44ac380ddb19fefba315b2d433582aa773b8e6c7
GIT binary patch
literal 782
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