- ludic.wildlife: WildlifeWorld.push / pushed_x / pushed_z (defaults change nothing); a ground walker's step is slid clear of a still thing with a body from its species' size and scale, and a step that gets nowhere turns away as the water does. Birds are not pushed; no dice added. - ludic.npc: NpcWorld.push / pushed_x / pushed_z (a person 0.35 m round) in npc_walk, and NpcWorld.clear (default true), which npc_line_ok asks at 1 m so a detour does not cut a trunk. - ludic.aim: AimView.clear replaces AimView.ground and the ground march; the pick asks the line a body's width short of where the ray enters the thing (aim_clear_at(t, back)), so a solid thing does not hide itself. probe.ludic (the ground-agreement probe) and AimView.dry are gone. - ludic.photo: PhotoLens.clear replaces PhotoLens.ground, PhotoLens.trunk and the march. Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
98 lines
3.3 KiB
Text
98 lines
3.3 KiB
Text
# ground.ludic - where a person can stand and walk: dry, gentle, allowed; a straight walk with no
|
|
# water, scramble or still thing on it; a spot in a ring, a spot toward something, the nearest shore.
|
|
# A finder that succeeds leaves its answer in npc_px / npc_pz (and the water in npc_wx / npc_wz).
|
|
|
|
export function npc_px(npc_st: NpcState) -> float { return npc_st.np_px }
|
|
export function npc_pz(npc_st: NpcState) -> float { return npc_st.np_pz }
|
|
export function npc_wx(npc_st: NpcState) -> float { return npc_st.np_wx }
|
|
export function npc_wz(npc_st: NpcState) -> float { return npc_st.np_wz }
|
|
|
|
export function npc_walkable(x: float, z: float) -> bool {
|
|
if not NpcWorld.allowed(x, z) { return false }
|
|
if NpcWorld.ground(x, z) < NpcWorld.water(x, z) + 0.6 { return false }
|
|
return NpcWorld.slope(x, z) < 0.75
|
|
}
|
|
|
|
export function npc_line_ok(ax: float, az: float, bx: float, bz: float) -> bool {
|
|
let d = npc_d(ax, az, bx, bz)
|
|
var n = int(d / 1.5)
|
|
if n < 1 { n = 1 }
|
|
var prev = NpcWorld.ground(ax, az)
|
|
if not NpcWorld.clear(ax, prev + 1.0, az, bx, NpcWorld.ground(bx, bz) + 1.0, bz) { return false } # a trunk, a tent
|
|
for i in 1 .. n + 1 {
|
|
let t = float(i) / float(n)
|
|
let x = ax + (bx - ax) * t
|
|
let z = az + (bz - az) * t
|
|
let h = NpcWorld.ground(x, z)
|
|
if h < NpcWorld.water(x, z) + 0.5 { return false }
|
|
if h - prev > d / float(n) * 1.3 { return false }
|
|
prev = h
|
|
}
|
|
return true
|
|
}
|
|
|
|
function np_found(npc_st: mut NpcState, x: float, z: float) -> bool {
|
|
npc_st.np_px = x
|
|
npc_st.np_pz = z
|
|
return true
|
|
}
|
|
|
|
# somewhere to stand d0 .. d1 from a point
|
|
export function npc_spot_near(npc_st: mut NpcState, x0: float, z0: float, d0: float, d1: float) -> bool {
|
|
for t in 0 .. 40 {
|
|
let ang = npc_rnd(npc_st) * NP_TAU
|
|
let d = d0 + npc_rnd(npc_st) * (d1 - d0)
|
|
let x = x0 + Math.cos(ang) * d
|
|
let z = z0 + Math.sin(ang) * d
|
|
if npc_walkable(x, z) { return np_found(npc_st, x, z) }
|
|
}
|
|
return false
|
|
}
|
|
|
|
# a place to stand d from (ax, az), on the side (bx, bz) is on
|
|
export function npc_toward(npc_st: mut NpcState, ax: float, az: float, bx: float, bz: float, d: float) -> bool {
|
|
let dd = Math.max(npc_d(ax, az, bx, bz), 0.5)
|
|
let x = ax + (bx - ax) / dd * d
|
|
let z = az + (bz - az) / dd * d
|
|
if npc_walkable(x, z) { return np_found(npc_st, x, z) }
|
|
for k in 0 .. 12 {
|
|
let ang = Math.atan2(bz - az, bx - ax) + float((k + 1) / 2 * (1 - 2 * (k % 2))) * 0.25
|
|
let x2 = ax + Math.cos(ang) * d
|
|
let z2 = az + Math.sin(ang) * d
|
|
if npc_walkable(x2, z2) { return np_found(npc_st, x2, z2) }
|
|
}
|
|
return npc_spot_near(npc_st, x, z, 0.0, 14.0)
|
|
}
|
|
|
|
# the nearest bit of shore within rmax: where to stand, and the water in front of it
|
|
export function npc_shore(npc_st: mut NpcState, x0: float, z0: float, rmax: float) -> bool {
|
|
var found = false
|
|
var bd = rmax
|
|
for k in 0 .. 16 {
|
|
let ang = float(k) * (NP_TAU / 16.0)
|
|
var lx = x0
|
|
var lz = z0
|
|
var ld = -100.0
|
|
var d = 2.0
|
|
while d < bd {
|
|
let x = x0 + Math.cos(ang) * d
|
|
let z = z0 + Math.sin(ang) * d
|
|
if NpcWorld.ground(x, z) < NpcWorld.water(x, z) {
|
|
if ld > 0.0 and d - ld < 12.0 {
|
|
bd = d
|
|
found = np_found(npc_st, lx, lz)
|
|
npc_st.np_wx = x
|
|
npc_st.np_wz = z
|
|
}
|
|
break
|
|
}
|
|
if npc_walkable(x, z) {
|
|
lx = x
|
|
lz = z
|
|
ld = d
|
|
}
|
|
d = d + 2.0
|
|
}
|
|
}
|
|
return found
|
|
}
|