diff --git a/tests/Aetheria.Shared.Tests/LockWarningTests.cs b/tests/Aetheria.Shared.Tests/LockWarningTests.cs index 28b6abbc2..3b2710660 100644 --- a/tests/Aetheria.Shared.Tests/LockWarningTests.cs +++ b/tests/Aetheria.Shared.Tests/LockWarningTests.cs @@ -68,7 +68,7 @@ public sealed class LockWarningTests : IDisposable private static PerformanceStat Const(float v) => new PerformanceStat { Min = v, Max = v }; - private static GearData Launcher(string name, float lockSpeed, float sensorImpact, float lockAngle, float directionImpact) => new GearData + private static GearData Launcher(string name, float lockSpeed, float sensorImpact, float lockAngle, float directionImpact) => WithMunitionParts(new GearData { Name = name, Hardpoint = HardpointType.Sensors, Shape = new Shape(), Durability = 1, MinimumTemperature = -1000, MaximumTemperature = 1000, OptimalTemperature = 0, PlateauWidth = 2000, @@ -84,7 +84,14 @@ public sealed class LockWarningTests : IDisposable DirectionImpact = Const(directionImpact), Decay = Const(.1f) } } - }; + }); + + // A launcher design carries the five munition parts (StatValidation.ValidateMunitionParts); these fixtures are about the lock. + private static GearData WithMunitionParts(GearData launcher) + { + launcher.Behaviors.AddRange(MunitionPartsTests.Parts(0)); + return launcher; + } private int _nextLot = 2; diff --git a/tests/Aetheria.Shared.Tests/MunitionPartsTests.cs b/tests/Aetheria.Shared.Tests/MunitionPartsTests.cs index 1e3de8fd2..a7da2c8c2 100644 --- a/tests/Aetheria.Shared.Tests/MunitionPartsTests.cs +++ b/tests/Aetheria.Shared.Tests/MunitionPartsTests.cs @@ -30,16 +30,18 @@ public sealed class MunitionPartsTests : IDisposable private static PerformanceStat Flat(float value) => new PerformanceStat { Min = value, Max = value }; - private static PerformanceStat Ranged(float min, float max, string role) => new PerformanceStat + private static PerformanceStat Ranged(float min, float max, string role) => role == null ? Flat(max) : new PerformanceStat { Min = min, Max = max, Terms = new List { new StatTerm { Source = StatSource.Quality, Exponent = 1.5f, Role = role } }, }; - // Every field set to a distinct value, so a field read from the wrong slot or dropped on the way is seen. - private static List Parts(int group) => new List + // The five parts a munition design carries, every field set to a distinct value so a field read from the wrong slot or + // dropped on the way is seen. The thruster's stats vary with the given role's quality when one is named; the design + // that carries them declares it. Fixtures that only need a valid munition pass none. + internal static List Parts(int group, string role = null) => new List { new MunitionHullData { Group = group, Durability = Flat(21), Radius = Flat(4.5f) }, - new MunitionThrusterData { Group = group, Acceleration = Ranged(300, 400, "motor"), Lateral = Ranged(150, 200, "motor"), MaxSpeed = Ranged(250, 350, "motor"), Visibility = Flat(11) }, + new MunitionThrusterData { Group = group, Acceleration = Ranged(300, 400, role), Lateral = Ranged(150, 200, role), MaxSpeed = Ranged(250, 350, role), Visibility = Flat(11) }, new MunitionSeekerData { Group = group, Sensitivity = Flat(.8f), BeamWidth = Flat(55), Range = Flat(900) }, new MunitionControlData { Group = group, Navigation = Flat(3.5f), Evasion = Flat(.4f), EvasionFrequency = Flat(.6f), Lifetime = Flat(12), Cognition = Flat(.35f) }, new MunitionFuelData { Group = group, DeltaV = Flat(700) }, @@ -57,7 +59,7 @@ public sealed class MunitionPartsTests : IDisposable launcher.Group = group; var design = new WeaponItemData { Name = name, Roles = new List { new ItemRole { Name = "motor" } } }; design.Behaviors.Add(launcher); - design.Behaviors.AddRange(Parts(group)); + design.Behaviors.AddRange(Parts(group, "motor")); return design; } @@ -102,12 +104,10 @@ public sealed class MunitionPartsTests : IDisposable Assert.Equal((thrustMin, thrustMax), (thruster.Acceleration.Min, thruster.Acceleration.Max)); Assert.Equal((thrustMin / 2f, thrustMax / 2f), (thruster.Lateral.Min, thruster.Lateral.Max)); Assert.Equal((speedMin, speedMax), (thruster.MaxSpeed.Min, thruster.MaxSpeed.Max)); + // The terms come across whole: the role's Quality term and whatever heat or durability terms the stat carried. + Assert.Equal(Describe(thruster.Acceleration).Split('[')[1], Describe(thruster.Lateral).Split('[')[1]); foreach (var stat in new[] { thruster.Acceleration, thruster.Lateral, thruster.MaxSpeed }) - { - var term = Assert.Single(stat.Terms); - Assert.Equal((StatSource.Quality, "thruster"), (term.Source, term.Role)); - } - Assert.Equal(thruster.Acceleration.Terms.Single().Exponent, thruster.Lateral.Terms.Single().Exponent); + Assert.Equal("thruster", Assert.Single(stat.Terms, t => t.Source == StatSource.Quality).Role); var evasion = Part(design).EvasionFrequency; Assert.Equal((dodge, dodge), (evasion.Min, evasion.Max)); @@ -183,7 +183,15 @@ public sealed class MunitionPartsTests : IDisposable var zone = new Zone(items, new PlanetSettings(), new ZonePack(), new GalaxyZone { Name = "Test", Owner = null }, null); ship = new Ship(items, zone, new EquippableItem { Data = cache.RefOf(hull), Durability = hull.Durability, Lot = 1 }, settings.DefaultEntitySettings); Assert.True(ship.TryEquip(new EquippableItem { Data = cache.RefOf(gt), Durability = gt.Durability, Lot = 2 }, hardpoint.Position)); - return ship.Equipment.Single(e => e.Data.Name == "GT 3K"); + zone.Entities.Add(ship); + ship.Activate(); + // Settle at the item's optimal temperature, as ConditionRatioTests does, so heat and wear read their identity and only + // the role's quality moves a stat. + var item = ship.Equipment.Single(e => e.Data.Name == "GT 3K"); + foreach (var cell in item.InsetShape.Coordinates) ship.Temperature[cell.x, cell.y] = gt.OptimalTemperature; + item.UpdatePerformance(); + item.UpdatePerformance(); + return item; } [Fact]