ludic/packages/ludic.npc/person.ludic
Orkuncakilkaya 56e4b6d688 feat(senses): walkers slide round still things, and lines of sight are the world's to answer
- 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>
2026-09-27 00:59:39 +03:00

122 lines
3.9 KiB
Text

# person.ludic - the people: walkers in slots the census fills and empties, and the fixed ones at
# their posts; the package's own dice and its facts
export state NpcState {
np_px: float = 0.0
np_pz: float = 0.0
np_wx: float = 0.0
np_wz: float = 0.0
np_clock: float = 0.0
np_recent: []string = null # the last few names that left
np_walkers: []NpcPerson = null
np_posts: []NpcPerson = null
np_max: int = 10 # walkers at most
np_n: int = 0 # walkers about
np_dice: Rng = null
np_facts: Queue<NpcFact> = null
np_next_h: float = 0.0 # the hour the census is next looked at
np_hold: bool = false # held where they stand (a shot of their poses)
np_mirror: bool = false # a guest drawing a host's: no routine runs here
nw_ids: int = 0
np_near_i: int = -1
np_said: string = ""
np_ask_x: float = 0.0 # the point handed to NpcWorld.push, then where it came out
np_ask_z: float = 0.0
}
const NP_PI: float = 3.1415927
const NP_TAU: float = 6.2831853
export function npc_facts(npc_st: mut NpcState) -> Queue<NpcFact> {
if npc_st.np_facts == null { npc_st.np_facts = queue_new("npc.facts") }
return npc_st.np_facts
}
function np_fact(npc_st: mut NpcState, what: int, p: NpcPerson, player: int) -> NpcFact {
let f = new NpcFact
f.what = what
f.person = p.id
f.slot = p.slot
f.fixed = p.fixed
f.player = player
f.act = p.act
q_push(npc_facts(npc_st), f)
return f
}
function np_ensure(npc_st: mut NpcState) -> void {
if npc_st.np_walkers == null { npc_st.np_walkers = new []NpcPerson }
if npc_st.np_posts == null { npc_st.np_posts = new []NpcPerson }
if npc_st.np_dice == null { npc_st.np_dice = rng_new(20260925) }
}
# how many walkers the place can hold at once
export function npc_config(npc_st: mut NpcState, max: int) -> void { npc_st.np_max = max }
export function npc_seed(npc_st: mut NpcState, n: int) -> void {
np_ensure(npc_st)
rng_seed(npc_st.np_dice, n)
}
# 0 .. 1, and whole seconds lo .. hi, off the package's dice
export function npc_rnd(npc_st: mut NpcState) -> float {
np_ensure(npc_st)
return rng_float(npc_st.np_dice)
}
export function npc_between(npc_st: mut NpcState, lo: int, hi: int) -> int {
np_ensure(npc_st)
return rng_between(npc_st.np_dice, lo, hi)
}
export function npc_secs(npc_st: mut NpcState, lo: int, hi: int) -> float { return float(npc_between(npc_st, lo, np_hi(lo, hi))) }
export function npc_walkers(npc_st: mut NpcState) -> []NpcPerson {
np_ensure(npc_st)
return npc_st.np_walkers
}
export function npc_posts(npc_st: mut NpcState) -> []NpcPerson {
np_ensure(npc_st)
return npc_st.np_posts
}
export function npc_count(npc_st: NpcState) -> int { return npc_st.np_n }
export function npc_max(npc_st: NpcState) -> int { return npc_st.np_max }
# a walker's slot or a post, and anyone by id
export function npc_at(npc_st: mut NpcState, slot: int) -> NpcPerson {
np_ensure(npc_st)
if slot < 0 or slot >= len(npc_st.np_walkers) { return null }
return npc_st.np_walkers[slot]
}
export function npc_post(npc_st: mut NpcState, i: int) -> NpcPerson {
np_ensure(npc_st)
if i < 0 or i >= len(npc_st.np_posts) { return null }
return npc_st.np_posts[i]
}
export function npc_by_id(npc_st: mut NpcState, id: int) -> NpcPerson {
np_ensure(npc_st)
for i in 0 .. len(npc_st.np_walkers) { if npc_st.np_walkers[i].active and npc_st.np_walkers[i].id == id { return npc_st.np_walkers[i] } }
for i in 0 .. len(npc_st.np_posts) { if npc_st.np_posts[i].active and npc_st.np_posts[i].id == id { return npc_st.np_posts[i] } }
return null
}
export function npc_d(ax: float, az: float, bx: float, bz: float) -> float {
let dx = ax - bx
let dz = az - bz
return Math.sqrt(dx * dx + dz * dz)
}
export function npc_wrap(a: float) -> float {
var r = a
while r > NP_PI { r = r - NP_TAU }
while r < -NP_PI { r = r + NP_TAU }
return r
}
function np_hi(lo: int, hi: int) -> int {
if hi < lo { return lo }
return hi
}