ludic/packages/ludic.npc/census.ludic

118 lines
3.4 KiB
Text

# census.ludic - making one (a slot reused before a new one, a look, a name, a start on its own
# ground out of the players' sight where that can be had), a post's fixed person, and leaving
export function npc_spawn(npc_st: mut NpcState, kind: int) -> NpcPerson {
if npc_st.np_n >= npc_st.np_max or kind < 0 or kind >= NPCK_COUNT { return null }
var p: NpcPerson = null
for i in 0 .. len(npc_st.np_walkers) {
if not npc_st.np_walkers[i].active {
p = npc_st.np_walkers[i]
break
}
}
if p == null {
if len(npc_st.np_walkers) >= npc_st.np_max { return null }
p = new NpcPerson
p.slot = len(npc_st.np_walkers)
push(npc_st.np_walkers, p)
}
np_fresh(p, kind, npc_between(npc_st, 1, 99999))
p.name = npc_pick_name(npc_st, p.body)
let k = NpcKinds[kind]
p.leg = npc_between(npc_st, 0, 3)
p.seed = npc_rnd(npc_st) * 40.0
p.out_h = k.leave_lo + npc_rnd(npc_st) * (k.leave_hi - k.leave_lo)
p.yaw = npc_rnd(npc_st) * NP_TAU
if k.start != null {
let start = k.start
start(p)
} else { npc_start_near(npc_st, p, NpcWorld.origin_x(), NpcWorld.origin_z(), 6.0, 30.0) }
p.active = true
npc_st.np_n += 1
NpcWorld.born(p)
npc_plan(npc_st, p)
return p
}
function np_fresh(p: NpcPerson, kind: int, look: int) -> void {
p.kind = kind
p.id = NpcWorld.next_id()
p.look = look
p.body = NpcWorld.body_of(look)
p.fixed = false
p.said = -1
p.near = 0
p.goal = -1
p.subj = -1
p.note = -1
p.note_h = 0.0
p.flags = 0
p.stalk = false
p.stall = 0.0
p.stall_max = 0.0
p.fails = 0
p.phase = 0.0
p.home_face = false
p.heard = false
p.act = NPCA_IDLE
p.act_t = 0.0
p.speed = 0.0
p.via_on = false
}
# its own ground: a spot r0 .. r1 from (cx, cz), tried a few times for one no player is within 60 m
# of, else near the place's origin; that is home, where it stands and faces
export function npc_start_near(npc_st: mut NpcState, p: NpcPerson, cx: float, cz: float, r0: float, r1: float) -> void {
var x = NpcWorld.origin_x()
var z = NpcWorld.origin_z()
var ok = false
for t in 0 .. 8 {
if not npc_spot_near(npc_st, cx, cz, r0, r1) { continue }
x = npc_st.np_px
z = npc_st.np_pz
ok = true
if npc_near(npc_st, x, z) > 60.0 { break }
}
if not ok and npc_spot_near(npc_st, x, z, 10.0, 45.0) {
x = npc_st.np_px
z = npc_st.np_pz
}
npc_set_at(p, x, z)
}
# put it down at (x, z) as its home, stood still
export function npc_set_at(p: NpcPerson, x: float, z: float) -> void {
p.x = x
p.z = z
p.y = NpcWorld.ground(x, z)
p.hx = x
p.hz = z
p.tx = x
p.tz = z
}
# somebody fixed at a post (a vendor behind the counter): never walks, never counted, never leaves,
# turns to a player within its kind's notice and back to `yaw` when they go
export function npc_place(npc_st: mut NpcState, kind: int, x: float, z: float, yaw: float, name: string, look: int) -> NpcPerson {
let p = new NpcPerson
p.slot = len(npc_st.np_posts)
np_fresh(p, kind, look)
p.fixed = true
p.name = name
p.seed = float(p.slot) * 0.9
p.stance = yaw
p.yaw = yaw
npc_set_at(p, x, z)
p.active = true
push(npc_st.np_posts, p)
NpcWorld.born(p)
npc_do(npc_st, p, NPCA_IDLE, 3600.0)
return p
}
export function npc_retire(npc_st: mut NpcState, p: NpcPerson) -> void {
if not p.active { return }
p.active = false
if not p.fixed and npc_st.np_n > 0 { npc_st.np_n -= 1 }
np_left(npc_st, p.name)
NpcWorld.gone(p)
}