Sweep: every old design-name literal in C# becomes its generic name; product texts ship without the authoring notes

Scenarios, tests, AetherDb templates and name-keyed maps now resolve designs by the generic names (231 literals in 30 files);
TargetingCatalog's product texts lose the authoring note, Steadfast carries its r3 text, DragOnBreath plight's old design text.
Not built yet; tests that depend on the generic-designs command and new tests follow.

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
This commit is contained in:
Meta Vens 2026-10-13 20:29:10 +02:00
commit f7cf3257d0
30 changed files with 212 additions and 212 deletions

View file

@ -20,13 +20,13 @@ public sealed class AiFusedDiscipline : Scenario
("Cockpit 2x2", int2(2, 6), None),
("Large Drive", int2(1, 0), Reversed),
("Large Drive", int2(3, 0), Reversed),
("Talaria", int2(2, 14), CounterClockwise),
("Talaria", int2(3, 14), Clockwise),
("Core Power", int2(2, 4), None),
("Rugged Drive", int2(2, 14), CounterClockwise),
("Rugged Drive", int2(3, 14), Clockwise),
("Compact Reactor", int2(2, 4), None),
(weapon, int2(1, 8), None),
("Iapyx", int2(2, 2), CounterClockwise),
("Iapyx", int2(3, 2), Clockwise),
("not if i see you first", int2(3, 10), None),
("Radiator", int2(2, 2), CounterClockwise),
("Radiator", int2(3, 2), Clockwise),
("Compact Sensor", int2(3, 10), None),
("Fire Control Array", int2(1, 6), Clockwise));
stage.Player(stage.Generated("Djinni"), float2(0, 0));

View file

@ -27,27 +27,27 @@ public sealed class Arcs : Scenario
("Cockpit 2x2", int2(4, 6), None),
("Large Drive", int2(3, 0), Reversed),
("Large Drive", int2(5, 0), Reversed),
("Talaria", int2(4, 14), CounterClockwise),
("Talaria", int2(5, 14), Clockwise),
("Core Power", int2(4, 4), None),
("GT 3K", int2(2, 5), None),
("GT 3K", int2(7, 5), None),
("FastBlast+-", int2(3, 8), None),
("FastBlast+-", int2(6, 8), None),
("Iapyx", int2(4, 2), CounterClockwise),
("Iapyx", int2(5, 2), Clockwise),
("not if i see you first", int2(5, 10), None),
("Rugged Drive", int2(4, 14), CounterClockwise),
("Rugged Drive", int2(5, 14), Clockwise),
("Compact Reactor", int2(4, 4), None),
("Guided Missile Launcher", int2(2, 5), None),
("Guided Missile Launcher", int2(7, 5), None),
("Cell Blaster", int2(3, 8), None),
("Cell Blaster", int2(6, 8), None),
("Radiator", int2(4, 2), CounterClockwise),
("Radiator", int2(5, 2), Clockwise),
("Compact Sensor", int2(5, 10), None),
("Fire Control Array", int2(3, 6), Clockwise),
("Autocannon", int2(8, 4), Clockwise),
("ChargeBlast SG", int2(0, 4), CounterClockwise));
("Charged Scatter Blaster", int2(0, 4), CounterClockwise));
var turret = stage.Fit("Turret",
("ClearPath", int2(1, 2), None),
("ClearPath", int2(5, 2), None),
("Skiron", int2(0, 2), CounterClockwise),
("Skiron", int2(7, 2), Clockwise),
("Core Power", int2(3, 3), None),
("Light Machine Gun", int2(1, 2), None),
("Light Machine Gun", int2(5, 2), None),
("Long Radiator", int2(0, 2), CounterClockwise),
("Long Radiator", int2(7, 2), Clockwise),
("Compact Reactor", int2(3, 3), None),
("Turret Control Module", int2(3, 5), None),
("not if i see you first", int2(4, 5), None),
("Compact Sensor", int2(4, 5), None),
("Fire Control Array", int2(3, 6), None));
stage.Player(fighter, float2(0, 0), facing: float2(0, 1));

View file

@ -23,16 +23,16 @@ public sealed class Belt : Scenario
("Cockpit 2x2", int2(2, 6), None),
("Large Drive", int2(1, 0), Reversed),
("Large Drive", int2(3, 0), Reversed),
("Talaria", int2(2, 14), CounterClockwise),
("Talaria", int2(3, 14), Clockwise),
("Core Power", int2(2, 4), None),
("GT 3K", int2(0, 5), None),
("GT 3K", int2(5, 5), None),
("plight", int2(1, 8), None),
("FastBlast+-", int2(4, 8), None),
("Iapyx", int2(2, 2), CounterClockwise),
("Iapyx", int2(3, 2), Clockwise),
("not if i see you first", int2(3, 10), None),
("Rugged Drive", int2(2, 14), CounterClockwise),
("Rugged Drive", int2(3, 14), Clockwise),
("Compact Reactor", int2(2, 4), None),
("Guided Missile Launcher", int2(0, 5), None),
("Guided Missile Launcher", int2(5, 5), None),
("Lightning Projector", int2(1, 8), None),
("Cell Blaster", int2(4, 8), None),
("Radiator", int2(2, 2), CounterClockwise),
("Radiator", int2(3, 2), Clockwise),
("Compact Sensor", int2(3, 10), None),
("Fire Control Array", int2(1, 6), Clockwise));
// The belt is a ring about its parent's position at the belt orbit's distance. The player stands 100 m outside

View file

@ -27,16 +27,16 @@ public sealed class Crossing : Scenario
("Cockpit 2x2", int2(2, 6), None),
("Large Drive", int2(1, 0), Reversed),
("Large Drive", int2(3, 0), Reversed),
("Talaria", int2(2, 14), CounterClockwise),
("Talaria", int2(3, 14), Clockwise),
("Core Power", int2(2, 4), None),
("GT 3K", int2(0, 5), None),
("GT 3K", int2(5, 5), None),
("plight", int2(1, 8), None),
("FastBlast+-", int2(4, 8), None),
("Iapyx", int2(2, 2), CounterClockwise),
("Iapyx", int2(3, 2), Clockwise),
("not if i see you first", int2(3, 10), None),
("Rugged Drive", int2(2, 14), CounterClockwise),
("Rugged Drive", int2(3, 14), Clockwise),
("Compact Reactor", int2(2, 4), None),
("Guided Missile Launcher", int2(0, 5), None),
("Guided Missile Launcher", int2(5, 5), None),
("Lightning Projector", int2(1, 8), None),
("Cell Blaster", int2(4, 8), None),
("Radiator", int2(2, 2), CounterClockwise),
("Radiator", int2(3, 2), Clockwise),
("Compact Sensor", int2(3, 10), None),
("Fire Control Array", int2(1, 6), Clockwise));
stage.Player(fighter, float2(0, 0), facing: float2(0, 1));

View file

@ -17,22 +17,22 @@ public sealed class Duel : Scenario
("Cockpit 2x2", int2(2, 6), None),
("Large Drive", int2(1, 0), Reversed),
("Large Drive", int2(3, 0), Reversed),
("Talaria", int2(2, 14), CounterClockwise),
("Talaria", int2(3, 14), Clockwise),
("Core Power", int2(2, 4), None),
("GT 3K", int2(0, 5), None),
("GT 3K", int2(5, 5), None),
("FastBlast+-", int2(1, 8), None),
("FastBlast+-", int2(4, 8), None),
("Iapyx", int2(2, 2), CounterClockwise),
("Iapyx", int2(3, 2), Clockwise),
("not if i see you first", int2(3, 10), None),
("PotaT+-", int2(1, 5), None),
("Rugged Drive", int2(2, 14), CounterClockwise),
("Rugged Drive", int2(3, 14), Clockwise),
("Compact Reactor", int2(2, 4), None),
("Guided Missile Launcher", int2(0, 5), None),
("Guided Missile Launcher", int2(5, 5), None),
("Cell Blaster", int2(1, 8), None),
("Cell Blaster", int2(4, 8), None),
("Radiator", int2(2, 2), CounterClockwise),
("Radiator", int2(3, 2), Clockwise),
("Compact Sensor", int2(3, 10), None),
("Capacitor", int2(1, 5), None),
("Fire Control Array", int2(1, 6), Clockwise),
("Store-All Plus", int2(2, 8), None));
("Cargo Bay", int2(2, 8), None));
stage.Player(fighter, float2(0, 0));
var rival = stage.Place(fighter, float2(0, 900), facing: float2(0, -1), stance: ScenarioStance.Hostile, piloted: true);
stage.Cargo(rival, "Spectra");
stage.Cargo(rival, "Light Laser");
}
}

View file

@ -30,15 +30,15 @@ public sealed class FusedRounds : Scenario
("Cockpit 2x2", int2(4, 6), None),
("Large Drive", int2(3, 0), Reversed),
("Large Drive", int2(5, 0), Reversed),
("Talaria", int2(4, 14), CounterClockwise),
("Talaria", int2(5, 14), Clockwise),
("Core Power", int2(4, 4), None),
("Rugged Drive", int2(4, 14), CounterClockwise),
("Rugged Drive", int2(5, 14), Clockwise),
("Compact Reactor", int2(4, 4), None),
("Smoke Proximity", int2(3, 8), None),
("Smoke Delayed", int2(6, 8), None),
("DeathCluster", int2(5, 17), None),
("Iapyx", int2(4, 2), CounterClockwise),
("Iapyx", int2(5, 2), Clockwise),
("not if i see you first", int2(5, 10), None),
("Cluster Cannon", int2(5, 17), None),
("Radiator", int2(4, 2), CounterClockwise),
("Radiator", int2(5, 2), Clockwise),
("Compact Sensor", int2(5, 10), None),
("Fire Control Array", int2(3, 6), Clockwise));
stage.Player(shooter, float2(0, 0), facing: float2(0, 1));

View file

@ -17,16 +17,16 @@ public sealed class LauncherAngles : Scenario
("Cockpit 2x2", int2(2, 6), None),
("Large Drive", int2(1, 0), Reversed),
("Large Drive", int2(3, 0), Reversed),
("Talaria", int2(2, 14), CounterClockwise),
("Talaria", int2(3, 14), Clockwise),
("Core Power", int2(2, 4), None),
("GT 3K", int2(0, 5), None),
("pswarm", int2(5, 5), None),
("FastBlast+-", int2(1, 8), None),
("FastBlast+-", int2(4, 8), None),
("Iapyx", int2(2, 2), CounterClockwise),
("Iapyx", int2(3, 2), Clockwise),
("not if i see you first", int2(3, 10), None),
("Rugged Drive", int2(2, 14), CounterClockwise),
("Rugged Drive", int2(3, 14), Clockwise),
("Compact Reactor", int2(2, 4), None),
("Guided Missile Launcher", int2(0, 5), None),
("Swarm Rocket Pod", int2(5, 5), None),
("Cell Blaster", int2(1, 8), None),
("Cell Blaster", int2(4, 8), None),
("Radiator", int2(2, 2), CounterClockwise),
("Radiator", int2(3, 2), Clockwise),
("Compact Sensor", int2(3, 10), None),
("Fire Control Array", int2(1, 6), Clockwise));
stage.Player(launcher, float2(0, 0));

View file

@ -23,35 +23,35 @@ public sealed class Pursuit : Scenario
("Cockpit 2x2", int2(2, 6), None),
("Large Drive", int2(1, 0), Reversed),
("Large Drive", int2(3, 0), Reversed),
("Talaria", int2(2, 14), CounterClockwise),
("Talaria", int2(3, 14), Clockwise),
("Core Power", int2(2, 4), None),
("Rugged Drive", int2(2, 14), CounterClockwise),
("Rugged Drive", int2(3, 14), Clockwise),
("Compact Reactor", int2(2, 4), None),
("Mine Launcher", int2(0, 5), None),
("pswarm", int2(5, 5), None),
("FastBlast+-", int2(1, 8), None),
("FastBlast+-", int2(4, 8), None),
("Iapyx", int2(2, 2), CounterClockwise),
("Iapyx", int2(3, 2), Clockwise),
("not if i see you first", int2(3, 10), None),
("Swarm Rocket Pod", int2(5, 5), None),
("Cell Blaster", int2(1, 8), None),
("Cell Blaster", int2(4, 8), None),
("Radiator", int2(2, 2), CounterClockwise),
("Radiator", int2(3, 2), Clockwise),
("Compact Sensor", int2(3, 10), None),
("Fire Control Array", int2(1, 6), Clockwise),
("Store-All Plus", int2(2, 8), None));
("Cargo Bay", int2(2, 8), None));
var pursuer = stage.Fit("Longinus",
("Cockpit 2x2", int2(2, 6), None),
("Large Drive", int2(1, 0), Reversed),
("Large Drive", int2(3, 0), Reversed),
("Talaria", int2(2, 14), CounterClockwise),
("Talaria", int2(3, 14), Clockwise),
("Core Power", int2(2, 4), None),
("GT 3K", int2(0, 5), None),
("GT 3K", int2(5, 5), None),
("FastBlast+-", int2(1, 8), None),
("FastBlast+-", int2(4, 8), None),
("Iapyx", int2(2, 2), CounterClockwise),
("Iapyx", int2(3, 2), Clockwise),
("not if i see you first", int2(3, 10), None),
("PotaT+-", int2(1, 5), None),
("Rugged Drive", int2(2, 14), CounterClockwise),
("Rugged Drive", int2(3, 14), Clockwise),
("Compact Reactor", int2(2, 4), None),
("Guided Missile Launcher", int2(0, 5), None),
("Guided Missile Launcher", int2(5, 5), None),
("Cell Blaster", int2(1, 8), None),
("Cell Blaster", int2(4, 8), None),
("Radiator", int2(2, 2), CounterClockwise),
("Radiator", int2(3, 2), Clockwise),
("Compact Sensor", int2(3, 10), None),
("Capacitor", int2(1, 5), None),
("Fire Control Array", int2(1, 6), Clockwise),
("Store-All Plus", int2(2, 8), None));
("Cargo Bay", int2(2, 8), None));
var player = stage.Player(layer, float2(0, 0), facing: float2(0, 1));
stage.Cargo(player, "Coolant Vent", "Coolant Vent", "Coolant Vent", "Thruster Overdrive", "Thruster Overdrive");

View file

@ -22,16 +22,16 @@ public sealed class RefusedRounds : Scenario
("Cockpit 2x2", int2(4, 6), None),
("Large Drive", int2(3, 0), Reversed),
("Large Drive", int2(5, 0), Reversed),
("Talaria", int2(4, 14), CounterClockwise),
("Talaria", int2(5, 14), Clockwise),
("Core Power", int2(4, 4), None),
("Rugged Drive", int2(4, 14), CounterClockwise),
("Rugged Drive", int2(5, 14), Clockwise),
("Compact Reactor", int2(4, 4), None),
("Smoke Refused", int2(3, 8), None),
("Smoke Refused Beam", int2(6, 8), None),
("Smoke Refused Charge", int2(3, 17), None),
("Autocannon", int2(5, 17), None),
("Iapyx", int2(4, 2), CounterClockwise),
("Iapyx", int2(5, 2), Clockwise),
("not if i see you first", int2(5, 10), None),
("Radiator", int2(4, 2), CounterClockwise),
("Radiator", int2(5, 2), Clockwise),
("Compact Sensor", int2(5, 10), None),
("Fire Control Array", int2(3, 6), Clockwise));
stage.Player(shooter, float2(0, 0), facing: float2(0, 1));

View file

@ -17,14 +17,14 @@ public sealed class StarvedReactor : Scenario
("Cockpit 2x2", int2(2, 6), None),
("Large Drive", int2(1, 0), Reversed),
("Large Drive", int2(3, 0), Reversed),
("Talaria", int2(2, 14), CounterClockwise),
("Talaria", int2(3, 14), Clockwise),
("MoveOnPro", int2(2, 4), None),
("Spectra", int2(1, 8), None),
("Spectra", int2(4, 8), None),
("Iapyx", int2(2, 2), CounterClockwise),
("Iapyx", int2(3, 2), Clockwise),
("not if i see you first", int2(3, 10), None),
("Rugged Drive", int2(2, 14), CounterClockwise),
("Rugged Drive", int2(3, 14), Clockwise),
("Muon Fusion Reactor", int2(2, 4), None),
("Light Laser", int2(1, 8), None),
("Light Laser", int2(4, 8), None),
("Radiator", int2(2, 2), CounterClockwise),
("Radiator", int2(3, 2), Clockwise),
("Compact Sensor", int2(3, 10), None),
("Fire Control Array", int2(1, 6), Clockwise));
stage.Player(starved, float2(0, 0));
stage.Place(stage.Bare("Longinus"), float2(0, 400));

View file

@ -21,15 +21,15 @@ public sealed class WeaponFeel : Scenario
("Cockpit 2x2", int2(4, 6), None),
("Large Drive", int2(3, 0), Reversed),
("Large Drive", int2(5, 0), Reversed),
("Talaria", int2(4, 14), CounterClockwise),
("Talaria", int2(5, 14), Clockwise),
("Core Power", int2(4, 4), None),
("ChargeBlast SG", int2(3, 17), None),
("Rugged Drive", int2(4, 14), CounterClockwise),
("Rugged Drive", int2(5, 14), Clockwise),
("Compact Reactor", int2(4, 4), None),
("Charged Scatter Blaster", int2(3, 17), None),
("Autocannon", int2(5, 17), None),
("FastBlast+-", int2(3, 8), None),
("Iapyx", int2(4, 2), CounterClockwise),
("Iapyx", int2(5, 2), Clockwise),
("not if i see you first", int2(5, 10), None),
("Cell Blaster", int2(3, 8), None),
("Radiator", int2(4, 2), CounterClockwise),
("Radiator", int2(5, 2), Clockwise),
("Compact Sensor", int2(5, 10), None),
("Fire Control Array", int2(3, 6), Clockwise));
stage.Player(shooter, float2(0, 0), facing: float2(0, 1));

View file

@ -24,7 +24,7 @@ using static CultMath.math;
// (to decide whether the pump can keep up this tick). Cut 7 asks for the brownout curve to live on exactly
// the stats the behaviour actually curves (PumpedHeat), but F6 forbade a PowerSupply term on any
// stat a request reads at all, on pain of the exact oscillation Soul measured against the shipped catalog's own
// "OK Disperser" radiator (SOUL_RadiatorRequestDependsOnItsOwnGrantAndOscillates, docs/stats-and-power-cut.md).
// "Heat Pump" radiator (SOUL_RadiatorRequestDependsOnItsOwnGrantAndOscillates, docs/stats-and-power-cut.md).
// The six tests below that authored one were marked Skip rather than deleted or silently reworked to hide the
// gap, naming the conflict as real, scoped work for a future pass rather than a fix a registry correction should
// smuggle in.

View file

@ -121,13 +121,13 @@ public sealed class CatalogRoleTests
AssertRange(autocannon, "Range", false, "barrel");
AssertRange(autocannon, "Penetration", false, "barrel");
var lrm = Design("LRMM72");
var lrm = Design("Long-Range Missile Rack");
Assert.Equal(new[] { "guidance system", "thruster", "warhead" }, Roles(lrm));
AssertRange(lrm, "Damage", false, "warhead");
AssertRange(lrm, "Cooldown", true, "guidance system");
AssertRange(lrm, "LockAngle", false, "guidance system");
var srm = Design("SRMM72");
var srm = Design("Short-Range Missile Rack");
Assert.Equal(new[] { "guidance system", "thruster", "warhead" }, Roles(srm));
AssertRange(srm, "Damage", false, "warhead");
AssertRange(srm, "Cooldown", true, "guidance system");
@ -152,12 +152,12 @@ public sealed class CatalogRoleTests
AssertRange(Design("Small Drive"), "Thrust", false, "nozzle");
// Designs whose non-flat stats named no role are pointed at the role their kind's map gives them.
AssertNamed(Design("DeathCluster"), "Count", "feed mechanism");
AssertNamed(Design("Cluster Cannon"), "Count", "feed mechanism");
AssertNamed(Design("Flak Gun"), "Count", "feed mechanism");
AssertNamed(Design("GT 3K"), "MinRange", "guidance system");
AssertNamed(Design("plight"), "DamageSpread", "focusing array");
AssertNamed(Design("MoveOnPro"), "Modifier", "core");
AssertNamed(Design("MoveOnPro Station Reactor"), "Modifier", "core");
AssertNamed(Design("Guided Missile Launcher"), "MinRange", "guidance system");
AssertNamed(Design("Lightning Projector"), "DamageSpread", "focusing array");
AssertNamed(Design("Muon Fusion Reactor"), "Modifier", "core");
AssertNamed(Design("Muon Fusion Station Reactor"), "Modifier", "core");
// Each seller's means come from its maker's profile; the Pirates are middling and inconsistent.
var profiles = new Dictionary<string, (float Mean, float Dev)>

View file

@ -21,8 +21,8 @@ public sealed partial class RunStartTests
Assert.Equal(4, galaxy.HomeZones.Count);
var player = staged.Player;
var plight = player.Equipment.Single(item => item.Data.Name == "plight");
var small = player.Equipment.Single(item => item.Data.Name == "FastBlast+-");
var plight = player.Equipment.Single(item => item.Data.Name == "Lightning Projector");
var small = player.Equipment.Single(item => item.Data.Name == "Cell Blaster");
Assert.Contains(player.Equipment, item => item.Data.Name == "Fire Control Array");
var groupOf = new System.Func<EquippedItem, int>(item => System.Array.FindIndex(player.WeaponGroups, group => group.items.Contains(item)));
Assert.True(groupOf(plight) >= 0 && groupOf(small) >= 0, "both guns are in a weapon group");

View file

@ -24,14 +24,14 @@ public sealed partial class RunStartTests
// The Duel's guns on a Longinus: the generated Longinus's thrusters (two Large Drive forward, two Talaria on the
// flanks) and power, its Targeting Computer, and the Duel's cockpit, guns, launchers and sensor.
private static ScenarioFit EvLonginus(ScenarioStage stage, string gun = "FastBlast+-", string second = null) => stage.Fit("Longinus",
("Cockpit 2x2", int2(2, 6), ItemRotation.None), ("Core Power", int2(2, 4), ItemRotation.None),
private static ScenarioFit EvLonginus(ScenarioStage stage, string gun = "Cell Blaster", string second = null) => stage.Fit("Longinus",
("Cockpit 2x2", int2(2, 6), ItemRotation.None), ("Compact Reactor", int2(2, 4), ItemRotation.None),
("Large Drive", int2(1, 0), ItemRotation.Reversed), ("Large Drive", int2(3, 0), ItemRotation.Reversed),
("Talaria", int2(2, 14), ItemRotation.CounterClockwise), ("Talaria", int2(3, 14), ItemRotation.Clockwise),
("GT 3K", int2(0, 5), ItemRotation.None), ("GT 3K", int2(5, 5), ItemRotation.None), (gun, int2(1, 8), ItemRotation.None),
(second ?? gun, int2(4, 8), ItemRotation.None), ("Iapyx", int2(2, 2), ItemRotation.CounterClockwise), ("Iapyx", int2(3, 2), ItemRotation.Clockwise),
("not if i see you first", int2(3, 10), ItemRotation.None), ("PotaT+-", int2(1, 6), ItemRotation.None),
("Targeting Computer", int2(1, 7), ItemRotation.None), ("Store-All Plus", int2(2, 8), ItemRotation.None));
("Rugged Drive", int2(2, 14), ItemRotation.CounterClockwise), ("Rugged Drive", int2(3, 14), ItemRotation.Clockwise),
("Guided Missile Launcher", int2(0, 5), ItemRotation.None), ("Guided Missile Launcher", int2(5, 5), ItemRotation.None), (gun, int2(1, 8), ItemRotation.None),
(second ?? gun, int2(4, 8), ItemRotation.None), ("Radiator", int2(2, 2), ItemRotation.CounterClockwise), ("Radiator", int2(3, 2), ItemRotation.Clockwise),
("Compact Sensor", int2(3, 10), ItemRotation.None), ("Capacitor", int2(1, 6), ItemRotation.None),
("Targeting Computer", int2(1, 7), ItemRotation.None), ("Cargo Bay", int2(2, 8), ItemRotation.None));
// The catalog's two generated ships, far apart in the fixture arena, at the fixture seed.
private (Zone arena, Ship longinus, Ship djinni) EvFleet()
@ -349,7 +349,7 @@ public sealed partial class RunStartTests
var settings = _items.GameplaySettings;
var thrusters = longinus.GetBehaviors<Thruster>().Where(t => t.Item.Active.Value).ToList();
var largeDrives = thrusters.Where(t => t.Item.Data.Name == "Large Drive").ToList();
var flanks = thrusters.Where(t => t.Item.Data.Name == "Talaria").ToList();
var flanks = thrusters.Where(t => t.Item.Data.Name == "Rugged Drive").ToList();
Assert.Equal(2, largeDrives.Count);
Assert.Equal(2, flanks.Count);
@ -584,13 +584,13 @@ public sealed partial class RunStartTests
// reactor, cockpit and radiators. What the evasion tests price is this ship's strafing, not whatever the generator
// rolls for it from the galaxy.
private static ScenarioFit EvDjinni(ScenarioStage stage) => stage.Fit("Djinni",
("Cockpit 2x2", int2(6, 3), ItemRotation.None), ("Core Power", int2(6, 11), ItemRotation.None),
("Talaria", int2(6, 0), ItemRotation.Reversed), ("Talaria", int2(5, 1), ItemRotation.Reversed), ("Talaria", int2(7, 1), ItemRotation.Reversed),
("Talaria", int2(4, 4), ItemRotation.CounterClockwise), ("Talaria", int2(4, 11), ItemRotation.CounterClockwise),
("Talaria", int2(9, 4), ItemRotation.Clockwise), ("Talaria", int2(9, 11), ItemRotation.Clockwise),
("Talaria", int2(6, 14), ItemRotation.None),
("Iapyx", int2(1, 4), ItemRotation.Reversed), ("Iapyx", int2(3, 1), ItemRotation.Reversed),
("Iapyx", int2(9, 1), ItemRotation.Reversed), ("Iapyx", int2(11, 4), ItemRotation.Reversed));
("Cockpit 2x2", int2(6, 3), ItemRotation.None), ("Compact Reactor", int2(6, 11), ItemRotation.None),
("Rugged Drive", int2(6, 0), ItemRotation.Reversed), ("Rugged Drive", int2(5, 1), ItemRotation.Reversed), ("Rugged Drive", int2(7, 1), ItemRotation.Reversed),
("Rugged Drive", int2(4, 4), ItemRotation.CounterClockwise), ("Rugged Drive", int2(4, 11), ItemRotation.CounterClockwise),
("Rugged Drive", int2(9, 4), ItemRotation.Clockwise), ("Rugged Drive", int2(9, 11), ItemRotation.Clockwise),
("Rugged Drive", int2(6, 14), ItemRotation.None),
("Radiator", int2(1, 4), ItemRotation.Reversed), ("Radiator", int2(3, 1), ItemRotation.Reversed),
("Radiator", int2(9, 1), ItemRotation.Reversed), ("Radiator", int2(11, 4), ItemRotation.Reversed));
private EvRange EvRangeLaunch()
{
@ -598,9 +598,9 @@ public sealed partial class RunStartTests
var scenario = new Scripted(false, stage =>
{
stage.Player(stage.Bare("Djinni"), float2(-50000, -50000));
gunner = stage.Place(EvLonginus(stage, "FastBlast+-", "ColdFire"), float2(0, 0), facing: float2(0, 1)) as Ship;
gunner = stage.Place(EvLonginus(stage, "Cell Blaster", "Long Laser"), float2(0, 0), facing: float2(0, 1)) as Ship;
target = stage.Place(EvDjinni(stage), float2(0, 200), facing: float2(0, 1)) as Ship;
lasing = stage.Place(EvLonginus(stage, "ColdFire"), float2(0, 400), facing: float2(0, -1)) as Ship;
lasing = stage.Place(EvLonginus(stage, "Long Laser"), float2(0, 400), facing: float2(0, -1)) as Ship;
});
var (_, arena, _, failures) = Launch(scenario, Inputs(() => GalaxySeed));
Assert.True(failures.Count == 0, string.Join("; ", failures));

View file

@ -367,8 +367,8 @@ public sealed partial class RunStartTests
{
("Point Defense Gun", 40f, 80000, 60f, WeaponModifiers.RapidFire, (1.5f, 4f), (1f, 1f), (300f, 550f), (.06f, .025f), (1f, .3f),
(1100f, 1600f), (.4f, .2f), (40f, 15f), (400f, 150f), true, 250, 3f),
("Point Defense Laser", 30f, 110000, 30f, PdDesign("Spectra").WeaponModifiers, (5f, 12f), (1f, 1f), (400f, 750f), (.2f, .1f), (.05f, 0f),
(0f, 0f), (6f, 10f), (300f, 150f), (300f, 100f), false, PdDesign("Spectra").Behaviors.OfType<InstantWeaponData>().Single().MagazineSize, PdDesign("Spectra").Behaviors.OfType<InstantWeaponData>().Single().ReloadTime),
("Point Defense Laser", 30f, 110000, 30f, PdDesign("Light Laser").WeaponModifiers, (5f, 12f), (1f, 1f), (400f, 750f), (.2f, .1f), (.05f, 0f),
(0f, 0f), (6f, 10f), (300f, 150f), (300f, 100f), false, PdDesign("Light Laser").Behaviors.OfType<InstantWeaponData>().Single().MagazineSize, PdDesign("Light Laser").Behaviors.OfType<InstantWeaponData>().Single().ReloadTime),
("Flak Gun", 120f, 180000, 80f, WeaponModifiers.Cluster, (30f, 70f), (6f, 8f), (350f, 800f), (.6f, .35f), (4f, 2f),
(900f, 1300f), (1f, .5f), (300f, 150f), (800f, 300f), true, 40, 4f),
};
@ -449,7 +449,7 @@ public sealed partial class RunStartTests
return FireControl.TrackingRate(range.Gun, range.Gunner);
}
var pd = FireControl.PMount(omega, RateOf("Point Defense Gun"));
var clearPath = FireControl.PMount(omega, RateOf("ClearPath"));
var clearPath = FireControl.PMount(omega, RateOf("Light Machine Gun"));
Assert.True(pd >= .75f, $"the PD gun follows a speed demon: {pd}");
Assert.True(clearPath <= .25f, $"the machine gun does not: {clearPath}");
}
@ -458,7 +458,7 @@ public sealed partial class RunStartTests
[Fact]
public void PlightHasItsRuledShape()
{
var plight = _cache.GetAll<WeaponItemData>().Single(w => w.Name == "plight");
var plight = _cache.GetAll<WeaponItemData>().Single(w => w.Name == "Lightning Projector");
Assert.Equal(1, plight.Shape.Width);
Assert.Equal(2, plight.Shape.Height);
Assert.True(plight.Shape.Cells[0, 0] && plight.Shape.Cells[0, 1], "both cells are occupied");

View file

@ -23,11 +23,11 @@ public sealed class MunitionPartsTests : IDisposable
// both ranged stats. The column names are the retired fields'.
private static readonly (string Design, float ThrustMin, float ThrustMax, float MissileVelocityMin, float MissileVelocityMax, float DodgeFrequency)[] Golden =
{
("GT 3K", 135, 325, 150, 300, 0.25f),
("LRMM72", 400, 600, 200, 300, 0.25f),
("SRMM72", 1600, 2400, 400, 600, 1f),
("pswarm", 500, 2000, 400, 600, 1f),
("scorched void policy", 500, 2000, 400, 600, 1f),
("Guided Missile Launcher", 135, 325, 150, 300, 0.25f),
("Long-Range Missile Rack", 400, 600, 200, 300, 0.25f),
("Short-Range Missile Rack", 1600, 2400, 400, 600, 1f),
("Swarm Rocket Pod", 500, 2000, 400, 600, 1f),
("Incendiary Rocket Pod", 500, 2000, 400, 600, 1f),
};
private static PerformanceStat Flat(float value) => new PerformanceStat { Min = value, Max = value };
@ -208,13 +208,13 @@ public sealed class MunitionPartsTests : IDisposable
[Fact]
public void CatalogLoadRefusesAnIncompleteOrStrayMunitionPart()
{
using (AetheriaStores.Open(Forged<WeaponItemData>(d => d.Name == "GT 3K", _ => { }), registry: TestCatalog.Registry())) { }
using (AetheriaStores.Open(Forged<WeaponItemData>(d => d.Name == "Guided Missile Launcher", _ => { }), registry: TestCatalog.Registry())) { }
foreach (var part in AllParts)
{
var path = Forged<WeaponItemData>(d => d.Name == "GT 3K", d => d.Behaviors.RemoveAll(b => b.GetType() == part));
var path = Forged<WeaponItemData>(d => d.Name == "Guided Missile Launcher", d => d.Behaviors.RemoveAll(b => b.GetType() == part));
var refusal = Assert.ThrowsAny<Exception>(() => AetheriaStores.Open(path, registry: TestCatalog.Registry()));
Assert.Contains("GT 3K", refusal.ToString());
Assert.Contains("Guided Missile Launcher", refusal.ToString());
Assert.Contains(part.Name, refusal.ToString());
}
@ -245,13 +245,13 @@ public sealed class MunitionPartsTests : IDisposable
// The Longinus's own gear: two drives, a core, a cockpit and a sensor, so the ship has thrusters, a sensor and a plume
// for any munition contribution to be seen against.
private static readonly (string Name, int X, int Y)[] ShipGear =
{ ("Large Drive", 1, 0), ("Large Drive", 3, 0), ("Core Power", 2, 4), ("Cockpit 2x2", 2, 6), ("not if i see you first", 3, 10) };
{ ("Large Drive", 1, 0), ("Large Drive", 3, 0), ("Compact Reactor", 2, 4), ("Cockpit 2x2", 2, 6), ("Compact Sensor", 3, 10) };
// A GT 3K fitted to a Longinus launcher hardpoint beside that gear, its lot's thruster role at the given quality.
private static EquippedItem Fit(CultCache cache, float thrusterQuality, out Ship ship)
{
var hull = cache.GetByName<HullData>("Longinus");
var gt = cache.GetByName<WeaponItemData>("GT 3K");
var gt = cache.GetByName<WeaponItemData>("Guided Missile Launcher");
var hardpoint = hull.Hardpoints.First(h => h.Type == HardpointType.Launcher && h.IsFilledBy(gt));
var settings = RestoredHullsTests.Settings();
var ledger = new ProvenanceLedger();
@ -269,7 +269,7 @@ public sealed class MunitionPartsTests : IDisposable
zone.Admit(ship, piloted: false);
// 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");
var item = ship.Equipment.Single(e => e.Data.Name == "Guided Missile Launcher");
foreach (var cell in item.InsetShape.Coordinates) ship.Temperature[cell.x, cell.y] = gt.OptimalTemperature;
item.UpdatePerformance();
item.UpdatePerformance();
@ -280,7 +280,7 @@ public sealed class MunitionPartsTests : IDisposable
public void PartsReadThroughTheItem()
{
using var cache = RestoredHullsTests.OpenCatalog();
var design = cache.GetByName<WeaponItemData>("GT 3K");
var design = cache.GetByName<WeaponItemData>("Guided Missile Launcher");
var poor = Fit(cache, .2f, out var poorShip);
var good = Fit(cache, .9f, out _);
@ -324,7 +324,7 @@ public sealed class MunitionPartsTests : IDisposable
public void ShipSumsIgnoreTheFittedMunitionParts()
{
using var cache = RestoredHullsTests.OpenCatalog();
var design = cache.GetByName<WeaponItemData>("GT 3K");
var design = cache.GetByName<WeaponItemData>("Guided Missile Launcher");
var part = Part<MunitionThrusterData>(design);
var item = Fit(cache, .5f, out var ship);
for (var i = 0; i < 5; i++) ship.Update(.1f);

View file

@ -79,13 +79,13 @@ public sealed class PiratesFactionCommandTests : IDisposable
var expected = new (string Design, string Name, string Description)[]
{
("Autocannon", "🫳🔫", "Serial number filed off. Still shoots."),
("Earp", "🪦🤠", "The previous owner had no further use for it."),
("FastBlast+-", "🧾🚫", "Warranty void where prohibited, which is everywhere."),
("6k Shooter", "🎨🙈", "The logo underneath is somebody else's problem."),
("scorched void policy", "🔥", "Turns out we did start the fire after all."),
("Long Slug Rifle", "🪦🤠", "The previous owner had no further use for it."),
("Cell Blaster", "🧾🚫", "Warranty void where prohibited, which is everywhere."),
("Slug Rifle", "🎨🙈", "The logo underneath is somebody else's problem."),
("Incendiary Rocket Pod", "🔥", "Turns out we did start the fire after all."),
("Targeting Computer", "👀🎯", "Somebody else's eyes. They still work."),
("Small Drive", "🔑🏃💨", "Hotwired. Do not ask about the ignition."),
("Store-All Plus", "📦🤫", "Contents not as declared."),
("Cargo Bay", "📦🤫", "Contents not as declared."),
};
Assert.Equal(expected.Select(e => e.Name).OrderBy(n => n, StringComparer.Ordinal), products.Select(p => p.Name).OrderBy(n => n, StringComparer.Ordinal));
foreach (var (designName, name, description) in expected)

View file

@ -306,7 +306,7 @@ public sealed class PowerCurveTests : IDisposable
// --- F6 (docs/stats-and-power-cut.md, Soul pass 2026-09-19) named PumpedHeat as a Radiator request field
// --- (PowerRequest's own early-out gate reads it, the exact shape Soul reproduced against the shipped
// --- catalog's "OK Disperser": SOUL_RadiatorRequestDependsOnItsOwnGrantAndOscillates) and, at the time,
// --- catalog's "Heat Pump": SOUL_RadiatorRequestDependsOnItsOwnGrantAndOscillates) and, at the time,
// --- refused a PowerSupply term there for exactly that reason. The nominal-request ruling above is what
// --- actually fixes the oscillation (the request no longer reads the live grant at all), so this shape is
// --- accepted now -- the six shipped records this ruling exists to make legal again include exactly this

View file

@ -952,7 +952,7 @@ public sealed class RestoredHullsTests
// Every restored thruster's particle effect is Thruster 1.prefab, by the legacy record (soul-dump.txt).
var thruster1Guid = GuidOf("Assets/Content/Prefabs/Thrusters/Thruster 1.prefab");
var restoredThrusterNames = new[] { "deep space burnout", "Large Drive", "Victoire", "Small Drive", "Talaria", "RevvITup 2.0", "Medium Drive" };
var restoredThrusterNames = new[] { "Burn Drive", "Large Drive", "Racing Drive", "Small Drive", "Rugged Drive", "High-Thrust Drive", "Medium Drive" };
foreach (var name in restoredThrusterNames)
{
var design = cache.GetAll<GearData>().First(g => g.Name == name);

View file

@ -13,13 +13,13 @@ using Xunit;
// oracle, since the command produced it.
public sealed class RolesBackfillCommandTests : IDisposable
{
private static readonly string[] Flattened = { "Autocannon", "LRMM72", "SRMM72", "Mine Launcher", "Large Drive", "Small Drive" };
private static readonly string[] Flattened = { "Autocannon", "Long-Range Missile Rack", "Short-Range Missile Rack", "Mine Launcher", "Large Drive", "Small Drive" };
// Designs that shipped with non-flat stats whose Quality term named no role; the field is the stat to unname.
private static readonly (string Design, string Field)[] Unnamed =
{
("DeathCluster", "Count"), ("Flak Gun", "Count"), ("GT 3K", "MinRange"), ("plight", "DamageSpread"),
("MoveOnPro", "Modifier"), ("MoveOnPro Station Reactor", "Modifier"),
("Cluster Cannon", "Count"), ("Flak Gun", "Count"), ("Guided Missile Launcher", "MinRange"), ("Lightning Projector", "DamageSpread"),
("Muon Fusion Reactor", "Modifier"), ("Muon Fusion Station Reactor", "Modifier"),
};
private readonly string _root = Path.Combine(Path.GetTempPath(), "roles-backfill-" + Guid.NewGuid().ToString("N"));
@ -165,7 +165,7 @@ public sealed class RolesBackfillCommandTests : IDisposable
static Dictionary<string, float> Exponents(EquippableItemData d) => CatalogRoleTests.StatsOf(d)
.SelectMany(s => s.Stat.Terms.Where(t => t.Source == StatSource.Quality && !string.IsNullOrEmpty(t.Role)).Select(t => (s.Name, t.Exponent)))
.ToDictionary(x => x.Name, x => x.Exponent);
var designs = new[] { "Autocannon", "LRMM72" };
var designs = new[] { "Autocannon", "Long-Range Missile Rack" };
Dictionary<string, Dictionary<string, float>> shipped;
Dictionary<string, Dictionary<string, float>> Read(EquippableItemData[] all) => all.Where(d => designs.Contains(d.Name)).ToDictionary(d => d.Name, Exponents);
using (var catalog = RestoredHullsTests.OpenCatalog()) shipped = Read(catalog.GetAll<EquippableItemData>().ToArray());

View file

@ -445,7 +445,7 @@ public sealed partial class RunStartTests : IDisposable
}
// The sold hardpoint gear the generator gives no home today: the production rule (LoadoutGenerator.HasHome over the hulls a
// product sells). The Smoke Test Hull, which no product sells, gives ChargeBlast SG and ChargeBlast+- no home; authoring a
// product sells). The Smoke Test Hull, which no product sells, gives Charged Scatter Blaster and Charged Blaster no home; authoring a
// sold hull that takes one shows up here as a changed list.
[Fact]
public void TheSoldHardpointGearWithNoHomeToday()
@ -456,7 +456,7 @@ public sealed partial class RunStartTests : IDisposable
.Where(design => sold.Contains(_cache.RefOf(design).Key) && design.Price > 0)
.Where(design => !LoadoutGenerator.HasHome(design, hulls))
.Select(design => design.Name).OrderBy(name => name, StringComparer.Ordinal).ToArray();
Assert.Equal(new[] { "CShot RainbowLite Lazer", "ChargeBlast SG", "ChargeBlast+-", "OK Disperser" }, homeless);
Assert.Equal(new[] { "Charged Blaster", "Charged Scatter Blaster", "Heat Pump", "Heavy Beam Laser" }, homeless);
}
// A sold weapon can be generated onto an NPC, whose combat state samples its damage at range, so every weapon a

View file

@ -537,7 +537,7 @@ public sealed partial class RunStartTests
runs.Add(Stage(Arena(false), new Scripted(false, stage =>
{
var ship = stage.Player(stage.Fit("Djinni", ("Census Fitted", int2(1, 6), ItemRotation.None), ("Store-All Plus", int2(3, 6), ItemRotation.None)), float2(0, 0));
var ship = stage.Player(stage.Fit("Djinni", ("Census Fitted", int2(1, 6), ItemRotation.None), ("Cargo Bay", int2(3, 6), ItemRotation.None)), float2(0, 0));
stage.Cargo(ship, "Census Carried");
})));
Assert.Empty(UnsoldAndUnplaced(runs));

View file

@ -37,7 +37,7 @@ public sealed class SmokeHullCommandTests : IDisposable
var hulls = db.Cache.GetAll<HullData>().Where(h => h.Name == HullName).ToArray();
var keys = hulls.Select(h => db.Cache.RefOf(h).Key).ToArray();
var products = db.Cache.GetAll<FactionProductData>().Count(p => keys.Any(k => p.Design.Key.Equals(k)));
var fitted = new[] { "ChargeBlast SG", "Autocannon" }
var fitted = new[] { "Charged Scatter Blaster", "Autocannon" }
.Select(name => db.Cache.GetAll<EquippableItemData>().Single(d => d.Name == name)).ToArray();
return (hulls, db.Cache.GetAll<HullData>().Single(h => h.Name == "Longinus"), fitted, products);
}

View file

@ -23,7 +23,7 @@ public sealed partial class RunStartTests
Assert.Equal("Smoke Test Hull", _items.GetData(player.EquippedHull.EquippableItem).Name);
EquippedItem Mount(string design) => Assert.Single(WeaponMounts(player), item => _items.GetData(item.EquippableItem).Name == design);
var charge = Mount("ChargeBlast SG");
var charge = Mount("Charged Scatter Blaster");
var autocannon = Mount("Autocannon");
Assert.Equal((HardpointType.Energy, 2, 2), (charge.Hardpoint.Type, charge.Hardpoint.Shape.Width, charge.Hardpoint.Shape.Height));
Assert.Equal((HardpointType.Ballistic, 2, 2), (autocannon.Hardpoint.Type, autocannon.Hardpoint.Shape.Width, autocannon.Hardpoint.Shape.Height));

View file

@ -51,7 +51,7 @@ public sealed class SmokeRoundsCommandTests : IDisposable
var smoke = db.Cache.GetAll<WeaponItemData>().Where(w => Names.Contains(w.Name)).ToArray();
var keys = smoke.Select(w => db.Cache.RefOf(w).Key).ToArray();
var products = db.Cache.GetAll<FactionProductData>().Count(p => keys.Any(k => p.Design.Key.Equals(k)));
return (smoke, db.Cache.GetAll<WeaponItemData>().Single(w => w.Name == "Spectra"), db.Cache.GetAll<WeaponItemData>().Single(w => w.Name == "ChargeBlast SG"), products);
return (smoke, db.Cache.GetAll<WeaponItemData>().Single(w => w.Name == "Light Laser"), db.Cache.GetAll<WeaponItemData>().Single(w => w.Name == "Charged Scatter Blaster"), products);
}
finally { db.Cache.Dispose(); }
}

View file

@ -34,7 +34,7 @@ public sealed partial class RunStartTests
var proximity = Carried(player, "Smoke Proximity");
var delayed = Carried(player, "Smoke Delayed");
var direct = Carried(player, "DeathCluster");
var direct = Carried(player, "Cluster Cannon");
Assert.Null(player.Target.Value.Entity);
// The bare hull is on the initial aim line, ahead, and inside every weapon mount's arc.

View file

@ -24,7 +24,7 @@ public sealed partial class RunStartTests
// in this arena, so a fused weapon that does not is not a harness that cannot fire. A fused round flies slowly enough
// to be in the air when the direct weapon kills the fragile hull (check A.3) and bursts on the first hull on the aim line.
[Theory]
[InlineData("DeathCluster")]
[InlineData("Cluster Cannon")]
[InlineData("Smoke Proximity")]
[InlineData("Smoke Delayed")]
public void EveryWeaponAboardFiresInTheSteppedFusedRoundsArena(string design)
@ -42,7 +42,7 @@ public sealed partial class RunStartTests
for (var i = 0; i < 60; i++) arena.Update(SteppedDt);
Assert.True(fired.Count > 0, $"{design} fired nothing in 3 s; the ship's reactor is {(player.PowerBus.TotalGeneration > 0f ? "running" : "down")}");
if (design == "DeathCluster") return;
if (design == "Cluster Cannon") return;
var (at, burst) = committed.First();
Assert.Equal(ShotResult.Burst, burst.Result);
Assert.True(burst.HasBurstPoint);
@ -71,7 +71,7 @@ public sealed partial class RunStartTests
});
WeaponOf(proximity).Activate();
WeaponOf(Carried(player, "DeathCluster")).Activate();
WeaponOf(Carried(player, "Cluster Cannon")).Activate();
float? deadAt = null;
for (var i = 0; i < 120 && landed == null; i++)
{

View file

@ -317,7 +317,7 @@ public sealed partial class RunStartTests
for (var tick = 0; tick < 10; tick++) player.Update(AllocDt);
var thrusters = player.GetBehaviors<Thruster>().Where(t => t.Item.Active.Value).ToArray();
var drives = thrusters.Where(t => t.Item.Data.Name == "Large Drive").ToArray();
var flanks = thrusters.Where(t => t.Item.Data.Name == "Talaria").ToArray();
var flanks = thrusters.Where(t => t.Item.Data.Name == "Rugged Drive").ToArray();
Assert.Equal(2, drives.Length);
Assert.Equal(2, flanks.Length);
float Clockwise(IEnumerable<Thruster> of) => of.Sum(t => max(t.Column(t.Thrust).z, 0f));

View file

@ -406,7 +406,7 @@ public static class Program
private static (float Mean, float Dev, string Basis) AuthorProductRole(AetherDb db, FactionProductData product, string designName, string role)
{
var maker = db.Cache.Get(product.Manufacturer)?.Name;
if (designName == "Arctica" && maker == "Alakrita" && role == "fins")
if (designName == "Adaptive Radiator" && maker == "Alakrita" && role == "fins")
return (.78f, .07f, "lore: Alakrita brands on heat efficiency (item-provenance-target.md)");
var hash = StableHash($"{product.Name}|{role}");
@ -1175,10 +1175,10 @@ public static class Program
var newDesigns = new (GearData Design, string ProductName, Faction Maker, string ProductDescription, (string Role, float Mean, float Dev)[] Roles)[]
{
(targetingComputer, "LockOn", FactionByShortName("NiteLife"),
"Keeps the lights on your target. (new text)",
"Keeps the lights on your target.",
new[] { ("processor", .55f, .15f), ("array", .5f, .16f) }),
(fireControlArray, "LockOn Pro", FactionByShortName("NiteLife"),
"Same promise, sharper lock. (new text)",
"Same promise, sharper lock.",
new[] { ("processor", .72f, .12f), ("array", .68f, .13f) }),
};
@ -1191,17 +1191,17 @@ public static class Program
// outside this cut's brief).
var existingDesigns = new (string DesignName, string ProductName, Faction Maker, string ProductDescription, (string Role, float Mean, float Dev)[] Roles)[]
{
("plight", "DragOnBreath", FactionByShortName("Lucent"),
"The subsidiary plight's own description already namechecks: DragOnBreath, a Lucent Media property.",
("Lightning Projector", "DragOnBreath", FactionByShortName("Lucent"),
"Chain lightning has your enemies chain smoking while you enjoy a relaxing DragOnBreath vapepop, now available in 17! flavours (manufactured by DragOnBreath, a subsidary of Lucent Media)",
new[] { ("focusing array", .7f, .13f), ("power coupling", .55f, .15f) }),
("pswarm", "Leonid", FactionByShortName("AU"),
("Swarm Rocket Pod", "Leonid", FactionByShortName("AU"),
"A rain of pain that falls mainly on space planes.",
new[] { ("guidance system", .65f, .14f), ("thruster", .63f, .15f), ("warhead", .7f, .13f) }),
("Core Power", "Steadfast", FactionByShortName("R&D"),
"Rated for continuous operation. \"Continuous\" does not imply \"uninterrupted.\" (new text)",
("Compact Reactor", "Steadfast", FactionByShortName("R&D"),
"It gets the job done, but that's all. Rated for continuous operation. \"Continuous\" does not imply \"uninterrupted.\"",
new[] { ("core", .5f, .12f), ("regulator", .5f, .12f) }),
("Large Drive", "True North", FactionByShortName("Lightsail"),
"Gets your cargo there. Getting you there is your problem. (new text)",
"Gets your cargo there. Getting you there is your problem.",
Array.Empty<(string, float, float)>()),
};
@ -1313,16 +1313,16 @@ public static class Program
var newProducts = new (GearData Design, string ProductName, Faction Maker, string ProductDescription, (string Role, float Mean, float Dev)[] Roles)[]
{
(targetingComputer, "Panopticon", FactionByShortName("Finch"),
"Sees everything, judges nothing. Well, mostly nothing. (new text)",
"Sees everything, judges nothing. Well, mostly nothing.",
new[] { ("processor", .5f, .13f), ("array", .58f, .12f) }),
(fireControlArray, "Panopticon Prime", FactionByShortName("Finch"),
"The upgrade nobody at Finch will admit they needed until they had it. (new text)",
"The upgrade nobody at Finch will admit they needed until they had it.",
new[] { ("processor", .68f, .11f), ("array", .75f, .10f) }),
(targetingComputer, "ClapBack", FactionByShortName("Lucent"),
"Your target won't clock it until the killcam. (new text)",
"Your target won't clock it until the killcam.",
new[] { ("processor", .6f, .16f), ("array", .48f, .15f) }),
(fireControlArray, "ClapBack Ultra", FactionByShortName("Lucent"),
"Now with main-character energy built in. (new text)",
"Now with main-character energy built in.",
new[] { ("processor", .78f, .14f), ("array", .65f, .13f) }),
};
@ -1528,7 +1528,7 @@ public static class Program
static void Set(PerformanceStat stat, float min, float max) { stat.Min = min; stat.Max = max; }
static void Track(WeaponData data, float rate) => data.Tracking = new PerformanceStat { Min = rate, Max = rate, Terms = new List<StatTerm>() };
var gun = Copy(Template("ClearPath"), designNames[0], "Close-in defence gun: a hose of light rounds.", 40f, 80000, 60f, 1, 1, WeaponModifiers.RapidFire);
var gun = Copy(Template("Light Machine Gun"), designNames[0], "Close-in defence gun: a hose of light rounds.", 40f, 80000, 60f, 1, 1, WeaponModifiers.RapidFire);
var gunData = gun.Behaviors.OfType<InstantWeaponData>().Single();
Set(gunData.Damage, 1.5f, 4f); Set(gunData.Range, 300f, 550f); Set(gunData.MinRange, 0f, 0f);
Set(gunData.Cooldown, .06f, .025f); Set(gunData.Count, 1f, 1f); Set(gunData.Spread, 1f, .3f);
@ -1536,14 +1536,14 @@ public static class Program
gunData.AmmoType = db.Cache.RefOf(ammunition); gunData.MagazineSize = 250; gunData.ReloadTime = 3f;
Track(gunData, 40f);
var laser = Copy(Template("Spectra"), designNames[1], "Close-in defence beam: quick, light, instant.", 30f, 110000, 30f, 1, 1, Template("Spectra").WeaponModifiers);
var laser = Copy(Template("Light Laser"), designNames[1], "Close-in defence beam: quick, light, instant.", 30f, 110000, 30f, 1, 1, Template("Light Laser").WeaponModifiers);
var laserData = laser.Behaviors.OfType<InstantWeaponData>().Single();
Set(laserData.Damage, 5f, 12f); Set(laserData.Range, 400f, 750f); Set(laserData.MinRange, 0f, 0f);
Set(laserData.Cooldown, .2f, .1f); Set(laserData.Count, 1f, 1f); Set(laserData.Spread, .05f, 0f);
Set(laserData.Velocity, 0f, 0f); Set(laserData.Energy, 6f, 10f); Set(laserData.Heat, 300f, 150f); Set(laserData.Visibility, 300f, 100f);
Track(laserData, 40f);
var flak = Copy(Template("DeathCluster"), designNames[2], "Small flak gun: a short-range pellet volley.", 120f, 180000, 80f, 1, 2, WeaponModifiers.Cluster);
var flak = Copy(Template("Cluster Cannon"), designNames[2], "Small flak gun: a short-range pellet volley.", 120f, 180000, 80f, 1, 2, WeaponModifiers.Cluster);
var flakData = flak.Behaviors.OfType<InstantWeaponData>().Single();
Set(flakData.Damage, 30f, 70f); Set(flakData.Count, 6f, 8f); Set(flakData.Range, 350f, 800f); Set(flakData.MinRange, 0f, 0f);
Set(flakData.Cooldown, .6f, .35f); Set(flakData.Spread, 4f, 2f); Set(flakData.Velocity, 900f, 1300f);
@ -1714,11 +1714,11 @@ public static class Program
}
static PerformanceStat Fixed(float value) => new PerformanceStat { Min = value, Max = value, Terms = new List<StatTerm>() };
var proximity = Copy("Spectra", names[0], "A Spectra that bursts by proximity, blast 8. For scenarios; no one builds it.", WeaponFuse.Proximity, 8f);
var delayed = Copy("Spectra", names[1], "A Spectra that bursts after two cells of metal, blast 4. For scenarios; no one builds it.", WeaponFuse.Delayed, 4f);
var refused = Copy("Spectra", names[2], "A Spectra whose blast is wider than its reach, so it never fires. For scenarios; no one builds it.", WeaponFuse.Proximity, 30f);
var charge = Copy("ChargeBlast SG", names[4], "A ChargeBlast SG whose blast is wider than its reach, so it never charges. For scenarios; no one builds it.", WeaponFuse.Proximity, 30f);
var beam = Copy("Spectra", names[3], "A constant beam whose blast is wider than its reach, so it never starts. For scenarios; no one builds it.", WeaponFuse.Proximity, 30f);
var proximity = Copy("Light Laser", names[0], "A Spectra that bursts by proximity, blast 8. For scenarios; no one builds it.", WeaponFuse.Proximity, 8f);
var delayed = Copy("Light Laser", names[1], "A Spectra that bursts after two cells of metal, blast 4. For scenarios; no one builds it.", WeaponFuse.Delayed, 4f);
var refused = Copy("Light Laser", names[2], "A Spectra whose blast is wider than its reach, so it never fires. For scenarios; no one builds it.", WeaponFuse.Proximity, 30f);
var charge = Copy("Charged Scatter Blaster", names[4], "A ChargeBlast SG whose blast is wider than its reach, so it never charges. For scenarios; no one builds it.", WeaponFuse.Proximity, 30f);
var beam = Copy("Light Laser", names[3], "A constant beam whose blast is wider than its reach, so it never starts. For scenarios; no one builds it.", WeaponFuse.Proximity, 30f);
// The Smoke Test Hull carries one 2x2 reactor. A Spectra's 20-40 energy a shot at its cadence is more than that reactor makes,
// so two of them overload it, it overheats and shuts down within a second, and nothing aboard fires again (Fused Rounds,
@ -1888,8 +1888,8 @@ public static class Program
// no non-flat stat reads; DeathCluster, Flak Gun, GT 3K, plight and the two MoveOnPros because each had a non-flat stat
// whose Quality term named no role (CB-R1: each non-flat stat reads exactly one declared role). Idempotent: a design with
// no flat mapped stat and no unnamed one is left alone, a product with a role is left alone. Dry run unless passed "apply".
private static readonly string[] BackfillDesigns = { "Autocannon", "LRMM72", "SRMM72", "Mine Launcher", "Large Drive", "Small Drive",
"DeathCluster", "Flak Gun", "GT 3K", "plight", "MoveOnPro", "MoveOnPro Station Reactor" };
private static readonly string[] BackfillDesigns = { "Autocannon", "Long-Range Missile Rack", "Short-Range Missile Rack", "Mine Launcher", "Large Drive", "Small Drive",
"Cluster Cannon", "Flak Gun", "Guided Missile Launcher", "Lightning Projector", "Muon Fusion Reactor", "Muon Fusion Station Reactor" };
// Stats the backfill names but never ranges: a shot count is whole, and which way a launcher's MinRange should fall is
// each design's own call (GT 3K authors it as a cost already).
@ -2053,13 +2053,13 @@ public static class Program
var rebrands = new (string Design, string Name, string Description)[]
{
("Autocannon", "\U0001FAF3\U0001F52B", "Serial number filed off. Still shoots."),
("Earp", "\U0001FAA6\U0001F920", "The previous owner had no further use for it."),
("FastBlast+-", "\U0001F9FE\U0001F6AB", "Warranty void where prohibited, which is everywhere."),
("6k Shooter", "\U0001F3A8\U0001F648", "The logo underneath is somebody else's problem."),
("scorched void policy", "\U0001F525", "Turns out we did start the fire after all."),
("Long Slug Rifle", "\U0001FAA6\U0001F920", "The previous owner had no further use for it."),
("Cell Blaster", "\U0001F9FE\U0001F6AB", "Warranty void where prohibited, which is everywhere."),
("Slug Rifle", "\U0001F3A8\U0001F648", "The logo underneath is somebody else's problem."),
("Incendiary Rocket Pod", "\U0001F525", "Turns out we did start the fire after all."),
("Targeting Computer", "\U0001F440\U0001F3AF", "Somebody else's eyes. They still work."),
("Small Drive", "\U0001F511\U0001F3C3\U0001F4A8", "Hotwired. Do not ask about the ignition."),
("Store-All Plus", "\U0001F4E6\U0001F92B", "Contents not as declared."),
("Cargo Bay", "\U0001F4E6\U0001F92B", "Contents not as declared."),
};
var products = rebrands.Select(r =>
@ -2365,7 +2365,7 @@ public static class Program
// sells (rulings catalog-grows-generic-designs-branded-products, kitchen-sink-content, designs-are-tech-nodes). A
// Renames row renames the design found under its old name and gives it the functional text; a Brands row renames the
// maker's same-named product and sets its text and the design's functional text; ProductTexts sets the rest; every
// shipped product text ending in the authoring note " (new text)" loses it. Dry run unless passed "apply".
// shipped product text ending in the authoring note loses it. Dry run unless passed "apply".
public static int GenericDesigns(bool apply, string root = null)
{
const string AuthoringNote = " (new text)";