Replace BlockSolutionAccessComponent with an attempt event (#26988)
* 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.
This commit is contained in:
@@ -27,8 +27,6 @@ public sealed partial class PuddleSystem
|
||||
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);
|
||||
@@ -97,33 +95,6 @@ public sealed partial class PuddleSystem
|
||||
}
|
||||
}
|
||||
|
||||
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))
|
||||
|
||||
@@ -1,11 +0,0 @@
|
||||
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
|
||||
{
|
||||
}
|
||||
@@ -48,6 +48,12 @@ public partial record struct SolutionOverflowEvent(Entity<SolutionComponent> Sol
|
||||
public bool Handled = false;
|
||||
}
|
||||
|
||||
[ByRefEvent]
|
||||
public partial record struct SolutionAccessAttemptEvent(string SolutionName)
|
||||
{
|
||||
public bool Cancelled;
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Part of Chemistry system deal with SolutionContainers
|
||||
/// </summary>
|
||||
@@ -156,12 +162,6 @@ public abstract partial class SharedSolutionContainerSystem : EntitySystem
|
||||
[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;
|
||||
@@ -170,7 +170,18 @@ public abstract partial class SharedSolutionContainerSystem : EntitySystem
|
||||
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;
|
||||
@@ -218,11 +229,14 @@ public abstract partial class SharedSolutionContainerSystem : EntitySystem
|
||||
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)));
|
||||
}
|
||||
|
||||
24
Content.Shared/Fluids/Components/SpillWhenWornComponent.cs
Normal file
24
Content.Shared/Fluids/Components/SpillWhenWornComponent.cs
Normal file
@@ -0,0 +1,24 @@
|
||||
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;
|
||||
}
|
||||
@@ -14,13 +14,6 @@ public sealed partial class SpillableComponent : Component
|
||||
[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;
|
||||
|
||||
|
||||
55
Content.Shared/Fluids/EntitySystems/SpillWhenWornSystem.cs
Normal file
55
Content.Shared/Fluids/EntitySystems/SpillWhenWornSystem.cs
Normal file
@@ -0,0 +1,55 @@
|
||||
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;
|
||||
}
|
||||
}
|
||||
@@ -45,6 +45,8 @@
|
||||
Blunt: 0
|
||||
- type: Spillable
|
||||
solution: bucket
|
||||
- type: SpillWhenWorn
|
||||
solution: bucket
|
||||
- type: DrawableSolution
|
||||
solution: bucket
|
||||
- type: RefillableSolution
|
||||
|
||||
Reference in New Issue
Block a user