A step round what is in the way, a target planned again after twenty seconds without progress, and a target given up are each pushed as NPC_F_STUCK (how, x, z), so the game can see where the way failed a person. The lake test expects one when a walker turns back from the water; the way test expects none when the world gives the way. Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
58 lines
1.9 KiB
Text
58 lines
1.9 KiB
Text
# way.ludic - where a person walks when the straight line will not do: the world's way (NpcWorld.way,
|
|
# a navmesh by a person's taste in Maroon Lake), and without one a step round what is in the way,
|
|
# and giving the target up after three tries - each of those a NPC_F_STUCK fact, so the fallback is seen
|
|
export const NPC_STUCK_DETOUR: int = 0 # a step round what was in front of it
|
|
export const NPC_STUCK_RETRY: int = 1 # no closer for twenty seconds, or no step round: planned again
|
|
export const NPC_STUCK_GAVE_UP: int = 2 # the third of those: the target given up
|
|
function np_stuck_fact(npc_st: NpcState, p: NpcPerson, how: int) -> void {
|
|
let f = np_fact(npc_st, NPC_F_STUCK, p, -1)
|
|
f.how = how
|
|
f.x = p.x
|
|
f.z = p.z
|
|
}
|
|
|
|
# the next corner toward the target, asked again every half second, on reaching it, or for a new target
|
|
const NP_WAY_EVERY: float = 0.5
|
|
function np_way(p: NpcPerson, dt: float) -> void {
|
|
p.way_t = p.way_t - dt
|
|
let fresh = p.wtx != p.tx or p.wtz != p.tz
|
|
if p.way_t > 0.0 and not fresh and npc_d(p.x, p.z, p.wx, p.wz) >= 1.0 { return }
|
|
p.way_t = NP_WAY_EVERY
|
|
p.wtx = p.tx
|
|
p.wtz = p.tz
|
|
p.wx = p.tx
|
|
p.wz = p.tz
|
|
if NpcWorld.way(p, p.tx, p.tz) {
|
|
p.wx = NpcWorld.way_x()
|
|
p.wz = NpcWorld.way_z()
|
|
}
|
|
}
|
|
|
|
function np_detour(p: NpcPerson, want: float) -> bool {
|
|
for k in 0 .. 8 {
|
|
let ang = want + float((k / 2 + 1) * (1 - 2 * (k % 2))) * 0.6
|
|
let x = p.x - Math.sin(ang) * 6.0
|
|
let z = p.z - Math.cos(ang) * 6.0
|
|
if npc_line_ok(p.x, p.z, x, z) {
|
|
p.via_on = true
|
|
p.vx = x
|
|
p.vz = z
|
|
p.yaw = ang
|
|
return true
|
|
}
|
|
}
|
|
return false
|
|
}
|
|
|
|
function np_stuck(npc_st: mut NpcState, p: NpcPerson) -> void {
|
|
p.fails += 1
|
|
p.via_on = false
|
|
if p.fails >= 3 {
|
|
np_stuck_fact(npc_st, p, NPC_STUCK_GAVE_UP)
|
|
p.fails = 0
|
|
npc_wander(npc_st, p)
|
|
} else {
|
|
np_stuck_fact(npc_st, p, NPC_STUCK_RETRY)
|
|
npc_plan(npc_st, p)
|
|
}
|
|
}
|