diff --git a/packages/ludic.vehicles/call.ludic b/packages/ludic.vehicles/call.ludic index 168d0c92..12ed5764 100644 --- a/packages/ludic.vehicles/call.ludic +++ b/packages/ludic.vehicles/call.ludic @@ -1,10 +1,11 @@ # call.ludic - a player's boat or horse brought to a place: made there the first time, fetched there # after; gone when its player leaves -function ve_add(vehicles_st: VehiclesState, kind: int, x: float, z: float, yaw: float) -> Vehicle { +function ve_add(vehicles_st: VehiclesState, kind: int, owner: int, x: float, z: float, yaw: float) -> Vehicle { if kind != VEHICLE_HORSE and kind != VEHICLE_BOAT { return null } let v = new Vehicle v.nid = VehicleWorld.next_id() v.kind = kind + v.owner = owner v.yaw = yaw if kind == VEHICLE_HORSE { v.seat_h = 1.35 @@ -14,7 +15,7 @@ function ve_add(vehicles_st: VehiclesState, kind: int, x: float, z: float, yaw: v.seat_h = 0.30 } ve_put(v, x, z) - push(ve_all(vehicles_st), v) + ve_file(vehicles_st.ve, v) ve_settle(v) VehicleWorld.made(v) return v @@ -51,9 +52,8 @@ export function vehicle_call_for(vehicles_st: VehiclesState, pid: int, kind: int var yaw = vehicles_st.ve_dock_yaw if kind == VEHICLE_HORSE { yaw = vehicles_st.ve_rail_yaw } if v == null { - let made = ve_add(vehicles_st, kind, vehicle_place_x(vehicles_st, kind, k), vehicle_place_z(vehicles_st, kind, k), yaw) + let made = ve_add(vehicles_st, kind, pid, vehicle_place_x(vehicles_st, kind, k), vehicle_place_z(vehicles_st, kind, k), yaw) if made == null { return false } - made.owner = pid if pid == 0 { ve_apply_kept(vehicles_st, made) } return true } @@ -68,10 +68,10 @@ export function vehicle_call_for(vehicles_st: VehiclesState, pid: int, kind: int # a player left: their boat and horse go with them, and their places are free export function vehicles_release(vehicles_st: mut VehiclesState, pid: int) -> void { if pid == 0 { return } - let keep = new []Vehicle - let l = ve_all(vehicles_st) - for i in 0 .. len(l) { - if l[i].owner != pid { push(keep, l[i]) } else { ve_gone(l[i]) } + let rows = ix_rows(vehicles_st.ve.owners, pid) + while len(rows) > 0 { + let v = ve_all(vehicles_st)[rows[len(rows) - 1]] + ve_gone(v) + ve_unfile(vehicles_st.ve, v) } - vehicles_st.ve_list = keep } diff --git a/packages/ludic.vehicles/index.ludic b/packages/ludic.vehicles/index.ludic index ab502dd3..087da740 100644 --- a/packages/ludic.vehicles/index.ludic +++ b/packages/ludic.vehicles/index.ludic @@ -5,6 +5,7 @@ module ludic_vehicles uses ludic_base numbers float import "ludic.base" import "kinds.ludic" +import "table.ludic" import "ports.ludic" import "state.ludic" import "places.ludic" diff --git a/packages/ludic.vehicles/kinds.ludic b/packages/ludic.vehicles/kinds.ludic index 9b78a6d4..0d469d65 100644 --- a/packages/ludic.vehicles/kinds.ludic +++ b/packages/ludic.vehicles/kinds.ludic @@ -19,6 +19,8 @@ export property Vehicle { rider: int = -1 # the player on it, -1 nobody home_x: float = 0.0 # a horse is tied where its home is home_z: float = 0.0 + ent: int = -1 # its handle in the table + tab: Table = null } export const VEHICLE_MOUNTED: int = 0 diff --git a/packages/ludic.vehicles/ports.ludic b/packages/ludic.vehicles/ports.ludic index 690eccca..3add3590 100644 --- a/packages/ludic.vehicles/ports.ludic +++ b/packages/ludic.vehicles/ports.ludic @@ -45,7 +45,7 @@ export state VehiclesState { ve_ids: int = 0 ve_sx: float = 0.0 ve_sz: float = 0.0 - ve_list: []Vehicle = new []Vehicle + ve: VehicleTable = ve__new() ve_cur: Vehicle = null ve_dock_x: float = 0.0 ve_dock_z: float = 0.0 diff --git a/packages/ludic.vehicles/state.ludic b/packages/ludic.vehicles/state.ludic index 03b826f7..dfbb3559 100644 --- a/packages/ludic.vehicles/state.ludic +++ b/packages/ludic.vehicles/state.ludic @@ -18,7 +18,7 @@ function ve_say(vehicles_st: VehiclesState, what: int, v: Vehicle, n: float) -> q_push(vehicle_facts(vehicles_st), f) } -function ve_all(vehicles_st: VehiclesState) -> []Vehicle { return vehicles_st.ve_list } +function ve_all(vehicles_st: VehiclesState) -> []Vehicle { return vehicles_st.ve.tab.rec } # every vehicle in the valley, to draw and to aim at (change one only through the verbs) export function vehicles_all(vehicles_st: VehiclesState) -> []Vehicle { return ve_all(vehicles_st) } @@ -32,8 +32,9 @@ export function vehicle_ride_kind(vehicles_st: VehiclesState) -> int { export function vehicle_current(vehicles_st: VehiclesState) -> Vehicle { return vehicles_st.ve_cur } export function vehicle_of(vehicles_st: VehiclesState, pid: int, kind: int) -> Vehicle { + let rows = ix_rows(vehicles_st.ve.owners, pid) let l = ve_all(vehicles_st) - for i in 0 .. len(l) { if l[i].kind == kind and l[i].owner == pid { return l[i] } } + for k in 0 .. len(rows) { if l[rows[k]].kind == kind { return l[rows[k]] } } return null } diff --git a/packages/ludic.vehicles/system.ludic b/packages/ludic.vehicles/system.ludic index fb6712f0..619ef7ab 100644 --- a/packages/ludic.vehicles/system.ludic +++ b/packages/ludic.vehicles/system.ludic @@ -2,13 +2,14 @@ # and the horse's hay); where they lie is not saved - they are called again. The boats' hulls are # read back and pushed by the wind in vehicles_tick, which the game calls where the world is run export function vehicles_reset(vehicles_st: mut VehiclesState) -> void { - if vehicles_st.ve_list != null { - for i in 0 .. len(vehicles_st.ve_list) { - let v = vehicles_st.ve_list[i] - if v.kind == VEHICLE_BOAT { VehicleHull.gone(v.nid) } else { VehicleLegs.gone(v.nid) } - } + let l = ve_all(vehicles_st) + for i in 0 .. len(l) { + let v = l[i] + if v.kind == VEHICLE_BOAT { VehicleHull.gone(v.nid) } else { VehicleLegs.gone(v.nid) } + v.ent = -1 } - vehicles_st.ve_list = new []Vehicle + tb_clear(vehicles_st.ve.tab) + imap_clear(vehicles_st.ve.nids) vehicles_st.ve_cur = null vehicles_st.ve_have_dock = false vehicles_st.ve_swell_said = 0.0 diff --git a/packages/ludic.vehicles/table.ludic b/packages/ludic.vehicles/table.ludic new file mode 100644 index 00000000..96183951 --- /dev/null +++ b/packages/ludic.vehicles/table.ludic @@ -0,0 +1,45 @@ +# table.ludic - the vehicles, rows of a ludic.base Table: kind and owner as columns, each player's +# own by index, and a nid to its handle. Where one is stays on its record: a boat moves every frame +# and there are never more than two a player to search. +export const VE_KIND: int = 0 # int columns +export const VE_OWNER: int = 1 + +export property VehicleTable { + tab: Table = null + owners: IntIndex = null # every vehicle by the player it belongs to + nids: IntMap = null +} + +function ve__new() -> VehicleTable { + let w = new VehicleTable + let tb: Table = table_new(0, 2) + w.tab = tb + w.owners = tb_index(tb, VE_OWNER, -1) + w.nids = imap_new() + return w +} + +# a new row for v, its kind and owner from its record +function ve_file(w: VehicleTable, v: Vehicle) -> void { + v.tab = w.tab + v.ent = tb_add(w.tab, v) + let r = tb_row(w.tab, v.ent) + w.tab.i[VE_KIND][r] = v.kind + w.tab.i[VE_OWNER][r] = v.owner + tb_refile(w.tab, r) + imap_put(w.nids, v.nid, v.ent) +} + +function ve_unfile(w: VehicleTable, v: Vehicle) -> void { + imap_del(w.nids, v.nid) + tb_remove(w.tab, v.ent) + v.ent = -1 +} + +# the vehicle a message names, or null +export function vehicle_by_nid(vehicles_st: VehiclesState, nid: int) -> Vehicle { + let tb = vehicles_st.ve.tab + let r = tb_row(tb, imap_get(vehicles_st.ve.nids, nid, -1)) + if r < 0 or tb.rec[r].nid != nid { return null } + return tb.rec[r] +} diff --git a/packages/ludic.vehicles/tests/vehicles_test.ludic b/packages/ludic.vehicles/tests/vehicles_test.ludic index 62b2c790..653caf78 100644 --- a/packages/ludic.vehicles/tests/vehicles_test.ludic +++ b/packages/ludic.vehicles/tests/vehicles_test.ludic @@ -344,4 +344,23 @@ program VehiclesTest { expect_near(vehicle_find(vehicles_st, VEHICLE_HORSE).food, 77.0, 0.01) expect(not vehicle_find(vehicles_st, VEHICLE_BOAT).owned) } + + test "the table: a nid finds its vehicle, each player's own by the owner index, and a release takes both" (vehicles_st: mut VehiclesState, vehicles_test_st: mut VehiclesTestState) { + fresh(vehicles_st, vehicles_test_st) + vehicle_call_for(vehicles_st, 5, VEHICLE_HORSE, 0) + vehicle_call_for(vehicles_st, 5, VEHICLE_BOAT, 0) + vehicle_call_for(vehicles_st, 6, VEHICLE_BOAT, 1) + let b = vehicle_of(vehicles_st, 6, VEHICLE_BOAT) + expect(b != null) + expect(vehicle_by_nid(vehicles_st, b.nid) == b) + expect(vehicle_of(vehicles_st, 6, VEHICLE_HORSE) == null) + let h = vehicle_of(vehicles_st, 5, VEHICLE_HORSE) + vehicles_release(vehicles_st, 5) + expect_eq(len(vehicles_all(vehicles_st)), 1) + expect(vehicle_by_nid(vehicles_st, h.nid) == null) + expect(vehicle_of(vehicles_st, 6, VEHICLE_BOAT) == b) + vehicles_reset(vehicles_st) + expect_eq(len(vehicles_all(vehicles_st)), 0) + expect(vehicle_by_nid(vehicles_st, b.nid) == null) + } }