106 lines
3.1 KiB
Text
106 lines
3.1 KiB
Text
# routine.ludic - going somewhere to do something, doing it here, and deciding what is next: the
|
|
# kind's own plan first, then a weighted draw among its steps for this hour, falling through to the
|
|
# next step whose spot can be found, and standing a while when none can
|
|
export function npc_go(npc_st: NpcState, p: NpcPerson, x: float, z: float, act: int, dur: float) -> void {
|
|
p.tx = x
|
|
p.tz = z
|
|
p.next_act = act
|
|
p.next_t = dur
|
|
p.act = NPCA_WALK
|
|
p.via_on = false
|
|
p.detours = 0
|
|
p.prog_t = 0.0
|
|
p.best = npc_d(p.x, p.z, x, z)
|
|
p.fx = x + (x - p.x)
|
|
p.fz = z + (z - p.z)
|
|
p.speed = 1.1 + npc_rnd(npc_st) * 0.4
|
|
}
|
|
|
|
# whatever it is, it is not done where the place says nobody stops: walk out of there first
|
|
export function npc_do(npc_st: mut NpcState, p: NpcPerson, act: int, dur: float) -> void {
|
|
if act != NPCA_WALK and not p.fixed and not NpcWorld.allowed(p.x, p.z) {
|
|
if npc_spot_near(npc_st, p.x, p.z, 20.0, 60.0) {
|
|
let fx = p.fx
|
|
let fz = p.fz
|
|
npc_go(npc_st, p, npc_st.np_px, npc_st.np_pz, act, dur)
|
|
if act != NPCA_IDLE {
|
|
p.fx = fx
|
|
p.fz = fz
|
|
}
|
|
return
|
|
}
|
|
}
|
|
p.act = act
|
|
p.act_t = dur
|
|
p.speed = 0.0
|
|
}
|
|
|
|
export function npc_face(p: NpcPerson, x: float, z: float) -> void {
|
|
p.fx = x
|
|
p.fz = z
|
|
}
|
|
|
|
export function npc_face_ahead(p: NpcPerson) -> void {
|
|
p.fx = p.x - Math.sin(p.yaw) * 10.0
|
|
p.fz = p.z - Math.cos(p.yaw) * 10.0
|
|
}
|
|
|
|
# where it faces sitting at home: its own fire when it has one, else out ahead from home
|
|
export function npc_set_home_face(p: NpcPerson, x: float, z: float) -> void {
|
|
p.hfx = x
|
|
p.hfz = z
|
|
p.home_face = true
|
|
}
|
|
|
|
function np_in_hours(s: NpcStep, h: float) -> bool {
|
|
if s.from <= s.to { return h >= s.from and h < s.to }
|
|
return h >= s.from or h < s.to
|
|
}
|
|
|
|
# what next: the kind's plan, then its steps for this hour
|
|
export function npc_plan(npc_st: mut NpcState, p: NpcPerson) -> void {
|
|
p.stalk = false
|
|
if p.fixed {
|
|
npc_do(npc_st, p, NPCA_IDLE, 3600.0)
|
|
return
|
|
}
|
|
let k = NpcKinds[p.kind]
|
|
if k.plan != null {
|
|
let plan = k.plan
|
|
if plan(p) { return }
|
|
}
|
|
if k.steps != null and npc_steps(npc_st, p, k.steps) { return }
|
|
npc_face_ahead(p)
|
|
npc_do(npc_st, p, NPCA_IDLE, 10.0)
|
|
}
|
|
|
|
# a weighted draw among the steps whose hours hold now; a step whose spot cannot be found
|
|
# gives way to the next one in the table, round to the start
|
|
export function npc_steps(npc_st: NpcState, p: NpcPerson, steps: []NpcStep) -> bool {
|
|
let h = NpcWorld.hour()
|
|
var total = 0
|
|
for i in 0 .. len(steps) { if np_in_hours(steps[i], h) { total += np_pos(steps[i].weight) } }
|
|
if total <= 0 { return false }
|
|
var r = npc_between(npc_st, 0, total - 1)
|
|
var first = -1
|
|
for i in 0 .. len(steps) {
|
|
if not np_in_hours(steps[i], h) { continue }
|
|
r -= np_pos(steps[i].weight)
|
|
if r < 0 {
|
|
first = i
|
|
break
|
|
}
|
|
}
|
|
for k in 0 .. len(steps) {
|
|
let s = steps[(first + k) % len(steps)]
|
|
if not np_in_hours(s, h) or s.spot < 0 or s.spot >= NPCS_COUNT { continue }
|
|
let find = NpcSpots[s.spot].find
|
|
if find != null and find(p, s) { return true }
|
|
}
|
|
return false
|
|
}
|
|
|
|
function np_pos(n: int) -> int {
|
|
if n < 0 { return 0 }
|
|
return n
|
|
}
|