From 61f802e9ad44b13853bed1fc04546aa00d91c5e4 Mon Sep 17 00:00:00 2001 From: Orkuncakilkaya Date: Sun, 27 Sep 2026 22:31:07 +0300 Subject: [PATCH] ludic.wildlife (17.6): a fleeing or wary animal goes by the world's way It sets a target straight away from the threat (40 m when it flees, 20 m when it is wary) and heads for it with wl_head, so the way port takes it round water and cliffs. Where the world gives no way, it still runs straight away as before. way_test now has a flee round the wall's end. Co-Authored-By: Claude Opus 5.5 --- packages/ludic.wildlife/react.ludic | 6 ++++-- packages/ludic.wildlife/tests/way_test.ludic | 19 +++++++++++++++++++ packages/ludic.wildlife/way.ludic | 17 +++++++++++++++++ 3 files changed, 40 insertions(+), 2 deletions(-) diff --git a/packages/ludic.wildlife/react.ludic b/packages/ludic.wildlife/react.ludic index 3f3580bc..e2172e5d 100644 --- a/packages/ludic.wildlife/react.ludic +++ b/packages/ludic.wildlife/react.ludic @@ -9,14 +9,16 @@ function wl_react(wildlife_st: mut WildlifeState, a: WildAnimal, np: int, dt: fl return true } if a.state == WILD_WARY { - wl_face(a, a.x + (a.x - a.sus_x), a.z + (a.z - a.sus_z), 2.6, dt) + wl_away(a, a.sus_x, a.sus_z, 20.0) + wl_head(a, a.tx, a.tz, 2.6, dt) a.speed = s.walk * 0.8 wl_step(wildlife_st, a, dt) if a.timer < 0.0 { wl_wander(wildlife_st, a, 3.0 + wl_rnd(wildlife_st) * 4.0) } return true } if a.state == WILD_FLEE { - wl_face(a, a.x + (a.x - WildlifeWorld.player_x(np)), a.z + (a.z - WildlifeWorld.player_z(np)), 5.0, dt) + wl_away(a, WildlifeWorld.player_x(np), WildlifeWorld.player_z(np), 40.0) + wl_head(a, a.tx, a.tz, 5.0, dt) a.speed = s.run wl_step(wildlife_st, a, dt) if a.timer < 0.0 { diff --git a/packages/ludic.wildlife/tests/way_test.ludic b/packages/ludic.wildlife/tests/way_test.ludic index b9624030..65b5ffbb 100644 --- a/packages/ludic.wildlife/tests/way_test.ludic +++ b/packages/ludic.wildlife/tests/way_test.ludic @@ -103,4 +103,23 @@ program WayTest { expect_near(a.tx, a.home_x + 7.0, 0.001) expect_near(a.tz, a.home_z + 3.0, 0.001) } + + test "it runs from the player by the way too: round the wall's end, not into it" (wildlife_st: mut WildlifeState, wildlife_tests_fake_st: mut WildlifeTestsFakeState, way_test_st: WayTestState) { + fk_setup(wildlife_st, wildlife_tests_fake_st) + let a = wildlife_make(wildlife_st, 0, 0.0, 0.0, false, 0.0, 0, 1.0, 1) + wildlife_tests_fake_st.fk_px[0] = 0.0 + wildlife_tests_fake_st.fk_pz[0] = 20.0 + wildlife_tests_fake_st.fk_hidden = true + a.state = WILD_FLEE + a.timer = 300.0 + var east = -100.0 + for k in 0 .. 1200 { + wildlife_tick(wildlife_st, 0.05, 0.0) + if a.z > -42.0 and a.z < -38.0 { east = Math.max(east, a.x) } + } + expect_eq(a.state, WILD_FLEE) + expect(east > 29.0) + expect(a.z < -45.0) + expect(way_test_st.asked > 10) + } } diff --git a/packages/ludic.wildlife/way.ludic b/packages/ludic.wildlife/way.ludic index ddc00e31..6cb5f9e9 100644 --- a/packages/ludic.wildlife/way.ludic +++ b/packages/ludic.wildlife/way.ludic @@ -34,3 +34,20 @@ function wl_pick_target(wildlife_st: WildlifeState, a: WildAnimal, radius: float a.tz = WildlifeWorld.way_z() } } + +# a target d metres straight away from (fx, fz): where it runs or backs off to, by the world's way - +# round water and a cliff where there is one, and straight away as before where there is not +function wl_away(a: WildAnimal, fx: float, fz: float, d: float) -> void { + var dx = a.x - fx + var dz = a.z - fz + let l = Math.sqrt(dx * dx + dz * dz) + if l < 0.01 { + dx = -Math.sin(a.yaw) + dz = -Math.cos(a.yaw) + } else { + dx = dx / l + dz = dz / l + } + a.tx = a.x + dx * d + a.tz = a.z + dz * d +}