Add SolutionContainerSystem tests (#6726)
This commit is contained in:
195
Content.IntegrationTests/Tests/Chemistry/SolutionSystemTests.cs
Normal file
195
Content.IntegrationTests/Tests/Chemistry/SolutionSystemTests.cs
Normal file
@@ -0,0 +1,195 @@
|
|||||||
|
using System.Threading.Tasks;
|
||||||
|
using Content.Server.Chemistry.EntitySystems;
|
||||||
|
using Content.Shared.Chemistry.Components;
|
||||||
|
using Content.Shared.FixedPoint;
|
||||||
|
using NUnit.Framework;
|
||||||
|
using Robust.Shared.GameObjects;
|
||||||
|
using Robust.Shared.Map;
|
||||||
|
|
||||||
|
namespace Content.IntegrationTests.Tests.Chemistry;
|
||||||
|
|
||||||
|
|
||||||
|
// We are adding two non-reactive solutions in these tests
|
||||||
|
// To ensure volume(A) + volume(B) = volume(A+B)
|
||||||
|
// reactions can change this assumption
|
||||||
|
[TestFixture]
|
||||||
|
[TestOf(typeof(SolutionContainerSystem))]
|
||||||
|
public sealed class SolutionSystemTests : ContentIntegrationTest
|
||||||
|
{
|
||||||
|
private const string Prototypes = @"
|
||||||
|
- type: entity
|
||||||
|
id: SolutionTarget
|
||||||
|
components:
|
||||||
|
- type: SolutionContainerManager
|
||||||
|
solutions:
|
||||||
|
beaker:
|
||||||
|
maxVol: 50
|
||||||
|
";
|
||||||
|
|
||||||
|
[Test]
|
||||||
|
public async Task TryAddTwoNonReactiveReagent()
|
||||||
|
{
|
||||||
|
var options = new ServerContentIntegrationOption { ExtraPrototypes = Prototypes };
|
||||||
|
var server = StartServer(options);
|
||||||
|
|
||||||
|
await server.WaitIdleAsync();
|
||||||
|
|
||||||
|
var entityManager = server.ResolveDependency<IEntityManager>();
|
||||||
|
var mapManager = server.ResolveDependency<IMapManager>();
|
||||||
|
var coordinates = GetMainEntityCoordinates(mapManager);
|
||||||
|
|
||||||
|
EntityUid beaker;
|
||||||
|
|
||||||
|
server.Assert(() =>
|
||||||
|
{
|
||||||
|
var oilQuantity = FixedPoint2.New(15);
|
||||||
|
var waterQuantity = FixedPoint2.New(10);
|
||||||
|
|
||||||
|
var oilAdded = new Solution("Oil", oilQuantity);
|
||||||
|
var originalWater = new Solution("Water", waterQuantity);
|
||||||
|
|
||||||
|
beaker = entityManager.SpawnEntity("SolutionTarget", coordinates);
|
||||||
|
Assert.That(EntitySystem.Get<SolutionContainerSystem>()
|
||||||
|
.TryGetSolution(beaker, "beaker", out var solution));
|
||||||
|
|
||||||
|
solution.AddSolution(originalWater);
|
||||||
|
Assert.That(EntitySystem.Get<SolutionContainerSystem>()
|
||||||
|
.TryAddSolution(beaker, solution, oilAdded));
|
||||||
|
|
||||||
|
solution.ContainsReagent("Water", out var water);
|
||||||
|
solution.ContainsReagent("Oil", out var oil);
|
||||||
|
Assert.That(water, Is.EqualTo(waterQuantity));
|
||||||
|
Assert.That(oil, Is.EqualTo(oilQuantity));
|
||||||
|
});
|
||||||
|
|
||||||
|
await server.WaitIdleAsync();
|
||||||
|
}
|
||||||
|
|
||||||
|
// This test mimics current behavior
|
||||||
|
// i.e. if adding too much `TryAddSolution` adding will fail
|
||||||
|
[Test]
|
||||||
|
public async Task TryAddTooMuchNonReactiveReagent()
|
||||||
|
{
|
||||||
|
var options = new ServerContentIntegrationOption { ExtraPrototypes = Prototypes };
|
||||||
|
var server = StartServer(options);
|
||||||
|
|
||||||
|
await server.WaitIdleAsync();
|
||||||
|
|
||||||
|
var entityManager = server.ResolveDependency<IEntityManager>();
|
||||||
|
var mapManager = server.ResolveDependency<IMapManager>();
|
||||||
|
var coordinates = GetMainEntityCoordinates(mapManager);
|
||||||
|
|
||||||
|
EntityUid beaker;
|
||||||
|
|
||||||
|
server.Assert(() =>
|
||||||
|
{
|
||||||
|
var oilQuantity = FixedPoint2.New(1500);
|
||||||
|
var waterQuantity = FixedPoint2.New(10);
|
||||||
|
|
||||||
|
var oilAdded = new Solution("Oil", oilQuantity);
|
||||||
|
var originalWater = new Solution("Water", waterQuantity);
|
||||||
|
|
||||||
|
beaker = entityManager.SpawnEntity("SolutionTarget", coordinates);
|
||||||
|
Assert.That(EntitySystem.Get<SolutionContainerSystem>()
|
||||||
|
.TryGetSolution(beaker, "beaker", out var solution));
|
||||||
|
|
||||||
|
solution.AddSolution(originalWater);
|
||||||
|
Assert.That(EntitySystem.Get<SolutionContainerSystem>()
|
||||||
|
.TryAddSolution(beaker, solution, oilAdded), Is.False);
|
||||||
|
|
||||||
|
solution.ContainsReagent("Water", out var water);
|
||||||
|
solution.ContainsReagent("Oil", out var oil);
|
||||||
|
Assert.That(water, Is.EqualTo(waterQuantity));
|
||||||
|
Assert.That(oil, Is.EqualTo(FixedPoint2.Zero));
|
||||||
|
});
|
||||||
|
|
||||||
|
await server.WaitIdleAsync();
|
||||||
|
}
|
||||||
|
|
||||||
|
// Unlike TryAddSolution this adds and two solution without then splits leaving only threshold in original
|
||||||
|
[Test]
|
||||||
|
public async Task TryMixAndOverflowTooMuchReagent()
|
||||||
|
{
|
||||||
|
var options = new ServerContentIntegrationOption { ExtraPrototypes = Prototypes };
|
||||||
|
var server = StartServer(options);
|
||||||
|
|
||||||
|
await server.WaitIdleAsync();
|
||||||
|
|
||||||
|
var entityManager = server.ResolveDependency<IEntityManager>();
|
||||||
|
var mapManager = server.ResolveDependency<IMapManager>();
|
||||||
|
var coordinates = GetMainEntityCoordinates(mapManager);
|
||||||
|
|
||||||
|
EntityUid beaker;
|
||||||
|
|
||||||
|
server.Assert(() =>
|
||||||
|
{
|
||||||
|
int ratio = 9;
|
||||||
|
int threshold = 20;
|
||||||
|
var waterQuantity = FixedPoint2.New(10);
|
||||||
|
var oilQuantity = FixedPoint2.New(ratio * waterQuantity.Int());
|
||||||
|
|
||||||
|
var oilAdded = new Solution("Oil", oilQuantity);
|
||||||
|
var originalWater = new Solution("Water", waterQuantity);
|
||||||
|
|
||||||
|
beaker = entityManager.SpawnEntity("SolutionTarget", coordinates);
|
||||||
|
Assert.That(EntitySystem.Get<SolutionContainerSystem>()
|
||||||
|
.TryGetSolution(beaker, "beaker", out var solution));
|
||||||
|
|
||||||
|
solution.AddSolution(originalWater);
|
||||||
|
Assert.That(EntitySystem.Get<SolutionContainerSystem>()
|
||||||
|
.TryMixAndOverflow(beaker, solution, oilAdded, threshold, out var overflowingSolution));
|
||||||
|
|
||||||
|
Assert.That(solution.CurrentVolume, Is.EqualTo(FixedPoint2.New(threshold)));
|
||||||
|
solution.ContainsReagent("Water", out var waterMix);
|
||||||
|
solution.ContainsReagent("Oil", out var oilMix);
|
||||||
|
Assert.That(waterMix, Is.EqualTo(FixedPoint2.New(threshold / (ratio + 1))));
|
||||||
|
Assert.That(oilMix, Is.EqualTo(FixedPoint2.New(threshold / (ratio + 1) * ratio)));
|
||||||
|
|
||||||
|
Assert.That(overflowingSolution.CurrentVolume, Is.EqualTo(FixedPoint2.New(80)));
|
||||||
|
overflowingSolution.ContainsReagent("Water", out var waterOverflow);
|
||||||
|
overflowingSolution.ContainsReagent("Oil", out var oilOverFlow);
|
||||||
|
Assert.That(waterOverflow, Is.EqualTo(waterQuantity - waterMix));
|
||||||
|
Assert.That(oilOverFlow, Is.EqualTo(oilQuantity - oilMix));
|
||||||
|
});
|
||||||
|
|
||||||
|
await server.WaitIdleAsync();
|
||||||
|
}
|
||||||
|
|
||||||
|
// TryMixAndOverflow will fail if Threshold larger than MaxVolume
|
||||||
|
[Test]
|
||||||
|
public async Task TryMixAndOverflowTooBigOverflow()
|
||||||
|
{
|
||||||
|
var options = new ServerContentIntegrationOption { ExtraPrototypes = Prototypes };
|
||||||
|
var server = StartServer(options);
|
||||||
|
|
||||||
|
await server.WaitIdleAsync();
|
||||||
|
|
||||||
|
var entityManager = server.ResolveDependency<IEntityManager>();
|
||||||
|
var mapManager = server.ResolveDependency<IMapManager>();
|
||||||
|
var coordinates = GetMainEntityCoordinates(mapManager);
|
||||||
|
|
||||||
|
EntityUid beaker;
|
||||||
|
|
||||||
|
server.Assert(() =>
|
||||||
|
{
|
||||||
|
int ratio = 9;
|
||||||
|
int threshold = 60;
|
||||||
|
var waterQuantity = FixedPoint2.New(10);
|
||||||
|
var oilQuantity = FixedPoint2.New(ratio * waterQuantity.Int());
|
||||||
|
|
||||||
|
var oilAdded = new Solution("Oil", oilQuantity);
|
||||||
|
var originalWater = new Solution("Water", waterQuantity);
|
||||||
|
|
||||||
|
beaker = entityManager.SpawnEntity("SolutionTarget", coordinates);
|
||||||
|
Assert.That(EntitySystem.Get<SolutionContainerSystem>()
|
||||||
|
.TryGetSolution(beaker, "beaker", out var solution));
|
||||||
|
|
||||||
|
solution.AddSolution(originalWater);
|
||||||
|
Assert.That(EntitySystem.Get<SolutionContainerSystem>()
|
||||||
|
.TryMixAndOverflow(beaker, solution, oilAdded, threshold, out _),
|
||||||
|
Is.False);
|
||||||
|
});
|
||||||
|
|
||||||
|
await server.WaitIdleAsync();
|
||||||
|
}
|
||||||
|
}
|
||||||
@@ -1,156 +1,153 @@
|
|||||||
using System.Diagnostics.CodeAnalysis;
|
using System.Diagnostics.CodeAnalysis;
|
||||||
using System.Text;
|
using System.Text;
|
||||||
using Content.Server.Chemistry.Components.SolutionManager;
|
using Content.Server.Chemistry.Components.SolutionManager;
|
||||||
using Content.Server.Database;
|
|
||||||
using Content.Shared.Chemistry.Components;
|
using Content.Shared.Chemistry.Components;
|
||||||
using Content.Shared.Chemistry.Reagent;
|
|
||||||
using Content.Shared.FixedPoint;
|
using Content.Shared.FixedPoint;
|
||||||
using Robust.Shared.GameObjects;
|
|
||||||
|
|
||||||
namespace Content.Server.Chemistry.EntitySystems
|
namespace Content.Server.Chemistry.EntitySystems;
|
||||||
|
|
||||||
|
public sealed partial class SolutionContainerSystem
|
||||||
{
|
{
|
||||||
public sealed partial class SolutionContainerSystem
|
public void Refill(EntityUid targetUid, Solution targetSolution, Solution addedSolution,
|
||||||
|
RefillableSolutionComponent? refillableSolution = null)
|
||||||
{
|
{
|
||||||
public void Refill(EntityUid targetUid, Solution targetSolution, Solution addedSolution,
|
if (!Resolve(targetUid, ref refillableSolution, false))
|
||||||
RefillableSolutionComponent? refillableSolution = null)
|
return;
|
||||||
{
|
|
||||||
if (!Resolve(targetUid, ref refillableSolution, false))
|
|
||||||
return;
|
|
||||||
|
|
||||||
TryAddSolution(targetUid, targetSolution, addedSolution);
|
TryAddSolution(targetUid, targetSolution, addedSolution);
|
||||||
|
}
|
||||||
|
|
||||||
|
public void Inject(EntityUid targetUid, Solution targetSolution, Solution addedSolution,
|
||||||
|
InjectableSolutionComponent? injectableSolution = null)
|
||||||
|
{
|
||||||
|
if (!Resolve(targetUid, ref injectableSolution, false))
|
||||||
|
return;
|
||||||
|
|
||||||
|
TryAddSolution(targetUid, targetSolution, addedSolution);
|
||||||
|
}
|
||||||
|
|
||||||
|
public Solution Draw(EntityUid targetUid, Solution solution, FixedPoint2 amount,
|
||||||
|
DrawableSolutionComponent? drawableSolution = null)
|
||||||
|
{
|
||||||
|
if (!Resolve(targetUid, ref drawableSolution, false))
|
||||||
|
return new Solution();
|
||||||
|
|
||||||
|
return SplitSolution(targetUid, solution, amount);
|
||||||
|
}
|
||||||
|
|
||||||
|
public Solution Drain(EntityUid targetUid, Solution targetSolution, FixedPoint2 amount,
|
||||||
|
DrainableSolutionComponent? drainableSolution = null)
|
||||||
|
{
|
||||||
|
if (!Resolve(targetUid, ref drainableSolution, false))
|
||||||
|
return new Solution();
|
||||||
|
|
||||||
|
return SplitSolution(targetUid, targetSolution, amount);
|
||||||
|
}
|
||||||
|
|
||||||
|
public bool TryGetInjectableSolution(EntityUid targetUid,
|
||||||
|
[NotNullWhen(true)] out Solution? solution,
|
||||||
|
InjectableSolutionComponent? injectable = null,
|
||||||
|
SolutionContainerManagerComponent? manager = null
|
||||||
|
)
|
||||||
|
{
|
||||||
|
if (!Resolve(targetUid, ref manager, ref injectable, false)
|
||||||
|
|| !manager.Solutions.TryGetValue(injectable.Solution, out solution))
|
||||||
|
{
|
||||||
|
solution = null;
|
||||||
|
return false;
|
||||||
}
|
}
|
||||||
|
|
||||||
public void Inject(EntityUid targetUid, Solution targetSolution, Solution addedSolution,
|
return true;
|
||||||
InjectableSolutionComponent? injectableSolution = null)
|
}
|
||||||
{
|
|
||||||
if (!Resolve(targetUid, ref injectableSolution, false))
|
|
||||||
return;
|
|
||||||
|
|
||||||
TryAddSolution(targetUid, targetSolution, addedSolution);
|
public bool TryGetRefillableSolution(EntityUid targetUid,
|
||||||
|
[NotNullWhen(true)] out Solution? solution,
|
||||||
|
SolutionContainerManagerComponent? solutionManager = null,
|
||||||
|
RefillableSolutionComponent? refillable = null)
|
||||||
|
{
|
||||||
|
if (!Resolve(targetUid, ref solutionManager, ref refillable, false)
|
||||||
|
|| !solutionManager.Solutions.TryGetValue(refillable.Solution, out var refillableSolution))
|
||||||
|
{
|
||||||
|
solution = null;
|
||||||
|
return false;
|
||||||
}
|
}
|
||||||
|
|
||||||
public Solution Draw(EntityUid targetUid, Solution solution, FixedPoint2 amount,
|
solution = refillableSolution;
|
||||||
DrawableSolutionComponent? drawableSolution = null)
|
return true;
|
||||||
{
|
}
|
||||||
if (!Resolve(targetUid, ref drawableSolution, false))
|
|
||||||
return new Solution();
|
|
||||||
|
|
||||||
return SplitSolution(targetUid, solution, amount);
|
public bool TryGetDrainableSolution(EntityUid uid,
|
||||||
|
[NotNullWhen(true)] out Solution? solution,
|
||||||
|
DrainableSolutionComponent? drainable = null,
|
||||||
|
SolutionContainerManagerComponent? manager = null)
|
||||||
|
{
|
||||||
|
if (!Resolve(uid, ref drainable, ref manager, false)
|
||||||
|
|| !manager.Solutions.TryGetValue(drainable.Solution, out solution))
|
||||||
|
{
|
||||||
|
solution = null;
|
||||||
|
return false;
|
||||||
}
|
}
|
||||||
|
|
||||||
public Solution Drain(EntityUid targetUid, Solution targetSolution, FixedPoint2 amount,
|
return true;
|
||||||
DrainableSolutionComponent? drainableSolution = null)
|
}
|
||||||
{
|
|
||||||
if (!Resolve(targetUid, ref drainableSolution, false))
|
|
||||||
return new Solution();
|
|
||||||
|
|
||||||
return SplitSolution(targetUid, targetSolution, amount);
|
public bool TryGetDrawableSolution(EntityUid uid,
|
||||||
|
[NotNullWhen(true)] out Solution? solution,
|
||||||
|
DrawableSolutionComponent? drawable = null,
|
||||||
|
SolutionContainerManagerComponent? manager = null)
|
||||||
|
{
|
||||||
|
if (!Resolve(uid, ref drawable, ref manager, false)
|
||||||
|
|| !manager.Solutions.TryGetValue(drawable.Solution, out solution))
|
||||||
|
{
|
||||||
|
solution = null;
|
||||||
|
return false;
|
||||||
}
|
}
|
||||||
|
|
||||||
public bool TryGetInjectableSolution(EntityUid targetUid,
|
return true;
|
||||||
[NotNullWhen(true)] out Solution? solution,
|
}
|
||||||
InjectableSolutionComponent? injectable = null,
|
|
||||||
SolutionContainerManagerComponent? manager = null
|
public FixedPoint2 DrainAvailable(EntityUid uid)
|
||||||
)
|
{
|
||||||
|
return !TryGetDrainableSolution(uid, out var solution)
|
||||||
|
? FixedPoint2.Zero
|
||||||
|
: solution.CurrentVolume;
|
||||||
|
}
|
||||||
|
|
||||||
|
public bool TryGetFitsInDispenser(EntityUid owner,
|
||||||
|
[NotNullWhen(true)] out Solution? solution,
|
||||||
|
FitsInDispenserComponent? dispenserFits = null,
|
||||||
|
SolutionContainerManagerComponent? solutionManager = null)
|
||||||
|
{
|
||||||
|
if (!Resolve(owner, ref dispenserFits, ref solutionManager, false)
|
||||||
|
|| !solutionManager.Solutions.TryGetValue(dispenserFits.Solution, out solution))
|
||||||
{
|
{
|
||||||
if (!Resolve(targetUid, ref manager, ref injectable, false)
|
solution = null;
|
||||||
|| !manager.Solutions.TryGetValue(injectable.Solution, out solution))
|
return false;
|
||||||
|
}
|
||||||
|
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
|
||||||
|
public static string ToPrettyString(Solution solution)
|
||||||
|
{
|
||||||
|
var sb = new StringBuilder();
|
||||||
|
sb.Append("[");
|
||||||
|
var first = true;
|
||||||
|
foreach (var (id, quantity) in solution.Contents)
|
||||||
|
{
|
||||||
|
if (first)
|
||||||
{
|
{
|
||||||
solution = null;
|
first = false;
|
||||||
return false;
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
sb.Append(", ");
|
||||||
}
|
}
|
||||||
|
|
||||||
return true;
|
sb.AppendFormat("{0}: {1}u", id, quantity);
|
||||||
}
|
}
|
||||||
|
|
||||||
public bool TryGetRefillableSolution(EntityUid targetUid,
|
sb.Append(']');
|
||||||
[NotNullWhen(true)] out Solution? solution,
|
return sb.ToString();
|
||||||
SolutionContainerManagerComponent? solutionManager = null,
|
|
||||||
RefillableSolutionComponent? refillable = null)
|
|
||||||
{
|
|
||||||
if (!Resolve(targetUid, ref solutionManager, ref refillable, false)
|
|
||||||
|| !solutionManager.Solutions.TryGetValue(refillable.Solution, out var refillableSolution))
|
|
||||||
{
|
|
||||||
solution = null;
|
|
||||||
return false;
|
|
||||||
}
|
|
||||||
|
|
||||||
solution = refillableSolution;
|
|
||||||
return true;
|
|
||||||
}
|
|
||||||
|
|
||||||
public bool TryGetDrainableSolution(EntityUid uid,
|
|
||||||
[NotNullWhen(true)] out Solution? solution,
|
|
||||||
DrainableSolutionComponent? drainable = null,
|
|
||||||
SolutionContainerManagerComponent? manager = null)
|
|
||||||
{
|
|
||||||
if (!Resolve(uid, ref drainable, ref manager, false)
|
|
||||||
|| !manager.Solutions.TryGetValue(drainable.Solution, out solution))
|
|
||||||
{
|
|
||||||
solution = null;
|
|
||||||
return false;
|
|
||||||
}
|
|
||||||
|
|
||||||
return true;
|
|
||||||
}
|
|
||||||
|
|
||||||
public bool TryGetDrawableSolution(EntityUid uid,
|
|
||||||
[NotNullWhen(true)] out Solution? solution,
|
|
||||||
DrawableSolutionComponent? drawable = null,
|
|
||||||
SolutionContainerManagerComponent? manager = null)
|
|
||||||
{
|
|
||||||
if (!Resolve(uid, ref drawable, ref manager, false)
|
|
||||||
|| !manager.Solutions.TryGetValue(drawable.Solution, out solution))
|
|
||||||
{
|
|
||||||
solution = null;
|
|
||||||
return false;
|
|
||||||
}
|
|
||||||
|
|
||||||
return true;
|
|
||||||
}
|
|
||||||
|
|
||||||
public FixedPoint2 DrainAvailable(EntityUid uid)
|
|
||||||
{
|
|
||||||
return !TryGetDrainableSolution(uid, out var solution)
|
|
||||||
? FixedPoint2.Zero
|
|
||||||
: solution.CurrentVolume;
|
|
||||||
}
|
|
||||||
|
|
||||||
public bool TryGetFitsInDispenser(EntityUid owner,
|
|
||||||
[NotNullWhen(true)] out Solution? solution,
|
|
||||||
FitsInDispenserComponent? dispenserFits = null,
|
|
||||||
SolutionContainerManagerComponent? solutionManager = null)
|
|
||||||
{
|
|
||||||
if (!Resolve(owner, ref dispenserFits, ref solutionManager, false)
|
|
||||||
|| !solutionManager.Solutions.TryGetValue(dispenserFits.Solution, out solution))
|
|
||||||
{
|
|
||||||
solution = null;
|
|
||||||
return false;
|
|
||||||
}
|
|
||||||
|
|
||||||
return true;
|
|
||||||
}
|
|
||||||
|
|
||||||
public static string ToPrettyString(Solution solution)
|
|
||||||
{
|
|
||||||
var sb = new StringBuilder();
|
|
||||||
sb.Append("[");
|
|
||||||
var first = true;
|
|
||||||
foreach (var (id, quantity) in solution.Contents)
|
|
||||||
{
|
|
||||||
if (first)
|
|
||||||
{
|
|
||||||
first = false;
|
|
||||||
}
|
|
||||||
else
|
|
||||||
{
|
|
||||||
sb.Append(", ");
|
|
||||||
}
|
|
||||||
sb.AppendFormat("{0}: {1}u", id, quantity);
|
|
||||||
|
|
||||||
}
|
|
||||||
sb.Append(']');
|
|
||||||
return sb.ToString();
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -1,8 +1,5 @@
|
|||||||
using System;
|
|
||||||
using System.Collections.Generic;
|
|
||||||
using System.Diagnostics.CodeAnalysis;
|
using System.Diagnostics.CodeAnalysis;
|
||||||
using Content.Server.Chemistry.Components.SolutionManager;
|
using Content.Server.Chemistry.Components.SolutionManager;
|
||||||
using Content.Server.Fluids.Components;
|
|
||||||
using Content.Shared.Chemistry;
|
using Content.Shared.Chemistry;
|
||||||
using Content.Shared.Chemistry.Components;
|
using Content.Shared.Chemistry.Components;
|
||||||
using Content.Shared.Chemistry.Reaction;
|
using Content.Shared.Chemistry.Reaction;
|
||||||
@@ -10,385 +7,384 @@ using Content.Shared.Chemistry.Reagent;
|
|||||||
using Content.Shared.Examine;
|
using Content.Shared.Examine;
|
||||||
using Content.Shared.FixedPoint;
|
using Content.Shared.FixedPoint;
|
||||||
using JetBrains.Annotations;
|
using JetBrains.Annotations;
|
||||||
using Robust.Shared.GameObjects;
|
|
||||||
using Robust.Shared.IoC;
|
|
||||||
using Robust.Shared.Localization;
|
|
||||||
using Robust.Shared.Log;
|
|
||||||
using Robust.Shared.Prototypes;
|
using Robust.Shared.Prototypes;
|
||||||
using Robust.Shared.Utility;
|
using Robust.Shared.Utility;
|
||||||
|
|
||||||
namespace Content.Server.Chemistry.EntitySystems
|
namespace Content.Server.Chemistry.EntitySystems;
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// This event alerts system that the solution was changed
|
||||||
|
/// </summary>
|
||||||
|
public sealed class SolutionChangedEvent : EntityEventArgs
|
||||||
{
|
{
|
||||||
/// <summary>
|
}
|
||||||
/// This event alerts system that the solution was changed
|
|
||||||
/// </summary>
|
/// <summary>
|
||||||
public sealed class SolutionChangedEvent : EntityEventArgs
|
/// Part of Chemistry system deal with SolutionContainers
|
||||||
|
/// </summary>
|
||||||
|
[UsedImplicitly]
|
||||||
|
public sealed partial class SolutionContainerSystem : EntitySystem
|
||||||
|
{
|
||||||
|
[Dependency]
|
||||||
|
private readonly SharedChemicalReactionSystem _chemistrySystem = default!;
|
||||||
|
|
||||||
|
[Dependency]
|
||||||
|
private readonly IPrototypeManager _prototypeManager = default!;
|
||||||
|
|
||||||
|
public override void Initialize()
|
||||||
{
|
{
|
||||||
|
base.Initialize();
|
||||||
|
|
||||||
|
SubscribeLocalEvent<SolutionContainerManagerComponent, ComponentInit>(InitSolution);
|
||||||
|
SubscribeLocalEvent<ExaminableSolutionComponent, ExaminedEvent>(OnExamineSolution);
|
||||||
}
|
}
|
||||||
|
|
||||||
/// <summary>
|
private void InitSolution(EntityUid uid, SolutionContainerManagerComponent component, ComponentInit args)
|
||||||
/// Part of Chemistry system deal with SolutionContainers
|
|
||||||
/// </summary>
|
|
||||||
[UsedImplicitly]
|
|
||||||
public sealed partial class SolutionContainerSystem : EntitySystem
|
|
||||||
{
|
{
|
||||||
[Dependency]
|
foreach (var keyValue in component.Solutions)
|
||||||
private readonly SharedChemicalReactionSystem _chemistrySystem = default!;
|
|
||||||
|
|
||||||
[Dependency]
|
|
||||||
private readonly IPrototypeManager _prototypeManager = default!;
|
|
||||||
|
|
||||||
public override void Initialize()
|
|
||||||
{
|
{
|
||||||
base.Initialize();
|
var solutionHolder = keyValue.Value;
|
||||||
|
if (solutionHolder.MaxVolume == FixedPoint2.Zero)
|
||||||
SubscribeLocalEvent<SolutionContainerManagerComponent, ComponentInit>(InitSolution);
|
|
||||||
SubscribeLocalEvent<ExaminableSolutionComponent, ExaminedEvent>(OnExamineSolution);
|
|
||||||
}
|
|
||||||
|
|
||||||
private void InitSolution(EntityUid uid, SolutionContainerManagerComponent component, ComponentInit args)
|
|
||||||
{
|
|
||||||
foreach (var keyValue in component.Solutions)
|
|
||||||
{
|
{
|
||||||
var solutionHolder = keyValue.Value;
|
solutionHolder.MaxVolume = solutionHolder.TotalVolume > solutionHolder.InitialMaxVolume
|
||||||
if (solutionHolder.MaxVolume == FixedPoint2.Zero)
|
? solutionHolder.TotalVolume
|
||||||
{
|
: solutionHolder.InitialMaxVolume;
|
||||||
solutionHolder.MaxVolume = solutionHolder.TotalVolume > solutionHolder.InitialMaxVolume
|
|
||||||
? solutionHolder.TotalVolume
|
|
||||||
: solutionHolder.InitialMaxVolume;
|
|
||||||
}
|
|
||||||
|
|
||||||
UpdateAppearance(uid, solutionHolder);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
private void OnExamineSolution(EntityUid uid, ExaminableSolutionComponent examinableComponent,
|
|
||||||
ExaminedEvent args)
|
|
||||||
{
|
|
||||||
SolutionContainerManagerComponent? solutionsManager = null;
|
|
||||||
if (!Resolve(args.Examined, ref solutionsManager)
|
|
||||||
|| !solutionsManager.Solutions.TryGetValue(examinableComponent.Solution, out var solutionHolder))
|
|
||||||
return;
|
|
||||||
|
|
||||||
if (solutionHolder.Contents.Count == 0)
|
|
||||||
{
|
|
||||||
args.PushText(Loc.GetString("shared-solution-container-component-on-examine-empty-container"));
|
|
||||||
return;
|
|
||||||
}
|
|
||||||
|
|
||||||
var primaryReagent = solutionHolder.GetPrimaryReagentId();
|
|
||||||
|
|
||||||
if (!_prototypeManager.TryIndex(primaryReagent, out ReagentPrototype? proto))
|
|
||||||
{
|
|
||||||
Logger.Error(
|
|
||||||
$"{nameof(Solution)} could not find the prototype associated with {primaryReagent}.");
|
|
||||||
return;
|
|
||||||
}
|
|
||||||
|
|
||||||
var colorHex = solutionHolder.Color
|
|
||||||
.ToHexNoAlpha(); //TODO: If the chem has a dark color, the examine text becomes black on a black background, which is unreadable.
|
|
||||||
var messageString = "shared-solution-container-component-on-examine-main-text";
|
|
||||||
|
|
||||||
args.PushMarkup(Loc.GetString(messageString,
|
|
||||||
("color", colorHex),
|
|
||||||
("wordedAmount", Loc.GetString(solutionHolder.Contents.Count == 1
|
|
||||||
? "shared-solution-container-component-on-examine-worded-amount-one-reagent"
|
|
||||||
: "shared-solution-container-component-on-examine-worded-amount-multiple-reagents")),
|
|
||||||
("desc", Loc.GetString(proto.PhysicalDescription))));
|
|
||||||
}
|
|
||||||
|
|
||||||
private void UpdateAppearance(EntityUid uid, Solution solution,
|
|
||||||
AppearanceComponent? appearanceComponent = null)
|
|
||||||
{
|
|
||||||
if (!EntityManager.EntityExists(uid)
|
|
||||||
|| !Resolve(uid, ref appearanceComponent, false))
|
|
||||||
return;
|
|
||||||
|
|
||||||
var filledVolumePercent = solution.CurrentVolume.Float() / solution.MaxVolume.Float();
|
|
||||||
appearanceComponent.SetData(SolutionContainerVisuals.VisualState, new SolutionContainerVisualState(solution.Color, filledVolumePercent));
|
|
||||||
}
|
|
||||||
|
|
||||||
/// <summary>
|
|
||||||
/// Removes part of the solution in the container.
|
|
||||||
/// </summary>
|
|
||||||
/// <param name="targetUid"></param>
|
|
||||||
/// <param name="solutionHolder"></param>
|
|
||||||
/// <param name="quantity">the volume of solution to remove.</param>
|
|
||||||
/// <returns>The solution that was removed.</returns>
|
|
||||||
public Solution SplitSolution(EntityUid targetUid, Solution solutionHolder, FixedPoint2 quantity)
|
|
||||||
{
|
|
||||||
var splitSol = solutionHolder.SplitSolution(quantity);
|
|
||||||
UpdateChemicals(targetUid, solutionHolder);
|
|
||||||
return splitSol;
|
|
||||||
}
|
|
||||||
|
|
||||||
private void UpdateChemicals(EntityUid uid, Solution solutionHolder, bool needsReactionsProcessing = false)
|
|
||||||
{
|
|
||||||
// Process reactions
|
|
||||||
if (needsReactionsProcessing && solutionHolder.CanReact)
|
|
||||||
{
|
|
||||||
_chemistrySystem.FullyReactSolution(solutionHolder, uid, solutionHolder.MaxVolume);
|
|
||||||
}
|
}
|
||||||
|
|
||||||
UpdateAppearance(uid, solutionHolder);
|
UpdateAppearance(uid, solutionHolder);
|
||||||
RaiseLocalEvent(uid, new SolutionChangedEvent());
|
|
||||||
}
|
}
|
||||||
|
|
||||||
public void RemoveAllSolution(EntityUid uid, Solution solutionHolder)
|
|
||||||
{
|
|
||||||
if (solutionHolder.CurrentVolume == 0)
|
|
||||||
return;
|
|
||||||
|
|
||||||
solutionHolder.RemoveAllSolution();
|
|
||||||
UpdateChemicals(uid, solutionHolder);
|
|
||||||
}
|
|
||||||
|
|
||||||
public void RemoveAllSolution(EntityUid uid, SolutionContainerManagerComponent? solutionContainerManager = null)
|
|
||||||
{
|
|
||||||
if (!Resolve(uid, ref solutionContainerManager))
|
|
||||||
return;
|
|
||||||
|
|
||||||
foreach (var solution in solutionContainerManager.Solutions.Values)
|
|
||||||
{
|
|
||||||
RemoveAllSolution(uid, solution);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
/// <summary>
|
|
||||||
/// Sets the capacity (maximum volume) of a solution to a new value.
|
|
||||||
/// </summary>
|
|
||||||
/// <param name="targetUid">The entity containing the solution.</param>
|
|
||||||
/// <param name="targetSolution">The solution to set the capacity of.</param>
|
|
||||||
/// <param name="capacity">The value to set the capacity of the solution to.</param>
|
|
||||||
public void SetCapacity(EntityUid targetUid, Solution targetSolution, FixedPoint2 capacity)
|
|
||||||
{
|
|
||||||
if (targetSolution.MaxVolume == capacity)
|
|
||||||
return;
|
|
||||||
|
|
||||||
targetSolution.MaxVolume = capacity;
|
|
||||||
if (capacity < targetSolution.CurrentVolume)
|
|
||||||
targetSolution.RemoveSolution(targetSolution.CurrentVolume - capacity);
|
|
||||||
|
|
||||||
UpdateChemicals(targetUid, targetSolution);
|
|
||||||
}
|
|
||||||
|
|
||||||
/// <summary>
|
|
||||||
/// Adds reagent of an Id to the container.
|
|
||||||
/// </summary>
|
|
||||||
/// <param name="targetUid"></param>
|
|
||||||
/// <param name="targetSolution">Container to which we are adding reagent</param>
|
|
||||||
/// <param name="reagentId">The Id of the reagent to add.</param>
|
|
||||||
/// <param name="quantity">The amount of reagent to add.</param>
|
|
||||||
/// <param name="acceptedQuantity">The amount of reagent successfully added.</param>
|
|
||||||
/// <returns>If all the reagent could be added.</returns>
|
|
||||||
public bool TryAddReagent(EntityUid targetUid, Solution targetSolution, string reagentId, FixedPoint2 quantity,
|
|
||||||
out FixedPoint2 acceptedQuantity, float? temperature = null)
|
|
||||||
{
|
|
||||||
acceptedQuantity = targetSolution.AvailableVolume > quantity ? quantity : targetSolution.AvailableVolume;
|
|
||||||
targetSolution.AddReagent(reagentId, acceptedQuantity, temperature);
|
|
||||||
|
|
||||||
if (acceptedQuantity > 0)
|
|
||||||
UpdateChemicals(targetUid, targetSolution, true);
|
|
||||||
|
|
||||||
return acceptedQuantity == quantity;
|
|
||||||
}
|
|
||||||
|
|
||||||
/// <summary>
|
|
||||||
/// Removes reagent of an Id to the container.
|
|
||||||
/// </summary>
|
|
||||||
/// <param name="targetUid"></param>
|
|
||||||
/// <param name="container">Solution container from which we are removing reagent</param>
|
|
||||||
/// <param name="reagentId">The Id of the reagent to remove.</param>
|
|
||||||
/// <param name="quantity">The amount of reagent to remove.</param>
|
|
||||||
/// <returns>If the reagent to remove was found in the container.</returns>
|
|
||||||
public bool TryRemoveReagent(EntityUid targetUid, Solution? container, string reagentId, FixedPoint2 quantity)
|
|
||||||
{
|
|
||||||
if (container == null || !container.ContainsReagent(reagentId))
|
|
||||||
return false;
|
|
||||||
|
|
||||||
container.RemoveReagent(reagentId, quantity);
|
|
||||||
UpdateChemicals(targetUid, container);
|
|
||||||
return true;
|
|
||||||
}
|
|
||||||
|
|
||||||
/// <summary>
|
|
||||||
/// Adds a solution to the container, if it can fully fit.
|
|
||||||
/// </summary>
|
|
||||||
/// <param name="targetUid">entity holding targetSolution</param>
|
|
||||||
/// <param name="targetSolution">entity holding targetSolution</param>
|
|
||||||
/// <param name="addedSolution">solution being added</param>
|
|
||||||
/// <returns>If the solution could be added.</returns>
|
|
||||||
public bool TryAddSolution(EntityUid targetUid, Solution? targetSolution, Solution addedSolution)
|
|
||||||
{
|
|
||||||
if (targetSolution == null
|
|
||||||
|| !targetSolution.CanAddSolution(addedSolution) || addedSolution.TotalVolume == 0)
|
|
||||||
return false;
|
|
||||||
|
|
||||||
targetSolution.AddSolution(addedSolution);
|
|
||||||
UpdateChemicals(targetUid, targetSolution, true);
|
|
||||||
return true;
|
|
||||||
}
|
|
||||||
|
|
||||||
/// <summary>
|
|
||||||
/// Adds a solution to the container, overflowing the rest.
|
|
||||||
/// Unlike TryAddSolution it will ignore size limits.
|
|
||||||
/// </summary>
|
|
||||||
/// <param name="targetUid">entity holding targetSolution</param>
|
|
||||||
/// <param name="targetSolution">The container to which we try to add.</param>
|
|
||||||
/// <param name="addedSolution">solution being added</param>
|
|
||||||
/// <param name="overflowThreshold">After addition this much will be left in targetSolution</param>
|
|
||||||
/// <param name="overflowingSolution">Solution that exceeded overflowThreshold</param>
|
|
||||||
/// <returns></returns>
|
|
||||||
public bool TryMixAndOverflow(EntityUid targetUid, Solution targetSolution,
|
|
||||||
Solution addedSolution,
|
|
||||||
FixedPoint2 overflowThreshold,
|
|
||||||
[NotNullWhen(true)] out Solution? overflowingSolution)
|
|
||||||
{
|
|
||||||
if (addedSolution.TotalVolume == 0)
|
|
||||||
{
|
|
||||||
overflowingSolution = null;
|
|
||||||
return false;
|
|
||||||
}
|
|
||||||
|
|
||||||
targetSolution.AddSolution(addedSolution);
|
|
||||||
UpdateChemicals(targetUid, targetSolution, true);
|
|
||||||
overflowingSolution = targetSolution.SplitSolution(FixedPoint2.Max(FixedPoint2.Zero,
|
|
||||||
targetSolution.CurrentVolume - overflowThreshold));
|
|
||||||
return true;
|
|
||||||
}
|
|
||||||
|
|
||||||
public bool TryGetSolution(EntityUid uid, string name,
|
|
||||||
[NotNullWhen(true)] out Solution? solution,
|
|
||||||
SolutionContainerManagerComponent? solutionsMgr = null)
|
|
||||||
{
|
|
||||||
if (!Resolve(uid, ref solutionsMgr, false))
|
|
||||||
{
|
|
||||||
solution = null;
|
|
||||||
return false;
|
|
||||||
}
|
|
||||||
|
|
||||||
return solutionsMgr.Solutions.TryGetValue(name, out solution);
|
|
||||||
}
|
|
||||||
|
|
||||||
/// <summary>
|
|
||||||
/// Will ensure a solution is added to given entity even if it's missing solutionContainerManager
|
|
||||||
/// </summary>
|
|
||||||
/// <param name="uid">EntityUid to which to add solution</param>
|
|
||||||
/// <param name="name">name for the solution</param>
|
|
||||||
/// <param name="solutionsMgr">solution components used in resolves</param>
|
|
||||||
/// <returns>solution</returns>
|
|
||||||
public Solution EnsureSolution(EntityUid uid, string name,
|
|
||||||
SolutionContainerManagerComponent? solutionsMgr = null)
|
|
||||||
{
|
|
||||||
if (!Resolve(uid, ref solutionsMgr, false))
|
|
||||||
{
|
|
||||||
solutionsMgr = EntityManager.EnsureComponent<SolutionContainerManagerComponent>(uid);
|
|
||||||
}
|
|
||||||
|
|
||||||
if (!solutionsMgr.Solutions.ContainsKey(name))
|
|
||||||
{
|
|
||||||
var newSolution = new Solution();
|
|
||||||
solutionsMgr.Solutions.Add(name, newSolution);
|
|
||||||
}
|
|
||||||
|
|
||||||
return solutionsMgr.Solutions[name];
|
|
||||||
}
|
|
||||||
|
|
||||||
public string[] RemoveEachReagent(EntityUid uid, Solution solution, FixedPoint2 quantity)
|
|
||||||
{
|
|
||||||
var removedReagent = new string[solution.Contents.Count];
|
|
||||||
if (quantity <= 0)
|
|
||||||
return Array.Empty<string>();
|
|
||||||
|
|
||||||
var pos = 0;
|
|
||||||
for (var i = 0; i < solution.Contents.Count; i++)
|
|
||||||
{
|
|
||||||
var (reagentId, curQuantity) = solution.Contents[i];
|
|
||||||
removedReagent[pos++] = reagentId;
|
|
||||||
if (!_prototypeManager.TryIndex(reagentId, out ReagentPrototype? proto))
|
|
||||||
proto = new ReagentPrototype();
|
|
||||||
|
|
||||||
var newQuantity = curQuantity - quantity;
|
|
||||||
if (newQuantity <= 0)
|
|
||||||
{
|
|
||||||
solution.Contents.RemoveSwap(i);
|
|
||||||
solution.TotalVolume -= curQuantity;
|
|
||||||
}
|
|
||||||
else
|
|
||||||
{
|
|
||||||
solution.Contents[i] = new Solution.ReagentQuantity(reagentId, newQuantity);
|
|
||||||
solution.TotalVolume -= quantity;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
UpdateChemicals(uid, solution);
|
|
||||||
return removedReagent;
|
|
||||||
}
|
|
||||||
|
|
||||||
public FixedPoint2 GetReagentQuantity(EntityUid owner, string reagentId)
|
|
||||||
{
|
|
||||||
var reagentQuantity = FixedPoint2.New(0);
|
|
||||||
if (EntityManager.EntityExists(owner)
|
|
||||||
&& EntityManager.TryGetComponent(owner, out SolutionContainerManagerComponent? managerComponent))
|
|
||||||
{
|
|
||||||
foreach (var solution in managerComponent.Solutions.Values)
|
|
||||||
{
|
|
||||||
reagentQuantity += solution.GetReagentQuantity(reagentId);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
return reagentQuantity;
|
|
||||||
}
|
|
||||||
|
|
||||||
|
|
||||||
// Thermal energy and temperature management.
|
|
||||||
#region Thermal Energy and Temperature
|
|
||||||
|
|
||||||
/// <summary>
|
|
||||||
/// Sets the temperature of a solution to a new value and then checks for reaction processing.
|
|
||||||
/// </summary>
|
|
||||||
/// <param name="owner">The entity in which the solution is located.</param>
|
|
||||||
/// <param name="solution">The solution to set the temperature of.</param>
|
|
||||||
/// <param name="temperature">The new value to set the temperature to.</param>
|
|
||||||
public void SetTemperature(EntityUid owner, Solution solution, float temperature)
|
|
||||||
{
|
|
||||||
if (temperature == solution.Temperature)
|
|
||||||
return;
|
|
||||||
|
|
||||||
solution.Temperature = temperature;
|
|
||||||
UpdateChemicals(owner, solution, true);
|
|
||||||
}
|
|
||||||
|
|
||||||
/// <summary>
|
|
||||||
/// Sets the thermal energy of a solution to a new value and then checks for reaction processing.
|
|
||||||
/// </summary>
|
|
||||||
/// <param name="owner">The entity in which the solution is located.</param>
|
|
||||||
/// <param name="solution">The solution to set the thermal energy of.</param>
|
|
||||||
/// <param name="thermalEnergy">The new value to set the thermal energy to.</param>
|
|
||||||
public void SetThermalEnergy(EntityUid owner, Solution solution, float thermalEnergy)
|
|
||||||
{
|
|
||||||
if (thermalEnergy == solution.ThermalEnergy)
|
|
||||||
return;
|
|
||||||
|
|
||||||
solution.ThermalEnergy = thermalEnergy;
|
|
||||||
UpdateChemicals(owner, solution, true);
|
|
||||||
}
|
|
||||||
|
|
||||||
/// <summary>
|
|
||||||
/// Adds some thermal energy to a solution and then checks for reaction processing.
|
|
||||||
/// </summary>
|
|
||||||
/// <param name="owner">The entity in which the solution is located.</param>
|
|
||||||
/// <param name="solution">The solution to set the thermal energy of.</param>
|
|
||||||
/// <param name="thermalEnergy">The new value to set the thermal energy to.</param>
|
|
||||||
public void AddThermalEnergy(EntityUid owner, Solution solution, float thermalEnergy)
|
|
||||||
{
|
|
||||||
if (thermalEnergy == 0.0f)
|
|
||||||
return;
|
|
||||||
|
|
||||||
solution.ThermalEnergy += thermalEnergy;
|
|
||||||
UpdateChemicals(owner, solution, true);
|
|
||||||
}
|
|
||||||
|
|
||||||
#endregion Thermal Energy and Temperature
|
|
||||||
}
|
}
|
||||||
|
|
||||||
|
private void OnExamineSolution(EntityUid uid, ExaminableSolutionComponent examinableComponent,
|
||||||
|
ExaminedEvent args)
|
||||||
|
{
|
||||||
|
SolutionContainerManagerComponent? solutionsManager = null;
|
||||||
|
if (!Resolve(args.Examined, ref solutionsManager)
|
||||||
|
|| !solutionsManager.Solutions.TryGetValue(examinableComponent.Solution, out var solutionHolder))
|
||||||
|
return;
|
||||||
|
|
||||||
|
if (solutionHolder.Contents.Count == 0)
|
||||||
|
{
|
||||||
|
args.PushText(Loc.GetString("shared-solution-container-component-on-examine-empty-container"));
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
var primaryReagent = solutionHolder.GetPrimaryReagentId();
|
||||||
|
|
||||||
|
if (!_prototypeManager.TryIndex(primaryReagent, out ReagentPrototype? proto))
|
||||||
|
{
|
||||||
|
Logger.Error(
|
||||||
|
$"{nameof(Solution)} could not find the prototype associated with {primaryReagent}.");
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
var colorHex = solutionHolder.Color
|
||||||
|
.ToHexNoAlpha(); //TODO: If the chem has a dark color, the examine text becomes black on a black background, which is unreadable.
|
||||||
|
var messageString = "shared-solution-container-component-on-examine-main-text";
|
||||||
|
|
||||||
|
args.PushMarkup(Loc.GetString(messageString,
|
||||||
|
("color", colorHex),
|
||||||
|
("wordedAmount", Loc.GetString(solutionHolder.Contents.Count == 1
|
||||||
|
? "shared-solution-container-component-on-examine-worded-amount-one-reagent"
|
||||||
|
: "shared-solution-container-component-on-examine-worded-amount-multiple-reagents")),
|
||||||
|
("desc", Loc.GetString(proto.PhysicalDescription))));
|
||||||
|
}
|
||||||
|
|
||||||
|
private void UpdateAppearance(EntityUid uid, Solution solution,
|
||||||
|
AppearanceComponent? appearanceComponent = null)
|
||||||
|
{
|
||||||
|
if (!EntityManager.EntityExists(uid)
|
||||||
|
|| !Resolve(uid, ref appearanceComponent, false))
|
||||||
|
return;
|
||||||
|
|
||||||
|
var filledVolumePercent = solution.CurrentVolume.Float() / solution.MaxVolume.Float();
|
||||||
|
appearanceComponent.SetData(SolutionContainerVisuals.VisualState,
|
||||||
|
new SolutionContainerVisualState(solution.Color, filledVolumePercent));
|
||||||
|
}
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// Removes part of the solution in the container.
|
||||||
|
/// </summary>
|
||||||
|
/// <param name="targetUid"></param>
|
||||||
|
/// <param name="solutionHolder"></param>
|
||||||
|
/// <param name="quantity">the volume of solution to remove.</param>
|
||||||
|
/// <returns>The solution that was removed.</returns>
|
||||||
|
public Solution SplitSolution(EntityUid targetUid, Solution solutionHolder, FixedPoint2 quantity)
|
||||||
|
{
|
||||||
|
var splitSol = solutionHolder.SplitSolution(quantity);
|
||||||
|
UpdateChemicals(targetUid, solutionHolder);
|
||||||
|
return splitSol;
|
||||||
|
}
|
||||||
|
|
||||||
|
private void UpdateChemicals(EntityUid uid, Solution solutionHolder, bool needsReactionsProcessing = false)
|
||||||
|
{
|
||||||
|
// Process reactions
|
||||||
|
if (needsReactionsProcessing && solutionHolder.CanReact)
|
||||||
|
{
|
||||||
|
_chemistrySystem.FullyReactSolution(solutionHolder, uid, solutionHolder.MaxVolume);
|
||||||
|
}
|
||||||
|
|
||||||
|
UpdateAppearance(uid, solutionHolder);
|
||||||
|
RaiseLocalEvent(uid, new SolutionChangedEvent());
|
||||||
|
}
|
||||||
|
|
||||||
|
public void RemoveAllSolution(EntityUid uid, Solution solutionHolder)
|
||||||
|
{
|
||||||
|
if (solutionHolder.CurrentVolume == 0)
|
||||||
|
return;
|
||||||
|
|
||||||
|
solutionHolder.RemoveAllSolution();
|
||||||
|
UpdateChemicals(uid, solutionHolder);
|
||||||
|
}
|
||||||
|
|
||||||
|
public void RemoveAllSolution(EntityUid uid, SolutionContainerManagerComponent? solutionContainerManager = null)
|
||||||
|
{
|
||||||
|
if (!Resolve(uid, ref solutionContainerManager))
|
||||||
|
return;
|
||||||
|
|
||||||
|
foreach (var solution in solutionContainerManager.Solutions.Values)
|
||||||
|
{
|
||||||
|
RemoveAllSolution(uid, solution);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// Sets the capacity (maximum volume) of a solution to a new value.
|
||||||
|
/// </summary>
|
||||||
|
/// <param name="targetUid">The entity containing the solution.</param>
|
||||||
|
/// <param name="targetSolution">The solution to set the capacity of.</param>
|
||||||
|
/// <param name="capacity">The value to set the capacity of the solution to.</param>
|
||||||
|
public void SetCapacity(EntityUid targetUid, Solution targetSolution, FixedPoint2 capacity)
|
||||||
|
{
|
||||||
|
if (targetSolution.MaxVolume == capacity)
|
||||||
|
return;
|
||||||
|
|
||||||
|
targetSolution.MaxVolume = capacity;
|
||||||
|
if (capacity < targetSolution.CurrentVolume)
|
||||||
|
targetSolution.RemoveSolution(targetSolution.CurrentVolume - capacity);
|
||||||
|
|
||||||
|
UpdateChemicals(targetUid, targetSolution);
|
||||||
|
}
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// Adds reagent of an Id to the container.
|
||||||
|
/// </summary>
|
||||||
|
/// <param name="targetUid"></param>
|
||||||
|
/// <param name="targetSolution">Container to which we are adding reagent</param>
|
||||||
|
/// <param name="reagentId">The Id of the reagent to add.</param>
|
||||||
|
/// <param name="quantity">The amount of reagent to add.</param>
|
||||||
|
/// <param name="acceptedQuantity">The amount of reagent successfully added.</param>
|
||||||
|
/// <returns>If all the reagent could be added.</returns>
|
||||||
|
public bool TryAddReagent(EntityUid targetUid, Solution targetSolution, string reagentId, FixedPoint2 quantity,
|
||||||
|
out FixedPoint2 acceptedQuantity, float? temperature = null)
|
||||||
|
{
|
||||||
|
acceptedQuantity = targetSolution.AvailableVolume > quantity ? quantity : targetSolution.AvailableVolume;
|
||||||
|
targetSolution.AddReagent(reagentId, acceptedQuantity, temperature);
|
||||||
|
|
||||||
|
if (acceptedQuantity > 0)
|
||||||
|
UpdateChemicals(targetUid, targetSolution, true);
|
||||||
|
|
||||||
|
return acceptedQuantity == quantity;
|
||||||
|
}
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// Removes reagent of an Id to the container.
|
||||||
|
/// </summary>
|
||||||
|
/// <param name="targetUid"></param>
|
||||||
|
/// <param name="container">Solution container from which we are removing reagent</param>
|
||||||
|
/// <param name="reagentId">The Id of the reagent to remove.</param>
|
||||||
|
/// <param name="quantity">The amount of reagent to remove.</param>
|
||||||
|
/// <returns>If the reagent to remove was found in the container.</returns>
|
||||||
|
public bool TryRemoveReagent(EntityUid targetUid, Solution? container, string reagentId, FixedPoint2 quantity)
|
||||||
|
{
|
||||||
|
if (container == null || !container.ContainsReagent(reagentId))
|
||||||
|
return false;
|
||||||
|
|
||||||
|
container.RemoveReagent(reagentId, quantity);
|
||||||
|
UpdateChemicals(targetUid, container);
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// Adds a solution to the container, if it can fully fit.
|
||||||
|
/// </summary>
|
||||||
|
/// <param name="targetUid">entity holding targetSolution</param>
|
||||||
|
/// <param name="targetSolution">entity holding targetSolution</param>
|
||||||
|
/// <param name="addedSolution">solution being added</param>
|
||||||
|
/// <returns>If the solution could be added.</returns>
|
||||||
|
public bool TryAddSolution(EntityUid targetUid, Solution? targetSolution, Solution addedSolution)
|
||||||
|
{
|
||||||
|
if (targetSolution == null
|
||||||
|
|| !targetSolution.CanAddSolution(addedSolution) || addedSolution.TotalVolume == 0)
|
||||||
|
return false;
|
||||||
|
|
||||||
|
targetSolution.AddSolution(addedSolution);
|
||||||
|
UpdateChemicals(targetUid, targetSolution, true);
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// Adds a solution to the container, overflowing the rest.
|
||||||
|
/// It will
|
||||||
|
/// Unlike <see cref="TryAddSolution"/> it will ignore size limits.
|
||||||
|
/// </summary>
|
||||||
|
/// <param name="targetUid">entity holding targetSolution</param>
|
||||||
|
/// <param name="targetSolution">The container to which we try to add.</param>
|
||||||
|
/// <param name="addedSolution">solution being added</param>
|
||||||
|
/// <param name="overflowThreshold">After addition this much will be left in targetSolution. Should be less
|
||||||
|
/// than targetSolution.TotalVolume</param>
|
||||||
|
/// <param name="overflowingSolution">Solution that exceeded overflowThreshold</param>
|
||||||
|
/// <returns></returns>
|
||||||
|
public bool TryMixAndOverflow(EntityUid targetUid, Solution targetSolution,
|
||||||
|
Solution addedSolution,
|
||||||
|
FixedPoint2 overflowThreshold,
|
||||||
|
[NotNullWhen(true)] out Solution? overflowingSolution)
|
||||||
|
{
|
||||||
|
if (addedSolution.TotalVolume == 0 || overflowThreshold > targetSolution.MaxVolume)
|
||||||
|
{
|
||||||
|
overflowingSolution = null;
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
|
||||||
|
targetSolution.AddSolution(addedSolution);
|
||||||
|
UpdateChemicals(targetUid, targetSolution, true);
|
||||||
|
overflowingSolution = targetSolution.SplitSolution(FixedPoint2.Max(FixedPoint2.Zero,
|
||||||
|
targetSolution.CurrentVolume - overflowThreshold));
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
|
||||||
|
public bool TryGetSolution(EntityUid uid, string name,
|
||||||
|
[NotNullWhen(true)] out Solution? solution,
|
||||||
|
SolutionContainerManagerComponent? solutionsMgr = null)
|
||||||
|
{
|
||||||
|
if (!Resolve(uid, ref solutionsMgr, false))
|
||||||
|
{
|
||||||
|
solution = null;
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
|
||||||
|
return solutionsMgr.Solutions.TryGetValue(name, out solution);
|
||||||
|
}
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// Will ensure a solution is added to given entity even if it's missing solutionContainerManager
|
||||||
|
/// </summary>
|
||||||
|
/// <param name="uid">EntityUid to which to add solution</param>
|
||||||
|
/// <param name="name">name for the solution</param>
|
||||||
|
/// <param name="solutionsMgr">solution components used in resolves</param>
|
||||||
|
/// <returns>solution</returns>
|
||||||
|
public Solution EnsureSolution(EntityUid uid, string name,
|
||||||
|
SolutionContainerManagerComponent? solutionsMgr = null)
|
||||||
|
{
|
||||||
|
if (!Resolve(uid, ref solutionsMgr, false))
|
||||||
|
{
|
||||||
|
solutionsMgr = EntityManager.EnsureComponent<SolutionContainerManagerComponent>(uid);
|
||||||
|
}
|
||||||
|
|
||||||
|
if (!solutionsMgr.Solutions.ContainsKey(name))
|
||||||
|
{
|
||||||
|
var newSolution = new Solution();
|
||||||
|
solutionsMgr.Solutions.Add(name, newSolution);
|
||||||
|
}
|
||||||
|
|
||||||
|
return solutionsMgr.Solutions[name];
|
||||||
|
}
|
||||||
|
|
||||||
|
public string[] RemoveEachReagent(EntityUid uid, Solution solution, FixedPoint2 quantity)
|
||||||
|
{
|
||||||
|
var removedReagent = new string[solution.Contents.Count];
|
||||||
|
if (quantity <= 0)
|
||||||
|
return Array.Empty<string>();
|
||||||
|
|
||||||
|
var pos = 0;
|
||||||
|
for (var i = 0; i < solution.Contents.Count; i++)
|
||||||
|
{
|
||||||
|
var (reagentId, curQuantity) = solution.Contents[i];
|
||||||
|
removedReagent[pos++] = reagentId;
|
||||||
|
if (!_prototypeManager.TryIndex(reagentId, out ReagentPrototype? proto))
|
||||||
|
proto = new ReagentPrototype();
|
||||||
|
|
||||||
|
var newQuantity = curQuantity - quantity;
|
||||||
|
if (newQuantity <= 0)
|
||||||
|
{
|
||||||
|
solution.Contents.RemoveSwap(i);
|
||||||
|
solution.TotalVolume -= curQuantity;
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
solution.Contents[i] = new Solution.ReagentQuantity(reagentId, newQuantity);
|
||||||
|
solution.TotalVolume -= quantity;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
UpdateChemicals(uid, solution);
|
||||||
|
return removedReagent;
|
||||||
|
}
|
||||||
|
|
||||||
|
public FixedPoint2 GetReagentQuantity(EntityUid owner, string reagentId)
|
||||||
|
{
|
||||||
|
var reagentQuantity = FixedPoint2.New(0);
|
||||||
|
if (EntityManager.EntityExists(owner)
|
||||||
|
&& EntityManager.TryGetComponent(owner, out SolutionContainerManagerComponent? managerComponent))
|
||||||
|
{
|
||||||
|
foreach (var solution in managerComponent.Solutions.Values)
|
||||||
|
{
|
||||||
|
reagentQuantity += solution.GetReagentQuantity(reagentId);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
return reagentQuantity;
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
// Thermal energy and temperature management.
|
||||||
|
|
||||||
|
#region Thermal Energy and Temperature
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// Sets the temperature of a solution to a new value and then checks for reaction processing.
|
||||||
|
/// </summary>
|
||||||
|
/// <param name="owner">The entity in which the solution is located.</param>
|
||||||
|
/// <param name="solution">The solution to set the temperature of.</param>
|
||||||
|
/// <param name="temperature">The new value to set the temperature to.</param>
|
||||||
|
public void SetTemperature(EntityUid owner, Solution solution, float temperature)
|
||||||
|
{
|
||||||
|
if (temperature == solution.Temperature)
|
||||||
|
return;
|
||||||
|
|
||||||
|
solution.Temperature = temperature;
|
||||||
|
UpdateChemicals(owner, solution, true);
|
||||||
|
}
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// Sets the thermal energy of a solution to a new value and then checks for reaction processing.
|
||||||
|
/// </summary>
|
||||||
|
/// <param name="owner">The entity in which the solution is located.</param>
|
||||||
|
/// <param name="solution">The solution to set the thermal energy of.</param>
|
||||||
|
/// <param name="thermalEnergy">The new value to set the thermal energy to.</param>
|
||||||
|
public void SetThermalEnergy(EntityUid owner, Solution solution, float thermalEnergy)
|
||||||
|
{
|
||||||
|
if (thermalEnergy == solution.ThermalEnergy)
|
||||||
|
return;
|
||||||
|
|
||||||
|
solution.ThermalEnergy = thermalEnergy;
|
||||||
|
UpdateChemicals(owner, solution, true);
|
||||||
|
}
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// Adds some thermal energy to a solution and then checks for reaction processing.
|
||||||
|
/// </summary>
|
||||||
|
/// <param name="owner">The entity in which the solution is located.</param>
|
||||||
|
/// <param name="solution">The solution to set the thermal energy of.</param>
|
||||||
|
/// <param name="thermalEnergy">The new value to set the thermal energy to.</param>
|
||||||
|
public void AddThermalEnergy(EntityUid owner, Solution solution, float thermalEnergy)
|
||||||
|
{
|
||||||
|
if (thermalEnergy == 0.0f)
|
||||||
|
return;
|
||||||
|
|
||||||
|
solution.ThermalEnergy += thermalEnergy;
|
||||||
|
UpdateChemicals(owner, solution, true);
|
||||||
|
}
|
||||||
|
|
||||||
|
#endregion Thermal Energy and Temperature
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -1,484 +1,483 @@
|
|||||||
using Content.Shared.Chemistry.Components;
|
using Content.Shared.Chemistry.Components;
|
||||||
using Content.Shared.Chemistry.Reagent;
|
|
||||||
using Content.Shared.FixedPoint;
|
using Content.Shared.FixedPoint;
|
||||||
using Robust.Shared.IoC;
|
using Robust.Shared.IoC;
|
||||||
using Robust.Shared.Prototypes;
|
using Robust.Shared.Prototypes;
|
||||||
using NUnit.Framework;
|
using NUnit.Framework;
|
||||||
|
|
||||||
namespace Content.Tests.Shared.Chemistry
|
namespace Content.Tests.Shared.Chemistry;
|
||||||
|
|
||||||
|
[TestFixture, Parallelizable, TestOf(typeof(Solution))]
|
||||||
|
public sealed class Solution_Tests : ContentUnitTest
|
||||||
{
|
{
|
||||||
[TestFixture, Parallelizable, TestOf(typeof(Solution))]
|
[OneTimeSetUp]
|
||||||
public sealed class Solution_Tests : ContentUnitTest
|
public void Setup()
|
||||||
{
|
{
|
||||||
[OneTimeSetUp]
|
IoCManager.Resolve<IPrototypeManager>().Initialize();
|
||||||
public void Setup()
|
|
||||||
{
|
|
||||||
IoCManager.Resolve<IPrototypeManager>().Initialize();
|
|
||||||
}
|
|
||||||
|
|
||||||
[Test]
|
|
||||||
public void AddReagentAndGetSolution()
|
|
||||||
{
|
|
||||||
var solution = new Solution();
|
|
||||||
solution.AddReagent("water", FixedPoint2.New(1000));
|
|
||||||
var quantity = solution.GetReagentQuantity("water");
|
|
||||||
|
|
||||||
Assert.That(quantity.Int(), Is.EqualTo(1000));
|
|
||||||
}
|
|
||||||
|
|
||||||
[Test]
|
|
||||||
public void ConstructorAddReagent()
|
|
||||||
{
|
|
||||||
var solution = new Solution("water", FixedPoint2.New(1000));
|
|
||||||
var quantity = solution.GetReagentQuantity("water");
|
|
||||||
|
|
||||||
Assert.That(quantity.Int(), Is.EqualTo(1000));
|
|
||||||
}
|
|
||||||
|
|
||||||
[Test]
|
|
||||||
public void NonExistingReagentReturnsZero()
|
|
||||||
{
|
|
||||||
var solution = new Solution();
|
|
||||||
var quantity = solution.GetReagentQuantity("water");
|
|
||||||
|
|
||||||
Assert.That(quantity.Int(), Is.EqualTo(0));
|
|
||||||
}
|
|
||||||
|
|
||||||
[Test]
|
|
||||||
public void AddLessThanZeroReagentReturnsZero()
|
|
||||||
{
|
|
||||||
var solution = new Solution("water", FixedPoint2.New(-1000));
|
|
||||||
var quantity = solution.GetReagentQuantity("water");
|
|
||||||
|
|
||||||
Assert.That(quantity.Int(), Is.EqualTo(0));
|
|
||||||
}
|
|
||||||
|
|
||||||
[Test]
|
|
||||||
public void AddingReagentsSumsProperly()
|
|
||||||
{
|
|
||||||
var solution = new Solution();
|
|
||||||
solution.AddReagent("water", FixedPoint2.New(1000));
|
|
||||||
solution.AddReagent("water", FixedPoint2.New(2000));
|
|
||||||
var quantity = solution.GetReagentQuantity("water");
|
|
||||||
|
|
||||||
Assert.That(quantity.Int(), Is.EqualTo(3000));
|
|
||||||
}
|
|
||||||
|
|
||||||
[Test]
|
|
||||||
public void ReagentQuantitiesStayUnique()
|
|
||||||
{
|
|
||||||
var solution = new Solution();
|
|
||||||
solution.AddReagent("water", FixedPoint2.New(1000));
|
|
||||||
solution.AddReagent("fire", FixedPoint2.New(2000));
|
|
||||||
|
|
||||||
Assert.That(solution.GetReagentQuantity("water").Int(), Is.EqualTo(1000));
|
|
||||||
Assert.That(solution.GetReagentQuantity("fire").Int(), Is.EqualTo(2000));
|
|
||||||
}
|
|
||||||
|
|
||||||
[Test]
|
|
||||||
public void TotalVolumeIsCorrect()
|
|
||||||
{
|
|
||||||
var solution = new Solution();
|
|
||||||
solution.AddReagent("water", FixedPoint2.New(1000));
|
|
||||||
solution.AddReagent("fire", FixedPoint2.New(2000));
|
|
||||||
|
|
||||||
Assert.That(solution.TotalVolume.Int(), Is.EqualTo(3000));
|
|
||||||
}
|
|
||||||
|
|
||||||
[Test]
|
|
||||||
public void CloningSolutionIsCorrect()
|
|
||||||
{
|
|
||||||
var solution = new Solution();
|
|
||||||
solution.AddReagent("water", FixedPoint2.New(1000));
|
|
||||||
solution.AddReagent("fire", FixedPoint2.New(2000));
|
|
||||||
|
|
||||||
var newSolution = solution.Clone();
|
|
||||||
|
|
||||||
Assert.That(newSolution.GetReagentQuantity("water").Int(), Is.EqualTo(1000));
|
|
||||||
Assert.That(newSolution.GetReagentQuantity("fire").Int(), Is.EqualTo(2000));
|
|
||||||
Assert.That(newSolution.TotalVolume.Int(), Is.EqualTo(3000));
|
|
||||||
}
|
|
||||||
|
|
||||||
[Test]
|
|
||||||
public void RemoveSolutionRecalculatesProperly()
|
|
||||||
{
|
|
||||||
var solution = new Solution();
|
|
||||||
solution.AddReagent("water", FixedPoint2.New(1000));
|
|
||||||
solution.AddReagent("fire", FixedPoint2.New(2000));
|
|
||||||
|
|
||||||
solution.RemoveReagent("water", FixedPoint2.New(500));
|
|
||||||
|
|
||||||
Assert.That(solution.GetReagentQuantity("water").Int(), Is.EqualTo(500));
|
|
||||||
Assert.That(solution.GetReagentQuantity("fire").Int(), Is.EqualTo(2000));
|
|
||||||
Assert.That(solution.TotalVolume.Int(), Is.EqualTo(2500));
|
|
||||||
}
|
|
||||||
|
|
||||||
[Test]
|
|
||||||
public void RemoveLessThanOneQuantityDoesNothing()
|
|
||||||
{
|
|
||||||
var solution = new Solution("water", FixedPoint2.New(100));
|
|
||||||
|
|
||||||
solution.RemoveReagent("water", FixedPoint2.New(-100));
|
|
||||||
|
|
||||||
Assert.That(solution.GetReagentQuantity("water").Int(), Is.EqualTo(100));
|
|
||||||
Assert.That(solution.TotalVolume.Int(), Is.EqualTo(100));
|
|
||||||
}
|
|
||||||
|
|
||||||
[Test]
|
|
||||||
public void RemoveMoreThanTotalRemovesAllReagent()
|
|
||||||
{
|
|
||||||
var solution = new Solution("water", FixedPoint2.New(100));
|
|
||||||
|
|
||||||
solution.RemoveReagent("water", FixedPoint2.New(1000));
|
|
||||||
|
|
||||||
Assert.That(solution.GetReagentQuantity("water").Int(), Is.EqualTo(0));
|
|
||||||
Assert.That(solution.TotalVolume.Int(), Is.EqualTo(0));
|
|
||||||
}
|
|
||||||
|
|
||||||
[Test]
|
|
||||||
public void RemoveNonExistReagentDoesNothing()
|
|
||||||
{
|
|
||||||
var solution = new Solution("water", FixedPoint2.New(100));
|
|
||||||
|
|
||||||
solution.RemoveReagent("fire", FixedPoint2.New(1000));
|
|
||||||
|
|
||||||
Assert.That(solution.GetReagentQuantity("water").Int(), Is.EqualTo(100));
|
|
||||||
Assert.That(solution.TotalVolume.Int(), Is.EqualTo(100));
|
|
||||||
}
|
|
||||||
|
|
||||||
[Test]
|
|
||||||
public void RemoveSolution()
|
|
||||||
{
|
|
||||||
var solution = new Solution("water", FixedPoint2.New(700));
|
|
||||||
|
|
||||||
solution.RemoveSolution(FixedPoint2.New(500));
|
|
||||||
|
|
||||||
//Check that edited solution is correct
|
|
||||||
Assert.That(solution.GetReagentQuantity("water").Int(), Is.EqualTo(200));
|
|
||||||
Assert.That(solution.TotalVolume.Int(), Is.EqualTo(200));
|
|
||||||
}
|
|
||||||
|
|
||||||
[Test]
|
|
||||||
public void RemoveSolutionMoreThanTotalRemovesAll()
|
|
||||||
{
|
|
||||||
var solution = new Solution("water", FixedPoint2.New(800));
|
|
||||||
|
|
||||||
solution.RemoveSolution(FixedPoint2.New(1000));
|
|
||||||
|
|
||||||
//Check that edited solution is correct
|
|
||||||
Assert.That(solution.GetReagentQuantity("water").Int(), Is.EqualTo(0));
|
|
||||||
Assert.That(solution.TotalVolume.Int(), Is.EqualTo(0));
|
|
||||||
}
|
|
||||||
|
|
||||||
[Test]
|
|
||||||
public void RemoveSolutionRatioPreserved()
|
|
||||||
{
|
|
||||||
var solution = new Solution();
|
|
||||||
solution.AddReagent("water", FixedPoint2.New(1000));
|
|
||||||
solution.AddReagent("fire", FixedPoint2.New(2000));
|
|
||||||
|
|
||||||
solution.RemoveSolution(FixedPoint2.New(1500));
|
|
||||||
|
|
||||||
Assert.That(solution.GetReagentQuantity("water").Int(), Is.EqualTo(500));
|
|
||||||
Assert.That(solution.GetReagentQuantity("fire").Int(), Is.EqualTo(1000));
|
|
||||||
Assert.That(solution.TotalVolume.Int(), Is.EqualTo(1500));
|
|
||||||
}
|
|
||||||
|
|
||||||
[Test]
|
|
||||||
public void RemoveSolutionLessThanOneDoesNothing()
|
|
||||||
{
|
|
||||||
var solution = new Solution("water", FixedPoint2.New(800));
|
|
||||||
|
|
||||||
solution.RemoveSolution(FixedPoint2.New(-200));
|
|
||||||
|
|
||||||
Assert.That(solution.GetReagentQuantity("water").Int(), Is.EqualTo(800));
|
|
||||||
Assert.That(solution.TotalVolume.Int(), Is.EqualTo(800));
|
|
||||||
}
|
|
||||||
|
|
||||||
[Test]
|
|
||||||
public void SplitSolution()
|
|
||||||
{
|
|
||||||
var solution = new Solution();
|
|
||||||
solution.AddReagent("water", FixedPoint2.New(1000));
|
|
||||||
solution.AddReagent("fire", FixedPoint2.New(2000));
|
|
||||||
|
|
||||||
var splitSolution = solution.SplitSolution(FixedPoint2.New(750));
|
|
||||||
|
|
||||||
Assert.That(solution.GetReagentQuantity("water").Int(), Is.EqualTo(750));
|
|
||||||
Assert.That(solution.GetReagentQuantity("fire").Int(), Is.EqualTo(1500));
|
|
||||||
Assert.That(solution.TotalVolume.Int(), Is.EqualTo(2250));
|
|
||||||
|
|
||||||
Assert.That(splitSolution.GetReagentQuantity("water").Int(), Is.EqualTo(250));
|
|
||||||
Assert.That(splitSolution.GetReagentQuantity("fire").Int(), Is.EqualTo(500));
|
|
||||||
Assert.That(splitSolution.TotalVolume.Int(), Is.EqualTo(750));
|
|
||||||
}
|
|
||||||
|
|
||||||
[Test]
|
|
||||||
public void SplitSolutionFractional()
|
|
||||||
{
|
|
||||||
var solution = new Solution();
|
|
||||||
solution.AddReagent("water", FixedPoint2.New(1));
|
|
||||||
solution.AddReagent("fire", FixedPoint2.New(2));
|
|
||||||
|
|
||||||
var splitSolution = solution.SplitSolution(FixedPoint2.New(1));
|
|
||||||
|
|
||||||
Assert.That(solution.GetReagentQuantity("water").Float(), Is.EqualTo(0.67f));
|
|
||||||
Assert.That(solution.GetReagentQuantity("fire").Float(), Is.EqualTo(1.33f));
|
|
||||||
Assert.That(solution.TotalVolume.Int(), Is.EqualTo(2));
|
|
||||||
|
|
||||||
Assert.That(splitSolution.GetReagentQuantity("water").Float(), Is.EqualTo(0.33f));
|
|
||||||
Assert.That(splitSolution.GetReagentQuantity("fire").Float(), Is.EqualTo(0.67f));
|
|
||||||
Assert.That(splitSolution.TotalVolume.Int(), Is.EqualTo(1));
|
|
||||||
}
|
|
||||||
|
|
||||||
[Test]
|
|
||||||
public void SplitSolutionFractionalOpposite()
|
|
||||||
{
|
|
||||||
var solution = new Solution();
|
|
||||||
solution.AddReagent("water", FixedPoint2.New(1));
|
|
||||||
solution.AddReagent("fire", FixedPoint2.New(2));
|
|
||||||
|
|
||||||
var splitSolution = solution.SplitSolution(FixedPoint2.New(2));
|
|
||||||
|
|
||||||
Assert.That(solution.GetReagentQuantity("water").Float(), Is.EqualTo(0.33f));
|
|
||||||
Assert.That(solution.GetReagentQuantity("fire").Float(), Is.EqualTo(0.67f));
|
|
||||||
Assert.That(solution.TotalVolume.Int(), Is.EqualTo(1));
|
|
||||||
|
|
||||||
Assert.That(splitSolution.GetReagentQuantity("water").Float(), Is.EqualTo(0.67f));
|
|
||||||
Assert.That(splitSolution.GetReagentQuantity("fire").Float(), Is.EqualTo(1.33f));
|
|
||||||
Assert.That(splitSolution.TotalVolume.Int(), Is.EqualTo(2));
|
|
||||||
}
|
|
||||||
|
|
||||||
[Test]
|
|
||||||
[TestCase(0.03f, 0.01f, 0.02f)]
|
|
||||||
[TestCase(0.03f, 0.02f, 0.01f)]
|
|
||||||
public void SplitSolutionTinyFractionalBigSmall(float initial, float reduce, float remainder)
|
|
||||||
{
|
|
||||||
var solution = new Solution();
|
|
||||||
solution.AddReagent("water", FixedPoint2.New(initial));
|
|
||||||
|
|
||||||
var splitSolution = solution.SplitSolution(FixedPoint2.New(reduce));
|
|
||||||
|
|
||||||
Assert.That(solution.GetReagentQuantity("water").Float(), Is.EqualTo(remainder));
|
|
||||||
Assert.That(solution.TotalVolume.Float(), Is.EqualTo(remainder));
|
|
||||||
|
|
||||||
Assert.That(splitSolution.GetReagentQuantity("water").Float(), Is.EqualTo(reduce));
|
|
||||||
Assert.That(splitSolution.TotalVolume.Float(), Is.EqualTo(reduce));
|
|
||||||
}
|
|
||||||
|
|
||||||
[Test]
|
|
||||||
[TestCase(2)]
|
|
||||||
[TestCase(10)]
|
|
||||||
[TestCase(100)]
|
|
||||||
[TestCase(1000)]
|
|
||||||
public void SplitRounding(int amount)
|
|
||||||
{
|
|
||||||
var solutionOne = new Solution();
|
|
||||||
solutionOne.AddReagent("foo", FixedPoint2.New(amount));
|
|
||||||
solutionOne.AddReagent("bar", FixedPoint2.New(amount));
|
|
||||||
solutionOne.AddReagent("baz", FixedPoint2.New(amount));
|
|
||||||
|
|
||||||
var splitAmount = FixedPoint2.New(5);
|
|
||||||
var split = solutionOne.SplitSolution(splitAmount);
|
|
||||||
|
|
||||||
Assert.That(split.TotalVolume, Is.EqualTo(splitAmount));
|
|
||||||
}
|
|
||||||
|
|
||||||
[Test]
|
|
||||||
public void SplitSolutionMoreThanTotalRemovesAll()
|
|
||||||
{
|
|
||||||
var solution = new Solution("water", FixedPoint2.New(800));
|
|
||||||
|
|
||||||
var splitSolution = solution.SplitSolution(FixedPoint2.New(1000));
|
|
||||||
|
|
||||||
Assert.That(solution.GetReagentQuantity("water").Int(), Is.EqualTo(0));
|
|
||||||
Assert.That(solution.TotalVolume.Int(), Is.EqualTo(0));
|
|
||||||
|
|
||||||
Assert.That(splitSolution.GetReagentQuantity("water").Int(), Is.EqualTo(800));
|
|
||||||
Assert.That(splitSolution.TotalVolume.Int(), Is.EqualTo(800));
|
|
||||||
}
|
|
||||||
|
|
||||||
[Test]
|
|
||||||
public void SplitSolutionLessThanOneDoesNothing()
|
|
||||||
{
|
|
||||||
var solution = new Solution("water", FixedPoint2.New(800));
|
|
||||||
|
|
||||||
var splitSolution = solution.SplitSolution(FixedPoint2.New(-200));
|
|
||||||
|
|
||||||
Assert.That(solution.GetReagentQuantity("water").Int(), Is.EqualTo(800));
|
|
||||||
Assert.That(solution.TotalVolume.Int(), Is.EqualTo(800));
|
|
||||||
|
|
||||||
Assert.That(splitSolution.GetReagentQuantity("water").Int(), Is.EqualTo(0));
|
|
||||||
Assert.That(splitSolution.TotalVolume.Int(), Is.EqualTo(0));
|
|
||||||
}
|
|
||||||
|
|
||||||
[Test]
|
|
||||||
public void SplitSolutionZero()
|
|
||||||
{
|
|
||||||
var solution = new Solution();
|
|
||||||
solution.AddReagent("Impedrezene", FixedPoint2.New(0.01 + 0.19));
|
|
||||||
solution.AddReagent("Thermite", FixedPoint2.New(0.01 + 0.39));
|
|
||||||
solution.AddReagent("Li", FixedPoint2.New(0.01 + 0.17));
|
|
||||||
solution.AddReagent("F", FixedPoint2.New(0.01 + 0.17));
|
|
||||||
solution.AddReagent("Na", FixedPoint2.New(0 + 0.13));
|
|
||||||
solution.AddReagent("Hg", FixedPoint2.New(0.15 + 4.15));
|
|
||||||
solution.AddReagent("Cu", FixedPoint2.New(0 + 0.13));
|
|
||||||
solution.AddReagent("U", FixedPoint2.New(0.76 + 20.77));
|
|
||||||
solution.AddReagent("Fe", FixedPoint2.New(0.01 + 0.36));
|
|
||||||
solution.AddReagent("SpaceDrugs", FixedPoint2.New(0.02 + 0.41));
|
|
||||||
solution.AddReagent("Al", FixedPoint2.New(0));
|
|
||||||
solution.AddReagent("Glucose", FixedPoint2.New(0));
|
|
||||||
solution.AddReagent("O", FixedPoint2.New(0));
|
|
||||||
|
|
||||||
solution.SplitSolution(FixedPoint2.New(0.98));
|
|
||||||
}
|
|
||||||
|
|
||||||
[Test]
|
|
||||||
public void AddSolution()
|
|
||||||
{
|
|
||||||
var solutionOne = new Solution();
|
|
||||||
solutionOne.AddReagent("water", FixedPoint2.New(1000));
|
|
||||||
solutionOne.AddReagent("fire", FixedPoint2.New(2000));
|
|
||||||
|
|
||||||
var solutionTwo = new Solution();
|
|
||||||
solutionTwo.AddReagent("water", FixedPoint2.New(500));
|
|
||||||
solutionTwo.AddReagent("earth", FixedPoint2.New(1000));
|
|
||||||
|
|
||||||
solutionOne.AddSolution(solutionTwo);
|
|
||||||
|
|
||||||
Assert.That(solutionOne.GetReagentQuantity("water").Int(), Is.EqualTo(1500));
|
|
||||||
Assert.That(solutionOne.GetReagentQuantity("fire").Int(), Is.EqualTo(2000));
|
|
||||||
Assert.That(solutionOne.GetReagentQuantity("earth").Int(), Is.EqualTo(1000));
|
|
||||||
Assert.That(solutionOne.TotalVolume.Int(), Is.EqualTo(4500));
|
|
||||||
}
|
|
||||||
|
|
||||||
// Tests concerning thermal energy and temperature.
|
|
||||||
#region Thermal Energy and Temperature
|
|
||||||
|
|
||||||
[Test]
|
|
||||||
public void EmptySolutionHasNoHeatCapacity()
|
|
||||||
{
|
|
||||||
var solution = new Solution();
|
|
||||||
Assert.That(solution.HeatCapacity, Is.EqualTo(0.0f));
|
|
||||||
}
|
|
||||||
|
|
||||||
[Test]
|
|
||||||
public void EmptySolutionHasNoThermalEnergy()
|
|
||||||
{
|
|
||||||
var solution = new Solution();
|
|
||||||
Assert.That(solution.ThermalEnergy, Is.EqualTo(0.0f));
|
|
||||||
}
|
|
||||||
|
|
||||||
[Test]
|
|
||||||
public void AddReagentToEmptySolutionSetsTemperature()
|
|
||||||
{
|
|
||||||
const float testTemp = 100.0f;
|
|
||||||
|
|
||||||
var solution = new Solution();
|
|
||||||
solution.AddReagent("water", FixedPoint2.New(100), testTemp);
|
|
||||||
Assert.That(solution.Temperature, Is.EqualTo(testTemp));
|
|
||||||
}
|
|
||||||
|
|
||||||
[Test]
|
|
||||||
public void AddReagentWithNullTemperatureDoesNotEffectTemperature()
|
|
||||||
{
|
|
||||||
const float initialTemp = 100.0f;
|
|
||||||
|
|
||||||
var solution = new Solution();
|
|
||||||
solution.AddReagent("water", FixedPoint2.New(100), initialTemp);
|
|
||||||
|
|
||||||
solution.AddReagent("water", FixedPoint2.New(100));
|
|
||||||
Assert.That(solution.Temperature, Is.EqualTo(initialTemp));
|
|
||||||
|
|
||||||
solution.AddReagent("earth", FixedPoint2.New(100));
|
|
||||||
Assert.That(solution.Temperature, Is.EqualTo(initialTemp));
|
|
||||||
}
|
|
||||||
|
|
||||||
[Test]
|
|
||||||
public void AddSolutionWithEqualTemperatureDoesNotChangeTemperature()
|
|
||||||
{
|
|
||||||
const float initialTemp = 100.0f;
|
|
||||||
|
|
||||||
var solutionOne = new Solution();
|
|
||||||
solutionOne.AddReagent("water", FixedPoint2.New(100));
|
|
||||||
solutionOne.Temperature = initialTemp;
|
|
||||||
|
|
||||||
var solutionTwo = new Solution();
|
|
||||||
solutionTwo.AddReagent("water", FixedPoint2.New(100));
|
|
||||||
solutionTwo.AddReagent("earth", FixedPoint2.New(100));
|
|
||||||
solutionTwo.Temperature = initialTemp;
|
|
||||||
|
|
||||||
solutionOne.AddSolution(solutionTwo);
|
|
||||||
Assert.That(solutionOne.Temperature, Is.EqualTo(initialTemp));
|
|
||||||
}
|
|
||||||
|
|
||||||
[Test]
|
|
||||||
public void RemoveReagentDoesNotEffectTemperature()
|
|
||||||
{
|
|
||||||
const float initialTemp = 100.0f;
|
|
||||||
|
|
||||||
var solution = new Solution();
|
|
||||||
solution.AddReagent("water", FixedPoint2.New(100), initialTemp);
|
|
||||||
solution.RemoveReagent("water", FixedPoint2.New(50));
|
|
||||||
Assert.That(solution.Temperature, Is.EqualTo(initialTemp));
|
|
||||||
}
|
|
||||||
|
|
||||||
[Test]
|
|
||||||
public void RemoveSolutionDoesNotEffectTemperature()
|
|
||||||
{
|
|
||||||
const float initialTemp = 100.0f;
|
|
||||||
|
|
||||||
var solution = new Solution();
|
|
||||||
solution.AddReagent("water", FixedPoint2.New(100), initialTemp);
|
|
||||||
solution.RemoveSolution(FixedPoint2.New(50));
|
|
||||||
Assert.That(solution.Temperature, Is.EqualTo(initialTemp));
|
|
||||||
}
|
|
||||||
|
|
||||||
[Test]
|
|
||||||
public void SplitSolutionDoesNotEffectTemperature()
|
|
||||||
{
|
|
||||||
const float initialTemp = 100.0f;
|
|
||||||
|
|
||||||
var solution = new Solution();
|
|
||||||
solution.AddReagent("water", FixedPoint2.New(100), initialTemp);
|
|
||||||
solution.SplitSolution(FixedPoint2.New(50));
|
|
||||||
Assert.That(solution.Temperature, Is.EqualTo(initialTemp));
|
|
||||||
}
|
|
||||||
|
|
||||||
[Test]
|
|
||||||
public void AddReagentWithSetTemperatureAdjustsTemperature()
|
|
||||||
{
|
|
||||||
const float temp = 100.0f;
|
|
||||||
|
|
||||||
var solution = new Solution();
|
|
||||||
solution.AddReagent("water", FixedPoint2.New(100), temp * 1);
|
|
||||||
Assert.That(solution.Temperature, Is.EqualTo(temp * 1));
|
|
||||||
|
|
||||||
solution.AddReagent("water", FixedPoint2.New(100), temp * 3);
|
|
||||||
Assert.That(solution.Temperature, Is.EqualTo(temp * 2));
|
|
||||||
|
|
||||||
solution.AddReagent("earth", FixedPoint2.New(100), temp * 5);
|
|
||||||
Assert.That(solution.Temperature, Is.EqualTo(temp * 3));
|
|
||||||
}
|
|
||||||
|
|
||||||
[Test]
|
|
||||||
public void AddSolutionCombinesThermalEnergy()
|
|
||||||
{
|
|
||||||
const float initialTemp = 100.0f;
|
|
||||||
|
|
||||||
var solutionOne = new Solution();
|
|
||||||
solutionOne.AddReagent("water", FixedPoint2.New(100), initialTemp);
|
|
||||||
|
|
||||||
var solutionTwo = new Solution();
|
|
||||||
solutionTwo.AddReagent("water", FixedPoint2.New(100), initialTemp);
|
|
||||||
solutionTwo.AddReagent("earth", FixedPoint2.New(100));
|
|
||||||
|
|
||||||
var thermalEnergyOne = solutionOne.ThermalEnergy;
|
|
||||||
var thermalEnergyTwo = solutionTwo.ThermalEnergy;
|
|
||||||
solutionOne.AddSolution(solutionTwo);
|
|
||||||
Assert.That(solutionOne.ThermalEnergy, Is.EqualTo(thermalEnergyOne + thermalEnergyTwo));
|
|
||||||
}
|
|
||||||
|
|
||||||
#endregion Thermal Energy and Temperature
|
|
||||||
}
|
}
|
||||||
|
|
||||||
|
[Test]
|
||||||
|
public void AddReagentAndGetSolution()
|
||||||
|
{
|
||||||
|
var solution = new Solution();
|
||||||
|
solution.AddReagent("water", FixedPoint2.New(1000));
|
||||||
|
var quantity = solution.GetReagentQuantity("water");
|
||||||
|
|
||||||
|
Assert.That(quantity.Int(), Is.EqualTo(1000));
|
||||||
|
}
|
||||||
|
|
||||||
|
[Test]
|
||||||
|
public void ConstructorAddReagent()
|
||||||
|
{
|
||||||
|
var solution = new Solution("water", FixedPoint2.New(1000));
|
||||||
|
var quantity = solution.GetReagentQuantity("water");
|
||||||
|
|
||||||
|
Assert.That(quantity.Int(), Is.EqualTo(1000));
|
||||||
|
}
|
||||||
|
|
||||||
|
[Test]
|
||||||
|
public void NonExistingReagentReturnsZero()
|
||||||
|
{
|
||||||
|
var solution = new Solution();
|
||||||
|
var quantity = solution.GetReagentQuantity("water");
|
||||||
|
|
||||||
|
Assert.That(quantity.Int(), Is.EqualTo(0));
|
||||||
|
}
|
||||||
|
|
||||||
|
[Test]
|
||||||
|
public void AddLessThanZeroReagentReturnsZero()
|
||||||
|
{
|
||||||
|
var solution = new Solution("water", FixedPoint2.New(-1000));
|
||||||
|
var quantity = solution.GetReagentQuantity("water");
|
||||||
|
|
||||||
|
Assert.That(quantity.Int(), Is.EqualTo(0));
|
||||||
|
}
|
||||||
|
|
||||||
|
[Test]
|
||||||
|
public void AddingReagentsSumsProperly()
|
||||||
|
{
|
||||||
|
var solution = new Solution();
|
||||||
|
solution.AddReagent("water", FixedPoint2.New(1000));
|
||||||
|
solution.AddReagent("water", FixedPoint2.New(2000));
|
||||||
|
var quantity = solution.GetReagentQuantity("water");
|
||||||
|
|
||||||
|
Assert.That(quantity.Int(), Is.EqualTo(3000));
|
||||||
|
}
|
||||||
|
|
||||||
|
[Test]
|
||||||
|
public void ReagentQuantitiesStayUnique()
|
||||||
|
{
|
||||||
|
var solution = new Solution();
|
||||||
|
solution.AddReagent("water", FixedPoint2.New(1000));
|
||||||
|
solution.AddReagent("fire", FixedPoint2.New(2000));
|
||||||
|
|
||||||
|
Assert.That(solution.GetReagentQuantity("water").Int(), Is.EqualTo(1000));
|
||||||
|
Assert.That(solution.GetReagentQuantity("fire").Int(), Is.EqualTo(2000));
|
||||||
|
}
|
||||||
|
|
||||||
|
[Test]
|
||||||
|
public void TotalVolumeIsCorrect()
|
||||||
|
{
|
||||||
|
var solution = new Solution();
|
||||||
|
solution.AddReagent("water", FixedPoint2.New(1000));
|
||||||
|
solution.AddReagent("fire", FixedPoint2.New(2000));
|
||||||
|
|
||||||
|
Assert.That(solution.TotalVolume.Int(), Is.EqualTo(3000));
|
||||||
|
}
|
||||||
|
|
||||||
|
[Test]
|
||||||
|
public void CloningSolutionIsCorrect()
|
||||||
|
{
|
||||||
|
var solution = new Solution();
|
||||||
|
solution.AddReagent("water", FixedPoint2.New(1000));
|
||||||
|
solution.AddReagent("fire", FixedPoint2.New(2000));
|
||||||
|
|
||||||
|
var newSolution = solution.Clone();
|
||||||
|
|
||||||
|
Assert.That(newSolution.GetReagentQuantity("water").Int(), Is.EqualTo(1000));
|
||||||
|
Assert.That(newSolution.GetReagentQuantity("fire").Int(), Is.EqualTo(2000));
|
||||||
|
Assert.That(newSolution.TotalVolume.Int(), Is.EqualTo(3000));
|
||||||
|
}
|
||||||
|
|
||||||
|
[Test]
|
||||||
|
public void RemoveSolutionRecalculatesProperly()
|
||||||
|
{
|
||||||
|
var solution = new Solution();
|
||||||
|
solution.AddReagent("water", FixedPoint2.New(1000));
|
||||||
|
solution.AddReagent("fire", FixedPoint2.New(2000));
|
||||||
|
|
||||||
|
solution.RemoveReagent("water", FixedPoint2.New(500));
|
||||||
|
|
||||||
|
Assert.That(solution.GetReagentQuantity("water").Int(), Is.EqualTo(500));
|
||||||
|
Assert.That(solution.GetReagentQuantity("fire").Int(), Is.EqualTo(2000));
|
||||||
|
Assert.That(solution.TotalVolume.Int(), Is.EqualTo(2500));
|
||||||
|
}
|
||||||
|
|
||||||
|
[Test]
|
||||||
|
public void RemoveLessThanOneQuantityDoesNothing()
|
||||||
|
{
|
||||||
|
var solution = new Solution("water", FixedPoint2.New(100));
|
||||||
|
|
||||||
|
solution.RemoveReagent("water", FixedPoint2.New(-100));
|
||||||
|
|
||||||
|
Assert.That(solution.GetReagentQuantity("water").Int(), Is.EqualTo(100));
|
||||||
|
Assert.That(solution.TotalVolume.Int(), Is.EqualTo(100));
|
||||||
|
}
|
||||||
|
|
||||||
|
[Test]
|
||||||
|
public void RemoveMoreThanTotalRemovesAllReagent()
|
||||||
|
{
|
||||||
|
var solution = new Solution("water", FixedPoint2.New(100));
|
||||||
|
|
||||||
|
solution.RemoveReagent("water", FixedPoint2.New(1000));
|
||||||
|
|
||||||
|
Assert.That(solution.GetReagentQuantity("water").Int(), Is.EqualTo(0));
|
||||||
|
Assert.That(solution.TotalVolume.Int(), Is.EqualTo(0));
|
||||||
|
}
|
||||||
|
|
||||||
|
[Test]
|
||||||
|
public void RemoveNonExistReagentDoesNothing()
|
||||||
|
{
|
||||||
|
var solution = new Solution("water", FixedPoint2.New(100));
|
||||||
|
|
||||||
|
solution.RemoveReagent("fire", FixedPoint2.New(1000));
|
||||||
|
|
||||||
|
Assert.That(solution.GetReagentQuantity("water").Int(), Is.EqualTo(100));
|
||||||
|
Assert.That(solution.TotalVolume.Int(), Is.EqualTo(100));
|
||||||
|
}
|
||||||
|
|
||||||
|
[Test]
|
||||||
|
public void RemoveSolution()
|
||||||
|
{
|
||||||
|
var solution = new Solution("water", FixedPoint2.New(700));
|
||||||
|
|
||||||
|
solution.RemoveSolution(FixedPoint2.New(500));
|
||||||
|
|
||||||
|
//Check that edited solution is correct
|
||||||
|
Assert.That(solution.GetReagentQuantity("water").Int(), Is.EqualTo(200));
|
||||||
|
Assert.That(solution.TotalVolume.Int(), Is.EqualTo(200));
|
||||||
|
}
|
||||||
|
|
||||||
|
[Test]
|
||||||
|
public void RemoveSolutionMoreThanTotalRemovesAll()
|
||||||
|
{
|
||||||
|
var solution = new Solution("water", FixedPoint2.New(800));
|
||||||
|
|
||||||
|
solution.RemoveSolution(FixedPoint2.New(1000));
|
||||||
|
|
||||||
|
//Check that edited solution is correct
|
||||||
|
Assert.That(solution.GetReagentQuantity("water").Int(), Is.EqualTo(0));
|
||||||
|
Assert.That(solution.TotalVolume.Int(), Is.EqualTo(0));
|
||||||
|
}
|
||||||
|
|
||||||
|
[Test]
|
||||||
|
public void RemoveSolutionRatioPreserved()
|
||||||
|
{
|
||||||
|
var solution = new Solution();
|
||||||
|
solution.AddReagent("water", FixedPoint2.New(1000));
|
||||||
|
solution.AddReagent("fire", FixedPoint2.New(2000));
|
||||||
|
|
||||||
|
solution.RemoveSolution(FixedPoint2.New(1500));
|
||||||
|
|
||||||
|
Assert.That(solution.GetReagentQuantity("water").Int(), Is.EqualTo(500));
|
||||||
|
Assert.That(solution.GetReagentQuantity("fire").Int(), Is.EqualTo(1000));
|
||||||
|
Assert.That(solution.TotalVolume.Int(), Is.EqualTo(1500));
|
||||||
|
}
|
||||||
|
|
||||||
|
[Test]
|
||||||
|
public void RemoveSolutionLessThanOneDoesNothing()
|
||||||
|
{
|
||||||
|
var solution = new Solution("water", FixedPoint2.New(800));
|
||||||
|
|
||||||
|
solution.RemoveSolution(FixedPoint2.New(-200));
|
||||||
|
|
||||||
|
Assert.That(solution.GetReagentQuantity("water").Int(), Is.EqualTo(800));
|
||||||
|
Assert.That(solution.TotalVolume.Int(), Is.EqualTo(800));
|
||||||
|
}
|
||||||
|
|
||||||
|
[Test]
|
||||||
|
public void SplitSolution()
|
||||||
|
{
|
||||||
|
var solution = new Solution();
|
||||||
|
solution.AddReagent("water", FixedPoint2.New(1000));
|
||||||
|
solution.AddReagent("fire", FixedPoint2.New(2000));
|
||||||
|
|
||||||
|
var splitSolution = solution.SplitSolution(FixedPoint2.New(750));
|
||||||
|
|
||||||
|
Assert.That(solution.GetReagentQuantity("water").Int(), Is.EqualTo(750));
|
||||||
|
Assert.That(solution.GetReagentQuantity("fire").Int(), Is.EqualTo(1500));
|
||||||
|
Assert.That(solution.TotalVolume.Int(), Is.EqualTo(2250));
|
||||||
|
|
||||||
|
Assert.That(splitSolution.GetReagentQuantity("water").Int(), Is.EqualTo(250));
|
||||||
|
Assert.That(splitSolution.GetReagentQuantity("fire").Int(), Is.EqualTo(500));
|
||||||
|
Assert.That(splitSolution.TotalVolume.Int(), Is.EqualTo(750));
|
||||||
|
}
|
||||||
|
|
||||||
|
[Test]
|
||||||
|
public void SplitSolutionFractional()
|
||||||
|
{
|
||||||
|
var solution = new Solution();
|
||||||
|
solution.AddReagent("water", FixedPoint2.New(1));
|
||||||
|
solution.AddReagent("fire", FixedPoint2.New(2));
|
||||||
|
|
||||||
|
var splitSolution = solution.SplitSolution(FixedPoint2.New(1));
|
||||||
|
|
||||||
|
Assert.That(solution.GetReagentQuantity("water").Float(), Is.EqualTo(0.67f));
|
||||||
|
Assert.That(solution.GetReagentQuantity("fire").Float(), Is.EqualTo(1.33f));
|
||||||
|
Assert.That(solution.TotalVolume.Int(), Is.EqualTo(2));
|
||||||
|
|
||||||
|
Assert.That(splitSolution.GetReagentQuantity("water").Float(), Is.EqualTo(0.33f));
|
||||||
|
Assert.That(splitSolution.GetReagentQuantity("fire").Float(), Is.EqualTo(0.67f));
|
||||||
|
Assert.That(splitSolution.TotalVolume.Int(), Is.EqualTo(1));
|
||||||
|
}
|
||||||
|
|
||||||
|
[Test]
|
||||||
|
public void SplitSolutionFractionalOpposite()
|
||||||
|
{
|
||||||
|
var solution = new Solution();
|
||||||
|
solution.AddReagent("water", FixedPoint2.New(1));
|
||||||
|
solution.AddReagent("fire", FixedPoint2.New(2));
|
||||||
|
|
||||||
|
var splitSolution = solution.SplitSolution(FixedPoint2.New(2));
|
||||||
|
|
||||||
|
Assert.That(solution.GetReagentQuantity("water").Float(), Is.EqualTo(0.33f));
|
||||||
|
Assert.That(solution.GetReagentQuantity("fire").Float(), Is.EqualTo(0.67f));
|
||||||
|
Assert.That(solution.TotalVolume.Int(), Is.EqualTo(1));
|
||||||
|
|
||||||
|
Assert.That(splitSolution.GetReagentQuantity("water").Float(), Is.EqualTo(0.67f));
|
||||||
|
Assert.That(splitSolution.GetReagentQuantity("fire").Float(), Is.EqualTo(1.33f));
|
||||||
|
Assert.That(splitSolution.TotalVolume.Int(), Is.EqualTo(2));
|
||||||
|
}
|
||||||
|
|
||||||
|
[Test]
|
||||||
|
[TestCase(0.03f, 0.01f, 0.02f)]
|
||||||
|
[TestCase(0.03f, 0.02f, 0.01f)]
|
||||||
|
public void SplitSolutionTinyFractionalBigSmall(float initial, float reduce, float remainder)
|
||||||
|
{
|
||||||
|
var solution = new Solution();
|
||||||
|
solution.AddReagent("water", FixedPoint2.New(initial));
|
||||||
|
|
||||||
|
var splitSolution = solution.SplitSolution(FixedPoint2.New(reduce));
|
||||||
|
|
||||||
|
Assert.That(solution.GetReagentQuantity("water").Float(), Is.EqualTo(remainder));
|
||||||
|
Assert.That(solution.TotalVolume.Float(), Is.EqualTo(remainder));
|
||||||
|
|
||||||
|
Assert.That(splitSolution.GetReagentQuantity("water").Float(), Is.EqualTo(reduce));
|
||||||
|
Assert.That(splitSolution.TotalVolume.Float(), Is.EqualTo(reduce));
|
||||||
|
}
|
||||||
|
|
||||||
|
[Test]
|
||||||
|
[TestCase(2)]
|
||||||
|
[TestCase(10)]
|
||||||
|
[TestCase(100)]
|
||||||
|
[TestCase(1000)]
|
||||||
|
public void SplitRounding(int amount)
|
||||||
|
{
|
||||||
|
var solutionOne = new Solution();
|
||||||
|
solutionOne.AddReagent("foo", FixedPoint2.New(amount));
|
||||||
|
solutionOne.AddReagent("bar", FixedPoint2.New(amount));
|
||||||
|
solutionOne.AddReagent("baz", FixedPoint2.New(amount));
|
||||||
|
|
||||||
|
var splitAmount = FixedPoint2.New(5);
|
||||||
|
var split = solutionOne.SplitSolution(splitAmount);
|
||||||
|
|
||||||
|
Assert.That(split.TotalVolume, Is.EqualTo(splitAmount));
|
||||||
|
}
|
||||||
|
|
||||||
|
[Test]
|
||||||
|
public void SplitSolutionMoreThanTotalRemovesAll()
|
||||||
|
{
|
||||||
|
var solution = new Solution("water", FixedPoint2.New(800));
|
||||||
|
|
||||||
|
var splitSolution = solution.SplitSolution(FixedPoint2.New(1000));
|
||||||
|
|
||||||
|
Assert.That(solution.GetReagentQuantity("water").Int(), Is.EqualTo(0));
|
||||||
|
Assert.That(solution.TotalVolume.Int(), Is.EqualTo(0));
|
||||||
|
|
||||||
|
Assert.That(splitSolution.GetReagentQuantity("water").Int(), Is.EqualTo(800));
|
||||||
|
Assert.That(splitSolution.TotalVolume.Int(), Is.EqualTo(800));
|
||||||
|
}
|
||||||
|
|
||||||
|
[Test]
|
||||||
|
public void SplitSolutionLessThanOneDoesNothing()
|
||||||
|
{
|
||||||
|
var solution = new Solution("water", FixedPoint2.New(800));
|
||||||
|
|
||||||
|
var splitSolution = solution.SplitSolution(FixedPoint2.New(-200));
|
||||||
|
|
||||||
|
Assert.That(solution.GetReagentQuantity("water").Int(), Is.EqualTo(800));
|
||||||
|
Assert.That(solution.TotalVolume.Int(), Is.EqualTo(800));
|
||||||
|
|
||||||
|
Assert.That(splitSolution.GetReagentQuantity("water").Int(), Is.EqualTo(0));
|
||||||
|
Assert.That(splitSolution.TotalVolume.Int(), Is.EqualTo(0));
|
||||||
|
}
|
||||||
|
|
||||||
|
[Test]
|
||||||
|
public void SplitSolutionZero()
|
||||||
|
{
|
||||||
|
var solution = new Solution();
|
||||||
|
solution.AddReagent("Impedrezene", FixedPoint2.New(0.01 + 0.19));
|
||||||
|
solution.AddReagent("Thermite", FixedPoint2.New(0.01 + 0.39));
|
||||||
|
solution.AddReagent("Li", FixedPoint2.New(0.01 + 0.17));
|
||||||
|
solution.AddReagent("F", FixedPoint2.New(0.01 + 0.17));
|
||||||
|
solution.AddReagent("Na", FixedPoint2.New(0 + 0.13));
|
||||||
|
solution.AddReagent("Hg", FixedPoint2.New(0.15 + 4.15));
|
||||||
|
solution.AddReagent("Cu", FixedPoint2.New(0 + 0.13));
|
||||||
|
solution.AddReagent("U", FixedPoint2.New(0.76 + 20.77));
|
||||||
|
solution.AddReagent("Fe", FixedPoint2.New(0.01 + 0.36));
|
||||||
|
solution.AddReagent("SpaceDrugs", FixedPoint2.New(0.02 + 0.41));
|
||||||
|
solution.AddReagent("Al", FixedPoint2.New(0));
|
||||||
|
solution.AddReagent("Glucose", FixedPoint2.New(0));
|
||||||
|
solution.AddReagent("O", FixedPoint2.New(0));
|
||||||
|
|
||||||
|
solution.SplitSolution(FixedPoint2.New(0.98));
|
||||||
|
}
|
||||||
|
|
||||||
|
[Test]
|
||||||
|
public void AddSolution()
|
||||||
|
{
|
||||||
|
var solutionOne = new Solution();
|
||||||
|
solutionOne.AddReagent("water", FixedPoint2.New(1000));
|
||||||
|
solutionOne.AddReagent("fire", FixedPoint2.New(2000));
|
||||||
|
|
||||||
|
var solutionTwo = new Solution();
|
||||||
|
solutionTwo.AddReagent("water", FixedPoint2.New(500));
|
||||||
|
solutionTwo.AddReagent("earth", FixedPoint2.New(1000));
|
||||||
|
|
||||||
|
solutionOne.AddSolution(solutionTwo);
|
||||||
|
|
||||||
|
Assert.That(solutionOne.GetReagentQuantity("water").Int(), Is.EqualTo(1500));
|
||||||
|
Assert.That(solutionOne.GetReagentQuantity("fire").Int(), Is.EqualTo(2000));
|
||||||
|
Assert.That(solutionOne.GetReagentQuantity("earth").Int(), Is.EqualTo(1000));
|
||||||
|
Assert.That(solutionOne.TotalVolume.Int(), Is.EqualTo(4500));
|
||||||
|
}
|
||||||
|
|
||||||
|
// Tests concerning thermal energy and temperature.
|
||||||
|
|
||||||
|
#region Thermal Energy and Temperature
|
||||||
|
|
||||||
|
[Test]
|
||||||
|
public void EmptySolutionHasNoHeatCapacity()
|
||||||
|
{
|
||||||
|
var solution = new Solution();
|
||||||
|
Assert.That(solution.HeatCapacity, Is.EqualTo(0.0f));
|
||||||
|
}
|
||||||
|
|
||||||
|
[Test]
|
||||||
|
public void EmptySolutionHasNoThermalEnergy()
|
||||||
|
{
|
||||||
|
var solution = new Solution();
|
||||||
|
Assert.That(solution.ThermalEnergy, Is.EqualTo(0.0f));
|
||||||
|
}
|
||||||
|
|
||||||
|
[Test]
|
||||||
|
public void AddReagentToEmptySolutionSetsTemperature()
|
||||||
|
{
|
||||||
|
const float testTemp = 100.0f;
|
||||||
|
|
||||||
|
var solution = new Solution();
|
||||||
|
solution.AddReagent("water", FixedPoint2.New(100), testTemp);
|
||||||
|
Assert.That(solution.Temperature, Is.EqualTo(testTemp));
|
||||||
|
}
|
||||||
|
|
||||||
|
[Test]
|
||||||
|
public void AddReagentWithNullTemperatureDoesNotEffectTemperature()
|
||||||
|
{
|
||||||
|
const float initialTemp = 100.0f;
|
||||||
|
|
||||||
|
var solution = new Solution();
|
||||||
|
solution.AddReagent("water", FixedPoint2.New(100), initialTemp);
|
||||||
|
|
||||||
|
solution.AddReagent("water", FixedPoint2.New(100));
|
||||||
|
Assert.That(solution.Temperature, Is.EqualTo(initialTemp));
|
||||||
|
|
||||||
|
solution.AddReagent("earth", FixedPoint2.New(100));
|
||||||
|
Assert.That(solution.Temperature, Is.EqualTo(initialTemp));
|
||||||
|
}
|
||||||
|
|
||||||
|
[Test]
|
||||||
|
public void AddSolutionWithEqualTemperatureDoesNotChangeTemperature()
|
||||||
|
{
|
||||||
|
const float initialTemp = 100.0f;
|
||||||
|
|
||||||
|
var solutionOne = new Solution();
|
||||||
|
solutionOne.AddReagent("water", FixedPoint2.New(100));
|
||||||
|
solutionOne.Temperature = initialTemp;
|
||||||
|
|
||||||
|
var solutionTwo = new Solution();
|
||||||
|
solutionTwo.AddReagent("water", FixedPoint2.New(100));
|
||||||
|
solutionTwo.AddReagent("earth", FixedPoint2.New(100));
|
||||||
|
solutionTwo.Temperature = initialTemp;
|
||||||
|
|
||||||
|
solutionOne.AddSolution(solutionTwo);
|
||||||
|
Assert.That(solutionOne.Temperature, Is.EqualTo(initialTemp));
|
||||||
|
}
|
||||||
|
|
||||||
|
[Test]
|
||||||
|
public void RemoveReagentDoesNotEffectTemperature()
|
||||||
|
{
|
||||||
|
const float initialTemp = 100.0f;
|
||||||
|
|
||||||
|
var solution = new Solution();
|
||||||
|
solution.AddReagent("water", FixedPoint2.New(100), initialTemp);
|
||||||
|
solution.RemoveReagent("water", FixedPoint2.New(50));
|
||||||
|
Assert.That(solution.Temperature, Is.EqualTo(initialTemp));
|
||||||
|
}
|
||||||
|
|
||||||
|
[Test]
|
||||||
|
public void RemoveSolutionDoesNotEffectTemperature()
|
||||||
|
{
|
||||||
|
const float initialTemp = 100.0f;
|
||||||
|
|
||||||
|
var solution = new Solution();
|
||||||
|
solution.AddReagent("water", FixedPoint2.New(100), initialTemp);
|
||||||
|
solution.RemoveSolution(FixedPoint2.New(50));
|
||||||
|
Assert.That(solution.Temperature, Is.EqualTo(initialTemp));
|
||||||
|
}
|
||||||
|
|
||||||
|
[Test]
|
||||||
|
public void SplitSolutionDoesNotEffectTemperature()
|
||||||
|
{
|
||||||
|
const float initialTemp = 100.0f;
|
||||||
|
|
||||||
|
var solution = new Solution();
|
||||||
|
solution.AddReagent("water", FixedPoint2.New(100), initialTemp);
|
||||||
|
solution.SplitSolution(FixedPoint2.New(50));
|
||||||
|
Assert.That(solution.Temperature, Is.EqualTo(initialTemp));
|
||||||
|
}
|
||||||
|
|
||||||
|
[Test]
|
||||||
|
public void AddReagentWithSetTemperatureAdjustsTemperature()
|
||||||
|
{
|
||||||
|
const float temp = 100.0f;
|
||||||
|
|
||||||
|
var solution = new Solution();
|
||||||
|
solution.AddReagent("water", FixedPoint2.New(100), temp * 1);
|
||||||
|
Assert.That(solution.Temperature, Is.EqualTo(temp * 1));
|
||||||
|
|
||||||
|
solution.AddReagent("water", FixedPoint2.New(100), temp * 3);
|
||||||
|
Assert.That(solution.Temperature, Is.EqualTo(temp * 2));
|
||||||
|
|
||||||
|
solution.AddReagent("earth", FixedPoint2.New(100), temp * 5);
|
||||||
|
Assert.That(solution.Temperature, Is.EqualTo(temp * 3));
|
||||||
|
}
|
||||||
|
|
||||||
|
[Test]
|
||||||
|
public void AddSolutionCombinesThermalEnergy()
|
||||||
|
{
|
||||||
|
const float initialTemp = 100.0f;
|
||||||
|
|
||||||
|
var solutionOne = new Solution();
|
||||||
|
solutionOne.AddReagent("water", FixedPoint2.New(100), initialTemp);
|
||||||
|
|
||||||
|
var solutionTwo = new Solution();
|
||||||
|
solutionTwo.AddReagent("water", FixedPoint2.New(100), initialTemp);
|
||||||
|
solutionTwo.AddReagent("earth", FixedPoint2.New(100));
|
||||||
|
|
||||||
|
var thermalEnergyOne = solutionOne.ThermalEnergy;
|
||||||
|
var thermalEnergyTwo = solutionTwo.ThermalEnergy;
|
||||||
|
solutionOne.AddSolution(solutionTwo);
|
||||||
|
Assert.That(solutionOne.ThermalEnergy, Is.EqualTo(thermalEnergyOne + thermalEnergyTwo));
|
||||||
|
}
|
||||||
|
|
||||||
|
#endregion Thermal Energy and Temperature
|
||||||
}
|
}
|
||||||
|
|||||||
Reference in New Issue
Block a user