wip(0.S3): packages and examples migrated again from their pre-0.S sources in one run
ludic migrate state packages <every example program> packages/ludic.lab/example/plate.ludic 1804 vars into 126 states, 64 into lets; 23498 edits in 460 files Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
This commit is contained in:
parent
5ffe50ed02
commit
19fcf60599
459 changed files with 17862 additions and 17603 deletions
|
|
@ -1,100 +1,97 @@
|
|||
# explored.ludic - walking reveals the cells round you; "explored" is the share of the core's LAND
|
||||
# that has been seen, since open water has nothing on it to miss
|
||||
var mm_land_n: int = 0 # land cells in the core, counted once per origin
|
||||
var mm_land_ox: float = 0.0
|
||||
var mm_land_oz: float = 0.0
|
||||
|
||||
# every cell any part of which is within r of (x, z)
|
||||
export function minimap_reveal(x: float, z: float, r: float) -> void {
|
||||
mm_grid()
|
||||
let c = minimap_cell(x, z)
|
||||
let reach = int(r / mm_cell_m) + 1
|
||||
let x0 = minimap_grid_x0()
|
||||
let z0 = minimap_grid_z0()
|
||||
let ci = int(Math.floor((x - x0) / mm_cell_m))
|
||||
let cj = int(Math.floor((z - z0) / mm_cell_m))
|
||||
export function minimap_reveal(minimap_st: mut MinimapState, x: float, z: float, r: float) -> void {
|
||||
mm_grid(minimap_st)
|
||||
let c = minimap_cell(minimap_st, x, z)
|
||||
let reach = int(r / minimap_st.mm_cell_m) + 1
|
||||
let x0 = minimap_grid_x0(minimap_st)
|
||||
let z0 = minimap_grid_z0(minimap_st)
|
||||
let ci = int(Math.floor((x - x0) / minimap_st.mm_cell_m))
|
||||
let cj = int(Math.floor((z - z0) / minimap_st.mm_cell_m))
|
||||
for j in cj - reach .. cj + reach + 1 {
|
||||
for i in ci - reach .. ci + reach + 1 {
|
||||
if i < 0 or j < 0 or i >= mm_cells or j >= mm_cells { continue }
|
||||
let nx = Math.clamp(x, x0 + float(i) * mm_cell_m, x0 + float(i + 1) * mm_cell_m)
|
||||
let nz = Math.clamp(z, z0 + float(j) * mm_cell_m, z0 + float(j + 1) * mm_cell_m)
|
||||
if (nx - x) * (nx - x) + (nz - z) * (nz - z) <= r * r { minimap_reveal_cell(j * mm_cells + i) }
|
||||
if i < 0 or j < 0 or i >= minimap_st.mm_cells or j >= minimap_st.mm_cells { continue }
|
||||
let nx = Math.clamp(x, x0 + float(i) * minimap_st.mm_cell_m, x0 + float(i + 1) * minimap_st.mm_cell_m)
|
||||
let nz = Math.clamp(z, z0 + float(j) * minimap_st.mm_cell_m, z0 + float(j + 1) * minimap_st.mm_cell_m)
|
||||
if (nx - x) * (nx - x) + (nz - z) * (nz - z) <= r * r { minimap_reveal_cell(minimap_st, j * minimap_st.mm_cells + i) }
|
||||
}
|
||||
}
|
||||
if c >= 0 { minimap_reveal_cell(c) }
|
||||
if c >= 0 { minimap_reveal_cell(minimap_st, c) }
|
||||
}
|
||||
|
||||
export function minimap_reveal_cell(c: int) -> void {
|
||||
mm_grid()
|
||||
if c < 0 or c >= mm_cells * mm_cells or mm_seen[c] != 0 { return }
|
||||
mm_seen[c] = 1
|
||||
mm_version += 1
|
||||
export function minimap_reveal_cell(minimap_st: mut MinimapState, c: int) -> void {
|
||||
mm_grid(minimap_st)
|
||||
if c < 0 or c >= minimap_st.mm_cells * minimap_st.mm_cells or minimap_st.mm_seen[c] != 0 { return }
|
||||
minimap_st.mm_seen[c] = 1
|
||||
minimap_st.mm_version += 1
|
||||
}
|
||||
|
||||
export function minimap_seen(c: int) -> bool {
|
||||
if mm_seen == null or c < 0 or c >= mm_cells * mm_cells { return false }
|
||||
return mm_seen[c] != 0
|
||||
export function minimap_seen(minimap_st: MinimapState, c: int) -> bool {
|
||||
if minimap_st.mm_seen == null or c < 0 or c >= minimap_st.mm_cells * minimap_st.mm_cells { return false }
|
||||
return minimap_st.mm_seen[c] != 0
|
||||
}
|
||||
|
||||
export function minimap_seen_at(x: float, z: float) -> bool { return minimap_seen(minimap_cell(x, z)) }
|
||||
export function minimap_seen_at(minimap_st: MinimapState, x: float, z: float) -> bool { return minimap_seen(minimap_st, minimap_cell(minimap_st, x, z)) }
|
||||
|
||||
export function minimap_seen_count() -> int {
|
||||
export function minimap_seen_count(minimap_st: MinimapState) -> int {
|
||||
var n = 0
|
||||
if mm_seen == null { return 0 }
|
||||
for c in 0 .. len(mm_seen) { if mm_seen[c] != 0 { n += 1 } }
|
||||
if minimap_st.mm_seen == null { return 0 }
|
||||
for c in 0 .. len(minimap_st.mm_seen) { if minimap_st.mm_seen[c] != 0 { n += 1 } }
|
||||
return n
|
||||
}
|
||||
|
||||
# goes up whenever what has been seen changes: a picture of the fog is baked again when it does
|
||||
export function minimap_version() -> int { return mm_version }
|
||||
export function minimap_version(minimap_st: MinimapState) -> int { return minimap_st.mm_version }
|
||||
|
||||
export function minimap_explored_pct() -> int {
|
||||
mm_land_count()
|
||||
export function minimap_explored_pct(minimap_st: mut MinimapState) -> int {
|
||||
mm_land_count(minimap_st)
|
||||
var n = 0
|
||||
for j in mm_core0 .. mm_core0 + mm_core_n {
|
||||
for i in mm_core0 .. mm_core0 + mm_core_n {
|
||||
if minimap_seen(j * mm_cells + i) and mm_land(i, j) { n += 1 }
|
||||
for j in minimap_st.mm_core0 .. minimap_st.mm_core0 + minimap_st.mm_core_n {
|
||||
for i in minimap_st.mm_core0 .. minimap_st.mm_core0 + minimap_st.mm_core_n {
|
||||
if minimap_seen(minimap_st, j * minimap_st.mm_cells + i) and mm_land(minimap_st, i, j) { n += 1 }
|
||||
}
|
||||
}
|
||||
return Math.min(n * 100 / mm_land_n, 100)
|
||||
return Math.min(n * 100 / minimap_st.mm_land_n, 100)
|
||||
}
|
||||
|
||||
function mm_land(i: int, j: int) -> bool { return MinimapWorld.land(minimap_cell_x(i), minimap_cell_z(j)) }
|
||||
function mm_land(minimap_st: MinimapState, i: int, j: int) -> bool { return MinimapWorld.land(minimap_cell_x(minimap_st, i), minimap_cell_z(minimap_st, j)) }
|
||||
|
||||
function mm_land_count() -> void {
|
||||
function mm_land_count(minimap_st: mut MinimapState) -> void {
|
||||
let ox = MinimapWorld.origin_x()
|
||||
let oz = MinimapWorld.origin_z()
|
||||
if mm_land_n > 0 and ox == mm_land_ox and oz == mm_land_oz { return }
|
||||
mm_land_ox = ox
|
||||
mm_land_oz = oz
|
||||
mm_land_n = 0
|
||||
for j in mm_core0 .. mm_core0 + mm_core_n {
|
||||
for i in mm_core0 .. mm_core0 + mm_core_n { if mm_land(i, j) { mm_land_n += 1 } }
|
||||
if minimap_st.mm_land_n > 0 and ox == minimap_st.mm_land_ox and oz == minimap_st.mm_land_oz { return }
|
||||
minimap_st.mm_land_ox = ox
|
||||
minimap_st.mm_land_oz = oz
|
||||
minimap_st.mm_land_n = 0
|
||||
for j in minimap_st.mm_core0 .. minimap_st.mm_core0 + minimap_st.mm_core_n {
|
||||
for i in minimap_st.mm_core0 .. minimap_st.mm_core0 + minimap_st.mm_core_n { if mm_land(minimap_st, i, j) { minimap_st.mm_land_n += 1 } }
|
||||
}
|
||||
mm_land_n = Math.max(mm_land_n, 1)
|
||||
minimap_st.mm_land_n = Math.max(minimap_st.mm_land_n, 1)
|
||||
}
|
||||
|
||||
# the ground under the grid is not what it was (a new world): count its land again
|
||||
export function minimap_land_changed() -> void { mm_land_n = 0 }
|
||||
export function minimap_land_changed(minimap_st: mut MinimapState) -> void { minimap_st.mm_land_n = 0 }
|
||||
|
||||
# the grid as one string of 0 / 1, row by row, and back (a shorter string leaves the rest unseen)
|
||||
export function minimap_seen_text() -> string {
|
||||
mm_grid()
|
||||
export function minimap_seen_text(minimap_st: mut MinimapState) -> string {
|
||||
mm_grid(minimap_st)
|
||||
var s = ""
|
||||
for j in 0 .. mm_cells {
|
||||
for j in 0 .. minimap_st.mm_cells {
|
||||
var row = ""
|
||||
for i in 0 .. mm_cells { if mm_seen[j * mm_cells + i] != 0 { row = row + "1" } else { row = row + "0" } }
|
||||
for i in 0 .. minimap_st.mm_cells { if minimap_st.mm_seen[j * minimap_st.mm_cells + i] != 0 { row = row + "1" } else { row = row + "0" } }
|
||||
s = s + row
|
||||
}
|
||||
return s
|
||||
}
|
||||
|
||||
export function minimap_seen_from_text(s: string) -> void {
|
||||
mm_grid()
|
||||
export function minimap_seen_from_text(minimap_st: mut MinimapState, s: string) -> void {
|
||||
mm_grid(minimap_st)
|
||||
let n = len(s)
|
||||
for c in 0 .. mm_cells * mm_cells {
|
||||
mm_seen[c] = 0
|
||||
if c < n and s[c] == 49 { mm_seen[c] = 1 }
|
||||
for c in 0 .. minimap_st.mm_cells * minimap_st.mm_cells {
|
||||
minimap_st.mm_seen[c] = 0
|
||||
if c < n and s[c] == 49 { minimap_st.mm_seen[c] = 1 }
|
||||
}
|
||||
mm_version += 1
|
||||
minimap_st.mm_version += 1
|
||||
}
|
||||
|
|
|
|||
|
|
@ -1,47 +1,76 @@
|
|||
# grid.ludic - the explored grid: square cells round the origin, and the part of it "explored" is
|
||||
# measured over (a core, so a bigger grid does not change what a share of it means)
|
||||
var mm_cells: int = 128 # per side
|
||||
var mm_cell_m: float = 100.0 # metres per cell
|
||||
var mm_core0: int = 0 # the measured square: from this cell, this many per side
|
||||
var mm_core_n: int = 128
|
||||
var mm_seen: []int = null # 0 / 1 per cell, row by row
|
||||
var mm_version: int = 0 # goes up whenever a cell is revealed or the grid is replaced
|
||||
export state MinimapState {
|
||||
mm_land_n: int = 0 # land cells in the core, counted once per origin
|
||||
mm_land_ox: float = 0.0
|
||||
mm_land_oz: float = 0.0
|
||||
mm_cells: int = 128 # per side
|
||||
mm_cell_m: float = 100.0 # metres per cell
|
||||
mm_core0: int = 0 # the measured square: from this cell, this many per side
|
||||
mm_core_n: int = 128
|
||||
mm_seen: []int = null # 0 / 1 per cell, row by row
|
||||
mm_version: int = 0 # goes up whenever a cell is revealed or the grid is replaced
|
||||
mm_pins: []MinimapPin = null
|
||||
mm_pin_max: int = 32
|
||||
mm_symbols: int = 8
|
||||
mm_colours: int = 5
|
||||
mm_open: int = -1
|
||||
mm_followed: int = -1
|
||||
mm_last: int = 0
|
||||
mm_placing: bool = false
|
||||
mm_x0: float = 0.0
|
||||
mm_y0: float = 0.0
|
||||
mm_size: float = 512.0
|
||||
mm_span: float = 6400.0
|
||||
mm_zoom_min: float = 0.5
|
||||
mm_zoom_max: float = 8.0
|
||||
mm_zoom_focus: float = 4.0
|
||||
mm_zoom: float = 1.0
|
||||
mm_vx: float = 0.0
|
||||
mm_vz: float = 0.0
|
||||
mm_have_view: bool = false
|
||||
mm_panning: bool = false
|
||||
mm_drag_rx: float = 0.0
|
||||
mm_drag_ry: float = 0.0
|
||||
mm_drag_vx: float = 0.0
|
||||
mm_drag_vz: float = 0.0
|
||||
}
|
||||
|
||||
# the grid: `cells` per side of `cell_m` metres, centred on MinimapWorld's origin; the whole of it
|
||||
# is measured until minimap_config_core says otherwise
|
||||
export function minimap_config(cells: int, cell_m: float) -> void {
|
||||
mm_cells = Math.max(cells, 1)
|
||||
mm_cell_m = Math.max(cell_m, 0.001)
|
||||
mm_core0 = 0
|
||||
mm_core_n = mm_cells
|
||||
mm_seen = new []int
|
||||
for i in 0 .. mm_cells * mm_cells { push(mm_seen, 0) }
|
||||
mm_land_n = 0
|
||||
mm_version += 1
|
||||
export function minimap_config(minimap_st: mut MinimapState, cells: int, cell_m: float) -> void {
|
||||
minimap_st.mm_cells = Math.max(cells, 1)
|
||||
minimap_st.mm_cell_m = Math.max(cell_m, 0.001)
|
||||
minimap_st.mm_core0 = 0
|
||||
minimap_st.mm_core_n = minimap_st.mm_cells
|
||||
minimap_st.mm_seen = new []int
|
||||
for i in 0 .. minimap_st.mm_cells * minimap_st.mm_cells { push(minimap_st.mm_seen, 0) }
|
||||
minimap_st.mm_land_n = 0
|
||||
minimap_st.mm_version += 1
|
||||
}
|
||||
|
||||
export function minimap_config_core(from: int, n: int) -> void {
|
||||
mm_core0 = Math.clamp(from, 0, mm_cells - 1)
|
||||
mm_core_n = Math.clamp(n, 1, mm_cells - mm_core0)
|
||||
mm_land_n = 0
|
||||
export function minimap_config_core(minimap_st: mut MinimapState, from: int, n: int) -> void {
|
||||
minimap_st.mm_core0 = Math.clamp(from, 0, minimap_st.mm_cells - 1)
|
||||
minimap_st.mm_core_n = Math.clamp(n, 1, minimap_st.mm_cells - minimap_st.mm_core0)
|
||||
minimap_st.mm_land_n = 0
|
||||
}
|
||||
|
||||
export function minimap_cells() -> int { return mm_cells }
|
||||
export function minimap_cell_m() -> float { return mm_cell_m }
|
||||
export function minimap_grid_half() -> float { return float(mm_cells) * mm_cell_m * 0.5 }
|
||||
export function minimap_cells(minimap_st: MinimapState) -> int { return minimap_st.mm_cells }
|
||||
export function minimap_cell_m(minimap_st: MinimapState) -> float { return minimap_st.mm_cell_m }
|
||||
export function minimap_grid_half(minimap_st: MinimapState) -> float { return float(minimap_st.mm_cells) * minimap_st.mm_cell_m * 0.5 }
|
||||
|
||||
# the grid's west and north edges, and a column's or a row's
|
||||
export function minimap_grid_x0() -> float { return MinimapWorld.origin_x() - minimap_grid_half() }
|
||||
export function minimap_grid_z0() -> float { return MinimapWorld.origin_z() - minimap_grid_half() }
|
||||
export function minimap_cell_x(i: int) -> float { return minimap_grid_x0() + float(i) * mm_cell_m }
|
||||
export function minimap_cell_z(j: int) -> float { return minimap_grid_z0() + float(j) * mm_cell_m }
|
||||
export function minimap_grid_x0(minimap_st: MinimapState) -> float { return MinimapWorld.origin_x() - minimap_grid_half(minimap_st) }
|
||||
export function minimap_grid_z0(minimap_st: MinimapState) -> float { return MinimapWorld.origin_z() - minimap_grid_half(minimap_st) }
|
||||
export function minimap_cell_x(minimap_st: MinimapState, i: int) -> float { return minimap_grid_x0(minimap_st) + float(i) * minimap_st.mm_cell_m }
|
||||
export function minimap_cell_z(minimap_st: MinimapState, j: int) -> float { return minimap_grid_z0(minimap_st) + float(j) * minimap_st.mm_cell_m }
|
||||
|
||||
# the cell a point is in, -1 off the grid
|
||||
export function minimap_cell(x: float, z: float) -> int {
|
||||
let i = int(Math.floor((x - minimap_grid_x0()) / mm_cell_m))
|
||||
let j = int(Math.floor((z - minimap_grid_z0()) / mm_cell_m))
|
||||
if i < 0 or j < 0 or i >= mm_cells or j >= mm_cells { return -1 }
|
||||
return j * mm_cells + i
|
||||
export function minimap_cell(minimap_st: MinimapState, x: float, z: float) -> int {
|
||||
let i = int(Math.floor((x - minimap_grid_x0(minimap_st)) / minimap_st.mm_cell_m))
|
||||
let j = int(Math.floor((z - minimap_grid_z0(minimap_st)) / minimap_st.mm_cell_m))
|
||||
if i < 0 or j < 0 or i >= minimap_st.mm_cells or j >= minimap_st.mm_cells { return -1 }
|
||||
return j * minimap_st.mm_cells + i
|
||||
}
|
||||
|
||||
function mm_grid() -> void { if mm_seen == null { minimap_config(mm_cells, mm_cell_m) } }
|
||||
function mm_grid(minimap_st: mut MinimapState) -> void { if minimap_st.mm_seen == null { minimap_config(minimap_st, minimap_st.mm_cells, minimap_st.mm_cell_m) } }
|
||||
|
|
|
|||
|
|
@ -1,68 +1,68 @@
|
|||
# pin_edit.ludic - changing a mark: its name, symbol and colour, rubbing it out, which one is open
|
||||
# and which followed, and whether the map is waiting for a place to drop the next
|
||||
export function minimap_pin_remove(i: int) -> void {
|
||||
if i < 0 or i >= minimap_pin_count() { return }
|
||||
export function minimap_pin_remove(minimap_st: mut MinimapState, i: int) -> void {
|
||||
if i < 0 or i >= minimap_pin_count(minimap_st) { return }
|
||||
let rest = new []MinimapPin
|
||||
for k in 0 .. len(mm_pins) { if k != i { push(rest, mm_pins[k]) } }
|
||||
mm_pins = rest
|
||||
if mm_open == i { mm_open = -1 } else if mm_open > i { mm_open -= 1 }
|
||||
if mm_followed == i { mm_followed = -1 } else if mm_followed > i { mm_followed -= 1 }
|
||||
for k in 0 .. len(minimap_st.mm_pins) { if k != i { push(rest, minimap_st.mm_pins[k]) } }
|
||||
minimap_st.mm_pins = rest
|
||||
if minimap_st.mm_open == i { minimap_st.mm_open = -1 } else if minimap_st.mm_open > i { minimap_st.mm_open -= 1 }
|
||||
if minimap_st.mm_followed == i { minimap_st.mm_followed = -1 } else if minimap_st.mm_followed > i { minimap_st.mm_followed -= 1 }
|
||||
}
|
||||
|
||||
export function minimap_pin_set_label(i: int, s: string) -> void { if i >= 0 and i < minimap_pin_count() { mm_pins[i].label = s } }
|
||||
export function minimap_pin_set_label(minimap_st: mut MinimapState, i: int, s: string) -> void { if i >= 0 and i < minimap_pin_count(minimap_st) { minimap_st.mm_pins[i].label = s } }
|
||||
|
||||
# the symbol chosen is the one the next mark takes
|
||||
export function minimap_pin_set_icon(i: int, k: int) -> void {
|
||||
if i < 0 or i >= minimap_pin_count() { return }
|
||||
mm_pins[i].icon = Math.clamp(k, 0, mm_symbols - 1)
|
||||
mm_last = mm_pins[i].icon
|
||||
export function minimap_pin_set_icon(minimap_st: mut MinimapState, i: int, k: int) -> void {
|
||||
if i < 0 or i >= minimap_pin_count(minimap_st) { return }
|
||||
minimap_st.mm_pins[i].icon = Math.clamp(k, 0, minimap_st.mm_symbols - 1)
|
||||
minimap_st.mm_last = minimap_st.mm_pins[i].icon
|
||||
}
|
||||
|
||||
export function minimap_pin_set_colour(i: int, k: int) -> void { if i >= 0 and i < minimap_pin_count() { mm_pins[i].colour = Math.clamp(k, 0, mm_colours - 1) } }
|
||||
export function minimap_pin_set_colour(minimap_st: mut MinimapState, i: int, k: int) -> void { if i >= 0 and i < minimap_pin_count(minimap_st) { minimap_st.mm_pins[i].colour = Math.clamp(k, 0, minimap_st.mm_colours - 1) } }
|
||||
|
||||
export function minimap_pin_last_icon() -> int { return mm_last }
|
||||
export function minimap_pin_last_icon(minimap_st: MinimapState) -> int { return minimap_st.mm_last }
|
||||
|
||||
# the mark the map's legend has open, -1 none
|
||||
export function minimap_pin_open() -> int {
|
||||
if mm_open >= minimap_pin_count() { mm_open = -1 }
|
||||
return mm_open
|
||||
export function minimap_pin_open(minimap_st: mut MinimapState) -> int {
|
||||
if minimap_st.mm_open >= minimap_pin_count(minimap_st) { minimap_st.mm_open = -1 }
|
||||
return minimap_st.mm_open
|
||||
}
|
||||
|
||||
export function minimap_pin_select(i: int) -> void {
|
||||
mm_open = -1
|
||||
if i >= 0 and i < minimap_pin_count() { mm_open = i }
|
||||
export function minimap_pin_select(minimap_st: mut MinimapState, i: int) -> void {
|
||||
minimap_st.mm_open = -1
|
||||
if i >= 0 and i < minimap_pin_count(minimap_st) { minimap_st.mm_open = i }
|
||||
}
|
||||
|
||||
# the mark the compass carries, -1 none
|
||||
export function minimap_pin_followed() -> int {
|
||||
if mm_followed >= minimap_pin_count() { mm_followed = -1 }
|
||||
return mm_followed
|
||||
export function minimap_pin_followed(minimap_st: mut MinimapState) -> int {
|
||||
if minimap_st.mm_followed >= minimap_pin_count(minimap_st) { minimap_st.mm_followed = -1 }
|
||||
return minimap_st.mm_followed
|
||||
}
|
||||
|
||||
export function minimap_pin_follow(i: int) -> void {
|
||||
mm_followed = -1
|
||||
if i >= 0 and i < minimap_pin_count() { mm_followed = i }
|
||||
export function minimap_pin_follow(minimap_st: mut MinimapState, i: int) -> void {
|
||||
minimap_st.mm_followed = -1
|
||||
if i >= 0 and i < minimap_pin_count(minimap_st) { minimap_st.mm_followed = i }
|
||||
}
|
||||
|
||||
# follow the open mark, or stop following it
|
||||
export function minimap_pin_follow_toggle() -> void {
|
||||
let i = minimap_pin_open()
|
||||
export function minimap_pin_follow_toggle(minimap_st: mut MinimapState) -> void {
|
||||
let i = minimap_pin_open(minimap_st)
|
||||
if i < 0 { return }
|
||||
if mm_followed == i { mm_followed = -1 } else { mm_followed = i }
|
||||
if minimap_st.mm_followed == i { minimap_st.mm_followed = -1 } else { minimap_st.mm_followed = i }
|
||||
}
|
||||
|
||||
export function minimap_placing() -> bool { return mm_placing }
|
||||
export function minimap_placing(minimap_st: MinimapState) -> bool { return minimap_st.mm_placing }
|
||||
|
||||
# the next press on the map drops a mark; asked again, it does not
|
||||
export function minimap_place_toggle() -> void {
|
||||
mm_placing = not mm_placing
|
||||
mm_open = -1
|
||||
export function minimap_place_toggle(minimap_st: mut MinimapState) -> void {
|
||||
minimap_st.mm_placing = not minimap_st.mm_placing
|
||||
minimap_st.mm_open = -1
|
||||
}
|
||||
|
||||
# the press that drops it, at a point on the window: the new mark is open, -1 if there was no room
|
||||
export function minimap_place(rx: float, ry: float, label: string) -> int {
|
||||
mm_placing = false
|
||||
let i = minimap_pin_add(minimap_wx(rx), minimap_wz(ry), mm_last, label)
|
||||
if i >= 0 { mm_open = i }
|
||||
export function minimap_place(minimap_st: mut MinimapState, rx: float, ry: float, label: string) -> int {
|
||||
minimap_st.mm_placing = false
|
||||
let i = minimap_pin_add(minimap_st, minimap_wx(minimap_st, rx), minimap_wz(minimap_st, ry), minimap_st.mm_last, label)
|
||||
if i >= 0 { minimap_st.mm_open = i }
|
||||
return i
|
||||
}
|
||||
|
|
|
|||
|
|
@ -10,83 +10,75 @@ export property MinimapPin {
|
|||
label: string = ""
|
||||
}
|
||||
|
||||
var mm_pins: []MinimapPin = null
|
||||
var mm_pin_max: int = 32
|
||||
var mm_symbols: int = 8
|
||||
var mm_colours: int = 5
|
||||
var mm_open: int = -1
|
||||
var mm_followed: int = -1
|
||||
var mm_last: int = 0
|
||||
var mm_placing: bool = false
|
||||
|
||||
export function minimap_config_pins(max: int, symbols: int, colours: int) -> void {
|
||||
mm_pin_max = Math.max(max, 1)
|
||||
mm_symbols = Math.max(symbols, 1)
|
||||
mm_colours = Math.max(colours, 1)
|
||||
minimap_pins_clear()
|
||||
export function minimap_config_pins(minimap_st: mut MinimapState, max: int, symbols: int, colours: int) -> void {
|
||||
minimap_st.mm_pin_max = Math.max(max, 1)
|
||||
minimap_st.mm_symbols = Math.max(symbols, 1)
|
||||
minimap_st.mm_colours = Math.max(colours, 1)
|
||||
minimap_pins_clear(minimap_st)
|
||||
}
|
||||
|
||||
export function minimap_pins_clear() -> void {
|
||||
mm_pins = new []MinimapPin
|
||||
mm_open = -1
|
||||
mm_followed = -1
|
||||
mm_last = 0
|
||||
mm_placing = false
|
||||
export function minimap_pins_clear(minimap_st: mut MinimapState) -> void {
|
||||
minimap_st.mm_pins = new []MinimapPin
|
||||
minimap_st.mm_open = -1
|
||||
minimap_st.mm_followed = -1
|
||||
minimap_st.mm_last = 0
|
||||
minimap_st.mm_placing = false
|
||||
}
|
||||
|
||||
export function minimap_pin_count() -> int {
|
||||
if mm_pins == null { return 0 }
|
||||
return len(mm_pins)
|
||||
export function minimap_pin_count(minimap_st: MinimapState) -> int {
|
||||
if minimap_st.mm_pins == null { return 0 }
|
||||
return len(minimap_st.mm_pins)
|
||||
}
|
||||
|
||||
export function minimap_pin_max() -> int { return mm_pin_max }
|
||||
export function minimap_pin_full() -> bool { return minimap_pin_count() >= mm_pin_max }
|
||||
export function minimap_pin_max(minimap_st: MinimapState) -> int { return minimap_st.mm_pin_max }
|
||||
export function minimap_pin_full(minimap_st: MinimapState) -> bool { return minimap_pin_count(minimap_st) >= minimap_st.mm_pin_max }
|
||||
|
||||
# a mark at (x, z) made today, with the colour 0; -1 when the map holds all it will
|
||||
export function minimap_pin_add(x: float, z: float, icon: int, label: string) -> int {
|
||||
if mm_pins == null { minimap_pins_clear() }
|
||||
if minimap_pin_full() { return -1 }
|
||||
export function minimap_pin_add(minimap_st: mut MinimapState, x: float, z: float, icon: int, label: string) -> int {
|
||||
if minimap_st.mm_pins == null { minimap_pins_clear(minimap_st) }
|
||||
if minimap_pin_full(minimap_st) { return -1 }
|
||||
let p = new MinimapPin
|
||||
p.x = x
|
||||
p.z = z
|
||||
p.icon = Math.clamp(icon, 0, mm_symbols - 1)
|
||||
p.icon = Math.clamp(icon, 0, minimap_st.mm_symbols - 1)
|
||||
p.day = MinimapWorld.day()
|
||||
p.label = label
|
||||
push(mm_pins, p)
|
||||
mm_last = p.icon
|
||||
return len(mm_pins) - 1
|
||||
push(minimap_st.mm_pins, p)
|
||||
minimap_st.mm_last = p.icon
|
||||
return len(minimap_st.mm_pins) - 1
|
||||
}
|
||||
|
||||
# as saved: everything given, the symbol last chosen left alone
|
||||
export function minimap_pin_put(x: float, z: float, icon: int, colour: int, day: int, label: string) -> int {
|
||||
if mm_pins == null { minimap_pins_clear() }
|
||||
if minimap_pin_full() { return -1 }
|
||||
export function minimap_pin_put(minimap_st: mut MinimapState, x: float, z: float, icon: int, colour: int, day: int, label: string) -> int {
|
||||
if minimap_st.mm_pins == null { minimap_pins_clear(minimap_st) }
|
||||
if minimap_pin_full(minimap_st) { return -1 }
|
||||
let p = new MinimapPin
|
||||
p.x = x
|
||||
p.z = z
|
||||
p.icon = Math.clamp(icon, 0, mm_symbols - 1)
|
||||
p.colour = Math.clamp(colour, 0, mm_colours - 1)
|
||||
p.icon = Math.clamp(icon, 0, minimap_st.mm_symbols - 1)
|
||||
p.colour = Math.clamp(colour, 0, minimap_st.mm_colours - 1)
|
||||
p.day = day
|
||||
p.label = label
|
||||
push(mm_pins, p)
|
||||
return len(mm_pins) - 1
|
||||
push(minimap_st.mm_pins, p)
|
||||
return len(minimap_st.mm_pins) - 1
|
||||
}
|
||||
|
||||
# the i-th mark, or an empty one past the end
|
||||
export function minimap_pin(i: int) -> MinimapPin {
|
||||
if i < 0 or i >= minimap_pin_count() { return new MinimapPin }
|
||||
return mm_pins[i]
|
||||
export function minimap_pin(minimap_st: MinimapState, i: int) -> MinimapPin {
|
||||
if i < 0 or i >= minimap_pin_count(minimap_st) { return new MinimapPin }
|
||||
return minimap_st.mm_pins[i]
|
||||
}
|
||||
|
||||
# the nearest n marks within `within` of (x, z), nearest first, leaving out the followed one
|
||||
export function minimap_pins_near(x: float, z: float, n: int, within: float) -> []int {
|
||||
export function minimap_pins_near(minimap_st: MinimapState, x: float, z: float, n: int, within: float) -> []int {
|
||||
let out = new []int
|
||||
for k in 0 .. n {
|
||||
var best = -1
|
||||
var bd = within * within
|
||||
for i in 0 .. minimap_pin_count() {
|
||||
if i == mm_followed or mm_has(out, i) { continue }
|
||||
let d = (mm_pins[i].x - x) * (mm_pins[i].x - x) + (mm_pins[i].z - z) * (mm_pins[i].z - z)
|
||||
for i in 0 .. minimap_pin_count(minimap_st) {
|
||||
if i == minimap_st.mm_followed or mm_has(out, i) { continue }
|
||||
let d = (minimap_st.mm_pins[i].x - x) * (minimap_st.mm_pins[i].x - x) + (minimap_st.mm_pins[i].z - z) * (minimap_st.mm_pins[i].z - z)
|
||||
if d < bd {
|
||||
bd = d
|
||||
best = i
|
||||
|
|
|
|||
|
|
@ -1,20 +1,20 @@
|
|||
# system.ludic - the map as a system: what has been seen and the marks, in its own save section by
|
||||
# key. The view is where the player left it this session and is not saved.
|
||||
export function minimap_reset() -> void {
|
||||
mm_grid()
|
||||
for c in 0 .. len(mm_seen) { mm_seen[c] = 0 }
|
||||
mm_version += 1
|
||||
minimap_pins_clear()
|
||||
mm_have_view = false
|
||||
mm_panning = false
|
||||
export function minimap_reset(minimap_st: mut MinimapState) -> void {
|
||||
mm_grid(minimap_st)
|
||||
for c in 0 .. len(minimap_st.mm_seen) { minimap_st.mm_seen[c] = 0 }
|
||||
minimap_st.mm_version += 1
|
||||
minimap_pins_clear(minimap_st)
|
||||
minimap_st.mm_have_view = false
|
||||
minimap_st.mm_panning = false
|
||||
}
|
||||
|
||||
export function minimap_save() -> Val {
|
||||
export function minimap_save(minimap_st: mut MinimapState) -> Val {
|
||||
let v = Value.object()
|
||||
sv_put_str(v, "seen", minimap_seen_text())
|
||||
sv_put_str(v, "seen", minimap_seen_text(minimap_st))
|
||||
let l = Value.list()
|
||||
for i in 0 .. minimap_pin_count() {
|
||||
let p = mm_pins[i]
|
||||
for i in 0 .. minimap_pin_count(minimap_st) {
|
||||
let p = minimap_st.mm_pins[i]
|
||||
let o = Value.object()
|
||||
sv_put_float(o, "x", p.x)
|
||||
sv_put_float(o, "z", p.z)
|
||||
|
|
@ -25,23 +25,23 @@ export function minimap_save() -> Val {
|
|||
Value.add(l, o)
|
||||
}
|
||||
Value.put(v, "pins", l)
|
||||
sv_put_int(v, "followed", minimap_pin_followed())
|
||||
sv_put_int(v, "last", mm_last)
|
||||
sv_put_int(v, "followed", minimap_pin_followed(minimap_st))
|
||||
sv_put_int(v, "last", minimap_st.mm_last)
|
||||
return v
|
||||
}
|
||||
|
||||
export function minimap_load(v: Val, version: int) -> void {
|
||||
minimap_reset()
|
||||
minimap_seen_from_text(sv_str(v, "seen", ""))
|
||||
export function minimap_load(minimap_st: mut MinimapState, v: Val, version: int) -> void {
|
||||
minimap_reset(minimap_st)
|
||||
minimap_seen_from_text(minimap_st, sv_str(v, "seen", ""))
|
||||
if Value.has(v, "pins") != 0 {
|
||||
let l = Value.get(v, "pins")
|
||||
for i in 0 .. Value.count(l) {
|
||||
let o = Value.at(l, i)
|
||||
minimap_pin_put(sv_float(o, "x", 0.0), sv_float(o, "z", 0.0), sv_int(o, "icon", 0), sv_int(o, "colour", 0), sv_int(o, "day", 1), sv_str(o, "label", ""))
|
||||
minimap_pin_put(minimap_st, sv_float(o, "x", 0.0), sv_float(o, "z", 0.0), sv_int(o, "icon", 0), sv_int(o, "colour", 0), sv_int(o, "day", 1), sv_str(o, "label", ""))
|
||||
}
|
||||
}
|
||||
minimap_pin_follow(sv_int(v, "followed", -1))
|
||||
mm_last = Math.clamp(sv_int(v, "last", 0), 0, mm_symbols - 1)
|
||||
minimap_pin_follow(minimap_st, sv_int(v, "followed", -1))
|
||||
minimap_st.mm_last = Math.clamp(sv_int(v, "last", 0), 0, minimap_st.mm_symbols - 1)
|
||||
}
|
||||
|
||||
export function minimap_system() -> System {
|
||||
|
|
|
|||
|
|
@ -6,187 +6,189 @@ import "ludic.base"
|
|||
program MinimapTest {
|
||||
numbers float
|
||||
|
||||
var you_x: float = 100.0
|
||||
var you_z: float = 100.0
|
||||
var day: int = 3
|
||||
state MinimapTestState {
|
||||
you_x: float = 100.0
|
||||
you_z: float = 100.0
|
||||
}
|
||||
let day: int = 3
|
||||
|
||||
function fk_ox() -> float { return 100.0 }
|
||||
function fk_land(x: float, z: float) -> bool { return x >= 50.0 }
|
||||
function fk_you_x() -> float { return you_x }
|
||||
function fk_you_z() -> float { return you_z }
|
||||
function fk_you_x(minimap_test_st: MinimapTestState) -> float { return minimap_test_st.you_x }
|
||||
function fk_you_z(minimap_test_st: MinimapTestState) -> float { return minimap_test_st.you_z }
|
||||
function fk_camp() -> float { return 120.0 }
|
||||
function fk_day() -> int { return day }
|
||||
function fk_lo() -> float { return 0.0 }
|
||||
function fk_hi() -> float { return 200.0 }
|
||||
bind MinimapWorld { origin_x: fn fk_ox, origin_z: fn fk_ox, land: fn fk_land, you_x: fn fk_you_x, you_z: fn fk_you_z, camp_x: fn fk_camp, camp_z: fn fk_camp, day: fn fk_day, lo_x: fn fk_lo, lo_z: fn fk_lo, hi_x: fn fk_hi, hi_z: fn fk_hi }
|
||||
|
||||
function fresh() -> void {
|
||||
minimap_config(20, 10.0)
|
||||
minimap_config_pins(3, 8, 5)
|
||||
minimap_config_view(200.0, 0.5, 8.0, 4.0)
|
||||
minimap_window(0.0, 0.0, 400.0)
|
||||
minimap_reset()
|
||||
you_x = 100.0
|
||||
you_z = 100.0
|
||||
function fresh(minimap_st: mut MinimapState, minimap_test_st: mut MinimapTestState) -> void {
|
||||
minimap_config(minimap_st, 20, 10.0)
|
||||
minimap_config_pins(minimap_st, 3, 8, 5)
|
||||
minimap_config_view(minimap_st, 200.0, 0.5, 8.0, 4.0)
|
||||
minimap_window(minimap_st, 0.0, 0.0, 400.0)
|
||||
minimap_reset(minimap_st)
|
||||
minimap_test_st.you_x = 100.0
|
||||
minimap_test_st.you_z = 100.0
|
||||
}
|
||||
|
||||
test "the grid sits round its origin, and a point has its cell" {
|
||||
fresh()
|
||||
expect_near(minimap_grid_x0(), 0.0, 0.001)
|
||||
expect_eq(minimap_cell(5.0, 5.0), 0)
|
||||
expect_eq(minimap_cell(15.0, 25.0), 41)
|
||||
expect_eq(minimap_cell(-1.0, 5.0), -1)
|
||||
expect_eq(minimap_cell(200.0, 5.0), -1)
|
||||
test "the grid sits round its origin, and a point has its cell" (minimap_st: mut MinimapState, minimap_test_st: mut MinimapTestState) {
|
||||
fresh(minimap_st, minimap_test_st)
|
||||
expect_near(minimap_grid_x0(minimap_st), 0.0, 0.001)
|
||||
expect_eq(minimap_cell(minimap_st, 5.0, 5.0), 0)
|
||||
expect_eq(minimap_cell(minimap_st, 15.0, 25.0), 41)
|
||||
expect_eq(minimap_cell(minimap_st, -1.0, 5.0), -1)
|
||||
expect_eq(minimap_cell(minimap_st, 200.0, 5.0), -1)
|
||||
}
|
||||
|
||||
test "walking reveals the cells within reach, and explored counts the land only" {
|
||||
fresh()
|
||||
let v0 = minimap_version()
|
||||
minimap_reveal(105.0, 105.0, 10.0)
|
||||
expect(minimap_seen_at(105.0, 105.0))
|
||||
expect(minimap_seen_at(95.0, 105.0))
|
||||
expect(not minimap_seen_at(125.0, 105.0))
|
||||
expect_eq(minimap_seen_count(), 9)
|
||||
expect(minimap_version() > v0)
|
||||
let v1 = minimap_version()
|
||||
minimap_reveal(105.0, 105.0, 10.0)
|
||||
expect_eq(minimap_version(), v1)
|
||||
expect_eq(minimap_explored_pct(), 3)
|
||||
minimap_reveal(5.0, 5.0, 0.0)
|
||||
expect_eq(minimap_explored_pct(), 3)
|
||||
minimap_config_core(5, 10)
|
||||
minimap_land_changed()
|
||||
expect_eq(minimap_explored_pct(), 9)
|
||||
test "walking reveals the cells within reach, and explored counts the land only" (minimap_st: mut MinimapState, minimap_test_st: mut MinimapTestState) {
|
||||
fresh(minimap_st, minimap_test_st)
|
||||
let v0 = minimap_version(minimap_st)
|
||||
minimap_reveal(minimap_st, 105.0, 105.0, 10.0)
|
||||
expect(minimap_seen_at(minimap_st, 105.0, 105.0))
|
||||
expect(minimap_seen_at(minimap_st, 95.0, 105.0))
|
||||
expect(not minimap_seen_at(minimap_st, 125.0, 105.0))
|
||||
expect_eq(minimap_seen_count(minimap_st), 9)
|
||||
expect(minimap_version(minimap_st) > v0)
|
||||
let v1 = minimap_version(minimap_st)
|
||||
minimap_reveal(minimap_st, 105.0, 105.0, 10.0)
|
||||
expect_eq(minimap_version(minimap_st), v1)
|
||||
expect_eq(minimap_explored_pct(minimap_st), 3)
|
||||
minimap_reveal(minimap_st, 5.0, 5.0, 0.0)
|
||||
expect_eq(minimap_explored_pct(minimap_st), 3)
|
||||
minimap_config_core(minimap_st, 5, 10)
|
||||
minimap_land_changed(minimap_st)
|
||||
expect_eq(minimap_explored_pct(minimap_st), 9)
|
||||
}
|
||||
|
||||
test "a mark is made today with the last symbol, and the map holds only so many" {
|
||||
fresh()
|
||||
expect_eq(minimap_pin_add(10.0, 20.0, 2, "pool"), 0)
|
||||
expect_eq(minimap_pin(0).day, 3)
|
||||
expect_eq(minimap_pin_last_icon(), 2)
|
||||
expect_eq(minimap_pin_add(30.0, 20.0, 99, "rock"), 1)
|
||||
expect_eq(minimap_pin(1).icon, 7)
|
||||
expect_eq(minimap_pin_add(50.0, 20.0, 0, "bend"), 2)
|
||||
expect(minimap_pin_full())
|
||||
expect_eq(minimap_pin_add(60.0, 20.0, 0, "one more"), -1)
|
||||
expect_eq(minimap_pin_count(), 3)
|
||||
test "a mark is made today with the last symbol, and the map holds only so many" (minimap_st: mut MinimapState, minimap_test_st: mut MinimapTestState) {
|
||||
fresh(minimap_st, minimap_test_st)
|
||||
expect_eq(minimap_pin_add(minimap_st, 10.0, 20.0, 2, "pool"), 0)
|
||||
expect_eq(minimap_pin(minimap_st, 0).day, 3)
|
||||
expect_eq(minimap_pin_last_icon(minimap_st), 2)
|
||||
expect_eq(minimap_pin_add(minimap_st, 30.0, 20.0, 99, "rock"), 1)
|
||||
expect_eq(minimap_pin(minimap_st, 1).icon, 7)
|
||||
expect_eq(minimap_pin_add(minimap_st, 50.0, 20.0, 0, "bend"), 2)
|
||||
expect(minimap_pin_full(minimap_st))
|
||||
expect_eq(minimap_pin_add(minimap_st, 60.0, 20.0, 0, "one more"), -1)
|
||||
expect_eq(minimap_pin_count(minimap_st), 3)
|
||||
}
|
||||
|
||||
test "the open mark is named, coloured and followed, and rubbing one out moves the others up" {
|
||||
fresh()
|
||||
minimap_pin_add(10.0, 20.0, 0, "a")
|
||||
minimap_pin_add(30.0, 20.0, 0, "b")
|
||||
minimap_pin_add(50.0, 20.0, 0, "c")
|
||||
minimap_pin_select(2)
|
||||
minimap_pin_follow_toggle()
|
||||
expect_eq(minimap_pin_followed(), 2)
|
||||
minimap_pin_set_label(2, "deer pool")
|
||||
minimap_pin_set_colour(2, 9)
|
||||
minimap_pin_set_icon(2, 3)
|
||||
expect(minimap_pin(2).label == "deer pool")
|
||||
expect_eq(minimap_pin(2).colour, 4)
|
||||
expect_eq(minimap_pin_last_icon(), 3)
|
||||
minimap_pin_remove(0)
|
||||
expect_eq(minimap_pin_count(), 2)
|
||||
expect_eq(minimap_pin_open(), 1)
|
||||
expect_eq(minimap_pin_followed(), 1)
|
||||
minimap_pin_remove(1)
|
||||
expect_eq(minimap_pin_open(), -1)
|
||||
expect_eq(minimap_pin_followed(), -1)
|
||||
test "the open mark is named, coloured and followed, and rubbing one out moves the others up" (minimap_st: mut MinimapState, minimap_test_st: mut MinimapTestState) {
|
||||
fresh(minimap_st, minimap_test_st)
|
||||
minimap_pin_add(minimap_st, 10.0, 20.0, 0, "a")
|
||||
minimap_pin_add(minimap_st, 30.0, 20.0, 0, "b")
|
||||
minimap_pin_add(minimap_st, 50.0, 20.0, 0, "c")
|
||||
minimap_pin_select(minimap_st, 2)
|
||||
minimap_pin_follow_toggle(minimap_st)
|
||||
expect_eq(minimap_pin_followed(minimap_st), 2)
|
||||
minimap_pin_set_label(minimap_st, 2, "deer pool")
|
||||
minimap_pin_set_colour(minimap_st, 2, 9)
|
||||
minimap_pin_set_icon(minimap_st, 2, 3)
|
||||
expect(minimap_pin(minimap_st, 2).label == "deer pool")
|
||||
expect_eq(minimap_pin(minimap_st, 2).colour, 4)
|
||||
expect_eq(minimap_pin_last_icon(minimap_st), 3)
|
||||
minimap_pin_remove(minimap_st, 0)
|
||||
expect_eq(minimap_pin_count(minimap_st), 2)
|
||||
expect_eq(minimap_pin_open(minimap_st), 1)
|
||||
expect_eq(minimap_pin_followed(minimap_st), 1)
|
||||
minimap_pin_remove(minimap_st, 1)
|
||||
expect_eq(minimap_pin_open(minimap_st), -1)
|
||||
expect_eq(minimap_pin_followed(minimap_st), -1)
|
||||
}
|
||||
|
||||
test "the nearest marks for a compass leave out the followed one and anything too far" {
|
||||
fresh()
|
||||
minimap_config_pins(8, 8, 5)
|
||||
minimap_pin_add(110.0, 100.0, 0, "near")
|
||||
minimap_pin_add(130.0, 100.0, 0, "next")
|
||||
minimap_pin_add(105.0, 100.0, 0, "followed")
|
||||
minimap_pin_add(900.0, 100.0, 0, "far")
|
||||
minimap_pin_follow(2)
|
||||
let near = minimap_pins_near(100.0, 100.0, 3, 400.0)
|
||||
test "the nearest marks for a compass leave out the followed one and anything too far" (minimap_st: mut MinimapState, minimap_test_st: mut MinimapTestState) {
|
||||
fresh(minimap_st, minimap_test_st)
|
||||
minimap_config_pins(minimap_st, 8, 8, 5)
|
||||
minimap_pin_add(minimap_st, 110.0, 100.0, 0, "near")
|
||||
minimap_pin_add(minimap_st, 130.0, 100.0, 0, "next")
|
||||
minimap_pin_add(minimap_st, 105.0, 100.0, 0, "followed")
|
||||
minimap_pin_add(minimap_st, 900.0, 100.0, 0, "far")
|
||||
minimap_pin_follow(minimap_st, 2)
|
||||
let near = minimap_pins_near(minimap_st, 100.0, 100.0, 3, 400.0)
|
||||
expect_eq(len(near), 2)
|
||||
expect_eq(near[0], 0)
|
||||
expect_eq(near[1], 1)
|
||||
}
|
||||
|
||||
test "the view: the world on the window and back, zoom about a point, a pan, focus and the clamp" {
|
||||
fresh()
|
||||
minimap_centre(100.0, 100.0)
|
||||
expect_near(minimap_px(100.0), 200.0, 0.01)
|
||||
expect_near(minimap_px(150.0), 300.0, 0.01)
|
||||
expect_near(minimap_wx(300.0), 150.0, 0.01)
|
||||
minimap_zoom_about(300.0, 200.0, 2.0)
|
||||
expect_near(minimap_zoom(), 2.0, 0.001)
|
||||
expect_near(minimap_wx(300.0), 150.0, 0.01)
|
||||
expect_near(minimap_span(), 100.0, 0.01)
|
||||
minimap_pan_begin(200.0, 200.0)
|
||||
minimap_pan_to(160.0, 200.0)
|
||||
expect_near(minimap_view_x(), 135.0, 0.01)
|
||||
minimap_pan_end()
|
||||
minimap_pan_to(0.0, 0.0)
|
||||
expect_near(minimap_view_x(), 135.0, 0.01)
|
||||
minimap_centre(900.0, -5.0)
|
||||
expect_near(minimap_view_x(), 200.0, 0.01)
|
||||
expect_near(minimap_view_z(), 0.0, 0.01)
|
||||
minimap_focus(false)
|
||||
expect_near(minimap_view_x(), 120.0, 0.01)
|
||||
expect_near(minimap_zoom(), 4.0, 0.001)
|
||||
minimap_zoom_set(6.0)
|
||||
you_x = 80.0
|
||||
minimap_focus(true)
|
||||
expect_near(minimap_view_x(), 80.0, 0.01)
|
||||
expect_near(minimap_zoom(), 6.0, 0.001)
|
||||
minimap_zoom_step(1)
|
||||
expect_near(minimap_zoom(), 7.8, 0.001)
|
||||
minimap_zoom_step(1)
|
||||
expect_near(minimap_zoom(), 8.0, 0.001)
|
||||
test "the view: the world on the window and back, zoom about a point, a pan, focus and the clamp" (minimap_st: mut MinimapState, minimap_test_st: mut MinimapTestState) {
|
||||
fresh(minimap_st, minimap_test_st)
|
||||
minimap_centre(minimap_st, 100.0, 100.0)
|
||||
expect_near(minimap_px(minimap_st, 100.0), 200.0, 0.01)
|
||||
expect_near(minimap_px(minimap_st, 150.0), 300.0, 0.01)
|
||||
expect_near(minimap_wx(minimap_st, 300.0), 150.0, 0.01)
|
||||
minimap_zoom_about(minimap_st, 300.0, 200.0, 2.0)
|
||||
expect_near(minimap_zoom(minimap_st), 2.0, 0.001)
|
||||
expect_near(minimap_wx(minimap_st, 300.0), 150.0, 0.01)
|
||||
expect_near(minimap_span(minimap_st), 100.0, 0.01)
|
||||
minimap_pan_begin(minimap_st, 200.0, 200.0)
|
||||
minimap_pan_to(minimap_st, 160.0, 200.0)
|
||||
expect_near(minimap_view_x(minimap_st), 135.0, 0.01)
|
||||
minimap_pan_end(minimap_st)
|
||||
minimap_pan_to(minimap_st, 0.0, 0.0)
|
||||
expect_near(minimap_view_x(minimap_st), 135.0, 0.01)
|
||||
minimap_centre(minimap_st, 900.0, -5.0)
|
||||
expect_near(minimap_view_x(minimap_st), 200.0, 0.01)
|
||||
expect_near(minimap_view_z(minimap_st), 0.0, 0.01)
|
||||
minimap_focus(minimap_st, false)
|
||||
expect_near(minimap_view_x(minimap_st), 120.0, 0.01)
|
||||
expect_near(minimap_zoom(minimap_st), 4.0, 0.001)
|
||||
minimap_zoom_set(minimap_st, 6.0)
|
||||
minimap_test_st.you_x = 80.0
|
||||
minimap_focus(minimap_st, true)
|
||||
expect_near(minimap_view_x(minimap_st), 80.0, 0.01)
|
||||
expect_near(minimap_zoom(minimap_st), 6.0, 0.001)
|
||||
minimap_zoom_step(minimap_st, 1)
|
||||
expect_near(minimap_zoom(minimap_st), 7.8, 0.001)
|
||||
minimap_zoom_step(minimap_st, 1)
|
||||
expect_near(minimap_zoom(minimap_st), 8.0, 0.001)
|
||||
}
|
||||
|
||||
test "a press picks the mark under it, and placing drops one where the press lands" {
|
||||
fresh()
|
||||
minimap_centre(100.0, 100.0)
|
||||
minimap_pin_add(150.0, 100.0, 4, "here")
|
||||
expect_eq(minimap_pick(301.0, 199.0, 18.0), 0)
|
||||
expect_eq(minimap_pin_open(), 0)
|
||||
expect_eq(minimap_pick(10.0, 10.0, 18.0), -1)
|
||||
minimap_place_toggle()
|
||||
expect(minimap_placing())
|
||||
let i = minimap_place(100.0, 200.0, "Day 3")
|
||||
test "a press picks the mark under it, and placing drops one where the press lands" (minimap_st: mut MinimapState, minimap_test_st: mut MinimapTestState) {
|
||||
fresh(minimap_st, minimap_test_st)
|
||||
minimap_centre(minimap_st, 100.0, 100.0)
|
||||
minimap_pin_add(minimap_st, 150.0, 100.0, 4, "here")
|
||||
expect_eq(minimap_pick(minimap_st, 301.0, 199.0, 18.0), 0)
|
||||
expect_eq(minimap_pin_open(minimap_st), 0)
|
||||
expect_eq(minimap_pick(minimap_st, 10.0, 10.0, 18.0), -1)
|
||||
minimap_place_toggle(minimap_st)
|
||||
expect(minimap_placing(minimap_st))
|
||||
let i = minimap_place(minimap_st, 100.0, 200.0, "Day 3")
|
||||
expect_eq(i, 1)
|
||||
expect(not minimap_placing())
|
||||
expect_near(minimap_pin(1).x, 50.0, 0.01)
|
||||
expect_eq(minimap_pin(1).icon, 4)
|
||||
expect_eq(minimap_pin_open(), 1)
|
||||
expect(not minimap_placing(minimap_st))
|
||||
expect_near(minimap_pin(minimap_st, 1).x, 50.0, 0.01)
|
||||
expect_eq(minimap_pin(minimap_st, 1).icon, 4)
|
||||
expect_eq(minimap_pin_open(minimap_st), 1)
|
||||
}
|
||||
|
||||
test "a scale bar is a round distance no wider than a quarter of the window" {
|
||||
fresh()
|
||||
expect_eq(minimap_scale_metres(), 50)
|
||||
minimap_zoom_set(8.0)
|
||||
expect_eq(minimap_scale_metres(), 25)
|
||||
test "a scale bar is a round distance no wider than a quarter of the window" (minimap_st: mut MinimapState, minimap_test_st: mut MinimapTestState) {
|
||||
fresh(minimap_st, minimap_test_st)
|
||||
expect_eq(minimap_scale_metres(minimap_st), 50)
|
||||
minimap_zoom_set(minimap_st, 8.0)
|
||||
expect_eq(minimap_scale_metres(minimap_st), 25)
|
||||
}
|
||||
|
||||
test "what was seen and the marks come back from the save, and a missing section is a reset" {
|
||||
fresh()
|
||||
minimap_reveal(105.0, 105.0, 10.0)
|
||||
minimap_pin_add(10.0, 20.0, 2, "pool")
|
||||
minimap_pin_add(30.5, 20.25, 5, "rock")
|
||||
minimap_pin_set_colour(1, 3)
|
||||
minimap_pin_follow(1)
|
||||
let v = minimap_save()
|
||||
minimap_reset()
|
||||
expect_eq(minimap_seen_count(), 0)
|
||||
minimap_load(v, 1)
|
||||
expect_eq(minimap_seen_count(), 9)
|
||||
expect_eq(minimap_pin_count(), 2)
|
||||
expect(minimap_pin(1).label == "rock")
|
||||
expect_near(minimap_pin(1).x, 30.5, 0.001)
|
||||
expect_eq(minimap_pin(1).colour, 3)
|
||||
expect_eq(minimap_pin_followed(), 1)
|
||||
expect_eq(minimap_pin_last_icon(), 5)
|
||||
minimap_seen_from_text("0011")
|
||||
expect_eq(minimap_seen_count(), 2)
|
||||
let t = minimap_seen_text()
|
||||
test "what was seen and the marks come back from the save, and a missing section is a reset" (minimap_st: mut MinimapState, minimap_test_st: mut MinimapTestState) {
|
||||
fresh(minimap_st, minimap_test_st)
|
||||
minimap_reveal(minimap_st, 105.0, 105.0, 10.0)
|
||||
minimap_pin_add(minimap_st, 10.0, 20.0, 2, "pool")
|
||||
minimap_pin_add(minimap_st, 30.5, 20.25, 5, "rock")
|
||||
minimap_pin_set_colour(minimap_st, 1, 3)
|
||||
minimap_pin_follow(minimap_st, 1)
|
||||
let v = minimap_save(minimap_st)
|
||||
minimap_reset(minimap_st)
|
||||
expect_eq(minimap_seen_count(minimap_st), 0)
|
||||
minimap_load(minimap_st, v, 1)
|
||||
expect_eq(minimap_seen_count(minimap_st), 9)
|
||||
expect_eq(minimap_pin_count(minimap_st), 2)
|
||||
expect(minimap_pin(minimap_st, 1).label == "rock")
|
||||
expect_near(minimap_pin(minimap_st, 1).x, 30.5, 0.001)
|
||||
expect_eq(minimap_pin(minimap_st, 1).colour, 3)
|
||||
expect_eq(minimap_pin_followed(minimap_st), 1)
|
||||
expect_eq(minimap_pin_last_icon(minimap_st), 5)
|
||||
minimap_seen_from_text(minimap_st, "0011")
|
||||
expect_eq(minimap_seen_count(minimap_st), 2)
|
||||
let t = minimap_seen_text(minimap_st)
|
||||
expect_eq(len(t), 400)
|
||||
expect(t[0..4] == "0011")
|
||||
}
|
||||
|
|
|
|||
|
|
@ -1,81 +1,70 @@
|
|||
# view.ludic - the window onto the map: a square of `size` pixels at (x0, y0) showing `span` metres
|
||||
# across at zoom 1, centred on a world point. World to window and back, and a scale bar's length.
|
||||
var mm_x0: float = 0.0
|
||||
var mm_y0: float = 0.0
|
||||
var mm_size: float = 512.0
|
||||
var mm_span: float = 6400.0
|
||||
var mm_zoom_min: float = 0.5
|
||||
var mm_zoom_max: float = 8.0
|
||||
var mm_zoom_focus: float = 4.0
|
||||
var mm_zoom: float = 1.0
|
||||
var mm_vx: float = 0.0
|
||||
var mm_vz: float = 0.0
|
||||
var mm_have_view: bool = false
|
||||
|
||||
# metres across the window at zoom 1, the zoom's range, and how close a focus goes at least
|
||||
export function minimap_config_view(span: float, zoom_min: float, zoom_max: float, focus: float) -> void {
|
||||
mm_span = Math.max(span, 1.0)
|
||||
mm_zoom_min = zoom_min
|
||||
mm_zoom_max = Math.max(zoom_max, zoom_min)
|
||||
mm_zoom_focus = focus
|
||||
mm_zoom = Math.clamp(1.0, mm_zoom_min, mm_zoom_max)
|
||||
mm_have_view = false
|
||||
export function minimap_config_view(minimap_st: mut MinimapState, span: float, zoom_min: float, zoom_max: float, focus: float) -> void {
|
||||
minimap_st.mm_span = Math.max(span, 1.0)
|
||||
minimap_st.mm_zoom_min = zoom_min
|
||||
minimap_st.mm_zoom_max = Math.max(zoom_max, zoom_min)
|
||||
minimap_st.mm_zoom_focus = focus
|
||||
minimap_st.mm_zoom = Math.clamp(1.0, minimap_st.mm_zoom_min, minimap_st.mm_zoom_max)
|
||||
minimap_st.mm_have_view = false
|
||||
}
|
||||
|
||||
# where the window is on the screen this frame
|
||||
export function minimap_window(x0: float, y0: float, size: float) -> void {
|
||||
mm_x0 = x0
|
||||
mm_y0 = y0
|
||||
mm_size = Math.max(size, 1.0)
|
||||
export function minimap_window(minimap_st: mut MinimapState, x0: float, y0: float, size: float) -> void {
|
||||
minimap_st.mm_x0 = x0
|
||||
minimap_st.mm_y0 = y0
|
||||
minimap_st.mm_size = Math.max(size, 1.0)
|
||||
}
|
||||
|
||||
export function minimap_size() -> float { return mm_size }
|
||||
export function minimap_zoom() -> float { return mm_zoom }
|
||||
export function minimap_view_x() -> float { return mm_vx }
|
||||
export function minimap_view_z() -> float { return mm_vz }
|
||||
export function minimap_have_view() -> bool { return mm_have_view }
|
||||
export function minimap_size(minimap_st: MinimapState) -> float { return minimap_st.mm_size }
|
||||
export function minimap_zoom(minimap_st: MinimapState) -> float { return minimap_st.mm_zoom }
|
||||
export function minimap_view_x(minimap_st: MinimapState) -> float { return minimap_st.mm_vx }
|
||||
export function minimap_view_z(minimap_st: MinimapState) -> float { return minimap_st.mm_vz }
|
||||
export function minimap_have_view(minimap_st: MinimapState) -> bool { return minimap_st.mm_have_view }
|
||||
|
||||
# the metres the window shows across at the zoom
|
||||
export function minimap_span() -> float { return mm_span / mm_zoom }
|
||||
export function minimap_span(minimap_st: MinimapState) -> float { return minimap_st.mm_span / minimap_st.mm_zoom }
|
||||
|
||||
# pixels per metre
|
||||
export function minimap_scale() -> float { return mm_size / minimap_span() }
|
||||
export function minimap_scale(minimap_st: MinimapState) -> float { return minimap_st.mm_size / minimap_span(minimap_st) }
|
||||
|
||||
# a world point on the screen
|
||||
export function minimap_px(x: float) -> float { return mm_x0 + mm_size * 0.5 + (x - mm_vx) * minimap_scale() }
|
||||
export function minimap_py(z: float) -> float { return mm_y0 + mm_size * 0.5 + (z - mm_vz) * minimap_scale() }
|
||||
export function minimap_px(minimap_st: MinimapState, x: float) -> float { return minimap_st.mm_x0 + minimap_st.mm_size * 0.5 + (x - minimap_st.mm_vx) * minimap_scale(minimap_st) }
|
||||
export function minimap_py(minimap_st: MinimapState, z: float) -> float { return minimap_st.mm_y0 + minimap_st.mm_size * 0.5 + (z - minimap_st.mm_vz) * minimap_scale(minimap_st) }
|
||||
|
||||
# the world under a point of the window (pixels from its corner)
|
||||
export function minimap_wx(rx: float) -> float { return mm_vx + (rx - mm_size * 0.5) / minimap_scale() }
|
||||
export function minimap_wz(ry: float) -> float { return mm_vz + (ry - mm_size * 0.5) / minimap_scale() }
|
||||
export function minimap_wx(minimap_st: MinimapState, rx: float) -> float { return minimap_st.mm_vx + (rx - minimap_st.mm_size * 0.5) / minimap_scale(minimap_st) }
|
||||
export function minimap_wz(minimap_st: MinimapState, ry: float) -> float { return minimap_st.mm_vz + (ry - minimap_st.mm_size * 0.5) / minimap_scale(minimap_st) }
|
||||
|
||||
# a round distance whose bar is no wider than a quarter of the window
|
||||
export function minimap_scale_metres() -> int {
|
||||
export function minimap_scale_metres(minimap_st: MinimapState) -> int {
|
||||
let steps = [2000, 1000, 500, 250, 100, 50, 25]
|
||||
for k in 0 .. len(steps) { if float(steps[k]) * minimap_scale() <= mm_size / 4.0 { return steps[k] } }
|
||||
for k in 0 .. len(steps) { if float(steps[k]) * minimap_scale(minimap_st) <= minimap_st.mm_size / 4.0 { return steps[k] } }
|
||||
return 25
|
||||
}
|
||||
|
||||
# the view's centre is kept where MinimapWorld allows, so the land can reach the edge but not leave
|
||||
export function minimap_clamp() -> void {
|
||||
mm_vx = Math.clamp(mm_vx, MinimapWorld.lo_x(), MinimapWorld.hi_x())
|
||||
mm_vz = Math.clamp(mm_vz, MinimapWorld.lo_z(), MinimapWorld.hi_z())
|
||||
export function minimap_clamp(minimap_st: mut MinimapState) -> void {
|
||||
minimap_st.mm_vx = Math.clamp(minimap_st.mm_vx, MinimapWorld.lo_x(), MinimapWorld.hi_x())
|
||||
minimap_st.mm_vz = Math.clamp(minimap_st.mm_vz, MinimapWorld.lo_z(), MinimapWorld.hi_z())
|
||||
}
|
||||
|
||||
export function minimap_centre(x: float, z: float) -> void {
|
||||
mm_vx = x
|
||||
mm_vz = z
|
||||
mm_have_view = true
|
||||
minimap_clamp()
|
||||
export function minimap_centre(minimap_st: mut MinimapState, x: float, z: float) -> void {
|
||||
minimap_st.mm_vx = x
|
||||
minimap_st.mm_vz = z
|
||||
minimap_st.mm_have_view = true
|
||||
minimap_clamp(minimap_st)
|
||||
}
|
||||
|
||||
# the view on the camp, or on you
|
||||
export function minimap_recentre(on_you: bool) -> void {
|
||||
if on_you { minimap_centre(MinimapWorld.you_x(), MinimapWorld.you_z()) } else { minimap_centre(MinimapWorld.camp_x(), MinimapWorld.camp_z()) }
|
||||
export function minimap_recentre(minimap_st: mut MinimapState, on_you: bool) -> void {
|
||||
if on_you { minimap_centre(minimap_st, MinimapWorld.you_x(), MinimapWorld.you_z()) } else { minimap_centre(minimap_st, MinimapWorld.camp_x(), MinimapWorld.camp_z()) }
|
||||
}
|
||||
|
||||
# go there AND close in; never out, since a player already closer asked for that
|
||||
export function minimap_focus(on_you: bool) -> void {
|
||||
minimap_recentre(on_you)
|
||||
if mm_zoom < mm_zoom_focus { mm_zoom = Math.clamp(mm_zoom_focus, mm_zoom_min, mm_zoom_max) }
|
||||
export function minimap_focus(minimap_st: mut MinimapState, on_you: bool) -> void {
|
||||
minimap_recentre(minimap_st, on_you)
|
||||
if minimap_st.mm_zoom < minimap_st.mm_zoom_focus { minimap_st.mm_zoom = Math.clamp(minimap_st.mm_zoom_focus, minimap_st.mm_zoom_min, minimap_st.mm_zoom_max) }
|
||||
}
|
||||
|
|
|
|||
|
|
@ -1,61 +1,56 @@
|
|||
# view_moves.ludic - moving the view: zoom in steps or about a point (so what is under the pointer
|
||||
# stays under it), a drag that pans, and a press that picks the mark under it
|
||||
var mm_panning: bool = false
|
||||
var mm_drag_rx: float = 0.0
|
||||
var mm_drag_ry: float = 0.0
|
||||
var mm_drag_vx: float = 0.0
|
||||
var mm_drag_vz: float = 0.0
|
||||
|
||||
export function minimap_zoom_set(z: float) -> void {
|
||||
mm_zoom = Math.clamp(z, mm_zoom_min, mm_zoom_max)
|
||||
minimap_clamp()
|
||||
export function minimap_zoom_set(minimap_st: mut MinimapState, z: float) -> void {
|
||||
minimap_st.mm_zoom = Math.clamp(z, minimap_st.mm_zoom_min, minimap_st.mm_zoom_max)
|
||||
minimap_clamp(minimap_st)
|
||||
}
|
||||
|
||||
# a step in (dir > 0) or out, a third at a time
|
||||
export function minimap_zoom_step(dir: int) -> void {
|
||||
if dir > 0 { minimap_zoom_set(mm_zoom * 1.3) } else { minimap_zoom_set(mm_zoom / 1.3) }
|
||||
export function minimap_zoom_step(minimap_st: mut MinimapState, dir: int) -> void {
|
||||
if dir > 0 { minimap_zoom_set(minimap_st, minimap_st.mm_zoom * 1.3) } else { minimap_zoom_set(minimap_st, minimap_st.mm_zoom / 1.3) }
|
||||
}
|
||||
|
||||
# zoom by `factor` about a point of the window
|
||||
export function minimap_zoom_about(rx: float, ry: float, factor: float) -> void {
|
||||
let wx = minimap_wx(rx)
|
||||
let wz = minimap_wz(ry)
|
||||
mm_zoom = Math.clamp(mm_zoom * factor, mm_zoom_min, mm_zoom_max)
|
||||
mm_vx = mm_vx + wx - minimap_wx(rx)
|
||||
mm_vz = mm_vz + wz - minimap_wz(ry)
|
||||
minimap_clamp()
|
||||
export function minimap_zoom_about(minimap_st: mut MinimapState, rx: float, ry: float, factor: float) -> void {
|
||||
let wx = minimap_wx(minimap_st, rx)
|
||||
let wz = minimap_wz(minimap_st, ry)
|
||||
minimap_st.mm_zoom = Math.clamp(minimap_st.mm_zoom * factor, minimap_st.mm_zoom_min, minimap_st.mm_zoom_max)
|
||||
minimap_st.mm_vx = minimap_st.mm_vx + wx - minimap_wx(minimap_st, rx)
|
||||
minimap_st.mm_vz = minimap_st.mm_vz + wz - minimap_wz(minimap_st, ry)
|
||||
minimap_clamp(minimap_st)
|
||||
}
|
||||
|
||||
export function minimap_pan_begin(rx: float, ry: float) -> void {
|
||||
mm_panning = true
|
||||
mm_drag_rx = rx
|
||||
mm_drag_ry = ry
|
||||
mm_drag_vx = mm_vx
|
||||
mm_drag_vz = mm_vz
|
||||
export function minimap_pan_begin(minimap_st: mut MinimapState, rx: float, ry: float) -> void {
|
||||
minimap_st.mm_panning = true
|
||||
minimap_st.mm_drag_rx = rx
|
||||
minimap_st.mm_drag_ry = ry
|
||||
minimap_st.mm_drag_vx = minimap_st.mm_vx
|
||||
minimap_st.mm_drag_vz = minimap_st.mm_vz
|
||||
}
|
||||
|
||||
# the point pressed follows the pointer
|
||||
export function minimap_pan_to(rx: float, ry: float) -> void {
|
||||
if not mm_panning { return }
|
||||
mm_vx = mm_drag_vx - (rx - mm_drag_rx) / minimap_scale()
|
||||
mm_vz = mm_drag_vz - (ry - mm_drag_ry) / minimap_scale()
|
||||
minimap_clamp()
|
||||
export function minimap_pan_to(minimap_st: mut MinimapState, rx: float, ry: float) -> void {
|
||||
if not minimap_st.mm_panning { return }
|
||||
minimap_st.mm_vx = minimap_st.mm_drag_vx - (rx - minimap_st.mm_drag_rx) / minimap_scale(minimap_st)
|
||||
minimap_st.mm_vz = minimap_st.mm_drag_vz - (ry - minimap_st.mm_drag_ry) / minimap_scale(minimap_st)
|
||||
minimap_clamp(minimap_st)
|
||||
}
|
||||
|
||||
export function minimap_pan_end() -> void { mm_panning = false }
|
||||
export function minimap_panning() -> bool { return mm_panning }
|
||||
export function minimap_pan_end(minimap_st: mut MinimapState) -> void { minimap_st.mm_panning = false }
|
||||
export function minimap_panning(minimap_st: MinimapState) -> bool { return minimap_st.mm_panning }
|
||||
|
||||
# the mark within r pixels of a point of the window is opened (the last drawn, so the top one);
|
||||
# -1 and nothing changes when there is none
|
||||
export function minimap_pick(rx: float, ry: float, r: float) -> int {
|
||||
let sx = mm_x0 + rx
|
||||
let sy = mm_y0 + ry
|
||||
export function minimap_pick(minimap_st: mut MinimapState, rx: float, ry: float, r: float) -> int {
|
||||
let sx = minimap_st.mm_x0 + rx
|
||||
let sy = minimap_st.mm_y0 + ry
|
||||
var hit = -1
|
||||
for i in 0 .. minimap_pin_count() {
|
||||
let px = minimap_px(mm_pins[i].x)
|
||||
let py = minimap_py(mm_pins[i].z)
|
||||
for i in 0 .. minimap_pin_count(minimap_st) {
|
||||
let px = minimap_px(minimap_st, minimap_st.mm_pins[i].x)
|
||||
let py = minimap_py(minimap_st, minimap_st.mm_pins[i].z)
|
||||
if sx >= px - r and sx < px + r and sy >= py - r and sy < py + r { hit = i }
|
||||
}
|
||||
if hit >= 0 { mm_open = hit }
|
||||
if hit >= 0 { minimap_st.mm_open = hit }
|
||||
return hit
|
||||
}
|
||||
|
|
|
|||
Loading…
Add table
Add a link
Reference in a new issue