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);
|
SubscribeLocalEvent<SpillableComponent, LandEvent>(SpillOnLand);
|
||||||
// Openable handles the event if it's closed
|
// Openable handles the event if it's closed
|
||||||
SubscribeLocalEvent<SpillableComponent, MeleeHitEvent>(SplashOnMeleeHit, after: [typeof(OpenableSystem)]);
|
SubscribeLocalEvent<SpillableComponent, MeleeHitEvent>(SplashOnMeleeHit, after: [typeof(OpenableSystem)]);
|
||||||
SubscribeLocalEvent<SpillableComponent, ClothingGotEquippedEvent>(OnGotEquipped);
|
|
||||||
SubscribeLocalEvent<SpillableComponent, ClothingGotUnequippedEvent>(OnGotUnequipped);
|
|
||||||
SubscribeLocalEvent<SpillableComponent, SolutionContainerOverflowEvent>(OnOverflow);
|
SubscribeLocalEvent<SpillableComponent, SolutionContainerOverflowEvent>(OnOverflow);
|
||||||
SubscribeLocalEvent<SpillableComponent, SpillDoAfterEvent>(OnDoAfter);
|
SubscribeLocalEvent<SpillableComponent, SpillDoAfterEvent>(OnDoAfter);
|
||||||
SubscribeLocalEvent<SpillableComponent, AttemptPacifiedThrowEvent>(OnAttemptPacifiedThrow);
|
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)
|
private void SpillOnLand(Entity<SpillableComponent> entity, ref LandEvent args)
|
||||||
{
|
{
|
||||||
if (!_solutionContainerSystem.TryGetSolution(entity.Owner, entity.Comp.SolutionName, out var soln, out var solution))
|
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;
|
public bool Handled = false;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
[ByRefEvent]
|
||||||
|
public partial record struct SolutionAccessAttemptEvent(string SolutionName)
|
||||||
|
{
|
||||||
|
public bool Cancelled;
|
||||||
|
}
|
||||||
|
|
||||||
/// <summary>
|
/// <summary>
|
||||||
/// Part of Chemistry system deal with SolutionContainers
|
/// Part of Chemistry system deal with SolutionContainers
|
||||||
/// </summary>
|
/// </summary>
|
||||||
@@ -156,12 +162,6 @@ public abstract partial class SharedSolutionContainerSystem : EntitySystem
|
|||||||
[NotNullWhen(true)] out Entity<SolutionComponent>? entity,
|
[NotNullWhen(true)] out Entity<SolutionComponent>? entity,
|
||||||
bool errorOnMissing = false)
|
bool errorOnMissing = false)
|
||||||
{
|
{
|
||||||
if (TryComp(container, out BlockSolutionAccessComponent? blocker))
|
|
||||||
{
|
|
||||||
entity = null;
|
|
||||||
return false;
|
|
||||||
}
|
|
||||||
|
|
||||||
EntityUid uid;
|
EntityUid uid;
|
||||||
if (name is null)
|
if (name is null)
|
||||||
uid = container;
|
uid = container;
|
||||||
@@ -170,7 +170,18 @@ public abstract partial class SharedSolutionContainerSystem : EntitySystem
|
|||||||
solutionContainer is ContainerSlot solutionSlot &&
|
solutionContainer is ContainerSlot solutionSlot &&
|
||||||
solutionSlot.ContainedEntity is { } containedSolution
|
solutionSlot.ContainedEntity is { } containedSolution
|
||||||
)
|
)
|
||||||
|
{
|
||||||
|
var attemptEv = new SolutionAccessAttemptEvent(name);
|
||||||
|
RaiseLocalEvent(container, ref attemptEv);
|
||||||
|
|
||||||
|
if (attemptEv.Cancelled)
|
||||||
|
{
|
||||||
|
entity = null;
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
|
||||||
uid = containedSolution;
|
uid = containedSolution;
|
||||||
|
}
|
||||||
else
|
else
|
||||||
{
|
{
|
||||||
entity = null;
|
entity = null;
|
||||||
@@ -218,11 +229,14 @@ public abstract partial class SharedSolutionContainerSystem : EntitySystem
|
|||||||
if (!Resolve(container, ref container.Comp, logMissing: false))
|
if (!Resolve(container, ref container.Comp, logMissing: false))
|
||||||
yield break;
|
yield break;
|
||||||
|
|
||||||
if (HasComp<BlockSolutionAccessComponent>(container))
|
|
||||||
yield break;
|
|
||||||
|
|
||||||
foreach (var name in container.Comp.Containers)
|
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)
|
if (ContainerSystem.GetContainer(container, $"solution@{name}") is ContainerSlot slot && slot.ContainedEntity is { } solutionId)
|
||||||
yield return (name, (solutionId, Comp<SolutionComponent>(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")]
|
[DataField("solution")]
|
||||||
public string SolutionName = "puddle";
|
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]
|
[DataField]
|
||||||
public float? SpillDelay;
|
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
|
Blunt: 0
|
||||||
- type: Spillable
|
- type: Spillable
|
||||||
solution: bucket
|
solution: bucket
|
||||||
|
- type: SpillWhenWorn
|
||||||
|
solution: bucket
|
||||||
- type: DrawableSolution
|
- type: DrawableSolution
|
||||||
solution: bucket
|
solution: bucket
|
||||||
- type: RefillableSolution
|
- type: RefillableSolution
|
||||||
|
|||||||
Reference in New Issue
Block a user