Tests follow the allocator: warm-up, free thruster power, heat-detuned drives
The allocator reads Item.Active every tick, so fixtures that fire a thruster on their first update warm its performance first; flight fixtures take the thrusters' energy draw to zero so a brownout does not scale the turn; the Duel drives are mismatched after they heat apart, and degraded by heat (the Large Drive has no durability term); the consumer sits at (2,1), the Skiff's interior centre column. ReachIsWhatTheShipCanDo's Longinus ceiling is 1.3 (measured 1.195 nose-on, 1.249 broadside). Previous test commits do not build or pass; this one is unverified until the full run. Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
This commit is contained in:
parent
ffda2a8a76
commit
ab450e72d3
7 changed files with 32 additions and 9 deletions
|
|
@ -111,8 +111,7 @@ public sealed class BrownoutTests : IDisposable
|
|||
Assert.True(ship.TryEquip(Mint(cache, items, reactorData)));
|
||||
// The Skiff's centre column: a thruster there has no torque, so the allocator can fire it alone. These tests pin power,
|
||||
// not flight, and a lone off-centre thruster could not fire without turning.
|
||||
Assert.True(ship.TryEquip(Mint(cache, items, cache.GetByName<GearData>("Consumer")), new int2(2, 0)));
|
||||
Assert.True(ship.GetBehavior<Thruster>().Torque == 0f, "the lone thruster turns nothing");
|
||||
Assert.True(ship.TryEquip(Mint(cache, items, cache.GetByName<GearData>("Consumer")), new int2(2, 1)));
|
||||
|
||||
zone.Entities.Add(ship);
|
||||
// Ship.Turn stays 0, so Ship.Update commands no rotation: no incidental torque thrust from the
|
||||
|
|
@ -132,6 +131,8 @@ public sealed class BrownoutTests : IDisposable
|
|||
Thrust = Curved(100, exponent), Visibility = Constant(0), Heat = Constant(0), EnergyUsage = Constant(100)
|
||||
});
|
||||
var ship = BuildShip(cache, reactorCharge);
|
||||
Assert.True(ship.GetBehavior<Thruster>().Torque == 0f, "the lone thruster turns nothing");
|
||||
ship.Equipment.Single(e => e.Data.Name == "Consumer").UpdatePerformance(); // live from its first performance update
|
||||
ship.MovementDirection = float2(0, -1); // reverse-thruster axis += -MovementDirection.y == 1
|
||||
ship.Update(1f);
|
||||
return (-ship.Velocity.y, ship.GetBehavior<Thruster>());
|
||||
|
|
@ -339,9 +340,11 @@ public sealed class BrownoutTests : IDisposable
|
|||
var energyUsage = Curved(100, exponent: 1);
|
||||
using var cache = OpenCatalog(new ThrusterData
|
||||
{
|
||||
Thrust = Constant(0), Visibility = Constant(0), Heat = Constant(0), EnergyUsage = energyUsage
|
||||
Thrust = Constant(100), Visibility = Constant(0), Heat = Constant(0), EnergyUsage = energyUsage
|
||||
});
|
||||
var ship = BuildShip(cache, reactorCharge: 25); // demand 100 (nominal), generation 25 -> ratio .25
|
||||
// The allocator fires a thruster that can push; it is live from its first performance update.
|
||||
ship.Equipment.Single(e => e.Data.Name == "Consumer").UpdatePerformance();
|
||||
ship.MovementDirection = float2(0, -1);
|
||||
ship.Update(1f);
|
||||
var thruster = ship.GetBehavior<Thruster>();
|
||||
|
|
|
|||
|
|
@ -94,13 +94,13 @@ public sealed class ConditionRatioTests : IDisposable
|
|||
Assert.True(ship.TryEquip(Mint(cache, items, reactorData)));
|
||||
// The Skiff's centre column: a thruster there has no torque, so the allocator can fire it alone. These tests pin power,
|
||||
// not flight, and a lone off-centre thruster could not fire without turning.
|
||||
Assert.True(ship.TryEquip(Mint(cache, items, cache.GetByName<GearData>("Consumer")), new int2(2, 0)));
|
||||
Assert.True(ship.GetBehavior<Thruster>().Torque == 0f, "the lone thruster turns nothing");
|
||||
Assert.True(ship.TryEquip(Mint(cache, items, cache.GetByName<GearData>("Consumer")), new int2(2, 1)));
|
||||
|
||||
zone.Entities.Add(ship);
|
||||
ship.Aim = float3(0, 0, 1); // Turn stays 0, as in BrownoutTests
|
||||
ship.Activate();
|
||||
consumer = ship.Equipment.Single(e => e.Data.Name == "Consumer");
|
||||
Assert.True(ship.GetBehavior<Thruster>().Torque == 0f, "the lone thruster turns nothing");
|
||||
|
||||
// Settle at the plateau's center: two ticks so UpdatePerformance's deltaTemp term reads 0 before a test
|
||||
// drives its own change, matching HeatResponseTests' own settle pattern.
|
||||
|
|
|
|||
|
|
@ -273,7 +273,11 @@ public sealed partial class RunStartTests
|
|||
// The Djinni's measured motion is further below its reach (+53% nose-on, +27% broadside at the last measurement): its
|
||||
// strafers are off-axis and Ship.Update cancels their torque (M24), which the envelope, summed from what each thruster
|
||||
// can push, does not model. Stated deviation; the bound still pins that the reach covers what the ship does.
|
||||
var ceiling = name == "djinni" ? 1.6f : 1.15f;
|
||||
// The Longinus's reach sits 19.5% (nose-on) and 24.9% (broadside) above what the allocator's flight measures
|
||||
// (ruling allocator-divergence-accepted): the allocator holds the heading and pays for the drive torque out of
|
||||
// the flank thrusters, so the envelope's box support (cut envelope-from-columns reads the allocator's columns)
|
||||
// promises more than a controlled flight spends.
|
||||
var ceiling = name == "djinni" ? 1.6f : 1.3f;
|
||||
Assert.InRange(reach.noseOn, measured.noseOn * .9f, measured.noseOn * ceiling);
|
||||
Assert.InRange(reach.broadside, measured.broadside * .9f, measured.broadside * ceiling);
|
||||
}
|
||||
|
|
|
|||
|
|
@ -268,6 +268,16 @@ public sealed class RestoredHullsTests
|
|||
}
|
||||
}
|
||||
|
||||
// For a fixture that pins flight, not brownout: the thrusters draw no power. A ship with every thruster firing asks
|
||||
// for more than its reactor gives, and a brownout scales the thrusters' thrust unevenly (follow-up
|
||||
// allocator-brownout-columns), so the turn or heading a test reads would be the brownout's.
|
||||
internal static void FreeThrusterPower(CultCache cache)
|
||||
{
|
||||
foreach (var gear in cache.GetAll<GearData>())
|
||||
foreach (var thruster in gear.Behaviors.OfType<ThrusterData>())
|
||||
thruster.EnergyUsage = new PerformanceStat { Min = 0, Max = 0 };
|
||||
}
|
||||
|
||||
// A restored hull with every thruster hardpoint (and its reactor) filled, activated and warmed up: the
|
||||
// rotation thrusters the helm tests need. The caller owns the cache.
|
||||
internal static Ship BuildThrustedShip(CultCache cache, string name)
|
||||
|
|
|
|||
|
|
@ -290,6 +290,7 @@ public sealed class SteeringTests
|
|||
public void ATurnIsThatFractionOfTheHullsTurn(float turn)
|
||||
{
|
||||
using var cache = RestoredHullsTests.OpenCatalog();
|
||||
RestoredHullsTests.FreeThrusterPower(cache);
|
||||
var ship = RestoredHullsTests.BuildThrustedShip(cache, Hull);
|
||||
var settings = RestoredHullsTests.Settings();
|
||||
const float dt = 1f / 60f;
|
||||
|
|
|
|||
|
|
@ -89,6 +89,8 @@ public sealed class ThrottleLockTests : IDisposable
|
|||
zone.Entities.Add(ship);
|
||||
ship.Aim = float3(0, 0, 1);
|
||||
ship.Activate();
|
||||
// A thruster is live from its first performance update; the allocator reads that every tick.
|
||||
foreach (var item in ship.Equipment) item.UpdatePerformance();
|
||||
|
||||
var thrusters = ship.GetBehaviors<Thruster>().ToArray();
|
||||
return new Fixture
|
||||
|
|
|
|||
|
|
@ -43,10 +43,11 @@ public sealed partial class RunStartTests
|
|||
{
|
||||
var (_, player) = AllocDuel();
|
||||
var drives = AllocDrives(player);
|
||||
Assert.True(drives.Length >= 2 && drives[^1].NominalThrust > drives[0].NominalThrust * 1.05f, "fixture: the drives are mismatched");
|
||||
player.MovementDirection = float2(0, 1);
|
||||
player.Turn = 0;
|
||||
Assert.True(abs(AllocFly(player, 120)) < .1f);
|
||||
// The drives start alike and heat apart as they fire: by now they are mismatched and both pushing.
|
||||
Assert.True(drives.Length >= 2 && drives[^1].NominalThrust > drives[0].NominalThrust * 1.05f, "fixture: the drives are mismatched");
|
||||
Assert.All(drives, d => Assert.True(d.Axis > .5f, "fixture: the drives are pushing"));
|
||||
}
|
||||
|
||||
|
|
@ -88,11 +89,12 @@ public sealed partial class RunStartTests
|
|||
player.Turn = 0;
|
||||
Assert.True(abs(AllocFly(player, 30)) < .1f);
|
||||
|
||||
// The drive is heated a little off its plateau: its live thrust moves, and a column cached before would not.
|
||||
var weakened = drives[^1];
|
||||
var before = weakened.Thrust;
|
||||
weakened.Item.EquippableItem.Durability *= .5f;
|
||||
foreach (var cell in weakened.Item.InsetShape.Coordinates) player.Temperature[cell.x, cell.y] += 5f;
|
||||
weakened.Item.UpdatePerformance();
|
||||
Assert.True(weakened.Thrust < before * .95f, "fixture: halving durability weakens the drive");
|
||||
Assert.True(weakened.Thrust < before * .95f && weakened.Item.Active.Value, "fixture: the heated drive pushes measurably less");
|
||||
Assert.True(abs(AllocFly(player, 60)) < .1f);
|
||||
}
|
||||
|
||||
|
|
@ -100,6 +102,7 @@ public sealed partial class RunStartTests
|
|||
public void ATinyImbalanceStillHolds()
|
||||
{
|
||||
using var cache = RestoredHullsTests.OpenCatalog();
|
||||
RestoredHullsTests.FreeThrusterPower(cache);
|
||||
var ship = RestoredHullsTests.BuildThrustedShip(cache, "Longinus");
|
||||
var drives = AllocDrives(ship);
|
||||
Assert.True(drives.Length >= 2);
|
||||
|
|
|
|||
Loading…
Reference in a new issue