Add prediction to Spill Container verb, add dummy TrySpill methods to shared (#25813)
* Moved abstract spill methods to shared; added prediction to spill container verb. * Rerun tests * Requested changes * Note Client behavior in Spill method docs
This commit is contained in:
@@ -1,7 +1,9 @@
|
|||||||
using Content.Client.IconSmoothing;
|
using Content.Client.IconSmoothing;
|
||||||
|
using Content.Shared.Chemistry.Components;
|
||||||
using Content.Shared.Fluids;
|
using Content.Shared.Fluids;
|
||||||
using Content.Shared.Fluids.Components;
|
using Content.Shared.Fluids.Components;
|
||||||
using Robust.Client.GameObjects;
|
using Robust.Client.GameObjects;
|
||||||
|
using Robust.Shared.Map;
|
||||||
|
|
||||||
namespace Content.Client.Fluids;
|
namespace Content.Client.Fluids;
|
||||||
|
|
||||||
@@ -21,7 +23,7 @@ public sealed class PuddleSystem : SharedPuddleSystem
|
|||||||
if (args.Sprite == null)
|
if (args.Sprite == null)
|
||||||
return;
|
return;
|
||||||
|
|
||||||
float volume = 1f;
|
var volume = 1f;
|
||||||
|
|
||||||
if (args.AppearanceData.TryGetValue(PuddleVisuals.CurrentVolume, out var volumeObj))
|
if (args.AppearanceData.TryGetValue(PuddleVisuals.CurrentVolume, out var volumeObj))
|
||||||
{
|
{
|
||||||
@@ -64,4 +66,38 @@ public sealed class PuddleSystem : SharedPuddleSystem
|
|||||||
args.Sprite.Color *= baseColor;
|
args.Sprite.Color *= baseColor;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
#region Spill
|
||||||
|
|
||||||
|
// Maybe someday we'll have clientside prediction for entity spawning, but not today.
|
||||||
|
// Until then, these methods do nothing on the client.
|
||||||
|
/// <inheritdoc/>
|
||||||
|
public override bool TrySplashSpillAt(EntityUid uid, EntityCoordinates coordinates, Solution solution, out EntityUid puddleUid, bool sound = true, EntityUid? user = null)
|
||||||
|
{
|
||||||
|
puddleUid = EntityUid.Invalid;
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
|
||||||
|
/// <inheritdoc/>
|
||||||
|
public override bool TrySpillAt(EntityCoordinates coordinates, Solution solution, out EntityUid puddleUid, bool sound = true)
|
||||||
|
{
|
||||||
|
puddleUid = EntityUid.Invalid;
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
|
||||||
|
/// <inheritdoc/>
|
||||||
|
public override bool TrySpillAt(EntityUid uid, Solution solution, out EntityUid puddleUid, bool sound = true, TransformComponent? transformComponent = null)
|
||||||
|
{
|
||||||
|
puddleUid = EntityUid.Invalid;
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
|
||||||
|
/// <inheritdoc/>
|
||||||
|
public override bool TrySpillAt(TileRef tileRef, Solution solution, out EntityUid puddleUid, bool sound = true, bool tileReact = true)
|
||||||
|
{
|
||||||
|
puddleUid = EntityUid.Invalid;
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
|
||||||
|
#endregion Spill
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -1,7 +0,0 @@
|
|||||||
namespace Content.Server.Fluids.Components;
|
|
||||||
|
|
||||||
[RegisterComponent]
|
|
||||||
public sealed partial class PreventSpillerComponent : Component
|
|
||||||
{
|
|
||||||
|
|
||||||
}
|
|
||||||
@@ -1,5 +1,4 @@
|
|||||||
using Content.Server.Chemistry.Containers.EntitySystems;
|
using Content.Server.Chemistry.Containers.EntitySystems;
|
||||||
using Content.Server.Fluids.Components;
|
|
||||||
using Content.Server.Nutrition.EntitySystems;
|
using Content.Server.Nutrition.EntitySystems;
|
||||||
using Content.Shared.Chemistry.Components;
|
using Content.Shared.Chemistry.Components;
|
||||||
using Content.Shared.Chemistry.EntitySystems;
|
using Content.Shared.Chemistry.EntitySystems;
|
||||||
@@ -8,7 +7,6 @@ using Content.Shared.Chemistry.Reagent;
|
|||||||
using Content.Shared.Clothing.Components;
|
using Content.Shared.Clothing.Components;
|
||||||
using Content.Shared.CombatMode.Pacification;
|
using Content.Shared.CombatMode.Pacification;
|
||||||
using Content.Shared.Database;
|
using Content.Shared.Database;
|
||||||
using Content.Shared.DoAfter;
|
|
||||||
using Content.Shared.FixedPoint;
|
using Content.Shared.FixedPoint;
|
||||||
using Content.Shared.Fluids.Components;
|
using Content.Shared.Fluids.Components;
|
||||||
using Content.Shared.IdentityManagement;
|
using Content.Shared.IdentityManagement;
|
||||||
@@ -16,7 +14,6 @@ using Content.Shared.Inventory.Events;
|
|||||||
using Content.Shared.Popups;
|
using Content.Shared.Popups;
|
||||||
using Content.Shared.Spillable;
|
using Content.Shared.Spillable;
|
||||||
using Content.Shared.Throwing;
|
using Content.Shared.Throwing;
|
||||||
using Content.Shared.Verbs;
|
|
||||||
using Content.Shared.Weapons.Melee.Events;
|
using Content.Shared.Weapons.Melee.Events;
|
||||||
using Robust.Shared.Player;
|
using Robust.Shared.Player;
|
||||||
|
|
||||||
@@ -24,9 +21,6 @@ namespace Content.Server.Fluids.EntitySystems;
|
|||||||
|
|
||||||
public sealed partial class PuddleSystem
|
public sealed partial class PuddleSystem
|
||||||
{
|
{
|
||||||
[Dependency] private readonly OpenableSystem _openable = default!;
|
|
||||||
[Dependency] private readonly IEntityManager _entityManager = default!;
|
|
||||||
|
|
||||||
protected override void InitializeSpillable()
|
protected override void InitializeSpillable()
|
||||||
{
|
{
|
||||||
base.InitializeSpillable();
|
base.InitializeSpillable();
|
||||||
@@ -34,7 +28,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, GetVerbsEvent<Verb>>(AddSpillVerb);
|
|
||||||
SubscribeLocalEvent<SpillableComponent, GotEquippedEvent>(OnGotEquipped);
|
SubscribeLocalEvent<SpillableComponent, GotEquippedEvent>(OnGotEquipped);
|
||||||
SubscribeLocalEvent<SpillableComponent, SolutionContainerOverflowEvent>(OnOverflow);
|
SubscribeLocalEvent<SpillableComponent, SolutionContainerOverflowEvent>(OnOverflow);
|
||||||
SubscribeLocalEvent<SpillableComponent, SpillDoAfterEvent>(OnDoAfter);
|
SubscribeLocalEvent<SpillableComponent, SpillDoAfterEvent>(OnDoAfter);
|
||||||
@@ -134,7 +127,7 @@ public sealed partial class PuddleSystem
|
|||||||
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))
|
||||||
return;
|
return;
|
||||||
|
|
||||||
if (_openable.IsClosed(entity.Owner))
|
if (Openable.IsClosed(entity.Owner))
|
||||||
return;
|
return;
|
||||||
|
|
||||||
if (args.User != null)
|
if (args.User != null)
|
||||||
@@ -153,7 +146,7 @@ public sealed partial class PuddleSystem
|
|||||||
private void OnAttemptPacifiedThrow(Entity<SpillableComponent> ent, ref AttemptPacifiedThrowEvent args)
|
private void OnAttemptPacifiedThrow(Entity<SpillableComponent> ent, ref AttemptPacifiedThrowEvent args)
|
||||||
{
|
{
|
||||||
// Don’t care about closed containers.
|
// Don’t care about closed containers.
|
||||||
if (_openable.IsClosed(ent))
|
if (Openable.IsClosed(ent))
|
||||||
return;
|
return;
|
||||||
|
|
||||||
// Don’t care about empty containers.
|
// Don’t care about empty containers.
|
||||||
@@ -163,57 +156,6 @@ public sealed partial class PuddleSystem
|
|||||||
args.Cancel("pacified-cannot-throw-spill");
|
args.Cancel("pacified-cannot-throw-spill");
|
||||||
}
|
}
|
||||||
|
|
||||||
private void AddSpillVerb(Entity<SpillableComponent> entity, ref GetVerbsEvent<Verb> args)
|
|
||||||
{
|
|
||||||
if (!args.CanAccess || !args.CanInteract)
|
|
||||||
return;
|
|
||||||
|
|
||||||
if (!_solutionContainerSystem.TryGetSolution(args.Target, entity.Comp.SolutionName, out var soln, out var solution))
|
|
||||||
return;
|
|
||||||
|
|
||||||
if (_openable.IsClosed(args.Target))
|
|
||||||
return;
|
|
||||||
|
|
||||||
if (solution.Volume == FixedPoint2.Zero)
|
|
||||||
return;
|
|
||||||
|
|
||||||
if (_entityManager.HasComponent<PreventSpillerComponent>(args.User))
|
|
||||||
return;
|
|
||||||
|
|
||||||
|
|
||||||
Verb verb = new()
|
|
||||||
{
|
|
||||||
Text = Loc.GetString("spill-target-verb-get-data-text")
|
|
||||||
};
|
|
||||||
|
|
||||||
// TODO VERB ICONS spill icon? pouring out a glass/beaker?
|
|
||||||
if (entity.Comp.SpillDelay == null)
|
|
||||||
{
|
|
||||||
var target = args.Target;
|
|
||||||
verb.Act = () =>
|
|
||||||
{
|
|
||||||
var puddleSolution = _solutionContainerSystem.SplitSolution(soln.Value, solution.Volume);
|
|
||||||
TrySpillAt(Transform(target).Coordinates, puddleSolution, out _);
|
|
||||||
};
|
|
||||||
}
|
|
||||||
else
|
|
||||||
{
|
|
||||||
var user = args.User;
|
|
||||||
verb.Act = () =>
|
|
||||||
{
|
|
||||||
_doAfterSystem.TryStartDoAfter(new DoAfterArgs(EntityManager, user, entity.Comp.SpillDelay ?? 0, new SpillDoAfterEvent(), entity.Owner, target: entity.Owner)
|
|
||||||
{
|
|
||||||
BreakOnDamage = true,
|
|
||||||
BreakOnMove = true,
|
|
||||||
NeedHand = true,
|
|
||||||
});
|
|
||||||
};
|
|
||||||
}
|
|
||||||
verb.Impact = LogImpact.Medium; // dangerous reagent reaction are logged separately.
|
|
||||||
verb.DoContactInteraction = true;
|
|
||||||
args.Verbs.Add(verb);
|
|
||||||
}
|
|
||||||
|
|
||||||
private void OnDoAfter(Entity<SpillableComponent> entity, ref SpillDoAfterEvent args)
|
private void OnDoAfter(Entity<SpillableComponent> entity, ref SpillDoAfterEvent args)
|
||||||
{
|
{
|
||||||
if (args.Handled || args.Cancelled || args.Args.Target == null)
|
if (args.Handled || args.Cancelled || args.Args.Target == null)
|
||||||
|
|||||||
@@ -46,7 +46,6 @@ public sealed partial class PuddleSystem : SharedPuddleSystem
|
|||||||
[Dependency] private readonly IRobustRandom _random = default!;
|
[Dependency] private readonly IRobustRandom _random = default!;
|
||||||
[Dependency] private readonly ITileDefinitionManager _tileDefMan = default!;
|
[Dependency] private readonly ITileDefinitionManager _tileDefMan = default!;
|
||||||
[Dependency] private readonly AudioSystem _audio = default!;
|
[Dependency] private readonly AudioSystem _audio = default!;
|
||||||
[Dependency] private readonly DoAfterSystem _doAfterSystem = default!;
|
|
||||||
[Dependency] private readonly EntityLookupSystem _lookup = default!;
|
[Dependency] private readonly EntityLookupSystem _lookup = default!;
|
||||||
[Dependency] private readonly ReactiveSystem _reactive = default!;
|
[Dependency] private readonly ReactiveSystem _reactive = default!;
|
||||||
[Dependency] private readonly SharedAppearanceSystem _appearance = default!;
|
[Dependency] private readonly SharedAppearanceSystem _appearance = default!;
|
||||||
@@ -551,11 +550,8 @@ public sealed partial class PuddleSystem : SharedPuddleSystem
|
|||||||
|
|
||||||
#region Spill
|
#region Spill
|
||||||
|
|
||||||
/// <summary>
|
/// <inheritdoc/>
|
||||||
/// First splashes reagent on reactive entities near the spilling entity, then spills the rest regularly to a
|
public override bool TrySplashSpillAt(EntityUid uid,
|
||||||
/// puddle. This is intended for 'destructive' spills, like when entities are destroyed or thrown.
|
|
||||||
/// </summary>
|
|
||||||
public bool TrySplashSpillAt(EntityUid uid,
|
|
||||||
EntityCoordinates coordinates,
|
EntityCoordinates coordinates,
|
||||||
Solution solution,
|
Solution solution,
|
||||||
out EntityUid puddleUid,
|
out EntityUid puddleUid,
|
||||||
@@ -600,11 +596,8 @@ public sealed partial class PuddleSystem : SharedPuddleSystem
|
|||||||
return TrySpillAt(coordinates, solution, out puddleUid, sound);
|
return TrySpillAt(coordinates, solution, out puddleUid, sound);
|
||||||
}
|
}
|
||||||
|
|
||||||
/// <summary>
|
/// <inheritdoc/>
|
||||||
/// Spills solution at the specified coordinates.
|
public override bool TrySpillAt(EntityCoordinates coordinates, Solution solution, out EntityUid puddleUid, bool sound = true)
|
||||||
/// Will add to an existing puddle if present or create a new one if not.
|
|
||||||
/// </summary>
|
|
||||||
public bool TrySpillAt(EntityCoordinates coordinates, Solution solution, out EntityUid puddleUid, bool sound = true)
|
|
||||||
{
|
{
|
||||||
if (solution.Volume == 0)
|
if (solution.Volume == 0)
|
||||||
{
|
{
|
||||||
@@ -622,10 +615,8 @@ public sealed partial class PuddleSystem : SharedPuddleSystem
|
|||||||
return TrySpillAt(_map.GetTileRef(gridUid.Value, mapGrid, coordinates), solution, out puddleUid, sound);
|
return TrySpillAt(_map.GetTileRef(gridUid.Value, mapGrid, coordinates), solution, out puddleUid, sound);
|
||||||
}
|
}
|
||||||
|
|
||||||
/// <summary>
|
/// <inheritdoc/>
|
||||||
/// <see cref="TrySpillAt(Robust.Shared.Map.EntityCoordinates,Content.Shared.Chemistry.Components.Solution,out Robust.Shared.GameObjects.EntityUid,bool)"/>
|
public override bool TrySpillAt(EntityUid uid, Solution solution, out EntityUid puddleUid, bool sound = true,
|
||||||
/// </summary>
|
|
||||||
public bool TrySpillAt(EntityUid uid, Solution solution, out EntityUid puddleUid, bool sound = true,
|
|
||||||
TransformComponent? transformComponent = null)
|
TransformComponent? transformComponent = null)
|
||||||
{
|
{
|
||||||
if (!Resolve(uid, ref transformComponent, false))
|
if (!Resolve(uid, ref transformComponent, false))
|
||||||
@@ -637,10 +628,8 @@ public sealed partial class PuddleSystem : SharedPuddleSystem
|
|||||||
return TrySpillAt(transformComponent.Coordinates, solution, out puddleUid, sound: sound);
|
return TrySpillAt(transformComponent.Coordinates, solution, out puddleUid, sound: sound);
|
||||||
}
|
}
|
||||||
|
|
||||||
/// <summary>
|
/// <inheritdoc/>
|
||||||
/// <see cref="TrySpillAt(Robust.Shared.Map.EntityCoordinates,Content.Shared.Chemistry.Components.Solution,out Robust.Shared.GameObjects.EntityUid,bool)"/>
|
public override bool TrySpillAt(TileRef tileRef, Solution solution, out EntityUid puddleUid, bool sound = true,
|
||||||
/// </summary>
|
|
||||||
public bool TrySpillAt(TileRef tileRef, Solution solution, out EntityUid puddleUid, bool sound = true,
|
|
||||||
bool tileReact = true)
|
bool tileReact = true)
|
||||||
{
|
{
|
||||||
if (solution.Volume <= 0)
|
if (solution.Volume <= 0)
|
||||||
|
|||||||
12
Content.Shared/Fluids/Components/PreventSpillerComponent.cs
Normal file
12
Content.Shared/Fluids/Components/PreventSpillerComponent.cs
Normal file
@@ -0,0 +1,12 @@
|
|||||||
|
using Robust.Shared.GameStates;
|
||||||
|
|
||||||
|
namespace Content.Shared.Fluids.Components;
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// Blocks this entity's ability to spill solution containing entities via the verb menu.
|
||||||
|
/// </summary>
|
||||||
|
[RegisterComponent, NetworkedComponent]
|
||||||
|
public sealed partial class PreventSpillerComponent : Component
|
||||||
|
{
|
||||||
|
|
||||||
|
}
|
||||||
@@ -2,6 +2,12 @@ using Content.Shared.FixedPoint;
|
|||||||
|
|
||||||
namespace Content.Shared.Fluids.Components;
|
namespace Content.Shared.Fluids.Components;
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// Makes a solution contained in this entity spillable.
|
||||||
|
/// Spills can occur when a container with this component overflows,
|
||||||
|
/// is used to melee attack something, is equipped (see <see cref="SpillWorn"/>),
|
||||||
|
/// lands after being thrown, or has the Spill verb used.
|
||||||
|
/// </summary>
|
||||||
[RegisterComponent]
|
[RegisterComponent]
|
||||||
public sealed partial class SpillableComponent : Component
|
public sealed partial class SpillableComponent : Component
|
||||||
{
|
{
|
||||||
|
|||||||
@@ -1,14 +1,23 @@
|
|||||||
|
using Content.Shared.Database;
|
||||||
|
using Content.Shared.DoAfter;
|
||||||
using Content.Shared.Examine;
|
using Content.Shared.Examine;
|
||||||
|
using Content.Shared.FixedPoint;
|
||||||
using Content.Shared.Fluids.Components;
|
using Content.Shared.Fluids.Components;
|
||||||
|
using Content.Shared.Nutrition.EntitySystems;
|
||||||
|
using Content.Shared.Spillable;
|
||||||
|
using Content.Shared.Verbs;
|
||||||
using Content.Shared.Weapons.Melee;
|
using Content.Shared.Weapons.Melee;
|
||||||
|
|
||||||
namespace Content.Shared.Fluids;
|
namespace Content.Shared.Fluids;
|
||||||
|
|
||||||
public abstract partial class SharedPuddleSystem
|
public abstract partial class SharedPuddleSystem
|
||||||
{
|
{
|
||||||
|
[Dependency] protected readonly SharedOpenableSystem Openable = default!;
|
||||||
|
|
||||||
protected virtual void InitializeSpillable()
|
protected virtual void InitializeSpillable()
|
||||||
{
|
{
|
||||||
SubscribeLocalEvent<SpillableComponent, ExaminedEvent>(OnExamined);
|
SubscribeLocalEvent<SpillableComponent, ExaminedEvent>(OnExamined);
|
||||||
|
SubscribeLocalEvent<SpillableComponent, GetVerbsEvent<Verb>>(AddSpillVerb);
|
||||||
}
|
}
|
||||||
|
|
||||||
private void OnExamined(Entity<SpillableComponent> entity, ref ExaminedEvent args)
|
private void OnExamined(Entity<SpillableComponent> entity, ref ExaminedEvent args)
|
||||||
@@ -21,4 +30,55 @@ public abstract partial class SharedPuddleSystem
|
|||||||
args.PushMarkup(Loc.GetString("spill-examine-spillable-weapon"));
|
args.PushMarkup(Loc.GetString("spill-examine-spillable-weapon"));
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
private void AddSpillVerb(Entity<SpillableComponent> entity, ref GetVerbsEvent<Verb> args)
|
||||||
|
{
|
||||||
|
if (!args.CanAccess || !args.CanInteract)
|
||||||
|
return;
|
||||||
|
|
||||||
|
if (!_solutionContainerSystem.TryGetSolution(args.Target, entity.Comp.SolutionName, out var soln, out var solution))
|
||||||
|
return;
|
||||||
|
|
||||||
|
if (Openable.IsClosed(args.Target))
|
||||||
|
return;
|
||||||
|
|
||||||
|
if (solution.Volume == FixedPoint2.Zero)
|
||||||
|
return;
|
||||||
|
|
||||||
|
if (HasComp<PreventSpillerComponent>(args.User))
|
||||||
|
return;
|
||||||
|
|
||||||
|
|
||||||
|
Verb verb = new()
|
||||||
|
{
|
||||||
|
Text = Loc.GetString("spill-target-verb-get-data-text")
|
||||||
|
};
|
||||||
|
|
||||||
|
// TODO VERB ICONS spill icon? pouring out a glass/beaker?
|
||||||
|
if (entity.Comp.SpillDelay == null)
|
||||||
|
{
|
||||||
|
var target = args.Target;
|
||||||
|
verb.Act = () =>
|
||||||
|
{
|
||||||
|
var puddleSolution = _solutionContainerSystem.SplitSolution(soln.Value, solution.Volume);
|
||||||
|
TrySpillAt(Transform(target).Coordinates, puddleSolution, out _);
|
||||||
|
};
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
var user = args.User;
|
||||||
|
verb.Act = () =>
|
||||||
|
{
|
||||||
|
_doAfterSystem.TryStartDoAfter(new DoAfterArgs(EntityManager, user, entity.Comp.SpillDelay ?? 0, new SpillDoAfterEvent(), entity.Owner, target: entity.Owner)
|
||||||
|
{
|
||||||
|
BreakOnDamage = true,
|
||||||
|
BreakOnMove = true,
|
||||||
|
NeedHand = true,
|
||||||
|
});
|
||||||
|
};
|
||||||
|
}
|
||||||
|
verb.Impact = LogImpact.Medium; // dangerous reagent reaction are logged separately.
|
||||||
|
verb.DoContactInteraction = true;
|
||||||
|
args.Verbs.Add(verb);
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -1,12 +1,14 @@
|
|||||||
using Content.Shared.Chemistry.Components;
|
using Content.Shared.Chemistry.Components;
|
||||||
using Content.Shared.Chemistry.EntitySystems;
|
using Content.Shared.Chemistry.EntitySystems;
|
||||||
using Content.Shared.Chemistry.Reagent;
|
using Content.Shared.Chemistry.Reagent;
|
||||||
|
using Content.Shared.DoAfter;
|
||||||
using Content.Shared.DragDrop;
|
using Content.Shared.DragDrop;
|
||||||
using Content.Shared.Examine;
|
using Content.Shared.Examine;
|
||||||
using Content.Shared.FixedPoint;
|
using Content.Shared.FixedPoint;
|
||||||
using Content.Shared.Fluids.Components;
|
using Content.Shared.Fluids.Components;
|
||||||
using Content.Shared.Movement.Events;
|
using Content.Shared.Movement.Events;
|
||||||
using Content.Shared.StepTrigger.Components;
|
using Content.Shared.StepTrigger.Components;
|
||||||
|
using Robust.Shared.Map;
|
||||||
using Robust.Shared.Prototypes;
|
using Robust.Shared.Prototypes;
|
||||||
|
|
||||||
namespace Content.Shared.Fluids;
|
namespace Content.Shared.Fluids;
|
||||||
@@ -15,6 +17,7 @@ public abstract partial class SharedPuddleSystem : EntitySystem
|
|||||||
{
|
{
|
||||||
[Dependency] private readonly IPrototypeManager _prototypeManager = default!;
|
[Dependency] private readonly IPrototypeManager _prototypeManager = default!;
|
||||||
[Dependency] private readonly SharedSolutionContainerSystem _solutionContainerSystem = default!;
|
[Dependency] private readonly SharedSolutionContainerSystem _solutionContainerSystem = default!;
|
||||||
|
[Dependency] private readonly SharedDoAfterSystem _doAfterSystem = default!;
|
||||||
|
|
||||||
/// <summary>
|
/// <summary>
|
||||||
/// The lowest threshold to be considered for puddle sprite states as well as slipperiness of a puddle.
|
/// The lowest threshold to be considered for puddle sprite states as well as slipperiness of a puddle.
|
||||||
@@ -106,4 +109,54 @@ public abstract partial class SharedPuddleSystem : EntitySystem
|
|||||||
args.PushMarkup(Loc.GetString("puddle-component-examine-evaporating-no"));
|
args.PushMarkup(Loc.GetString("puddle-component-examine-evaporating-no"));
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
#region Spill
|
||||||
|
// These methods are in Shared to make it easier to interact with PuddleSystem in Shared code.
|
||||||
|
// Note that they always fail when run on the client, not creating a puddle and returning false.
|
||||||
|
// Adding proper prediction to this system would require spawning temporary puddle entities on the
|
||||||
|
// client and replacing or merging them with the ones spawned by the server when the client goes to
|
||||||
|
// replicate those, and I am not enough of a wizard to attempt implementing that.
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// First splashes reagent on reactive entities near the spilling entity, then spills the rest regularly to a
|
||||||
|
/// puddle. This is intended for 'destructive' spills, like when entities are destroyed or thrown.
|
||||||
|
/// </summary>
|
||||||
|
/// <remarks>
|
||||||
|
/// On the client, this will always set <paramref name="puddleUid"/> to <see cref="EntityUid.Invalid"> and return false.
|
||||||
|
/// </remarks>
|
||||||
|
public abstract bool TrySplashSpillAt(EntityUid uid,
|
||||||
|
EntityCoordinates coordinates,
|
||||||
|
Solution solution,
|
||||||
|
out EntityUid puddleUid,
|
||||||
|
bool sound = true,
|
||||||
|
EntityUid? user = null);
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// Spills solution at the specified coordinates.
|
||||||
|
/// Will add to an existing puddle if present or create a new one if not.
|
||||||
|
/// </summary>
|
||||||
|
/// <remarks>
|
||||||
|
/// On the client, this will always set <paramref name="puddleUid"/> to <see cref="EntityUid.Invalid"> and return false.
|
||||||
|
/// </remarks>
|
||||||
|
public abstract bool TrySpillAt(EntityCoordinates coordinates, Solution solution, out EntityUid puddleUid, bool sound = true);
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// <see cref="TrySpillAt(EntityCoordinates, Solution, out EntityUid, bool)"/>
|
||||||
|
/// </summary>
|
||||||
|
/// <remarks>
|
||||||
|
/// On the client, this will always set <paramref name="puddleUid"/> to <see cref="EntityUid.Invalid"> and return false.
|
||||||
|
/// </remarks>
|
||||||
|
public abstract bool TrySpillAt(EntityUid uid, Solution solution, out EntityUid puddleUid, bool sound = true,
|
||||||
|
TransformComponent? transformComponent = null);
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// <see cref="TrySpillAt(EntityCoordinates, Solution, out EntityUid, bool)"/>
|
||||||
|
/// </summary>
|
||||||
|
/// <remarks>
|
||||||
|
/// On the client, this will always set <paramref name="puddleUid"/> to <see cref="EntityUid.Invalid"> and return false.
|
||||||
|
/// </remarks>
|
||||||
|
public abstract bool TrySpillAt(TileRef tileRef, Solution solution, out EntityUid puddleUid, bool sound = true,
|
||||||
|
bool tileReact = true);
|
||||||
|
|
||||||
|
#endregion Spill
|
||||||
}
|
}
|
||||||
|
|||||||
Reference in New Issue
Block a user