# water.ludic - one axis decides it: how far the bed is below the surface where the body stands. # Under CHAR_WADE_MAX the walk wades; past it the feet leave the bottom. Coming out wants a # shallower bed (CHAR_STAND_UP) than going in did, so a shelving shore does not flicker. function chr_enter_water(character_st: mut CharacterState, x: float, z: float) -> void { if character_st.chr_swim { return } character_st.chr_swim = true character_st.chr_dive = false character_st.chr_depth = 0.0 character_st.chr_breath = body_breath_max() character_st.chr_float = 0.0 character_st.chr_air = false character_st.chr_vy = 0.0 character_st.chr_sit = false character_st.chr_x = x character_st.chr_z = z character_st.chr_water = CharacterGround.water(x, z) character_st.chr_y = character_st.chr_water - 0.30 chr_say(character_st, CHAR_STARTED_SWIMMING, 0.0) } function chr_leave_water(character_st: mut CharacterState) -> void { if not character_st.chr_swim { return } character_st.chr_swim = false character_st.chr_dive = false character_st.chr_depth = 0.0 character_st.chr_y = CharacterGround.height(character_st.chr_x, character_st.chr_z) character_st.chr_speed = Math.min(character_st.chr_speed, 1.0) chr_say(character_st, CHAR_LEFT_WATER, 0.0) } # the descent: the jump held pushes the body under, letting go floats it back up function chr_dive_tick(character_st: mut CharacterState, jump: bool, dt: float) -> void { let bed = Math.max(chr_bed_depth(character_st.chr_x, character_st.chr_z), 0.0) let max_d = Math.min(6.0, Math.max(bed - 0.4, 0.0)) if jump and max_d > 0.2 { character_st.chr_dive = true character_st.chr_depth = Math.min(character_st.chr_depth + 1.2 * dt, max_d) } else { character_st.chr_depth = Math.max(character_st.chr_depth - 1.6 * dt, 0.0) if character_st.chr_depth < 0.05 { character_st.chr_dive = false } } } # air is spent only under the surface, and comes back fast at the top function chr_breath_tick(character_st: mut CharacterState, dt: float) -> void { if not (character_st.chr_depth > 0.55) { character_st.chr_breath = Math.min(character_st.chr_breath + dt * 12.0, body_breath_max()) return } character_st.chr_breath = character_st.chr_breath - dt if character_st.chr_breath < 0.0 { character_st.chr_breath = 0.0 character_st.chr_dive = false character_st.chr_depth = Math.max(character_st.chr_depth - 3.0 * dt, 0.0) chr_say(character_st, CHAR_OUT_OF_AIR, dt) } } # The edge of the world is a current, not a wall: it takes the outward part of a stroke, so # turning round always works. Said once every twelve seconds while it is strong. function chr_current_tick(character_st: mut CharacterState, dt: float) -> void { let fx = -Math.sin(character_st.chr_yaw) let fz = -Math.cos(character_st.chr_yaw) let take = Math.clamp(CharacterGround.current(character_st.chr_x, character_st.chr_z, fx, fz), 0.0, 1.0) if take > 0.0 { character_st.chr_speed = character_st.chr_speed * (1.0 - take) if take > 0.55 and character_st.chr_edge_said < 0.0 { character_st.chr_edge_said = 12.0 chr_say(character_st, CHAR_CURRENT, take) } } character_st.chr_edge_said = character_st.chr_edge_said - dt }