Staged Approach: the pilot starts knowing its anchor, through the sensors' own info state (ruling stage-states-pilot-knowledge)
Co-Authored-By: Claude Sonnet 5.5 <noreply@anthropic.com>
This commit is contained in:
parent
63e71a1f30
commit
d5d94fb483
3 changed files with 71 additions and 1 deletions
|
|
@ -55,6 +55,12 @@ public static class RunStart
|
|||
player.SetIff(placed.Entity, hostile);
|
||||
arena.Admit(placed.Entity, placed.Piloted, placed.Task);
|
||||
}
|
||||
|
||||
// A start state includes what a pilot knows (ruling stage-states-pilot-knowledge): its anchor is tracked from the first
|
||||
// step, by the sensors' own path (info gathered past the detection threshold), so they can lose it like any track.
|
||||
foreach (var placed in stage.Placed)
|
||||
if (placed.Knows != null && placed.Piloted)
|
||||
placed.Entity.EntityInfoGathered[placed.Knows] = (itemManager.GameplaySettings.TargetDetectionInfoThreshold + 1f) / 2f;
|
||||
return new Staged { Player = player, Credits = stage.Credits, Entities = stage.Placed.Select(placed => placed.Entity).ToList() };
|
||||
}
|
||||
|
||||
|
|
|
|||
|
|
@ -50,6 +50,9 @@ public sealed class ScenarioStage
|
|||
public ScenarioStance Stance;
|
||||
public bool Piloted;
|
||||
public AgentTask Task;
|
||||
// What the pilot already knows at the start: an entity its sensors hold a track of (Approach). Seeded through the
|
||||
// sensors' own state at admission, so they may lose it honestly.
|
||||
public Entity Knows;
|
||||
}
|
||||
|
||||
// A hull fitted slot by slot: each slot a design or a product, the hull cell it goes in, and its rotation. A name is
|
||||
|
|
@ -137,7 +140,7 @@ public sealed class ScenarioStage
|
|||
}
|
||||
|
||||
// The task a piloted entity starts on: it closes on the target and holds there (the flight's follow task, standoff
|
||||
// nothing), in place of the patrol circuit the zone would draw for it. A check that rests on where a pilot goes states
|
||||
// nothing), in place of the patrol circuit the zone would draw for it. The pilot starts knowing it (RunStart seeds a sensor track). A check that rests on where a pilot goes states
|
||||
// it here, so the pilot's course is the scenario's and not a draw. An entity that is not placed and piloted, or a
|
||||
// target that is not placed, is a failure.
|
||||
public void Approach(Entity entity, Entity target)
|
||||
|
|
@ -146,6 +149,7 @@ public sealed class ScenarioStage
|
|||
if (placement == null || !placement.Piloted) { _failures.Add($"approach: {entity?.Name ?? "no entity"} is not a placed, piloted ship"); return; }
|
||||
if (target == null) { _failures.Add("approach: no target to close on"); return; }
|
||||
placement.Task = new FollowTask { Anchor = PilotView.Handle(target), Standoff = 0f };
|
||||
placement.Knows = target;
|
||||
}
|
||||
|
||||
// Items in the entity's first cargo bay, one per name. A name is an equippable or consumable design (open: the stage
|
||||
|
|
|
|||
60
tests/Aetheria.Shared.Tests/ApproachKnowledgeTests.cs
Normal file
60
tests/Aetheria.Shared.Tests/ApproachKnowledgeTests.cs
Normal file
|
|
@ -0,0 +1,60 @@
|
|||
using System.Linq;
|
||||
using CultMath;
|
||||
using Xunit;
|
||||
using static CultMath.math;
|
||||
using float2 = CultMath.float2;
|
||||
using float3 = CultMath.float3;
|
||||
|
||||
// A staged Approach states what its pilot already knows (ruling stage-states-pilot-knowledge): the anchor is a sensor
|
||||
// track from the first step, and the pilot follows it only as long as the sensors keep it.
|
||||
public sealed partial class RunStartTests
|
||||
{
|
||||
private (Zone arena, Ship east, Ship west) StagedApproach()
|
||||
{
|
||||
Ship east = null, west = null;
|
||||
var (_, arena, _, failures) = Launch(new Scripted(false, stage =>
|
||||
{
|
||||
stage.Player(stage.Bare("Djinni"), float2(-50000, -50000));
|
||||
east = stage.Place(EvLonginus(stage), float2(450, 0), facing: float2(-1, 0), piloted: true) as Ship;
|
||||
west = stage.Place(EvLonginus(stage), float2(-450, 0), facing: float2(1, 0), piloted: true) as Ship;
|
||||
stage.Approach(east, west);
|
||||
}));
|
||||
Assert.True(failures.Count == 0, string.Join("; ", failures));
|
||||
return (arena, east, west);
|
||||
}
|
||||
|
||||
[Fact]
|
||||
public void AStagedApproachFollowerClosesOnItsAnchorFromTheFirstStep()
|
||||
{
|
||||
var (arena, east, west) = StagedApproach();
|
||||
var view = arena.Agents.Single(a => a.Ship == east).View;
|
||||
var startGap = east.Position.x - west.Position.x;
|
||||
|
||||
arena.Update(1f / 60f);
|
||||
arena.Update(1f / 60f);
|
||||
|
||||
Assert.NotNull(view.TrackOf(east, PilotView.Handle(west)));
|
||||
Assert.True(east.Velocity.x < -.5f, $"the follower thrusts toward its anchor from the first steps (vx {east.Velocity.x})");
|
||||
for (var i = 0; i < 120; i++) arena.Update(1f / 60f);
|
||||
Assert.True(east.Position.x - west.Position.x < startGap - 20f, "the follower closed on its anchor");
|
||||
}
|
||||
|
||||
[Fact]
|
||||
public void AStagedApproachFollowerStopsFollowingOnceTheSensorsLoseTheTrack()
|
||||
{
|
||||
var (arena, east, west) = StagedApproach();
|
||||
var view = arena.Agents.Single(a => a.Ship == east).View;
|
||||
var sentinel = new float3(0, 0, 12345);
|
||||
for (var i = 0; i < 3; i++) arena.Update(1f / 60f);
|
||||
|
||||
east.Command.Aim = sentinel;
|
||||
arena.Update(1f / 60f);
|
||||
Assert.NotEqual(sentinel, east.Command.Aim.Value);
|
||||
|
||||
east.EntityInfoGathered[west] = 0f;
|
||||
Assert.Null(view.TrackOf(east, PilotView.Handle(west)));
|
||||
east.Command.Aim = sentinel;
|
||||
arena.Update(1f / 60f);
|
||||
Assert.Equal(sentinel, east.Command.Aim.Value);
|
||||
}
|
||||
}
|
||||
Loading…
Reference in a new issue