Revert 'Revert 'Solution Entities'' (#23168)
This commit is contained in:
@@ -1,3 +1,4 @@
|
||||
using Content.Server.Chemistry.Containers.EntitySystems;
|
||||
using Content.Server.Popups;
|
||||
using Content.Shared.Chemistry.Components;
|
||||
using Content.Shared.Chemistry.EntitySystems;
|
||||
@@ -24,7 +25,7 @@ public sealed class AbsorbentSystem : SharedAbsorbentSystem
|
||||
[Dependency] private readonly PuddleSystem _puddleSystem = default!;
|
||||
[Dependency] private readonly SharedMeleeWeaponSystem _melee = default!;
|
||||
[Dependency] private readonly SharedTransformSystem _transform = default!;
|
||||
[Dependency] private readonly SolutionContainerSystem _solutionSystem = default!;
|
||||
[Dependency] private readonly SolutionContainerSystem _solutionContainerSystem = default!;
|
||||
[Dependency] private readonly UseDelaySystem _useDelay = default!;
|
||||
|
||||
public override void Initialize()
|
||||
@@ -33,7 +34,7 @@ public sealed class AbsorbentSystem : SharedAbsorbentSystem
|
||||
SubscribeLocalEvent<AbsorbentComponent, ComponentInit>(OnAbsorbentInit);
|
||||
SubscribeLocalEvent<AbsorbentComponent, AfterInteractEvent>(OnAfterInteract);
|
||||
SubscribeLocalEvent<AbsorbentComponent, InteractNoHandEvent>(OnInteractNoHand);
|
||||
SubscribeLocalEvent<AbsorbentComponent, SolutionChangedEvent>(OnAbsorbentSolutionChange);
|
||||
SubscribeLocalEvent<AbsorbentComponent, SolutionContainerChangedEvent>(OnAbsorbentSolutionChange);
|
||||
}
|
||||
|
||||
private void OnAbsorbentInit(EntityUid uid, AbsorbentComponent component, ComponentInit args)
|
||||
@@ -42,14 +43,14 @@ public sealed class AbsorbentSystem : SharedAbsorbentSystem
|
||||
UpdateAbsorbent(uid, component);
|
||||
}
|
||||
|
||||
private void OnAbsorbentSolutionChange(EntityUid uid, AbsorbentComponent component, SolutionChangedEvent args)
|
||||
private void OnAbsorbentSolutionChange(EntityUid uid, AbsorbentComponent component, ref SolutionContainerChangedEvent args)
|
||||
{
|
||||
UpdateAbsorbent(uid, component);
|
||||
}
|
||||
|
||||
private void UpdateAbsorbent(EntityUid uid, AbsorbentComponent component)
|
||||
{
|
||||
if (!_solutionSystem.TryGetSolution(uid, AbsorbentComponent.SolutionName, out var solution))
|
||||
if (!_solutionContainerSystem.TryGetSolution(uid, AbsorbentComponent.SolutionName, out _, out var solution))
|
||||
return;
|
||||
|
||||
var oldProgress = component.Progress.ShallowClone();
|
||||
@@ -102,17 +103,17 @@ public sealed class AbsorbentSystem : SharedAbsorbentSystem
|
||||
|
||||
public void Mop(EntityUid user, EntityUid target, EntityUid used, AbsorbentComponent component)
|
||||
{
|
||||
if (!_solutionSystem.TryGetSolution(used, AbsorbentComponent.SolutionName, out var absorbentSolution))
|
||||
if (!_solutionContainerSystem.TryGetSolution(used, AbsorbentComponent.SolutionName, out var absorberSoln))
|
||||
return;
|
||||
|
||||
if (_useDelay.ActiveDelay(used))
|
||||
return;
|
||||
|
||||
// If it's a puddle try to grab from
|
||||
if (!TryPuddleInteract(user, used, target, component, absorbentSolution))
|
||||
if (!TryPuddleInteract(user, used, target, component, absorberSoln.Value))
|
||||
{
|
||||
// If it's refillable try to transfer
|
||||
if (!TryRefillableInteract(user, used, target, component, absorbentSolution))
|
||||
if (!TryRefillableInteract(user, used, target, component, absorberSoln.Value))
|
||||
return;
|
||||
}
|
||||
}
|
||||
@@ -120,24 +121,24 @@ public sealed class AbsorbentSystem : SharedAbsorbentSystem
|
||||
/// <summary>
|
||||
/// Logic for an absorbing entity interacting with a refillable.
|
||||
/// </summary>
|
||||
private bool TryRefillableInteract(EntityUid user, EntityUid used, EntityUid target, AbsorbentComponent component, Solution absorbentSolution)
|
||||
private bool TryRefillableInteract(EntityUid user, EntityUid used, EntityUid target, AbsorbentComponent component, Entity<SolutionComponent> absorbentSoln)
|
||||
{
|
||||
if (!TryComp(target, out RefillableSolutionComponent? refillable))
|
||||
return false;
|
||||
|
||||
if (!_solutionSystem.TryGetRefillableSolution(target, out var refillableSolution, refillable: refillable))
|
||||
if (!_solutionContainerSystem.TryGetRefillableSolution((target, refillable, null), out var refillableSoln, out var refillableSolution))
|
||||
return false;
|
||||
|
||||
if (refillableSolution.Volume <= 0)
|
||||
{
|
||||
// Target empty - only transfer absorbent contents into refillable
|
||||
if (!TryTransferFromAbsorbentToRefillable(user, used, target, component, absorbentSolution, refillableSolution))
|
||||
if (!TryTransferFromAbsorbentToRefillable(user, used, target, component, absorbentSoln, refillableSoln.Value))
|
||||
return false;
|
||||
}
|
||||
else
|
||||
{
|
||||
// Target non-empty - do a two-way transfer
|
||||
if (!TryTwoWayAbsorbentRefillableTransfer(user, used, target, component, absorbentSolution, refillableSolution))
|
||||
if (!TryTwoWayAbsorbentRefillableTransfer(user, used, target, component, absorbentSoln, refillableSoln.Value))
|
||||
return false;
|
||||
}
|
||||
|
||||
@@ -154,15 +155,17 @@ public sealed class AbsorbentSystem : SharedAbsorbentSystem
|
||||
EntityUid used,
|
||||
EntityUid target,
|
||||
AbsorbentComponent component,
|
||||
Solution absorbentSolution,
|
||||
Solution refillableSolution)
|
||||
Entity<SolutionComponent> absorbentSoln,
|
||||
Entity<SolutionComponent> refillableSoln)
|
||||
{
|
||||
var absorbentSolution = absorbentSoln.Comp.Solution;
|
||||
if (absorbentSolution.Volume <= 0)
|
||||
{
|
||||
_popups.PopupEntity(Loc.GetString("mopping-system-target-container-empty", ("target", target)), user, user);
|
||||
return false;
|
||||
}
|
||||
|
||||
var refillableSolution = refillableSoln.Comp.Solution;
|
||||
var transferAmount = component.PickupAmount < refillableSolution.AvailableVolume ?
|
||||
component.PickupAmount :
|
||||
refillableSolution.AvailableVolume;
|
||||
@@ -174,17 +177,15 @@ public sealed class AbsorbentSystem : SharedAbsorbentSystem
|
||||
}
|
||||
|
||||
// Prioritize transferring non-evaporatives if absorbent has any
|
||||
var contaminants = absorbentSolution.SplitSolutionWithout(transferAmount, PuddleSystem.EvaporationReagents);
|
||||
var contaminants = _solutionContainerSystem.SplitSolutionWithout(absorbentSoln, transferAmount, PuddleSystem.EvaporationReagents);
|
||||
if (contaminants.Volume > 0)
|
||||
{
|
||||
_solutionSystem.UpdateChemicals(used, absorbentSolution, true);
|
||||
_solutionSystem.TryAddSolution(target, refillableSolution, contaminants);
|
||||
_solutionContainerSystem.TryAddSolution(refillableSoln, contaminants);
|
||||
}
|
||||
else
|
||||
{
|
||||
var evaporatives = absorbentSolution.SplitSolution(transferAmount);
|
||||
_solutionSystem.UpdateChemicals(used, absorbentSolution, true);
|
||||
_solutionSystem.TryAddSolution(target, refillableSolution, evaporatives);
|
||||
var evaporatives = _solutionContainerSystem.SplitSolution(absorbentSoln, transferAmount);
|
||||
_solutionContainerSystem.TryAddSolution(refillableSoln, evaporatives);
|
||||
}
|
||||
|
||||
return true;
|
||||
@@ -198,12 +199,12 @@ public sealed class AbsorbentSystem : SharedAbsorbentSystem
|
||||
EntityUid used,
|
||||
EntityUid target,
|
||||
AbsorbentComponent component,
|
||||
Solution absorbentSolution,
|
||||
Solution refillableSolution)
|
||||
Entity<SolutionComponent> absorbentSoln,
|
||||
Entity<SolutionComponent> refillableSoln)
|
||||
{
|
||||
var contaminantsFromAbsorbent = absorbentSolution.SplitSolutionWithout(component.PickupAmount, PuddleSystem.EvaporationReagents);
|
||||
_solutionSystem.UpdateChemicals(used, absorbentSolution, true);
|
||||
var contaminantsFromAbsorbent = _solutionContainerSystem.SplitSolutionWithout(absorbentSoln, component.PickupAmount, PuddleSystem.EvaporationReagents);
|
||||
|
||||
var absorbentSolution = absorbentSoln.Comp.Solution;
|
||||
if (contaminantsFromAbsorbent.Volume == FixedPoint2.Zero && absorbentSolution.AvailableVolume == FixedPoint2.Zero)
|
||||
{
|
||||
// Nothing to transfer to refillable and no room to absorb anything extra
|
||||
@@ -217,8 +218,9 @@ public sealed class AbsorbentSystem : SharedAbsorbentSystem
|
||||
component.PickupAmount :
|
||||
absorbentSolution.AvailableVolume;
|
||||
|
||||
var refillableSolution = refillableSoln.Comp.Solution;
|
||||
var waterFromRefillable = refillableSolution.SplitSolutionWithOnly(waterPulled, PuddleSystem.EvaporationReagents);
|
||||
_solutionSystem.UpdateChemicals(target, refillableSolution);
|
||||
_solutionContainerSystem.UpdateChemicals(refillableSoln);
|
||||
|
||||
if (waterFromRefillable.Volume == FixedPoint2.Zero && contaminantsFromAbsorbent.Volume == FixedPoint2.Zero)
|
||||
{
|
||||
@@ -234,7 +236,7 @@ public sealed class AbsorbentSystem : SharedAbsorbentSystem
|
||||
if (waterFromRefillable.Volume > FixedPoint2.Zero)
|
||||
{
|
||||
// transfer water to absorbent
|
||||
_solutionSystem.TryAddSolution(used, absorbentSolution, waterFromRefillable);
|
||||
_solutionContainerSystem.TryAddSolution(absorbentSoln, waterFromRefillable);
|
||||
anyTransferOccurred = true;
|
||||
}
|
||||
|
||||
@@ -248,12 +250,12 @@ public sealed class AbsorbentSystem : SharedAbsorbentSystem
|
||||
{
|
||||
// transfer as much contaminants to refillable as will fit
|
||||
var contaminantsForRefillable = contaminantsFromAbsorbent.SplitSolution(refillableSolution.AvailableVolume);
|
||||
_solutionSystem.TryAddSolution(target, refillableSolution, contaminantsForRefillable);
|
||||
_solutionContainerSystem.TryAddSolution(refillableSoln, contaminantsForRefillable);
|
||||
anyTransferOccurred = true;
|
||||
}
|
||||
|
||||
// absorb everything that did not fit in the refillable back by the absorbent
|
||||
_solutionSystem.TryAddSolution(used, absorbentSolution, contaminantsFromAbsorbent);
|
||||
_solutionContainerSystem.TryAddSolution(absorbentSoln, contaminantsFromAbsorbent);
|
||||
}
|
||||
|
||||
return anyTransferOccurred;
|
||||
@@ -262,23 +264,24 @@ public sealed class AbsorbentSystem : SharedAbsorbentSystem
|
||||
/// <summary>
|
||||
/// Logic for an absorbing entity interacting with a puddle.
|
||||
/// </summary>
|
||||
private bool TryPuddleInteract(EntityUid user, EntityUid used, EntityUid target, AbsorbentComponent absorber, Solution absorberSoln)
|
||||
private bool TryPuddleInteract(EntityUid user, EntityUid used, EntityUid target, AbsorbentComponent absorber, Entity<SolutionComponent> absorberSoln)
|
||||
{
|
||||
if (!TryComp(target, out PuddleComponent? puddle))
|
||||
return false;
|
||||
|
||||
if (!_solutionSystem.TryGetSolution(target, puddle.SolutionName, out var puddleSoln) || puddleSoln.Volume <= 0)
|
||||
if (!_solutionContainerSystem.ResolveSolution(target, puddle.SolutionName, ref puddle.Solution, out var puddleSolution) || puddleSolution.Volume <= 0)
|
||||
return false;
|
||||
|
||||
// Check if the puddle has any non-evaporative reagents
|
||||
if (_puddleSystem.CanFullyEvaporate(puddleSoln))
|
||||
if (_puddleSystem.CanFullyEvaporate(puddleSolution))
|
||||
{
|
||||
_popups.PopupEntity(Loc.GetString("mopping-system-puddle-evaporate", ("target", target)), user, user);
|
||||
return true;
|
||||
}
|
||||
|
||||
// Check if we have any evaporative reagents on our absorber to transfer
|
||||
var available = absorberSoln.GetTotalPrototypeQuantity(PuddleSystem.EvaporationReagents);
|
||||
var absorberSolution = absorberSoln.Comp.Solution;
|
||||
var available = absorberSolution.GetTotalPrototypeQuantity(PuddleSystem.EvaporationReagents);
|
||||
|
||||
// No material
|
||||
if (available == FixedPoint2.Zero)
|
||||
@@ -290,8 +293,8 @@ public sealed class AbsorbentSystem : SharedAbsorbentSystem
|
||||
var transferMax = absorber.PickupAmount;
|
||||
var transferAmount = available > transferMax ? transferMax : available;
|
||||
|
||||
var puddleSplit = puddleSoln.SplitSolutionWithout(transferAmount, PuddleSystem.EvaporationReagents);
|
||||
var absorberSplit = absorberSoln.SplitSolutionWithOnly(puddleSplit.Volume, PuddleSystem.EvaporationReagents);
|
||||
var puddleSplit = puddleSolution.SplitSolutionWithout(transferAmount, PuddleSystem.EvaporationReagents);
|
||||
var absorberSplit = absorberSolution.SplitSolutionWithOnly(puddleSplit.Volume, PuddleSystem.EvaporationReagents);
|
||||
|
||||
// Do tile reactions first
|
||||
var coordinates = Transform(target).Coordinates;
|
||||
@@ -300,11 +303,9 @@ public sealed class AbsorbentSystem : SharedAbsorbentSystem
|
||||
_puddleSystem.DoTileReactions(mapGrid.GetTileRef(coordinates), absorberSplit);
|
||||
}
|
||||
|
||||
puddleSoln.AddSolution(absorberSplit, _prototype);
|
||||
absorberSoln.AddSolution(puddleSplit, _prototype);
|
||||
_solutionContainerSystem.AddSolution(puddle.Solution.Value, absorberSplit);
|
||||
_solutionContainerSystem.AddSolution(absorberSoln, puddleSplit);
|
||||
|
||||
_solutionSystem.UpdateChemicals(used, absorberSoln);
|
||||
_solutionSystem.UpdateChemicals(target, puddleSoln);
|
||||
_audio.PlayPvs(absorber.PickupSound, target);
|
||||
_useDelay.BeginDelay(used);
|
||||
|
||||
|
||||
@@ -1,9 +1,9 @@
|
||||
using Content.Server.Chemistry.Containers.EntitySystems;
|
||||
using Content.Server.DoAfter;
|
||||
using Content.Server.Fluids.Components;
|
||||
using Content.Server.Popups;
|
||||
using Content.Shared.Audio;
|
||||
using Content.Shared.Chemistry.Components.SolutionManager;
|
||||
using Content.Shared.Chemistry.EntitySystems;
|
||||
using Content.Shared.Database;
|
||||
using Content.Shared.DoAfter;
|
||||
using Content.Shared.Examine;
|
||||
@@ -13,10 +13,9 @@ using Content.Shared.Fluids.Components;
|
||||
using Content.Shared.Interaction;
|
||||
using Content.Shared.Tag;
|
||||
using Content.Shared.Verbs;
|
||||
using Content.Shared.Fluids.Components;
|
||||
using Robust.Shared.Audio;
|
||||
using Robust.Shared.Audio.Systems;
|
||||
using Robust.Shared.Collections;
|
||||
using Robust.Shared.Prototypes;
|
||||
using Robust.Shared.Random;
|
||||
using Robust.Shared.Utility;
|
||||
|
||||
@@ -25,7 +24,7 @@ namespace Content.Server.Fluids.EntitySystems;
|
||||
public sealed class DrainSystem : SharedDrainSystem
|
||||
{
|
||||
[Dependency] private readonly EntityLookupSystem _lookup = default!;
|
||||
[Dependency] private readonly SolutionContainerSystem _solutionSystem = default!;
|
||||
[Dependency] private readonly SolutionContainerSystem _solutionContainerSystem = default!;
|
||||
[Dependency] private readonly SharedAmbientSoundSystem _ambientSoundSystem = default!;
|
||||
[Dependency] private readonly SharedAudioSystem _audioSystem = default!;
|
||||
[Dependency] private readonly PopupSystem _popupSystem = default!;
|
||||
@@ -33,6 +32,7 @@ public sealed class DrainSystem : SharedDrainSystem
|
||||
[Dependency] private readonly DoAfterSystem _doAfterSystem = default!;
|
||||
[Dependency] private readonly PuddleSystem _puddleSystem = default!;
|
||||
[Dependency] private readonly IRobustRandom _random = default!;
|
||||
[Dependency] private readonly IPrototypeManager _prototypeManager = default!;
|
||||
|
||||
public override void Initialize()
|
||||
{
|
||||
@@ -43,7 +43,7 @@ public sealed class DrainSystem : SharedDrainSystem
|
||||
SubscribeLocalEvent<DrainComponent, DrainDoAfterEvent>(OnDoAfter);
|
||||
}
|
||||
|
||||
private void AddEmptyVerb(EntityUid uid, DrainComponent component, GetVerbsEvent<Verb> args)
|
||||
private void AddEmptyVerb(Entity<DrainComponent> entity, ref GetVerbsEvent<Verb> args)
|
||||
{
|
||||
if (!args.CanAccess || !args.CanInteract || args.Using == null)
|
||||
return;
|
||||
@@ -52,12 +52,14 @@ public sealed class DrainSystem : SharedDrainSystem
|
||||
!TryComp(args.Target, out DrainComponent? drain))
|
||||
return;
|
||||
|
||||
var used = args.Using.Value;
|
||||
var target = args.Target;
|
||||
Verb verb = new()
|
||||
{
|
||||
Text = Loc.GetString("drain-component-empty-verb-inhand", ("object", Name(args.Using.Value))),
|
||||
Text = Loc.GetString("drain-component-empty-verb-inhand", ("object", Name(used))),
|
||||
Act = () =>
|
||||
{
|
||||
Empty(args.Using.Value, spillable, args.Target, drain);
|
||||
Empty(used, spillable, target, drain);
|
||||
},
|
||||
Impact = LogImpact.Low,
|
||||
Icon = new SpriteSpecifier.Texture(new ResPath("/Textures/Interface/VerbIcons/eject.svg.192dpi.png"))
|
||||
@@ -69,8 +71,7 @@ public sealed class DrainSystem : SharedDrainSystem
|
||||
private void Empty(EntityUid container, SpillableComponent spillable, EntityUid target, DrainComponent drain)
|
||||
{
|
||||
// Find the solution in the container that is emptied
|
||||
if (!_solutionSystem.TryGetDrainableSolution(container, out var containerSolution) ||
|
||||
containerSolution.Volume == FixedPoint2.Zero)
|
||||
if (!_solutionContainerSystem.TryGetDrainableSolution(container, out var containerSoln, out var containerSolution) || containerSolution.Volume == FixedPoint2.Zero)
|
||||
{
|
||||
_popupSystem.PopupEntity(
|
||||
Loc.GetString("drain-component-empty-verb-using-is-empty-message", ("object", container)),
|
||||
@@ -79,17 +80,17 @@ public sealed class DrainSystem : SharedDrainSystem
|
||||
}
|
||||
|
||||
// try to find the drain's solution
|
||||
if (!_solutionSystem.TryGetSolution(target, DrainComponent.SolutionName, out var drainSolution))
|
||||
if (!_solutionContainerSystem.ResolveSolution(target, DrainComponent.SolutionName, ref drain.Solution, out var drainSolution))
|
||||
{
|
||||
return;
|
||||
}
|
||||
|
||||
// Try to transfer as much solution as possible to the drain
|
||||
|
||||
var transferSolution = _solutionSystem.SplitSolution(container, containerSolution,
|
||||
var transferSolution = _solutionContainerSystem.SplitSolution(containerSoln.Value,
|
||||
FixedPoint2.Min(containerSolution.Volume, drainSolution.AvailableVolume));
|
||||
|
||||
_solutionSystem.TryAddSolution(target, drainSolution, transferSolution);
|
||||
_solutionContainerSystem.TryAddSolution(drain.Solution.Value, transferSolution);
|
||||
|
||||
_audioSystem.PlayPvs(drain.ManualDrainSound, target);
|
||||
_ambientSoundSystem.SetAmbience(target, true);
|
||||
@@ -111,7 +112,7 @@ public sealed class DrainSystem : SharedDrainSystem
|
||||
var managerQuery = GetEntityQuery<SolutionContainerManagerComponent>();
|
||||
var xformQuery = GetEntityQuery<TransformComponent>();
|
||||
var puddleQuery = GetEntityQuery<PuddleComponent>();
|
||||
var puddles = new ValueList<(EntityUid Entity, string Solution)>();
|
||||
var puddles = new ValueList<(Entity<PuddleComponent> Entity, string Solution)>();
|
||||
|
||||
var query = EntityQueryEnumerator<DrainComponent>();
|
||||
while (query.MoveNext(out var uid, out var drain))
|
||||
@@ -134,9 +135,7 @@ public sealed class DrainSystem : SharedDrainSystem
|
||||
continue;
|
||||
|
||||
// Best to do this one every second rather than once every tick...
|
||||
_solutionSystem.TryGetSolution(uid, DrainComponent.SolutionName, out var drainSolution, manager);
|
||||
|
||||
if (drainSolution is null)
|
||||
if (!_solutionContainerSystem.ResolveSolution((uid, manager), DrainComponent.SolutionName, ref drain.Solution, out var drainSolution))
|
||||
continue;
|
||||
|
||||
if (drainSolution.AvailableVolume <= 0)
|
||||
@@ -146,7 +145,7 @@ public sealed class DrainSystem : SharedDrainSystem
|
||||
}
|
||||
|
||||
// Remove a bit from the buffer
|
||||
_solutionSystem.SplitSolution(uid, drainSolution, (drain.UnitsDestroyedPerSecond * drain.DrainFrequency));
|
||||
_solutionContainerSystem.SplitSolution(drain.Solution.Value, (drain.UnitsDestroyedPerSecond * drain.DrainFrequency));
|
||||
|
||||
// This will ensure that UnitsPerSecond is per second...
|
||||
var amount = drain.UnitsPerSecond * drain.DrainFrequency;
|
||||
@@ -162,7 +161,7 @@ public sealed class DrainSystem : SharedDrainSystem
|
||||
// and these are placed by mappers and not buildable/movable so shouldnt really be a problem...
|
||||
if (puddleQuery.TryGetComponent(entity, out var puddle))
|
||||
{
|
||||
puddles.Add((entity, puddle.SolutionName));
|
||||
puddles.Add(((entity, puddle), puddle.SolutionName));
|
||||
}
|
||||
}
|
||||
|
||||
@@ -180,7 +179,7 @@ public sealed class DrainSystem : SharedDrainSystem
|
||||
{
|
||||
// Queue the solution deletion if it's empty. EvaporationSystem might also do this
|
||||
// but queuedelete should be pretty safe.
|
||||
if (!_solutionSystem.TryGetSolution(puddle, solution, out var puddleSolution))
|
||||
if (!_solutionContainerSystem.ResolveSolution(puddle.Owner, solution, ref puddle.Comp.Solution, out var puddleSolution))
|
||||
{
|
||||
EntityManager.QueueDeleteEntity(puddle);
|
||||
continue;
|
||||
@@ -190,24 +189,26 @@ public sealed class DrainSystem : SharedDrainSystem
|
||||
// the drain component's units per second adjusted for # of puddles
|
||||
// the puddle's remaining volume (making it cleanly zero)
|
||||
// the drain's remaining volume in its buffer.
|
||||
var transferSolution = _solutionSystem.SplitSolution(puddle, puddleSolution,
|
||||
var transferSolution = _solutionContainerSystem.SplitSolution(puddle.Comp.Solution.Value,
|
||||
FixedPoint2.Min(FixedPoint2.New(amount), puddleSolution.Volume, drainSolution.AvailableVolume));
|
||||
|
||||
_solutionSystem.TryAddSolution(uid, drainSolution, transferSolution);
|
||||
drainSolution.AddSolution(transferSolution, _prototypeManager);
|
||||
|
||||
if (puddleSolution.Volume <= 0)
|
||||
{
|
||||
QueueDel(puddle);
|
||||
}
|
||||
}
|
||||
|
||||
_solutionContainerSystem.UpdateChemicals(drain.Solution.Value);
|
||||
}
|
||||
}
|
||||
|
||||
private void OnExamined(EntityUid uid, DrainComponent component, ExaminedEvent args)
|
||||
private void OnExamined(Entity<DrainComponent> entity, ref ExaminedEvent args)
|
||||
{
|
||||
if (!args.IsInDetailsRange ||
|
||||
!HasComp<SolutionContainerManagerComponent>(uid) ||
|
||||
!_solutionSystem.TryGetSolution(uid, DrainComponent.SolutionName, out var drainSolution))
|
||||
!HasComp<SolutionContainerManagerComponent>(entity) ||
|
||||
!_solutionContainerSystem.ResolveSolution(entity.Owner, DrainComponent.SolutionName, ref entity.Comp.Solution, out var drainSolution))
|
||||
{
|
||||
return;
|
||||
}
|
||||
@@ -218,11 +219,11 @@ public sealed class DrainSystem : SharedDrainSystem
|
||||
args.Message.AddMarkup($"\n\n{text}");
|
||||
}
|
||||
|
||||
private void OnInteract(EntityUid uid, DrainComponent component, InteractEvent args)
|
||||
private void OnInteract(Entity<DrainComponent> entity, ref AfterInteractUsingEvent args)
|
||||
{
|
||||
if (!args.CanReach || args.Target == null ||
|
||||
!_tagSystem.HasTag(args.Used, DrainComponent.PlungerTag) ||
|
||||
!_solutionSystem.TryGetSolution(args.Target.Value, DrainComponent.SolutionName, out var drainSolution))
|
||||
!_solutionContainerSystem.ResolveSolution(args.Target.Value, DrainComponent.SolutionName, ref entity.Comp.Solution, out var drainSolution))
|
||||
{
|
||||
return;
|
||||
}
|
||||
@@ -233,10 +234,10 @@ public sealed class DrainSystem : SharedDrainSystem
|
||||
return;
|
||||
}
|
||||
|
||||
_audioSystem.PlayPvs(component.PlungerSound, uid);
|
||||
_audioSystem.PlayPvs(entity.Comp.PlungerSound, entity);
|
||||
|
||||
|
||||
var doAfterArgs = new DoAfterArgs(EntityManager, args.User, component.UnclogDuration, new DrainDoAfterEvent(),uid, args.Target, args.Used)
|
||||
var doAfterArgs = new DoAfterArgs(EntityManager, args.User, entity.Comp.UnclogDuration, new DrainDoAfterEvent(), entity, args.Target, args.Used)
|
||||
{
|
||||
BreakOnTargetMove = true,
|
||||
BreakOnUserMove = true,
|
||||
@@ -247,27 +248,26 @@ public sealed class DrainSystem : SharedDrainSystem
|
||||
_doAfterSystem.TryStartDoAfter(doAfterArgs);
|
||||
}
|
||||
|
||||
private void OnDoAfter(EntityUid uid, DrainComponent component, DoAfterEvent args)
|
||||
private void OnDoAfter(Entity<DrainComponent> entity, ref DrainDoAfterEvent args)
|
||||
{
|
||||
if (args.Target == null)
|
||||
return;
|
||||
|
||||
if (!_random.Prob(component.UnclogProbability))
|
||||
if (!_random.Prob(entity.Comp.UnclogProbability))
|
||||
{
|
||||
_popupSystem.PopupEntity(Loc.GetString("drain-component-unclog-fail", ("object", args.Target.Value)), args.Target.Value);
|
||||
return;
|
||||
}
|
||||
|
||||
|
||||
if (!_solutionSystem.TryGetSolution(args.Target.Value, DrainComponent.SolutionName,
|
||||
out var drainSolution))
|
||||
if (!_solutionContainerSystem.ResolveSolution(args.Target.Value, DrainComponent.SolutionName, ref entity.Comp.Solution))
|
||||
{
|
||||
return;
|
||||
}
|
||||
|
||||
|
||||
_solutionSystem.RemoveAllSolution(args.Target.Value, drainSolution);
|
||||
_audioSystem.PlayPvs(component.UnclogSound, args.Target.Value);
|
||||
_solutionContainerSystem.RemoveAllSolution(entity.Comp.Solution.Value);
|
||||
_audioSystem.PlayPvs(entity.Comp.UnclogSound, args.Target.Value);
|
||||
_popupSystem.PopupEntity(Loc.GetString("drain-component-unclog-success", ("object", args.Target.Value)), args.Target.Value);
|
||||
}
|
||||
}
|
||||
|
||||
@@ -18,9 +18,9 @@ public sealed partial class PuddleSystem
|
||||
|
||||
public static string[] EvaporationReagents = new[] { Water, SoapyWater };
|
||||
|
||||
private void OnEvaporationMapInit(EntityUid uid, EvaporationComponent component, MapInitEvent args)
|
||||
private void OnEvaporationMapInit(Entity<EvaporationComponent> entity, ref MapInitEvent args)
|
||||
{
|
||||
component.NextTick = _timing.CurTime + EvaporationCooldown;
|
||||
entity.Comp.NextTick = _timing.CurTime + EvaporationCooldown;
|
||||
}
|
||||
|
||||
private void UpdateEvaporation(EntityUid uid, Solution solution)
|
||||
@@ -52,7 +52,7 @@ public sealed partial class PuddleSystem
|
||||
|
||||
evaporation.NextTick += EvaporationCooldown;
|
||||
|
||||
if (!_solutionContainerSystem.TryGetSolution(uid, puddle.SolutionName, out var puddleSolution))
|
||||
if (!_solutionContainerSystem.ResolveSolution(uid, puddle.SolutionName, ref puddle.Solution, out var puddleSolution))
|
||||
continue;
|
||||
|
||||
var reagentTick = evaporation.EvaporationAmount * EvaporationCooldown.TotalSeconds;
|
||||
|
||||
@@ -1,4 +1,4 @@
|
||||
using Content.Server.Chemistry.EntitySystems;
|
||||
using Content.Server.Chemistry.Containers.EntitySystems;
|
||||
using Content.Server.Fluids.Components;
|
||||
using Content.Server.Nutrition.EntitySystems;
|
||||
using Content.Shared.Chemistry.Components;
|
||||
@@ -36,29 +36,29 @@ public sealed partial class PuddleSystem
|
||||
SubscribeLocalEvent<SpillableComponent, MeleeHitEvent>(SplashOnMeleeHit, after: new[] { typeof(OpenableSystem) });
|
||||
SubscribeLocalEvent<SpillableComponent, GetVerbsEvent<Verb>>(AddSpillVerb);
|
||||
SubscribeLocalEvent<SpillableComponent, GotEquippedEvent>(OnGotEquipped);
|
||||
SubscribeLocalEvent<SpillableComponent, SolutionOverflowEvent>(OnOverflow);
|
||||
SubscribeLocalEvent<SpillableComponent, SolutionContainerOverflowEvent>(OnOverflow);
|
||||
SubscribeLocalEvent<SpillableComponent, SpillDoAfterEvent>(OnDoAfter);
|
||||
SubscribeLocalEvent<SpillableComponent, AttemptPacifiedThrowEvent>(OnAttemptPacifiedThrow);
|
||||
}
|
||||
|
||||
private void OnExamined(EntityUid uid, SpillableComponent component, ExaminedEvent args)
|
||||
private void OnExamined(Entity<SpillableComponent> entity, ref ExaminedEvent args)
|
||||
{
|
||||
args.PushMarkup(Loc.GetString("spill-examine-is-spillable"));
|
||||
|
||||
if (HasComp<MeleeWeaponComponent>(uid))
|
||||
if (HasComp<MeleeWeaponComponent>(entity))
|
||||
args.PushMarkup(Loc.GetString("spill-examine-spillable-weapon"));
|
||||
}
|
||||
|
||||
private void OnOverflow(EntityUid uid, SpillableComponent component, ref SolutionOverflowEvent args)
|
||||
private void OnOverflow(Entity<SpillableComponent> entity, ref SolutionContainerOverflowEvent args)
|
||||
{
|
||||
if (args.Handled)
|
||||
return;
|
||||
|
||||
TrySpillAt(Transform(uid).Coordinates, args.Overflow, out _);
|
||||
TrySpillAt(Transform(entity).Coordinates, args.Overflow, out _);
|
||||
args.Handled = true;
|
||||
}
|
||||
|
||||
private void SplashOnMeleeHit(EntityUid uid, SpillableComponent component, MeleeHitEvent args)
|
||||
private void SplashOnMeleeHit(Entity<SpillableComponent> entity, ref MeleeHitEvent args)
|
||||
{
|
||||
if (args.Handled)
|
||||
return;
|
||||
@@ -68,20 +68,20 @@ public sealed partial class PuddleSystem
|
||||
// If this also has solution transfer, then assume the transfer amount is how much we want to spill.
|
||||
// Otherwise let's say they want to spill a quarter of its max volume.
|
||||
|
||||
if (!_solutionContainerSystem.TryGetDrainableSolution(uid, out var solution))
|
||||
if (!_solutionContainerSystem.TryGetDrainableSolution(entity.Owner, out var soln, out var solution))
|
||||
return;
|
||||
|
||||
var hitCount = args.HitEntities.Count;
|
||||
|
||||
var totalSplit = FixedPoint2.Min(solution.MaxVolume * 0.25, solution.Volume);
|
||||
if (TryComp<SolutionTransferComponent>(uid, out var transfer))
|
||||
if (TryComp<SolutionTransferComponent>(entity, out var transfer))
|
||||
{
|
||||
totalSplit = FixedPoint2.Min(transfer.TransferAmount, solution.Volume);
|
||||
}
|
||||
|
||||
// a little lame, but reagent quantity is not very balanced and we don't want people
|
||||
// spilling like 100u of reagent on someone at once!
|
||||
totalSplit = FixedPoint2.Min(totalSplit, component.MaxMeleeSpillAmount);
|
||||
totalSplit = FixedPoint2.Min(totalSplit, entity.Comp.MaxMeleeSpillAmount);
|
||||
|
||||
if (totalSplit == 0)
|
||||
return;
|
||||
@@ -95,29 +95,29 @@ public sealed partial class PuddleSystem
|
||||
continue;
|
||||
}
|
||||
|
||||
var splitSolution = _solutionContainerSystem.SplitSolution(uid, solution, totalSplit / hitCount);
|
||||
var splitSolution = _solutionContainerSystem.SplitSolution(soln.Value, totalSplit / hitCount);
|
||||
|
||||
_adminLogger.Add(LogType.MeleeHit, $"{ToPrettyString(args.User)} splashed {SolutionContainerSystem.ToPrettyString(splitSolution):solution} from {ToPrettyString(uid):entity} onto {ToPrettyString(hit):target}");
|
||||
_adminLogger.Add(LogType.MeleeHit, $"{ToPrettyString(args.User)} splashed {SolutionContainerSystem.ToPrettyString(splitSolution):solution} from {ToPrettyString(entity.Owner):entity} onto {ToPrettyString(hit):target}");
|
||||
_reactive.DoEntityReaction(hit, splitSolution, ReactionMethod.Touch);
|
||||
|
||||
_popups.PopupEntity(
|
||||
Loc.GetString("spill-melee-hit-attacker", ("amount", totalSplit / hitCount), ("spillable", uid),
|
||||
Loc.GetString("spill-melee-hit-attacker", ("amount", totalSplit / hitCount), ("spillable", entity.Owner),
|
||||
("target", Identity.Entity(hit, EntityManager))),
|
||||
hit, args.User);
|
||||
|
||||
_popups.PopupEntity(
|
||||
Loc.GetString("spill-melee-hit-others", ("attacker", args.User), ("spillable", uid),
|
||||
Loc.GetString("spill-melee-hit-others", ("attacker", args.User), ("spillable", entity.Owner),
|
||||
("target", Identity.Entity(hit, EntityManager))),
|
||||
hit, Filter.PvsExcept(args.User), true, PopupType.SmallCaution);
|
||||
}
|
||||
}
|
||||
|
||||
private void OnGotEquipped(EntityUid uid, SpillableComponent component, GotEquippedEvent args)
|
||||
private void OnGotEquipped(Entity<SpillableComponent> entity, ref GotEquippedEvent args)
|
||||
{
|
||||
if (!component.SpillWorn)
|
||||
if (!entity.Comp.SpillWorn)
|
||||
return;
|
||||
|
||||
if (!TryComp(uid, out ClothingComponent? clothing))
|
||||
if (!TryComp(entity, out ClothingComponent? clothing))
|
||||
return;
|
||||
|
||||
// check if entity was actually used as clothing
|
||||
@@ -126,33 +126,33 @@ public sealed partial class PuddleSystem
|
||||
if (!isCorrectSlot)
|
||||
return;
|
||||
|
||||
if (!_solutionContainerSystem.TryGetSolution(uid, component.SolutionName, out var solution))
|
||||
if (!_solutionContainerSystem.TryGetSolution(entity.Owner, entity.Comp.SolutionName, out var soln, out var solution))
|
||||
return;
|
||||
|
||||
if (solution.Volume == 0)
|
||||
return;
|
||||
|
||||
// spill all solution on the player
|
||||
var drainedSolution = _solutionContainerSystem.Drain(uid, solution, solution.Volume);
|
||||
TrySplashSpillAt(uid, Transform(args.Equipee).Coordinates, drainedSolution, out _);
|
||||
var drainedSolution = _solutionContainerSystem.Drain(entity.Owner, soln.Value, solution.Volume);
|
||||
TrySplashSpillAt(entity.Owner, Transform(args.Equipee).Coordinates, drainedSolution, out _);
|
||||
}
|
||||
|
||||
private void SpillOnLand(EntityUid uid, SpillableComponent component, ref LandEvent args)
|
||||
private void SpillOnLand(Entity<SpillableComponent> entity, ref LandEvent args)
|
||||
{
|
||||
if (!_solutionContainerSystem.TryGetSolution(uid, component.SolutionName, out var solution))
|
||||
if (!_solutionContainerSystem.TryGetSolution(entity.Owner, entity.Comp.SolutionName, out var soln, out var solution))
|
||||
return;
|
||||
|
||||
if (_openable.IsClosed(uid))
|
||||
if (_openable.IsClosed(entity.Owner))
|
||||
return;
|
||||
|
||||
if (args.User != null)
|
||||
{
|
||||
_adminLogger.Add(LogType.Landed,
|
||||
$"{ToPrettyString(uid):entity} spilled a solution {SolutionContainerSystem.ToPrettyString(solution):solution} on landing");
|
||||
$"{ToPrettyString(entity.Owner):entity} spilled a solution {SolutionContainerSystem.ToPrettyString(solution):solution} on landing");
|
||||
}
|
||||
|
||||
var drainedSolution = _solutionContainerSystem.Drain(uid, solution, solution.Volume);
|
||||
TrySplashSpillAt(uid, Transform(uid).Coordinates, drainedSolution, out _);
|
||||
var drainedSolution = _solutionContainerSystem.Drain(entity.Owner, soln.Value, solution.Volume);
|
||||
TrySplashSpillAt(entity.Owner, Transform(entity).Coordinates, drainedSolution, out _);
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
@@ -165,18 +165,18 @@ public sealed partial class PuddleSystem
|
||||
return;
|
||||
|
||||
// Don’t care about empty containers.
|
||||
if (!_solutionContainerSystem.TryGetSolution(ent, ent.Comp.SolutionName, out var solution))
|
||||
if (!_solutionContainerSystem.TryGetSolution(ent.Owner, ent.Comp.SolutionName, out _, out var solution) || solution.Volume <= 0)
|
||||
return;
|
||||
|
||||
args.Cancel("pacified-cannot-throw-spill");
|
||||
}
|
||||
|
||||
private void AddSpillVerb(EntityUid uid, SpillableComponent component, GetVerbsEvent<Verb> args)
|
||||
private void AddSpillVerb(Entity<SpillableComponent> entity, ref GetVerbsEvent<Verb> args)
|
||||
{
|
||||
if (!args.CanAccess || !args.CanInteract)
|
||||
return;
|
||||
|
||||
if (!_solutionContainerSystem.TryGetSolution(args.Target, component.SolutionName, out var solution))
|
||||
if (!_solutionContainerSystem.TryGetSolution(args.Target, entity.Comp.SolutionName, out var soln, out var solution))
|
||||
return;
|
||||
|
||||
if (_openable.IsClosed(args.Target))
|
||||
@@ -195,20 +195,21 @@ public sealed partial class PuddleSystem
|
||||
};
|
||||
|
||||
// TODO VERB ICONS spill icon? pouring out a glass/beaker?
|
||||
if (component.SpillDelay == null)
|
||||
if (entity.Comp.SpillDelay == null)
|
||||
{
|
||||
var target = args.Target;
|
||||
verb.Act = () =>
|
||||
{
|
||||
var puddleSolution = _solutionContainerSystem.SplitSolution(args.Target,
|
||||
solution, solution.Volume);
|
||||
TrySpillAt(Transform(args.Target).Coordinates, puddleSolution, out _);
|
||||
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, args.User, component.SpillDelay ?? 0, new SpillDoAfterEvent(), uid, target: uid)
|
||||
_doAfterSystem.TryStartDoAfter(new DoAfterArgs(EntityManager, user, entity.Comp.SpillDelay ?? 0, new SpillDoAfterEvent(), entity.Owner, target: entity.Owner)
|
||||
{
|
||||
BreakOnTargetMove = true,
|
||||
BreakOnUserMove = true,
|
||||
@@ -222,17 +223,17 @@ public sealed partial class PuddleSystem
|
||||
args.Verbs.Add(verb);
|
||||
}
|
||||
|
||||
private void OnDoAfter(EntityUid uid, SpillableComponent component, DoAfterEvent args)
|
||||
private void OnDoAfter(Entity<SpillableComponent> entity, ref SpillDoAfterEvent args)
|
||||
{
|
||||
if (args.Handled || args.Cancelled || args.Args.Target == null)
|
||||
return;
|
||||
|
||||
//solution gone by other means before doafter completes
|
||||
if (!_solutionContainerSystem.TryGetDrainableSolution(uid, out var solution) || solution.Volume == 0)
|
||||
if (!_solutionContainerSystem.TryGetDrainableSolution(entity.Owner, out var soln, out var solution) || solution.Volume == 0)
|
||||
return;
|
||||
|
||||
var puddleSolution = _solutionContainerSystem.SplitSolution(uid, solution, solution.Volume);
|
||||
TrySpillAt(Transform(uid).Coordinates, puddleSolution, out _);
|
||||
var puddleSolution = _solutionContainerSystem.SplitSolution(soln.Value, solution.Volume);
|
||||
TrySpillAt(Transform(entity).Coordinates, puddleSolution, out _);
|
||||
args.Handled = true;
|
||||
}
|
||||
}
|
||||
|
||||
@@ -1,9 +1,7 @@
|
||||
using Content.Server.Fluids.Components;
|
||||
using Content.Shared.Chemistry.Components;
|
||||
using Content.Shared.DragDrop;
|
||||
using Content.Shared.FixedPoint;
|
||||
using Content.Shared.Fluids;
|
||||
using Content.Shared.Fluids.Components;
|
||||
|
||||
namespace Content.Server.Fluids.EntitySystems;
|
||||
|
||||
@@ -14,33 +12,30 @@ public sealed partial class PuddleSystem
|
||||
SubscribeLocalEvent<RefillableSolutionComponent, DragDropDraggedEvent>(OnRefillableDragged);
|
||||
}
|
||||
|
||||
private void OnRefillableDragged(EntityUid uid, RefillableSolutionComponent component, ref DragDropDraggedEvent args)
|
||||
private void OnRefillableDragged(Entity<RefillableSolutionComponent> entity, ref DragDropDraggedEvent args)
|
||||
{
|
||||
_solutionContainerSystem.TryGetSolution(uid, component.Solution, out var solution);
|
||||
|
||||
if (solution?.Volume == FixedPoint2.Zero)
|
||||
if (!_solutionContainerSystem.TryGetSolution(entity.Owner, entity.Comp.Solution, out var soln, out var solution) || solution.Volume == FixedPoint2.Zero)
|
||||
{
|
||||
_popups.PopupEntity(Loc.GetString("mopping-system-empty", ("used", uid)), uid, args.User);
|
||||
_popups.PopupEntity(Loc.GetString("mopping-system-empty", ("used", entity.Owner)), entity, args.User);
|
||||
return;
|
||||
}
|
||||
|
||||
// Dump reagents into DumpableSolution
|
||||
if (TryComp<DumpableSolutionComponent>(args.Target, out var dump))
|
||||
{
|
||||
_solutionContainerSystem.TryGetDumpableSolution(args.Target, out var dumpableSolution, dump);
|
||||
if (dumpableSolution == null || solution == null)
|
||||
if (!_solutionContainerSystem.TryGetDumpableSolution((args.Target, dump, null), out var dumpableSoln, out var dumpableSolution))
|
||||
return;
|
||||
|
||||
bool success = true;
|
||||
if (dump.Unlimited)
|
||||
{
|
||||
var split = _solutionContainerSystem.SplitSolution(uid, solution, solution.Volume);
|
||||
var split = _solutionContainerSystem.SplitSolution(soln.Value, solution.Volume);
|
||||
dumpableSolution.AddSolution(split, _prototypeManager);
|
||||
}
|
||||
else
|
||||
{
|
||||
var split = _solutionContainerSystem.SplitSolution(uid, solution, dumpableSolution.AvailableVolume);
|
||||
success = _solutionContainerSystem.TryAddSolution(args.Target, dumpableSolution, split);
|
||||
var split = _solutionContainerSystem.SplitSolution(soln.Value, dumpableSolution.AvailableVolume);
|
||||
success = _solutionContainerSystem.TryAddSolution(dumpableSoln.Value, split);
|
||||
}
|
||||
|
||||
if (success)
|
||||
@@ -55,25 +50,21 @@ public sealed partial class PuddleSystem
|
||||
return;
|
||||
}
|
||||
|
||||
TryComp<DrainableSolutionComponent>(args.Target, out var drainable);
|
||||
|
||||
_solutionContainerSystem.TryGetDrainableSolution(args.Target, out var drainableSolution, drainable);
|
||||
|
||||
// Take reagents from target
|
||||
if (drainable != null)
|
||||
if (!TryComp<DrainableSolutionComponent>(args.Target, out var drainable))
|
||||
{
|
||||
if (drainableSolution == null || solution == null)
|
||||
if (!_solutionContainerSystem.TryGetDrainableSolution((args.Target, drainable, null), out var drainableSolution, out _))
|
||||
return;
|
||||
|
||||
var split = _solutionContainerSystem.SplitSolution(args.Target, drainableSolution, solution.AvailableVolume);
|
||||
var split = _solutionContainerSystem.SplitSolution(drainableSolution.Value, solution.AvailableVolume);
|
||||
|
||||
if (_solutionContainerSystem.TryAddSolution(uid, solution, split))
|
||||
if (_solutionContainerSystem.TryAddSolution(soln.Value, split))
|
||||
{
|
||||
_audio.PlayPvs(AbsorbentComponent.DefaultTransferSound, uid);
|
||||
_audio.PlayPvs(AbsorbentComponent.DefaultTransferSound, entity);
|
||||
}
|
||||
else
|
||||
{
|
||||
_popups.PopupEntity(Loc.GetString("mopping-system-full", ("used", uid)), uid, args.User);
|
||||
_popups.PopupEntity(Loc.GetString("mopping-system-full", ("used", entity.Owner)), entity, args.User);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@@ -1,4 +1,5 @@
|
||||
using Content.Server.Administration.Logs;
|
||||
using Content.Server.Chemistry.Containers.EntitySystems;
|
||||
using Content.Server.DoAfter;
|
||||
using Content.Server.Fluids.Components;
|
||||
using Content.Server.Spreader;
|
||||
@@ -22,19 +23,13 @@ using Content.Shared.Popups;
|
||||
using Content.Shared.Slippery;
|
||||
using Content.Shared.StepTrigger.Components;
|
||||
using Content.Shared.StepTrigger.Systems;
|
||||
using Robust.Server.GameObjects;
|
||||
using Robust.Shared.Audio;
|
||||
using Robust.Server.Audio;
|
||||
using Robust.Shared.Map;
|
||||
using Robust.Shared.Map.Components;
|
||||
using Robust.Shared.Player;
|
||||
using Robust.Shared.Prototypes;
|
||||
using Robust.Shared.Random;
|
||||
using Robust.Shared.Timing;
|
||||
using Content.Shared.Movement.Components;
|
||||
using Content.Shared.Movement.Systems;
|
||||
using Content.Shared.Maps;
|
||||
using Content.Shared.Effects;
|
||||
using Robust.Server.Audio;
|
||||
|
||||
namespace Content.Server.Fluids.EntitySystems;
|
||||
|
||||
@@ -91,7 +86,7 @@ public sealed partial class PuddleSystem : SharedPuddleSystem
|
||||
// Shouldn't need re-anchoring.
|
||||
SubscribeLocalEvent<PuddleComponent, AnchorStateChangedEvent>(OnAnchorChanged);
|
||||
SubscribeLocalEvent<PuddleComponent, ExaminedEvent>(HandlePuddleExamined);
|
||||
SubscribeLocalEvent<PuddleComponent, SolutionChangedEvent>(OnSolutionUpdate);
|
||||
SubscribeLocalEvent<PuddleComponent, SolutionContainerChangedEvent>(OnSolutionUpdate);
|
||||
SubscribeLocalEvent<PuddleComponent, ComponentInit>(OnPuddleInit);
|
||||
SubscribeLocalEvent<PuddleComponent, SpreadNeighborsEvent>(OnPuddleSpread);
|
||||
SubscribeLocalEvent<PuddleComponent, SlipEvent>(OnPuddleSlip);
|
||||
@@ -102,13 +97,13 @@ public sealed partial class PuddleSystem : SharedPuddleSystem
|
||||
InitializeTransfers();
|
||||
}
|
||||
|
||||
private void OnPuddleSpread(EntityUid uid, PuddleComponent component, ref SpreadNeighborsEvent args)
|
||||
private void OnPuddleSpread(Entity<PuddleComponent> entity, ref SpreadNeighborsEvent args)
|
||||
{
|
||||
var overflow = GetOverflowSolution(uid, component);
|
||||
var overflow = GetOverflowSolution(entity.Owner, entity.Comp);
|
||||
|
||||
if (overflow.Volume == FixedPoint2.Zero)
|
||||
{
|
||||
RemCompDeferred<ActiveEdgeSpreaderComponent>(uid);
|
||||
RemCompDeferred<ActiveEdgeSpreaderComponent>(entity);
|
||||
return;
|
||||
}
|
||||
|
||||
@@ -125,7 +120,7 @@ public sealed partial class PuddleSystem : SharedPuddleSystem
|
||||
foreach (var neighbor in args.Neighbors)
|
||||
{
|
||||
if (!puddleQuery.TryGetComponent(neighbor, out var puddle) ||
|
||||
!_solutionContainerSystem.TryGetSolution(neighbor, puddle.SolutionName, out var neighborSolution) ||
|
||||
!_solutionContainerSystem.ResolveSolution(neighbor, puddle.SolutionName, ref puddle.Solution, out var neighborSolution) ||
|
||||
CanFullyEvaporate(neighborSolution))
|
||||
{
|
||||
continue;
|
||||
@@ -138,7 +133,7 @@ public sealed partial class PuddleSystem : SharedPuddleSystem
|
||||
|
||||
var split = overflow.SplitSolution(remaining);
|
||||
|
||||
if (!_solutionContainerSystem.TryAddSolution(neighbor, neighborSolution, split))
|
||||
if (!_solutionContainerSystem.TryAddSolution(puddle.Solution.Value, split))
|
||||
continue;
|
||||
|
||||
args.Updates--;
|
||||
@@ -150,7 +145,7 @@ public sealed partial class PuddleSystem : SharedPuddleSystem
|
||||
|
||||
if (overflow.Volume == FixedPoint2.Zero)
|
||||
{
|
||||
RemCompDeferred<ActiveEdgeSpreaderComponent>(uid);
|
||||
RemCompDeferred<ActiveEdgeSpreaderComponent>(entity);
|
||||
return;
|
||||
}
|
||||
}
|
||||
@@ -173,7 +168,7 @@ public sealed partial class PuddleSystem : SharedPuddleSystem
|
||||
break;
|
||||
}
|
||||
|
||||
RemCompDeferred<ActiveEdgeSpreaderComponent>(uid);
|
||||
RemCompDeferred<ActiveEdgeSpreaderComponent>(entity);
|
||||
return;
|
||||
}
|
||||
|
||||
@@ -186,7 +181,7 @@ public sealed partial class PuddleSystem : SharedPuddleSystem
|
||||
{
|
||||
// Overflow to neighbours (unless it's pure water)
|
||||
if (!puddleQuery.TryGetComponent(neighbor, out var puddle) ||
|
||||
!_solutionContainerSystem.TryGetSolution(neighbor, puddle.SolutionName, out var neighborSolution) ||
|
||||
!_solutionContainerSystem.ResolveSolution(neighbor, puddle.SolutionName, ref puddle.Solution, out var neighborSolution) ||
|
||||
CanFullyEvaporate(neighborSolution))
|
||||
{
|
||||
continue;
|
||||
@@ -194,7 +189,7 @@ public sealed partial class PuddleSystem : SharedPuddleSystem
|
||||
|
||||
var split = overflow.SplitSolution(spillPerNeighbor);
|
||||
|
||||
if (!_solutionContainerSystem.TryAddSolution(neighbor, neighborSolution, split))
|
||||
if (!_solutionContainerSystem.TryAddSolution(puddle.Solution.Value, split))
|
||||
continue;
|
||||
|
||||
EnsureComp<ActiveEdgeSpreaderComponent>(neighbor);
|
||||
@@ -206,13 +201,13 @@ public sealed partial class PuddleSystem : SharedPuddleSystem
|
||||
}
|
||||
|
||||
// Add the remainder back
|
||||
if (_solutionContainerSystem.TryGetSolution(uid, component.SolutionName, out var puddleSolution))
|
||||
if (_solutionContainerSystem.ResolveSolution(entity.Owner, entity.Comp.SolutionName, ref entity.Comp.Solution))
|
||||
{
|
||||
_solutionContainerSystem.TryAddSolution(uid, puddleSolution, overflow);
|
||||
_solutionContainerSystem.TryAddSolution(entity.Comp.Solution.Value, overflow);
|
||||
}
|
||||
}
|
||||
|
||||
private void OnPuddleSlip(EntityUid uid, PuddleComponent component, ref SlipEvent args)
|
||||
private void OnPuddleSlip(Entity<PuddleComponent> entity, ref SlipEvent args)
|
||||
{
|
||||
// Reactive entities have a chance to get a touch reaction from slipping on a puddle
|
||||
// (i.e. it is implied they fell face first onto it or something)
|
||||
@@ -224,14 +219,14 @@ public sealed partial class PuddleSystem : SharedPuddleSystem
|
||||
if (!_random.Prob(0.5f))
|
||||
return;
|
||||
|
||||
if (!_solutionContainerSystem.TryGetSolution(uid, component.SolutionName, out var solution))
|
||||
if (!_solutionContainerSystem.ResolveSolution(entity.Owner, entity.Comp.SolutionName, ref entity.Comp.Solution, out var solution))
|
||||
return;
|
||||
|
||||
_popups.PopupEntity(Loc.GetString("puddle-component-slipped-touch-reaction", ("puddle", uid)),
|
||||
_popups.PopupEntity(Loc.GetString("puddle-component-slipped-touch-reaction", ("puddle", entity.Owner)),
|
||||
args.Slipped, args.Slipped, PopupType.SmallCaution);
|
||||
|
||||
// Take 15% of the puddle solution
|
||||
var splitSol = _solutionContainerSystem.SplitSolution(uid, solution, solution.Volume * 0.15f);
|
||||
var splitSol = _solutionContainerSystem.SplitSolution(entity.Comp.Solution.Value, solution.Volume * 0.15f);
|
||||
_reactive.DoEntityReaction(args.Slipped, splitSol, ReactionMethod.Touch);
|
||||
}
|
||||
|
||||
@@ -248,27 +243,27 @@ public sealed partial class PuddleSystem : SharedPuddleSystem
|
||||
TickEvaporation();
|
||||
}
|
||||
|
||||
private void OnPuddleInit(EntityUid uid, PuddleComponent component, ComponentInit args)
|
||||
private void OnPuddleInit(Entity<PuddleComponent> entity, ref ComponentInit args)
|
||||
{
|
||||
_solutionContainerSystem.EnsureSolution(uid, component.SolutionName, FixedPoint2.New(PuddleVolume), out _);
|
||||
_solutionContainerSystem.EnsureSolution(entity.Owner, entity.Comp.SolutionName, FixedPoint2.New(PuddleVolume), out _);
|
||||
}
|
||||
|
||||
private void OnSolutionUpdate(EntityUid uid, PuddleComponent component, SolutionChangedEvent args)
|
||||
private void OnSolutionUpdate(Entity<PuddleComponent> entity, ref SolutionContainerChangedEvent args)
|
||||
{
|
||||
if (args.Solution.Name != component.SolutionName)
|
||||
if (args.SolutionId != entity.Comp.SolutionName)
|
||||
return;
|
||||
|
||||
if (args.Solution.Volume <= 0)
|
||||
{
|
||||
_deletionQueue.Add(uid);
|
||||
_deletionQueue.Add(entity);
|
||||
return;
|
||||
}
|
||||
|
||||
_deletionQueue.Remove(uid);
|
||||
UpdateSlip(uid, component, args.Solution);
|
||||
UpdateSlow(uid, args.Solution);
|
||||
UpdateEvaporation(uid, args.Solution);
|
||||
UpdateAppearance(uid, component);
|
||||
_deletionQueue.Remove(entity);
|
||||
UpdateSlip(entity, entity.Comp, args.Solution);
|
||||
UpdateSlow(entity, args.Solution);
|
||||
UpdateEvaporation(entity, args.Solution);
|
||||
UpdateAppearance(entity, entity.Comp);
|
||||
}
|
||||
|
||||
private void UpdateAppearance(EntityUid uid, PuddleComponent? puddleComponent = null, AppearanceComponent? appearance = null)
|
||||
@@ -281,7 +276,7 @@ public sealed partial class PuddleSystem : SharedPuddleSystem
|
||||
var volume = FixedPoint2.Zero;
|
||||
Color color = Color.White;
|
||||
|
||||
if (_solutionContainerSystem.TryGetSolution(uid, puddleComponent.SolutionName, out var solution))
|
||||
if (_solutionContainerSystem.ResolveSolution(uid, puddleComponent.SolutionName, ref puddleComponent.Solution, out var solution))
|
||||
{
|
||||
volume = solution.Volume / puddleComponent.OverflowVolume;
|
||||
|
||||
@@ -364,39 +359,31 @@ public sealed partial class PuddleSystem : SharedPuddleSystem
|
||||
}
|
||||
}
|
||||
|
||||
private void HandlePuddleExamined(EntityUid uid, PuddleComponent component, ExaminedEvent args)
|
||||
private void HandlePuddleExamined(Entity<PuddleComponent> entity, ref ExaminedEvent args)
|
||||
{
|
||||
if (TryComp<StepTriggerComponent>(uid, out var slippery) && slippery.Active)
|
||||
if (TryComp<StepTriggerComponent>(entity, out var slippery) && slippery.Active)
|
||||
{
|
||||
args.PushMarkup(Loc.GetString("puddle-component-examine-is-slipper-text"));
|
||||
}
|
||||
|
||||
if (HasComp<EvaporationComponent>(uid))
|
||||
if (HasComp<EvaporationComponent>(entity) &&
|
||||
_solutionContainerSystem.ResolveSolution(entity.Owner, entity.Comp.SolutionName, ref entity.Comp.Solution, out var solution))
|
||||
{
|
||||
if (_solutionContainerSystem.TryGetSolution(uid, component.SolutionName, out var solution) &&
|
||||
CanFullyEvaporate(solution))
|
||||
{
|
||||
if (CanFullyEvaporate(solution))
|
||||
args.PushMarkup(Loc.GetString("puddle-component-examine-evaporating"));
|
||||
}
|
||||
else if (solution?.GetTotalPrototypeQuantity(EvaporationReagents) > FixedPoint2.Zero)
|
||||
{
|
||||
else if (solution.GetTotalPrototypeQuantity(EvaporationReagents) > FixedPoint2.Zero)
|
||||
args.PushMarkup(Loc.GetString("puddle-component-examine-evaporating-partial"));
|
||||
}
|
||||
else
|
||||
{
|
||||
args.PushMarkup(Loc.GetString("puddle-component-examine-evaporating-no"));
|
||||
}
|
||||
}
|
||||
else
|
||||
{
|
||||
args.PushMarkup(Loc.GetString("puddle-component-examine-evaporating-no"));
|
||||
}
|
||||
}
|
||||
|
||||
private void OnAnchorChanged(EntityUid uid, PuddleComponent puddle, ref AnchorStateChangedEvent args)
|
||||
private void OnAnchorChanged(Entity<PuddleComponent> entity, ref AnchorStateChangedEvent args)
|
||||
{
|
||||
if (!args.Anchored)
|
||||
QueueDel(uid);
|
||||
QueueDel(entity);
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
@@ -407,8 +394,7 @@ public sealed partial class PuddleSystem : SharedPuddleSystem
|
||||
if (!Resolve(uid, ref puddleComponent))
|
||||
return FixedPoint2.Zero;
|
||||
|
||||
return _solutionContainerSystem.TryGetSolution(uid, puddleComponent.SolutionName,
|
||||
out var solution)
|
||||
return _solutionContainerSystem.ResolveSolution(uid, puddleComponent.SolutionName, ref puddleComponent.Solution, out var solution)
|
||||
? solution.Volume
|
||||
: FixedPoint2.Zero;
|
||||
}
|
||||
@@ -432,14 +418,12 @@ public sealed partial class PuddleSystem : SharedPuddleSystem
|
||||
return false;
|
||||
|
||||
if (addedSolution.Volume == 0 ||
|
||||
!_solutionContainerSystem.TryGetSolution(puddleUid, puddleComponent.SolutionName,
|
||||
out var solution))
|
||||
!_solutionContainerSystem.ResolveSolution(puddleUid, puddleComponent.SolutionName, ref puddleComponent.Solution))
|
||||
{
|
||||
return false;
|
||||
}
|
||||
|
||||
solution.AddSolution(addedSolution, _prototypeManager);
|
||||
_solutionContainerSystem.UpdateChemicals(puddleUid, solution, true);
|
||||
_solutionContainerSystem.AddSolution(puddleComponent.Solution.Value, addedSolution);
|
||||
|
||||
if (checkForOverflow && IsOverflowing(puddleUid, puddleComponent))
|
||||
{
|
||||
@@ -482,15 +466,14 @@ public sealed partial class PuddleSystem : SharedPuddleSystem
|
||||
/// </summary>
|
||||
public Solution GetOverflowSolution(EntityUid uid, PuddleComponent? puddle = null)
|
||||
{
|
||||
if (!Resolve(uid, ref puddle) || !_solutionContainerSystem.TryGetSolution(uid, puddle.SolutionName,
|
||||
out var solution))
|
||||
if (!Resolve(uid, ref puddle) || !_solutionContainerSystem.ResolveSolution(uid, puddle.SolutionName, ref puddle.Solution))
|
||||
{
|
||||
return new Solution(0);
|
||||
}
|
||||
|
||||
// TODO: This is going to fail with struct solutions.
|
||||
var remaining = puddle.OverflowVolume;
|
||||
var split = _solutionContainerSystem.SplitSolution(uid, solution, CurrentVolume(uid, puddle) - remaining);
|
||||
var split = _solutionContainerSystem.SplitSolution(puddle.Solution.Value, CurrentVolume(uid, puddle) - remaining);
|
||||
return split;
|
||||
}
|
||||
|
||||
|
||||
@@ -1,7 +1,7 @@
|
||||
using System.Linq;
|
||||
using Content.Server.Administration.Logs;
|
||||
using Content.Server.Body.Components;
|
||||
using Content.Server.Body.Systems;
|
||||
using Content.Server.Chemistry.Containers.EntitySystems;
|
||||
using Content.Server.Chemistry.ReactionEffects;
|
||||
using Content.Server.Spreader;
|
||||
using Content.Shared.Chemistry;
|
||||
@@ -21,6 +21,8 @@ using Robust.Shared.Physics.Systems;
|
||||
using Robust.Shared.Prototypes;
|
||||
using Robust.Shared.Random;
|
||||
using Robust.Shared.Timing;
|
||||
using System.Linq;
|
||||
|
||||
using TimedDespawnComponent = Robust.Shared.Spawners.TimedDespawnComponent;
|
||||
|
||||
namespace Content.Server.Fluids.EntitySystems;
|
||||
@@ -42,7 +44,7 @@ public sealed class SmokeSystem : EntitySystem
|
||||
[Dependency] private readonly ReactiveSystem _reactive = default!;
|
||||
[Dependency] private readonly SharedBroadphaseSystem _broadphase = default!;
|
||||
[Dependency] private readonly SharedPhysicsSystem _physics = default!;
|
||||
[Dependency] private readonly SolutionContainerSystem _solutionSystem = default!;
|
||||
[Dependency] private readonly SolutionContainerSystem _solutionContainerSystem = default!;
|
||||
[Dependency] private readonly TransformSystem _transform = default!;
|
||||
|
||||
private EntityQuery<SmokeComponent> _smokeQuery;
|
||||
@@ -59,6 +61,7 @@ public sealed class SmokeSystem : EntitySystem
|
||||
SubscribeLocalEvent<SmokeComponent, StartCollideEvent>(OnStartCollide);
|
||||
SubscribeLocalEvent<SmokeComponent, EndCollideEvent>(OnEndCollide);
|
||||
SubscribeLocalEvent<SmokeComponent, ReactionAttemptEvent>(OnReactionAttempt);
|
||||
SubscribeLocalEvent<SmokeComponent, SolutionRelayEvent<ReactionAttemptEvent>>(OnReactionAttempt);
|
||||
SubscribeLocalEvent<SmokeComponent, SpreadNeighborsEvent>(OnSmokeSpread);
|
||||
SubscribeLocalEvent<SmokeAffectedComponent, EntityUnpausedEvent>(OnAffectedUnpaused);
|
||||
}
|
||||
@@ -80,33 +83,33 @@ public sealed class SmokeSystem : EntitySystem
|
||||
}
|
||||
}
|
||||
|
||||
private void OnStartCollide(EntityUid uid, SmokeComponent component, ref StartCollideEvent args)
|
||||
private void OnStartCollide(Entity<SmokeComponent> entity, ref StartCollideEvent args)
|
||||
{
|
||||
if (_smokeAffectedQuery.HasComponent(args.OtherEntity))
|
||||
return;
|
||||
|
||||
var smokeAffected = AddComp<SmokeAffectedComponent>(args.OtherEntity);
|
||||
smokeAffected.SmokeEntity = uid;
|
||||
smokeAffected.SmokeEntity = entity;
|
||||
smokeAffected.NextSecond = _timing.CurTime + TimeSpan.FromSeconds(1);
|
||||
}
|
||||
|
||||
private void OnEndCollide(EntityUid uid, SmokeComponent component, ref EndCollideEvent args)
|
||||
private void OnEndCollide(Entity<SmokeComponent> entity, ref EndCollideEvent args)
|
||||
{
|
||||
// if we are already in smoke, make sure the thing we are exiting is the current smoke we are in.
|
||||
if (_smokeAffectedQuery.TryGetComponent(args.OtherEntity, out var smokeAffectedComponent))
|
||||
{
|
||||
if (smokeAffectedComponent.SmokeEntity != uid)
|
||||
if (smokeAffectedComponent.SmokeEntity != entity.Owner)
|
||||
return;
|
||||
}
|
||||
|
||||
var exists = Exists(uid);
|
||||
var exists = Exists(entity);
|
||||
|
||||
if (!TryComp<PhysicsComponent>(args.OtherEntity, out var body))
|
||||
return;
|
||||
|
||||
foreach (var ent in _physics.GetContactingEntities(args.OtherEntity, body))
|
||||
{
|
||||
if (exists && ent == uid)
|
||||
if (exists && ent == entity.Owner)
|
||||
continue;
|
||||
|
||||
if (!_smokeQuery.HasComponent(ent))
|
||||
@@ -121,51 +124,51 @@ public sealed class SmokeSystem : EntitySystem
|
||||
RemComp(args.OtherEntity, smokeAffectedComponent);
|
||||
}
|
||||
|
||||
private void OnAffectedUnpaused(EntityUid uid, SmokeAffectedComponent component, ref EntityUnpausedEvent args)
|
||||
private void OnAffectedUnpaused(Entity<SmokeAffectedComponent> entity, ref EntityUnpausedEvent args)
|
||||
{
|
||||
component.NextSecond += args.PausedTime;
|
||||
entity.Comp.NextSecond += args.PausedTime;
|
||||
}
|
||||
|
||||
private void OnSmokeSpread(EntityUid uid, SmokeComponent component, ref SpreadNeighborsEvent args)
|
||||
private void OnSmokeSpread(Entity<SmokeComponent> entity, ref SpreadNeighborsEvent args)
|
||||
{
|
||||
if (component.SpreadAmount == 0 || !_solutionSystem.TryGetSolution(uid, SmokeComponent.SolutionName, out var solution))
|
||||
if (entity.Comp.SpreadAmount == 0 || !_solutionContainerSystem.ResolveSolution(entity.Owner, SmokeComponent.SolutionName, ref entity.Comp.Solution, out var solution))
|
||||
{
|
||||
RemCompDeferred<ActiveEdgeSpreaderComponent>(uid);
|
||||
RemCompDeferred<ActiveEdgeSpreaderComponent>(entity);
|
||||
return;
|
||||
}
|
||||
|
||||
if (Prototype(uid) is not { } prototype)
|
||||
if (Prototype(entity) is not { } prototype)
|
||||
{
|
||||
RemCompDeferred<ActiveEdgeSpreaderComponent>(uid);
|
||||
RemCompDeferred<ActiveEdgeSpreaderComponent>(entity);
|
||||
return;
|
||||
}
|
||||
|
||||
if (!args.NeighborFreeTiles.Any())
|
||||
return;
|
||||
|
||||
TryComp<TimedDespawnComponent>(uid, out var timer);
|
||||
TryComp<TimedDespawnComponent>(entity, out var timer);
|
||||
|
||||
// wtf is the logic behind any of this.
|
||||
var smokePerSpread = component.SpreadAmount / Math.Max(1, args.NeighborFreeTiles.Count);
|
||||
var smokePerSpread = entity.Comp.SpreadAmount / Math.Max(1, args.NeighborFreeTiles.Count);
|
||||
foreach (var neighbor in args.NeighborFreeTiles)
|
||||
{
|
||||
var coords = neighbor.Grid.GridTileToLocal(neighbor.Tile);
|
||||
var ent = Spawn(prototype.ID, coords);
|
||||
var spreadAmount = Math.Max(0, smokePerSpread);
|
||||
component.SpreadAmount -= args.NeighborFreeTiles.Count();
|
||||
entity.Comp.SpreadAmount -= args.NeighborFreeTiles.Count();
|
||||
|
||||
StartSmoke(ent, solution.Clone(), timer?.Lifetime ?? component.Duration, spreadAmount);
|
||||
StartSmoke(ent, solution.Clone(), timer?.Lifetime ?? entity.Comp.Duration, spreadAmount);
|
||||
|
||||
if (component.SpreadAmount == 0)
|
||||
if (entity.Comp.SpreadAmount == 0)
|
||||
{
|
||||
RemCompDeferred<ActiveEdgeSpreaderComponent>(uid);
|
||||
RemCompDeferred<ActiveEdgeSpreaderComponent>(entity);
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
args.Updates--;
|
||||
|
||||
if (args.NeighborFreeTiles.Count > 0 || args.Neighbors.Count == 0 || component.SpreadAmount < 1)
|
||||
if (args.NeighborFreeTiles.Count > 0 || args.Neighbors.Count == 0 || entity.Comp.SpreadAmount < 1)
|
||||
return;
|
||||
|
||||
// We have no more neighbours to spread to. So instead we will randomly distribute our volume to neighbouring smoke tiles.
|
||||
@@ -179,21 +182,21 @@ public sealed class SmokeSystem : EntitySystem
|
||||
continue;
|
||||
|
||||
smoke.SpreadAmount++;
|
||||
component.SpreadAmount--;
|
||||
entity.Comp.SpreadAmount--;
|
||||
EnsureComp<ActiveEdgeSpreaderComponent>(neighbor);
|
||||
|
||||
if (component.SpreadAmount == 0)
|
||||
if (entity.Comp.SpreadAmount == 0)
|
||||
{
|
||||
RemCompDeferred<ActiveEdgeSpreaderComponent>(uid);
|
||||
RemCompDeferred<ActiveEdgeSpreaderComponent>(entity);
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
private void OnReactionAttempt(EntityUid uid, SmokeComponent component, ReactionAttemptEvent args)
|
||||
private void OnReactionAttempt(Entity<SmokeComponent> entity, ref ReactionAttemptEvent args)
|
||||
{
|
||||
if (args.Solution.Name != SmokeComponent.SolutionName)
|
||||
if (args.Cancelled)
|
||||
return;
|
||||
|
||||
// Prevent smoke/foam fork bombs (smoke creating more smoke).
|
||||
@@ -201,12 +204,18 @@ public sealed class SmokeSystem : EntitySystem
|
||||
{
|
||||
if (effect is AreaReactionEffect)
|
||||
{
|
||||
args.Cancel();
|
||||
args.Cancelled = true;
|
||||
return;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
private void OnReactionAttempt(Entity<SmokeComponent> entity, ref SolutionRelayEvent<ReactionAttemptEvent> args)
|
||||
{
|
||||
if (args.Name == SmokeComponent.SolutionName)
|
||||
OnReactionAttempt(entity, ref args.Event);
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Sets up a smoke component for spreading.
|
||||
/// </summary>
|
||||
@@ -245,14 +254,14 @@ public sealed class SmokeSystem : EntitySystem
|
||||
if (!Resolve(smokeUid, ref component))
|
||||
return;
|
||||
|
||||
if (!_solutionSystem.TryGetSolution(smokeUid, SmokeComponent.SolutionName, out var solution) ||
|
||||
if (!_solutionContainerSystem.ResolveSolution(smokeUid, SmokeComponent.SolutionName, ref component.Solution, out var solution) ||
|
||||
solution.Contents.Count == 0)
|
||||
{
|
||||
return;
|
||||
}
|
||||
|
||||
ReactWithEntity(entity, smokeUid, solution, component);
|
||||
UpdateVisuals(smokeUid);
|
||||
UpdateVisuals((smokeUid, component));
|
||||
}
|
||||
|
||||
private void ReactWithEntity(EntityUid entity, EntityUid smokeUid, Solution solution, SmokeComponent? component = null)
|
||||
@@ -263,11 +272,14 @@ public sealed class SmokeSystem : EntitySystem
|
||||
if (!TryComp<BloodstreamComponent>(entity, out var bloodstream))
|
||||
return;
|
||||
|
||||
var blockIngestion = _internals.AreInternalsWorking(entity);
|
||||
if (!_solutionContainerSystem.ResolveSolution(entity, bloodstream.ChemicalSolutionName, ref bloodstream.ChemicalSolution, out var chemSolution) || chemSolution.AvailableVolume <= 0)
|
||||
return;
|
||||
|
||||
var blockIngestion = _internals.AreInternalsWorking(entity);
|
||||
|
||||
var cloneSolution = solution.Clone();
|
||||
var availableTransfer = FixedPoint2.Min(cloneSolution.Volume, component.TransferRate);
|
||||
var transferAmount = FixedPoint2.Min(availableTransfer, bloodstream.ChemicalSolution.AvailableVolume);
|
||||
var transferAmount = FixedPoint2.Min(availableTransfer, chemSolution.AvailableVolume);
|
||||
var transferSolution = cloneSolution.SplitSolution(transferAmount);
|
||||
|
||||
foreach (var reagentQuantity in transferSolution.Contents.ToArray())
|
||||
@@ -296,7 +308,7 @@ public sealed class SmokeSystem : EntitySystem
|
||||
if (!Resolve(uid, ref component, ref xform))
|
||||
return;
|
||||
|
||||
if (!_solutionSystem.TryGetSolution(uid, SmokeComponent.SolutionName, out var solution) || !solution.Any())
|
||||
if (!_solutionContainerSystem.ResolveSolution(uid, SmokeComponent.SolutionName, ref component.Solution, out var solution) || !solution.Any())
|
||||
return;
|
||||
|
||||
if (!_mapManager.TryGetGrid(xform.GridUid, out var mapGrid))
|
||||
@@ -317,29 +329,30 @@ public sealed class SmokeSystem : EntitySystem
|
||||
/// <summary>
|
||||
/// Adds the specified solution to the relevant smoke solution.
|
||||
/// </summary>
|
||||
private void TryAddSolution(EntityUid uid, Solution solution)
|
||||
private void TryAddSolution(Entity<SmokeComponent?> smoke, Solution solution)
|
||||
{
|
||||
if (solution.Volume == FixedPoint2.Zero)
|
||||
return;
|
||||
|
||||
if (!_solutionSystem.TryGetSolution(uid, SmokeComponent.SolutionName, out var solutionArea))
|
||||
if (!Resolve(smoke, ref smoke.Comp))
|
||||
return;
|
||||
|
||||
var addSolution =
|
||||
solution.SplitSolution(FixedPoint2.Min(solution.Volume, solutionArea.AvailableVolume));
|
||||
if (!_solutionContainerSystem.ResolveSolution(smoke.Owner, SmokeComponent.SolutionName, ref smoke.Comp.Solution, out var solutionArea))
|
||||
return;
|
||||
|
||||
_solutionSystem.TryAddSolution(uid, solutionArea, addSolution);
|
||||
var addSolution = solution.SplitSolution(FixedPoint2.Min(solution.Volume, solutionArea.AvailableVolume));
|
||||
_solutionContainerSystem.TryAddSolution(smoke.Comp.Solution.Value, addSolution);
|
||||
|
||||
UpdateVisuals(uid);
|
||||
UpdateVisuals(smoke);
|
||||
}
|
||||
|
||||
private void UpdateVisuals(EntityUid uid)
|
||||
private void UpdateVisuals(Entity<SmokeComponent?, AppearanceComponent?> smoke)
|
||||
{
|
||||
if (!TryComp(uid, out AppearanceComponent? appearance) ||
|
||||
!_solutionSystem.TryGetSolution(uid, SmokeComponent.SolutionName, out var solution))
|
||||
if (!Resolve(smoke, ref smoke.Comp1, ref smoke.Comp2) ||
|
||||
!_solutionContainerSystem.ResolveSolution(smoke.Owner, SmokeComponent.SolutionName, ref smoke.Comp1.Solution, out var solution))
|
||||
return;
|
||||
|
||||
var color = solution.GetColor(_prototype);
|
||||
_appearance.SetData(uid, SmokeVisuals.Color, color, appearance);
|
||||
_appearance.SetData(smoke.Owner, SmokeVisuals.Color, color, smoke.Comp2);
|
||||
}
|
||||
}
|
||||
|
||||
@@ -1,22 +1,21 @@
|
||||
using System.Numerics;
|
||||
using Content.Server.Chemistry.Components;
|
||||
using Content.Server.Chemistry.Containers.EntitySystems;
|
||||
using Content.Server.Chemistry.EntitySystems;
|
||||
using Content.Server.Cooldown;
|
||||
using Content.Server.Extinguisher;
|
||||
using Content.Server.Fluids.Components;
|
||||
using Content.Server.Gravity;
|
||||
using Content.Server.Popups;
|
||||
using Content.Shared.Chemistry.EntitySystems;
|
||||
using Content.Shared.Cooldown;
|
||||
using Content.Shared.FixedPoint;
|
||||
using Content.Shared.Interaction;
|
||||
using Content.Shared.Vapor;
|
||||
using Robust.Server.GameObjects;
|
||||
using Robust.Shared.Audio;
|
||||
using Robust.Shared.Audio.Systems;
|
||||
using Robust.Shared.Physics.Components;
|
||||
using Robust.Shared.Prototypes;
|
||||
using Robust.Shared.Timing;
|
||||
using System.Numerics;
|
||||
|
||||
namespace Content.Server.Fluids.EntitySystems;
|
||||
|
||||
@@ -40,23 +39,23 @@ public sealed class SpraySystem : EntitySystem
|
||||
SubscribeLocalEvent<SprayComponent, AfterInteractEvent>(OnAfterInteract, after: new[] { typeof(FireExtinguisherSystem) });
|
||||
}
|
||||
|
||||
private void OnAfterInteract(EntityUid uid, SprayComponent component, AfterInteractEvent args)
|
||||
private void OnAfterInteract(Entity<SprayComponent> entity, ref AfterInteractEvent args)
|
||||
{
|
||||
if (args.Handled)
|
||||
return;
|
||||
|
||||
args.Handled = true;
|
||||
|
||||
if (!_solutionContainer.TryGetSolution(uid, SprayComponent.SolutionName, out var solution))
|
||||
if (!_solutionContainer.TryGetSolution(entity.Owner, SprayComponent.SolutionName, out var soln, out var solution))
|
||||
return;
|
||||
|
||||
var ev = new SprayAttemptEvent(args.User);
|
||||
RaiseLocalEvent(uid, ev);
|
||||
RaiseLocalEvent(entity, ev);
|
||||
if (ev.Cancelled)
|
||||
return;
|
||||
|
||||
var curTime = _gameTiming.CurTime;
|
||||
if (TryComp<ItemCooldownComponent>(uid, out var cooldown)
|
||||
if (TryComp<ItemCooldownComponent>(entity, out var cooldown)
|
||||
&& curTime < cooldown.CooldownEnd)
|
||||
{
|
||||
return;
|
||||
@@ -64,8 +63,7 @@ public sealed class SpraySystem : EntitySystem
|
||||
|
||||
if (solution.Volume <= 0)
|
||||
{
|
||||
_popupSystem.PopupEntity(Loc.GetString("spray-component-is-empty-message"), uid,
|
||||
args.User);
|
||||
_popupSystem.PopupEntity(Loc.GetString("spray-component-is-empty-message"), entity.Owner, args.User);
|
||||
return;
|
||||
}
|
||||
|
||||
@@ -82,9 +80,9 @@ public sealed class SpraySystem : EntitySystem
|
||||
var diffNorm = diffPos.Normalized();
|
||||
var diffLength = diffPos.Length();
|
||||
|
||||
if (diffLength > component.SprayDistance)
|
||||
if (diffLength > entity.Comp.SprayDistance)
|
||||
{
|
||||
diffLength = component.SprayDistance;
|
||||
diffLength = entity.Comp.SprayDistance;
|
||||
}
|
||||
|
||||
var diffAngle = diffNorm.ToAngle();
|
||||
@@ -93,8 +91,8 @@ public sealed class SpraySystem : EntitySystem
|
||||
var threeQuarters = diffNorm * 0.75f;
|
||||
var quarter = diffNorm * 0.25f;
|
||||
|
||||
var amount = Math.Max(Math.Min((solution.Volume / component.TransferAmount).Int(), component.VaporAmount), 1);
|
||||
var spread = component.VaporSpread / amount;
|
||||
var amount = Math.Max(Math.Min((solution.Volume / entity.Comp.TransferAmount).Int(), entity.Comp.VaporAmount), 1);
|
||||
var spread = entity.Comp.VaporSpread / amount;
|
||||
// TODO: Just use usedelay homie.
|
||||
var cooldownTime = 0f;
|
||||
|
||||
@@ -108,18 +106,18 @@ public sealed class SpraySystem : EntitySystem
|
||||
.Offset((diffNorm + rotation.ToVec()).Normalized() * diffLength + quarter);
|
||||
|
||||
var distance = (target.Position - userMapPos.Position).Length();
|
||||
if (distance > component.SprayDistance)
|
||||
target = userMapPos.Offset(diffNorm * component.SprayDistance);
|
||||
if (distance > entity.Comp.SprayDistance)
|
||||
target = userMapPos.Offset(diffNorm * entity.Comp.SprayDistance);
|
||||
|
||||
var adjustedSolutionAmount = component.TransferAmount / component.VaporAmount;
|
||||
var newSolution = _solutionContainer.SplitSolution(uid, solution, adjustedSolutionAmount);
|
||||
var adjustedSolutionAmount = entity.Comp.TransferAmount / entity.Comp.VaporAmount;
|
||||
var newSolution = _solutionContainer.SplitSolution(soln.Value, adjustedSolutionAmount);
|
||||
|
||||
if (newSolution.Volume <= FixedPoint2.Zero)
|
||||
break;
|
||||
|
||||
// Spawn the vapor cloud onto the grid/map the user is present on. Offset the start position based on how far the target destination is.
|
||||
var vaporPos = userMapPos.Offset(distance < 1 ? quarter : threeQuarters);
|
||||
var vapor = Spawn(component.SprayedPrototype, vaporPos);
|
||||
var vapor = Spawn(entity.Comp.SprayedPrototype, vaporPos);
|
||||
var vaporXform = xformQuery.GetComponent(vapor);
|
||||
|
||||
_transform.SetWorldRotation(vaporXform, rotation);
|
||||
@@ -137,22 +135,21 @@ public sealed class SpraySystem : EntitySystem
|
||||
|
||||
// impulse direction is defined in world-coordinates, not local coordinates
|
||||
var impulseDirection = rotation.ToVec();
|
||||
var time = diffLength / component.SprayVelocity;
|
||||
var time = diffLength / entity.Comp.SprayVelocity;
|
||||
cooldownTime = MathF.Max(time, cooldownTime);
|
||||
|
||||
_vapor.Start(ent, vaporXform, impulseDirection * diffLength, component.SprayVelocity, target, time, args.User);
|
||||
_vapor.Start(ent, vaporXform, impulseDirection * diffLength, entity.Comp.SprayVelocity, target, time, args.User);
|
||||
|
||||
if (TryComp<PhysicsComponent>(args.User, out var body))
|
||||
{
|
||||
if (_gravity.IsWeightless(args.User, body))
|
||||
_physics.ApplyLinearImpulse(args.User, -impulseDirection.Normalized() * component.PushbackAmount, body: body);
|
||||
_physics.ApplyLinearImpulse(args.User, -impulseDirection.Normalized() * entity.Comp.PushbackAmount, body: body);
|
||||
}
|
||||
}
|
||||
|
||||
_audio.PlayPvs(component.SpraySound, uid, component.SpraySound.Params.WithVariation(0.125f));
|
||||
_audio.PlayPvs(entity.Comp.SpraySound, entity, entity.Comp.SpraySound.Params.WithVariation(0.125f));
|
||||
|
||||
RaiseLocalEvent(uid,
|
||||
new RefreshItemCooldownEvent(curTime, curTime + TimeSpan.FromSeconds(cooldownTime)), true);
|
||||
RaiseLocalEvent(entity, new RefreshItemCooldownEvent(curTime, curTime + TimeSpan.FromSeconds(cooldownTime)), true);
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
Reference in New Issue
Block a user