feat(packages): ludic.compass - bearing marks on a strip: marks gathered once a frame from an open registry of providers (CompassProviders), gated by the viewer's tier, sorted tracked / note / plain and culled to a cap; bearings and distances off the viewer's facing, the tracked mark, a capture that lets a guide hear the providers whatever the tier, the eight points, and the radar's range per tier with blips on a unit disc; the viewer through a port
Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
This commit is contained in:
parent
dc71fc986c
commit
1005a677f2
10 changed files with 453 additions and 0 deletions
|
|
@ -17,6 +17,7 @@ section. The rules are in [ludic.base](ludic.base/README.md).
|
|||
| [ludic.anim](ludic.anim/README.md) | glTF animation clips sampled and cross-faded onto a render3d Skin (uses `ludic_render3d`) |
|
||||
| [ludic.character](ludic.character/README.md) | a third-person walking body: gait, steps and slopes, a jump, wading, swimming, sitting, a safe put-down, the orbit camera |
|
||||
| [ludic.audio](ludic.audio/README.md) | world sounds with a gain, pan and pitch from a listener port, flat interface sounds, packed clips loaded, the one door to `Audio.*` |
|
||||
| [ludic.compass](ludic.compass/README.md) | bearing marks on a strip: gathered from registered providers, gated by tier, sorted by priority, bearings, distances and a radar |
|
||||
| [ludic.clock](ludic.clock/README.md) | the hour, the day, the moon and a calendar of seasons |
|
||||
| [ludic.crafting](ludic.crafting/README.md) | recipes: what goes in and out, where and how long, making, refunding, hold-to-make |
|
||||
| [ludic.effects](ludic.effects/README.md) | timed modifiers that run down in game time (a meal's warmth, a drink's legs) |
|
||||
|
|
|
|||
84
packages/ludic.compass/README.md
Normal file
84
packages/ludic.compass/README.md
Normal file
|
|
@ -0,0 +1,84 @@
|
|||
# ludic.compass
|
||||
|
||||
Bearing markers on a strip: where things are from where you stand. Each frame the package asks
|
||||
every provider the game registered, keeps the marks the viewer's compass is good enough to show,
|
||||
sorts them by priority and culls them to a cap, and answers each one's bearing and distance - for a
|
||||
strip across the top of the screen, a radar in a corner, a map, or a guide's arrow. Uses
|
||||
[`ludic.base`](../ludic.base/README.md) and nothing else.
|
||||
|
||||
```ludic
|
||||
import "ludic.compass"
|
||||
```
|
||||
|
||||
The package never draws and never names a picture. A mark's `icon` and `colour` are the game's
|
||||
keys (an index into its icon sheet and its palette), and its `label` is the game's words.
|
||||
|
||||
## A mark
|
||||
|
||||
| | |
|
||||
| --- | --- |
|
||||
| `x`, `z` | where it is in the world |
|
||||
| `icon`, `colour` | the game's keys for its picture and its colour |
|
||||
| `tier` | the least compass that shows it: the viewer's `CompassWorld.tier()` below it, the mark is dropped |
|
||||
| `prio` | `COMPASS_TRACKED` (the objective: its distance is shown, and it stays at the strip's edge when off it), `COMPASS_NOTE` (one the player asked for), `COMPASS_PLAIN` |
|
||||
| `label` | its name |
|
||||
|
||||
## Providers
|
||||
|
||||
A provider is a function that calls `compass_mark` for each thing it knows about. The game
|
||||
registers them in the open registry, and `compass_gather()` asks them in the registry's order:
|
||||
|
||||
```ludic
|
||||
def CompassProviders places { gather: fn cp_places }
|
||||
def CompassProviders story { gather: fn story_marks }
|
||||
```
|
||||
|
||||
Then the marks are sorted - tracked first, then notes, then the rest, each band in the order the
|
||||
providers gave them - and culled to `compass_config(cap)`. A viewer with tier 0 gathers nothing.
|
||||
|
||||
A **capture** lets something else hear where the providers point without touching the frame's
|
||||
list, whatever the tier (a guide that points at the objective before a compass is bought):
|
||||
|
||||
```ludic
|
||||
compass_capture_begin()
|
||||
story_marks()
|
||||
let marks = compass_capture_end()
|
||||
```
|
||||
|
||||
## The port
|
||||
|
||||
```ludic
|
||||
export port CompassWorld { # every member has a default: at the origin facing -z, every tier
|
||||
x: fn() -> float
|
||||
z: fn() -> float
|
||||
yaw: fn() -> float # radians; 0 faces -z, and +yaw turns toward -x
|
||||
tier: fn() -> int # the compass carried; 0 none
|
||||
}
|
||||
```
|
||||
|
||||
## API
|
||||
|
||||
| | |
|
||||
| --- | --- |
|
||||
| `compass_config(cap)` | how many marks a frame keeps |
|
||||
| `compass_gather()` | once a frame: begin, every provider, end |
|
||||
| `compass_begin()`, `compass_mark(x, z, icon, colour, tier, prio, label)`, `compass_end()` | the frame by hand (a test, one provider asked alone) |
|
||||
| `compass_capture_begin()`, `compass_capture_end() -> []CompassMark`, `compass_capturing()` | the providers heard by someone else |
|
||||
| `compass_count()`, `compass_at(i) -> CompassMark`, `compass_tracked()` | the frame's marks; the first tracked one or -1 |
|
||||
| `compass_bearing(i)`, `compass_dist(i)`, `compass_bearing_to(x, z)`, `compass_dist_to(x, z)` | from the viewer: a bearing in -pi .. pi off its facing, a distance in metres |
|
||||
| `compass_heading(dx, dz)`, `compass_rel(heading)`, `compass_wrap(a)`, `compass_strip_t(bearing, half)` | the arithmetic: a world heading, as the strip sees it, wrapped, and across a strip showing `half` either side (-1 .. 1 on it) |
|
||||
| `compass_octant(dx, dz)` | which of eight points an offset lies toward, 0 at heading 0 and going toward -x (N, NW, W ...) |
|
||||
| `compass_config_radar(ranges, from_tier)` | the radar's range per compass tier (0 none; past the table the last) and the least mark tier it shows (the tracked mark always) |
|
||||
| `compass_radar_on()`, `compass_radar_range()`, `compass_radar_has(i)`, `compass_radar_x(i)`, `compass_radar_y(i)` | the radar: carried, how far, whether a mark is a blip, and where on a unit disc (x right, y down, ahead is up) |
|
||||
|
||||
There is no save: the marks are the providers' state, asked again every frame.
|
||||
|
||||
## Tests
|
||||
|
||||
```bash
|
||||
ludic test packages/ludic.compass
|
||||
```
|
||||
|
||||
A viewer and two providers: the order and the bands, the tier gate and no compass, the cap,
|
||||
bearings and distances as the viewer turns and moves, a capture, the radar's tiers and blips, and
|
||||
the eight points.
|
||||
61
packages/ludic.compass/bearing.ludic
Normal file
61
packages/ludic.compass/bearing.ludic
Normal file
|
|
@ -0,0 +1,61 @@
|
|||
# bearing.ludic - the frame's marks as the strip reads them: how many, each one, where it bears
|
||||
# from the viewer's facing and how far it is. A heading is the world's (0 toward -z, a quarter
|
||||
# turn toward -x), a bearing is the heading less the viewer's yaw, in -pi .. pi.
|
||||
export function compass_count() -> int {
|
||||
if cmp_list == null { return 0 }
|
||||
return len(cmp_list)
|
||||
}
|
||||
|
||||
# the i-th mark, or an empty one past the end
|
||||
export function compass_at(i: int) -> CompassMark {
|
||||
if i < 0 or i >= compass_count() { return new CompassMark }
|
||||
return cmp_list[i]
|
||||
}
|
||||
|
||||
export function compass_wrap(a: float) -> float {
|
||||
var r = a
|
||||
let turn = 2.0 * CMP_PI
|
||||
while r > CMP_PI { r -= turn }
|
||||
while r < -CMP_PI { r += turn }
|
||||
return r
|
||||
}
|
||||
|
||||
export function compass_heading(dx: float, dz: float) -> float { return Math.atan2(-dx, -dz) }
|
||||
|
||||
# a world heading as the strip sees it
|
||||
export function compass_rel(heading: float) -> float { return compass_wrap(heading - CompassWorld.yaw()) }
|
||||
|
||||
export function compass_bearing_to(x: float, z: float) -> float { return compass_rel(compass_heading(x - CompassWorld.x(), z - CompassWorld.z())) }
|
||||
|
||||
export function compass_dist_to(x: float, z: float) -> float {
|
||||
let dx = x - CompassWorld.x()
|
||||
let dz = z - CompassWorld.z()
|
||||
return Math.sqrt(dx * dx + dz * dz)
|
||||
}
|
||||
|
||||
export function compass_bearing(i: int) -> float {
|
||||
let m = compass_at(i)
|
||||
return compass_bearing_to(m.x, m.z)
|
||||
}
|
||||
|
||||
export function compass_dist(i: int) -> float {
|
||||
let m = compass_at(i)
|
||||
return compass_dist_to(m.x, m.z)
|
||||
}
|
||||
|
||||
# where a bearing falls across a strip showing `half` radians either side: -1 .. 1, or past it
|
||||
export function compass_strip_t(bearing: float, half: float) -> float { return bearing / Math.max(half, 0.001) }
|
||||
|
||||
# the objective: the first tracked mark of the frame, or -1
|
||||
export function compass_tracked() -> int {
|
||||
for i in 0 .. compass_count() { if cmp_list[i].prio >= COMPASS_TRACKED { return i } }
|
||||
return -1
|
||||
}
|
||||
|
||||
# which of eight points an offset lies toward: 0 the heading 0, then a quarter turn in two steps
|
||||
# at a time toward -x (for a world where 0 is north: N, NW, W, SW, S, SE, E, NE)
|
||||
export function compass_octant(dx: float, dz: float) -> int {
|
||||
var deg = compass_heading(dx, dz) * 180.0 / CMP_PI
|
||||
if deg < 0.0 { deg += 360.0 }
|
||||
return int(Math.floor(deg / 45.0 + 0.5)) % 8
|
||||
}
|
||||
56
packages/ludic.compass/gather.ludic
Normal file
56
packages/ludic.compass/gather.ludic
Normal file
|
|
@ -0,0 +1,56 @@
|
|||
# gather.ludic - a frame's marks: begin, every provider marks, end sorts and culls. While a
|
||||
# capture is open the marks go to whoever is listening instead, whatever the tier.
|
||||
export function compass_begin() -> void { cmp_list = new []CompassMark }
|
||||
|
||||
# a provider's verb: a thing at (x, z), shown from compass `tier` up
|
||||
export function compass_mark(x: float, z: float, icon: int, colour: int, tier: int, prio: int, label: string) -> void {
|
||||
if cmp_list == null { compass_begin() }
|
||||
let m = cmp_new(x, z, icon, colour, tier, prio, label)
|
||||
if cmp_capturing {
|
||||
push(cmp_caught, m)
|
||||
return
|
||||
}
|
||||
if CompassWorld.tier() < tier { return }
|
||||
push(cmp_list, m)
|
||||
}
|
||||
|
||||
# highest priority first, the providers' order kept within one; then the cap
|
||||
export function compass_end() -> void {
|
||||
if cmp_list == null { compass_begin() }
|
||||
let out = new []CompassMark
|
||||
for p in 0 .. 3 {
|
||||
let want = COMPASS_TRACKED - p
|
||||
for i in 0 .. len(cmp_list) { if cmp_band(cmp_list[i].prio) == want and len(out) < cmp_cap { push(out, cmp_list[i]) } }
|
||||
}
|
||||
cmp_list = out
|
||||
}
|
||||
|
||||
function cmp_band(p: int) -> int { return Math.clamp(p, COMPASS_PLAIN, COMPASS_TRACKED) }
|
||||
|
||||
# once a frame: ask every registered provider, in the registry's order
|
||||
export function compass_gather() -> void {
|
||||
compass_begin()
|
||||
if CompassWorld.tier() <= 0 { return }
|
||||
for i in 0 .. COMPASS_FROM_COUNT {
|
||||
let f = CompassProviders[i].gather
|
||||
if f != null { f() }
|
||||
}
|
||||
compass_end()
|
||||
}
|
||||
|
||||
# someone else wants to know where the providers point (a guide's arrow): until the end every
|
||||
# mark is theirs, whatever the tier, and the frame's list is left alone
|
||||
export function compass_capture_begin() -> void {
|
||||
cmp_capturing = true
|
||||
cmp_caught = new []CompassMark
|
||||
}
|
||||
|
||||
export function compass_capture_end() -> []CompassMark {
|
||||
cmp_capturing = false
|
||||
var got = cmp_caught
|
||||
cmp_caught = new []CompassMark
|
||||
if got == null { got = new []CompassMark }
|
||||
return got
|
||||
}
|
||||
|
||||
export function compass_capturing() -> bool { return cmp_capturing }
|
||||
11
packages/ludic.compass/index.ludic
Normal file
11
packages/ludic.compass/index.ludic
Normal file
|
|
@ -0,0 +1,11 @@
|
|||
# ludic.compass - where things are from where you stand: marks gathered once a frame from an open
|
||||
# registry of providers, gated by a tier and sorted by priority, turned into bearings for a strip
|
||||
# and blips for a radar. The game draws both.
|
||||
module ludic_compass uses ludic_base
|
||||
numbers float
|
||||
import "ludic.base"
|
||||
import "ports.ludic"
|
||||
import "marks.ludic"
|
||||
import "gather.ludic"
|
||||
import "bearing.ludic"
|
||||
import "radar.ludic"
|
||||
46
packages/ludic.compass/marks.ludic
Normal file
46
packages/ludic.compass/marks.ludic
Normal file
|
|
@ -0,0 +1,46 @@
|
|||
# marks.ludic - a mark, the providers the game registers, and the frame's list
|
||||
export const COMPASS_PLAIN: int = 0 # priorities: an ordinary mark
|
||||
export const COMPASS_NOTE: int = 1 # one the player asked for (a mark of their own)
|
||||
export const COMPASS_TRACKED: int = 2 # the objective: its distance is shown, at the edge too
|
||||
|
||||
export property CompassMark {
|
||||
x: float = 0.0
|
||||
z: float = 0.0
|
||||
icon: int = 0 # the game's key for its picture
|
||||
colour: int = 0 # the game's key for its colour
|
||||
tier: int = 1 # the least compass that shows it
|
||||
prio: int = 0
|
||||
label: string = ""
|
||||
}
|
||||
|
||||
# a provider says where its things are by calling compass_mark; the game fills the registry
|
||||
# (`def CompassProviders story { gather: fn story_marks }`) and they are asked in its order
|
||||
export property CompassProvider {
|
||||
key: string = ""
|
||||
gather: fn() -> void = null
|
||||
}
|
||||
|
||||
export open registry CompassProviders of CompassProvider as COMPASS_FROM
|
||||
|
||||
var cmp_cap: int = 64
|
||||
var cmp_list: []CompassMark = null # this frame's, sorted and culled
|
||||
var cmp_capturing: bool = false
|
||||
var cmp_caught: []CompassMark = null # what providers said while someone was listening
|
||||
|
||||
# how many marks a frame keeps (the lowest priorities go first past it)
|
||||
export function compass_config(cap: int) -> void {
|
||||
cmp_cap = Math.max(cap, 1)
|
||||
compass_begin()
|
||||
}
|
||||
|
||||
function cmp_new(x: float, z: float, icon: int, colour: int, tier: int, prio: int, label: string) -> CompassMark {
|
||||
let m = new CompassMark
|
||||
m.x = x
|
||||
m.z = z
|
||||
m.icon = icon
|
||||
m.colour = colour
|
||||
m.tier = tier
|
||||
m.prio = prio
|
||||
m.label = label
|
||||
return m
|
||||
}
|
||||
6
packages/ludic.compass/package.ludic
Normal file
6
packages/ludic.compass/package.ludic
Normal file
|
|
@ -0,0 +1,6 @@
|
|||
# ludic.compass - bearing markers on a strip: marks gathered each frame from the game's providers,
|
||||
# gated by the viewer's tier, sorted and culled by priority, as bearings and distances, and the
|
||||
# radar's tiers. Uses ludic.base and nothing else. See README.md.
|
||||
package "ludic.compass"
|
||||
version "0.1.0"
|
||||
kind source
|
||||
14
packages/ludic.compass/ports.ludic
Normal file
14
packages/ludic.compass/ports.ludic
Normal file
|
|
@ -0,0 +1,14 @@
|
|||
# ports.ludic - what the compass asks the game: where the viewer stands, which way the strip
|
||||
# faces and which compass is in the pack. Unbound, it stands at the origin facing -z (yaw 0) and
|
||||
# carries every tier.
|
||||
export port CompassWorld {
|
||||
x: fn() -> float = fn cmp__zero
|
||||
z: fn() -> float = fn cmp__zero
|
||||
yaw: fn() -> float = fn cmp__zero # radians; 0 faces -z, and +yaw turns toward -x
|
||||
tier: fn() -> int = fn cmp__every # 0 no compass: nothing at all is gathered
|
||||
}
|
||||
|
||||
function cmp__zero() -> float { return 0.0 }
|
||||
function cmp__every() -> int { return 1000 }
|
||||
|
||||
const CMP_PI: float = 3.14159265
|
||||
40
packages/ludic.compass/radar.ludic
Normal file
40
packages/ludic.compass/radar.ludic
Normal file
|
|
@ -0,0 +1,40 @@
|
|||
# radar.ludic - the radar's tiers: a range for each compass tier (0 is no radar), which marks it
|
||||
# shows, and where each falls on a unit disc with ahead at the top
|
||||
var cmp_ranges: []float = null
|
||||
var cmp_radar_from: int = 2 # marks of at least this tier are blips; the tracked one always is
|
||||
|
||||
export function compass_config_radar(ranges: []float, from_tier: int) -> void {
|
||||
cmp_ranges = new []float
|
||||
for i in 0 .. len(ranges) { push(cmp_ranges, ranges[i]) }
|
||||
cmp_radar_from = from_tier
|
||||
}
|
||||
|
||||
# how far the radar reaches with the viewer's compass, 0 without one; a tier past the table has
|
||||
# the last range
|
||||
export function compass_radar_range() -> float {
|
||||
if cmp_ranges == null or len(cmp_ranges) == 0 { return 0.0 }
|
||||
let t = CompassWorld.tier()
|
||||
if t < 0 { return 0.0 }
|
||||
if t >= len(cmp_ranges) { return cmp_ranges[len(cmp_ranges) - 1] }
|
||||
return cmp_ranges[t]
|
||||
}
|
||||
|
||||
export function compass_radar_on() -> bool { return compass_radar_range() > 0.0 }
|
||||
|
||||
# the i-th mark is a blip: a radar is carried, it is shown there and it is in range
|
||||
export function compass_radar_has(i: int) -> bool {
|
||||
if i < 0 or i >= compass_count() or not compass_radar_on() { return false }
|
||||
let m = cmp_list[i]
|
||||
if m.tier < cmp_radar_from and m.prio < COMPASS_TRACKED { return false }
|
||||
return compass_dist(i) <= compass_radar_range()
|
||||
}
|
||||
|
||||
# where on a unit disc: x right, y down, so ahead is (0, -1) and the edge is the range
|
||||
export function compass_radar_x(i: int) -> float { return -Math.sin(compass_bearing(i)) * cmp_radar_frac(i) }
|
||||
export function compass_radar_y(i: int) -> float { return -Math.cos(compass_bearing(i)) * cmp_radar_frac(i) }
|
||||
|
||||
function cmp_radar_frac(i: int) -> float {
|
||||
let r = compass_radar_range()
|
||||
if r <= 0.0 { return 0.0 }
|
||||
return Math.min(compass_dist(i) / r, 1.0)
|
||||
}
|
||||
134
packages/ludic.compass/tests/compass_test.ludic
Normal file
134
packages/ludic.compass/tests/compass_test.ludic
Normal file
|
|
@ -0,0 +1,134 @@
|
|||
# compass_test.ludic - a viewer at (vx, vz) facing yaw with a compass of `tier`, and two providers:
|
||||
# the places (a camp ahead, a sign west, a far legend) and the objective. The tier gate, the order
|
||||
# and the cap, bearings and distances, the tracked mark, a capture, the radar's tiers, the points.
|
||||
import "ludic.compass"
|
||||
import "ludic.base"
|
||||
program CompassTest {
|
||||
numbers float
|
||||
|
||||
var vx: float = 0.0
|
||||
var vz: float = 0.0
|
||||
var yaw: float = 0.0
|
||||
var tier: int = 4
|
||||
var objective: bool = true
|
||||
|
||||
function fk_x() -> float { return vx }
|
||||
function fk_z() -> float { return vz }
|
||||
function fk_yaw() -> float { return yaw }
|
||||
function fk_tier() -> int { return tier }
|
||||
bind CompassWorld { x: fn fk_x, z: fn fk_z, yaw: fn fk_yaw, tier: fn fk_tier }
|
||||
|
||||
function places() -> void {
|
||||
compass_mark(0.0, -100.0, 1, 10, 1, COMPASS_PLAIN, "camp")
|
||||
compass_mark(-50.0, 0.0, 2, 11, 2, COMPASS_PLAIN, "sign")
|
||||
compass_mark(0.0, 300.0, 3, 12, 4, COMPASS_PLAIN, "legend")
|
||||
compass_mark(10.0, 10.0, 4, 13, 1, COMPASS_NOTE, "my mark")
|
||||
}
|
||||
function goal() -> void { if objective { compass_mark(80.0, 0.0, 5, 14, 2, COMPASS_TRACKED, "the dock") } }
|
||||
def CompassProviders places { gather: fn places }
|
||||
def CompassProviders goal { gather: fn goal }
|
||||
|
||||
function fresh() -> void {
|
||||
compass_config(64)
|
||||
compass_config_radar([0.0, 0.0, 0.0, 120.0, 260.0], 2)
|
||||
vx = 0.0
|
||||
vz = 0.0
|
||||
yaw = 0.0
|
||||
tier = 4
|
||||
objective = true
|
||||
}
|
||||
function labels() -> string {
|
||||
var s = ""
|
||||
for i in 0 .. compass_count() { s = s + compass_at(i).label + ";" }
|
||||
return s
|
||||
}
|
||||
|
||||
test "every provider is asked, the tracked mark first, then the player's, then the rest in order" {
|
||||
fresh()
|
||||
compass_gather()
|
||||
expect_eq(compass_count(), 5)
|
||||
expect(labels() == "the dock;my mark;camp;sign;legend;")
|
||||
expect_eq(compass_tracked(), 0)
|
||||
}
|
||||
|
||||
test "a mark shows from its tier up, and without a compass nothing is gathered" {
|
||||
fresh()
|
||||
tier = 1
|
||||
compass_gather()
|
||||
expect(labels() == "my mark;camp;")
|
||||
expect_eq(compass_tracked(), -1)
|
||||
tier = 0
|
||||
compass_gather()
|
||||
expect_eq(compass_count(), 0)
|
||||
}
|
||||
|
||||
test "past the cap the lowest priorities go" {
|
||||
fresh()
|
||||
compass_config(2)
|
||||
compass_gather()
|
||||
expect(labels() == "the dock;my mark;")
|
||||
}
|
||||
|
||||
test "a bearing is from the viewer's facing, a distance from where it stands" {
|
||||
fresh()
|
||||
compass_gather()
|
||||
expect_near(compass_bearing(2), 0.0, 0.001)
|
||||
expect_near(compass_dist(2), 100.0, 0.01)
|
||||
expect_near(compass_bearing(3), 1.5708, 0.001)
|
||||
expect_near(compass_bearing(0), -1.5708, 0.001)
|
||||
yaw = 1.5708
|
||||
expect_near(compass_bearing(3), 0.0, 0.001)
|
||||
expect_near(compass_bearing(2), -1.5708, 0.001)
|
||||
vx = -50.0
|
||||
vz = 100.0
|
||||
expect_near(compass_dist(3), 100.0, 0.01)
|
||||
expect_near(compass_wrap(7.0), 7.0 - 6.2832, 0.001)
|
||||
expect_near(compass_strip_t(0.5, 1.0), 0.5, 0.001)
|
||||
}
|
||||
|
||||
test "a capture hears every mark whatever the tier and leaves the frame's list alone" {
|
||||
fresh()
|
||||
compass_gather()
|
||||
tier = 1
|
||||
compass_capture_begin()
|
||||
expect(compass_capturing())
|
||||
goal()
|
||||
places()
|
||||
let got = compass_capture_end()
|
||||
expect(not compass_capturing())
|
||||
expect_eq(len(got), 5)
|
||||
expect(got[0].label == "the dock")
|
||||
expect_eq(compass_count(), 5)
|
||||
}
|
||||
|
||||
test "the radar: its range by tier, the blips in it, and where each falls on the disc" {
|
||||
fresh()
|
||||
tier = 2
|
||||
compass_gather()
|
||||
expect(not compass_radar_on())
|
||||
expect(not compass_radar_has(0))
|
||||
tier = 3
|
||||
compass_gather()
|
||||
expect(compass_radar_on())
|
||||
expect_near(compass_radar_range(), 120.0, 0.01)
|
||||
expect(compass_radar_has(0))
|
||||
expect(not compass_radar_has(1))
|
||||
expect(not compass_radar_has(2))
|
||||
expect(compass_radar_has(3))
|
||||
expect_near(compass_radar_x(3), -50.0 / 120.0, 0.001)
|
||||
expect_near(compass_radar_y(3), 0.0, 0.001)
|
||||
expect_near(compass_radar_x(0), 80.0 / 120.0, 0.001)
|
||||
tier = 9
|
||||
expect_near(compass_radar_range(), 260.0, 0.01)
|
||||
}
|
||||
|
||||
test "the eight points go round from the heading 0 toward -x" {
|
||||
expect_eq(compass_octant(0.0, -10.0), 0)
|
||||
expect_eq(compass_octant(-10.0, -10.0), 1)
|
||||
expect_eq(compass_octant(-10.0, 0.0), 2)
|
||||
expect_eq(compass_octant(0.0, 10.0), 4)
|
||||
expect_eq(compass_octant(10.0, 0.0), 6)
|
||||
expect_eq(compass_octant(10.0, -10.0), 7)
|
||||
expect_eq(compass_octant(1.0, -10.0), 0)
|
||||
}
|
||||
}
|
||||
Loading…
Add table
Add a link
Reference in a new issue