diff --git a/packages/ludic.npc/README.md b/packages/ludic.npc/README.md index 42263c87..dc46f886 100644 --- a/packages/ludic.npc/README.md +++ b/packages/ludic.npc/README.md @@ -114,7 +114,7 @@ by a person's taste. | `npc_pick_name(body)`, `npc_name_used(n)`, `npc_name_clashes()` | names | | `npc_talk(p, player)`, `npc_line_for(p)`, `npc_words(p, line)`, `npc_said()`, `npc_choose(p, line, c, player)`, `npc_talked_today(p)`, `npc_greeting(p)` | talk | | `npc_mirror(on)`, `npc_mirroring()`, `npc_put(slot, id, kind, look, seed, name, hx, hz)`, `npc_heard(slot, x, y, z, yaw, speed, act, stalk)`, `npc_heard_lately(p)`, `npc_mirror_tick(dt)` | a guest's copy of the host's people | -| `npc_facts() -> Queue` | `NPC_F_GREETED` (`player`), `NPC_F_TALKED` (`player`, `line`, `choice`), `NPC_F_ARRIVED` (`act`) | +| `npc_facts() -> Queue` | `NPC_F_GREETED` (`player`), `NPC_F_TALKED` (`player`, `line`, `choice`), `NPC_F_ARRIVED` (`act`), `NPC_F_STUCK` (`how` - `NPC_STUCK_DETOUR`, `_RETRY`, `_GAVE_UP` - at `x`, `z`: the way failed it and it fell back) | | `npc_system() -> System` | `"npc"`, `PH_SIMULATE`, a reset and no tick; nothing saved | ## Tests diff --git a/packages/ludic.npc/defs.ludic b/packages/ludic.npc/defs.ludic index 18e3121a..2352a657 100644 --- a/packages/ludic.npc/defs.ludic +++ b/packages/ludic.npc/defs.ludic @@ -131,6 +131,7 @@ export open registry NpcNames of NpcName as NPCN export const NPC_F_GREETED: int = 0 # a player came within notice export const NPC_F_TALKED: int = 1 # a player talked (line, choice -1 or the choice taken) export const NPC_F_ARRIVED: int = 2 # got where it was walking, and began the act +export const NPC_F_STUCK: int = 3 # the way failed it and it fell back (`how`, at `x`, `z`) export property NpcFact { what: int = 0 @@ -141,4 +142,7 @@ export property NpcFact { line: int = -1 choice: int = -1 act: int = -1 + how: int = 0 # NPC_STUCK_* + x: float = 0.0 + z: float = 0.0 } diff --git a/packages/ludic.npc/tests/npc_test.ludic b/packages/ludic.npc/tests/npc_test.ludic index 0b001a50..c9b5bbe0 100644 --- a/packages/ludic.npc/tests/npc_test.ludic +++ b/packages/ludic.npc/tests/npc_test.ludic @@ -114,7 +114,7 @@ program NpcTest { expect_eq(p.act, NPCA_SIT) } - test "nobody walks into the lake" (npc_st: mut NpcState, npc_tests_fake_st: mut NpcTestsFakeState) { + test "nobody walks into the lake, and turning back from it is told as a fallback" (npc_st: mut NpcState, npc_tests_fake_st: mut NpcTestsFakeState) { let p = one(npc_st, npc_tests_fake_st, NPCK_HIKER) npc_go(npc_st, p, -80.0, 0.0, NPCA_SIT, 30.0) var west = 0.0 @@ -123,6 +123,12 @@ program NpcTest { west = Math.min(west, p.x) } expect(west > -50.5) + var fell = 0 + let fs = q_drain(npc_facts(npc_st)) + for i in 0 .. len(fs) { + if fs[i].what == NPC_F_STUCK and fs[i].x > -52.0 { fell += 1 } + } + expect(fell >= 1) } test "a step's spot is where its hours say: the shore by day, home by night" (npc_st: mut NpcState, npc_tests_fake_st: mut NpcTestsFakeState) { diff --git a/packages/ludic.npc/tests/way_test.ludic b/packages/ludic.npc/tests/way_test.ludic index 22b726b4..b76fda18 100644 --- a/packages/ludic.npc/tests/way_test.ludic +++ b/packages/ludic.npc/tests/way_test.ludic @@ -78,5 +78,7 @@ program NpcWayTest { expect_eq(p.act, NPCA_SIT) expect(npc_d(p.x, p.z, 38.0, -25.0) < 1.3) expect(way_test_st.asked > 5) + let fs = q_drain(npc_facts(npc_st)) + for i in 0 .. len(fs) { expect(fs[i].what != NPC_F_STUCK) } } } diff --git a/packages/ludic.npc/walk.ludic b/packages/ludic.npc/walk.ludic index 90758386..6f416cc4 100644 --- a/packages/ludic.npc/walk.ludic +++ b/packages/ludic.npc/walk.ludic @@ -46,6 +46,7 @@ export function npc_walk(npc_st: mut NpcState, p: NpcPerson, dt: float) -> void 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 } diff --git a/packages/ludic.npc/way.ludic b/packages/ludic.npc/way.ludic index 1108897f..d0ffa8ad 100644 --- a/packages/ludic.npc/way.ludic +++ b/packages/ludic.npc/way.ludic @@ -1,6 +1,15 @@ # 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 +# 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 @@ -39,7 +48,11 @@ 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 { npc_plan(npc_st, p) } + } else { + np_stuck_fact(npc_st, p, NPC_STUCK_RETRY) + npc_plan(npc_st, p) + } }