This commit is contained in:
root
2026-10-01 22:16:48 +02:00
parent b6d1909d7f
commit 9dfdf79fa7
39 changed files with 4560 additions and 181 deletions
+66 -37
View File
@@ -7,6 +7,7 @@ import (
"halcyon/config"
"halcyon/fixed"
"halcyon/vm"
"halcyon/world"
)
func testCfg() config.Config {
@@ -147,43 +148,6 @@ func TestInclinedOrbitLeavesPlane(t *testing.T) {
}
}
func TestMineAndSell(t *testing.T) {
cfg := testCfg()
s := NewState(cfg)
// Sit on asteroid 1, matching its motion for the whole first tick, and mine.
pos, vel := s.Asteroids[0].Orbit.State(0)
sh := addShip(t, s, cfg, 1, mustAsm(t, `
ldi r0, 1
out 0x30, r0 ; select asteroid 1
out 0x50, r0 ; mine
yield
jmp -2
`), pos, vel)
if _, err := s.RunDay(cfg, DayInput{}); err != nil {
t.Fatal(err)
}
// Gravity acts on the ship differently than the rails, so it soon drifts
// out of range; it should still have mined something at the start.
if sh.CargoTotal() == 0 {
t.Fatal("nothing mined")
}
// Now dock at the station and sell.
s2 := NewState(cfg)
sp, sv := s2.Station.Orbit.State(0)
sh2 := addShip(t, s2, cfg, 1, mustAsm(t, "ldi r0, 1\n out 0x66, r0\n halt"), sp, sv)
sh2.Cargo[0] = 1000 // iron
if _, err := s2.RunDay(cfg, DayInput{}); err != nil {
t.Fatal(err)
}
if s2.Credits[1] != 2000 || sh2.CargoTotal() != 0 {
t.Fatalf("credits=%d cargo=%d", s2.Credits[1], sh2.CargoTotal())
}
if s2.Market.Prices[0] >= 2 && s2.Market.Supply[0] != 1000 {
t.Fatalf("market not updated: %+v", s2.Market)
}
}
func TestCommsBuffers(t *testing.T) {
cfg := testCfg()
s := NewState(cfg)
@@ -209,3 +173,68 @@ func TestCommsBuffers(t *testing.T) {
t.Fatalf("downlink = %q", res.Downlinks)
}
}
func TestScannerRange(t *testing.T) {
cfg := testCfg()
s := NewState(cfg)
stPos, stVel := s.Station.Orbit.State(0)
sh := addShip(t, s, cfg, 1, mustAsm(t, "halt\n"), stPos, stVel)
tc := newTickCtx(s, cfg, 0, 0, stPos, stVel, &DayResult{}, new([world.NumOre]int64))
b := &shipBus{tc: tc, sh: sh}
// Find the true nearest asteroid and its distance from the ship.
var near int
var nd fixed.F = fixed.Max
for i := range s.Asteroids {
p, _ := tc.asteroid(i)
if d := p.Sub(sh.Pos).Len(); d < nd {
near, nd = i+1, d
}
}
limit := fixed.FromInt(ScanRangeKm)
if nd <= limit {
if got := b.In(PortScanNearest); got != int32(near) {
t.Fatalf("nearest = %d, want %d", got, near)
}
} else if got := b.In(PortScanNearest); got != 0 {
t.Fatalf("nearest = %d beyond range, want 0", got)
}
// Move the ship out of range of everything: the scanner goes blind.
sh.Pos = fixed.Vec{X: fixed.FromInt(50_000_000)}
if got := b.In(PortScanNearest); got != 0 {
t.Fatalf("nearest out of range = %d, want 0", got)
}
b.Out(PortScanSelect, int32(near))
for _, p := range []uint16{PortScanRelX, PortScanRelVX, PortScanDist, PortScanOre} {
if got := b.In(p); got != 0 {
t.Fatalf("port %#x = %d out of range, want 0", p, got)
}
}
}
func TestScrapRemovesShipAndReleasesTow(t *testing.T) {
cfg := testCfg()
s := NewState(cfg)
stPos, stVel := s.Station.Orbit.State(0)
sh := addShip(t, s, cfg, 1, mustAsm(t, "halt\n"), stPos, stVel)
s.Containers = append(s.Containers, &Container{ID: 1, Towed: sh.ID, Pos: stPos, Vel: stVel})
res, err := s.RunDay(cfg, DayInput{Scraps: []int64{1, 42}}) // an unknown id is ignored
if err != nil {
t.Fatal(err)
}
if len(s.Ships) != 0 {
t.Fatalf("%d ships left after scrapping", len(s.Ships))
}
c := s.Containers[0]
if c.Towed != 0 || c.Dropped != 1 {
t.Fatalf("container after scrapping: towed %d dropped %d, want adrift", c.Towed, c.Dropped)
}
found := false
for _, e := range res.Events {
found = found || (e.Kind == "scrapped" && e.ShipID == 1)
}
if !found {
t.Fatal("no scrapped event")
}
}