Puddles & spreader refactor (#15191)
This commit is contained in:
@@ -1,96 +0,0 @@
|
||||
using Content.Server.Body.Components;
|
||||
using Content.Server.Body.Systems;
|
||||
using Content.Server.Chemistry.EntitySystems;
|
||||
using Content.Shared.Administration.Logs;
|
||||
using Content.Shared.Database;
|
||||
using Content.Shared.FixedPoint;
|
||||
using Content.Shared.Foam;
|
||||
using Content.Shared.Inventory;
|
||||
using Robust.Shared.Prototypes;
|
||||
|
||||
namespace Content.Server.Chemistry.Components
|
||||
{
|
||||
[RegisterComponent]
|
||||
[ComponentReference(typeof(SolutionAreaEffectComponent))]
|
||||
public sealed class FoamSolutionAreaEffectComponent : SolutionAreaEffectComponent
|
||||
{
|
||||
[Dependency] private readonly IEntityManager _entMan = default!;
|
||||
[Dependency] private readonly IPrototypeManager _proto = default!;
|
||||
[Dependency] private readonly ISharedAdminLogManager _adminLogger = default!;
|
||||
|
||||
public new const string SolutionName = "solutionArea";
|
||||
|
||||
[DataField("foamedMetalPrototype")] private string? _foamedMetalPrototype;
|
||||
|
||||
protected override void UpdateVisuals()
|
||||
{
|
||||
if (_entMan.TryGetComponent(Owner, out AppearanceComponent? appearance) &&
|
||||
EntitySystem.Get<SolutionContainerSystem>().TryGetSolution(Owner, SolutionName, out var solution))
|
||||
{
|
||||
appearance.SetData(FoamVisuals.Color, solution.GetColor(_proto).WithAlpha(0.80f));
|
||||
}
|
||||
}
|
||||
|
||||
protected override void ReactWithEntity(EntityUid entity, double solutionFraction)
|
||||
{
|
||||
if (!EntitySystem.Get<SolutionContainerSystem>().TryGetSolution(Owner, SolutionName, out var solution))
|
||||
return;
|
||||
|
||||
if (!_entMan.TryGetComponent(entity, out BloodstreamComponent? bloodstream))
|
||||
return;
|
||||
|
||||
var invSystem = EntitySystem.Get<InventorySystem>();
|
||||
|
||||
// TODO: Add a permeability property to clothing
|
||||
// For now it just adds to protection for each clothing equipped
|
||||
var protection = 0f;
|
||||
if (invSystem.TryGetSlots(entity, out var slotDefinitions))
|
||||
{
|
||||
foreach (var slot in slotDefinitions)
|
||||
{
|
||||
if (slot.Name == "back" ||
|
||||
slot.Name == "pocket1" ||
|
||||
slot.Name == "pocket2" ||
|
||||
slot.Name == "id")
|
||||
continue;
|
||||
|
||||
if (invSystem.TryGetSlotEntity(entity, slot.Name, out _))
|
||||
protection += 0.025f;
|
||||
}
|
||||
}
|
||||
|
||||
var bloodstreamSys = EntitySystem.Get<BloodstreamSystem>();
|
||||
|
||||
var cloneSolution = solution.Clone();
|
||||
var transferAmount = FixedPoint2.Min(cloneSolution.Volume * solutionFraction * (1 - protection),
|
||||
bloodstream.ChemicalSolution.AvailableVolume);
|
||||
var transferSolution = cloneSolution.SplitSolution(transferAmount);
|
||||
|
||||
if (bloodstreamSys.TryAddToChemicals(entity, transferSolution, bloodstream))
|
||||
{
|
||||
// Log solution addition by foam
|
||||
_adminLogger.Add(LogType.ForceFeed, LogImpact.Medium, $"{_entMan.ToPrettyString(entity):target} was affected by foam {SolutionContainerSystem.ToPrettyString(transferSolution)}");
|
||||
}
|
||||
}
|
||||
|
||||
protected override void OnKill()
|
||||
{
|
||||
if (_entMan.Deleted(Owner))
|
||||
return;
|
||||
if (_entMan.TryGetComponent(Owner, out AppearanceComponent? appearance))
|
||||
{
|
||||
appearance.SetData(FoamVisuals.State, true);
|
||||
}
|
||||
|
||||
Owner.SpawnTimer(600, () =>
|
||||
{
|
||||
if (!string.IsNullOrEmpty(_foamedMetalPrototype))
|
||||
{
|
||||
_entMan.SpawnEntity(_foamedMetalPrototype, _entMan.GetComponent<TransformComponent>(Owner).Coordinates);
|
||||
}
|
||||
|
||||
_entMan.QueueDeleteEntity(Owner);
|
||||
});
|
||||
}
|
||||
}
|
||||
}
|
||||
26
Content.Server/Chemistry/Components/SmokeComponent.cs
Normal file
26
Content.Server/Chemistry/Components/SmokeComponent.cs
Normal file
@@ -0,0 +1,26 @@
|
||||
using Content.Shared.Fluids.Components;
|
||||
using Robust.Shared.Serialization.TypeSerializers.Implementations.Custom;
|
||||
|
||||
namespace Content.Server.Chemistry.Components;
|
||||
|
||||
/// <summary>
|
||||
/// Stores solution on an anchored entity that has touch and ingestion reactions
|
||||
/// to entities that collide with it. Similar to <see cref="PuddleComponent"/>
|
||||
/// </summary>
|
||||
[RegisterComponent]
|
||||
public sealed class SmokeComponent : Component
|
||||
{
|
||||
public const string SolutionName = "solutionArea";
|
||||
|
||||
[DataField("nextReact", customTypeSerializer:typeof(TimeOffsetSerializer))]
|
||||
public TimeSpan NextReact = TimeSpan.Zero;
|
||||
|
||||
[DataField("spreadAmount")]
|
||||
public int SpreadAmount = 0;
|
||||
|
||||
/// <summary>
|
||||
/// Have we reacted with our tile yet?
|
||||
/// </summary>
|
||||
[DataField("reactedTile")]
|
||||
public bool ReactedTile = false;
|
||||
}
|
||||
@@ -0,0 +1,16 @@
|
||||
using Content.Server.Fluids.EntitySystems;
|
||||
using Robust.Shared.Prototypes;
|
||||
using Robust.Shared.Serialization.TypeSerializers.Implementations.Custom.Prototype;
|
||||
|
||||
namespace Content.Server.Chemistry.Components;
|
||||
|
||||
|
||||
/// <summary>
|
||||
/// When a <see cref="SmokeComponent"/> despawns this will spawn another entity in its place.
|
||||
/// </summary>
|
||||
[RegisterComponent, Access(typeof(SmokeSystem))]
|
||||
public sealed class SmokeDissipateSpawnComponent : Component
|
||||
{
|
||||
[DataField("prototype", required: true, customTypeSerializer:typeof(PrototypeIdSerializer<EntityPrototype>))]
|
||||
public string Prototype = string.Empty;
|
||||
}
|
||||
@@ -1,72 +0,0 @@
|
||||
using Content.Server.Body.Components;
|
||||
using Content.Server.Body.Systems;
|
||||
using Content.Server.Chemistry.EntitySystems;
|
||||
using Content.Shared.Administration.Logs;
|
||||
using Content.Shared.Chemistry;
|
||||
using Content.Shared.Chemistry.Reagent;
|
||||
using Content.Shared.Database;
|
||||
using Content.Shared.FixedPoint;
|
||||
using Content.Shared.Smoking;
|
||||
using Robust.Shared.Prototypes;
|
||||
|
||||
namespace Content.Server.Chemistry.Components
|
||||
{
|
||||
[RegisterComponent]
|
||||
[ComponentReference(typeof(SolutionAreaEffectComponent))]
|
||||
public sealed class SmokeSolutionAreaEffectComponent : SolutionAreaEffectComponent
|
||||
{
|
||||
[Dependency] private readonly IEntityManager _entMan = default!;
|
||||
[Dependency] private readonly IPrototypeManager _proto = default!;
|
||||
[Dependency] private readonly ISharedAdminLogManager _adminLogger = default!;
|
||||
|
||||
public new const string SolutionName = "solutionArea";
|
||||
|
||||
protected override void UpdateVisuals()
|
||||
{
|
||||
if (_entMan.TryGetComponent(Owner, out AppearanceComponent? appearance) &&
|
||||
EntitySystem.Get<SolutionContainerSystem>().TryGetSolution(Owner, SolutionName, out var solution))
|
||||
{
|
||||
appearance.SetData(SmokeVisuals.Color, solution.GetColor(_proto));
|
||||
}
|
||||
}
|
||||
|
||||
protected override void ReactWithEntity(EntityUid entity, double solutionFraction)
|
||||
{
|
||||
if (!EntitySystem.Get<SolutionContainerSystem>().TryGetSolution(Owner, SolutionName, out var solution))
|
||||
return;
|
||||
|
||||
if (!_entMan.TryGetComponent(entity, out BloodstreamComponent? bloodstream))
|
||||
return;
|
||||
|
||||
if (_entMan.TryGetComponent(entity, out InternalsComponent? internals) &&
|
||||
IoCManager.Resolve<IEntitySystemManager>().GetEntitySystem<InternalsSystem>().AreInternalsWorking(internals))
|
||||
return;
|
||||
|
||||
var chemistry = EntitySystem.Get<ReactiveSystem>();
|
||||
var cloneSolution = solution.Clone();
|
||||
var transferAmount = FixedPoint2.Min(cloneSolution.Volume * solutionFraction, bloodstream.ChemicalSolution.AvailableVolume);
|
||||
var transferSolution = cloneSolution.SplitSolution(transferAmount);
|
||||
|
||||
foreach (var reagentQuantity in transferSolution.Contents.ToArray())
|
||||
{
|
||||
if (reagentQuantity.Quantity == FixedPoint2.Zero) continue;
|
||||
chemistry.ReactionEntity(entity, ReactionMethod.Ingestion, reagentQuantity.ReagentId, reagentQuantity.Quantity, transferSolution);
|
||||
}
|
||||
|
||||
var bloodstreamSys = EntitySystem.Get<BloodstreamSystem>();
|
||||
if (bloodstreamSys.TryAddToChemicals(entity, transferSolution, bloodstream))
|
||||
{
|
||||
// Log solution addition by smoke
|
||||
_adminLogger.Add(LogType.ForceFeed, LogImpact.Medium, $"{_entMan.ToPrettyString(entity):target} was affected by smoke {SolutionContainerSystem.ToPrettyString(transferSolution)}");
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
protected override void OnKill()
|
||||
{
|
||||
if (_entMan.Deleted(Owner))
|
||||
return;
|
||||
_entMan.DeleteEntity(Owner);
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -1,219 +0,0 @@
|
||||
using System.Linq;
|
||||
using Content.Server.Atmos.Components;
|
||||
using Content.Server.Chemistry.EntitySystems;
|
||||
using Content.Shared.Chemistry;
|
||||
using Content.Shared.Chemistry.Components;
|
||||
using Content.Shared.Chemistry.Reagent;
|
||||
using Content.Shared.FixedPoint;
|
||||
using Robust.Shared.Map;
|
||||
using Robust.Shared.Map.Components;
|
||||
using Robust.Shared.Prototypes;
|
||||
using Robust.Shared.Utility;
|
||||
|
||||
namespace Content.Server.Chemistry.Components
|
||||
{
|
||||
/// <summary>
|
||||
/// Used to clone its owner repeatedly and group up them all so they behave like one unit, that way you can have
|
||||
/// effects that cover an area. Inherited by <see cref="SmokeSolutionAreaEffectComponent"/> and <see cref="FoamSolutionAreaEffectComponent"/>.
|
||||
/// </summary>
|
||||
public abstract class SolutionAreaEffectComponent : Component
|
||||
{
|
||||
public const string SolutionName = "solutionArea";
|
||||
|
||||
[Dependency] protected readonly IMapManager MapManager = default!;
|
||||
[Dependency] protected readonly IPrototypeManager PrototypeManager = default!;
|
||||
[Dependency] private readonly IEntityManager _entities = default!;
|
||||
[Dependency] private readonly IEntitySystemManager _systems = default!;
|
||||
|
||||
public int Amount { get; set; }
|
||||
public SolutionAreaEffectInceptionComponent? Inception { get; set; }
|
||||
|
||||
/// <summary>
|
||||
/// Have we reacted with our tile yet?
|
||||
/// </summary>
|
||||
public bool ReactedTile = false;
|
||||
|
||||
/// <summary>
|
||||
/// Adds an <see cref="SolutionAreaEffectInceptionComponent"/> to owner so the effect starts spreading and reacting.
|
||||
/// </summary>
|
||||
/// <param name="amount">The range of the effect</param>
|
||||
/// <param name="duration"></param>
|
||||
/// <param name="spreadDelay"></param>
|
||||
/// <param name="removeDelay"></param>
|
||||
public void Start(int amount, float duration, float spreadDelay, float removeDelay)
|
||||
{
|
||||
if (Inception != null)
|
||||
return;
|
||||
|
||||
if (_entities.HasComponent<SolutionAreaEffectInceptionComponent>(Owner))
|
||||
return;
|
||||
|
||||
Amount = amount;
|
||||
var inception = _entities.AddComponent<SolutionAreaEffectInceptionComponent>(Owner);
|
||||
|
||||
inception.Add(this);
|
||||
inception.Setup(amount, duration, spreadDelay, removeDelay);
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Gets called by an AreaEffectInceptionComponent. "Clones" Owner into the four directions and copies the
|
||||
/// solution into each of them.
|
||||
/// </summary>
|
||||
public void Spread()
|
||||
{
|
||||
var meta = _entities.GetComponent<MetaDataComponent>(Owner);
|
||||
if (meta.EntityPrototype == null)
|
||||
{
|
||||
Logger.Error("AreaEffectComponent needs its owner to be spawned by a prototype.");
|
||||
return;
|
||||
}
|
||||
|
||||
var xform = _entities.GetComponent<TransformComponent>(Owner);
|
||||
var solSys = _systems.GetEntitySystem<SolutionContainerSystem>();
|
||||
|
||||
if (!_entities.TryGetComponent(xform.GridUid, out MapGridComponent? gridComp))
|
||||
return;
|
||||
|
||||
var origin = gridComp.TileIndicesFor(xform.Coordinates);
|
||||
|
||||
DebugTools.Assert(xform.Anchored, "Area effect entity prototypes must be anchored.");
|
||||
|
||||
void SpreadToDir(Direction dir)
|
||||
{
|
||||
// Currently no support for spreading off or across grids.
|
||||
var index = origin + dir.ToIntVec();
|
||||
if (!gridComp.TryGetTileRef(index, out var tile) || tile.Tile.IsEmpty)
|
||||
return;
|
||||
|
||||
foreach (var neighbor in gridComp.GetAnchoredEntities(index))
|
||||
{
|
||||
if (_entities.TryGetComponent(neighbor,
|
||||
out SolutionAreaEffectComponent? comp) && comp.Inception == Inception)
|
||||
return;
|
||||
|
||||
// TODO for thindows and the like, need to check the directions that are being blocked.
|
||||
// --> would then also mean you need to check for blockers on the origin tile.
|
||||
if (_entities.TryGetComponent(neighbor,
|
||||
out AirtightComponent? airtight) && airtight.AirBlocked)
|
||||
return;
|
||||
}
|
||||
|
||||
var newEffect = _entities.SpawnEntity(
|
||||
meta.EntityPrototype.ID,
|
||||
gridComp.GridTileToLocal(index));
|
||||
|
||||
if (!_entities.TryGetComponent(newEffect, out SolutionAreaEffectComponent? effectComponent))
|
||||
{
|
||||
_entities.DeleteEntity(newEffect);
|
||||
return;
|
||||
}
|
||||
|
||||
if (solSys.TryGetSolution(Owner, SolutionName, out var solution))
|
||||
{
|
||||
effectComponent.TryAddSolution(solution.Clone());
|
||||
}
|
||||
|
||||
effectComponent.Amount = Amount - 1;
|
||||
Inception?.Add(effectComponent);
|
||||
}
|
||||
|
||||
SpreadToDir(Direction.North);
|
||||
SpreadToDir(Direction.East);
|
||||
SpreadToDir(Direction.South);
|
||||
SpreadToDir(Direction.West);
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Gets called by an AreaEffectInceptionComponent.
|
||||
/// Removes this component from its inception and calls OnKill(). The implementation of OnKill() should
|
||||
/// eventually delete the entity.
|
||||
/// </summary>
|
||||
public void Kill()
|
||||
{
|
||||
Inception?.Remove(this);
|
||||
OnKill();
|
||||
}
|
||||
|
||||
protected abstract void OnKill();
|
||||
|
||||
/// <summary>
|
||||
/// Gets called by an AreaEffectInceptionComponent.
|
||||
/// Makes this effect's reagents react with the tile its on and with the entities it covers. Also calls
|
||||
/// ReactWithEntity on the entities so inheritors can implement more specific behavior.
|
||||
/// </summary>
|
||||
/// <param name="averageExposures">How many times will this get called over this area effect's duration, averaged
|
||||
/// with the other area effects from the inception.</param>
|
||||
public void React(float averageExposures)
|
||||
{
|
||||
if (!_entities.EntitySysManager.GetEntitySystem<SolutionContainerSystem>()
|
||||
.TryGetSolution(Owner, SolutionName, out var solution) ||
|
||||
solution.Contents.Count == 0)
|
||||
{
|
||||
return;
|
||||
}
|
||||
|
||||
var xform = _entities.GetComponent<TransformComponent>(Owner);
|
||||
if (!MapManager.TryGetGrid(xform.GridUid, out var mapGrid))
|
||||
return;
|
||||
|
||||
var tile = mapGrid.GetTileRef(xform.Coordinates.ToVector2i(_entities, MapManager));
|
||||
var chemistry = _entities.EntitySysManager.GetEntitySystem<ReactiveSystem>();
|
||||
var lookup = _entities.EntitySysManager.GetEntitySystem<EntityLookupSystem>();
|
||||
|
||||
var solutionFraction = 1 / Math.Floor(averageExposures);
|
||||
var ents = lookup.GetEntitiesIntersecting(tile, LookupFlags.Uncontained).ToArray();
|
||||
|
||||
foreach (var reagentQuantity in solution.Contents.ToArray())
|
||||
{
|
||||
if (reagentQuantity.Quantity == FixedPoint2.Zero) continue;
|
||||
var reagent = PrototypeManager.Index<ReagentPrototype>(reagentQuantity.ReagentId);
|
||||
|
||||
// React with the tile the effect is on
|
||||
// We don't multiply by solutionFraction here since the tile is only ever reacted once
|
||||
if (!ReactedTile)
|
||||
{
|
||||
reagent.ReactionTile(tile, reagentQuantity.Quantity);
|
||||
ReactedTile = true;
|
||||
}
|
||||
|
||||
// Touch every entity on the tile
|
||||
foreach (var entity in ents)
|
||||
{
|
||||
chemistry.ReactionEntity(entity, ReactionMethod.Touch, reagent,
|
||||
reagentQuantity.Quantity * solutionFraction, solution);
|
||||
}
|
||||
}
|
||||
|
||||
foreach (var entity in ents)
|
||||
{
|
||||
ReactWithEntity(entity, solutionFraction);
|
||||
}
|
||||
}
|
||||
|
||||
protected abstract void ReactWithEntity(EntityUid entity, double solutionFraction);
|
||||
|
||||
public void TryAddSolution(Solution solution)
|
||||
{
|
||||
if (solution.Volume == 0)
|
||||
return;
|
||||
|
||||
if (!EntitySystem.Get<SolutionContainerSystem>().TryGetSolution(Owner, SolutionName, out var solutionArea))
|
||||
return;
|
||||
|
||||
var addSolution =
|
||||
solution.SplitSolution(FixedPoint2.Min(solution.Volume, solutionArea.AvailableVolume));
|
||||
|
||||
EntitySystem.Get<SolutionContainerSystem>().TryAddSolution(Owner, solutionArea, addSolution);
|
||||
|
||||
UpdateVisuals();
|
||||
}
|
||||
|
||||
protected abstract void UpdateVisuals();
|
||||
|
||||
protected override void OnRemove()
|
||||
{
|
||||
base.OnRemove();
|
||||
Inception?.Remove(this);
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -1,136 +0,0 @@
|
||||
using System.Linq;
|
||||
|
||||
namespace Content.Server.Chemistry.Components
|
||||
{
|
||||
/// <summary>
|
||||
/// The "mastermind" of a SolutionAreaEffect group. It gets updated by the SolutionAreaEffectSystem and tells the
|
||||
/// group when to spread, react and remove itself. This makes the group act like a single unit.
|
||||
/// </summary>
|
||||
/// <remarks> It should only be manually added to an entity by the <see cref="SolutionAreaEffectComponent"/> and not with a prototype.</remarks>
|
||||
[RegisterComponent]
|
||||
public sealed class SolutionAreaEffectInceptionComponent : Component
|
||||
{
|
||||
private const float ReactionDelay = 1.5f;
|
||||
|
||||
private readonly HashSet<SolutionAreaEffectComponent> _group = new();
|
||||
|
||||
[ViewVariables] private float _lifeTimer;
|
||||
[ViewVariables] private float _spreadTimer;
|
||||
[ViewVariables] private float _reactionTimer;
|
||||
|
||||
[ViewVariables] private int _amountCounterSpreading;
|
||||
[ViewVariables] private int _amountCounterRemoving;
|
||||
|
||||
/// <summary>
|
||||
/// How much time to wait after fully spread before starting to remove itself.
|
||||
/// </summary>
|
||||
[ViewVariables] private float _duration;
|
||||
|
||||
/// <summary>
|
||||
/// Time between each spread step. Decreasing this makes spreading faster.
|
||||
/// </summary>
|
||||
[ViewVariables] private float _spreadDelay;
|
||||
|
||||
/// <summary>
|
||||
/// Time between each remove step. Decreasing this makes removing faster.
|
||||
/// </summary>
|
||||
[ViewVariables] private float _removeDelay;
|
||||
|
||||
/// <summary>
|
||||
/// How many times will the effect react. As some entities from the group last a different amount of time than
|
||||
/// others, they will react a different amount of times, so we calculate the average to make the group behave
|
||||
/// a bit more uniformly.
|
||||
/// </summary>
|
||||
[ViewVariables] private float _averageExposures;
|
||||
|
||||
public void Setup(int amount, float duration, float spreadDelay, float removeDelay)
|
||||
{
|
||||
_amountCounterSpreading = amount;
|
||||
_duration = duration;
|
||||
_spreadDelay = spreadDelay;
|
||||
_removeDelay = removeDelay;
|
||||
|
||||
// So the first square reacts immediately after spawning
|
||||
_reactionTimer = ReactionDelay;
|
||||
/*
|
||||
The group takes amount*spreadDelay seconds to fully spread, same with fully disappearing.
|
||||
The outer squares will last duration seconds.
|
||||
The first square will last duration + how many seconds the group takes to fully spread and fully disappear, so
|
||||
it will last duration + amount*(spreadDelay+removeDelay).
|
||||
Thus, the average lifetime of the smokes will be (outerSmokeLifetime + firstSmokeLifetime)/2 = duration + amount*(spreadDelay+removeDelay)/2
|
||||
*/
|
||||
_averageExposures = (duration + amount * (spreadDelay+removeDelay) / 2)/ReactionDelay;
|
||||
}
|
||||
|
||||
public void InceptionUpdate(float frameTime)
|
||||
{
|
||||
_group.RemoveWhere(effect => effect.Deleted);
|
||||
if (_group.Count == 0)
|
||||
return;
|
||||
|
||||
// Make every outer square from the group spread
|
||||
if (_amountCounterSpreading > 0)
|
||||
{
|
||||
_spreadTimer += frameTime;
|
||||
if (_spreadTimer > _spreadDelay)
|
||||
{
|
||||
_spreadTimer -= _spreadDelay;
|
||||
|
||||
var outerEffects = new HashSet<SolutionAreaEffectComponent>(_group.Where(effect => effect.Amount == _amountCounterSpreading));
|
||||
foreach (var effect in outerEffects)
|
||||
{
|
||||
effect.Spread();
|
||||
}
|
||||
|
||||
_amountCounterSpreading -= 1;
|
||||
}
|
||||
}
|
||||
// Start counting for _duration after fully spreading
|
||||
else
|
||||
{
|
||||
_lifeTimer += frameTime;
|
||||
}
|
||||
|
||||
// Delete every outer square
|
||||
if (_lifeTimer > _duration)
|
||||
{
|
||||
_spreadTimer += frameTime;
|
||||
if (_spreadTimer > _removeDelay)
|
||||
{
|
||||
_spreadTimer -= _removeDelay;
|
||||
|
||||
var outerEffects = new HashSet<SolutionAreaEffectComponent>(_group.Where(effect => effect.Amount == _amountCounterRemoving));
|
||||
foreach (var effect in outerEffects)
|
||||
{
|
||||
effect.Kill();
|
||||
}
|
||||
|
||||
_amountCounterRemoving += 1;
|
||||
}
|
||||
}
|
||||
|
||||
// Make every square from the group react with the tile and entities
|
||||
_reactionTimer += frameTime;
|
||||
if (_reactionTimer > ReactionDelay)
|
||||
{
|
||||
_reactionTimer -= ReactionDelay;
|
||||
foreach (var effect in _group)
|
||||
{
|
||||
effect.React(_averageExposures);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
public void Add(SolutionAreaEffectComponent effect)
|
||||
{
|
||||
_group.Add(effect);
|
||||
effect.Inception = this;
|
||||
}
|
||||
|
||||
public void Remove(SolutionAreaEffectComponent effect)
|
||||
{
|
||||
_group.Remove(effect);
|
||||
effect.Inception = null;
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -1,17 +0,0 @@
|
||||
namespace Content.Server.Chemistry.Components.SolutionManager
|
||||
{
|
||||
/// <summary>
|
||||
/// Denotes the solution that can be easily removed through any reagent container.
|
||||
/// Think pouring this or draining from a water tank.
|
||||
/// </summary>
|
||||
[RegisterComponent]
|
||||
public sealed class DrainableSolutionComponent : Component
|
||||
{
|
||||
/// <summary>
|
||||
/// Solution name that can be drained.
|
||||
/// </summary>
|
||||
[ViewVariables(VVAccess.ReadWrite)]
|
||||
[DataField("solution")]
|
||||
public string Solution { get; set; } = "default";
|
||||
}
|
||||
}
|
||||
@@ -1,29 +0,0 @@
|
||||
using Content.Shared.FixedPoint;
|
||||
|
||||
namespace Content.Server.Chemistry.Components.SolutionManager
|
||||
{
|
||||
/// <summary>
|
||||
/// Reagents that can be added easily. For example like
|
||||
/// pouring something into another beaker, glass, or into the gas
|
||||
/// tank of a car.
|
||||
/// </summary>
|
||||
[RegisterComponent]
|
||||
public sealed class RefillableSolutionComponent : Component
|
||||
{
|
||||
/// <summary>
|
||||
/// Solution name that can added to easily.
|
||||
/// </summary>
|
||||
[ViewVariables(VVAccess.ReadWrite)]
|
||||
[DataField("solution")]
|
||||
public string Solution { get; set; } = "default";
|
||||
|
||||
/// <summary>
|
||||
/// The maximum amount that can be transferred to the solution at once
|
||||
/// </summary>
|
||||
[DataField("maxRefill")]
|
||||
[ViewVariables(VVAccess.ReadWrite)]
|
||||
public FixedPoint2? MaxRefill { get; set; } = null;
|
||||
|
||||
|
||||
}
|
||||
}
|
||||
Reference in New Issue
Block a user