# 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 }