zones_set / zones_clear / zones_merge, zones_contains / zones_nearest and the clusters' bounding circles, over fixed arrays of ZONES_MAX (16). WildlifeWorld.active freezes an animal outside (no state change, no dice), NpcWorld.active a walker (and no birth outside), VehicleWorld.active a moored boat, and ThingsWorld.restocks keeps a morning's restock inside; every default is "everywhere", so an unbound game is unchanged. Tests: the merge (near players one cluster, far two, a player leaving splits a chain), contains, nearest, the radius; wildlife, npc, vehicles and things pass as before. Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
86 lines
3.5 KiB
Text
86 lines
3.5 KiB
Text
# ride.ludic - the rider's stick steers what they are on: a horse walks, canters on stamina and
|
|
# stops at water, a slope or a trunk; a boat is rowed - a stroke and a turn handed to its hull,
|
|
# which the water floats, the wind drifts and the lake bed stops
|
|
const VE_ROW: float = 630.0 # N: a full stroke forward, about 3 m/s on Maroon Lake's hull
|
|
const VE_ROW_TURN: float = 270.0 # N.m: the oars pulled against each other, about 1.1 rad/s
|
|
const VE_WIND: float = 70.0 # N on a boat in a full wind
|
|
|
|
export function vehicle_update(vehicles_st: mut VehiclesState, ix: float, iz: float, run: bool, dt: float) -> void {
|
|
let v = vehicles_st.ve_cur
|
|
if v == null { return }
|
|
if v.kind == VEHICLE_BOAT { ve_row(vehicles_st, v, ix, iz, dt) } else { ve_ride_horse(vehicles_st, v, ix, iz, run, dt) }
|
|
VehicleWorld.placed(v)
|
|
VehicleRider.ride_at(v.x, v.y + v.seat_h, v.z, v.yaw, Math.abs(v.speed))
|
|
}
|
|
|
|
# the stick is the oars: forward and back a stroke, left and right the two pulled against each
|
|
# other; the swell at the edge takes the outward share of a stroke
|
|
function ve_row(vehicles_st: mut VehiclesState, v: Vehicle, ix: float, iz: float, dt: float) -> void {
|
|
ve_hull_read(v)
|
|
let take = ve_swell(vehicles_st, v, iz, dt)
|
|
VehicleHull.row(v.nid, iz * VE_ROW * (1.0 - take), -ix * VE_ROW_TURN)
|
|
let d = Math.abs(v.speed) * dt
|
|
if d > 0.0 { ve_moved_add(vehicles_st, v, d) }
|
|
}
|
|
|
|
# where the hull is now, and how fast it goes along its bow
|
|
function ve_hull_read(v: Vehicle) -> void {
|
|
if not VehicleHull.read(v.nid) { return }
|
|
v.x = VehicleHull.x()
|
|
v.y = VehicleHull.y()
|
|
v.z = VehicleHull.z()
|
|
v.yaw = VehicleHull.yaw()
|
|
v.speed = VehicleHull.speed()
|
|
}
|
|
|
|
# a boat gets a longer leash than a swimmer and the same current at the end of it: the outward
|
|
# part of the stroke only, so a boat at the limit can always be put about. The share it takes.
|
|
function ve_swell(vehicles_st: mut VehiclesState, v: Vehicle, iz: float, dt: float) -> float {
|
|
var fx = -Math.sin(v.yaw)
|
|
var fz = -Math.cos(v.yaw)
|
|
if iz < 0.0 {
|
|
fx = -fx
|
|
fz = -fz
|
|
}
|
|
let take = Math.clamp(VehicleWorld.swell(v.x, v.z, fx, fz), 0.0, 1.0)
|
|
if take > 0.55 and vehicles_st.ve_swell_said < 0.0 {
|
|
vehicles_st.ve_swell_said = 14.0
|
|
ve_say(vehicles_st, VEHICLE_SWELL, v, take)
|
|
}
|
|
vehicles_st.ve_swell_said = vehicles_st.ve_swell_said - dt
|
|
return take
|
|
}
|
|
|
|
# every boat: a rowed one pushed by the wind across the lake; one nobody rows moored where it was
|
|
# called or left, its hull read back and held there
|
|
export function vehicles_tick(vehicles_st: VehiclesState, dt: float) -> void {
|
|
let l = ve_all(vehicles_st)
|
|
let w = VehicleWorld.wind() * VE_WIND
|
|
let wy = VehicleWorld.wind_yaw()
|
|
for i in 0 .. len(l) {
|
|
let v = l[i]
|
|
if v.kind != VEHICLE_BOAT { continue }
|
|
if v.rider >= 0 {
|
|
if w > 0.0 { VehicleHull.drift(v.nid, -Math.sin(wy) * w, -Math.cos(wy) * w) }
|
|
continue
|
|
}
|
|
if not VehicleWorld.active(v.x, v.z) { continue } # outside every zone: left where it lies
|
|
ve_hull_read(v)
|
|
ve_hold(v)
|
|
VehicleWorld.placed(v)
|
|
}
|
|
}
|
|
|
|
# a moored hull that has moved off its mooring (a knock, the swell) is put back on it, at rest
|
|
function ve_hold(v: Vehicle) -> void {
|
|
let dx = v.x - v.home_x
|
|
let dz = v.z - v.home_z
|
|
let dyaw = Math.abs(Math.atan2(Math.sin(v.yaw - v.home_yaw), Math.cos(v.yaw - v.home_yaw)))
|
|
if dx * dx + dz * dz < 0.0004 and dyaw < 0.01 and Math.abs(v.speed) < 0.01 { return }
|
|
v.x = v.home_x
|
|
v.z = v.home_z
|
|
v.yaw = v.home_yaw
|
|
v.y = VehicleWorld.water(v.x, v.z) + 0.02
|
|
v.speed = 0.0
|
|
VehicleHull.put(v.nid, v.x, v.y, v.z, v.yaw)
|
|
}
|