Merge branch 'lang/foundations' into lang/nav
This commit is contained in:
commit
c2902a2246
12 changed files with 86 additions and 19 deletions
|
|
@ -14,6 +14,14 @@ export const PH_COMMIT: int = 4
|
|||
export const PH_PRESENT: int = 5
|
||||
export const PH_COUNT: int = 6
|
||||
|
||||
# the same Tick filled again: the frame loop keeps one and hands it on, rather than a new one a frame
|
||||
export function tick_set(t: Tick, dt: float, frame: int, hours: float) -> Tick {
|
||||
t.dt = dt
|
||||
t.frame = frame
|
||||
t.hours = hours
|
||||
return t
|
||||
}
|
||||
|
||||
export function tick_new(dt: float, frame: int, hours: float) -> Tick {
|
||||
let t = new Tick
|
||||
t.dt = dt
|
||||
|
|
|
|||
|
|
@ -1,30 +1,55 @@
|
|||
# gather.ludic - a frame's marks: begin, every provider marks, end sorts and culls. While a
|
||||
# capture is open the marks go to whoever is listening instead, whatever the tier.
|
||||
export function compass_begin(compass_st: mut CompassState) -> void { compass_st.cmp_list = new []CompassMark }
|
||||
# a frame's list and marks are the state's own, emptied and reused rather than made again
|
||||
export function compass_begin(compass_st: mut CompassState) -> void {
|
||||
if compass_st.cmp_list == null {
|
||||
compass_st.cmp_list = new []CompassMark
|
||||
compass_st.cmp_back = new []CompassMark
|
||||
compass_st.cmp_pool = new []CompassMark
|
||||
}
|
||||
List.clear(compass_st.cmp_list)
|
||||
compass_st.cmp_used = 0
|
||||
}
|
||||
|
||||
# a provider's verb: a thing at (x, z), shown from compass `tier` up
|
||||
export function compass_mark(compass_st: mut CompassState, x: float, z: float, icon: int, colour: int, tier: int, prio: int, label: string) -> void {
|
||||
if compass_st.cmp_list == null { compass_begin(compass_st) }
|
||||
let m = cmp_new(x, z, icon, colour, tier, prio, label)
|
||||
if compass_st.cmp_capturing {
|
||||
push(compass_st.cmp_caught, m)
|
||||
push(compass_st.cmp_caught, cmp_new(x, z, icon, colour, tier, prio, label)) # kept by the listener
|
||||
return
|
||||
}
|
||||
if CompassWorld.tier() < tier { return }
|
||||
push(compass_st.cmp_list, m)
|
||||
push(compass_st.cmp_list, cmp_take(compass_st, x, z, icon, colour, tier, prio, label))
|
||||
}
|
||||
|
||||
# highest priority first, the providers' order kept within one; then the cap
|
||||
export function compass_end(compass_st: mut CompassState) -> void {
|
||||
if compass_st.cmp_list == null { compass_begin(compass_st) }
|
||||
let out = new []CompassMark
|
||||
let out = compass_st.cmp_back
|
||||
List.clear(out)
|
||||
for p in 0 .. 3 {
|
||||
let want = COMPASS_TRACKED - p
|
||||
for i in 0 .. len(compass_st.cmp_list) { if cmp_band(compass_st.cmp_list[i].prio) == want and len(out) < compass_st.cmp_cap { push(out, compass_st.cmp_list[i]) } }
|
||||
}
|
||||
compass_st.cmp_back = compass_st.cmp_list
|
||||
compass_st.cmp_list = out
|
||||
}
|
||||
|
||||
# the pool's next mark, filled (one made only when the pool is short)
|
||||
function cmp_take(compass_st: mut CompassState, x: float, z: float, icon: int, colour: int, tier: int, prio: int, label: string) -> CompassMark {
|
||||
if compass_st.cmp_used >= len(compass_st.cmp_pool) { push(compass_st.cmp_pool, new CompassMark) }
|
||||
let m = compass_st.cmp_pool[compass_st.cmp_used]
|
||||
compass_st.cmp_used += 1
|
||||
m.x = x
|
||||
m.z = z
|
||||
m.icon = icon
|
||||
m.colour = colour
|
||||
m.tier = tier
|
||||
m.prio = prio
|
||||
m.label = label
|
||||
return m
|
||||
}
|
||||
|
||||
function cmp_band(p: int) -> int { return Math.clamp(p, COMPASS_PLAIN, COMPASS_TRACKED) }
|
||||
|
||||
# once a frame: ask every registered provider, in the registry's order
|
||||
|
|
|
|||
|
|
@ -25,6 +25,9 @@ export open registry CompassProviders of CompassProvider as COMPASS_FROM
|
|||
export state CompassState {
|
||||
cmp_cap: int = 64
|
||||
cmp_list: []CompassMark = null # this frame's, sorted and culled
|
||||
cmp_back: []CompassMark = null # the list the sort fills, then swapped with cmp_list
|
||||
cmp_pool: []CompassMark = null # a frame's marks, reused: Ludic frees nothing
|
||||
cmp_used: int = 0
|
||||
cmp_capturing: bool = false
|
||||
cmp_caught: []CompassMark = null # what providers said while someone was listening
|
||||
cmp_ranges: []float = null
|
||||
|
|
|
|||
|
|
@ -387,9 +387,9 @@ function layer_new(render3d_st: mut Render3dState, model: Model, cap: int, folia
|
|||
l.near = near
|
||||
l.cull = cull
|
||||
l.tint = v3_new(1.0, 1.0, 1.0)
|
||||
# room for what the layer holds, not for what it might: 45 layers at full capacity up front were
|
||||
# 0.4 GB, most of it never filled (plan 23 of maroon-lake)
|
||||
l.have = min(cap, 256)
|
||||
# the whole capacity up front: a game writes l.inst directly (Maroon Lake's prints, trees and
|
||||
# rocks do), so a layer cannot start smaller than it may be written to
|
||||
l.have = cap
|
||||
l.inst = floats(l.have * INST_FLOATS)
|
||||
l.scratch = floats(l.have * INST_FLOATS)
|
||||
l.last_cam = v3_new(100000.0, 0.0, 0.0)
|
||||
|
|
@ -402,7 +402,9 @@ function layer_new(render3d_st: mut Render3dState, model: Model, cap: int, folia
|
|||
return l
|
||||
}
|
||||
|
||||
# room for n instances (at most the layer's cap), doubling what there is so a fill costs a few copies
|
||||
# room for n instances (at most the layer's cap), doubling what there is so a fill costs a few copies;
|
||||
# a caller writing l.inst itself reserves first
|
||||
function layer_reserve(l: Layer, n: int) -> void { layer_room(l, n) }
|
||||
function layer_room(l: Layer, n: int) -> void {
|
||||
if n <= l.have { return }
|
||||
var want = max(l.have * 2, n)
|
||||
|
|
|
|||
|
|
@ -232,8 +232,10 @@ function shadow_dump(render3d_st: mut Render3dState) -> void {
|
|||
}
|
||||
|
||||
# a uniform array's location: some drivers only answer to the "[0]" spelling
|
||||
function sh_loc(render3d_st: Render3dState, prog: int, name: string) -> int {
|
||||
var loc = gpu_uniform(render3d_st, prog, name + "[0]")
|
||||
# an array uniform by its first element's name, else its bare one; both names are literals, because
|
||||
# building `name + "[0]"` here made a string per program per pass per frame that was never freed
|
||||
function sh_loc(render3d_st: Render3dState, prog: int, first: string, name: string) -> int {
|
||||
var loc = gpu_uniform(render3d_st, prog, first)
|
||||
if loc < 0 { loc = gpu_uniform(render3d_st, prog, name) }
|
||||
return loc
|
||||
}
|
||||
|
|
@ -252,10 +254,10 @@ function shadow_bind(render3d_st: mut Render3dState, prog: int) -> void {
|
|||
if loc < 0 { loc = gpu_uniform(render3d_st, prog, "u_cascade_vp") }
|
||||
if render3d_st.r3d_debug_shadow and not render3d_st.sh_printed { render3d_st.sh_printed = true; print(`cascade vp loc {loc} / {gpu_uniform(render3d_st, prog, "u_cascade_vp")} split loc {gpu_uniform(render3d_st, prog, "u_cascade_split")} shadow loc {gpu_uniform(render3d_st, prog, "u_shadow")}`) }
|
||||
u_mat4n(render3d_st, loc, SHADOW_CASCADES, render3d_st.sh_vp)
|
||||
u_fv(render3d_st, sh_loc(render3d_st, prog, "u_cascade_split"), SHADOW_CASCADES, render3d_st.sh_split)
|
||||
u_fv(render3d_st, sh_loc(render3d_st, prog, "u_cascade_split[0]", "u_cascade_split"), SHADOW_CASCADES, render3d_st.sh_split)
|
||||
if render3d_st.r3d_debug_shadow and not render3d_st.sh_printed3 { render3d_st.sh_printed3 = true; print(`range {fixed(render3d_st.sh_range[0])} {fixed(render3d_st.sh_range[1])} {fixed(render3d_st.sh_range[2])} {fixed(render3d_st.sh_range[3])} texel*1000 {fixed(render3d_st.sh_texel[0] * 1000.0)} {fixed(render3d_st.sh_texel[1] * 1000.0)} {fixed(render3d_st.sh_texel[2] * 1000.0)} {fixed(render3d_st.sh_texel[3] * 1000.0)} locs {gpu_uniform(render3d_st, prog, "u_cascade_range")} {gpu_uniform(render3d_st, prog, "u_cascade_texel")}`) }
|
||||
u_fv(render3d_st, sh_loc(render3d_st, prog, "u_cascade_range"), SHADOW_CASCADES, render3d_st.sh_range)
|
||||
u_fv(render3d_st, sh_loc(render3d_st, prog, "u_cascade_range[0]", "u_cascade_range"), SHADOW_CASCADES, render3d_st.sh_range)
|
||||
if r3d_env_has(render3d_st, "R3D_FORCE") { render3d_st.sh_force = Text.to_int(r3d_env(render3d_st, "R3D_FORCE")) }
|
||||
u_i(render3d_st, gpu_uniform(render3d_st, prog, "u_force_cascade"), render3d_st.sh_force)
|
||||
u_fv(render3d_st, sh_loc(render3d_st, prog, "u_cascade_texel"), SHADOW_CASCADES, render3d_st.sh_texel)
|
||||
u_fv(render3d_st, sh_loc(render3d_st, prog, "u_cascade_texel[0]", "u_cascade_texel"), SHADOW_CASCADES, render3d_st.sh_texel)
|
||||
}
|
||||
|
|
|
|||
|
|
@ -5,7 +5,7 @@ const VE_HORSE_GALLOP: float = 11.0
|
|||
const VE_HORSE_ACC: float = 4.0
|
||||
const VE_HORSE_TURN: float = 1.6
|
||||
|
||||
function ve_ride_horse(vehicles_st: VehiclesState, v: Vehicle, ix: float, iz: float, run: bool, dt: float) -> void {
|
||||
function ve_ride_horse(vehicles_st: mut VehiclesState, v: Vehicle, ix: float, iz: float, run: bool, dt: float) -> void {
|
||||
var top = VE_HORSE_WALK
|
||||
if run and v.fuel > 5.0 { top = VE_HORSE_GALLOP }
|
||||
v.speed = v.speed + Math.clamp(iz * top - v.speed, -VE_HORSE_ACC * dt, VE_HORSE_ACC * dt)
|
||||
|
|
@ -29,7 +29,7 @@ function ve_ride_horse(vehicles_st: VehiclesState, v: Vehicle, ix: float, iz: fl
|
|||
|
||||
# the legs carry it from where it is; what they covered along its heading is its speed now, never
|
||||
# more than was asked, so a trunk or a rise it cannot take brings it to a stand
|
||||
function ve_legs_walk(vehicles_st: VehiclesState, v: Vehicle, vx: float, vz: float, dt: float) -> void {
|
||||
function ve_legs_walk(vehicles_st: mut VehiclesState, v: Vehicle, vx: float, vz: float, dt: float) -> void {
|
||||
if not VehicleLegs.walk(v.nid, v.x, v.y, v.z, vx, vz, dt) { return }
|
||||
let dx = VehicleLegs.x() - v.x
|
||||
let dz = VehicleLegs.z() - v.z
|
||||
|
|
@ -39,7 +39,7 @@ function ve_legs_walk(vehicles_st: VehiclesState, v: Vehicle, vx: float, vz: flo
|
|||
let got = (dx * -Math.sin(v.yaw) + dz * -Math.cos(v.yaw)) / dt
|
||||
if v.speed > 0.0 { v.speed = Math.clamp(got, 0.0, v.speed) } else { v.speed = Math.clamp(got, v.speed, 0.0) }
|
||||
let moved = Math.sqrt(dx * dx + dz * dz)
|
||||
if moved > 0.0 { ve_say(vehicles_st, VEHICLE_MOVED, v, moved) }
|
||||
if moved > 0.0 { ve_moved_add(vehicles_st, v, moved) }
|
||||
}
|
||||
|
||||
# a gallop spends stamina and a walk gives it back; every metre costs hay
|
||||
|
|
|
|||
|
|
@ -13,6 +13,7 @@ import "call.ludic"
|
|||
import "keep.ludic"
|
||||
import "mount.ludic"
|
||||
import "ride.ludic"
|
||||
import "moved.ludic"
|
||||
import "horse.ludic"
|
||||
import "legs.ludic"
|
||||
import "system.ludic"
|
||||
|
|
|
|||
19
packages/ludic.vehicles/moved.ludic
Normal file
19
packages/ludic.vehicles/moved.ludic
Normal file
|
|
@ -0,0 +1,19 @@
|
|||
# moved.ludic - the ground the ridden vehicle covers, added up rather than said a frame at a time: a
|
||||
# fact a frame was a new record a frame, and Ludic frees nothing. The game takes the sum when it asks.
|
||||
function ve_moved_add(vehicles_st: mut VehiclesState, v: Vehicle, d: float) -> void {
|
||||
vehicles_st.ve_moved += d
|
||||
vehicles_st.ve_moved_kind = v.kind
|
||||
vehicles_st.ve_moved_x = v.x
|
||||
vehicles_st.ve_moved_z = v.z
|
||||
}
|
||||
|
||||
# the metres covered since the last take (0 when nothing moved), and the sum starts again
|
||||
export function vehicle_moved_take(vehicles_st: mut VehiclesState) -> float {
|
||||
let d = vehicles_st.ve_moved
|
||||
vehicles_st.ve_moved = 0.0
|
||||
return d
|
||||
}
|
||||
# what covered them, and where it was when it last moved
|
||||
export function vehicle_moved_kind(vehicles_st: VehiclesState) -> int { return vehicles_st.ve_moved_kind }
|
||||
export function vehicle_moved_x(vehicles_st: VehiclesState) -> float { return vehicles_st.ve_moved_x }
|
||||
export function vehicle_moved_z(vehicles_st: VehiclesState) -> float { return vehicles_st.ve_moved_z }
|
||||
|
|
@ -43,6 +43,10 @@ export state VehiclesState {
|
|||
ve_kept_boat: bool = false
|
||||
ve_kept_food: float = 40.0
|
||||
ve_ids: int = 0
|
||||
ve_moved: float = 0.0 # metres the ridden vehicle covered since the game last took them
|
||||
ve_moved_kind: int = 0
|
||||
ve_moved_x: float = 0.0
|
||||
ve_moved_z: float = 0.0
|
||||
ve_sx: float = 0.0
|
||||
ve_sz: float = 0.0
|
||||
ve: VehicleTable = ve__new()
|
||||
|
|
|
|||
|
|
@ -20,7 +20,7 @@ function ve_row(vehicles_st: mut VehiclesState, v: Vehicle, ix: float, iz: float
|
|||
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_say(vehicles_st, VEHICLE_MOVED, v, d) }
|
||||
if d > 0.0 { ve_moved_add(vehicles_st, v, d) }
|
||||
}
|
||||
|
||||
# where the hull is now, and how fast it goes along its bow
|
||||
|
|
|
|||
|
|
@ -11,6 +11,7 @@ export function vehicles_reset(vehicles_st: mut VehiclesState) -> void {
|
|||
tb_clear(vehicles_st.ve.tab)
|
||||
imap_clear(vehicles_st.ve.nids)
|
||||
vehicles_st.ve_cur = null
|
||||
vehicles_st.ve_moved = 0.0
|
||||
vehicles_st.ve_have_dock = false
|
||||
vehicles_st.ve_swell_said = 0.0
|
||||
vehicles_st.ve_kept_horse = false
|
||||
|
|
|
|||
|
|
@ -246,7 +246,9 @@ program VehiclesTest {
|
|||
vehicle_mount(vehicles_st, h)
|
||||
ride(physics_st, vehicles_st, 0.0, 1.0, false, 3.0)
|
||||
expect_near(h.speed, 4.5, 0.05)
|
||||
expect(count(facts(vehicles_st), VEHICLE_MOVED) > 100)
|
||||
expect(vehicle_moved_take(vehicles_st) > 10.0) # 3 s at 4.5 m/s, added up
|
||||
expect_eq(vehicle_moved_kind(vehicles_st), VEHICLE_HORSE)
|
||||
expect_near(vehicle_moved_take(vehicles_st), 0.0, 0.0001)
|
||||
ride(physics_st, vehicles_st, 0.0, 1.0, true, 3.0)
|
||||
expect_near(h.speed, 11.0, 0.1)
|
||||
expect(h.fuel < 100.0)
|
||||
|
|
|
|||
Loading…
Add table
Add a link
Reference in a new issue