feat(base): 0.R4 - a queue keeps its own count, so every package verb takes only its own state; ludic migrate state --prune

ludic.base's Queue<T> carries a QueueTag (its name and pending count): queue_new(name), q_push(q, v),
q_drain(q), q_clear(q) take no BaseState, and core_undrained(tags) names the given queues still holding
facts. A reducer on a package's state can now call that package's verbs (wallet_earn(wallet_st, n)).

ludic migrate state --prune (ludicc --migrate-prune) takes out each state parameter a function no
longer uses, nor anything it calls, and the argument that fills it - including an argument for a
parameter the callee has dropped, which is taken out before the call is checked, so a generic's T is
told by the argument that says it. A reducer keeps its state. --dry-run now counts the edits it would
make. Every package was moved with it: 608 base_st parameters and their arguments, 1889 edits.

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
This commit is contained in:
Orkun ÇAKILKAYA 2026-09-26 04:19:56 +03:00
parent 8cf4b3fed6
commit 71735b10a2
151 changed files with 58668 additions and 54719 deletions

View file

@ -67,10 +67,10 @@ export function vehicles_release(vehicles_st: mut VehiclesState, pid: int) -> vo
export function vehicle_own(v: Vehicle) -> void { if v != null { v.owned = true } }
# hay for a horse, up to a full belly
export function vehicle_feed(base_st: mut BaseState, vehicles_st: mut VehiclesState, v: Vehicle, amount: float) -> void {
export function vehicle_feed(vehicles_st: mut VehiclesState, v: Vehicle, amount: float) -> void {
if v == null { return }
v.food = Math.min(v.food + amount, 100.0)
ve_say(base_st, vehicles_st, VEHICLE_FED, v, amount)
ve_say(vehicles_st, VEHICLE_FED, v, amount)
}
# a horse nobody rides goes where its animal goes, round the home it is tied at (home_x, home_z)

View file

@ -4,27 +4,27 @@
export const VEHICLE_HAY_MIN: float = 10.0 # a horse with less hay than this will not go
# this machine's player onto v; false when it is somebody else's, taken, or a hungry horse
export function vehicle_mount(base_st: mut BaseState, vehicles_st: mut VehiclesState, v: Vehicle) -> bool {
export function vehicle_mount(vehicles_st: mut VehiclesState, v: Vehicle) -> bool {
if v == null or v.owner != 0 or v.rider >= 0 or vehicles_st.ve_cur != null { return false }
if v.kind == VEHICLE_HORSE and v.food < VEHICLE_HAY_MIN {
ve_say(base_st, vehicles_st, VEHICLE_HUNGRY, v, v.food)
ve_say(vehicles_st, VEHICLE_HUNGRY, v, v.food)
return false
}
vehicles_st.ve_cur = v
v.rider = 0
VehicleRider.board(v.x, v.z, v.yaw)
ve_say(base_st, vehicles_st, VEHICLE_MOUNTED, v, 0.0)
ve_say(vehicles_st, VEHICLE_MOUNTED, v, 0.0)
return true
}
# Off, onto the nearest spot a body could stand and walk off: from a boat a wade of up to 1.25 m
# within ten metres, from a horse beside its right flank. False (and said) when a boat is too far out.
export function vehicle_dismount(base_st: mut BaseState, vehicles_st: mut VehiclesState) -> bool {
export function vehicle_dismount(vehicles_st: mut VehiclesState) -> bool {
let v = vehicles_st.ve_cur
if v == null { return false }
if v.kind == VEHICLE_BOAT {
if not VehicleRider.safe_spot(v.x, v.z, VehicleWorld.water(v.x, v.z), 1.25) {
ve_say(base_st, vehicles_st, VEHICLE_NO_LANDING, v, 0.0)
ve_say(vehicles_st, VEHICLE_NO_LANDING, v, 0.0)
return false
}
VehicleRider.step_off(VehicleRider.safe_x(), VehicleRider.safe_z())
@ -40,7 +40,7 @@ export function vehicle_dismount(base_st: mut BaseState, vehicles_st: mut Vehicl
vehicles_st.ve_cur = null
v.rider = -1
v.speed = 0.0
ve_say(base_st, vehicles_st, VEHICLE_DISMOUNTED, v, 0.0)
ve_say(vehicles_st, VEHICLE_DISMOUNTED, v, 0.0)
return true
}

View file

@ -8,7 +8,7 @@ const VE_BOAT_TOP: float = 3.2
const VE_BOAT_ACC: float = 1.2
const VE_BOAT_TURN: float = 1.1
export function vehicle_update(base_st: mut BaseState, vehicles_st: mut VehiclesState, ix: float, iz: float, run: bool, dt: float) -> void {
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 }
var top = VE_BOAT_TOP
@ -21,7 +21,7 @@ export function vehicle_update(base_st: mut BaseState, vehicles_st: mut Vehicles
if run and v.fuel > 5.0 { top = VE_HORSE_GALLOP }
}
v.speed = v.speed + Math.clamp(iz * top - v.speed, -acc * dt, acc * dt)
if v.kind == VEHICLE_BOAT { ve_swell(base_st, vehicles_st, v, dt) }
if v.kind == VEHICLE_BOAT { ve_swell(vehicles_st, v, dt) }
# Steering follows SIGNED speed: backing up with the stick left swings the nose right
if Math.abs(v.speed) > 0.3 {
var rate = Math.clamp(Math.abs(v.speed) / 3.0, 0.4, 1.0)
@ -29,14 +29,14 @@ export function vehicle_update(base_st: mut BaseState, vehicles_st: mut Vehicles
v.yaw = v.yaw - ix * turn * (dt * rate)
}
let d = v.speed * dt
ve_travel(base_st, vehicles_st, v, v.x - Math.sin(v.yaw) * d, v.z - Math.cos(v.yaw) * d, d)
ve_travel(vehicles_st, v, v.x - Math.sin(v.yaw) * d, v.z - Math.cos(v.yaw) * d, d)
if v.kind == VEHICLE_HORSE { ve_stamina(v, d, dt) } else { ve_float(v, d, dt) }
VehicleWorld.placed(v)
VehicleRider.ride_at(v.x, v.y + v.seat_h, v.z, v.yaw, Math.abs(v.speed))
}
# a boat only where there is water under it; a horse only on dry ground, up a walkable rise, clear
function ve_travel(base_st: mut BaseState, vehicles_st: mut VehiclesState, v: Vehicle, nx: float, nz: float, d: float) -> void {
function ve_travel(vehicles_st: mut VehiclesState, v: Vehicle, nx: float, nz: float, d: float) -> void {
let nh = VehicleWorld.ground(nx, nz)
var ok = true
if v.kind == VEHICLE_BOAT { ok = nh < VehicleWorld.water(nx, nz) - 0.35 } else {
@ -51,12 +51,12 @@ function ve_travel(base_st: mut BaseState, vehicles_st: mut VehiclesState, v: Ve
v.x = nx
v.z = nz
if v.kind != VEHICLE_BOAT { v.y = nh }
if Math.abs(d) > 0.0 { ve_say(base_st, vehicles_st, VEHICLE_MOVED, v, Math.abs(d)) }
if Math.abs(d) > 0.0 { ve_say(vehicles_st, VEHICLE_MOVED, v, Math.abs(d)) }
}
# 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
function ve_swell(base_st: mut BaseState, vehicles_st: mut VehiclesState, v: Vehicle, dt: float) -> void {
function ve_swell(vehicles_st: mut VehiclesState, v: Vehicle, dt: float) -> void {
var fx = -Math.sin(v.yaw)
var fz = -Math.cos(v.yaw)
if v.speed < 0.0 {
@ -67,7 +67,7 @@ function ve_swell(base_st: mut BaseState, vehicles_st: mut VehiclesState, v: Veh
v.speed = v.speed * (1.0 - take)
if take > 0.55 and vehicles_st.ve_swell_said < 0.0 {
vehicles_st.ve_swell_said = 14.0
ve_say(base_st, vehicles_st, VEHICLE_SWELL, v, take)
ve_say(vehicles_st, VEHICLE_SWELL, v, take)
}
vehicles_st.ve_swell_said = vehicles_st.ve_swell_said - dt
}

View file

@ -2,12 +2,12 @@
# from, and the facts
const ve_pi: float = 3.14159265
export function vehicle_facts(base_st: mut BaseState, vehicles_st: mut VehiclesState) -> Queue<VehicleFact> {
if vehicles_st.ve_fact_q == null { vehicles_st.ve_fact_q = queue_new(base_st, "vehicles.facts") }
export function vehicle_facts(vehicles_st: mut VehiclesState) -> Queue<VehicleFact> {
if vehicles_st.ve_fact_q == null { vehicles_st.ve_fact_q = queue_new("vehicles.facts") }
return vehicles_st.ve_fact_q
}
function ve_say(base_st: mut BaseState, vehicles_st: mut VehiclesState, what: int, v: Vehicle, n: float) -> void {
function ve_say(vehicles_st: mut VehiclesState, what: int, v: Vehicle, n: float) -> void {
let f = new VehicleFact
f.what = what
f.nid = v.nid
@ -16,7 +16,7 @@ function ve_say(base_st: mut BaseState, vehicles_st: mut VehiclesState, what: in
f.x = v.x
f.z = v.z
f.v = n
q_push(base_st, vehicle_facts(base_st, vehicles_st), f)
q_push(vehicle_facts(vehicles_st), f)
}
function ve_all(vehicles_st: mut VehiclesState) -> []Vehicle {

View file

@ -1,7 +1,7 @@
# system.ludic - vehicles as a system: a reset, and this player's own saved by kind (hired or not,
# and the horse's hay); where they lie is not saved - they are called again. The idle boats' bob is
# vehicles_tick, which the game calls where the world is run
export function vehicles_reset(base_st: mut BaseState, vehicles_st: mut VehiclesState) -> void {
export function vehicles_reset(vehicles_st: mut VehiclesState) -> void {
vehicles_st.ve_list = new []Vehicle
vehicles_st.ve_cur = null
vehicles_st.ve_have_dock = false
@ -9,7 +9,7 @@ export function vehicles_reset(base_st: mut BaseState, vehicles_st: mut Vehicles
vehicles_st.ve_kept_horse = false
vehicles_st.ve_kept_boat = false
vehicles_st.ve_kept_food = 40.0
q_clear(base_st, vehicle_facts(base_st, vehicles_st))
q_clear(vehicle_facts(vehicles_st))
}
export function vehicles_save(vehicles_st: mut VehiclesState) -> Val {

View file

@ -70,8 +70,8 @@ program VehiclesTest {
const EAST: float = -1.5707963
function fresh(base_st: mut BaseState, vehicles_st: mut VehiclesState, vehicles_test_st: mut VehiclesTestState) -> void {
vehicles_reset(base_st, vehicles_st)
function fresh(vehicles_st: mut VehiclesState, vehicles_test_st: mut VehiclesTestState) -> void {
vehicles_reset(vehicles_st)
vehicles_dock_at(vehicles_st, 10.0, 0.0, EAST)
vehicles_rail_at(vehicles_st, 0.0, 5.0, 0.0)
vehicles_test_st.made = 0
@ -79,26 +79,26 @@ program VehiclesTest {
vehicles_test_st.swell = 0.0
vehicles_test_st.wind = 0.0
}
function facts(base_st: mut BaseState, vehicles_st: mut VehiclesState) -> []VehicleFact { return q_drain(base_st, vehicle_facts(base_st, vehicles_st)) }
function facts(vehicles_st: mut VehiclesState) -> []VehicleFact { return q_drain(vehicle_facts(vehicles_st)) }
function count(fs: []VehicleFact, what: int) -> int {
var n = 0
for i in 0 .. len(fs) { if fs[i].what == what { n += 1 } }
return n
}
function ride(base_st: mut BaseState, vehicles_st: mut VehiclesState, ix: float, iz: float, run: bool, secs: float) -> void {
for i in 0 .. int(secs * 60.0) { vehicle_update(base_st, vehicles_st, ix, iz, run, 1.0 / 60.0) }
function ride(vehicles_st: mut VehiclesState, ix: float, iz: float, run: bool, secs: float) -> void {
for i in 0 .. int(secs * 60.0) { vehicle_update(vehicles_st, ix, iz, run, 1.0 / 60.0) }
}
test "a berth is off the pier head in the water, a bay on the meadow" (base_st: mut BaseState, vehicles_st: mut VehiclesState, vehicles_test_st: mut VehiclesTestState) {
fresh(base_st, vehicles_st, vehicles_test_st)
test "a berth is off the pier head in the water, a bay on the meadow" (vehicles_st: mut VehiclesState, vehicles_test_st: mut VehiclesTestState) {
fresh(vehicles_st, vehicles_test_st)
expect_near(vehicle_berth_x(vehicles_st, 0), 17.25, 0.01)
expect_near(vehicle_berth_z(vehicles_st, 0), -3.3, 0.01)
expect_near(vehicle_post_x(vehicles_st, 3), 16.15, 0.01)
expect_near(vehicle_bay_z(vehicles_st, 2), 3.6, 0.01)
}
test "the first call makes a vehicle, a later one fetches it, and a taken place refuses" (base_st: mut BaseState, vehicles_st: mut VehiclesState, vehicles_test_st: mut VehiclesTestState) {
fresh(base_st, vehicles_st, vehicles_test_st)
test "the first call makes a vehicle, a later one fetches it, and a taken place refuses" (vehicles_st: mut VehiclesState, vehicles_test_st: mut VehiclesTestState) {
fresh(vehicles_st, vehicles_test_st)
expect(vehicle_call_for(vehicles_st, 0, VEHICLE_BOAT, 0))
expect_eq(vehicles_test_st.made, 1)
let b = vehicle_find(vehicles_st, VEHICLE_BOAT)
@ -115,8 +115,8 @@ program VehiclesTest {
expect(vehicle_mine_in_place(vehicles_st, VEHICLE_BOAT))
}
test "a player leaving takes theirs away; this machine's player never leaves" (base_st: mut BaseState, vehicles_st: mut VehiclesState, vehicles_test_st: mut VehiclesTestState) {
fresh(base_st, vehicles_st, vehicles_test_st)
test "a player leaving takes theirs away; this machine's player never leaves" (vehicles_st: mut VehiclesState, vehicles_test_st: mut VehiclesTestState) {
fresh(vehicles_st, vehicles_test_st)
vehicle_call_for(vehicles_st, 0, VEHICLE_HORSE, 0)
vehicle_call_for(vehicles_st, 3, VEHICLE_HORSE, 1)
vehicles_release(vehicles_st, 0)
@ -127,19 +127,19 @@ program VehiclesTest {
expect(vehicle_in_place(vehicles_st, VEHICLE_HORSE, 1) == null)
}
test "a hungry horse will not go; a fed one is mounted, and only by its owner" (base_st: mut BaseState, vehicles_st: mut VehiclesState, vehicles_test_st: mut VehiclesTestState) {
fresh(base_st, vehicles_st, vehicles_test_st)
test "a hungry horse will not go; a fed one is mounted, and only by its owner" (vehicles_st: mut VehiclesState, vehicles_test_st: mut VehiclesTestState) {
fresh(vehicles_st, vehicles_test_st)
vehicle_call_for(vehicles_st, 0, VEHICLE_HORSE, 0)
vehicle_call_for(vehicles_st, 4, VEHICLE_HORSE, 1)
let h = vehicle_find(vehicles_st, VEHICLE_HORSE)
h.food = 5.0
expect(not vehicle_mount(base_st, vehicles_st, h))
expect_eq(count(facts(base_st, vehicles_st), VEHICLE_HUNGRY), 1)
vehicle_feed(base_st, vehicles_st, h, 50.0)
expect(not vehicle_mount(vehicles_st, h))
expect_eq(count(facts(vehicles_st), VEHICLE_HUNGRY), 1)
vehicle_feed(vehicles_st, h, 50.0)
expect_near(h.food, 55.0, 0.001)
expect(not vehicle_mount(base_st, vehicles_st, vehicle_of(vehicles_st, 4, VEHICLE_HORSE)))
expect(not vehicle_mount(vehicles_st, vehicle_of(vehicles_st, 4, VEHICLE_HORSE)))
vehicles_test_st.boarded = 0
expect(vehicle_mount(base_st, vehicles_st, h))
expect(vehicle_mount(vehicles_st, h))
expect_eq(vehicles_test_st.boarded, 1)
expect_eq(vehicle_ride_kind(vehicles_st), VEHICLE_HORSE)
expect_eq(h.rider, 0)
@ -147,22 +147,22 @@ program VehiclesTest {
expect(vehicle_in_place(vehicles_st, VEHICLE_HORSE, 0) == null)
}
test "a horse walks, gallops on stamina, stops at the water and at a trunk" (base_st: mut BaseState, vehicles_st: mut VehiclesState, vehicles_test_st: mut VehiclesTestState) {
fresh(base_st, vehicles_st, vehicles_test_st)
test "a horse walks, gallops on stamina, stops at the water and at a trunk" (vehicles_st: mut VehiclesState, vehicles_test_st: mut VehiclesTestState) {
fresh(vehicles_st, vehicles_test_st)
vehicle_call_for(vehicles_st, 0, VEHICLE_HORSE, 0)
let h = vehicle_find(vehicles_st, VEHICLE_HORSE)
vehicle_mount(base_st, vehicles_st, h)
ride(base_st, vehicles_st, 0.0, 1.0, false, 3.0)
vehicle_mount(vehicles_st, h)
ride(vehicles_st, 0.0, 1.0, false, 3.0)
expect_near(h.speed, 4.5, 0.05)
expect(count(facts(base_st, vehicles_st), VEHICLE_MOVED) > 100)
ride(base_st, vehicles_st, 0.0, 1.0, true, 3.0)
expect(count(facts(vehicles_st), VEHICLE_MOVED) > 100)
ride(vehicles_st, 0.0, 1.0, true, 3.0)
expect_near(h.speed, 11.0, 0.1)
expect(h.fuel < 100.0)
expect(h.z < -15.0)
expect_near(vehicles_test_st.rz, h.z, 0.001)
expect_near(vehicles_test_st.ry, 1.35, 0.001)
# the trunk at z = -60 stops it
ride(base_st, vehicles_st, 0.0, 1.0, true, 6.0)
ride(vehicles_st, 0.0, 1.0, true, 6.0)
expect(h.z > -60.0 + 1.7)
expect_near(h.speed, 0.0, 0.001)
# and the lake to the east does too
@ -170,65 +170,65 @@ program VehiclesTest {
h.x = 7.0
h.z = 0.0
h.yaw = EAST
vehicle_mount(base_st, vehicles_st, h)
ride(base_st, vehicles_st, 0.0, 1.0, false, 4.0)
vehicle_mount(vehicles_st, h)
ride(vehicles_st, 0.0, 1.0, false, 4.0)
expect(h.x < 9.6)
}
test "a boat rows on water, stops at the shore, loses its stroke to the swell, drifts on the wind" (base_st: mut BaseState, vehicles_st: mut VehiclesState, vehicles_test_st: mut VehiclesTestState) {
fresh(base_st, vehicles_st, vehicles_test_st)
test "a boat rows on water, stops at the shore, loses its stroke to the swell, drifts on the wind" (vehicles_st: mut VehiclesState, vehicles_test_st: mut VehiclesTestState) {
fresh(vehicles_st, vehicles_test_st)
vehicle_call_for(vehicles_st, 0, VEHICLE_BOAT, 0)
let b = vehicle_find(vehicles_st, VEHICLE_BOAT)
vehicle_mount(base_st, vehicles_st, b)
ride(base_st, vehicles_st, 0.0, 1.0, false, 2.0)
vehicle_mount(vehicles_st, b)
ride(vehicles_st, 0.0, 1.0, false, 2.0)
let x2 = b.x
expect(x2 > 18.0)
vehicles_test_st.swell = 1.0
ride(base_st, vehicles_st, 0.0, 1.0, false, 1.0)
ride(vehicles_st, 0.0, 1.0, false, 1.0)
expect_near(b.x, x2, 0.2)
expect_eq(count(facts(base_st, vehicles_st), VEHICLE_SWELL), 1)
expect_eq(count(facts(vehicles_st), VEHICLE_SWELL), 1)
vehicles_test_st.swell = 0.0
ride(base_st, vehicles_st, 0.0, -1.0, false, 12.0)
ride(vehicles_st, 0.0, -1.0, false, 12.0)
expect(b.x > 10.3)
vehicles_test_st.wind = 1.0
let z0 = b.z
ride(base_st, vehicles_st, 0.0, 0.0, false, 1.0)
ride(vehicles_st, 0.0, 0.0, false, 1.0)
expect(b.z < z0)
}
test "getting off a boat needs a shore near enough; a horse is left tied where it stands" (base_st: mut BaseState, vehicles_st: mut VehiclesState, vehicles_test_st: mut VehiclesTestState) {
fresh(base_st, vehicles_st, vehicles_test_st)
test "getting off a boat needs a shore near enough; a horse is left tied where it stands" (vehicles_st: mut VehiclesState, vehicles_test_st: mut VehiclesTestState) {
fresh(vehicles_st, vehicles_test_st)
vehicle_call_for(vehicles_st, 0, VEHICLE_BOAT, 0)
let b = vehicle_find(vehicles_st, VEHICLE_BOAT)
vehicle_mount(base_st, vehicles_st, b)
vehicle_mount(vehicles_st, b)
b.x = 40.0
expect(not vehicle_dismount(base_st, vehicles_st))
expect_eq(count(facts(base_st, vehicles_st), VEHICLE_NO_LANDING), 1)
expect(not vehicle_dismount(vehicles_st))
expect_eq(count(facts(vehicles_st), VEHICLE_NO_LANDING), 1)
expect_eq(vehicle_ride_kind(vehicles_st), VEHICLE_BOAT)
b.x = 12.0
expect(vehicle_dismount(base_st, vehicles_st))
expect(vehicle_dismount(vehicles_st))
expect_near(vehicles_test_st.rx, 11.0, 0.001)
expect_eq(vehicle_ride_kind(vehicles_st), 0)
expect_eq(b.rider, -1)
vehicle_call_for(vehicles_st, 0, VEHICLE_HORSE, 0)
let h = vehicle_find(vehicles_st, VEHICLE_HORSE)
vehicle_mount(base_st, vehicles_st, h)
vehicle_mount(vehicles_st, h)
h.x = -5.0
h.z = -5.0
expect(vehicle_dismount(base_st, vehicles_st))
expect(vehicle_dismount(vehicles_st))
expect_near(h.home_x, -5.0, 0.001)
expect(vehicle_in_place(vehicles_st, VEHICLE_HORSE, 0) == null)
expect_near(vehicles_test_st.rx, -5.0 + 1.2, 0.001)
}
test "this player's own are saved by kind, and a save read before they are made still applies" (base_st: mut BaseState, vehicles_st: mut VehiclesState, vehicles_test_st: mut VehiclesTestState) {
fresh(base_st, vehicles_st, vehicles_test_st)
test "this player's own are saved by kind, and a save read before they are made still applies" (vehicles_st: mut VehiclesState, vehicles_test_st: mut VehiclesTestState) {
fresh(vehicles_st, vehicles_test_st)
vehicle_call_for(vehicles_st, 0, VEHICLE_HORSE, 0)
vehicle_call_for(vehicles_st, 0, VEHICLE_BOAT, 0)
vehicle_own(vehicle_find(vehicles_st, VEHICLE_HORSE))
vehicle_find(vehicles_st, VEHICLE_HORSE).food = 77.0
let saved = vehicles_save(vehicles_st)
fresh(base_st, vehicles_st, vehicles_test_st)
fresh(vehicles_st, vehicles_test_st)
vehicles_load(vehicles_st, saved, 1)
vehicle_call_for(vehicles_st, 0, VEHICLE_HORSE, 0)
vehicle_call_for(vehicles_st, 0, VEHICLE_BOAT, 0)