Spray nozzle can suck puddles into tank directly! (#30600)
* feat: now vacuum cleaner can suck solutions from floor * refactor using AbsorbentSystem instead of separate vacuum cleaner * refactor: remove unused vacuum cleaner files * refactor: renamed ConnectedContainerComponent to SlotBasedConnectedContainerComponent (and system) * fix: fix invalid comp name * fix: no more spray nozzle messaging about water inside bottles etc. * refactor: minor refactor in SlotBasedConnectedContainerSystem and adjustments after merge * refactor: cleanups * refactor: renaming * refactor: update to use _puddleSystem.GetAbsorbentReagents * refactor: changed interactions with SlotBasedConnectedContainerSystem into events * refactor: new sound and action delay adjusted to sound (amount tweaked a bit accordingly, almost) * refactor: added networking for SlotBasedConnectedContainerComponent * fix attribution for vacuum-cleaner-fast.ogg * trying to fix multi-license for mix sound file * remove empty line * refactor: remove trailing whitespace * by ref struct, brother --------- Co-authored-by: pa.pecherskij <pa.pecherskij@interfax.ru> Co-authored-by: EmoGarbage404 <retron404@gmail.com>
This commit is contained in:
@@ -33,6 +33,7 @@ public sealed class AbsorbentTest
|
||||
id: {AbsorbentDummyId}
|
||||
components:
|
||||
- type: Absorbent
|
||||
useAbsorberSolution: true
|
||||
- type: SolutionContainerManager
|
||||
solutions:
|
||||
absorbed:
|
||||
@@ -94,7 +95,7 @@ public sealed class AbsorbentTest
|
||||
refillable = entityManager.SpawnEntity(RefillableDummyId, coordinates);
|
||||
|
||||
entityManager.TryGetComponent(absorbent, out component);
|
||||
solutionContainerSystem.TryGetSolution(absorbent, AbsorbentComponent.SolutionName, out var absorbentSoln, out var absorbentSolution);
|
||||
solutionContainerSystem.TryGetSolution(absorbent, component.SolutionName, out var absorbentSoln, out var absorbentSolution);
|
||||
solutionContainerSystem.TryGetRefillableSolution(refillable, out var refillableSoln, out var refillableSolution);
|
||||
|
||||
// Arrange
|
||||
@@ -152,7 +153,7 @@ public sealed class AbsorbentTest
|
||||
refillable = entityManager.SpawnEntity(SmallRefillableDummyId, coordinates);
|
||||
|
||||
entityManager.TryGetComponent(absorbent, out component);
|
||||
solutionContainerSystem.TryGetSolution(absorbent, AbsorbentComponent.SolutionName, out var absorbentSoln, out var absorbentSolution);
|
||||
solutionContainerSystem.TryGetSolution(absorbent, component.SolutionName, out var absorbentSoln, out var absorbentSolution);
|
||||
solutionContainerSystem.TryGetRefillableSolution(refillable, out var refillableSoln, out var refillableSolution);
|
||||
|
||||
// Arrange
|
||||
|
||||
@@ -91,7 +91,7 @@ public sealed class InjectorSystem : SharedInjectorSystem
|
||||
// Is the target a mob? If yes, use a do-after to give them time to respond.
|
||||
if (HasComp<MobStateComponent>(target) || HasComp<BloodstreamComponent>(target))
|
||||
{
|
||||
// Are use using an injector capible of targeting a mob?
|
||||
// Are use using an injector capable of targeting a mob?
|
||||
if (entity.Comp.IgnoreMobs)
|
||||
return;
|
||||
|
||||
|
||||
@@ -19,6 +19,8 @@ namespace Content.Server.Fluids.EntitySystems;
|
||||
/// <inheritdoc/>
|
||||
public sealed class AbsorbentSystem : SharedAbsorbentSystem
|
||||
{
|
||||
private static readonly EntProtoId Sparkles = "PuddleSparkle";
|
||||
|
||||
[Dependency] private readonly IPrototypeManager _prototype = default!;
|
||||
[Dependency] private readonly AudioSystem _audio = default!;
|
||||
[Dependency] private readonly PopupSystem _popups = default!;
|
||||
@@ -51,7 +53,7 @@ public sealed class AbsorbentSystem : SharedAbsorbentSystem
|
||||
|
||||
private void UpdateAbsorbent(EntityUid uid, AbsorbentComponent component)
|
||||
{
|
||||
if (!_solutionContainerSystem.TryGetSolution(uid, AbsorbentComponent.SolutionName, out _, out var solution))
|
||||
if (!_solutionContainerSystem.TryGetSolution(uid, component.SolutionName, out _, out var solution))
|
||||
return;
|
||||
|
||||
var oldProgress = component.Progress.ShallowClone();
|
||||
@@ -104,7 +106,7 @@ public sealed class AbsorbentSystem : SharedAbsorbentSystem
|
||||
|
||||
public void Mop(EntityUid user, EntityUid target, EntityUid used, AbsorbentComponent component)
|
||||
{
|
||||
if (!_solutionContainerSystem.TryGetSolution(used, AbsorbentComponent.SolutionName, out var absorberSoln))
|
||||
if (!_solutionContainerSystem.TryGetSolution(used, component.SolutionName, out var absorberSoln))
|
||||
return;
|
||||
|
||||
if (TryComp<UseDelayComponent>(used, out var useDelay)
|
||||
@@ -112,7 +114,7 @@ public sealed class AbsorbentSystem : SharedAbsorbentSystem
|
||||
return;
|
||||
|
||||
// If it's a puddle try to grab from
|
||||
if (!TryPuddleInteract(user, used, target, component, useDelay, absorberSoln.Value))
|
||||
if (!TryPuddleInteract(user, used, target, component, useDelay, absorberSoln.Value) && component.UseAbsorberSolution)
|
||||
{
|
||||
// If it's refillable try to transfer
|
||||
if (!TryRefillableInteract(user, used, target, component, useDelay, absorberSoln.Value))
|
||||
@@ -282,36 +284,53 @@ public sealed class AbsorbentSystem : SharedAbsorbentSystem
|
||||
return true;
|
||||
}
|
||||
|
||||
// Check if we have any evaporative reagents on our absorber to transfer
|
||||
var absorberSolution = absorberSoln.Comp.Solution;
|
||||
var available = absorberSolution.GetTotalPrototypeQuantity(_puddleSystem.GetAbsorbentReagents(absorberSolution));
|
||||
|
||||
// No material
|
||||
if (available == FixedPoint2.Zero)
|
||||
Solution puddleSplit;
|
||||
var isRemoved = false;
|
||||
if (absorber.UseAbsorberSolution)
|
||||
{
|
||||
_popups.PopupEntity(Loc.GetString("mopping-system-no-water", ("used", used)), user, user);
|
||||
return true;
|
||||
// Check if we have any evaporative reagents on our absorber to transfer
|
||||
var absorberSolution = absorberSoln.Comp.Solution;
|
||||
var available = absorberSolution.GetTotalPrototypeQuantity(_puddleSystem.GetAbsorbentReagents(absorberSolution));
|
||||
|
||||
// No material
|
||||
if (available == FixedPoint2.Zero)
|
||||
{
|
||||
_popups.PopupEntity(Loc.GetString("mopping-system-no-water", ("used", used)), user, user);
|
||||
return true;
|
||||
}
|
||||
|
||||
var transferMax = absorber.PickupAmount;
|
||||
var transferAmount = available > transferMax ? transferMax : available;
|
||||
|
||||
puddleSplit = puddleSolution.SplitSolutionWithout(transferAmount, _puddleSystem.GetAbsorbentReagents(puddleSolution));
|
||||
var absorberSplit = absorberSolution.SplitSolutionWithOnly(puddleSplit.Volume, _puddleSystem.GetAbsorbentReagents(absorberSolution));
|
||||
|
||||
// Do tile reactions first
|
||||
var transform = Transform(target);
|
||||
var gridUid = transform.GridUid;
|
||||
if (TryComp(gridUid, out MapGridComponent? mapGrid))
|
||||
{
|
||||
var tileRef = _mapSystem.GetTileRef(gridUid.Value, mapGrid, transform.Coordinates);
|
||||
_puddleSystem.DoTileReactions(tileRef, absorberSplit);
|
||||
}
|
||||
_solutionContainerSystem.AddSolution(puddle.Solution.Value, absorberSplit);
|
||||
}
|
||||
else
|
||||
{
|
||||
puddleSplit = puddleSolution.SplitSolutionWithout(absorber.PickupAmount, _puddleSystem.GetAbsorbentReagents(puddleSolution));
|
||||
// Despawn if we're done
|
||||
if (puddleSolution.Volume == FixedPoint2.Zero)
|
||||
{
|
||||
// Spawn a *sparkle*
|
||||
Spawn(Sparkles, GetEntityQuery<TransformComponent>().GetComponent(target).Coordinates);
|
||||
QueueDel(target);
|
||||
isRemoved = true;
|
||||
}
|
||||
}
|
||||
|
||||
var transferMax = absorber.PickupAmount;
|
||||
var transferAmount = available > transferMax ? transferMax : available;
|
||||
|
||||
var puddleSplit = puddleSolution.SplitSolutionWithout(transferAmount, _puddleSystem.GetAbsorbentReagents(puddleSolution));
|
||||
var absorberSplit = absorberSolution.SplitSolutionWithOnly(puddleSplit.Volume, _puddleSystem.GetAbsorbentReagents(absorberSolution));
|
||||
|
||||
// Do tile reactions first
|
||||
var transform = Transform(target);
|
||||
var gridUid = transform.GridUid;
|
||||
if (TryComp(gridUid, out MapGridComponent? mapGrid))
|
||||
{
|
||||
var tileRef = _mapSystem.GetTileRef(gridUid.Value, mapGrid, transform.Coordinates);
|
||||
_puddleSystem.DoTileReactions(tileRef, absorberSplit);
|
||||
}
|
||||
|
||||
_solutionContainerSystem.AddSolution(puddle.Solution.Value, absorberSplit);
|
||||
_solutionContainerSystem.AddSolution(absorberSoln, puddleSplit);
|
||||
|
||||
_audio.PlayPvs(absorber.PickupSound, target);
|
||||
_audio.PlayPvs(absorber.PickupSound, isRemoved ? used : target);
|
||||
if (useDelay != null)
|
||||
_useDelay.TryResetDelay((used, useDelay));
|
||||
|
||||
|
||||
@@ -0,0 +1,25 @@
|
||||
using Content.Shared.Containers;
|
||||
using Content.Shared.Inventory;
|
||||
using Content.Shared.Whitelist;
|
||||
using Robust.Shared.GameStates;
|
||||
|
||||
namespace Content.Shared.Chemistry.Components;
|
||||
|
||||
/// <summary>
|
||||
/// Component for marking linked container in character slot, to which entity is bound.
|
||||
/// </summary>
|
||||
[RegisterComponent, Access(typeof(SlotBasedConnectedContainerSystem)), NetworkedComponent]
|
||||
public sealed partial class SlotBasedConnectedContainerComponent : Component
|
||||
{
|
||||
/// <summary>
|
||||
/// The slot in which target container should be.
|
||||
/// </summary>
|
||||
[DataField(required: true)]
|
||||
public SlotFlags TargetSlot;
|
||||
|
||||
/// <summary>
|
||||
/// A whitelist for determining whether container is valid or not .
|
||||
/// </summary>
|
||||
[DataField]
|
||||
public EntityWhitelist? ContainerWhitelist;
|
||||
}
|
||||
@@ -14,6 +14,7 @@ using System.Linq;
|
||||
using System.Numerics;
|
||||
using System.Runtime.CompilerServices;
|
||||
using System.Text;
|
||||
using Content.Shared.Containers;
|
||||
using Content.Shared.Hands.Components;
|
||||
using Content.Shared.Hands.EntitySystems;
|
||||
using Robust.Shared.Map;
|
||||
@@ -162,6 +163,12 @@ public abstract partial class SharedSolutionContainerSystem : EntitySystem
|
||||
[NotNullWhen(true)] out Entity<SolutionComponent>? entity,
|
||||
bool errorOnMissing = false)
|
||||
{
|
||||
// use connected container instead of entity from arguments, if it exists.
|
||||
var ev = new GetConnectedContainerEvent();
|
||||
RaiseLocalEvent(container, ref ev);
|
||||
if (ev.ContainerEntity.HasValue)
|
||||
container = ev.ContainerEntity.Value;
|
||||
|
||||
EntityUid uid;
|
||||
if (name is null)
|
||||
uid = container;
|
||||
|
||||
@@ -0,0 +1,86 @@
|
||||
using System.Diagnostics.CodeAnalysis;
|
||||
using Content.Shared.Chemistry.Components;
|
||||
using Content.Shared.Inventory;
|
||||
using Content.Shared.Whitelist;
|
||||
using Robust.Shared.Containers;
|
||||
|
||||
namespace Content.Shared.Containers;
|
||||
|
||||
/// <summary>
|
||||
/// System for getting container that is linked to subject entity. Container is supposed to be present in certain character slot.
|
||||
/// Can be used for linking ammo feeder, solution source for spray nozzle, etc.
|
||||
/// </summary>
|
||||
public sealed class SlotBasedConnectedContainerSystem : EntitySystem
|
||||
{
|
||||
[Dependency] private readonly SharedContainerSystem _containers = default!;
|
||||
[Dependency] private readonly EntityWhitelistSystem _whitelistSystem = default!;
|
||||
[Dependency] private readonly InventorySystem _inventory = default!;
|
||||
|
||||
/// <inheritdoc />
|
||||
public override void Initialize()
|
||||
{
|
||||
SubscribeLocalEvent<SlotBasedConnectedContainerComponent, GetConnectedContainerEvent>(OnGettingConnectedContainer);
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Try get connected container entity in character slots for <see cref="uid"/>.
|
||||
/// </summary>
|
||||
/// <param name="uid">
|
||||
/// Entity for which connected container is required. If <see cref="SlotBasedConnectedContainerComponent"/>
|
||||
/// is used - tries to find container in slot, returns false and null <see cref="slotEntity"/> otherwise.
|
||||
/// </param>
|
||||
/// <param name="slotEntity">Found connected container entity or null.</param>
|
||||
/// <returns>True if connected container was found, false otherwise.</returns>
|
||||
public bool TryGetConnectedContainer(EntityUid uid, [NotNullWhen(true)] out EntityUid? slotEntity)
|
||||
{
|
||||
if (!TryComp<SlotBasedConnectedContainerComponent>(uid, out var component))
|
||||
{
|
||||
slotEntity = null;
|
||||
return false;
|
||||
}
|
||||
|
||||
return TryGetConnectedContainer(uid, component.TargetSlot, component.ContainerWhitelist, out slotEntity);
|
||||
}
|
||||
|
||||
private void OnGettingConnectedContainer(Entity<SlotBasedConnectedContainerComponent> ent, ref GetConnectedContainerEvent args)
|
||||
{
|
||||
if (TryGetConnectedContainer(ent, ent.Comp.TargetSlot, ent.Comp.ContainerWhitelist, out var val))
|
||||
args.ContainerEntity = val;
|
||||
}
|
||||
|
||||
private bool TryGetConnectedContainer(EntityUid uid, SlotFlags slotFlag, EntityWhitelist? providerWhitelist, [NotNullWhen(true)] out EntityUid? slotEntity)
|
||||
{
|
||||
slotEntity = null;
|
||||
|
||||
if (!_containers.TryGetContainingContainer((uid, null, null), out var container))
|
||||
return false;
|
||||
|
||||
var user = container.Owner;
|
||||
if (!_inventory.TryGetContainerSlotEnumerator(user, out var enumerator, slotFlag))
|
||||
return false;
|
||||
|
||||
while (enumerator.NextItem(out var item))
|
||||
{
|
||||
if (_whitelistSystem.IsWhitelistFailOrNull(providerWhitelist, item))
|
||||
continue;
|
||||
|
||||
slotEntity = item;
|
||||
return true;
|
||||
}
|
||||
|
||||
return false;
|
||||
}
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Event for an attempt of getting container, connected to entity on which event was raised.
|
||||
/// Fills <see cref="ContainerEntity"/> if connected container exists.
|
||||
/// </summary>
|
||||
[ByRefEvent]
|
||||
public struct GetConnectedContainerEvent
|
||||
{
|
||||
/// <summary>
|
||||
/// Container entity, if it exists, or null.
|
||||
/// </summary>
|
||||
public EntityUid? ContainerEntity;
|
||||
}
|
||||
@@ -11,23 +11,28 @@ namespace Content.Shared.Fluids;
|
||||
[RegisterComponent, NetworkedComponent]
|
||||
public sealed partial class AbsorbentComponent : Component
|
||||
{
|
||||
public const string SolutionName = "absorbed";
|
||||
|
||||
public Dictionary<Color, float> Progress = new();
|
||||
|
||||
/// <summary>
|
||||
/// Name for solution container, that should be used for absorbed solution storage and as source of absorber solution.
|
||||
/// Default is 'absorbed'.
|
||||
/// </summary>
|
||||
[DataField]
|
||||
public string SolutionName = "absorbed";
|
||||
|
||||
/// <summary>
|
||||
/// How much solution we can transfer in one interaction.
|
||||
/// </summary>
|
||||
[DataField("pickupAmount")]
|
||||
[DataField]
|
||||
public FixedPoint2 PickupAmount = FixedPoint2.New(100);
|
||||
|
||||
[DataField("pickupSound")]
|
||||
[DataField]
|
||||
public SoundSpecifier PickupSound = new SoundPathSpecifier("/Audio/Effects/Fluids/watersplash.ogg")
|
||||
{
|
||||
Params = AudioParams.Default.WithVariation(SharedContentAudioSystem.DefaultVariation),
|
||||
};
|
||||
|
||||
[DataField("transferSound")] public SoundSpecifier TransferSound =
|
||||
[DataField] public SoundSpecifier TransferSound =
|
||||
new SoundPathSpecifier("/Audio/Effects/Fluids/slosh.ogg")
|
||||
{
|
||||
Params = AudioParams.Default.WithVariation(SharedContentAudioSystem.DefaultVariation).WithVolume(-3f),
|
||||
@@ -38,4 +43,11 @@ public sealed partial class AbsorbentComponent : Component
|
||||
{
|
||||
Params = AudioParams.Default.WithVariation(SharedContentAudioSystem.DefaultVariation).WithVolume(-3f),
|
||||
};
|
||||
|
||||
/// <summary>
|
||||
/// Marker that absorbent component owner should try to use 'absorber solution' to replace solution to be absorbed.
|
||||
/// Target solution will be simply consumed into container if set to false.
|
||||
/// </summary>
|
||||
[DataField]
|
||||
public bool UseAbsorberSolution = true;
|
||||
}
|
||||
|
||||
@@ -3,4 +3,4 @@ using Robust.Shared.GameStates;
|
||||
namespace Content.Shared.Weapons.Ranged.Components;
|
||||
|
||||
[NetworkedComponent]
|
||||
public abstract partial class AmmoProviderComponent : Component {}
|
||||
public abstract partial class AmmoProviderComponent : Component;
|
||||
|
||||
@@ -1,6 +1,4 @@
|
||||
using Content.Shared.Inventory;
|
||||
using Content.Shared.Weapons.Ranged.Systems;
|
||||
using Content.Shared.Whitelist;
|
||||
using Robust.Shared.GameStates;
|
||||
|
||||
namespace Content.Shared.Weapons.Ranged.Components;
|
||||
@@ -10,17 +8,4 @@ namespace Content.Shared.Weapons.Ranged.Components;
|
||||
/// to an entity in the user's clothing slot.
|
||||
/// </summary>
|
||||
[RegisterComponent, NetworkedComponent, Access(typeof(SharedGunSystem))]
|
||||
public sealed partial class ClothingSlotAmmoProviderComponent : AmmoProviderComponent
|
||||
{
|
||||
/// <summary>
|
||||
/// The slot that the ammo provider should be located in.
|
||||
/// </summary>
|
||||
[DataField("targetSlot", required: true)]
|
||||
public SlotFlags TargetSlot;
|
||||
|
||||
/// <summary>
|
||||
/// A whitelist for determining whether or not an ammo provider is valid.
|
||||
/// </summary>
|
||||
[DataField("providerWhitelist")]
|
||||
public EntityWhitelist? ProviderWhitelist;
|
||||
}
|
||||
public sealed partial class ClothingSlotAmmoProviderComponent : AmmoProviderComponent;
|
||||
|
||||
@@ -1,5 +1,4 @@
|
||||
using System.Diagnostics.CodeAnalysis;
|
||||
using Content.Shared.Inventory;
|
||||
using Content.Shared.Containers;
|
||||
using Content.Shared.Weapons.Ranged.Components;
|
||||
using Content.Shared.Weapons.Ranged.Events;
|
||||
|
||||
@@ -7,8 +6,6 @@ namespace Content.Shared.Weapons.Ranged.Systems;
|
||||
|
||||
public partial class SharedGunSystem
|
||||
{
|
||||
[Dependency] private readonly InventorySystem _inventory = default!;
|
||||
|
||||
private void InitializeClothing()
|
||||
{
|
||||
SubscribeLocalEvent<ClothingSlotAmmoProviderComponent, TakeAmmoEvent>(OnClothingTakeAmmo);
|
||||
@@ -17,38 +14,21 @@ public partial class SharedGunSystem
|
||||
|
||||
private void OnClothingTakeAmmo(EntityUid uid, ClothingSlotAmmoProviderComponent component, TakeAmmoEvent args)
|
||||
{
|
||||
if (!TryGetClothingSlotEntity(uid, component, out var entity))
|
||||
var getConnectedContainerEvent = new GetConnectedContainerEvent();
|
||||
RaiseLocalEvent(uid, ref getConnectedContainerEvent);
|
||||
if(!getConnectedContainerEvent.ContainerEntity.HasValue)
|
||||
return;
|
||||
RaiseLocalEvent(entity.Value, args);
|
||||
|
||||
RaiseLocalEvent(getConnectedContainerEvent.ContainerEntity.Value, args);
|
||||
}
|
||||
|
||||
private void OnClothingAmmoCount(EntityUid uid, ClothingSlotAmmoProviderComponent component, ref GetAmmoCountEvent args)
|
||||
{
|
||||
if (!TryGetClothingSlotEntity(uid, component, out var entity))
|
||||
var getConnectedContainerEvent = new GetConnectedContainerEvent();
|
||||
RaiseLocalEvent(uid, ref getConnectedContainerEvent);
|
||||
if (!getConnectedContainerEvent.ContainerEntity.HasValue)
|
||||
return;
|
||||
RaiseLocalEvent(entity.Value, ref args);
|
||||
}
|
||||
|
||||
private bool TryGetClothingSlotEntity(EntityUid uid, ClothingSlotAmmoProviderComponent component, [NotNullWhen(true)] out EntityUid? slotEntity)
|
||||
{
|
||||
slotEntity = null;
|
||||
|
||||
if (!Containers.TryGetContainingContainer((uid, null, null), out var container))
|
||||
return false;
|
||||
var user = container.Owner;
|
||||
|
||||
if (!_inventory.TryGetContainerSlotEnumerator(user, out var enumerator, component.TargetSlot))
|
||||
return false;
|
||||
|
||||
while (enumerator.NextItem(out var item))
|
||||
{
|
||||
if (_whitelistSystem.IsWhitelistFailOrNull(component.ProviderWhitelist, item))
|
||||
continue;
|
||||
|
||||
slotEntity = item;
|
||||
return true;
|
||||
}
|
||||
|
||||
return false;
|
||||
RaiseLocalEvent(getConnectedContainerEvent.ContainerEntity.Value, ref args);
|
||||
}
|
||||
}
|
||||
|
||||
@@ -22,3 +22,13 @@
|
||||
license: "CC-BY-SA-3.0"
|
||||
copyright: "Created by the_toilet_guy"
|
||||
source: "https://freesound.org/people/the_toilet_guy/sounds/98770/"
|
||||
|
||||
- files: ["vacuum-cleaner-fast.ogg"]
|
||||
license: "CC0-1.0"
|
||||
copyright: "Created by kyles"
|
||||
source: "https://freesound.org/people/kyles/sounds/637927/"
|
||||
|
||||
- files: ["vacuum-cleaner-fast.ogg"]
|
||||
license: "CC0-1.0"
|
||||
copyright: "Created by BrendanSound12 mixed by Fildrance"
|
||||
source: "https://freesound.org/people/BrendanSound12/sounds/445165/"
|
||||
|
||||
BIN
Resources/Audio/Effects/Fluids/vacuum-cleaner-fast.ogg
Normal file
BIN
Resources/Audio/Effects/Fluids/vacuum-cleaner-fast.ogg
Normal file
Binary file not shown.
@@ -34,6 +34,7 @@
|
||||
size: Large
|
||||
sprite: Objects/Specific/Janitorial/mop.rsi
|
||||
- type: Absorbent
|
||||
useAbsorberSolution: true
|
||||
- type: SolutionContainerManager
|
||||
solutions:
|
||||
absorbed:
|
||||
@@ -89,6 +90,7 @@
|
||||
sprite: Objects/Specific/Janitorial/advmop.rsi
|
||||
- type: Absorbent
|
||||
pickupAmount: 100
|
||||
useAbsorberSolution: true
|
||||
- type: UseDelay
|
||||
delay: 1.0
|
||||
- type: SolutionRegeneration
|
||||
@@ -322,6 +324,7 @@
|
||||
sprite: Objects/Specific/Janitorial/rag.rsi
|
||||
- type: Absorbent
|
||||
pickupAmount: 15
|
||||
useAbsorberSolution: true
|
||||
- type: Construction
|
||||
graph: Rag
|
||||
node: rag
|
||||
|
||||
@@ -21,9 +21,18 @@
|
||||
- FullAuto
|
||||
soundGunshot:
|
||||
path: /Audio/Weapons/Guns/Gunshots/water_spray.ogg
|
||||
- type: Absorbent
|
||||
pickupAmount: 35
|
||||
solutionName: tank
|
||||
useAbsorberSolution: false
|
||||
pickupSound:
|
||||
path: /Audio/Effects/Fluids/vacuum-cleaner-fast.ogg
|
||||
- type: Appearance
|
||||
- type: ClothingSlotAmmoProvider
|
||||
- type: SlotBasedConnectedContainer
|
||||
targetSlot: BACK
|
||||
providerWhitelist:
|
||||
containerWhitelist:
|
||||
tags:
|
||||
- NozzleBackTank
|
||||
- type: UseDelay
|
||||
delay: 1.0
|
||||
|
||||
Reference in New Issue
Block a user