Generalize ReagentUnit into FixedPoint2 and use it for damage calculations (#5151)
* Damage units * sum ext method
This commit is contained in:
@@ -2,6 +2,7 @@ using System;
|
||||
using Content.Shared.Chemistry;
|
||||
using Content.Shared.Chemistry.Reagent;
|
||||
using Content.Shared.Eui;
|
||||
using Content.Shared.FixedPoint;
|
||||
using Robust.Shared.Serialization;
|
||||
|
||||
namespace Content.Shared.Administration
|
||||
@@ -9,8 +10,8 @@ namespace Content.Shared.Administration
|
||||
[Serializable, NetSerializable]
|
||||
public sealed class AdminAddReagentEuiState : EuiStateBase
|
||||
{
|
||||
public ReagentUnit MaxVolume;
|
||||
public ReagentUnit CurVolume;
|
||||
public FixedPoint2 MaxVolume;
|
||||
public FixedPoint2 CurVolume;
|
||||
}
|
||||
|
||||
public static class AdminAddReagentEuiMsg
|
||||
@@ -25,7 +26,7 @@ namespace Content.Shared.Administration
|
||||
public sealed class DoAdd : EuiMessageBase
|
||||
{
|
||||
public bool CloseAfter;
|
||||
public ReagentUnit Amount;
|
||||
public FixedPoint2 Amount;
|
||||
public string ReagentId = string.Empty;
|
||||
}
|
||||
}
|
||||
|
||||
@@ -1,6 +1,7 @@
|
||||
using Content.Shared.Chemistry.Components;
|
||||
using Content.Shared.Chemistry.Reaction;
|
||||
using Content.Shared.Chemistry.Reagent;
|
||||
using Content.Shared.FixedPoint;
|
||||
using JetBrains.Annotations;
|
||||
using Robust.Shared.GameObjects;
|
||||
using Robust.Shared.IoC;
|
||||
@@ -21,14 +22,14 @@ namespace Content.Shared.Chemistry
|
||||
}
|
||||
}
|
||||
|
||||
public void ReactionEntity(IEntity entity, ReactionMethod method, string reagentId, ReagentUnit reactVolume, Solution? source)
|
||||
public void ReactionEntity(IEntity entity, ReactionMethod method, string reagentId, FixedPoint2 reactVolume, Solution? source)
|
||||
{
|
||||
// We throw if the reagent specified doesn't exist.
|
||||
ReactionEntity(entity, method, _prototypeManager.Index<ReagentPrototype>(reagentId), reactVolume, source);
|
||||
}
|
||||
|
||||
public void ReactionEntity(IEntity entity, ReactionMethod method, ReagentPrototype reagent,
|
||||
ReagentUnit reactVolume, Solution? source)
|
||||
FixedPoint2 reactVolume, Solution? source)
|
||||
{
|
||||
if (entity == null || entity.Deleted || !entity.TryGetComponent(out ReactiveComponent? reactive))
|
||||
return;
|
||||
|
||||
@@ -3,6 +3,7 @@ using System.Collections.Generic;
|
||||
using System.Collections.ObjectModel;
|
||||
using Content.Shared.Chemistry.Reagent;
|
||||
using Content.Shared.Cloning;
|
||||
using Content.Shared.FixedPoint;
|
||||
using Robust.Shared.GameObjects;
|
||||
using Robust.Shared.Serialization;
|
||||
|
||||
@@ -22,8 +23,8 @@ namespace Content.Shared.Chemistry.Components
|
||||
{
|
||||
public readonly bool HasPower;
|
||||
public readonly bool HasBeaker;
|
||||
public readonly ReagentUnit BeakerCurrentVolume;
|
||||
public readonly ReagentUnit BeakerMaxVolume;
|
||||
public readonly FixedPoint2 BeakerCurrentVolume;
|
||||
public readonly FixedPoint2 BeakerMaxVolume;
|
||||
public readonly string ContainerName;
|
||||
|
||||
/// <summary>
|
||||
@@ -38,10 +39,10 @@ namespace Content.Shared.Chemistry.Components
|
||||
|
||||
public readonly bool BufferModeTransfer;
|
||||
|
||||
public readonly ReagentUnit BufferCurrentVolume;
|
||||
public readonly FixedPoint2 BufferCurrentVolume;
|
||||
|
||||
public ChemMasterBoundUserInterfaceState(bool hasPower, bool hasBeaker, ReagentUnit beakerCurrentVolume, ReagentUnit beakerMaxVolume, string containerName,
|
||||
string dispenserName, IReadOnlyList<Solution.ReagentQuantity> containerReagents, IReadOnlyList<Solution.ReagentQuantity> bufferReagents, bool bufferModeTransfer, ReagentUnit bufferCurrentVolume)
|
||||
public ChemMasterBoundUserInterfaceState(bool hasPower, bool hasBeaker, FixedPoint2 beakerCurrentVolume, FixedPoint2 beakerMaxVolume, string containerName,
|
||||
string dispenserName, IReadOnlyList<Solution.ReagentQuantity> containerReagents, IReadOnlyList<Solution.ReagentQuantity> bufferReagents, bool bufferModeTransfer, FixedPoint2 bufferCurrentVolume)
|
||||
{
|
||||
HasPower = hasPower;
|
||||
HasBeaker = hasBeaker;
|
||||
@@ -63,13 +64,13 @@ namespace Content.Shared.Chemistry.Components
|
||||
public class UiActionMessage : BoundUserInterfaceMessage
|
||||
{
|
||||
public readonly UiAction action;
|
||||
public readonly ReagentUnit amount;
|
||||
public readonly FixedPoint2 amount;
|
||||
public readonly string id = "";
|
||||
public readonly bool isBuffer;
|
||||
public readonly int pillAmount;
|
||||
public readonly int bottleAmount;
|
||||
|
||||
public UiActionMessage(UiAction _action, ReagentUnit? _amount, string? _id, bool? _isBuffer, int? _pillAmount, int? _bottleAmount)
|
||||
public UiActionMessage(UiAction _action, FixedPoint2? _amount, string? _id, bool? _isBuffer, int? _pillAmount, int? _bottleAmount)
|
||||
{
|
||||
action = _action;
|
||||
if (action == UiAction.ChemButton)
|
||||
|
||||
@@ -1,5 +1,6 @@
|
||||
using System;
|
||||
using Content.Shared.Chemistry.Reagent;
|
||||
using Content.Shared.FixedPoint;
|
||||
using Robust.Shared.GameObjects;
|
||||
using Robust.Shared.GameStates;
|
||||
using Robust.Shared.Serialization;
|
||||
@@ -15,10 +16,10 @@ namespace Content.Shared.Chemistry.Components
|
||||
[Serializable, NetSerializable]
|
||||
protected sealed class HyposprayComponentState : ComponentState
|
||||
{
|
||||
public ReagentUnit CurVolume { get; }
|
||||
public ReagentUnit MaxVolume { get; }
|
||||
public FixedPoint2 CurVolume { get; }
|
||||
public FixedPoint2 MaxVolume { get; }
|
||||
|
||||
public HyposprayComponentState(ReagentUnit curVolume, ReagentUnit maxVolume)
|
||||
public HyposprayComponentState(FixedPoint2 curVolume, FixedPoint2 maxVolume)
|
||||
{
|
||||
CurVolume = curVolume;
|
||||
MaxVolume = maxVolume;
|
||||
|
||||
@@ -1,5 +1,6 @@
|
||||
using System;
|
||||
using Content.Shared.Chemistry.Reagent;
|
||||
using Content.Shared.FixedPoint;
|
||||
using Robust.Shared.GameObjects;
|
||||
using Robust.Shared.GameStates;
|
||||
using Robust.Shared.Serialization;
|
||||
@@ -20,11 +21,11 @@ namespace Content.Shared.Chemistry.Components
|
||||
[Serializable, NetSerializable]
|
||||
protected sealed class InjectorComponentState : ComponentState
|
||||
{
|
||||
public ReagentUnit CurrentVolume { get; }
|
||||
public ReagentUnit TotalVolume { get; }
|
||||
public FixedPoint2 CurrentVolume { get; }
|
||||
public FixedPoint2 TotalVolume { get; }
|
||||
public InjectorToggleMode CurrentMode { get; }
|
||||
|
||||
public InjectorComponentState(ReagentUnit currentVolume, ReagentUnit totalVolume, InjectorToggleMode currentMode)
|
||||
public InjectorComponentState(FixedPoint2 currentVolume, FixedPoint2 totalVolume, InjectorToggleMode currentMode)
|
||||
{
|
||||
CurrentVolume = currentVolume;
|
||||
TotalVolume = totalVolume;
|
||||
|
||||
@@ -1,4 +1,5 @@
|
||||
using Content.Shared.Chemistry.Reagent;
|
||||
using Content.Shared.FixedPoint;
|
||||
using Robust.Shared.Serialization.Manager.Attributes;
|
||||
using Robust.Shared.ViewVariables;
|
||||
|
||||
@@ -18,10 +19,10 @@ namespace Content.Shared.Chemistry.Components
|
||||
/// Volume needed to fill this container.
|
||||
/// </summary>
|
||||
[ViewVariables]
|
||||
public ReagentUnit AvailableVolume => MaxVolume - CurrentVolume;
|
||||
public FixedPoint2 AvailableVolume => MaxVolume - CurrentVolume;
|
||||
|
||||
public ReagentUnit DrawAvailable => CurrentVolume;
|
||||
public ReagentUnit DrainAvailable => CurrentVolume;
|
||||
public FixedPoint2 DrawAvailable => CurrentVolume;
|
||||
public FixedPoint2 DrainAvailable => CurrentVolume;
|
||||
|
||||
/// <summary>
|
||||
/// Checks if a solution can fit into the container.
|
||||
@@ -34,18 +35,18 @@ namespace Content.Shared.Chemistry.Components
|
||||
}
|
||||
|
||||
[DataField("maxSpillRefill")]
|
||||
public ReagentUnit MaxSpillRefill { get; set; }
|
||||
public FixedPoint2 MaxSpillRefill { get; set; }
|
||||
|
||||
/// <summary>
|
||||
/// Initially set <see cref="MaxVolume"/>. If empty will be calculated based
|
||||
/// on sum of <see cref="Contents"/> reagent units.
|
||||
/// on sum of <see cref="Contents"/> fixed units.
|
||||
/// </summary>
|
||||
[DataField("maxVol")] public ReagentUnit InitialMaxVolume;
|
||||
[DataField("maxVol")] public FixedPoint2 InitialMaxVolume;
|
||||
|
||||
[ViewVariables(VVAccess.ReadWrite)]
|
||||
public ReagentUnit MaxVolume { get; set; } = ReagentUnit.Zero;
|
||||
public FixedPoint2 MaxVolume { get; set; } = FixedPoint2.Zero;
|
||||
|
||||
[ViewVariables]
|
||||
public ReagentUnit CurrentVolume => TotalVolume;
|
||||
public FixedPoint2 CurrentVolume => TotalVolume;
|
||||
}
|
||||
}
|
||||
|
||||
@@ -4,6 +4,7 @@ using System.Collections.Generic;
|
||||
using System.Diagnostics.CodeAnalysis;
|
||||
using System.Linq;
|
||||
using Content.Shared.Chemistry.Reagent;
|
||||
using Content.Shared.FixedPoint;
|
||||
using Robust.Shared.GameObjects;
|
||||
using Robust.Shared.IoC;
|
||||
using Robust.Shared.Maths;
|
||||
@@ -32,7 +33,7 @@ namespace Content.Shared.Chemistry.Components
|
||||
/// The calculated total volume of all reagents in the solution (ex. Total volume of liquid in beaker).
|
||||
/// </summary>
|
||||
[ViewVariables]
|
||||
public ReagentUnit TotalVolume { get; set; }
|
||||
public FixedPoint2 TotalVolume { get; set; }
|
||||
|
||||
public Color Color => GetColor();
|
||||
|
||||
@@ -46,14 +47,14 @@ namespace Content.Shared.Chemistry.Components
|
||||
/// </summary>
|
||||
/// <param name="reagentId">The prototype ID of the reagent to add.</param>
|
||||
/// <param name="quantity">The quantity in milli-units.</param>
|
||||
public Solution(string reagentId, ReagentUnit quantity)
|
||||
public Solution(string reagentId, FixedPoint2 quantity)
|
||||
{
|
||||
AddReagent(reagentId, quantity);
|
||||
}
|
||||
|
||||
void ISerializationHooks.AfterDeserialization()
|
||||
{
|
||||
TotalVolume = ReagentUnit.Zero;
|
||||
TotalVolume = FixedPoint2.Zero;
|
||||
Contents.ForEach(reagent => TotalVolume += reagent.Quantity);
|
||||
}
|
||||
|
||||
@@ -62,7 +63,7 @@ namespace Content.Shared.Chemistry.Components
|
||||
return ContainsReagent(reagentId, out _);
|
||||
}
|
||||
|
||||
public bool ContainsReagent(string reagentId, out ReagentUnit quantity)
|
||||
public bool ContainsReagent(string reagentId, out FixedPoint2 quantity)
|
||||
{
|
||||
foreach (var reagent in Contents)
|
||||
{
|
||||
@@ -73,7 +74,7 @@ namespace Content.Shared.Chemistry.Components
|
||||
}
|
||||
}
|
||||
|
||||
quantity = ReagentUnit.New(0);
|
||||
quantity = FixedPoint2.New(0);
|
||||
return false;
|
||||
}
|
||||
|
||||
@@ -93,7 +94,7 @@ namespace Content.Shared.Chemistry.Components
|
||||
/// </summary>
|
||||
/// <param name="reagentId">The prototype ID of the reagent to add.</param>
|
||||
/// <param name="quantity">The quantity in milli-units.</param>
|
||||
public void AddReagent(string reagentId, ReagentUnit quantity)
|
||||
public void AddReagent(string reagentId, FixedPoint2 quantity)
|
||||
{
|
||||
if (quantity <= 0)
|
||||
return;
|
||||
@@ -139,7 +140,7 @@ namespace Content.Shared.Chemistry.Components
|
||||
/// </summary>
|
||||
/// <param name="reagentId">The prototype ID of the reagent to add.</param>
|
||||
/// <returns>The quantity in milli-units.</returns>
|
||||
public ReagentUnit GetReagentQuantity(string reagentId)
|
||||
public FixedPoint2 GetReagentQuantity(string reagentId)
|
||||
{
|
||||
for (var i = 0; i < Contents.Count; i++)
|
||||
{
|
||||
@@ -147,10 +148,10 @@ namespace Content.Shared.Chemistry.Components
|
||||
return Contents[i].Quantity;
|
||||
}
|
||||
|
||||
return ReagentUnit.New(0);
|
||||
return FixedPoint2.New(0);
|
||||
}
|
||||
|
||||
public void RemoveReagent(string reagentId, ReagentUnit quantity)
|
||||
public void RemoveReagent(string reagentId, FixedPoint2 quantity)
|
||||
{
|
||||
if(quantity <= 0)
|
||||
return;
|
||||
@@ -183,7 +184,7 @@ namespace Content.Shared.Chemistry.Components
|
||||
/// Remove the specified quantity from this solution.
|
||||
/// </summary>
|
||||
/// <param name="quantity">The quantity of this solution to remove</param>
|
||||
public void RemoveSolution(ReagentUnit quantity)
|
||||
public void RemoveSolution(FixedPoint2 quantity)
|
||||
{
|
||||
if(quantity <= 0)
|
||||
return;
|
||||
@@ -214,10 +215,10 @@ namespace Content.Shared.Chemistry.Components
|
||||
public void RemoveAllSolution()
|
||||
{
|
||||
Contents.Clear();
|
||||
TotalVolume = ReagentUnit.New(0);
|
||||
TotalVolume = FixedPoint2.New(0);
|
||||
}
|
||||
|
||||
public Solution SplitSolution(ReagentUnit quantity)
|
||||
public Solution SplitSolution(FixedPoint2 quantity)
|
||||
{
|
||||
if (quantity <= 0)
|
||||
return new Solution();
|
||||
@@ -232,7 +233,7 @@ namespace Content.Shared.Chemistry.Components
|
||||
}
|
||||
|
||||
newSolution = new Solution();
|
||||
var newTotalVolume = ReagentUnit.New(0);
|
||||
var newTotalVolume = FixedPoint2.New(0);
|
||||
var remainingVolume = TotalVolume;
|
||||
|
||||
for (var i = 0; i < Contents.Count; i++)
|
||||
@@ -291,7 +292,7 @@ namespace Content.Shared.Chemistry.Components
|
||||
}
|
||||
|
||||
Color mixColor = default;
|
||||
var runningTotalQuantity = ReagentUnit.New(0);
|
||||
var runningTotalQuantity = FixedPoint2.New(0);
|
||||
var protoManager = IoCManager.Resolve<IPrototypeManager>();
|
||||
|
||||
foreach (var reagent in Contents)
|
||||
@@ -317,7 +318,7 @@ namespace Content.Shared.Chemistry.Components
|
||||
|
||||
public Solution Clone()
|
||||
{
|
||||
var volume = ReagentUnit.New(0);
|
||||
var volume = FixedPoint2.New(0);
|
||||
var newSolution = new Solution();
|
||||
|
||||
for (var i = 0; i < Contents.Count; i++)
|
||||
@@ -348,9 +349,9 @@ namespace Content.Shared.Chemistry.Components
|
||||
[DataField("ReagentId", customTypeSerializer:typeof(PrototypeIdSerializer<ReagentPrototype>))]
|
||||
public readonly string ReagentId;
|
||||
[DataField("Quantity")]
|
||||
public readonly ReagentUnit Quantity;
|
||||
public readonly FixedPoint2 Quantity;
|
||||
|
||||
public ReagentQuantity(string reagentId, ReagentUnit quantity)
|
||||
public ReagentQuantity(string reagentId, FixedPoint2 quantity)
|
||||
{
|
||||
ReagentId = reagentId;
|
||||
Quantity = quantity;
|
||||
@@ -364,7 +365,7 @@ namespace Content.Shared.Chemistry.Components
|
||||
|
||||
public int CompareTo(ReagentQuantity other) { return Quantity.Float().CompareTo(other.Quantity.Float()); }
|
||||
|
||||
public void Deconstruct(out string reagentId, out ReagentUnit quantity)
|
||||
public void Deconstruct(out string reagentId, out FixedPoint2 quantity)
|
||||
{
|
||||
reagentId = ReagentId;
|
||||
quantity = Quantity;
|
||||
|
||||
@@ -1,6 +1,7 @@
|
||||
using System;
|
||||
using System.Collections.Generic;
|
||||
using Content.Shared.Chemistry.Reagent;
|
||||
using Content.Shared.FixedPoint;
|
||||
using Robust.Shared.GameObjects;
|
||||
using Robust.Shared.Serialization;
|
||||
|
||||
@@ -26,8 +27,8 @@ namespace Content.Shared.Chemistry.Dispenser
|
||||
{
|
||||
public readonly bool HasPower;
|
||||
public readonly bool HasBeaker;
|
||||
public readonly ReagentUnit BeakerCurrentVolume;
|
||||
public readonly ReagentUnit BeakerMaxVolume;
|
||||
public readonly FixedPoint2 BeakerCurrentVolume;
|
||||
public readonly FixedPoint2 BeakerMaxVolume;
|
||||
public readonly string ContainerName;
|
||||
/// <summary>
|
||||
/// A list of the reagents which this dispenser can dispense.
|
||||
@@ -38,10 +39,10 @@ namespace Content.Shared.Chemistry.Dispenser
|
||||
/// </summary>
|
||||
public readonly List<Components.Solution.ReagentQuantity>? ContainerReagents;
|
||||
public readonly string DispenserName;
|
||||
public readonly ReagentUnit SelectedDispenseAmount;
|
||||
public readonly FixedPoint2 SelectedDispenseAmount;
|
||||
|
||||
public ReagentDispenserBoundUserInterfaceState(bool hasPower, bool hasBeaker, ReagentUnit beakerCurrentVolume, ReagentUnit beakerMaxVolume, string containerName,
|
||||
List<ReagentDispenserInventoryEntry> inventory, string dispenserName, List<Components.Solution.ReagentQuantity>? containerReagents, ReagentUnit selectedDispenseAmount)
|
||||
public ReagentDispenserBoundUserInterfaceState(bool hasPower, bool hasBeaker, FixedPoint2 beakerCurrentVolume, FixedPoint2 beakerMaxVolume, string containerName,
|
||||
List<ReagentDispenserInventoryEntry> inventory, string dispenserName, List<Components.Solution.ReagentQuantity>? containerReagents, FixedPoint2 selectedDispenseAmount)
|
||||
{
|
||||
HasPower = hasPower;
|
||||
HasBeaker = hasBeaker;
|
||||
|
||||
@@ -1,10 +1,11 @@
|
||||
using Content.Shared.Chemistry.Reagent;
|
||||
using Content.Shared.FixedPoint;
|
||||
using Robust.Shared.Map;
|
||||
|
||||
namespace Content.Shared.Chemistry.Reaction
|
||||
{
|
||||
public interface ITileReaction
|
||||
{
|
||||
ReagentUnit TileReact(TileRef tile, ReagentPrototype reagent, ReagentUnit reactVolume);
|
||||
FixedPoint2 TileReact(TileRef tile, ReagentPrototype reagent, FixedPoint2 reactVolume);
|
||||
}
|
||||
}
|
||||
|
||||
@@ -1,5 +1,6 @@
|
||||
using System.Collections.Generic;
|
||||
using Content.Shared.Chemistry.Reagent;
|
||||
using Content.Shared.FixedPoint;
|
||||
using Content.Shared.Sound;
|
||||
using Robust.Shared.Prototypes;
|
||||
using Robust.Shared.Serialization.Manager.Attributes;
|
||||
@@ -14,7 +15,7 @@ namespace Content.Shared.Chemistry.Reaction
|
||||
public class ReactionPrototype : IPrototype
|
||||
{
|
||||
[DataField("reactants")] private Dictionary<string, ReactantPrototype> _reactants = new();
|
||||
[DataField("products")] private Dictionary<string, ReagentUnit> _products = new();
|
||||
[DataField("products")] private Dictionary<string, FixedPoint2> _products = new();
|
||||
[DataField("effects", serverOnly: true)] private List<IReactionEffect> _effects = new();
|
||||
|
||||
[ViewVariables]
|
||||
@@ -31,7 +32,7 @@ namespace Content.Shared.Chemistry.Reaction
|
||||
/// <summary>
|
||||
/// Reagents created when the reaction occurs.
|
||||
/// </summary>
|
||||
public IReadOnlyDictionary<string, ReagentUnit> Products => _products;
|
||||
public IReadOnlyDictionary<string, FixedPoint2> Products => _products;
|
||||
/// <summary>
|
||||
/// Effects to be triggered when the reaction occurs.
|
||||
/// </summary>
|
||||
@@ -48,14 +49,14 @@ namespace Content.Shared.Chemistry.Reaction
|
||||
public class ReactantPrototype
|
||||
{
|
||||
[DataField("amount")]
|
||||
private ReagentUnit _amount = ReagentUnit.New(1);
|
||||
private FixedPoint2 _amount = FixedPoint2.New(1);
|
||||
[DataField("catalyst")]
|
||||
private bool _catalyst;
|
||||
|
||||
/// <summary>
|
||||
/// Minimum amount of the reactant needed for the reaction to occur.
|
||||
/// </summary>
|
||||
public ReagentUnit Amount => _amount;
|
||||
public FixedPoint2 Amount => _amount;
|
||||
/// <summary>
|
||||
/// Whether or not the reactant is a catalyst. Catalysts aren't removed when a reaction occurs.
|
||||
/// </summary>
|
||||
|
||||
@@ -1,6 +1,7 @@
|
||||
using System.Collections.Generic;
|
||||
using Content.Shared.Chemistry.Components;
|
||||
using Content.Shared.Chemistry.Reagent;
|
||||
using Content.Shared.FixedPoint;
|
||||
using Robust.Shared.GameObjects;
|
||||
using Robust.Shared.IoC;
|
||||
using Robust.Shared.Log;
|
||||
@@ -29,9 +30,9 @@ namespace Content.Shared.Chemistry.Reaction
|
||||
/// <param name="reaction">The reaction to check.</param>
|
||||
/// <param name="lowestUnitReactions">How many times this reaction can occur.</param>
|
||||
/// <returns></returns>
|
||||
private static bool CanReact(Solution solution, ReactionPrototype reaction, out ReagentUnit lowestUnitReactions)
|
||||
private static bool CanReact(Solution solution, ReactionPrototype reaction, out FixedPoint2 lowestUnitReactions)
|
||||
{
|
||||
lowestUnitReactions = ReagentUnit.MaxValue;
|
||||
lowestUnitReactions = FixedPoint2.MaxValue;
|
||||
|
||||
foreach (var reactantData in reaction.Reactants)
|
||||
{
|
||||
@@ -55,7 +56,7 @@ namespace Content.Shared.Chemistry.Reaction
|
||||
/// Perform a reaction on a solution. This assumes all reaction criteria are met.
|
||||
/// Removes the reactants from the solution, then returns a solution with all products.
|
||||
/// </summary>
|
||||
private Solution PerformReaction(Solution solution, IEntity owner, ReactionPrototype reaction, ReagentUnit unitReactions)
|
||||
private Solution PerformReaction(Solution solution, IEntity owner, ReactionPrototype reaction, FixedPoint2 unitReactions)
|
||||
{
|
||||
//Remove reactants
|
||||
foreach (var reactant in reaction.Reactants)
|
||||
@@ -80,7 +81,7 @@ namespace Content.Shared.Chemistry.Reaction
|
||||
return products;
|
||||
}
|
||||
|
||||
protected virtual void OnReaction(Solution solution, ReactionPrototype reaction, IEntity owner, ReagentUnit unitReactions)
|
||||
protected virtual void OnReaction(Solution solution, ReactionPrototype reaction, IEntity owner, FixedPoint2 unitReactions)
|
||||
{
|
||||
foreach (var effect in reaction.Effects)
|
||||
{
|
||||
@@ -130,7 +131,7 @@ namespace Content.Shared.Chemistry.Reaction
|
||||
/// Continually react a solution until no more reactions occur, with a volume constraint.
|
||||
/// If a reaction's products would exceed the max volume, some product is deleted.
|
||||
/// </summary>
|
||||
public void FullyReactSolution(Solution solution, IEntity owner, ReagentUnit maxVolume)
|
||||
public void FullyReactSolution(Solution solution, IEntity owner, FixedPoint2 maxVolume)
|
||||
{
|
||||
for (var i = 0; i < MaxReactionIterations; i++)
|
||||
{
|
||||
|
||||
@@ -1,4 +1,5 @@
|
||||
using System;
|
||||
using Content.Shared.FixedPoint;
|
||||
using Robust.Shared.GameObjects;
|
||||
using Robust.Shared.Serialization.Manager.Attributes;
|
||||
using Robust.Shared.ViewVariables;
|
||||
@@ -27,7 +28,7 @@ namespace Content.Shared.Chemistry.Reagent
|
||||
[DataField("ingestion")]
|
||||
public bool Ingestion { get; } = false;
|
||||
|
||||
public void React(ReactionMethod method, IEntity entity, ReagentPrototype reagent, ReagentUnit volume, Components.Solution? source)
|
||||
public void React(ReactionMethod method, IEntity entity, ReagentPrototype reagent, FixedPoint2 volume, Components.Solution? source)
|
||||
{
|
||||
switch (method)
|
||||
{
|
||||
@@ -50,6 +51,6 @@ namespace Content.Shared.Chemistry.Reagent
|
||||
React(entity, reagent, volume, source);
|
||||
}
|
||||
|
||||
protected abstract void React(IEntity entity, ReagentPrototype reagent, ReagentUnit volume, Components.Solution? source);
|
||||
protected abstract void React(IEntity entity, ReagentPrototype reagent, FixedPoint2 volume, Components.Solution? source);
|
||||
}
|
||||
}
|
||||
|
||||
@@ -2,6 +2,7 @@
|
||||
using System.Collections.Generic;
|
||||
using Content.Shared.Botany;
|
||||
using Content.Shared.Chemistry.Reaction;
|
||||
using Content.Shared.FixedPoint;
|
||||
using Robust.Shared.GameObjects;
|
||||
using Robust.Shared.Map;
|
||||
using Robust.Shared.Maths;
|
||||
@@ -77,9 +78,9 @@ namespace Content.Shared.Chemistry.Reagent
|
||||
return SubstanceColor;
|
||||
}
|
||||
|
||||
public ReagentUnit ReactionTile(TileRef tile, ReagentUnit reactVolume)
|
||||
public FixedPoint2 ReactionTile(TileRef tile, FixedPoint2 reactVolume)
|
||||
{
|
||||
var removed = ReagentUnit.Zero;
|
||||
var removed = FixedPoint2.Zero;
|
||||
|
||||
if (tile.Tile.IsEmpty)
|
||||
return removed;
|
||||
|
||||
@@ -1,5 +1,6 @@
|
||||
using System;
|
||||
using Content.Shared.Chemistry.Reagent;
|
||||
using Content.Shared.FixedPoint;
|
||||
using Robust.Shared.GameObjects;
|
||||
using Robust.Shared.Serialization;
|
||||
|
||||
@@ -8,10 +9,10 @@ namespace Content.Shared.Chemistry
|
||||
[Serializable, NetSerializable]
|
||||
public class TransferAmountBoundInterfaceState : BoundUserInterfaceState
|
||||
{
|
||||
public ReagentUnit Max;
|
||||
public ReagentUnit Min;
|
||||
public FixedPoint2 Max;
|
||||
public FixedPoint2 Min;
|
||||
|
||||
public TransferAmountBoundInterfaceState(ReagentUnit max, ReagentUnit min)
|
||||
public TransferAmountBoundInterfaceState(FixedPoint2 max, FixedPoint2 min)
|
||||
{
|
||||
Max = max;
|
||||
Min = min;
|
||||
@@ -21,9 +22,9 @@ namespace Content.Shared.Chemistry
|
||||
[Serializable, NetSerializable]
|
||||
public class TransferAmountSetValueMessage : BoundUserInterfaceMessage
|
||||
{
|
||||
public ReagentUnit Value;
|
||||
public FixedPoint2 Value;
|
||||
|
||||
public TransferAmountSetValueMessage(ReagentUnit value)
|
||||
public TransferAmountSetValueMessage(FixedPoint2 value)
|
||||
{
|
||||
Value = value;
|
||||
}
|
||||
|
||||
@@ -9,12 +9,10 @@ using Robust.Shared.ViewVariables;
|
||||
using System;
|
||||
using System.Collections.Generic;
|
||||
using System.Linq;
|
||||
using Content.Shared.FixedPoint;
|
||||
|
||||
namespace Content.Shared.Damage
|
||||
{
|
||||
// TODO DAMAGE UNITS Move this whole class away from, using integers. Also get rid of a lot of the rounding. Just
|
||||
// use DamageUnit math operators.
|
||||
|
||||
/// <summary>
|
||||
/// This class represents a collection of damage types and damage values.
|
||||
/// </summary>
|
||||
@@ -25,17 +23,17 @@ namespace Content.Shared.Damage
|
||||
[DataDefinition]
|
||||
public class DamageSpecifier
|
||||
{
|
||||
[DataField("types", customTypeSerializer: typeof(PrototypeIdDictionarySerializer<int, DamageTypePrototype>))]
|
||||
private readonly Dictionary<string,int>? _damageTypeDictionary;
|
||||
[DataField("types", customTypeSerializer: typeof(PrototypeIdDictionarySerializer<FixedPoint2, DamageTypePrototype>))]
|
||||
private readonly Dictionary<string,FixedPoint2>? _damageTypeDictionary;
|
||||
|
||||
[DataField("groups", customTypeSerializer: typeof(PrototypeIdDictionarySerializer<int, DamageGroupPrototype>))]
|
||||
private readonly Dictionary<string, int>? _damageGroupDictionary;
|
||||
[DataField("groups", customTypeSerializer: typeof(PrototypeIdDictionarySerializer<FixedPoint2, DamageGroupPrototype>))]
|
||||
private readonly Dictionary<string, FixedPoint2>? _damageGroupDictionary;
|
||||
|
||||
/// <summary>
|
||||
/// Main DamageSpecifier dictionary. Most DamageSpecifier functions exist to somehow modifying this.
|
||||
/// </summary>
|
||||
[ViewVariables(VVAccess.ReadWrite)]
|
||||
public Dictionary<string, int> DamageDict
|
||||
public Dictionary<string, FixedPoint2> DamageDict
|
||||
{
|
||||
get
|
||||
{
|
||||
@@ -45,7 +43,7 @@ namespace Content.Shared.Damage
|
||||
}
|
||||
set => _damageDict = value;
|
||||
}
|
||||
private Dictionary<string, int>? _damageDict;
|
||||
private Dictionary<string, FixedPoint2>? _damageDict;
|
||||
|
||||
/// <summary>
|
||||
/// Sum of the damage values.
|
||||
@@ -55,7 +53,7 @@ namespace Content.Shared.Damage
|
||||
/// in another. For this purpose, you should instead use <see cref="TrimZeros()"/> and then check the <see
|
||||
/// cref="Empty"/> property.
|
||||
/// </remarks>
|
||||
public int Total => DamageDict.Values.Sum();
|
||||
public FixedPoint2 Total => DamageDict.Values.Sum();
|
||||
|
||||
/// <summary>
|
||||
/// Whether this damage specifier has any entries.
|
||||
@@ -79,7 +77,7 @@ namespace Content.Shared.Damage
|
||||
/// <summary>
|
||||
/// Constructor that takes a single damage type prototype and a damage value.
|
||||
/// </summary>
|
||||
public DamageSpecifier(DamageTypePrototype type, int value)
|
||||
public DamageSpecifier(DamageTypePrototype type, FixedPoint2 value)
|
||||
{
|
||||
DamageDict = new() { { type.ID, value } };
|
||||
}
|
||||
@@ -87,14 +85,14 @@ namespace Content.Shared.Damage
|
||||
/// <summary>
|
||||
/// Constructor that takes a single damage group prototype and a damage value. The value is divided between members of the damage group.
|
||||
/// </summary>
|
||||
public DamageSpecifier(DamageGroupPrototype group, int value)
|
||||
public DamageSpecifier(DamageGroupPrototype group, FixedPoint2 value)
|
||||
{
|
||||
_damageGroupDictionary = new() { { group.ID, value } };
|
||||
}
|
||||
#endregion constructors
|
||||
|
||||
/// <summary>
|
||||
/// Combines the damage group and type datafield dictionaries into a single damage dictionary.
|
||||
/// Combines the damage group and type datafield dictionaries FixedPoint2o a single damage dictionary.
|
||||
/// </summary>
|
||||
public void DeserializeDamage()
|
||||
{
|
||||
@@ -128,7 +126,7 @@ namespace Content.Shared.Damage
|
||||
var remainingDamage = entry.Value;
|
||||
foreach (var damageType in group.DamageTypes)
|
||||
{
|
||||
var damage = remainingDamage / remainingTypes;
|
||||
var damage = remainingDamage / FixedPoint2.New(remainingTypes);
|
||||
if (!_damageDict.TryAdd(damageType, damage))
|
||||
{
|
||||
// Key already exists, add values
|
||||
@@ -149,7 +147,7 @@ namespace Content.Shared.Damage
|
||||
public static DamageSpecifier ApplyModifierSet(DamageSpecifier damageSpec, DamageModifierSet modifierSet)
|
||||
{
|
||||
// Make a copy of the given data. Don't modify the one passed to this function. I did this before, and weapons became
|
||||
// duller as you hit walls. Neat, but not intended. And confusing, when you realize your fists don't work no
|
||||
// duller as you hit walls. Neat, but not FixedPoint2ended. And confusing, when you realize your fists don't work no
|
||||
// more cause they're just bloody stumps.
|
||||
DamageSpecifier newDamage = new(damageSpec);
|
||||
|
||||
@@ -157,7 +155,7 @@ namespace Content.Shared.Damage
|
||||
{
|
||||
if (entry.Value <= 0) continue;
|
||||
|
||||
float newValue = entry.Value;
|
||||
float newValue = entry.Value.Float();
|
||||
|
||||
if (modifierSet.FlatReduction.TryGetValue(entry.Key, out var reduction))
|
||||
{
|
||||
@@ -165,7 +163,7 @@ namespace Content.Shared.Damage
|
||||
if (newValue <= 0)
|
||||
{
|
||||
// flat reductions cannot heal you
|
||||
newDamage.DamageDict[entry.Key] = 0;
|
||||
newDamage.DamageDict[entry.Key] = FixedPoint2.Zero;
|
||||
continue;
|
||||
}
|
||||
}
|
||||
@@ -173,10 +171,10 @@ namespace Content.Shared.Damage
|
||||
if (modifierSet.Coefficients.TryGetValue(entry.Key, out var coefficient))
|
||||
{
|
||||
// negative coefficients **can** heal you.
|
||||
newValue = MathF.Round(newValue*coefficient, MidpointRounding.AwayFromZero);
|
||||
newValue = newValue * coefficient;
|
||||
}
|
||||
|
||||
newDamage.DamageDict[entry.Key] = (int) newValue;
|
||||
newDamage.DamageDict[entry.Key] = FixedPoint2.New(newValue);
|
||||
}
|
||||
|
||||
newDamage.TrimZeros();
|
||||
@@ -218,7 +216,7 @@ namespace Content.Shared.Damage
|
||||
/// <summary>
|
||||
/// Clamps each damage value to be within the given range.
|
||||
/// </summary>
|
||||
public void Clamp(int minValue = 0, int maxValue = 0)
|
||||
public void Clamp(FixedPoint2 minValue, FixedPoint2 maxValue)
|
||||
{
|
||||
DebugTools.Assert(minValue < maxValue);
|
||||
ClampMax(maxValue);
|
||||
@@ -231,7 +229,7 @@ namespace Content.Shared.Damage
|
||||
/// <remarks>
|
||||
/// Note that this only acts on damage types present in the dictionary. It will not add new damage types.
|
||||
/// </remarks>
|
||||
public void ClampMin(int minValue = 0)
|
||||
public void ClampMin(FixedPoint2 minValue)
|
||||
{
|
||||
foreach (var (key, value) in DamageDict)
|
||||
{
|
||||
@@ -246,7 +244,7 @@ namespace Content.Shared.Damage
|
||||
/// Sets all damage values to be at most some number. Note that if a damage type is not present in the
|
||||
/// dictionary, these will not be added.
|
||||
/// </summary>
|
||||
public void ClampMax(int maxValue = 0)
|
||||
public void ClampMax(FixedPoint2 maxValue)
|
||||
{
|
||||
foreach (var (key, value) in DamageDict)
|
||||
{
|
||||
@@ -282,10 +280,10 @@ namespace Content.Shared.Damage
|
||||
/// <remarks>
|
||||
/// If no members of the group are included in this specifier, returns false.
|
||||
/// </remarks>
|
||||
public bool TryGetDamageInGroup(DamageGroupPrototype group, out int total)
|
||||
public bool TryGetDamageInGroup(DamageGroupPrototype group, out FixedPoint2 total)
|
||||
{
|
||||
bool containsMemeber = false;
|
||||
total = 0;
|
||||
total = FixedPoint2.Zero;
|
||||
|
||||
foreach (var type in group.DamageTypes)
|
||||
{
|
||||
@@ -307,9 +305,9 @@ namespace Content.Shared.Damage
|
||||
/// total of each group. If no members of a group are present in this <see cref="DamageSpecifier"/>, the
|
||||
/// group is not included in the resulting dictionary.
|
||||
/// </remarks>
|
||||
public Dictionary<string, int> GetDamagePerGroup()
|
||||
public Dictionary<string, FixedPoint2> GetDamagePerGroup()
|
||||
{
|
||||
var damageGroupDict = new Dictionary<string, int>();
|
||||
var damageGroupDict = new Dictionary<string, FixedPoint2>();
|
||||
foreach (var group in IoCManager.Resolve<IPrototypeManager>().EnumeratePrototypes<DamageGroupPrototype>())
|
||||
{
|
||||
if (TryGetDamageInGroup(group, out var value))
|
||||
@@ -321,7 +319,7 @@ namespace Content.Shared.Damage
|
||||
}
|
||||
|
||||
#region Operators
|
||||
public static DamageSpecifier operator *(DamageSpecifier damageSpec, int factor)
|
||||
public static DamageSpecifier operator *(DamageSpecifier damageSpec, FixedPoint2 factor)
|
||||
{
|
||||
DamageSpecifier newDamage = new();
|
||||
foreach (var entry in damageSpec.DamageDict)
|
||||
@@ -336,17 +334,17 @@ namespace Content.Shared.Damage
|
||||
DamageSpecifier newDamage = new();
|
||||
foreach (var entry in damageSpec.DamageDict)
|
||||
{
|
||||
newDamage.DamageDict.Add(entry.Key, (int) MathF.Round(entry.Value * factor, MidpointRounding.AwayFromZero));
|
||||
newDamage.DamageDict.Add(entry.Key, entry.Value * factor);
|
||||
}
|
||||
return newDamage;
|
||||
}
|
||||
|
||||
public static DamageSpecifier operator /(DamageSpecifier damageSpec, int factor)
|
||||
public static DamageSpecifier operator /(DamageSpecifier damageSpec, FixedPoint2 factor)
|
||||
{
|
||||
DamageSpecifier newDamage = new();
|
||||
foreach (var entry in damageSpec.DamageDict)
|
||||
{
|
||||
newDamage.DamageDict.Add(entry.Key, (int) MathF.Round(entry.Value / (float) factor, MidpointRounding.AwayFromZero));
|
||||
newDamage.DamageDict.Add(entry.Key, entry.Value / factor);
|
||||
}
|
||||
return newDamage;
|
||||
}
|
||||
@@ -357,7 +355,7 @@ namespace Content.Shared.Damage
|
||||
|
||||
foreach (var entry in damageSpec.DamageDict)
|
||||
{
|
||||
newDamage.DamageDict.Add(entry.Key, (int) MathF.Round(entry.Value / factor, MidpointRounding.AwayFromZero));
|
||||
newDamage.DamageDict.Add(entry.Key, entry.Value / factor);
|
||||
}
|
||||
return newDamage;
|
||||
}
|
||||
@@ -387,7 +385,7 @@ namespace Content.Shared.Damage
|
||||
|
||||
public static DamageSpecifier operator *(float factor, DamageSpecifier damageSpec) => damageSpec * factor;
|
||||
|
||||
public static DamageSpecifier operator *(int factor, DamageSpecifier damageSpec) => damageSpec * factor;
|
||||
public static DamageSpecifier operator *(FixedPoint2 factor, DamageSpecifier damageSpec) => damageSpec * factor;
|
||||
}
|
||||
#endregion
|
||||
}
|
||||
|
||||
@@ -2,6 +2,7 @@ using System;
|
||||
using System.Collections.Generic;
|
||||
using Content.Shared.Acts;
|
||||
using Content.Shared.Damage.Prototypes;
|
||||
using Content.Shared.FixedPoint;
|
||||
using Content.Shared.Radiation;
|
||||
using Robust.Shared.Analyzers;
|
||||
using Robust.Shared.GameObjects;
|
||||
@@ -64,12 +65,12 @@ namespace Content.Shared.Damage
|
||||
/// Groups which have no members that are supported by this component will not be present in this
|
||||
/// dictionary.
|
||||
/// </remarks>
|
||||
[ViewVariables] public Dictionary<string, int> DamagePerGroup = new();
|
||||
[ViewVariables] public Dictionary<string, FixedPoint2> DamagePerGroup = new();
|
||||
|
||||
/// <summary>
|
||||
/// The sum of all damages in the DamageableComponent.
|
||||
/// </summary>
|
||||
[ViewVariables] public int TotalDamage;
|
||||
[ViewVariables] public FixedPoint2 TotalDamage;
|
||||
|
||||
// Really these shouldn't be here. OnExplosion() and RadiationAct() should be handled elsewhere.
|
||||
[ViewVariables]
|
||||
@@ -82,7 +83,7 @@ namespace Content.Shared.Damage
|
||||
// TODO RADIATION Remove this.
|
||||
void IRadiationAct.RadiationAct(float frameTime, SharedRadiationPulseComponent radiation)
|
||||
{
|
||||
var damageValue = Math.Max((int) (frameTime * radiation.RadsPerSecond), 1);
|
||||
var damageValue = FixedPoint2.New(MathF.Max((frameTime * radiation.RadsPerSecond), 1));
|
||||
|
||||
// Radiation should really just be a damage group instead of a list of types.
|
||||
DamageSpecifier damage = new();
|
||||
@@ -99,9 +100,9 @@ namespace Content.Shared.Damage
|
||||
{
|
||||
var damageValue = eventArgs.Severity switch
|
||||
{
|
||||
ExplosionSeverity.Light => 20,
|
||||
ExplosionSeverity.Heavy => 60,
|
||||
ExplosionSeverity.Destruction => 250,
|
||||
ExplosionSeverity.Light => FixedPoint2.New(20),
|
||||
ExplosionSeverity.Heavy => FixedPoint2.New(60),
|
||||
ExplosionSeverity.Destruction => FixedPoint2.New(250),
|
||||
_ => throw new ArgumentOutOfRangeException()
|
||||
};
|
||||
|
||||
@@ -119,11 +120,11 @@ namespace Content.Shared.Damage
|
||||
[Serializable, NetSerializable]
|
||||
public class DamageableComponentState : ComponentState
|
||||
{
|
||||
public readonly Dictionary<string, int> DamageDict;
|
||||
public readonly Dictionary<string, FixedPoint2> DamageDict;
|
||||
public readonly string? ModifierSetId;
|
||||
|
||||
public DamageableComponentState(
|
||||
Dictionary<string, int> damageDict,
|
||||
Dictionary<string, FixedPoint2> damageDict,
|
||||
string? modifierSetId)
|
||||
{
|
||||
DamageDict = damageDict;
|
||||
|
||||
@@ -1,6 +1,7 @@
|
||||
using System.Collections.Generic;
|
||||
using System.Linq;
|
||||
using Content.Shared.Damage.Prototypes;
|
||||
using Content.Shared.FixedPoint;
|
||||
using Robust.Shared.GameObjects;
|
||||
using Robust.Shared.GameStates;
|
||||
using Robust.Shared.IoC;
|
||||
@@ -33,7 +34,7 @@ namespace Content.Shared.Damage
|
||||
// container prototype
|
||||
foreach (var type in damageContainerPrototype.SupportedTypes)
|
||||
{
|
||||
component.Damage.DamageDict.TryAdd(type, 0);
|
||||
component.Damage.DamageDict.TryAdd(type, FixedPoint2.Zero);
|
||||
}
|
||||
|
||||
foreach (var groupID in damageContainerPrototype.SupportedGroups)
|
||||
@@ -41,7 +42,7 @@ namespace Content.Shared.Damage
|
||||
var group = _prototypeManager.Index<DamageGroupPrototype>(groupID);
|
||||
foreach (var type in group.DamageTypes)
|
||||
{
|
||||
component.Damage.DamageDict.TryAdd(type, 0);
|
||||
component.Damage.DamageDict.TryAdd(type, FixedPoint2.Zero);
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -50,7 +51,7 @@ namespace Content.Shared.Damage
|
||||
// No DamageContainerPrototype was given. So we will allow the container to support all damage types
|
||||
foreach (var type in _prototypeManager.EnumeratePrototypes<DamageTypePrototype>())
|
||||
{
|
||||
component.Damage.DamageDict.TryAdd(type.ID, 0);
|
||||
component.Damage.DamageDict.TryAdd(type.ID, FixedPoint2.Zero);
|
||||
}
|
||||
}
|
||||
|
||||
@@ -143,7 +144,7 @@ namespace Content.Shared.Damage
|
||||
DamageSpecifier oldDamage = new(damageable.Damage);
|
||||
|
||||
damageable.Damage.ExclusiveAdd(damage);
|
||||
damageable.Damage.ClampMin(0);
|
||||
damageable.Damage.ClampMin(FixedPoint2.Zero);
|
||||
|
||||
var delta = damageable.Damage - oldDamage;
|
||||
delta.TrimZeros();
|
||||
@@ -162,7 +163,7 @@ namespace Content.Shared.Damage
|
||||
/// <remakrs>
|
||||
/// Does nothing If the given damage value is negative.
|
||||
/// </remakrs>
|
||||
public void SetAllDamage(DamageableComponent component, int newValue)
|
||||
public void SetAllDamage(DamageableComponent component, FixedPoint2 newValue)
|
||||
{
|
||||
if (newValue < 0)
|
||||
{
|
||||
|
||||
@@ -1,40 +1,42 @@
|
||||
using System;
|
||||
using System.Collections;
|
||||
using System.Collections.Generic;
|
||||
using System.Globalization;
|
||||
using System.Linq;
|
||||
using Robust.Shared.Serialization;
|
||||
|
||||
namespace Content.Shared.Chemistry.Reagent
|
||||
namespace Content.Shared.FixedPoint
|
||||
{
|
||||
/// <summary>
|
||||
/// Represents a quantity of reagent, to a precision of 0.01.
|
||||
/// Represents a quantity of something, to a precision of 0.01.
|
||||
/// To enforce this level of precision, floats are shifted by 2 decimal points, rounded, and converted to an int.
|
||||
/// </summary>
|
||||
[Serializable]
|
||||
public struct ReagentUnit : ISelfSerialize, IComparable<ReagentUnit>, IEquatable<ReagentUnit>
|
||||
public struct FixedPoint2 : ISelfSerialize, IComparable<FixedPoint2>, IEquatable<FixedPoint2>
|
||||
{
|
||||
private int _value;
|
||||
private static readonly int Shift = 2;
|
||||
|
||||
public static ReagentUnit MaxValue { get; } = new(int.MaxValue);
|
||||
public static ReagentUnit Epsilon { get; } = new(1);
|
||||
public static ReagentUnit Zero { get; } = new(0);
|
||||
public static FixedPoint2 MaxValue { get; } = new(int.MaxValue);
|
||||
public static FixedPoint2 Epsilon { get; } = new(1);
|
||||
public static FixedPoint2 Zero { get; } = new(0);
|
||||
|
||||
private readonly double ShiftDown()
|
||||
{
|
||||
return _value / Math.Pow(10, Shift);
|
||||
}
|
||||
|
||||
private ReagentUnit(int value)
|
||||
private FixedPoint2(int value)
|
||||
{
|
||||
_value = value;
|
||||
}
|
||||
|
||||
public static ReagentUnit New(int value)
|
||||
public static FixedPoint2 New(int value)
|
||||
{
|
||||
return new(value * (int) Math.Pow(10, Shift));
|
||||
}
|
||||
|
||||
public static ReagentUnit New(float value)
|
||||
public static FixedPoint2 New(float value)
|
||||
{
|
||||
return new(FromFloat(value));
|
||||
}
|
||||
@@ -44,12 +46,12 @@ namespace Content.Shared.Chemistry.Reagent
|
||||
return (int) MathF.Round(value * MathF.Pow(10, Shift), MidpointRounding.AwayFromZero);
|
||||
}
|
||||
|
||||
public static ReagentUnit New(double value)
|
||||
public static FixedPoint2 New(double value)
|
||||
{
|
||||
return new((int) Math.Round(value * Math.Pow(10, Shift), MidpointRounding.AwayFromZero));
|
||||
}
|
||||
|
||||
public static ReagentUnit New(string value)
|
||||
public static FixedPoint2 New(string value)
|
||||
{
|
||||
return New(FloatFromString(value));
|
||||
}
|
||||
@@ -59,41 +61,41 @@ namespace Content.Shared.Chemistry.Reagent
|
||||
return float.Parse(value, CultureInfo.InvariantCulture);
|
||||
}
|
||||
|
||||
public static ReagentUnit operator +(ReagentUnit a) => a;
|
||||
public static FixedPoint2 operator +(FixedPoint2 a) => a;
|
||||
|
||||
public static ReagentUnit operator -(ReagentUnit a) => new(-a._value);
|
||||
public static FixedPoint2 operator -(FixedPoint2 a) => new(-a._value);
|
||||
|
||||
public static ReagentUnit operator +(ReagentUnit a, ReagentUnit b)
|
||||
public static FixedPoint2 operator +(FixedPoint2 a, FixedPoint2 b)
|
||||
=> new(a._value + b._value);
|
||||
|
||||
public static ReagentUnit operator -(ReagentUnit a, ReagentUnit b)
|
||||
public static FixedPoint2 operator -(FixedPoint2 a, FixedPoint2 b)
|
||||
=> a + -b;
|
||||
|
||||
public static ReagentUnit operator *(ReagentUnit a, ReagentUnit b)
|
||||
public static FixedPoint2 operator *(FixedPoint2 a, FixedPoint2 b)
|
||||
{
|
||||
var aD = a.ShiftDown();
|
||||
var bD = b.ShiftDown();
|
||||
return New(aD * bD);
|
||||
}
|
||||
|
||||
public static ReagentUnit operator *(ReagentUnit a, float b)
|
||||
public static FixedPoint2 operator *(FixedPoint2 a, float b)
|
||||
{
|
||||
var aD = (float) a.ShiftDown();
|
||||
return New(aD * b);
|
||||
}
|
||||
|
||||
public static ReagentUnit operator *(ReagentUnit a, double b)
|
||||
public static FixedPoint2 operator *(FixedPoint2 a, double b)
|
||||
{
|
||||
var aD = a.ShiftDown();
|
||||
return New(aD * b);
|
||||
}
|
||||
|
||||
public static ReagentUnit operator *(ReagentUnit a, int b)
|
||||
public static FixedPoint2 operator *(FixedPoint2 a, int b)
|
||||
{
|
||||
return new(a._value * b);
|
||||
}
|
||||
|
||||
public static ReagentUnit operator /(ReagentUnit a, ReagentUnit b)
|
||||
public static FixedPoint2 operator /(FixedPoint2 a, FixedPoint2 b)
|
||||
{
|
||||
if (b._value == 0)
|
||||
{
|
||||
@@ -104,62 +106,67 @@ namespace Content.Shared.Chemistry.Reagent
|
||||
return New(aD / bD);
|
||||
}
|
||||
|
||||
public static bool operator <=(ReagentUnit a, int b)
|
||||
public static FixedPoint2 operator /(FixedPoint2 a, float b)
|
||||
{
|
||||
return a / FixedPoint2.New(b);
|
||||
}
|
||||
|
||||
public static bool operator <=(FixedPoint2 a, int b)
|
||||
{
|
||||
return a <= New(b);
|
||||
}
|
||||
|
||||
public static bool operator >=(ReagentUnit a, int b)
|
||||
public static bool operator >=(FixedPoint2 a, int b)
|
||||
{
|
||||
return a >= New(b);
|
||||
}
|
||||
|
||||
public static bool operator <(ReagentUnit a, int b)
|
||||
public static bool operator <(FixedPoint2 a, int b)
|
||||
{
|
||||
return a < New(b);
|
||||
}
|
||||
|
||||
public static bool operator >(ReagentUnit a, int b)
|
||||
public static bool operator >(FixedPoint2 a, int b)
|
||||
{
|
||||
return a > New(b);
|
||||
}
|
||||
|
||||
public static bool operator ==(ReagentUnit a, int b)
|
||||
public static bool operator ==(FixedPoint2 a, int b)
|
||||
{
|
||||
return a == New(b);
|
||||
}
|
||||
|
||||
public static bool operator !=(ReagentUnit a, int b)
|
||||
public static bool operator !=(FixedPoint2 a, int b)
|
||||
{
|
||||
return a != New(b);
|
||||
}
|
||||
|
||||
public static bool operator ==(ReagentUnit a, ReagentUnit b)
|
||||
public static bool operator ==(FixedPoint2 a, FixedPoint2 b)
|
||||
{
|
||||
return a.Equals(b);
|
||||
}
|
||||
|
||||
public static bool operator !=(ReagentUnit a, ReagentUnit b)
|
||||
public static bool operator !=(FixedPoint2 a, FixedPoint2 b)
|
||||
{
|
||||
return !a.Equals(b);
|
||||
}
|
||||
|
||||
public static bool operator <=(ReagentUnit a, ReagentUnit b)
|
||||
public static bool operator <=(FixedPoint2 a, FixedPoint2 b)
|
||||
{
|
||||
return a._value <= b._value;
|
||||
}
|
||||
|
||||
public static bool operator >=(ReagentUnit a, ReagentUnit b)
|
||||
public static bool operator >=(FixedPoint2 a, FixedPoint2 b)
|
||||
{
|
||||
return a._value >= b._value;
|
||||
}
|
||||
|
||||
public static bool operator <(ReagentUnit a, ReagentUnit b)
|
||||
public static bool operator <(FixedPoint2 a, FixedPoint2 b)
|
||||
{
|
||||
return a._value < b._value;
|
||||
}
|
||||
|
||||
public static bool operator >(ReagentUnit a, ReagentUnit b)
|
||||
public static bool operator >(FixedPoint2 a, FixedPoint2 b)
|
||||
{
|
||||
return a._value > b._value;
|
||||
}
|
||||
@@ -179,22 +186,31 @@ namespace Content.Shared.Chemistry.Reagent
|
||||
return (int) ShiftDown();
|
||||
}
|
||||
|
||||
public static ReagentUnit Min(params ReagentUnit[] reagentUnits)
|
||||
// Implicit operators ftw
|
||||
public static implicit operator FixedPoint2(float n) => FixedPoint2.New(n);
|
||||
public static implicit operator FixedPoint2(double n) => FixedPoint2.New(n);
|
||||
public static implicit operator FixedPoint2(int n) => FixedPoint2.New(n);
|
||||
|
||||
public static explicit operator float(FixedPoint2 n) => n.Float();
|
||||
public static explicit operator double(FixedPoint2 n) => n.Double();
|
||||
public static explicit operator int(FixedPoint2 n) => n.Int();
|
||||
|
||||
public static FixedPoint2 Min(params FixedPoint2[] fixedPoints)
|
||||
{
|
||||
return reagentUnits.Min();
|
||||
return fixedPoints.Min();
|
||||
}
|
||||
|
||||
public static ReagentUnit Min(ReagentUnit a, ReagentUnit b)
|
||||
public static FixedPoint2 Min(FixedPoint2 a, FixedPoint2 b)
|
||||
{
|
||||
return a < b ? a : b;
|
||||
}
|
||||
|
||||
public static ReagentUnit Max(ReagentUnit a, ReagentUnit b)
|
||||
public static FixedPoint2 Max(FixedPoint2 a, FixedPoint2 b)
|
||||
{
|
||||
return a > b ? a : b;
|
||||
}
|
||||
|
||||
public static ReagentUnit Clamp(ReagentUnit reagent, ReagentUnit min, ReagentUnit max)
|
||||
public static FixedPoint2 Clamp(FixedPoint2 reagent, FixedPoint2 min, FixedPoint2 max)
|
||||
{
|
||||
if (min > max)
|
||||
{
|
||||
@@ -206,7 +222,7 @@ namespace Content.Shared.Chemistry.Reagent
|
||||
|
||||
public override readonly bool Equals(object? obj)
|
||||
{
|
||||
return obj is ReagentUnit unit &&
|
||||
return obj is FixedPoint2 unit &&
|
||||
_value == unit._value;
|
||||
}
|
||||
|
||||
@@ -228,12 +244,12 @@ namespace Content.Shared.Chemistry.Reagent
|
||||
return ToString();
|
||||
}
|
||||
|
||||
public readonly bool Equals(ReagentUnit other)
|
||||
public readonly bool Equals(FixedPoint2 other)
|
||||
{
|
||||
return _value == other._value;
|
||||
}
|
||||
|
||||
public readonly int CompareTo(ReagentUnit other)
|
||||
public readonly int CompareTo(FixedPoint2 other)
|
||||
{
|
||||
if(other._value > _value)
|
||||
{
|
||||
@@ -245,5 +261,21 @@ namespace Content.Shared.Chemistry.Reagent
|
||||
}
|
||||
return 0;
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
public static class FixedPointEnumerableExt
|
||||
{
|
||||
public static FixedPoint2 Sum(this System.Collections.Generic.IEnumerable<FixedPoint2> source)
|
||||
{
|
||||
var acc = FixedPoint2.Zero;
|
||||
|
||||
foreach (var n in source)
|
||||
{
|
||||
acc += n;
|
||||
}
|
||||
|
||||
return acc;
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -3,6 +3,7 @@ using System.Collections.Generic;
|
||||
using Content.Shared.Body.Components;
|
||||
using Content.Shared.Damage;
|
||||
using Content.Shared.DragDrop;
|
||||
using Content.Shared.FixedPoint;
|
||||
using Robust.Shared.GameObjects;
|
||||
using Robust.Shared.Serialization;
|
||||
|
||||
@@ -16,8 +17,8 @@ namespace Content.Shared.MedicalScanner
|
||||
public class MedicalScannerBoundUserInterfaceState : BoundUserInterfaceState
|
||||
{
|
||||
public readonly EntityUid? Entity;
|
||||
public readonly IReadOnlyDictionary<string, int> DamagePerGroup;
|
||||
public readonly IReadOnlyDictionary<string, int> DamagePerType;
|
||||
public readonly IReadOnlyDictionary<string, FixedPoint2> DamagePerGroup;
|
||||
public readonly IReadOnlyDictionary<string, FixedPoint2> DamagePerType;
|
||||
public readonly bool IsScanned;
|
||||
|
||||
public MedicalScannerBoundUserInterfaceState(
|
||||
|
||||
@@ -4,6 +4,7 @@ using System.Diagnostics.CodeAnalysis;
|
||||
using System.Linq;
|
||||
using Content.Shared.Alert;
|
||||
using Content.Shared.Damage;
|
||||
using Content.Shared.FixedPoint;
|
||||
using Content.Shared.MobState.State;
|
||||
using Robust.Shared.GameObjects;
|
||||
using Robust.Shared.GameStates;
|
||||
@@ -43,7 +44,7 @@ namespace Content.Shared.MobState.Components
|
||||
public IMobState? CurrentState { get; private set; }
|
||||
|
||||
[ViewVariables]
|
||||
public int? CurrentThreshold { get; private set; }
|
||||
public FixedPoint2? CurrentThreshold { get; private set; }
|
||||
|
||||
public IEnumerable<KeyValuePair<int, IMobState>> _highestToLowestStates => _lowestToHighestStates.Reverse();
|
||||
|
||||
@@ -59,7 +60,7 @@ namespace Content.Shared.MobState.Components
|
||||
else
|
||||
{
|
||||
// Initialize with some amount of damage, defaulting to 0.
|
||||
UpdateState(Owner.GetComponentOrNull<DamageableComponent>()?.TotalDamage ?? 0);
|
||||
UpdateState(Owner.GetComponentOrNull<DamageableComponent>()?.TotalDamage ?? FixedPoint2.Zero);
|
||||
}
|
||||
}
|
||||
|
||||
@@ -122,7 +123,7 @@ namespace Content.Shared.MobState.Components
|
||||
return CurrentState?.IsIncapacitated() ?? false;
|
||||
}
|
||||
|
||||
public (IMobState state, int threshold)? GetState(int damage)
|
||||
public (IMobState state, FixedPoint2 threshold)? GetState(FixedPoint2 damage)
|
||||
{
|
||||
foreach (var (threshold, state) in _highestToLowestStates)
|
||||
{
|
||||
@@ -136,9 +137,9 @@ namespace Content.Shared.MobState.Components
|
||||
}
|
||||
|
||||
public bool TryGetState(
|
||||
int damage,
|
||||
FixedPoint2 damage,
|
||||
[NotNullWhen(true)] out IMobState? state,
|
||||
out int threshold)
|
||||
out FixedPoint2 threshold)
|
||||
{
|
||||
var highestState = GetState(damage);
|
||||
|
||||
@@ -153,7 +154,7 @@ namespace Content.Shared.MobState.Components
|
||||
return true;
|
||||
}
|
||||
|
||||
private (IMobState state, int threshold)? GetEarliestState(int minimumDamage, Predicate<IMobState> predicate)
|
||||
private (IMobState state, FixedPoint2 threshold)? GetEarliestState(FixedPoint2 minimumDamage, Predicate<IMobState> predicate)
|
||||
{
|
||||
foreach (var (threshold, state) in _lowestToHighestStates)
|
||||
{
|
||||
@@ -169,7 +170,7 @@ namespace Content.Shared.MobState.Components
|
||||
return null;
|
||||
}
|
||||
|
||||
private (IMobState state, int threshold)? GetPreviousState(int maximumDamage, Predicate<IMobState> predicate)
|
||||
private (IMobState state, FixedPoint2 threshold)? GetPreviousState(FixedPoint2 maximumDamage, Predicate<IMobState> predicate)
|
||||
{
|
||||
foreach (var (threshold, state) in _highestToLowestStates)
|
||||
{
|
||||
@@ -185,30 +186,30 @@ namespace Content.Shared.MobState.Components
|
||||
return null;
|
||||
}
|
||||
|
||||
public (IMobState state, int threshold)? GetEarliestCriticalState(int minimumDamage)
|
||||
public (IMobState state, FixedPoint2 threshold)? GetEarliestCriticalState(FixedPoint2 minimumDamage)
|
||||
{
|
||||
return GetEarliestState(minimumDamage, s => s.IsCritical());
|
||||
}
|
||||
|
||||
public (IMobState state, int threshold)? GetEarliestIncapacitatedState(int minimumDamage)
|
||||
public (IMobState state, FixedPoint2 threshold)? GetEarliestIncapacitatedState(FixedPoint2 minimumDamage)
|
||||
{
|
||||
return GetEarliestState(minimumDamage, s => s.IsIncapacitated());
|
||||
}
|
||||
|
||||
public (IMobState state, int threshold)? GetEarliestDeadState(int minimumDamage)
|
||||
public (IMobState state, FixedPoint2 threshold)? GetEarliestDeadState(FixedPoint2 minimumDamage)
|
||||
{
|
||||
return GetEarliestState(minimumDamage, s => s.IsDead());
|
||||
}
|
||||
|
||||
public (IMobState state, int threshold)? GetPreviousCriticalState(int minimumDamage)
|
||||
public (IMobState state, FixedPoint2 threshold)? GetPreviousCriticalState(FixedPoint2 minimumDamage)
|
||||
{
|
||||
return GetPreviousState(minimumDamage, s => s.IsCritical());
|
||||
}
|
||||
|
||||
private bool TryGetState(
|
||||
(IMobState state, int threshold)? tuple,
|
||||
(IMobState state, FixedPoint2 threshold)? tuple,
|
||||
[NotNullWhen(true)] out IMobState? state,
|
||||
out int threshold)
|
||||
out FixedPoint2 threshold)
|
||||
{
|
||||
if (tuple == null)
|
||||
{
|
||||
@@ -222,9 +223,9 @@ namespace Content.Shared.MobState.Components
|
||||
}
|
||||
|
||||
public bool TryGetEarliestCriticalState(
|
||||
int minimumDamage,
|
||||
FixedPoint2 minimumDamage,
|
||||
[NotNullWhen(true)] out IMobState? state,
|
||||
out int threshold)
|
||||
out FixedPoint2 threshold)
|
||||
{
|
||||
var earliestState = GetEarliestCriticalState(minimumDamage);
|
||||
|
||||
@@ -232,9 +233,9 @@ namespace Content.Shared.MobState.Components
|
||||
}
|
||||
|
||||
public bool TryGetEarliestIncapacitatedState(
|
||||
int minimumDamage,
|
||||
FixedPoint2 minimumDamage,
|
||||
[NotNullWhen(true)] out IMobState? state,
|
||||
out int threshold)
|
||||
out FixedPoint2 threshold)
|
||||
{
|
||||
var earliestState = GetEarliestIncapacitatedState(minimumDamage);
|
||||
|
||||
@@ -242,9 +243,9 @@ namespace Content.Shared.MobState.Components
|
||||
}
|
||||
|
||||
public bool TryGetEarliestDeadState(
|
||||
int minimumDamage,
|
||||
FixedPoint2 minimumDamage,
|
||||
[NotNullWhen(true)] out IMobState? state,
|
||||
out int threshold)
|
||||
out FixedPoint2 threshold)
|
||||
{
|
||||
var earliestState = GetEarliestDeadState(minimumDamage);
|
||||
|
||||
@@ -252,9 +253,9 @@ namespace Content.Shared.MobState.Components
|
||||
}
|
||||
|
||||
public bool TryGetPreviousCriticalState(
|
||||
int maximumDamage,
|
||||
FixedPoint2 maximumDamage,
|
||||
[NotNullWhen(true)] out IMobState? state,
|
||||
out int threshold)
|
||||
out FixedPoint2 threshold)
|
||||
{
|
||||
var earliestState = GetPreviousCriticalState(maximumDamage);
|
||||
|
||||
@@ -273,7 +274,7 @@ namespace Content.Shared.MobState.Components
|
||||
/// <summary>
|
||||
/// Updates the mob state..
|
||||
/// </summary>
|
||||
public void UpdateState(int damage)
|
||||
public void UpdateState(FixedPoint2 damage)
|
||||
{
|
||||
if (!TryGetState(damage, out var newState, out var threshold))
|
||||
{
|
||||
@@ -286,7 +287,7 @@ namespace Content.Shared.MobState.Components
|
||||
/// <summary>
|
||||
/// Sets the mob state and marks the component as dirty.
|
||||
/// </summary>
|
||||
private void SetMobState(IMobState? old, (IMobState state, int threshold)? current)
|
||||
private void SetMobState(IMobState? old, (IMobState state, FixedPoint2 threshold)? current)
|
||||
{
|
||||
if (!current.HasValue)
|
||||
{
|
||||
@@ -324,9 +325,9 @@ namespace Content.Shared.MobState.Components
|
||||
[Serializable, NetSerializable]
|
||||
public class MobStateComponentState : ComponentState
|
||||
{
|
||||
public readonly int? CurrentThreshold;
|
||||
public readonly FixedPoint2? CurrentThreshold;
|
||||
|
||||
public MobStateComponentState(int? currentThreshold)
|
||||
public MobStateComponentState(FixedPoint2? currentThreshold)
|
||||
{
|
||||
CurrentThreshold = currentThreshold;
|
||||
}
|
||||
|
||||
@@ -1,4 +1,5 @@
|
||||
using System.Diagnostics.CodeAnalysis;
|
||||
using Content.Shared.FixedPoint;
|
||||
using Content.Shared.MobState.State;
|
||||
using Robust.Shared.GameObjects;
|
||||
|
||||
@@ -16,34 +17,34 @@ namespace Content.Shared.MobState
|
||||
|
||||
bool IsIncapacitated();
|
||||
|
||||
(IMobState state, int threshold)? GetEarliestIncapacitatedState(int minimumDamage);
|
||||
(IMobState state, FixedPoint2 threshold)? GetEarliestIncapacitatedState(FixedPoint2 minimumDamage);
|
||||
|
||||
(IMobState state, int threshold)? GetEarliestCriticalState(int minimumDamage);
|
||||
(IMobState state, FixedPoint2 threshold)? GetEarliestCriticalState(FixedPoint2 minimumDamage);
|
||||
|
||||
(IMobState state, int threshold)? GetEarliestDeadState(int minimumDamage);
|
||||
(IMobState state, FixedPoint2 threshold)? GetEarliestDeadState(FixedPoint2 minimumDamage);
|
||||
|
||||
(IMobState state, int threshold)? GetPreviousCriticalState(int maximumDamage);
|
||||
(IMobState state, FixedPoint2 threshold)? GetPreviousCriticalState(FixedPoint2 maximumDamage);
|
||||
|
||||
bool TryGetEarliestIncapacitatedState(
|
||||
int minimumDamage,
|
||||
FixedPoint2 minimumDamage,
|
||||
[NotNullWhen(true)] out IMobState? state,
|
||||
out int threshold);
|
||||
out FixedPoint2 threshold);
|
||||
|
||||
bool TryGetEarliestCriticalState(
|
||||
int minimumDamage,
|
||||
FixedPoint2 minimumDamage,
|
||||
[NotNullWhen(true)] out IMobState? state,
|
||||
out int threshold);
|
||||
out FixedPoint2 threshold);
|
||||
|
||||
bool TryGetEarliestDeadState(
|
||||
int minimumDamage,
|
||||
FixedPoint2 minimumDamage,
|
||||
[NotNullWhen(true)] out IMobState? state,
|
||||
out int threshold);
|
||||
out FixedPoint2 threshold);
|
||||
|
||||
bool TryGetPreviousCriticalState(
|
||||
int maximumDamage,
|
||||
FixedPoint2 maximumDamage,
|
||||
[NotNullWhen(true)] out IMobState? state,
|
||||
out int threshold);
|
||||
out FixedPoint2 threshold);
|
||||
|
||||
void UpdateState(int damage);
|
||||
void UpdateState(FixedPoint2 damage);
|
||||
}
|
||||
}
|
||||
|
||||
@@ -1,4 +1,5 @@
|
||||
using Robust.Shared.GameObjects;
|
||||
using Content.Shared.FixedPoint;
|
||||
using Robust.Shared.GameObjects;
|
||||
using Robust.Shared.Serialization.Manager.Attributes;
|
||||
|
||||
namespace Content.Shared.MobState.State
|
||||
@@ -32,6 +33,6 @@ namespace Content.Shared.MobState.State
|
||||
|
||||
public virtual void ExitState(IEntity entity) { }
|
||||
|
||||
public virtual void UpdateState(IEntity entity, int threshold) { }
|
||||
public virtual void UpdateState(IEntity entity, FixedPoint2 threshold) { }
|
||||
}
|
||||
}
|
||||
|
||||
@@ -1,4 +1,5 @@
|
||||
using Content.Shared.ActionBlocker;
|
||||
using Content.Shared.FixedPoint;
|
||||
using Robust.Shared.GameObjects;
|
||||
|
||||
namespace Content.Shared.MobState.State
|
||||
@@ -36,6 +37,6 @@ namespace Content.Shared.MobState.State
|
||||
/// <summary>
|
||||
/// Called when this state is updated.
|
||||
/// </summary>
|
||||
void UpdateState(IEntity entity, int threshold);
|
||||
void UpdateState(IEntity entity, FixedPoint2 threshold);
|
||||
}
|
||||
}
|
||||
|
||||
Reference in New Issue
Block a user