* BlockSolutionAccessComponent now only blocks one specified solution.
* Significant overhaul
Separated spilling when worn functionality into its own component/system.
Removed BlockSolutionAccessComponent.
Added an event for solution access.
SubscribeLocalEvent<SpillableComponent, LandEvent>(SpillOnLand);
// Openable handles the event if it's closed
SubscribeLocalEvent<SpillableComponent, MeleeHitEvent>(SplashOnMeleeHit, after: [typeof(OpenableSystem)]);
- SubscribeLocalEvent<SpillableComponent, ClothingGotEquippedEvent>(OnGotEquipped);
- SubscribeLocalEvent<SpillableComponent, ClothingGotUnequippedEvent>(OnGotUnequipped);
SubscribeLocalEvent<SpillableComponent, SolutionContainerOverflowEvent>(OnOverflow);
SubscribeLocalEvent<SpillableComponent, SpillDoAfterEvent>(OnDoAfter);
SubscribeLocalEvent<SpillableComponent, AttemptPacifiedThrowEvent>(OnAttemptPacifiedThrow);
}
}
- private void OnGotEquipped(Entity<SpillableComponent> entity, ref ClothingGotEquippedEvent args)
- {
- if (!entity.Comp.SpillWorn)
- return;
-
- if (!_solutionContainerSystem.TryGetSolution(entity.Owner, entity.Comp.SolutionName, out var soln, out var solution))
- return;
-
- // block access to the solution while worn
- AddComp<BlockSolutionAccessComponent>(entity);
-
- if (solution.Volume == 0)
- return;
-
- // spill all solution on the player
- var drainedSolution = _solutionContainerSystem.Drain(entity.Owner, soln.Value, solution.Volume);
- TrySplashSpillAt(entity.Owner, Transform(args.Wearer).Coordinates, drainedSolution, out _);
- }
-
- private void OnGotUnequipped(Entity<SpillableComponent> entity, ref ClothingGotUnequippedEvent args)
- {
- if (!entity.Comp.SpillWorn)
- return;
-
- RemCompDeferred<BlockSolutionAccessComponent>(entity);
- }
-
private void SpillOnLand(Entity<SpillableComponent> entity, ref LandEvent args)
{
if (!_solutionContainerSystem.TryGetSolution(entity.Owner, entity.Comp.SolutionName, out var soln, out var solution))
+++ /dev/null
-using Robust.Shared.GameStates;
-
-namespace Content.Shared.Chemistry.Components;
-
-/// <summary>
-/// Blocks all attempts to access solutions contained by this entity.
-/// </summary>
-[RegisterComponent, NetworkedComponent]
-public sealed partial class BlockSolutionAccessComponent : Component
-{
-}
public bool Handled = false;
}
+[ByRefEvent]
+public partial record struct SolutionAccessAttemptEvent(string SolutionName)
+{
+ public bool Cancelled;
+}
+
/// <summary>
/// Part of Chemistry system deal with SolutionContainers
/// </summary>
[NotNullWhen(true)] out Entity<SolutionComponent>? entity,
bool errorOnMissing = false)
{
- if (TryComp(container, out BlockSolutionAccessComponent? blocker))
- {
- entity = null;
- return false;
- }
-
EntityUid uid;
if (name is null)
uid = container;
solutionContainer is ContainerSlot solutionSlot &&
solutionSlot.ContainedEntity is { } containedSolution
)
+ {
+ var attemptEv = new SolutionAccessAttemptEvent(name);
+ RaiseLocalEvent(container, ref attemptEv);
+
+ if (attemptEv.Cancelled)
+ {
+ entity = null;
+ return false;
+ }
+
uid = containedSolution;
+ }
else
{
entity = null;
if (!Resolve(container, ref container.Comp, logMissing: false))
yield break;
- if (HasComp<BlockSolutionAccessComponent>(container))
- yield break;
-
foreach (var name in container.Comp.Containers)
{
+ var attemptEv = new SolutionAccessAttemptEvent(name);
+ RaiseLocalEvent(container, ref attemptEv);
+
+ if (attemptEv.Cancelled)
+ continue;
+
if (ContainerSystem.GetContainer(container, $"solution@{name}") is ContainerSlot slot && slot.ContainedEntity is { } solutionId)
yield return (name, (solutionId, Comp<SolutionComponent>(solutionId)));
}
--- /dev/null
+using Robust.Shared.GameStates;
+
+namespace Content.Shared.Fluids.Components;
+
+/// <summary>
+/// This entity will spill its contained solution onto the wearer when worn, and its
+/// (empty) contents will be inaccessible while still worn.
+/// </summary>
+[RegisterComponent]
+[NetworkedComponent, AutoGenerateComponentState]
+public sealed partial class SpillWhenWornComponent : Component
+{
+ /// <summary>
+ /// Name of the solution to spill.
+ /// </summary>
+ [DataField]
+ public string Solution = "default";
+
+ /// <summary>
+ /// Tracks if this item is currently being worn.
+ /// </summary>
+ [DataField, AutoNetworkedField]
+ public bool IsWorn;
+}
[DataField("solution")]
public string SolutionName = "puddle";
- /// <summary>
- /// Should this item be spilled when worn as clothing?
- /// Doesn't count for pockets or hands.
- /// </summary>
- [DataField]
- public bool SpillWorn = true;
-
[DataField]
public float? SpillDelay;
--- /dev/null
+using Content.Shared.Chemistry.EntitySystems;
+using Content.Shared.Clothing;
+using Content.Shared.Fluids.Components;
+
+namespace Content.Shared.Fluids.EntitySystems;
+
+/// <inheritdoc cref="SpillWhenWornComponent"/>
+public sealed class SpillWhenWornSystem : EntitySystem
+{
+ [Dependency] private readonly SharedSolutionContainerSystem _solutionContainer = default!;
+ [Dependency] private readonly SharedPuddleSystem _puddle = default!;
+
+ public override void Initialize()
+ {
+ base.Initialize();
+
+ SubscribeLocalEvent<SpillWhenWornComponent, ClothingGotEquippedEvent>(OnGotEquipped);
+ SubscribeLocalEvent<SpillWhenWornComponent, ClothingGotUnequippedEvent>(OnGotUnequipped);
+ SubscribeLocalEvent<SpillWhenWornComponent, SolutionAccessAttemptEvent>(OnSolutionAccessAttempt);
+ }
+
+ private void OnGotEquipped(Entity<SpillWhenWornComponent> ent, ref ClothingGotEquippedEvent args)
+ {
+ if (_solutionContainer.TryGetSolution(ent.Owner, ent.Comp.Solution, out var soln, out var solution)
+ && solution.Volume > 0)
+ {
+ // Spill all solution on the player
+ var drainedSolution = _solutionContainer.Drain(ent.Owner, soln.Value, solution.Volume);
+ _puddle.TrySplashSpillAt(ent.Owner, Transform(args.Wearer).Coordinates, drainedSolution, out _);
+ }
+
+ // Flag as worn after draining, otherwise we'll block ourself from accessing!
+ ent.Comp.IsWorn = true;
+ Dirty(ent);
+ }
+
+ private void OnGotUnequipped(Entity<SpillWhenWornComponent> ent, ref ClothingGotUnequippedEvent args)
+ {
+ ent.Comp.IsWorn = false;
+ Dirty(ent);
+ }
+
+ private void OnSolutionAccessAttempt(Entity<SpillWhenWornComponent> ent, ref SolutionAccessAttemptEvent args)
+ {
+ // If we're not being worn right now, we don't care
+ if (!ent.Comp.IsWorn)
+ return;
+
+ // Make sure it's the right solution
+ if (ent.Comp.Solution != args.SolutionName)
+ return;
+
+ args.Cancelled = true;
+ }
+}
Blunt: 0
- type: Spillable
solution: bucket
+ - type: SpillWhenWorn
+ solution: bucket
- type: DrawableSolution
solution: bucket
- type: RefillableSolution