refactor(packages): 0.R5 - the shop's week is rolled by its tick and asking reads it; needs start filled and vehicles start with their list; character, physics, vehicles and nativeecho's lazy starts are defaults; --tighten over all four
Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
This commit is contained in:
parent
67d8079c47
commit
87259f989d
31 changed files with 104 additions and 111 deletions
|
|
@ -103,7 +103,7 @@ export state CharacterState {
|
|||
chr_eyes_now: bool = false # the last camera was the eyes: the figure is hidden
|
||||
chr_safe_x: float = 0.0
|
||||
chr_safe_z: float = 0.0
|
||||
chr_fact_q: Queue<CharacterFact> = null
|
||||
chr_fact_q: Queue<CharacterFact> = chr_fact_q__new()
|
||||
}
|
||||
function chr__top_plain(x: float, z: float, r: float, from_y: float, step: float, base: float) -> float { return base }
|
||||
function chr__bed_plain(x: float, z: float) -> float { return CharacterGround.height(x, z) }
|
||||
|
|
@ -124,3 +124,4 @@ function chr__zero() -> float { return 0.0 }
|
|||
function chr__no() -> bool { return false }
|
||||
function chr__yes() -> bool { return true }
|
||||
function chr__not_carried(ix: float, iz: float, run: bool, dt: float) -> void { }
|
||||
function chr_fact_q__new() -> Queue<CharacterFact> { return queue_new("character.facts") }
|
||||
|
|
|
|||
|
|
@ -9,12 +9,11 @@ const chr_pi: float = 3.14159265
|
|||
|
||||
|
||||
|
||||
export function char_facts(character_st: mut CharacterState) -> Queue<CharacterFact> {
|
||||
if character_st.chr_fact_q == null { character_st.chr_fact_q = queue_new("character.facts") }
|
||||
export function char_facts(character_st: CharacterState) -> Queue<CharacterFact> {
|
||||
return character_st.chr_fact_q
|
||||
}
|
||||
|
||||
function chr_say(character_st: mut CharacterState, what: int, v: float) -> void {
|
||||
function chr_say(character_st: CharacterState, what: int, v: float) -> void {
|
||||
let f = new CharacterFact
|
||||
f.what = what
|
||||
f.x = character_st.chr_x
|
||||
|
|
|
|||
|
|
@ -107,7 +107,7 @@ program CharacterTest {
|
|||
char_release(character_st, CHAR_HOLD_SCREEN)
|
||||
char_teleport(character_st, x, z, yaw)
|
||||
}
|
||||
function facts(character_st: mut CharacterState) -> []CharacterFact { return q_drain(char_facts(character_st)) }
|
||||
function facts(character_st: CharacterState) -> []CharacterFact { return q_drain(char_facts(character_st)) }
|
||||
function count(fs: []CharacterFact, what: int) -> int {
|
||||
var n = 0
|
||||
for i in 0 .. len(fs) { if fs[i].what == what { n += 1 } }
|
||||
|
|
|
|||
|
|
@ -8,28 +8,24 @@ export property EchoFact {
|
|||
}
|
||||
|
||||
export state EchoState {
|
||||
ec_xs: []float = null
|
||||
ec_xs: []float = floats(ECHO_CAP)
|
||||
ec_n: int = 0
|
||||
ec_kinds: []int = null
|
||||
ec_values: []float = null
|
||||
ec_facts: Queue<EchoFact> = null
|
||||
ec_kinds: []int = words(ECHO_CAP)
|
||||
ec_values: []float = floats(ECHO_CAP)
|
||||
ec_facts: Queue<EchoFact> = ec_facts__new()
|
||||
}
|
||||
|
||||
function ec_ready(echo_st: mut EchoState) -> void {
|
||||
if echo_st.ec_xs == null { echo_st.ec_xs = floats(ECHO_CAP) }
|
||||
if echo_st.ec_kinds == null { echo_st.ec_kinds = words(ECHO_CAP) }
|
||||
if echo_st.ec_values == null { echo_st.ec_values = floats(ECHO_CAP) }
|
||||
function ec_ready() -> void {
|
||||
}
|
||||
|
||||
# what went over, oldest first
|
||||
export function echo_facts(echo_st: mut EchoState) -> Queue<EchoFact> {
|
||||
if echo_st.ec_facts == null { echo_st.ec_facts = queue_new("nativeecho.facts") }
|
||||
export function echo_facts(echo_st: EchoState) -> Queue<EchoFact> {
|
||||
return echo_st.ec_facts
|
||||
}
|
||||
|
||||
# put a value in the next slot; false when the slice is full
|
||||
export function echo_put(echo_st: mut EchoState, x: float) -> bool {
|
||||
ec_ready(echo_st)
|
||||
ec_ready()
|
||||
if echo_st.ec_n >= ECHO_CAP { return false }
|
||||
echo_st.ec_xs[echo_st.ec_n] = x
|
||||
echo_st.ec_n += 1
|
||||
|
|
@ -40,13 +36,13 @@ export function echo_clear(echo_st: mut EchoState) -> void { echo_st.ec_n = 0 }
|
|||
|
||||
# the sum of what was put, worked out in C
|
||||
export function echo_sum(echo_st: mut EchoState) -> float {
|
||||
ec_ready(echo_st)
|
||||
ec_ready()
|
||||
return ne_sum(echo_st.ec_xs, echo_st.ec_n)
|
||||
}
|
||||
|
||||
# C walks the values and records each one over `over`; the records come back as facts
|
||||
export function echo_scan(echo_st: mut EchoState, over: float) -> int {
|
||||
ec_ready(echo_st)
|
||||
ec_ready()
|
||||
let hits = ne_scan(echo_st.ec_xs, echo_st.ec_n, over)
|
||||
ec_drain(echo_st)
|
||||
return hits
|
||||
|
|
@ -67,3 +63,4 @@ export function echo_lost() -> int { return ne_lost_count() }
|
|||
|
||||
# a 64-bit value there and back
|
||||
export function echo_twice(x: long) -> long { return ne_twice(x) }
|
||||
function ec_facts__new() -> Queue<EchoFact> { return queue_new("nativeecho.facts") }
|
||||
|
|
|
|||
|
|
@ -1,13 +1,13 @@
|
|||
# queries.ludic - what the world asks the body
|
||||
export function needs_level(needs_st: mut NeedsState, k: int) -> float {
|
||||
export function needs_level(needs_st: NeedsState, k: int) -> float {
|
||||
if not nd_ok(k) { return 0.0 }
|
||||
return nd_lv(needs_st)[k]
|
||||
}
|
||||
|
||||
export function needs_warmth(needs_st: mut NeedsState) -> float { return nd_lv(needs_st)[NEED_WARMTH] }
|
||||
export function needs_food(needs_st: mut NeedsState) -> float { return nd_lv(needs_st)[NEED_FOOD] }
|
||||
export function needs_water(needs_st: mut NeedsState) -> float { return nd_lv(needs_st)[NEED_WATER] }
|
||||
export function needs_energy(needs_st: mut NeedsState) -> float { return nd_lv(needs_st)[NEED_ENERGY] }
|
||||
export function needs_warmth(needs_st: NeedsState) -> float { return nd_lv(needs_st)[NEED_WARMTH] }
|
||||
export function needs_food(needs_st: NeedsState) -> float { return nd_lv(needs_st)[NEED_FOOD] }
|
||||
export function needs_water(needs_st: NeedsState) -> float { return nd_lv(needs_st)[NEED_WATER] }
|
||||
export function needs_energy(needs_st: NeedsState) -> float { return nd_lv(needs_st)[NEED_ENERGY] }
|
||||
|
||||
# seconds left before a collapse (0: no countdown), and the need it is for
|
||||
export function needs_last_legs(needs_st: NeedsState) -> float { return needs_st.nd_legs }
|
||||
|
|
@ -15,7 +15,7 @@ export function needs_last_need(needs_st: NeedsState) -> int { return needs_st.n
|
|||
export function needs_collapses(needs_st: NeedsState) -> int { return needs_st.nd_collapses }
|
||||
|
||||
# the walk's pace, times: the ramp of each need, and 0.6 more on last legs
|
||||
export function needs_pace(needs_st: mut NeedsState) -> float {
|
||||
export function needs_pace(needs_st: NeedsState) -> float {
|
||||
let lv = nd_lv(needs_st)
|
||||
var m = nd_pace(lv[NEED_WARMTH]) * nd_pace(lv[NEED_FOOD])
|
||||
if NeedsWorld.thirst() { m = m * nd_pace(lv[NEED_WATER]) }
|
||||
|
|
@ -24,13 +24,13 @@ export function needs_pace(needs_st: mut NeedsState) -> float {
|
|||
}
|
||||
|
||||
# running needs legs, calories and a body that is not already in trouble
|
||||
export function needs_can_run(needs_st: mut NeedsState) -> bool {
|
||||
export function needs_can_run(needs_st: NeedsState) -> bool {
|
||||
let lv = nd_lv(needs_st)
|
||||
return lv[NEED_ENERGY] > 8.0 and lv[NEED_FOOD] > 20.0 and lv[NEED_WARMTH] > 20.0 and lv[NEED_WATER] > 20.0
|
||||
}
|
||||
|
||||
# the lowest of the four
|
||||
export function needs_lowest(needs_st: mut NeedsState) -> float {
|
||||
export function needs_lowest(needs_st: NeedsState) -> float {
|
||||
let lv = nd_lv(needs_st)
|
||||
return Math.min(Math.min(lv[NEED_WARMTH], lv[NEED_FOOD]), Math.min(lv[NEED_WATER], lv[NEED_ENERGY]))
|
||||
}
|
||||
|
|
|
|||
|
|
@ -1,10 +1,10 @@
|
|||
# run.ludic - `gh` game hours of whatever the body is doing, taken out of the four bars
|
||||
function nd_add(needs_st: mut NeedsState, k: int, d: float) -> void {
|
||||
function nd_add(needs_st: NeedsState, k: int, d: float) -> void {
|
||||
let lv = nd_lv(needs_st)
|
||||
lv[k] = Math.clamp(lv[k] + d, 0.0, 100.0)
|
||||
}
|
||||
|
||||
export function needs_run(needs_st: mut NeedsState, gh: float) -> void {
|
||||
export function needs_run(needs_st: NeedsState, gh: float) -> void {
|
||||
let a = NeedsWorld.activity()
|
||||
nd_add(needs_st, NEED_FOOD, (NeedsWorld.bonus(NEED_FOOD) - nd_food_rate(a) * NeedsWorld.drain(NEED_FOOD)) * gh)
|
||||
if NeedsWorld.thirst() {
|
||||
|
|
|
|||
|
|
@ -51,21 +51,24 @@ export property NeedFact {
|
|||
need: int = 0
|
||||
}
|
||||
|
||||
# where a body starts: warm, fed well enough, watered, rested
|
||||
function nd_start() -> []float {
|
||||
let l = floats(NEED_COUNT)
|
||||
l[NEED_WARMTH] = 100.0
|
||||
l[NEED_FOOD] = 70.0
|
||||
l[NEED_WATER] = 85.0
|
||||
l[NEED_ENERGY] = 100.0
|
||||
return l
|
||||
}
|
||||
export state NeedsState {
|
||||
nd_level: []float = null
|
||||
nd_level: []float = nd_start()
|
||||
nd_legs: float = 0.0 # seconds left before a collapse, 0 = none
|
||||
nd_last: int = 0 # the need the countdown is for
|
||||
nd_collapses: int = 0
|
||||
nd_facts: Queue<NeedFact> = nd_facts__new()
|
||||
}
|
||||
|
||||
function nd_lv(needs_st: mut NeedsState) -> []float {
|
||||
if needs_st.nd_level == null {
|
||||
needs_st.nd_level = floats(NEED_COUNT)
|
||||
nd_fill(needs_st)
|
||||
}
|
||||
return needs_st.nd_level
|
||||
}
|
||||
function nd_lv(needs_st: NeedsState) -> []float { return needs_st.nd_level }
|
||||
|
||||
function nd_fill(needs_st: mut NeedsState) -> void {
|
||||
needs_st.nd_level[NEED_WARMTH] = 100.0
|
||||
|
|
|
|||
|
|
@ -5,7 +5,7 @@ function needs_tick(needs_st: mut NeedsState, t: Tick) -> void {
|
|||
needs_watch(needs_st, t.dt)
|
||||
}
|
||||
|
||||
export function needs_save(needs_st: mut NeedsState) -> Val {
|
||||
export function needs_save(needs_st: NeedsState) -> Val {
|
||||
let v = Value.object()
|
||||
sv_put_float(v, "warmth", needs_warmth(needs_st))
|
||||
sv_put_float(v, "food", needs_food(needs_st))
|
||||
|
|
|
|||
|
|
@ -45,7 +45,7 @@ program NeedsTest {
|
|||
}
|
||||
|
||||
function fresh(needs_st: mut NeedsState) -> void { needs_reset(needs_st) }
|
||||
function hours(needs_st: mut NeedsState, h: float) -> void { for i in 0 .. int(h * 10.0) { needs_run(needs_st, 0.1) } }
|
||||
function hours(needs_st: NeedsState, h: float) -> void { for i in 0 .. int(h * 10.0) { needs_run(needs_st, 0.1) } }
|
||||
function facts(needs_st: NeedsState) -> []NeedFact { return q_drain(needs_facts(needs_st)) }
|
||||
|
||||
test "a new body is warm, rested, fed and watered" (needs_st: mut NeedsState) {
|
||||
|
|
|
|||
|
|
@ -1,27 +1,27 @@
|
|||
# verbs.ludic - the only way the needs change from outside; each is held to 0..100
|
||||
# `n` more of a need (less, when negative): a meal, a drink, a shove from a bear
|
||||
export function needs_feed(needs_st: mut NeedsState, k: int, n: float) -> void {
|
||||
export function needs_feed(needs_st: NeedsState, k: int, n: float) -> void {
|
||||
if nd_ok(k) { nd_add(needs_st, k, n) }
|
||||
}
|
||||
|
||||
# a meal: food, water and energy at once
|
||||
export function needs_meal(needs_st: mut NeedsState, food: float, water: float, energy: float) -> void {
|
||||
export function needs_meal(needs_st: NeedsState, food: float, water: float, energy: float) -> void {
|
||||
nd_add(needs_st, NEED_FOOD, food)
|
||||
nd_add(needs_st, NEED_WATER, water)
|
||||
nd_add(needs_st, NEED_ENERGY, energy)
|
||||
}
|
||||
|
||||
export function needs_set(needs_st: mut NeedsState, k: int, v: float) -> void {
|
||||
export function needs_set(needs_st: NeedsState, k: int, v: float) -> void {
|
||||
if nd_ok(k) { nd_lv(needs_st)[k] = Math.clamp(v, 0.0, 100.0) }
|
||||
}
|
||||
|
||||
# at least `v`
|
||||
export function needs_floor(needs_st: mut NeedsState, k: int, v: float) -> void {
|
||||
export function needs_floor(needs_st: NeedsState, k: int, v: float) -> void {
|
||||
if nd_ok(k) and nd_lv(needs_st)[k] < v { needs_set(needs_st, k, v) }
|
||||
}
|
||||
|
||||
# a night: rested to what it was worth, hungrier and thirstier for it, but never empty
|
||||
export function needs_after_night(needs_st: mut NeedsState, rested: float, food_lost: float, water_lost: float) -> void {
|
||||
export function needs_after_night(needs_st: NeedsState, rested: float, food_lost: float, water_lost: float) -> void {
|
||||
let lv = nd_lv(needs_st)
|
||||
lv[NEED_ENERGY] = Math.clamp(rested, 0.0, 100.0)
|
||||
lv[NEED_FOOD] = Math.max(lv[NEED_FOOD] - food_lost, 6.0)
|
||||
|
|
|
|||
|
|
@ -3,7 +3,7 @@
|
|||
const LAST_LEGS: float = 10.0
|
||||
const GENTLE_FLOOR: float = 22.0
|
||||
|
||||
function nd_empty(needs_st: mut NeedsState) -> int {
|
||||
function nd_empty(needs_st: NeedsState) -> int {
|
||||
let lv = nd_lv(needs_st)
|
||||
if lv[NEED_WARMTH] == 0.0 { return NEED_WARMTH }
|
||||
if lv[NEED_FOOD] == 0.0 { return NEED_FOOD }
|
||||
|
|
@ -11,7 +11,7 @@ function nd_empty(needs_st: mut NeedsState) -> int {
|
|||
return -1
|
||||
}
|
||||
|
||||
function nd_clear(needs_st: mut NeedsState) -> bool {
|
||||
function nd_clear(needs_st: NeedsState) -> bool {
|
||||
let lv = nd_lv(needs_st)
|
||||
return lv[NEED_WARMTH] > 5.0 and lv[NEED_FOOD] > 5.0 and lv[NEED_WATER] > 5.0
|
||||
}
|
||||
|
|
|
|||
|
|
@ -46,7 +46,7 @@ export function phys_remove(physics_st: mut PhysicsState, id: int) -> void {
|
|||
# where a body is, how it is turned and how fast it goes; null when there is no such body
|
||||
export function phys_pose(physics_st: mut PhysicsState, id: int) -> PhysPose {
|
||||
if physics_st.ph_world == null { return null }
|
||||
ph_buffers(physics_st)
|
||||
ph_buffers()
|
||||
if jph_body_read(physics_st.ph_world, id, physics_st.ph_vals) != 0 { return null }
|
||||
let v = physics_st.ph_vals
|
||||
let p = new PhysPose
|
||||
|
|
@ -77,7 +77,7 @@ export function phys_angular_impulse(physics_st: mut PhysicsState, id: int, x: f
|
|||
# how fast it turns about y, radians a second
|
||||
export function phys_spin_y(physics_st: mut PhysicsState, id: int) -> float {
|
||||
if physics_st.ph_world == null { return 0.0 }
|
||||
ph_buffers(physics_st)
|
||||
ph_buffers()
|
||||
jph_body_spin(physics_st.ph_world, id, physics_st.ph_vals)
|
||||
return physics_st.ph_vals[1]
|
||||
}
|
||||
|
|
|
|||
|
|
@ -16,7 +16,7 @@ export property PhysHit {
|
|||
export function phys_ray(physics_st: mut PhysicsState, ox: float, oy: float, oz: float, dx: float, dy: float, dz: float, mask: int) -> PhysHit {
|
||||
let h = new PhysHit
|
||||
if physics_st.ph_world == null { return h }
|
||||
ph_buffers(physics_st)
|
||||
ph_buffers()
|
||||
h.body = jph_ray(physics_st.ph_world, ox, oy, oz, dx, dy, dz, mask, physics_st.ph_vals)
|
||||
if h.body == -1 { return h }
|
||||
let v = physics_st.ph_vals
|
||||
|
|
@ -49,7 +49,7 @@ export function phys_step_top(physics_st: PhysicsState, x: float, z: float, r: f
|
|||
export function phys_overlap(physics_st: mut PhysicsState, x: float, y: float, z: float, r: float, mask: int) -> []int {
|
||||
let out = new []int
|
||||
if physics_st.ph_world == null { return out }
|
||||
ph_buffers(physics_st)
|
||||
ph_buffers()
|
||||
let n = jph_overlap(physics_st.ph_world, x, y, z, r, mask, physics_st.ph_ids, PH_CAP)
|
||||
for i in 0 .. n { push(out, physics_st.ph_ids[i]) }
|
||||
return out
|
||||
|
|
@ -66,7 +66,7 @@ export property PhysPush {
|
|||
export function phys_push(physics_st: mut PhysicsState, x: float, z: float, r: float, y0: float, y1: float, mask: int) -> PhysPush {
|
||||
let p = new PhysPush
|
||||
if physics_st.ph_world == null { return p }
|
||||
ph_buffers(physics_st)
|
||||
ph_buffers()
|
||||
p.n = jph_push(physics_st.ph_world, x, z, r, y0, y1, mask, physics_st.ph_vals)
|
||||
p.x = physics_st.ph_vals[0]
|
||||
p.z = physics_st.ph_vals[1]
|
||||
|
|
|
|||
|
|
@ -4,7 +4,7 @@
|
|||
# a world for up to max_bodies (threads 0: the cores less one, at most four); false if C refused
|
||||
export function phys_open(physics_st: mut PhysicsState, max_bodies: int, threads: int) -> bool {
|
||||
phys_close(physics_st)
|
||||
ph_buffers(physics_st)
|
||||
ph_buffers()
|
||||
physics_st.ph_world = jph_world_new(max_bodies, threads)
|
||||
physics_st.ph_gen += 1
|
||||
physics_st.ph_acc = 0.0
|
||||
|
|
@ -39,7 +39,7 @@ export function phys_close(physics_st: mut PhysicsState) -> void {
|
|||
|
||||
function ph_keep(physics_st: mut PhysicsState, s: pointer) -> int {
|
||||
if s == null { return -1 }
|
||||
ph_buffers(physics_st)
|
||||
ph_buffers()
|
||||
push(physics_st.ph_shapes, s)
|
||||
return len(physics_st.ph_shapes) - 1
|
||||
}
|
||||
|
|
|
|||
|
|
@ -36,7 +36,7 @@ export const PH_CAP: int = 512 # contacts drained a step, queries' buffer
|
|||
|
||||
export state PhysicsState {
|
||||
ph_world: pointer = null
|
||||
ph_shapes: []pointer = null # a shape id is its place here; null once freed
|
||||
ph_shapes: []pointer = new []pointer # a shape id is its place here; null once freed
|
||||
ph_step: float = 0.016666668 # seconds a step
|
||||
ph_sub: int = 1 # collision steps in each
|
||||
ph_max_steps: int = 4 # a slow frame catches up this far and no further
|
||||
|
|
@ -44,29 +44,22 @@ export state PhysicsState {
|
|||
ph_steps: int = 0
|
||||
ph_gen: int = 0 # how many worlds have been opened: an id from an older one is stale
|
||||
ph_hard: float = 2.0 # metres a second: a contact under this is not a fact
|
||||
ph_floats: []int = null # buoyant bodies' ids
|
||||
ph_float_k: []float = null # and theirs: buoyancy, linear drag, angular drag, wet
|
||||
ph_floats: []int = new []int # buoyant bodies' ids
|
||||
ph_float_k: []float = new []float # and theirs: buoyancy, linear drag, angular drag, wet
|
||||
ph_rx: float = 0.0 # where the last phys_resolve put a body
|
||||
ph_rz: float = 0.0
|
||||
ph_walkers: []pointer = null # a walker id is its place here; null once removed
|
||||
ph_ids: []int = null
|
||||
ph_vals: []float = null
|
||||
ph_facts: Queue<PhysFact> = null
|
||||
ph_walkers: []pointer = new []pointer # a walker id is its place here; null once removed
|
||||
ph_ids: []int = words(PH_CAP * 2)
|
||||
ph_vals: []float = floats(PH_CAP * 4)
|
||||
ph_facts: Queue<PhysFact> = ph_facts__new()
|
||||
}
|
||||
|
||||
# the facts, oldest first
|
||||
export function phys_facts(physics_st: mut PhysicsState) -> Queue<PhysFact> {
|
||||
if physics_st.ph_facts == null { physics_st.ph_facts = queue_new("physics.facts") }
|
||||
export function phys_facts(physics_st: PhysicsState) -> Queue<PhysFact> {
|
||||
return physics_st.ph_facts
|
||||
}
|
||||
|
||||
function ph_buffers(physics_st: mut PhysicsState) -> void {
|
||||
if physics_st.ph_ids == null { physics_st.ph_ids = words(PH_CAP * 2) }
|
||||
if physics_st.ph_vals == null { physics_st.ph_vals = floats(PH_CAP * 4) }
|
||||
if physics_st.ph_shapes == null { physics_st.ph_shapes = new []pointer }
|
||||
if physics_st.ph_floats == null { physics_st.ph_floats = new []int }
|
||||
if physics_st.ph_float_k == null { physics_st.ph_float_k = new []float }
|
||||
if physics_st.ph_walkers == null { physics_st.ph_walkers = new []pointer }
|
||||
function ph_buffers() -> void {
|
||||
}
|
||||
|
||||
# a step's length, its collision steps, and how hard a contact must be to be a fact
|
||||
|
|
@ -75,3 +68,4 @@ export function phys_config(physics_st: mut PhysicsState, step: float, sub: int,
|
|||
physics_st.ph_sub = sub
|
||||
physics_st.ph_hard = hard
|
||||
}
|
||||
function ph_facts__new() -> Queue<PhysFact> { return queue_new("physics.facts") }
|
||||
|
|
|
|||
|
|
@ -21,7 +21,7 @@ export function phys_advance(physics_st: mut PhysicsState, dt: float) -> int {
|
|||
# exactly one step: the water, Jolt, then the contacts that matter as facts
|
||||
export function phys_step(physics_st: mut PhysicsState) -> void {
|
||||
if physics_st.ph_world == null { return }
|
||||
ph_buffers(physics_st)
|
||||
ph_buffers()
|
||||
ph_buoy_all(physics_st)
|
||||
jph_world_step(physics_st.ph_world, physics_st.ph_step, physics_st.ph_sub)
|
||||
physics_st.ph_steps += 1
|
||||
|
|
|
|||
|
|
@ -26,7 +26,7 @@ function ph_walker(physics_st: PhysicsState, id: int) -> pointer {
|
|||
# r wide and h tall, feet at (x, y, z), mass in kg; -1 with no world
|
||||
export function phys_walker_add(physics_st: mut PhysicsState, r: float, h: float, x: float, y: float, z: float, max_slope: float, mass: float) -> int {
|
||||
if physics_st.ph_world == null { return -1 }
|
||||
ph_buffers(physics_st)
|
||||
ph_buffers()
|
||||
push(physics_st.ph_walkers, jph_char_new(physics_st.ph_world, r, h, x, y, z, max_slope, mass))
|
||||
return len(physics_st.ph_walkers) - 1
|
||||
}
|
||||
|
|
@ -56,7 +56,7 @@ export function phys_walker_step(physics_st: mut PhysicsState, id: int, dt: floa
|
|||
export function phys_walker_pose(physics_st: mut PhysicsState, id: int) -> PhysWalk {
|
||||
let k = ph_walker(physics_st, id)
|
||||
if k == null { return null }
|
||||
ph_buffers(physics_st)
|
||||
ph_buffers()
|
||||
jph_char_read(k, physics_st.ph_vals)
|
||||
let v = physics_st.ph_vals
|
||||
let p = new PhysWalk
|
||||
|
|
|
|||
|
|
@ -4,7 +4,7 @@ const PH_K: int = 4
|
|||
|
||||
# buoyancy 1 floats level with the surface, more rides higher; drags in 1/s
|
||||
export function phys_float(physics_st: mut PhysicsState, id: int, buoyancy: float, linear_drag: float, angular_drag: float) -> void {
|
||||
ph_buffers(physics_st)
|
||||
ph_buffers()
|
||||
phys_sink(physics_st, id)
|
||||
push(physics_st.ph_floats, id)
|
||||
push(physics_st.ph_float_k, buoyancy)
|
||||
|
|
@ -56,7 +56,7 @@ function ph_buoy_one(physics_st: mut PhysicsState, i: int, id: int, x: float, z:
|
|||
physics_st.ph_float_k[k + 3] = float(wet)
|
||||
}
|
||||
|
||||
function ph_splash(physics_st: mut PhysicsState, id: int, x: float, y: float, z: float) -> void {
|
||||
function ph_splash(physics_st: PhysicsState, id: int, x: float, y: float, z: float) -> void {
|
||||
let f = new PhysFact
|
||||
f.what = PHYS_SPLASH
|
||||
f.a = id
|
||||
|
|
|
|||
|
|
@ -35,7 +35,7 @@ function shop_roll_vendor(shop_st: mut ShopState, v: int) -> void {
|
|||
}
|
||||
|
||||
# the week's lists, rolled again only when the week turns
|
||||
function shop_roll(shop_st: mut ShopState) -> void {
|
||||
export function shop_roll(shop_st: mut ShopState) -> void {
|
||||
let week = shop_week(shop_st)
|
||||
if week == shop_st.shop_week_rolled and shop_st.shop_want_list != null { return }
|
||||
shop_st.shop_week_rolled = week
|
||||
|
|
@ -48,24 +48,21 @@ function shop_roll(shop_st: mut ShopState) -> void {
|
|||
for v in 0 .. shop_vendors(shop_st) { shop_roll_vendor(shop_st, v) }
|
||||
}
|
||||
|
||||
export function shop_wants(shop_st: mut ShopState, v: int, it: int) -> bool {
|
||||
if not shop_vendor_ok(shop_st, v) { return false }
|
||||
shop_roll(shop_st)
|
||||
export function shop_wants(shop_st: ShopState, v: int, it: int) -> bool {
|
||||
if not shop_vendor_ok(shop_st, v) or shop_st.shop_want_list == null { return false }
|
||||
for k in 0 .. shop_st.shop_wants_n { if shop_st.shop_want_list[v * shop_st.shop_wants_n + k] == it { return true } }
|
||||
return false
|
||||
}
|
||||
|
||||
export function shop_glutted(shop_st: mut ShopState, v: int, it: int) -> bool {
|
||||
if not shop_vendor_ok(shop_st, v) { return false }
|
||||
shop_roll(shop_st)
|
||||
export function shop_glutted(shop_st: ShopState, v: int, it: int) -> bool {
|
||||
if not shop_vendor_ok(shop_st, v) or shop_st.shop_full_list == null { return false }
|
||||
return shop_st.shop_full_list[v] == it
|
||||
}
|
||||
|
||||
# what a vendor wants this week, in its order
|
||||
export function shop_wanted(shop_st: mut ShopState, v: int) -> []int {
|
||||
export function shop_wanted(shop_st: ShopState, v: int) -> []int {
|
||||
let out = new []int
|
||||
if not shop_vendor_ok(shop_st, v) { return out }
|
||||
shop_roll(shop_st)
|
||||
if not shop_vendor_ok(shop_st, v) or shop_st.shop_want_list == null { return out }
|
||||
for k in 0 .. shop_st.shop_wants_n {
|
||||
let it = shop_st.shop_want_list[v * shop_st.shop_wants_n + k]
|
||||
if it >= 0 { push(out, it) }
|
||||
|
|
@ -74,7 +71,7 @@ export function shop_wanted(shop_st: mut ShopState, v: int) -> []int {
|
|||
}
|
||||
|
||||
# the week's multiplier on what `v` pays for `it` (1 with no vendor)
|
||||
export function shop_demand_mult(shop_st: mut ShopState, v: int, it: int) -> float {
|
||||
export function shop_demand_mult(shop_st: ShopState, v: int, it: int) -> float {
|
||||
if shop_wants(shop_st, v, it) { return shop_st.shop_want_mult }
|
||||
if shop_glutted(shop_st, v, it) { return shop_st.shop_glut_mult }
|
||||
return 1.0
|
||||
|
|
|
|||
|
|
@ -14,7 +14,7 @@ export function shop_price_buy(shop_st: ShopState, it: int) -> int {
|
|||
|
||||
# what vendor `v` pays (-1: no vendor, no demand). ROUNDED, so cheap raw material keeps its
|
||||
# order; and a vendor that stocks the thing never pays what it charges, not even a floor of $1
|
||||
export function shop_price_sell_at(shop_st: mut ShopState, v: int, it: int) -> int {
|
||||
export function shop_price_sell_at(shop_st: ShopState, v: int, it: int) -> int {
|
||||
if not shop_item_ok(shop_st, it) { return 0 }
|
||||
let f = shop_sell_factor(shop_st) * shop_st.shop_sell_frac[it] * shop_demand_mult(shop_st, v, it)
|
||||
var p = Math.max(int(float(shop_st.shop_base[it]) * f + 0.5), 1)
|
||||
|
|
@ -23,7 +23,7 @@ export function shop_price_sell_at(shop_st: mut ShopState, v: int, it: int) -> i
|
|||
}
|
||||
|
||||
# what the vendor at the counter pays
|
||||
export function shop_price_sell(shop_st: mut ShopState, it: int) -> int { return shop_price_sell_at(shop_st, shop_st.shop_at, it) }
|
||||
export function shop_price_sell(shop_st: ShopState, it: int) -> int { return shop_price_sell_at(shop_st, shop_st.shop_at, it) }
|
||||
|
||||
export function shop_stocks(shop_st: ShopState, v: int, it: int) -> bool {
|
||||
if not shop_vendor_ok(shop_st, v) or shop_st.shop_vendor_list[v].stock == null { return false }
|
||||
|
|
|
|||
|
|
@ -9,5 +9,8 @@ export function shop_reset(shop_st: mut ShopState) -> void {
|
|||
export function shop_system() -> System {
|
||||
let s = system_new("shop", PH_COMMIT)
|
||||
s.reset = fn shop_reset
|
||||
s.tick = fn shop_tick
|
||||
return s
|
||||
}
|
||||
# the week's demand, rolled when the week turns - the questions read it
|
||||
function shop_tick(shop_st: mut ShopState, t: Tick) -> void { shop_roll(shop_st) }
|
||||
|
|
|
|||
|
|
@ -154,6 +154,7 @@ program ShopTest {
|
|||
|
||||
test "the week's demand is the shop's own dice, and turns with the week" (shop_st: mut ShopState, shop_test_st: mut ShopTestState) {
|
||||
fresh(shop_st, shop_test_st)
|
||||
shop_roll(shop_st) # the shop's tick rolls the week; asking only reads it
|
||||
let a = shop_wanted(shop_st, 0)
|
||||
expect(len(a) > 0)
|
||||
for k in 0 .. len(a) { expect(shop_buys(shop_st, 0, a[k])) }
|
||||
|
|
@ -167,6 +168,7 @@ program ShopTest {
|
|||
var moved = false
|
||||
for w in 1 .. 12 {
|
||||
shop_test_st.day = 1 + w * 7
|
||||
shop_roll(shop_st)
|
||||
let b = shop_wanted(shop_st, 0)
|
||||
if len(b) != len(a) or b[0] != a[0] { moved = true }
|
||||
}
|
||||
|
|
|
|||
|
|
@ -51,7 +51,7 @@ export function shop_buy(shop_st: ShopState, it: int) -> bool {
|
|||
}
|
||||
|
||||
# `n` to the vendor at the counter (as many as the pack has); how many went
|
||||
export function shop_sell(shop_st: mut ShopState, it: int, n: int) -> int {
|
||||
export function shop_sell(shop_st: ShopState, it: int, n: int) -> int {
|
||||
if not shop_buys(shop_st, shop_st.shop_at, it) { return 0 }
|
||||
let k = Math.min(n, ShopPack.count(it))
|
||||
if k <= 0 { return 0 }
|
||||
|
|
|
|||
|
|
@ -1,6 +1,6 @@
|
|||
# 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: mut VehiclesState, kind: int, x: float, z: float, yaw: float) -> Vehicle {
|
||||
function ve_add(vehicles_st: VehiclesState, kind: 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()
|
||||
|
|
@ -41,7 +41,7 @@ function ve_put(v: Vehicle, x: float, z: float) -> void {
|
|||
|
||||
# Bring player pid's boat or horse to place k. False when the place is somebody else's, or it is
|
||||
# being ridden. A horse faces the trough: the bay lies on its near side.
|
||||
export function vehicle_call_for(vehicles_st: mut VehiclesState, pid: int, kind: int, k: int) -> bool {
|
||||
export function vehicle_call_for(vehicles_st: VehiclesState, pid: int, kind: int, k: int) -> bool {
|
||||
if not vehicles_st.ve_have_dock or k < 0 or k >= VEHICLE_PLACES { return false }
|
||||
let here = vehicle_in_place(vehicles_st, kind, k)
|
||||
let v = vehicle_of(vehicles_st, pid, kind)
|
||||
|
|
@ -78,7 +78,7 @@ 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(vehicles_st: mut VehiclesState, v: Vehicle, amount: float) -> void {
|
||||
export function vehicle_feed(vehicles_st: VehiclesState, v: Vehicle, amount: float) -> void {
|
||||
if v == null { return }
|
||||
v.food = Math.min(v.food + amount, 100.0)
|
||||
ve_say(vehicles_st, VEHICLE_FED, v, amount)
|
||||
|
|
|
|||
|
|
@ -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: mut VehiclesState, v: Vehicle, ix: float, iz: float, run: bool, dt: float) -> void {
|
||||
function ve_ride_horse(vehicles_st: 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)
|
||||
|
|
@ -21,7 +21,7 @@ function ve_ride_horse(vehicles_st: mut VehiclesState, v: Vehicle, ix: float, iz
|
|||
}
|
||||
|
||||
# a horse only on dry ground, up a walkable rise, clear of what is in its way
|
||||
function ve_travel(vehicles_st: mut VehiclesState, v: Vehicle, nx: float, nz: float, d: float) -> void {
|
||||
function ve_travel(vehicles_st: VehiclesState, v: Vehicle, nx: float, nz: float, d: float) -> void {
|
||||
let nh = VehicleWorld.ground(nx, nz)
|
||||
var ok = true
|
||||
if nh < VehicleWorld.water(nx, nz) + 0.4 { ok = false }
|
||||
|
|
|
|||
|
|
@ -42,7 +42,7 @@ export function vehicle_place_z(vehicles_st: VehiclesState, kind: int, k: int) -
|
|||
}
|
||||
|
||||
# who is in place k: the boat lying in the berth or the horse tied in the bay, or null
|
||||
export function vehicle_in_place(vehicles_st: mut VehiclesState, kind: int, k: int) -> Vehicle {
|
||||
export function vehicle_in_place(vehicles_st: VehiclesState, kind: int, k: int) -> Vehicle {
|
||||
let px = vehicle_place_x(vehicles_st, kind, k)
|
||||
let pz = vehicle_place_z(vehicles_st, kind, k)
|
||||
let l = ve_all(vehicles_st)
|
||||
|
|
@ -64,13 +64,13 @@ export function vehicle_in_place(vehicles_st: mut VehiclesState, kind: int, k: i
|
|||
}
|
||||
|
||||
# the first free place, or -1
|
||||
export function vehicle_free_place(vehicles_st: mut VehiclesState, kind: int) -> int {
|
||||
export function vehicle_free_place(vehicles_st: VehiclesState, kind: int) -> int {
|
||||
for k in 0 .. VEHICLE_PLACES { if vehicle_in_place(vehicles_st, kind, k) == null { return k } }
|
||||
return -1
|
||||
}
|
||||
|
||||
# this player's own is lying in one of the places
|
||||
export function vehicle_mine_in_place(vehicles_st: mut VehiclesState, kind: int) -> bool {
|
||||
export function vehicle_mine_in_place(vehicles_st: VehiclesState, kind: int) -> bool {
|
||||
let mine = vehicle_find(vehicles_st, kind)
|
||||
if mine == null { return false }
|
||||
for k in 0 .. VEHICLE_PLACES {
|
||||
|
|
|
|||
|
|
@ -46,7 +46,7 @@ export state VehiclesState {
|
|||
ve_ids: int = 0
|
||||
ve_sx: float = 0.0
|
||||
ve_sz: float = 0.0
|
||||
ve_list: []Vehicle = null
|
||||
ve_list: []Vehicle = new []Vehicle
|
||||
ve_cur: Vehicle = null
|
||||
ve_dock_x: float = 0.0
|
||||
ve_dock_z: float = 0.0
|
||||
|
|
@ -56,7 +56,7 @@ export state VehiclesState {
|
|||
ve_rail_yaw: float = 0.0
|
||||
ve_have_dock: bool = false
|
||||
ve_swell_said: float = 0.0
|
||||
ve_fact_q: Queue<VehicleFact> = null
|
||||
ve_fact_q: Queue<VehicleFact> = ve_fact_q__new()
|
||||
}
|
||||
function ve__dry(x: float, z: float) -> float { return -10000.0 }
|
||||
function ve__open(x: float, z: float, r: float) -> bool { return false }
|
||||
|
|
@ -77,3 +77,4 @@ function ve__safe(vehicles_st: mut VehiclesState, x: float, z: float, from_y: fl
|
|||
}
|
||||
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") }
|
||||
|
|
|
|||
|
|
@ -52,7 +52,7 @@ function ve_swell(vehicles_st: mut VehiclesState, v: Vehicle, iz: float, dt: flo
|
|||
}
|
||||
|
||||
# every boat: its hull read back, and the wind pushing it across the lake, ridden or not
|
||||
export function vehicles_tick(vehicles_st: mut VehiclesState, dt: float) -> void {
|
||||
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()
|
||||
|
|
|
|||
|
|
@ -2,12 +2,11 @@
|
|||
# from, and the facts
|
||||
const ve_pi: float = 3.14159265
|
||||
|
||||
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") }
|
||||
export function vehicle_facts(vehicles_st: VehiclesState) -> Queue<VehicleFact> {
|
||||
return vehicles_st.ve_fact_q
|
||||
}
|
||||
|
||||
function ve_say(vehicles_st: mut VehiclesState, what: int, v: Vehicle, n: float) -> void {
|
||||
function ve_say(vehicles_st: VehiclesState, what: int, v: Vehicle, n: float) -> void {
|
||||
let f = new VehicleFact
|
||||
f.what = what
|
||||
f.nid = v.nid
|
||||
|
|
@ -19,13 +18,10 @@ function ve_say(vehicles_st: mut VehiclesState, what: int, v: Vehicle, n: float)
|
|||
q_push(vehicle_facts(vehicles_st), f)
|
||||
}
|
||||
|
||||
function ve_all(vehicles_st: mut VehiclesState) -> []Vehicle {
|
||||
if vehicles_st.ve_list == null { vehicles_st.ve_list = new []Vehicle }
|
||||
return vehicles_st.ve_list
|
||||
}
|
||||
function ve_all(vehicles_st: VehiclesState) -> []Vehicle { return vehicles_st.ve_list }
|
||||
|
||||
# every vehicle in the valley, to draw and to aim at (change one only through the verbs)
|
||||
export function vehicles_all(vehicles_st: mut VehiclesState) -> []Vehicle { return ve_all(vehicles_st) }
|
||||
export function vehicles_all(vehicles_st: VehiclesState) -> []Vehicle { return ve_all(vehicles_st) }
|
||||
|
||||
# the kind this machine's player is riding, 0 none
|
||||
export function vehicle_ride_kind(vehicles_st: VehiclesState) -> int {
|
||||
|
|
@ -35,17 +31,17 @@ 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: mut VehiclesState, pid: int, kind: int) -> Vehicle {
|
||||
export function vehicle_of(vehicles_st: VehiclesState, pid: int, kind: int) -> Vehicle {
|
||||
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] } }
|
||||
return null
|
||||
}
|
||||
|
||||
# this player's own boat or horse
|
||||
export function vehicle_find(vehicles_st: mut VehiclesState, kind: int) -> Vehicle { return vehicle_of(vehicles_st, 0, kind) }
|
||||
export function vehicle_find(vehicles_st: VehiclesState, kind: int) -> Vehicle { return vehicle_of(vehicles_st, 0, kind) }
|
||||
|
||||
# the nearest vehicle nobody is on within `reach` of (x, z); nothing while riding
|
||||
export function vehicle_nearest(vehicles_st: mut VehiclesState, x: float, z: float, reach: float) -> Vehicle {
|
||||
export function vehicle_nearest(vehicles_st: VehiclesState, x: float, z: float, reach: float) -> Vehicle {
|
||||
if vehicles_st.ve_cur != null { return null }
|
||||
var best: Vehicle = null
|
||||
var bd = reach
|
||||
|
|
|
|||
|
|
@ -15,7 +15,7 @@ export function vehicles_reset(vehicles_st: mut VehiclesState) -> void {
|
|||
q_clear(vehicle_facts(vehicles_st))
|
||||
}
|
||||
|
||||
export function vehicles_save(vehicles_st: mut VehiclesState) -> Val {
|
||||
export function vehicles_save(vehicles_st: VehiclesState) -> Val {
|
||||
let v = Value.object()
|
||||
let h = vehicle_find(vehicles_st, VEHICLE_HORSE)
|
||||
let b = vehicle_find(vehicles_st, VEHICLE_BOAT)
|
||||
|
|
|
|||
|
|
@ -135,7 +135,7 @@ program VehiclesTest {
|
|||
vehicles_test_st.swell = 0.0
|
||||
vehicles_test_st.wind = 0.0
|
||||
}
|
||||
function facts(vehicles_st: mut VehiclesState) -> []VehicleFact { return q_drain(vehicle_facts(vehicles_st)) }
|
||||
function facts(vehicles_st: 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 } }
|
||||
|
|
|
|||
Loading…
Add table
Add a link
Reference in a new issue