Scenarios: Lock On (seed 113), a piloted hostile that closes from out of sight and locks the player

The hostile starts 4000 m ahead with no track of the player; stepped headlessly it
sees the player at tick 81 and paints a Track lock at tick 83. LockOnSituation pins
the staging, the absence of a paint at Update(0), and the lock's bearing and timing.
LockOn.cs.meta is provisional until the Unity compile on Starfire writes its own.
Builds: yes (not yet run; verification follows).

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
This commit is contained in:
Meta Vens 2026-10-13 19:13:59 +02:00
commit 05b17ba43a
4 changed files with 98 additions and 1 deletions

View file

@ -0,0 +1,43 @@
using static CultMath.math;
using static ItemRotation;
public sealed class LockOn : Scenario
{
public override string Name => "Lock On";
public override string Brief => "A hostile closes from out of sight, finds you and locks. Verify: no warning at first; once it locks, one " +
"indicator appears toward it and tightens as the lock grows; break line of sight or range and it vanishes; " +
"your own ping shows no incoming paint on its side, only the lock does.";
public override uint Seed => 113;
public override bool Ambient => false;
// The hostile starts far beyond the player's sight and the hostile's own, 4000 m ahead facing the player. Stepping the
// arena headlessly, it closes to about 3000 m, sees the player after some eight seconds, and locks two ticks later;
// at Duel's 900 m (and at 600 m) it sees and locks within a second.
public static readonly CultMath.float2 HostileAt = float2(0, 4000);
public override Galaxy Generate(GalaxyStage stage) => stage.Prelude(DemoTerminus.Cast);
public override void Stage(ScenarioStage stage)
{
var fighter = 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),
("Fire Control Array", int2(1, 6), Clockwise),
("Store-All Plus", int2(2, 8), None));
stage.Player(fighter, float2(0, 0), facing: float2(0, 1));
stage.Place(fighter, HostileAt, facing: float2(0, -1), stance: ScenarioStance.Hostile, piloted: true);
}
}

View file

@ -0,0 +1,11 @@
fileFormatVersion: 2
guid: 3f0b6d2a9c7e4a1b8d5e2c6f7a9b0c14
MonoImporter:
externalObjects: {}
serializedVersion: 2
defaultReferences: []
executionOrder: 0
icon: {instanceID: 0}
userData:
assetBundleName:
assetBundleVariant:

View file

@ -9,6 +9,6 @@ public static class Scenarios
public static readonly Scenario[] Tests =
{
new DjinniShakedown(), new StarvedReactor(), new Arcs(), new Duel(), new LauncherAngles(), new WeaponFeel(), new FusedRounds(), new RefusedRounds(), new AiFusedDiscipline(), new LongHaul(), new Pursuit(), new Crossing(), new Belt()
new DjinniShakedown(), new StarvedReactor(), new Arcs(), new Duel(), new LauncherAngles(), new WeaponFeel(), new FusedRounds(), new RefusedRounds(), new AiFusedDiscipline(), new LongHaul(), new Pursuit(), new Crossing(), new Belt(), new LockOn()
};
}