# walk.ludic - walking to the target by the world's way where it has one (way.ludic): turn toward the # next corner, step, slid round a trunk or a tent, never into the water and never up a scramble - step # round it instead - and give up on a target that gets no closer for twenty seconds const NP_BODY_R: float = 0.35 # a person's width, for the still things export function npc_walk(npc_st: mut NpcState, p: NpcPerson, dt: float) -> void { var gx = p.tx var gz = p.tz if p.via_on { gx = p.vx gz = p.vz } if npc_d(p.x, p.z, gx, gz) < 1.2 { np_arrive(npc_st, p) return } if not p.via_on { np_way(p, dt) gx = p.wx gz = p.wz } let dx = gx - p.x let dz = gz - p.z let dg = npc_d(p.x, p.z, p.tx, p.tz) if dg < p.best - 1.0 { p.best = dg p.prog_t = 0.0 } else { p.prog_t = p.prog_t + dt } if p.prog_t > 20.0 { np_stuck(npc_st, p) return } var sp = p.speed if sp < 0.1 { sp = 1.2 } if p.stalk { sp = Math.min(sp, 0.7) } let want = Math.atan2(-dx, -dz) let r = 3.0 * dt p.yaw = p.yaw + Math.clamp(npc_wrap(want - p.yaw), -r, r) let step = sp * dt np_slide(npc_st, p, p.x - Math.sin(p.yaw) * step, p.z - Math.cos(p.yaw) * step) let nx = npc_st.np_ask_x let nz = npc_st.np_ask_z let nh = NpcWorld.ground(nx, nz) let slid = Math.abs(nx - p.x) + Math.abs(nz - p.z) if nh < NpcWorld.water(nx, nz) + 0.4 or nh - p.y > step * 1.4 or slid < step * 0.2 { p.stall = p.stall + dt if p.stall > p.stall_max { p.stall_max = p.stall } if p.detours < 10 and np_detour(p, want) { np_stuck_fact(npc_st, p, NPC_STUCK_DETOUR) p.detours += 1 return } np_stuck(npc_st, p) return } p.x = nx p.z = nz p.y = nh p.stall = 0.0 p.phase = p.phase + step * 2.6 } # (x, z) slid clear of every still thing for a person; np_ask_x / _z hold where it came out function np_slide(npc_st: mut NpcState, p: NpcPerson, x: float, z: float) -> void { npc_st.np_ask_x = x npc_st.np_ask_z = z if not NpcWorld.push(x, z, NP_BODY_R, p.y + 0.1, p.y + 1.8) { return } let ox = NpcWorld.pushed_x() let oz = NpcWorld.pushed_z() npc_st.np_ask_x = ox npc_st.np_ask_z = oz } # there: a step round something ends, or the errand begins, facing what it came for function np_arrive(npc_st: mut NpcState, p: NpcPerson) -> void { if p.via_on { p.via_on = false return } let fx = p.fx let fz = p.fz npc_do(npc_st, p, p.next_act, p.next_t) p.fx = fx p.fz = fz p.stall = 0.0 if p.act != NPCA_WALK { np_fact(npc_st, NPC_F_ARRIVED, p, -1) } }