ludic/packages/ludic.character/safe.ludic
Orkuncakilkaya 19fcf60599 wip(0.S3): packages and examples migrated again from their pre-0.S sources in one run
ludic migrate state packages <every example program> packages/ludic.lab/example/plate.ludic
  1804 vars into 126 states, 64 into lets; 23498 edits in 460 files

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
2026-09-25 15:31:34 +03:00

39 lines
1.6 KiB
Text

# safe.ludic - somewhere a body can be put down: the one answer every dismount, every stand-up and
# every landing asks. The wanted spot if it will do, else the nearest ring out that is clear of every
# collider, no deeper than max_depth, within CHAR_DROP of the height being left, and on ground
# gentle enough to walk off - a spot you can stand on but cannot leave is not a safe spot.
function chr_safe_ok(character_st: mut CharacterState, x: float, z: float, from_y: float, max_depth: float) -> bool {
let g = CharacterGround.height(x, z)
if Math.abs(g - from_y) > CHAR_DROP { return false }
if CharacterGround.water(x, z) - g > max_depth { return false }
if chr_push(character_st, x, z, 0.4, g, g + CHAR_BODY) { return false }
var lo = g
var hi = g
for k in 0 .. 4 {
let a = float(k) * (chr_pi * 0.5)
let h = CharacterGround.height(x + Math.sin(a) * CHAR_SLOPE_PROBE, z + Math.cos(a) * CHAR_SLOPE_PROBE)
lo = Math.min(lo, h)
hi = Math.max(hi, h)
}
return not (hi - lo > CHAR_SLOPE_PROBE * 2.0)
}
export function char_safe_spot(character_st: mut CharacterState, x: float, z: float, from_y: float, max_depth: float) -> bool {
character_st.chr_safe_x = x
character_st.chr_safe_z = z
if chr_safe_ok(character_st, x, z, from_y, max_depth) { return true }
for r in 0 .. 9 {
let rad = 0.8 + float(r) * 1.1
for k in 0 .. 16 {
let a = float(k) * (chr_pi / 8.0)
let px = x + Math.sin(a) * rad
let pz = z + Math.cos(a) * rad
if chr_safe_ok(character_st, px, pz, from_y, max_depth) {
character_st.chr_safe_x = px
character_st.chr_safe_z = pz
return true
}
}
}
return false
}