ludic/packages/ludic.vehicles/ports.ludic
Orkuncakilkaya 045bf22e10 feat(ecs): ludic.vehicles on a Table<Vehicle>
The vehicles are rows of a ludic.base Table with kind and owner as columns, every player's own by
an owner index and a nid map: vehicle_of walks only that player's rows, vehicle_by_nid is a map
lookup, and a player who leaves has their rows removed instead of the whole list rebuilt. ve_add
takes the owner, so the owner is filed once and never assigned around the table. Positions stay
on the record: a boat moves every frame and there are at most two a player. vehicles_test holds
the table (9 tests); the game builds against it and lab/unit passes (88 tests).

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
2026-09-27 21:50:23 +03:00

81 lines
3.9 KiB
Text

# ports.ludic - what a vehicle asks the world, its hull and its rider. Unbound, the world is dry
# flat ground with nothing in the way and no wind, and the rider is put exactly where asked; the
# hull has no default - a boat is a body in the game's physics.
export port VehicleWorld {
ground: fn(float, float) -> float
water: fn(float, float) -> float = fn ve__dry # the surface over a point
swell: fn(float, float, float, float) -> float = fn ve__calm # (x, z, fx, fz): 0..1 of a stroke lost
wind: fn() -> float = fn ve__zero # 0..1
wind_yaw: fn() -> float = fn ve__zero # the yaw the wind pushes toward
next_id: fn() -> int = fn ve__next
made: fn(Vehicle) -> void = fn ve__nothing # a new vehicle: draw it
placed: fn(Vehicle) -> void = fn ve__nothing # it moved: put its model there
gone: fn(Vehicle) -> void = fn ve__nothing # its owner left: take it away
}
# a boat's hull in the world's physics (Maroon Lake: a buoyant Jolt body), named by the vehicle's
# nid. The water floats it and the lake bed stops it; the package rows it and reads where it is.
export port VehicleHull {
put: fn(int, float, float, float, float) -> void # (nid, x, y, z, yaw): at rest there, made if new
row: fn(int, float, float) -> void # (nid, forward N, turn N.m) over the next step
drift: fn(int, float, float) -> void # (nid, fx, fz): a push across the water (wind)
read: fn(int) -> bool # (nid): its pose into x .. speed; false if none
x: fn() -> float
y: fn() -> float
z: fn() -> float
yaw: fn() -> float
speed: fn() -> float # along its bow, m/s
gone: fn(int) -> void # (nid): out of the world
}
# the body on board: the game's walking body (ludic.character, through the game)
export port VehicleRider {
board: fn(float, float, float) -> void = fn ve__board # (x, z, yaw)
ride_at: fn(float, float, float, float, float) -> void = fn ve__ride # (x, y, z, yaw, speed)
step_off: fn(float, float) -> void = fn ve__off # (x, z)
safe_spot: fn(float, float, float, float) -> bool = fn ve__safe # (x, z, from_y, max_depth)
safe_x: fn() -> float = fn ve__safe_x
safe_z: fn() -> float = fn ve__safe_z
}
export state VehiclesState {
ve_kept_horse: bool = false
ve_kept_boat: bool = false
ve_kept_food: float = 40.0
ve_ids: int = 0
ve_sx: float = 0.0
ve_sz: float = 0.0
ve: VehicleTable = ve__new()
ve_cur: Vehicle = null
ve_dock_x: float = 0.0
ve_dock_z: float = 0.0
ve_dock_yaw: float = 0.0
ve_rail_x: float = 0.0
ve_rail_z: float = 0.0
ve_rail_yaw: float = 0.0
ve_have_dock: bool = false
ve_swell_said: float = 0.0
ve_lx: float = 0.0 # the unbound legs' pose
ve_ly: float = 0.0
ve_lz: float = 0.0
ve_fact_q: Queue<VehicleFact> = ve_fact_q__new()
}
function ve__dry(x: float, z: float) -> float { return -10000.0 }
function ve__calm(x: float, z: float, fx: float, fz: float) -> float { return 0.0 }
function ve__zero() -> float { return 0.0 }
function ve__next(vehicles_st: mut VehiclesState) -> int {
vehicles_st.ve_ids += 1
return vehicles_st.ve_ids
}
function ve__nothing(v: Vehicle) -> void { }
function ve__board(x: float, z: float, yaw: float) -> void { }
function ve__ride(x: float, y: float, z: float, yaw: float, speed: float) -> void { }
function ve__off(x: float, z: float) -> void { }
function ve__safe(vehicles_st: mut VehiclesState, x: float, z: float, from_y: float, max_depth: float) -> bool {
vehicles_st.ve_sx = x
vehicles_st.ve_sz = z
return true
}
function ve__safe_x(vehicles_st: VehiclesState) -> float { return vehicles_st.ve_sx }
function ve__safe_z(vehicles_st: VehiclesState) -> float { return vehicles_st.ve_sz }
function ve_fact_q__new() -> Queue<VehicleFact> { return queue_new("vehicles.facts") }