diff --git a/Content.IntegrationTests/Tests/Fluids/PuddleTest.cs b/Content.IntegrationTests/Tests/Fluids/PuddleTest.cs
index e314734242..2f2ab47e0a 100644
--- a/Content.IntegrationTests/Tests/Fluids/PuddleTest.cs
+++ b/Content.IntegrationTests/Tests/Fluids/PuddleTest.cs
@@ -26,7 +26,7 @@ namespace Content.IntegrationTests.Tests.Fluids
server.Assert(() =>
{
- var solution = new Solution("water", FixedPoint2.New(20));
+ var solution = new Solution("Water", FixedPoint2.New(20));
var grid = GetMainGrid(mapManager);
var (x, y) = GetMainTile(grid).GridIndices;
var coordinates = new EntityCoordinates(grid.GridEntityId, x, y);
@@ -65,7 +65,7 @@ namespace Content.IntegrationTests.Tests.Fluids
server.Assert(() =>
{
var coordinates = grid.ToCoordinates();
- var solution = new Solution("water", FixedPoint2.New(20));
+ var solution = new Solution("Water", FixedPoint2.New(20));
var puddle = solution.SpillAt(coordinates, "PuddleSmear");
Assert.Null(puddle);
});
@@ -125,7 +125,7 @@ namespace Content.IntegrationTests.Tests.Fluids
// Spawn a puddle
await server.WaitAssertion(() =>
{
- var solution = new Solution("water", FixedPoint2.New(amount));
+ var solution = new Solution("Water", FixedPoint2.New(amount));
puddle = solution.SpillAt(sCoordinates, "PuddleSmear");
// Check that the puddle was created
diff --git a/Content.Server/Chemistry/Components/SolutionAreaEffectComponent.cs b/Content.Server/Chemistry/Components/SolutionAreaEffectComponent.cs
index 07507fb443..bfa38c5e66 100644
--- a/Content.Server/Chemistry/Components/SolutionAreaEffectComponent.cs
+++ b/Content.Server/Chemistry/Components/SolutionAreaEffectComponent.cs
@@ -29,6 +29,11 @@ namespace Content.Server.Chemistry.Components
public int Amount { get; set; }
public SolutionAreaEffectInceptionComponent? Inception { get; set; }
+ ///
+ /// Have we reacted with our tile yet?
+ ///
+ public bool ReactedTile = false;
+
///
/// Adds an to owner so the effect starts spreading and reacting.
///
@@ -138,7 +143,12 @@ namespace Content.Server.Chemistry.Components
var reagent = PrototypeManager.Index(reagentQuantity.ReagentId);
// React with the tile the effect is on
- reagent.ReactionTile(tile, reagentQuantity.Quantity * solutionFraction);
+ // We don't multiply by solutionFraction here since the tile is only ever reacted once
+ if (!ReactedTile)
+ {
+ reagent.ReactionTile(tile, reagentQuantity.Quantity);
+ ReactedTile = true;
+ }
// Touch every entity on the tile
foreach (var entity in tile.GetEntitiesInTileFast().ToArray())
diff --git a/Content.Server/Chemistry/TileReactions/CreateEntityReaction.cs b/Content.Server/Chemistry/TileReactions/CreateEntityReaction.cs
new file mode 100644
index 0000000000..a779aec33a
--- /dev/null
+++ b/Content.Server/Chemistry/TileReactions/CreateEntityReaction.cs
@@ -0,0 +1,63 @@
+using Content.Shared.Chemistry.Reaction;
+using Content.Shared.Chemistry.Reagent;
+using Content.Shared.FixedPoint;
+using Content.Shared.Maps;
+using Content.Shared.Whitelist;
+using Robust.Shared.GameObjects;
+using Robust.Shared.IoC;
+using Robust.Shared.Map;
+using Robust.Shared.Maths;
+using Robust.Shared.Prototypes;
+using Robust.Shared.Serialization.Manager.Attributes;
+using Robust.Shared.Serialization.TypeSerializers.Implementations.Custom.Prototype;
+
+namespace Content.Server.Chemistry.TileReactions;
+
+[DataDefinition]
+public class CreateEntityReaction : ITileReaction
+{
+ [DataField("entity", required: true, customTypeSerializer:typeof(PrototypeIdSerializer))]
+ public string Entity = default!;
+
+ [DataField("usage")]
+ public FixedPoint2 Usage = FixedPoint2.New(1);
+
+ ///
+ /// How many of the whitelisted entity can fit on one tile?
+ ///
+ [DataField("maxOnTile")]
+ public int MaxOnTile = 1;
+
+ ///
+ /// The whitelist to use when determining what counts as "max entities on a tile".0
+ ///
+ [DataField("maxOnTileWhitelist")]
+ public EntityWhitelist? Whitelist;
+
+ public FixedPoint2 TileReact(TileRef tile, ReagentPrototype reagent, FixedPoint2 reactVolume)
+ {
+ if (reactVolume >= Usage)
+ {
+ // TODO probably pass this in args like reagenteffects do.
+ var entMan = IoCManager.Resolve();
+
+ if (Whitelist != null)
+ {
+ int acc = 0;
+ foreach (var ent in tile.GetEntitiesInTile())
+ {
+ if (Whitelist.IsValid(ent.Uid))
+ acc += 1;
+
+ if (acc >= MaxOnTile)
+ return FixedPoint2.Zero;
+ }
+ }
+
+ entMan.SpawnEntity(Entity, tile.GridPosition().Offset(new Vector2(0.5f, 0.5f)));
+ return Usage;
+ }
+
+ return FixedPoint2.Zero;
+ }
+}
diff --git a/Content.Server/Fluids/Components/SpillExtensions.cs b/Content.Server/Fluids/Components/SpillExtensions.cs
index bbb33c04b3..5410687c27 100644
--- a/Content.Server/Fluids/Components/SpillExtensions.cs
+++ b/Content.Server/Fluids/Components/SpillExtensions.cs
@@ -10,6 +10,7 @@ using Robust.Server.GameObjects;
using Robust.Shared.GameObjects;
using Robust.Shared.IoC;
using Robust.Shared.Map;
+using Robust.Shared.Prototypes;
namespace Content.Server.Fluids.Components
{
@@ -129,7 +130,7 @@ namespace Content.Server.Fluids.Components
if (solution.TotalVolume <= 0) return null;
var mapManager = IoCManager.Resolve();
- var entityManager = IoCManager.Resolve();
+ var prototypeManager = IoCManager.Resolve();
var serverEntityManager = IoCManager.Resolve();
// If space return early, let that spill go out into the void
@@ -138,6 +139,17 @@ namespace Content.Server.Fluids.Components
var gridId = tileRef.GridIndex;
if (!mapManager.TryGetGrid(gridId, out var mapGrid)) return null; // Let's not spill to invalid grids.
+ // First, do all tile reactions
+ foreach (var reagent in solution.Contents.ToArray())
+ {
+ var proto = prototypeManager.Index(reagent.ReagentId);
+ proto.ReactionTile(tileRef, reagent.Quantity);
+ }
+
+ // Tile reactions used up everything.
+ if (solution.CurrentVolume == FixedPoint2.Zero)
+ return null;
+
// Get normalized co-ordinate for spill location and spill it in the centre
// TODO: Does SnapGrid or something else already do this?
var spillGridCoords = mapGrid.GridTileToLocal(tileRef.GridIndices);
diff --git a/Resources/Locale/en-US/reagents/carpetium.ftl b/Resources/Locale/en-US/reagents/carpetium.ftl
new file mode 100644
index 0000000000..19d6c349f8
--- /dev/null
+++ b/Resources/Locale/en-US/reagents/carpetium.ftl
@@ -0,0 +1,2 @@
+carpetium-effect-blood-fibrous = Your blood feels oddly fibrous today.
+carpetium-effect-jumpsuit-insides = You feel like there's a jumpsuit inside you, for some reason.
diff --git a/Resources/Prototypes/Entities/Clothing/Shoes/base.yml b/Resources/Prototypes/Entities/Clothing/Shoes/base.yml
index f4b41edccf..9a32580f21 100644
--- a/Resources/Prototypes/Entities/Clothing/Shoes/base.yml
+++ b/Resources/Prototypes/Entities/Clothing/Shoes/base.yml
@@ -8,3 +8,8 @@
- shoes
- type: Sprite
state: icon
+ - type: Extractable
+ juiceSolution:
+ reagents:
+ - ReagentId: Fiber
+ Quantity: 5
diff --git a/Resources/Prototypes/Entities/Clothing/Uniforms/base.yml b/Resources/Prototypes/Entities/Clothing/Uniforms/base.yml
index d6ad4e65e1..76f196fb3f 100644
--- a/Resources/Prototypes/Entities/Clothing/Uniforms/base.yml
+++ b/Resources/Prototypes/Entities/Clothing/Uniforms/base.yml
@@ -9,6 +9,11 @@
Slots: [innerclothing]
EquipSound:
path: /Audio/Items/jumpsuit_equip.ogg
+ - type: Extractable
+ juiceSolution:
+ reagents:
+ - ReagentId: Fiber
+ Quantity: 10
- type: entity
abstract: true
@@ -22,3 +27,8 @@
femaleMask: UniformTop
EquipSound:
path: /Audio/Items/jumpsuit_equip.ogg
+ - type: Extractable
+ juiceSolution:
+ reagents:
+ - ReagentId: Fiber
+ Quantity: 5
diff --git a/Resources/Prototypes/Entities/Structures/Furniture/carpets.yml b/Resources/Prototypes/Entities/Structures/Furniture/carpets.yml
index 236a45b7b5..47a7cbde8c 100644
--- a/Resources/Prototypes/Entities/Structures/Furniture/carpets.yml
+++ b/Resources/Prototypes/Entities/Structures/Furniture/carpets.yml
@@ -11,6 +11,8 @@
- type: IconSmooth
key: full
base: carpet_
+ - type: Tag
+ tags: [ Carpet ]
- type: Physics
canCollide: false
fixtures:
diff --git a/Resources/Prototypes/Reagents/fun.yml b/Resources/Prototypes/Reagents/fun.yml
new file mode 100644
index 0000000000..da0b8523c1
--- /dev/null
+++ b/Resources/Prototypes/Reagents/fun.yml
@@ -0,0 +1,25 @@
+- type: reagent
+ id: Carpetium
+ name: carpetium
+ desc: A mystical chemical, usually outsourced from the Clown Planet, that covers everything it touches in carpet.
+ physicalDesc: fibrous
+ color: "#800000"
+ tileReactions:
+ - !type:CreateEntityReaction
+ entity: Carpet
+ maxOnTileWhitelist:
+ tags: [ Carpet ]
+ metabolisms:
+ Poison:
+ effects:
+ - !type:PopupMessage
+ type: Local
+ messages: [ "carpetium-effect-blood-fibrous", "carpetium-effect-jumpsuit-insides" ]
+ probability: 0.1
+
+- type: reagent
+ id: Fiber
+ name: fiber
+ desc: A raw material, usually extracted from wool or other fabric products.
+ physicalDesc: fibrous
+ color: "#808080"
diff --git a/Resources/Prototypes/Recipes/Reactions/fun.yml b/Resources/Prototypes/Recipes/Reactions/fun.yml
new file mode 100644
index 0000000000..5dcd48eb6f
--- /dev/null
+++ b/Resources/Prototypes/Recipes/Reactions/fun.yml
@@ -0,0 +1,9 @@
+- type: reaction
+ id: Carpetium
+ reactants:
+ SpaceDrugs:
+ amount: 1
+ Fiber:
+ amount: 2
+ products:
+ Carpetium: 3
diff --git a/Resources/Prototypes/tags.yml b/Resources/Prototypes/tags.yml
index 99e410ffa6..176567e0fb 100644
--- a/Resources/Prototypes/tags.yml
+++ b/Resources/Prototypes/tags.yml
@@ -27,6 +27,9 @@
- type: Tag
id: Carrot
+- type: Tag
+ id: Carpet
+
- type: Tag
id: CanPilot
@@ -125,7 +128,7 @@
- type: Tag
id: Handcuffs
-
+
- type: Tag
id: HideContextMenu