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