Merge branch 'lang/foundations' into lang/native-jolt

This commit is contained in:
Orkun ÇAKILKAYA 2026-09-27 01:01:27 +03:00
commit 53ab87dc36
102 changed files with 320 additions and 351 deletions

View file

@ -17,7 +17,7 @@ export property Clip {
}
export state AnimState {
clips: []Clip = null
clips: []Clip = new []Clip
positions: bool = false
q_a: floats = null
q_b: floats = null
@ -31,19 +31,18 @@ export state AnimState {
# Keyed translations are off unless asked for: baking keys location on every bone, and a skeleton
# does not translate its joints, so applying them turns rounding into a pose.
function clips_init(anim_st: mut AnimState) -> void {
if anim_st.clips == null { anim_st.clips = new []Clip }
function clips_init() -> void {
}
# the clip of that name, or null; names are per file (per body, per species), never shared
export function anim_find(anim_st: mut AnimState, name: string) -> Clip {
clips_init(anim_st)
export function anim_find(anim_st: AnimState, name: string) -> Clip {
clips_init()
for i in 0 .. len(anim_st.clips) { if anim_st.clips[i].name == name { return anim_st.clips[i] } }
return null
}
export function anim_count(anim_st: mut AnimState) -> int {
clips_init(anim_st)
export function anim_count(anim_st: AnimState) -> int {
clips_init()
return len(anim_st.clips)
}

View file

@ -4,7 +4,7 @@
# Call it straight after a load and before the next one: `gltf_doc` and `gltf_bin` point at
# whichever file was read last, so a clip that is not taken now cannot be taken later.
export function anim_read_doc(anim_st: mut AnimState, render3d_st: mut Render3dState, dir: string) -> int {
clips_init(anim_st)
clips_init()
if render3d_st.gltf_doc == null { return 0 }
if value_has(render3d_st.gltf_doc, "animations") == 0 { return 0 }
# REOPEN THE .bin. `gltf_load` closes it before it returns, and an accessor read through a closed
@ -39,7 +39,7 @@ function kept_path(ch: Val) -> string {
return path
}
function read_one(anim_st: mut AnimState, render3d_st: mut Render3dState, a: Val) -> Clip {
function read_one(anim_st: AnimState, render3d_st: mut Render3dState, a: Val) -> Clip {
var nm = ""
if value_has(a, "name") != 0 { nm = value_as_str(value_get(a, "name")) }
if anim_find(anim_st, nm) != null { return null } # a second rig's file, same clip

View file

@ -35,12 +35,11 @@ export state ClockState {
ck_moon_lo: float = 0.0
ck_moon_hi: float = 1.0
ck_dice: Rng = null
ck_days: Queue<DayTurned> = null
ck_days: Queue<DayTurned> = ck_days__new()
}
# the facts: each day that turned, in order; the game drains it and runs its morning
export function clock_days(clock_st: mut ClockState) -> Queue<DayTurned> {
if clock_st.ck_days == null { clock_st.ck_days = queue_new("clock.days") }
export function clock_days(clock_st: ClockState) -> Queue<DayTurned> {
return clock_st.ck_days
}
@ -61,3 +60,4 @@ export function clock_config_moon(clock_st: mut ClockState, days: float, lo: flo
clock_st.ck_moon_lo = lo
clock_st.ck_moon_hi = hi
}
function ck_days__new() -> Queue<DayTurned> { return queue_new("clock.days") }

View file

@ -27,8 +27,8 @@ program ClockTest {
clock_reset(clock_st)
}
function turned(clock_st: mut ClockState) -> []DayTurned { return q_drain(clock_days(clock_st)) }
function waiting(clock_st: mut ClockState) -> int { return q_len(clock_days(clock_st)) }
function turned(clock_st: ClockState) -> []DayTurned { return q_drain(clock_days(clock_st)) }
function waiting(clock_st: ClockState) -> int { return q_len(clock_days(clock_st)) }
function run_hours(h: float) -> void {
let s = clock_system()
s.tick(tick_new(0.016, 0, h))

View file

@ -65,7 +65,7 @@ program CraftingTest {
craft_reset(crafting_st)
}
function facts(crafting_st: mut CraftingState) -> []Crafted { return q_drain(craft_facts(crafting_st)) }
function facts(crafting_st: CraftingState) -> []Crafted { return q_drain(craft_facts(crafting_st)) }
test "the registry is the game's, in the order written" {
expect_eq(CRAFT_COUNT, 5)

View file

@ -2,11 +2,10 @@
export state CraftingState {
craft_hold_i: int = -1
craft_hold_t: float = 0.0
craft_fact_q: Queue<Crafted> = null
craft_fact_q: Queue<Crafted> = craft_fact_q__new()
}
export function craft_facts(crafting_st: mut CraftingState) -> Queue<Crafted> {
if crafting_st.craft_fact_q == null { crafting_st.craft_fact_q = queue_new("crafting.crafted") }
export function craft_facts(crafting_st: CraftingState) -> Queue<Crafted> {
return crafting_st.craft_fact_q
}
@ -50,7 +49,7 @@ export function craft_refund(i: int) -> void {
}
}
function craft_fact_push(crafting_st: mut CraftingState, i: int, queued: bool) -> void {
function craft_fact_push(crafting_st: CraftingState, i: int, queued: bool) -> void {
let r = CraftRecipes[i]
let c = new Crafted
c.recipe = i
@ -63,7 +62,7 @@ function craft_fact_push(crafting_st: mut CraftingState, i: int, queued: bool) -
# make it: a timed recipe at a station goes into the station (given back if it will not take it),
# anything else is handed over at once. False, and the pack untouched, when it cannot be made.
export function craft_make(crafting_st: mut CraftingState, i: int) -> bool {
export function craft_make(crafting_st: CraftingState, i: int) -> bool {
if not craft_can(i) { return false }
let r = CraftRecipes[i]
craft_take(i)
@ -79,3 +78,4 @@ export function craft_make(crafting_st: mut CraftingState, i: int) -> bool {
craft_fact_push(crafting_st, i, false)
return true
}
function craft_fact_q__new() -> Queue<Crafted> { return queue_new("crafting.crafted") }

View file

@ -2,20 +2,20 @@
function ef_live(e: Effect) -> bool { return e.delay < 0.01 }
# what the rules should add for a kind right now (a delayed one counts only once it begins)
export function effects_sum(effects_st: mut EffectsState, kind: int) -> float {
export function effects_sum(effects_st: EffectsState, kind: int) -> float {
let all = ef_all(effects_st)
var t = 0.0
for i in 0 .. len(all) { if all[i].kind == kind and ef_live(all[i]) { t = t + all[i].mag } }
return t
}
export function effects_has(effects_st: mut EffectsState, kind: int) -> bool {
export function effects_has(effects_st: EffectsState, kind: int) -> bool {
let all = ef_all(effects_st)
for i in 0 .. len(all) { if all[i].kind == kind and ef_live(all[i]) { return true } }
return false
}
export function effects_bonus_count(effects_st: mut EffectsState) -> int {
export function effects_bonus_count(effects_st: EffectsState) -> int {
let all = ef_all(effects_st)
var n = 0
for i in 0 .. len(all) { if all[i].bonus { n += 1 } }
@ -23,10 +23,10 @@ export function effects_bonus_count(effects_st: mut EffectsState) -> int {
}
# everything held, delayed or not, in the order added
export function effects_count(effects_st: mut EffectsState) -> int { return len(ef_all(effects_st)) }
export function effects_count(effects_st: EffectsState) -> int { return len(ef_all(effects_st)) }
# a copy, so a reader cannot change the ring
export function effects_at(effects_st: mut EffectsState, i: int) -> Effect {
export function effects_at(effects_st: EffectsState, i: int) -> Effect {
let src = ef_all(effects_st)[i]
let e = new Effect
e.kind = src.kind
@ -39,7 +39,7 @@ export function effects_at(effects_st: mut EffectsState, i: int) -> Effect {
}
# the indices of the ones that have begun, for a read-out
export function effects_live(effects_st: mut EffectsState) -> []int {
export function effects_live(effects_st: EffectsState) -> []int {
let out = new []int
let all = ef_all(effects_st)
for i in 0 .. len(all) { if ef_live(all[i]) { push(out, i) } }

View file

@ -21,20 +21,18 @@ export property EffectEnded {
}
export state EffectsState {
ef_list: []Effect = null
ef_list: []Effect = new []Effect
ef_max: int = 8
ef_bonus_max: int = 3
ef_ended: Queue<EffectEnded> = null
ef_ended: Queue<EffectEnded> = ef_ended__new()
}
function ef_all(effects_st: mut EffectsState) -> []Effect {
if effects_st.ef_list == null { effects_st.ef_list = new []Effect }
function ef_all(effects_st: EffectsState) -> []Effect {
return effects_st.ef_list
}
# the facts: what ended and why, oldest first; the game drains it
export function effects_ended(effects_st: mut EffectsState) -> Queue<EffectEnded> {
if effects_st.ef_ended == null { effects_st.ef_ended = queue_new("effects.ended") }
export function effects_ended(effects_st: EffectsState) -> Queue<EffectEnded> {
return effects_st.ef_ended
}
@ -46,3 +44,4 @@ export function effects_config(effects_st: mut EffectsState, max: int, bonus_max
export function effects_capacity(effects_st: EffectsState) -> int { return effects_st.ef_max }
export function effects_bonus_capacity(effects_st: EffectsState) -> int { return effects_st.ef_bonus_max }
function ef_ended__new() -> Queue<EffectEnded> { return queue_new("effects.ended") }

View file

@ -6,7 +6,7 @@ export function effects_reset(effects_st: mut EffectsState) -> void {
function effects_tick(effects_st: mut EffectsState, t: Tick) -> void { effects_run(effects_st, t.hours * 60.0) }
export function effects_save(effects_st: mut EffectsState) -> Val {
export function effects_save(effects_st: EffectsState) -> Val {
let l = Value.list()
let all = ef_all(effects_st)
for i in 0 .. len(all) {

View file

@ -13,8 +13,8 @@ program EffectsTest {
effects_reset(effects_st)
}
function ended(effects_st: mut EffectsState) -> []EffectEnded { return q_drain(effects_ended(effects_st)) }
function waiting(effects_st: mut EffectsState) -> int { return q_len(effects_ended(effects_st)) }
function ended(effects_st: EffectsState) -> []EffectEnded { return q_drain(effects_ended(effects_st)) }
function waiting(effects_st: EffectsState) -> int { return q_len(effects_ended(effects_st)) }
function tick_minutes(m: float) -> void {
let s = effects_system()

View file

@ -19,7 +19,7 @@ function ef_drop(effects_st: mut EffectsState, i: int) -> void {
}
# the one with the least time left (of the bonuses only, when asked); -1 when there is none
function ef_nearest_end(effects_st: mut EffectsState, bonus_only: bool) -> int {
function ef_nearest_end(effects_st: EffectsState, bonus_only: bool) -> int {
let all = ef_all(effects_st)
var at = -1
for i in 0 .. len(all) {

View file

@ -20,7 +20,7 @@ export state FireState {
fr_lit: bool = false
fr_fuel: float = 0.0 # game minutes left
fr_rain_h: float = 0.0 # game hours today it burned in the rain under cover
fr_facts: Queue<FireFact> = null
fr_facts: Queue<FireFact> = fr_facts__new()
}
# what lighting or feeding would come to, as the world stands
@ -43,12 +43,11 @@ export property FireFact {
# the facts, oldest first; the game drains them into its notices
export function fire_facts(fire_st: mut FireState) -> Queue<FireFact> {
if fire_st.fr_facts == null { fire_st.fr_facts = queue_new("fire.facts") }
export function fire_facts(fire_st: FireState) -> Queue<FireFact> {
return fire_st.fr_facts
}
function fr_fact(fire_st: mut FireState, what: int) -> void {
function fr_fact(fire_st: FireState, what: int) -> void {
let f = new FireFact
f.what = what
f.fuel = fire_st.fr_fuel
@ -68,3 +67,4 @@ export function fire_config_reach(fire_st: mut FireState, warm: float, cook: flo
fire_st.fr_warm_radius = warm
fire_st.fr_cook_radius = cook
}
function fr_facts__new() -> Queue<FireFact> { return queue_new("fire.facts") }

View file

@ -29,7 +29,7 @@ program FireTest {
fire_reset(fire_st)
}
function facts(fire_st: mut FireState) -> []FireFact { return q_drain(fire_facts(fire_st)) }
function facts(fire_st: FireState) -> []FireFact { return q_drain(fire_facts(fire_st)) }
function count(fs: []FireFact, what: int) -> int {
var n = 0
for i in 0 .. len(fs) { if fs[i].what == what { n += 1 } }

View file

@ -24,7 +24,7 @@ export state FishingState {
fishing_run_left: int = 0
fishing_run_next: float = 0.0
fishing_dice: Rng = null
fishing_fact_q: Queue<FishingFact> = null
fishing_fact_q: Queue<FishingFact> = fishing_fact_q__new()
fishing_n: int = 0 # the record: caught, the biggest (cm), a legend landed
fishing_big: int = 0
fishing_leg: bool = false
@ -42,8 +42,7 @@ export function fishing_config(fishing_st: mut FishingState, min_depth: float, d
fishing_st.fishing_dice = rng_new(seed)
}
export function fishing_facts(fishing_st: mut FishingState) -> Queue<FishingFact> {
if fishing_st.fishing_fact_q == null { fishing_st.fishing_fact_q = queue_new("fishing.facts") }
export function fishing_facts(fishing_st: FishingState) -> Queue<FishingFact> {
return fishing_st.fishing_fact_q
}
@ -52,7 +51,7 @@ function fishing_rand(fishing_st: mut FishingState) -> float {
return rng_float(fishing_st.fishing_dice)
}
function fishing_say(fishing_st: mut FishingState, what: int) -> void {
function fishing_say(fishing_st: FishingState, what: int) -> void {
let f = new FishingFact
f.what = what
f.species = fishing_st.fishing_sp
@ -89,3 +88,4 @@ export function fishing_legend_caught(fishing_st: FishingState) -> bool { return
export function fishing_water_at(fishing_st: FishingState, x: float, z: float) -> bool {
return FishingWorld.afloat() or FishingWorld.depth(x, z) >= fishing_st.fishing_min_depth
}
function fishing_fact_q__new() -> Queue<FishingFact> { return queue_new("fishing.facts") }

View file

@ -38,7 +38,7 @@ program FishingTest {
fishing_test_st.skill = 0.0
}
function facts(fishing_st: mut FishingState) -> []FishingFact { return q_drain(fishing_facts(fishing_st)) }
function facts(fishing_st: FishingState) -> []FishingFact { return q_drain(fishing_facts(fishing_st)) }
function saw(fs: []FishingFact, what: int) -> bool {
for i in 0 .. len(fs) { if fs[i].what == what { return true } }
return false

View file

@ -26,7 +26,7 @@ event Crit { target: int = 0, src: int = 0 } # the attacker's crit_pct fired
state GameplayState {
combat_reflecting: bool = false # thorns never reflect thorns
combat_pending: int = 0
fac_tbl: words = null
fac_tbl: words = words(FAC_MAX * FAC_MAX)
}
# the mutable channel for lever 6: listeners rewrite the pending damage here.

View file

@ -18,7 +18,6 @@ const REL_HOSTILE: int = 2
# A global var initialiser must be a literal, so it is allocated lazily.
function fac_ensure(gameplay_st: mut GameplayState) -> void {
if gameplay_st.fac_tbl == null { gameplay_st.fac_tbl = words(FAC_MAX * FAC_MAX) }
}
# Faction.set(a, b, rel) — record a symmetric relationship between two factions.

View file

@ -1,5 +1,5 @@
# buy.ludic - a tier bought with money once the standing is there; the kind's item follows
export function gear_can_buy(gear_st: mut GearState, k: int) -> bool {
export function gear_can_buy(gear_st: GearState, k: int) -> bool {
if not gear_ok(k) or gear_best(gear_st, k) or GearWorld.hidden(k) { return false }
return GearPurse.rep() >= gear_next_rep(gear_st, k) and GearPurse.money() >= gear_next_cost(gear_st, k)
}
@ -17,7 +17,6 @@ export function gear_buy(gear_st: mut GearState, k: int) -> bool {
# a kind whose item is already carried counts as its first tier
export function gear_sync(gear_st: mut GearState) -> void {
gear__ensure(gear_st)
for k in 0 .. GEAR_COUNT {
let it = GearKinds[k].item
if it >= 0 and gear_st.gear__lv[k] == 0 and GearPack.count(it) > 0 { gear_st.gear__lv[k] = 1 }

View file

@ -4,7 +4,6 @@ export function gear_hand(gear_st: GearState) -> int { return gear_st.gear__hand
# a new thing in the hand (-1 empty): whatever the old one was running goes out
export function gear_set_hand(gear_st: mut GearState, it: int) -> void {
gear__ensure(gear_st)
gear_st.gear__hand = it
for c in 0 .. CHARGE_COUNT { if GearCharges[c].hand { gear_st.gear__on[c] = false } }
}
@ -15,26 +14,22 @@ export function gear_charge_of(it: int) -> int {
return -1
}
export function gear_charge(gear_st: mut GearState, c: int) -> float {
gear__ensure(gear_st)
export function gear_charge(gear_st: GearState, c: int) -> float {
return gear_st.gear__left[c]
}
export function gear_charge_set(gear_st: mut GearState, c: int, v: float) -> void {
gear__ensure(gear_st)
gear_st.gear__left[c] = Math.clamp(v, 0.0, GearCharges[c].full)
}
export function gear_charge_fill(gear_st: mut GearState, c: int) -> void { gear_charge_set(gear_st, c, GearCharges[c].full) }
export function gear_running(gear_st: mut GearState, c: int) -> bool {
gear__ensure(gear_st)
export function gear_running(gear_st: GearState, c: int) -> bool {
return gear_st.gear__on[c]
}
# on or off; false when it has nothing left, or is held and not in the hand
export function gear_run(gear_st: mut GearState, c: int, on: bool) -> bool {
gear__ensure(gear_st)
if not on {
gear_st.gear__on[c] = false
return true
@ -46,13 +41,13 @@ export function gear_run(gear_st: mut GearState, c: int, on: bool) -> bool {
}
# the hand's own charge is running (a torch lit, a flashlight on)
export function gear_lit(gear_st: mut GearState) -> bool {
export function gear_lit(gear_st: GearState) -> bool {
if gear_st.gear__hand < 0 { return false }
let c = gear_charge_of(gear_st.gear__hand)
return c >= 0 and GearCharges[c].hand and gear_running(gear_st, c)
}
function gear__rate(gear_st: mut GearState, c: int) -> float {
function gear__rate(gear_st: GearState, c: int) -> float {
let d = GearCharges[c]
if d.rate >= 0 { return gear_value(gear_st, d.rate) }
return d.per_hour
@ -60,7 +55,6 @@ function gear__rate(gear_st: mut GearState, c: int) -> float {
# the game hours of a tick burn every running charge; one that runs out stops and says so
function gear__burn(gear_st: mut GearState, hours: float) -> void {
gear__ensure(gear_st)
for c in 0 .. CHARGE_COUNT {
if not gear_st.gear__on[c] { continue }
gear_st.gear__left[c] = gear_st.gear__left[c] - hours * gear__rate(gear_st, c)

View file

@ -1,30 +1,32 @@
# state.ludic - the level of each kind, the hand, each charge's units and whether it runs, the facts
export state GearState {
gear__lv: []int = null
gear__lv: []int = gear__starts()
gear__hand: int = -1
gear__left: []float = null
gear__on: []bool = null
gear__q: Queue<GearFact> = null
gear__left: []float = gear__fulls()
gear__on: []bool = gear__offs()
gear__q: Queue<GearFact> = gear__queue()
}
# what a new state starts with: every kind at its start, every charge full and off
function gear__starts() -> []int {
let xs = new []int
for k in 0 .. GEAR_COUNT { push(xs, GearKinds[k].start) }
return xs
}
function gear__fulls() -> []float {
let xs = new []float
for c in 0 .. CHARGE_COUNT { push(xs, GearCharges[c].full) }
return xs
}
function gear__queue() -> Queue<GearFact> { return queue_new("gear.facts") }
function gear__offs() -> []bool {
let xs = new []bool
for c in 0 .. CHARGE_COUNT { push(xs, false) }
return xs
}
function gear__ensure(gear_st: mut GearState) -> void {
if gear_st.gear__lv != null { return }
gear_st.gear__lv = new []int
for k in 0 .. GEAR_COUNT { push(gear_st.gear__lv, GearKinds[k].start) }
gear_st.gear__left = new []float
gear_st.gear__on = new []bool
for c in 0 .. CHARGE_COUNT {
push(gear_st.gear__left, GearCharges[c].full)
push(gear_st.gear__on, false)
}
}
export function gear_facts(gear_st: GearState) -> Queue<GearFact> { return gear_st.gear__q }
export function gear_facts(gear_st: mut GearState) -> Queue<GearFact> {
if gear_st.gear__q == null { gear_st.gear__q = queue_new("gear.facts") }
return gear_st.gear__q
}
function gear__fact(gear_st: mut GearState, what: int, k: int, c: int, cost: int) -> void {
function gear__fact(gear_st: GearState, what: int, k: int, c: int, cost: int) -> void {
let f = new GearFact
f.what = what
f.cost = cost

View file

@ -1,7 +1,6 @@
# system.ludic - gear as a system: the burn each tick, and the levels and charges saved by key (the
# hand is not saved: a trip opens with empty hands)
export function gear_reset(gear_st: mut GearState) -> void {
gear__ensure(gear_st)
for k in 0 .. GEAR_COUNT { gear_st.gear__lv[k] = GearKinds[k].start }
for c in 0 .. CHARGE_COUNT {
gear_st.gear__left[c] = GearCharges[c].full
@ -11,8 +10,7 @@ export function gear_reset(gear_st: mut GearState) -> void {
q_clear(gear_facts(gear_st))
}
export function gear_save(gear_st: mut GearState) -> Val {
gear__ensure(gear_st)
export function gear_save(gear_st: GearState) -> Val {
let v = Value.object()
let lv = Value.object()
for k in 0 .. GEAR_COUNT { sv_put_int(lv, GearKinds[k].key, gear_st.gear__lv[k]) }

View file

@ -51,7 +51,7 @@ program GearTest {
gear_reset(gear_st)
}
function ran_out(gear_st: mut GearState) -> int {
function ran_out(gear_st: GearState) -> int {
let fs = q_drain(gear_facts(gear_st))
var n = -1
for i in 0 .. len(fs) { if fs[i].what == GEAR_RAN_OUT { n = fs[i].charge } }

View file

@ -1,20 +1,18 @@
# tiers.ludic - what is owned and what a tier is worth
export function gear_ok(k: int) -> bool { return k >= 0 and k < GEAR_COUNT }
export function gear_level(gear_st: mut GearState, k: int) -> int {
gear__ensure(gear_st)
export function gear_level(gear_st: GearState, k: int) -> int {
return gear_st.gear__lv[k]
}
# outright: staging, a test, a camera handed over with the trip
export function gear_set_level(gear_st: mut GearState, k: int, lv: int) -> void {
gear__ensure(gear_st)
gear_st.gear__lv[k] = lv
}
export function gear_owned(gear_st: mut GearState, k: int) -> bool { return gear_level(gear_st, k) > 0 }
export function gear_owned(gear_st: GearState, k: int) -> bool { return gear_level(gear_st, k) > 0 }
export function gear_best(gear_st: mut GearState, k: int) -> bool { return gear_level(gear_st, k) >= GearKinds[k].tiers }
export function gear_best(gear_st: GearState, k: int) -> bool { return gear_level(gear_st, k) >= GearKinds[k].tiers }
# a tier's name, "" for none
export function gear_level_name(k: int, lv: int) -> string {
@ -23,14 +21,14 @@ export function gear_level_name(k: int, lv: int) -> string {
}
# the tier on offer next: its name, cost and the standing it wants
export function gear_next_name(gear_st: mut GearState, k: int) -> string { return gear_level_name(k, gear_level(gear_st, k) + 1) }
export function gear_next_name(gear_st: GearState, k: int) -> string { return gear_level_name(k, gear_level(gear_st, k) + 1) }
export function gear_next_cost(gear_st: mut GearState, k: int) -> int {
export function gear_next_cost(gear_st: GearState, k: int) -> int {
if gear_best(gear_st, k) { return 0 }
return GearKinds[k].cost[gear_level(gear_st, k)]
}
export function gear_next_rep(gear_st: mut GearState, k: int) -> int {
export function gear_next_rep(gear_st: GearState, k: int) -> int {
if gear_best(gear_st, k) { return 0 }
return GearKinds[k].rep[gear_level(gear_st, k)]
}
@ -43,10 +41,10 @@ function gear__pick(xs: []float, lv: int, fallback: float) -> float {
}
# the kind's own number at its level (1.0 when it has none)
export function gear_mult(gear_st: mut GearState, k: int) -> float { return gear__pick(GearKinds[k].mult, gear_level(gear_st, k), 1.0) }
export function gear_mult(gear_st: GearState, k: int) -> float { return gear__pick(GearKinds[k].mult, gear_level(gear_st, k), 1.0) }
# a value its kind's tier decides
export function gear_value(gear_st: mut GearState, v: int) -> float {
export function gear_value(gear_st: GearState, v: int) -> float {
let d = GearValues[v]
return gear__pick(d.at, gear_level(gear_st, d.gear), 0.0)
}

View file

@ -10,15 +10,14 @@ export state HintsState {
hn_t: float = 0.0 # seconds to the next pass
hn_pick: int = 0 # which chip the key would open
hn_card: int = -1 # the card being read, or -1
hn_facts: Queue<HintsFact> = null
hn_facts: Queue<HintsFact> = hn_facts__new()
}
export function hints_facts(hints_st: mut HintsState) -> Queue<HintsFact> {
if hints_st.hn_facts == null { hints_st.hn_facts = queue_new("hints.facts") }
export function hints_facts(hints_st: HintsState) -> Queue<HintsFact> {
return hints_st.hn_facts
}
function hn_fact(hints_st: mut HintsState, what: int, card: int) -> void {
function hn_fact(hints_st: HintsState, what: int, card: int) -> void {
let f = new HintsFact
f.what = what
f.card = card
@ -104,3 +103,4 @@ export function hints_reset(hints_st: mut HintsState) -> void {
hints_st.hn_card = -1
q_clear(hints_facts(hints_st))
}
function hn_facts__new() -> Queue<HintsFact> { return queue_new("hints.facts") }

View file

@ -29,7 +29,7 @@ program HintsTest {
hints_mutes_load(hints_st, Value.list())
}
function count(hints_st: mut HintsState, what: int) -> int {
function count(hints_st: HintsState, what: int) -> int {
let fs = q_drain(hints_facts(hints_st))
var n = 0
for i in 0 .. len(fs) { if fs[i].what == what { n += 1 } }

View file

@ -15,7 +15,7 @@ export property ItemChanged {
export state InventoryState {
iv_keys: []string = null
iv_counts: []int = null
iv_changes: Queue<ItemChanged> = null
iv_changes: Queue<ItemChanged> = iv_changes__new()
}
# the kinds, by the name each is saved under; the pack starts empty
@ -24,8 +24,7 @@ export function inv_config(inventory_st: mut InventoryState, keys: []string) ->
inv_clear(inventory_st)
}
export function inv_changes(inventory_st: mut InventoryState) -> Queue<ItemChanged> {
if inventory_st.iv_changes == null { inventory_st.iv_changes = queue_new("inventory.changes") }
export function inv_changes(inventory_st: InventoryState) -> Queue<ItemChanged> {
return inventory_st.iv_changes
}
@ -59,3 +58,4 @@ export function inv_total(inventory_st: InventoryState) -> int {
for i in 0 .. len(inventory_st.iv_counts) { t += inventory_st.iv_counts[i] }
return t
}
function iv_changes__new() -> Queue<ItemChanged> { return queue_new("inventory.changes") }

View file

@ -28,8 +28,8 @@ program InventoryTest {
inv_reset(inventory_st)
}
function changes(inventory_st: mut InventoryState) -> []ItemChanged { return q_drain(inv_changes(inventory_st)) }
function waiting(inventory_st: mut InventoryState) -> int { return q_len(inv_changes(inventory_st)) }
function changes(inventory_st: InventoryState) -> []ItemChanged { return q_drain(inv_changes(inventory_st)) }
function waiting(inventory_st: InventoryState) -> int { return q_len(inv_changes(inventory_st)) }
test "add puts in what fits and says how many" (inventory_st: mut InventoryState) {
fresh(inventory_st)

View file

@ -20,7 +20,7 @@ export state JobsState {
jobs__serial: []int = null # posts made, per board: each roll its own seed
jobs__seed: int = 1000
jobs__dice: Rng = null
jobs__q: Queue<JobsFact> = null
jobs__q: Queue<JobsFact> = jobs__q__new()
}
# the posts, every board's slots end to end from jobs__off[b]
@ -59,12 +59,11 @@ function jobs__ensure(jobs_st: mut JobsState) -> void {
jobs_st.jobs__dice = rng_new(jobs_st.jobs__seed)
}
export function jobs_facts(jobs_st: mut JobsState) -> Queue<JobsFact> {
if jobs_st.jobs__q == null { jobs_st.jobs__q = queue_new("jobs.facts") }
export function jobs_facts(jobs_st: JobsState) -> Queue<JobsFact> {
return jobs_st.jobs__q
}
function jobs__fact(jobs_st: mut JobsState, what: int, job: int, b: int, s: int, have: int, need: int) -> void {
function jobs__fact(jobs_st: JobsState, what: int, job: int, b: int, s: int, have: int, need: int) -> void {
let f = new JobsFact
f.what = what
f.job = job
@ -93,3 +92,4 @@ export function jobs_config_seed(jobs_st: mut JobsState, seed: int) -> void {
jobs_st.jobs__seed = seed
jobs_st.jobs__dice = rng_new(seed)
}
function jobs__q__new() -> Queue<JobsFact> { return queue_new("jobs.facts") }

View file

@ -59,7 +59,7 @@ program JobsTest {
jobs_party_reset(jobs_st)
}
function count_of(jobs_st: mut JobsState, what: int) -> int {
function count_of(jobs_st: JobsState, what: int) -> int {
let fs = q_drain(jobs_facts(jobs_st))
var n = 0
for i in 0 .. len(fs) { if fs[i].what == what { n += 1 } }

View file

@ -56,7 +56,7 @@ export state NeedsState {
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> = null
nd_facts: Queue<NeedFact> = nd_facts__new()
}
function nd_lv(needs_st: mut NeedsState) -> []float {
@ -75,12 +75,11 @@ function nd_fill(needs_st: mut NeedsState) -> void {
}
# the facts, oldest first; the game drains them into its notices and its collapse
export function needs_facts(needs_st: mut NeedsState) -> Queue<NeedFact> {
if needs_st.nd_facts == null { needs_st.nd_facts = queue_new("needs.facts") }
export function needs_facts(needs_st: NeedsState) -> Queue<NeedFact> {
return needs_st.nd_facts
}
function nd_fact(needs_st: mut NeedsState, what: int, need: int) -> void {
function nd_fact(needs_st: NeedsState, what: int, need: int) -> void {
let f = new NeedFact
f.what = what
f.need = need
@ -88,3 +87,4 @@ function nd_fact(needs_st: mut NeedsState, what: int, need: int) -> void {
}
function nd_ok(k: int) -> bool { return k >= 0 and k < NEED_COUNT }
function nd_facts__new() -> Queue<NeedFact> { return queue_new("needs.facts") }

View file

@ -46,7 +46,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 facts(needs_st: mut NeedsState) -> []NeedFact { return q_drain(needs_facts(needs_st)) }
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) {
fresh(needs_st)

View file

@ -73,7 +73,6 @@ export function nr_text(net_st: mut NetState, cap: int) -> string {
net_st.net__rbad = true
return ""
}
if net_st.net__tb == null { net_st.net__tb = buffer(NET_MTU) }
nb_copy(net_st.net__tb, 0, net_st.net__rb, net_st.net__rp, n)
net_st.net__rp += n
return text_of(net_st.net__tb, n)

View file

@ -61,17 +61,15 @@ export port NetSocket {
export function net_config(net_st: mut NetState, c: NetConfig) -> void { net_st.net__cfg = c }
function net__conf(net_st: mut NetState) -> NetConfig {
if net_st.net__cfg == null { net_st.net__cfg = new NetConfig }
function net__conf(net_st: NetState) -> NetConfig {
return net_st.net__cfg
}
export function net_facts(net_st: mut NetState) -> Queue<NetFact> {
if net_st.net__facts == null { net_st.net__facts = queue_new("net.facts") }
export function net_facts(net_st: NetState) -> Queue<NetFact> {
return net_st.net__facts
}
function net__fact(net_st: mut NetState, what: int, slot: int, pid: int, why: int, text: string) -> void {
function net__fact(net_st: NetState, what: int, slot: int, pid: int, why: int, text: string) -> void {
let f = new NetFact
f.what = what
f.slot = slot

View file

@ -4,7 +4,6 @@
function net__new_guest(net_st: mut NetState, pub: string, local: string) -> void {
let key = `{pub}|{local}`
if net_st.net__seen == null { net_st.net__seen = new []string }
for i in 0 .. len(net_st.net__seen) { if net_st.net__seen[i] == key { return } }
push(net_st.net__seen, key)
net__log(`room {net_st.net__room}: a guest at {pub} / {local}`)

View file

@ -77,7 +77,7 @@ function net__messages(net_st: mut NetState, slot: int, n: int) -> void {
}
# onto the inbox - except a heartbeat, and on a host anything but a hello before its welcome
function net__deliver(net_st: mut NetState, slot: int, from: int, kind: int, o: int, ml: int) -> void {
function net__deliver(net_st: NetState, slot: int, from: int, kind: int, o: int, ml: int) -> void {
if kind == NET_BEAT { return }
if net_st.net__state == NET_HOSTING and net_st.net__peers[slot].pid < 2 and kind != NET_HELLO { return }
let m = new NetMessage

View file

@ -38,7 +38,7 @@ function net__use_relay(net_st: mut NetState) -> void {
export function net_via_relay(net_st: NetState) -> bool { return net_st.net__via_relay }
function net__relayed(net_st: mut NetState, p: NetPeer) -> bool {
function net__relayed(net_st: NetState, p: NetPeer) -> bool {
return net_st.net__relay_ip != 0 and p.ip == net_st.net__relay_ip and (p.port >= net__conf(net_st).relay_port0 or net_st.net__via_relay)
}

View file

@ -10,7 +10,7 @@ const NET_R_DONE: int = 5 # a guest: the hello is on its way
# room codes are on when the game named a matchmaker
export function net_room_on(net_st: mut NetState) -> bool { return len(net__conf(net_st).signal_url) > 0 }
export function net_room_on(net_st: NetState) -> bool { return len(net__conf(net_st).signal_url) > 0 }
export function net_room(net_st: NetState) -> string { return net_st.net__room }
export function net_room_asking(net_st: NetState) -> bool { return net_st.net__r_state == NET_R_STUN or net_st.net__r_state == NET_R_ASK }

View file

@ -48,9 +48,9 @@ export property NetMessage {
}
export state NetState {
net__cfg: NetConfig = null
net__facts: Queue<NetFact> = null
net__seen: []string = null # guests already punched for
net__cfg: NetConfig = new NetConfig
net__facts: Queue<NetFact> = net__facts__new()
net__seen: []string = new []string # guests already punched for
net__punch_ip: words = null
net__punch_port: words = null
net__punch_left: words = null
@ -88,7 +88,7 @@ export state NetState {
net__rl: int = 0
net__rp: int = 0
net__rbad: bool = false
net__tb: []byte = null # text read out of a message, through one scratch buffer
net__tb: []byte = buffer(NET_MTU) # text read out of a message, through one scratch buffer
net__hello_b: []byte = null # the game's hello, sent again on every dial
net__hello_l: int = 0
net__hello_t: float = 0.0 # seconds since it went; -1 not yet
@ -100,15 +100,14 @@ export state NetState {
net__code_port: int = 0
net__bytes_out: int = 0
net__kind_out: words = null
net__inbox: Queue<NetMessage> = null
net__inbox: Queue<NetMessage> = net__inbox__new()
net__stun_ip: int = 0
net__stun_port: int = 0
net__txn: words = null
net__txn: words = words(3)
net__dice: Rng = null
}
export function net_inbox(net_st: mut NetState) -> Queue<NetMessage> {
if net_st.net__inbox == null { net_st.net__inbox = queue_new("net.inbox") }
export function net_inbox(net_st: NetState) -> Queue<NetMessage> {
return net_st.net__inbox
}
@ -126,3 +125,5 @@ function net__init(net_st: mut NetState) -> void {
net_st.net__rb = buffer(NET_MTU)
net_st.net__hello_b = buffer(NET_MTU)
}
function net__facts__new() -> Queue<NetFact> { return queue_new("net.facts") }
function net__inbox__new() -> Queue<NetMessage> { return queue_new("net.inbox") }

View file

@ -2,7 +2,6 @@
# from outside: the router's address and the port it mapped
function net__stun_send(net_st: mut NetState) -> void {
if net_st.net__txn == null { net_st.net__txn = words(3) }
if net_st.net__dice == null { net_st.net__dice = rng_new(net__conf(net_st).seed) }
if net_st.net__stun_ip == 0 {
let c = net__conf(net_st)

View file

@ -97,7 +97,7 @@ program NetTest {
return net_accept(net_st, got[0].slot)
}
function facts_of(net_st: mut NetState, what: int) -> []NetFact {
function facts_of(net_st: NetState, what: int) -> []NetFact {
let all = q_drain(net_facts(net_st))
let out = new []NetFact
for i in 0 .. len(all) { if all[i].what == what { push(out, all[i]) } }

View file

@ -30,7 +30,7 @@ function np_turns(act: int) -> bool {
}
# a player who came within notice since the last look is greeted - once, until they walk off
export function npc_notice(npc_st: mut NpcState, p: NpcPerson) -> void {
export function npc_notice(npc_st: NpcState, p: NpcPerson) -> void {
let reach = NpcKinds[p.kind].notice
for i in 0 .. NpcWorld.players() {
if i >= 30 { break }

View file

@ -1,7 +1,7 @@
# census.ludic - making one (a slot reused before a new one, a look, a name, a start on its own
# ground out of the players' sight where that can be had), a post's fixed person, and leaving
export function npc_spawn(npc_st: mut NpcState, kind: int) -> NpcPerson {
np_ensure(npc_st)
np_ensure()
if npc_st.np_n >= npc_st.np_max or kind < 0 or kind >= NPCK_COUNT { return null }
var p: NpcPerson = null
for i in 0 .. len(npc_st.np_walkers) {
@ -94,7 +94,7 @@ export function npc_set_at(p: NpcPerson, x: float, z: float) -> void {
# somebody fixed at a post (a vendor behind the counter): never walks, never counted, never leaves,
# turns to a player within its kind's notice and back to `yaw` when they go
export function npc_place(npc_st: mut NpcState, kind: int, x: float, z: float, yaw: float, name: string, look: int) -> NpcPerson {
np_ensure(npc_st)
np_ensure()
let p = new NpcPerson
p.slot = len(npc_st.np_posts)
np_fresh(p, kind, look)

View file

@ -3,7 +3,7 @@
# on: this machine's own walkers leave, and only the host's are drawn until it is turned off
export function npc_mirror(npc_st: mut NpcState, on: bool) -> void {
np_ensure(npc_st)
np_ensure()
if npc_st.np_mirror == on { return }
npc_st.np_mirror = on
for i in 0 .. len(npc_st.np_walkers) { npc_retire(npc_st, npc_st.np_walkers[i]) }
@ -14,7 +14,7 @@ export function npc_mirroring(npc_st: NpcState) -> bool { return npc_st.np_mirro
# the host's slot: somebody new in it (born), or nobody (gone)
export function npc_put(npc_st: mut NpcState, slot: int, id: int, kind: int, look: int, seed: float, name: string, hx: float, hz: float) -> NpcPerson {
np_ensure(npc_st)
np_ensure()
if slot < 0 or slot >= npc_st.np_max or kind < 0 or kind >= NPCK_COUNT { return null }
while len(npc_st.np_walkers) <= slot {
let q = new NpcPerson
@ -36,7 +36,7 @@ export function npc_put(npc_st: mut NpcState, slot: int, id: int, kind: int, loo
}
# where the host says it is now, and what it is doing
export function npc_heard(npc_st: mut NpcState, slot: int, x: float, y: float, z: float, yaw: float, speed: float, act: int, stalk: bool) -> void {
export function npc_heard(npc_st: NpcState, slot: int, x: float, y: float, z: float, yaw: float, speed: float, act: int, stalk: bool) -> void {
let p = npc_at(npc_st, slot)
if p == null or not p.active { return }
if not p.heard {
@ -60,7 +60,7 @@ export function npc_heard(npc_st: mut NpcState, slot: int, x: float, y: float, z
export function npc_heard_lately(npc_st: NpcState, p: NpcPerson) -> bool { return p.heard and npc_st.np_clock - p.heard_t <= 6.0 }
export function npc_mirror_tick(npc_st: mut NpcState, dt: float) -> void {
np_ensure(npc_st)
np_ensure()
npc_st.np_clock = npc_st.np_clock + dt
let k = Math.min(1.0, dt * 8.0)
for i in 0 .. len(npc_st.np_walkers) {

View file

@ -1,7 +1,7 @@
# names.ludic - a name nobody else in the place is using: not another person, not one the place
# keeps for itself (NpcWorld.taken: a vendor), and not somebody who left a little while ago
export function npc_name_used(npc_st: mut NpcState, n: string) -> bool {
export function npc_name_used(npc_st: NpcState, n: string) -> bool {
if NpcWorld.taken(n) { return true }
let all = npc_walkers(npc_st)
for i in 0 .. len(all) { if all[i].active and all[i].name == n { return true } }
@ -12,7 +12,7 @@ export function npc_name_used(npc_st: mut NpcState, n: string) -> bool {
}
# a free name from the body's pool, from a place in it the dice choose ("" when the pool is empty)
export function npc_pick_name(npc_st: mut NpcState, body: int) -> string {
export function npc_pick_name(npc_st: NpcState, body: int) -> string {
let pool = new []string
for i in 0 .. NPCN_COUNT { if NpcNames[i].body == body { push(pool, NpcNames[i].name) } }
let n = len(pool)
@ -26,7 +26,6 @@ export function npc_pick_name(npc_st: mut NpcState, body: int) -> string {
}
function np_left(npc_st: mut NpcState, name: string) -> void {
if npc_st.np_recent == null { npc_st.np_recent = new []string }
push(npc_st.np_recent, name)
if len(npc_st.np_recent) <= 8 { return }
let keep = new []string
@ -35,7 +34,7 @@ function np_left(npc_st: mut NpcState, name: string) -> void {
}
# how many pairs share a name, the place's own names included
export function npc_name_clashes(npc_st: mut NpcState) -> int {
export function npc_name_clashes(npc_st: NpcState) -> int {
var dup = 0
let all = npc_walkers(npc_st)
for i in 0 .. len(all) {

View file

@ -6,13 +6,13 @@ export state NpcState {
np_wx: float = 0.0
np_wz: float = 0.0
np_clock: float = 0.0
np_recent: []string = null # the last few names that left
np_walkers: []NpcPerson = null
np_posts: []NpcPerson = null
np_recent: []string = new []string # the last few names that left
np_walkers: []NpcPerson = new []NpcPerson
np_posts: []NpcPerson = new []NpcPerson
np_max: int = 10 # walkers at most
np_n: int = 0 # walkers about
np_dice: Rng = null
np_facts: Queue<NpcFact> = null
np_dice: Rng = rng_new(20260925)
np_facts: Queue<NpcFact> = np_facts__new()
np_next_h: float = 0.0 # the hour the census is next looked at
np_hold: bool = false # held where they stand (a shot of their poses)
np_mirror: bool = false # a guest drawing a host's: no routine runs here
@ -23,12 +23,11 @@ export state NpcState {
const NP_PI: float = 3.1415927
const NP_TAU: float = 6.2831853
export function npc_facts(npc_st: mut NpcState) -> Queue<NpcFact> {
if npc_st.np_facts == null { npc_st.np_facts = queue_new("npc.facts") }
export function npc_facts(npc_st: NpcState) -> Queue<NpcFact> {
return npc_st.np_facts
}
function np_fact(npc_st: mut NpcState, what: int, p: NpcPerson, player: int) -> NpcFact {
function np_fact(npc_st: NpcState, what: int, p: NpcPerson, player: int) -> NpcFact {
let f = new NpcFact
f.what = what
f.person = p.id
@ -40,40 +39,37 @@ function np_fact(npc_st: mut NpcState, what: int, p: NpcPerson, player: int) ->
return f
}
function np_ensure(npc_st: mut NpcState) -> void {
if npc_st.np_walkers == null { npc_st.np_walkers = new []NpcPerson }
if npc_st.np_posts == null { npc_st.np_posts = new []NpcPerson }
if npc_st.np_dice == null { npc_st.np_dice = rng_new(20260925) }
function np_ensure() -> void {
}
# how many walkers the place can hold at once
export function npc_config(npc_st: mut NpcState, max: int) -> void { npc_st.np_max = max }
export function npc_seed(npc_st: mut NpcState, n: int) -> void {
np_ensure(npc_st)
export function npc_seed(npc_st: NpcState, n: int) -> void {
np_ensure()
rng_seed(npc_st.np_dice, n)
}
# 0 .. 1, and whole seconds lo .. hi, off the package's dice
export function npc_rnd(npc_st: mut NpcState) -> float {
np_ensure(npc_st)
export function npc_rnd(npc_st: NpcState) -> float {
np_ensure()
return rng_float(npc_st.np_dice)
}
export function npc_between(npc_st: mut NpcState, lo: int, hi: int) -> int {
np_ensure(npc_st)
export function npc_between(npc_st: NpcState, lo: int, hi: int) -> int {
np_ensure()
return rng_between(npc_st.np_dice, lo, hi)
}
export function npc_secs(npc_st: mut NpcState, lo: int, hi: int) -> float { return float(npc_between(npc_st, lo, np_hi(lo, hi))) }
export function npc_secs(npc_st: NpcState, lo: int, hi: int) -> float { return float(npc_between(npc_st, lo, np_hi(lo, hi))) }
export function npc_walkers(npc_st: mut NpcState) -> []NpcPerson {
np_ensure(npc_st)
export function npc_walkers(npc_st: NpcState) -> []NpcPerson {
np_ensure()
return npc_st.np_walkers
}
export function npc_posts(npc_st: mut NpcState) -> []NpcPerson {
np_ensure(npc_st)
export function npc_posts(npc_st: NpcState) -> []NpcPerson {
np_ensure()
return npc_st.np_posts
}
@ -82,20 +78,20 @@ export function npc_count(npc_st: NpcState) -> int { return npc_st.np_n }
export function npc_max(npc_st: NpcState) -> int { return npc_st.np_max }
# a walker's slot or a post, and anyone by id
export function npc_at(npc_st: mut NpcState, slot: int) -> NpcPerson {
np_ensure(npc_st)
export function npc_at(npc_st: NpcState, slot: int) -> NpcPerson {
np_ensure()
if slot < 0 or slot >= len(npc_st.np_walkers) { return null }
return npc_st.np_walkers[slot]
}
export function npc_post(npc_st: mut NpcState, i: int) -> NpcPerson {
np_ensure(npc_st)
export function npc_post(npc_st: NpcState, i: int) -> NpcPerson {
np_ensure()
if i < 0 or i >= len(npc_st.np_posts) { return null }
return npc_st.np_posts[i]
}
export function npc_by_id(npc_st: mut NpcState, id: int) -> NpcPerson {
np_ensure(npc_st)
export function npc_by_id(npc_st: NpcState, id: int) -> NpcPerson {
np_ensure()
for i in 0 .. len(npc_st.np_walkers) { if npc_st.np_walkers[i].active and npc_st.np_walkers[i].id == id { return npc_st.np_walkers[i] } }
for i in 0 .. len(npc_st.np_posts) { if npc_st.np_posts[i].active and npc_st.np_posts[i].id == id { return npc_st.np_posts[i] } }
return null
@ -118,3 +114,4 @@ function np_hi(lo: int, hi: int) -> int {
if hi < lo { return lo }
return hi
}
function np_facts__new() -> Queue<NpcFact> { return queue_new("npc.facts") }

View file

@ -1,7 +1,7 @@
# routine.ludic - going somewhere to do something, doing it here, and deciding what is next: the
# kind's own plan first, then a weighted draw among its steps for this hour, falling through to the
# next step whose spot can be found, and standing a while when none can
export function npc_go(npc_st: mut NpcState, p: NpcPerson, x: float, z: float, act: int, dur: float) -> void {
export function npc_go(npc_st: NpcState, p: NpcPerson, x: float, z: float, act: int, dur: float) -> void {
p.tx = x
p.tz = z
p.next_act = act
@ -76,7 +76,7 @@ export function npc_plan(npc_st: mut NpcState, p: NpcPerson) -> void {
# a weighted draw among the steps whose hours hold now; a step whose spot cannot be found
# gives way to the next one in the table, round to the start
export function npc_steps(npc_st: mut NpcState, p: NpcPerson, steps: []NpcStep) -> bool {
export function npc_steps(npc_st: NpcState, p: NpcPerson, steps: []NpcStep) -> bool {
let h = NpcWorld.hour()
var total = 0
for i in 0 .. len(steps) { if np_in_hours(steps[i], h) { total += np_pos(steps[i].weight) } }

View file

@ -10,7 +10,7 @@ def NpcSpots shore_here { find: fn np_spot_shore_here }
def NpcSpots wander { find: fn np_spot_wander }
# the step's act for the step's time, at (x, z)
export function npc_step_go(npc_st: mut NpcState, p: NpcPerson, s: NpcStep, x: float, z: float) -> void {
export function npc_step_go(npc_st: NpcState, p: NpcPerson, s: NpcStep, x: float, z: float) -> void {
npc_go(npc_st, p, x, z, s.act, npc_secs(npc_st, s.lo, s.hi))
}

View file

@ -55,7 +55,7 @@ function fk_player_at(npc_tests_fake_st: mut NpcTestsFakeState, x: float, z: flo
# seconds of the place, in twentieths
function fk_run(npc_st: mut NpcState, secs: float) -> void { for k in 0 .. int(secs * 20.0) { npc_tick(npc_st, 0.05) } }
function fk_count(npc_st: mut NpcState, what: int) -> int {
function fk_count(npc_st: NpcState, what: int) -> int {
let fs = q_drain(npc_facts(npc_st))
var n = 0
for i in 0 .. len(fs) { if fs[i].what == what { n += 1 } }

View file

@ -1,7 +1,7 @@
# tick.ludic - a step of everyone, on the machine that runs the place: the census on the half hour,
# the day's end (only ever out of every player's sight), the walk or the act, and who noticed whom
export function npc_tick(npc_st: mut NpcState, dt: float) -> void {
np_ensure(npc_st)
np_ensure()
for i in 0 .. len(npc_st.np_posts) { if npc_st.np_posts[i].active { np_step_post(npc_st, npc_st.np_posts[i], dt) } }
if npc_st.np_hold or npc_st.np_mirror { return }
np_census(npc_st)
@ -15,7 +15,7 @@ export function npc_tick(npc_st: mut NpcState, dt: float) -> void {
# the posts alone: a machine that does not run the place still turns its vendors to whoever comes
export function npc_posts_tick(npc_st: mut NpcState, dt: float) -> void {
np_ensure(npc_st)
np_ensure()
for i in 0 .. len(npc_st.np_posts) { if npc_st.np_posts[i].active { np_step_post(npc_st, npc_st.np_posts[i], dt) } }
}
@ -43,7 +43,7 @@ function np_census(npc_st: mut NpcState) -> void {
function np_is_night(h: float) -> bool { return h >= 21.0 or h < 5.0 }
function np_draw_kind(npc_st: mut NpcState, night: bool) -> int {
function np_draw_kind(npc_st: NpcState, night: bool) -> int {
var total = 0
for k in 0 .. NPCK_COUNT { if np_drawn(k, night) { total += NpcKinds[k].weight } }
if total <= 0 { return -1 }
@ -82,7 +82,7 @@ export function npc_hold(npc_st: mut NpcState, on: bool) -> void { npc_st.np_hol
# everyone gone, as a new trip starts; the posts are the place's and stay
export function npc_reset(npc_st: mut NpcState) -> void {
np_ensure(npc_st)
np_ensure()
for i in 0 .. len(npc_st.np_walkers) { npc_retire(npc_st, npc_st.np_walkers[i]) }
npc_st.np_n = 0
npc_st.np_next_h = 0.0

View file

@ -54,17 +54,16 @@ export state PhotoState {
pht_pending_stars: bool = false
pht_comp: []float = null # size, framing, light, moment of the last subject scored
pht_comp_have: bool = false
pht_fact_q: Queue<PhotoFact> = null
pht_fact_q: Queue<PhotoFact> = pht_fact_q__new()
}
export function photo_facts(photo_st: mut PhotoState) -> Queue<PhotoFact> {
if photo_st.pht_fact_q == null { photo_st.pht_fact_q = queue_new("photo.facts") }
export function photo_facts(photo_st: PhotoState) -> Queue<PhotoFact> {
return photo_st.pht_fact_q
}
function pht_fact(photo_st: mut PhotoState, what: int, i: int) -> PhotoFact {
function pht_fact(photo_st: PhotoState, what: int, i: int) -> PhotoFact {
let f = new PhotoFact
f.what = what
f.index = i
@ -100,3 +99,4 @@ function pht_blank(photo_st: mut PhotoState) -> void {
photo_st.pht_comp = pht_floats(4)
photo_st.pht_comp_have = false
}
function pht_fact_q__new() -> Queue<PhotoFact> { return queue_new("photo.facts") }

View file

@ -56,7 +56,7 @@ program PhotoTest {
photo_test_st.sun_z = 0.0
photo_test_st.behaviour = false
}
function facts(photo_st: mut PhotoState) -> []PhotoFact { return q_drain(photo_facts(photo_st)) }
function facts(photo_st: PhotoState) -> []PhotoFact { return q_drain(photo_facts(photo_st)) }
function count(fs: []PhotoFact, what: int) -> int {
var n = 0
for i in 0 .. len(fs) { if fs[i].what == what { n += 1 } }

View file

@ -66,7 +66,7 @@ export state SessionState {
session__max: int = 4
session__open: bool = true
session__near_i: int = 0
session__facts: Queue<SessionFact> = null
session__facts: Queue<SessionFact> = session__facts__new()
session__vote_id: int = 0
session__vote_kind: int = 0
session__vote_param: int = 0
@ -78,12 +78,11 @@ export state SessionState {
session__vote_passed: int = -1 # the last vote: -1 none, 0 failed, 1 passed
}
export function ses_facts(session_st: mut SessionState) -> Queue<SessionFact> {
if session_st.session__facts == null { session_st.session__facts = queue_new("session.facts") }
export function ses_facts(session_st: SessionState) -> Queue<SessionFact> {
return session_st.session__facts
}
function session__fact(session_st: mut SessionState, what: int, slot: int, pid: int) -> SessionFact {
function session__fact(session_st: SessionState, what: int, slot: int, pid: int) -> SessionFact {
let f = new SessionFact
f.what = what
f.slot = slot
@ -99,3 +98,4 @@ function session__init(session_st: mut SessionState) -> void {
for i in 0 .. PLY_MAX { push(session_st.session__slot, new PartyMember) }
session_st.session__slot[0].on = true
}
function session__facts__new() -> Queue<SessionFact> { return queue_new("session.facts") }

View file

@ -14,14 +14,14 @@ program SessionTest {
function fname() -> string { return "me" }
bind SessionLocal { x: fn fx, y: fn fy, z: fn fz, name: fn fname }
function whats(session_st: mut SessionState) -> []int {
function whats(session_st: SessionState) -> []int {
let fs = q_drain(ses_facts(session_st))
let out = new []int
for i in 0 .. len(fs) { push(out, fs[i].what) }
return out
}
function last_of(session_st: mut SessionState, what: int) -> SessionFact {
function last_of(session_st: SessionState, what: int) -> SessionFact {
let fs = q_drain(ses_facts(session_st))
var f: SessionFact = null
for i in 0 .. len(fs) { if fs[i].what == what { f = fs[i] } }

View file

@ -92,7 +92,7 @@ function session__vote_finish(session_st: mut SessionState) -> void {
f.yes = passed
}
function session__vote_fact(session_st: mut SessionState, what: int) -> SessionFact {
function session__vote_fact(session_st: SessionState, what: int) -> SessionFact {
let f = session__fact(session_st, what, -1, 0)
f.id = session_st.session__vote_id
f.kind = session_st.session__vote_kind

View file

@ -4,7 +4,7 @@ export state SettingsState {
sg_defs: []SettingDef = null
sg_num: []float = null
sg_text: []string = null
sg_changes: Queue<SettingChanged> = null
sg_changes: Queue<SettingChanged> = sg_changes__new()
}
function sg_init(settings_st: mut SettingsState) -> void {
@ -14,8 +14,7 @@ function sg_init(settings_st: mut SettingsState) -> void {
settings_st.sg_text = new []string
}
export function settings_changes(settings_st: mut SettingsState) -> Queue<SettingChanged> {
if settings_st.sg_changes == null { settings_st.sg_changes = queue_new("settings.changes") }
export function settings_changes(settings_st: SettingsState) -> Queue<SettingChanged> {
return settings_st.sg_changes
}
@ -55,7 +54,7 @@ export function settings_get_int(settings_st: SettingsState, id: int) -> int { r
export function settings_get_bool(settings_st: SettingsState, id: int) -> bool { return settings_st.sg_num[id] != 0.0 }
export function settings_get_text(settings_st: SettingsState, id: int) -> string { return settings_st.sg_text[id] }
function sg_changed(settings_st: mut SettingsState, id: int) -> void {
function sg_changed(settings_st: SettingsState, id: int) -> void {
let c = new SettingChanged
c.id = id
c.key = settings_st.sg_defs[id].key
@ -93,3 +92,4 @@ export function settings_held(settings_st: SettingsState, id: int, v: float) ->
if d.hi >= d.lo and (x < d.lo or x > d.hi) { return d.num }
return x
}
function sg_changes__new() -> Queue<SettingChanged> { return queue_new("settings.changes") }

View file

@ -11,7 +11,7 @@ program SettingsTest {
for i in 0 .. TOY_COUNT { settings_add(settings_st, Toy[i]) }
}
function facts(settings_st: mut SettingsState) -> []SettingChanged { return q_drain(settings_changes(settings_st)) }
function facts(settings_st: SettingsState) -> []SettingChanged { return q_drain(settings_changes(settings_st)) }
test "a registry declares the store, each at its default" (settings_st: mut SettingsState) {
declare(settings_st)

View file

@ -49,7 +49,7 @@ export state ShopState {
shop_buy_best: float = 0.92
shop_sell_new: float = 0.62
shop_sell_best: float = 0.85
shop_trade_q: Queue<ShopTrade> = null
shop_trade_q: Queue<ShopTrade> = shop_trade_q__new()
}
# the curve: buying from `buy_new` of base at rep 0 down to `buy_best` at 100; selling the same way
@ -106,7 +106,7 @@ export property ShopTrade {
}
export function shop_trades(shop_st: mut ShopState) -> Queue<ShopTrade> {
if shop_st.shop_trade_q == null { shop_st.shop_trade_q = queue_new("shop.trades") }
export function shop_trades(shop_st: ShopState) -> Queue<ShopTrade> {
return shop_st.shop_trade_q
}
function shop_trade_q__new() -> Queue<ShopTrade> { return queue_new("shop.trades") }

View file

@ -98,7 +98,7 @@ program ShopTest {
shop_reset(shop_st)
}
function trades(shop_st: mut ShopState) -> []ShopTrade { return q_drain(shop_trades(shop_st)) }
function trades(shop_st: ShopState) -> []ShopTrade { return q_drain(shop_trades(shop_st)) }
test "buying takes the price and puts one in the pack, and says so" (shop_st: mut ShopState, shop_test_st: mut ShopTestState) {
fresh(shop_st, shop_test_st)

View file

@ -26,7 +26,7 @@ export function shop_sellable(shop_st: ShopState, v: int) -> []int {
return out
}
function shop_trade_fact(shop_st: mut ShopState, what: int, it: int, n: int, price: int) -> void {
function shop_trade_fact(shop_st: ShopState, what: int, it: int, n: int, price: int) -> void {
let t = new ShopTrade
t.what = what
t.vendor = shop_st.shop_at
@ -41,7 +41,7 @@ export function shop_can_buy(shop_st: ShopState, it: int) -> bool {
}
# one, paid for and in the pack; false and nothing spent when it cannot be
export function shop_buy(shop_st: mut ShopState, it: int) -> bool {
export function shop_buy(shop_st: ShopState, it: int) -> bool {
if not shop_can_buy(shop_st, it) { return false }
let pr = shop_price_buy(shop_st, it)
if not ShopPurse.spend(pr) { return false }

View file

@ -56,15 +56,14 @@ export state StepsState {
steps__need: []int = null
steps__cur: int = 0
steps__done: int = 0
steps__facts: Queue<StepsFact> = null
steps__facts: Queue<StepsFact> = steps__facts__new()
}
export function steps_facts(steps_st: mut StepsState) -> Queue<StepsFact> {
if steps_st.steps__facts == null { steps_st.steps__facts = queue_new("steps.facts") }
export function steps_facts(steps_st: StepsState) -> Queue<StepsFact> {
return steps_st.steps__facts
}
function steps__fact(steps_st: mut StepsState, what: int, ch: int, i: int) -> void {
function steps__fact(steps_st: StepsState, what: int, ch: int, i: int) -> void {
let f = new StepsFact
f.what = what
f.chapter = ch
@ -81,3 +80,4 @@ export function steps_popcount(m: int) -> int {
}
return n
}
function steps__facts__new() -> Queue<StepsFact> { return queue_new("steps.facts") }

View file

@ -63,7 +63,7 @@ program StepsTest {
steps_add(steps_st, K_COMPASS, 0, 1)
}
function facts_of(steps_st: mut StepsState, what: int) -> int {
function facts_of(steps_st: StepsState, what: int) -> int {
let fs = q_drain(steps_facts(steps_st))
var n = 0
for i in 0 .. len(fs) { if fs[i].what == what { n += 1 } }

View file

@ -1,8 +1,7 @@
# ports.ludic - the config, and what the ports answer when the game leaves them unbound
export function telemetry_config(telemetry_st: mut TelemetryState, c: TelemetryConfig) -> void { telemetry_st.telemetry__cfg = c }
function telemetry__conf(telemetry_st: mut TelemetryState) -> TelemetryConfig {
if telemetry_st.telemetry__cfg == null { telemetry_st.telemetry__cfg = new TelemetryConfig }
function telemetry__conf(telemetry_st: TelemetryState) -> TelemetryConfig {
return telemetry_st.telemetry__cfg
}
@ -10,7 +9,7 @@ function telemetry__yes() -> bool { return true }
function telemetry__wall_ms(telemetry_st: TelemetryState) -> int { return (Time.now() - telemetry_st.telemetry__t0) * 1000 }
function telemetry__wall_stamp() -> string { return DateTime.format(Time.now(), "YYYY-MM-DDTHH:mm:ssZ") }
function telemetry__can_send(telemetry_st: mut TelemetryState) -> bool {
function telemetry__can_send(telemetry_st: TelemetryState) -> bool {
let c = telemetry__conf(telemetry_st)
if len(c.host) == 0 or len(c.key) == 0 { return false }
return TelemetryWorld.can_send()
@ -40,7 +39,7 @@ function telemetry__http_poll(h: int) -> int {
function telemetry__http_drop(h: int) -> void { Http.free(h) }
function telemetry__send(telemetry_st: mut TelemetryState, body: string) -> int { return TelemetryTransport.send(telemetry__conf(telemetry_st).host + telemetry__conf(telemetry_st).path, body) }
function telemetry__send(telemetry_st: TelemetryState, body: string) -> int { return TelemetryTransport.send(telemetry__conf(telemetry_st).host + telemetry__conf(telemetry_st).path, body) }
function telemetry__poll(h: int) -> int { return TelemetryTransport.poll(h) }
# a request abandoned (the player said no)

View file

@ -2,7 +2,7 @@
export function telemetry_id(telemetry_st: TelemetryState) -> string { return telemetry_st.telemetry__id }
export function telemetry_session(telemetry_st: TelemetryState) -> string { return telemetry_st.telemetry__session }
export function telemetry_ready(telemetry_st: TelemetryState) -> bool { return telemetry_st.telemetry__ready }
export function telemetry_get_config(telemetry_st: mut TelemetryState) -> TelemetryConfig { return telemetry__conf(telemetry_st) }
export function telemetry_get_config(telemetry_st: TelemetryState) -> TelemetryConfig { return telemetry__conf(telemetry_st) }
export function telemetry_fails(telemetry_st: TelemetryState) -> int { return telemetry_st.telemetry__fails }
export function telemetry_next_ms(telemetry_st: TelemetryState) -> int { return telemetry_st.telemetry__next_ms }
export function telemetry_in_flight(telemetry_st: TelemetryState) -> bool { return telemetry_st.telemetry__h >= 0 }

View file

@ -13,7 +13,7 @@ export function telemetry_start(telemetry_st: mut TelemetryState) -> void {
}
# may an event be kept right now?
export function telemetry_on(telemetry_st: mut TelemetryState) -> bool { return telemetry_st.telemetry__ready and telemetry__enabled() and telemetry__can_send(telemetry_st) }
export function telemetry_on(telemetry_st: TelemetryState) -> bool { return telemetry_st.telemetry__ready and telemetry__enabled() and telemetry__can_send(telemetry_st) }
# an event: the properties (null for none) with the session and the library added, and the player
# as a mark put in when the batch goes, so an event queued before the id is known is not misfiled
@ -77,7 +77,7 @@ function telemetry__queue_drop(telemetry_st: mut TelemetryState, n: int) -> void
}
# the batch: the first n lines joined, with the player id put in - no parsing
export function telemetry_batch_body(telemetry_st: mut TelemetryState, n: int) -> string {
export function telemetry_batch_body(telemetry_st: TelemetryState, n: int) -> string {
let part = new []string
for i in 0 .. n { push(part, telemetry_st.telemetry__q[i]) }
let head = Value.object()

View file

@ -52,7 +52,7 @@ export state TelemetryState {
telemetry__proc_t0: int = 0
telemetry__rand_n: int = 0
telemetry__clock_on: bool = false
telemetry__cfg: TelemetryConfig = null
telemetry__cfg: TelemetryConfig = new TelemetryConfig
telemetry__ready: bool = false
telemetry__id: string = ""
telemetry__session: string = ""
@ -64,15 +64,14 @@ export state TelemetryState {
telemetry__saved_ms: int = 0 # when the queue was last put on disk
telemetry__fails: int = 0 # sends failed in a row
telemetry__t0: int = 0 # the default clock's zero, wall seconds
telemetry__facts: Queue<TelemetryFact> = null
telemetry__facts: Queue<TelemetryFact> = telemetry__facts__new()
}
export function telemetry_facts(telemetry_st: mut TelemetryState) -> Queue<TelemetryFact> {
if telemetry_st.telemetry__facts == null { telemetry_st.telemetry__facts = queue_new("telemetry.facts") }
export function telemetry_facts(telemetry_st: TelemetryState) -> Queue<TelemetryFact> {
return telemetry_st.telemetry__facts
}
function telemetry__fact(telemetry_st: mut TelemetryState, what: int, count: int, status: int, retry: int) -> void {
function telemetry__fact(telemetry_st: TelemetryState, what: int, count: int, status: int, retry: int) -> void {
let f = new TelemetryFact
f.what = what
f.count = count
@ -80,3 +79,4 @@ function telemetry__fact(telemetry_st: mut TelemetryState, what: int, count: int
f.retry_ms = retry
q_push(telemetry_facts(telemetry_st), f)
}
function telemetry__facts__new() -> Queue<TelemetryFact> { return queue_new("telemetry.facts") }

View file

@ -73,7 +73,7 @@ program TelemetryTest {
telemetry_tick(telemetry_st)
}
function facts_of(telemetry_st: mut TelemetryState, what: int) -> int {
function facts_of(telemetry_st: TelemetryState, what: int) -> int {
let fs = q_drain(telemetry_facts(telemetry_st))
var n = 0
for i in 0 .. len(fs) { if fs[i].what == what { n += 1 } }

View file

@ -21,7 +21,7 @@ export function thing_prompt(t: Thing) -> string {
}
# the kind does what using it does; the use is a fact whatever the kind made of it
export function thing_use(things_st: mut ThingsState, t: Thing) -> void {
export function thing_use(things_st: ThingsState, t: Thing) -> void {
if t == null or not thing_kind_ok(t.kind) { return }
let k = ThingKinds[t.kind]
th_fact(things_st, THING_USED, t)
@ -46,7 +46,7 @@ export function thing_is_personal(t: Thing) -> bool { return thing_kind_ok(t.kin
export function thing_is_put_down(t: Thing) -> bool { return ThingsWorld.put_down(t) }
# every active Thing whose kind ticks, `hours` of the world's clock on
export function things_tick(things_st: mut ThingsState, hours: float) -> void {
export function things_tick(things_st: ThingsState, hours: float) -> void {
let all = things_all(things_st)
for i in 0 .. len(all) {
let t = all[i]
@ -58,7 +58,7 @@ export function things_tick(things_st: mut ThingsState, hours: float) -> void {
# a restock: every Thing the world grew is back, and loses its `used` unless its kind keeps it;
# what was put down is left as it is
export function things_restock(things_st: mut ThingsState) -> void {
export function things_restock(things_st: ThingsState) -> void {
let all = things_all(things_st)
for i in 0 .. len(all) {
let t = all[i]

View file

@ -3,7 +3,7 @@
function th_of(t: Thing, kind: int) -> bool { return kind < 0 or t.kind == kind }
# the first active one of a kind (and of that id, unless id < 0), in the order placed
export function thing_find(things_st: mut ThingsState, kind: int, id: int) -> Thing {
export function thing_find(things_st: ThingsState, kind: int, id: int) -> Thing {
let all = things_all(things_st)
for i in 0 .. len(all) {
let t = all[i]
@ -12,14 +12,14 @@ export function thing_find(things_st: mut ThingsState, kind: int, id: int) -> Th
return null
}
export function thing_by_uid(things_st: mut ThingsState, uid: int) -> Thing {
export function thing_by_uid(things_st: ThingsState, uid: int) -> Thing {
let all = things_all(things_st)
for i in 0 .. len(all) { if all[i].uid == uid { return all[i] } }
return null
}
# the nearest active one of a kind to (x, z), or null
export function thing_nearest(things_st: mut ThingsState, kind: int, x: float, z: float) -> Thing {
export function thing_nearest(things_st: ThingsState, kind: int, x: float, z: float) -> Thing {
var best: Thing = null
var bd = 0.0
let all = things_all(things_st)
@ -43,7 +43,7 @@ export function thing_dist2(t: Thing, x: float, z: float) -> float {
}
# every active one within r of (x, z), nearest first
export function things_within(things_st: mut ThingsState, x: float, z: float, r: float) -> []Thing {
export function things_within(things_st: ThingsState, x: float, z: float, r: float) -> []Thing {
let out = new []Thing
let all = things_all(things_st)
for i in 0 .. len(all) {
@ -64,7 +64,7 @@ function th_insert(out: []Thing, t: Thing, x: float, z: float) -> void {
}
# every active one of a kind, in the order placed
export function things_each(things_st: mut ThingsState, kind: int) -> []Thing {
export function things_each(things_st: ThingsState, kind: int) -> []Thing {
let out = new []Thing
let all = things_all(things_st)
for i in 0 .. len(all) { if all[i].active and th_of(all[i], kind) { push(out, all[i]) } }
@ -72,7 +72,7 @@ export function things_each(things_st: mut ThingsState, kind: int) -> []Thing {
}
# every one of a kind, active or not
export function things_each_all(things_st: mut ThingsState, kind: int) -> []Thing {
export function things_each_all(things_st: ThingsState, kind: int) -> []Thing {
let out = new []Thing
let all = things_all(things_st)
for i in 0 .. len(all) { if th_of(all[i], kind) { push(out, all[i]) } }

View file

@ -1,18 +1,17 @@
# store.ludic - the Things, and the only verbs that make, remove, move, show and hide one; each
# placing and removing is a fact, and the port is told at once so the game can draw it
export state ThingsState {
th_list: []Thing = null
th_list: []Thing = new []Thing
th_uid: int = 0
th_facts: Queue<ThingFact> = null
th_facts: Queue<ThingFact> = th_facts__new()
th_marked: int = -1
}
export function things_facts(things_st: mut ThingsState) -> Queue<ThingFact> {
if things_st.th_facts == null { things_st.th_facts = queue_new("things.facts") }
export function things_facts(things_st: ThingsState) -> Queue<ThingFact> {
return things_st.th_facts
}
function th_fact(things_st: mut ThingsState, what: int, t: Thing) -> void {
function th_fact(things_st: ThingsState, what: int, t: Thing) -> void {
let f = new ThingFact
f.what = what
f.uid = t.uid
@ -28,12 +27,11 @@ function th_fact(things_st: mut ThingsState, what: int, t: Thing) -> void {
export function things_ready(things_st: ThingsState) -> bool { return things_st.th_list != null }
# every Thing, in the order placed; the list is the package's, never to be pushed to
export function things_all(things_st: mut ThingsState) -> []Thing {
if things_st.th_list == null { things_st.th_list = new []Thing }
export function things_all(things_st: ThingsState) -> []Thing {
return things_st.th_list
}
export function things_count(things_st: mut ThingsState) -> int { return len(things_all(things_st)) }
export function things_count(things_st: ThingsState) -> int { return len(things_all(things_st)) }
# a new world: every Thing forgotten, quietly (the game has already dropped its drawings)
export function things_clear(things_st: mut ThingsState) -> void { things_st.th_list = new []Thing }
@ -110,3 +108,4 @@ export function thing_set_active(t: Thing, on: bool) -> void {
}
export function thing_hide(t: Thing) -> void { thing_set_active(t, false) }
export function thing_show(t: Thing) -> void { thing_set_active(t, true) }
function th_facts__new() -> Queue<ThingFact> { return queue_new("things.facts") }

View file

@ -1,6 +1,6 @@
# system.ludic - the things as a system: its save section carries every active Thing the port
# keeps, by its kind's KEY (so the game may reorder its kinds), and a load puts each back
export function things_save(things_st: mut ThingsState) -> Val {
export function things_save(things_st: ThingsState) -> Val {
let l = Value.list()
let all = things_all(things_st)
for i in 0 .. len(all) {

View file

@ -45,7 +45,7 @@ program ThingsTest {
bind ThingsWorld { ground: fn hill, placed: fn on_placed, removed: fn on_removed, shown: fn on_shown, restored: fn on_restored }
function put(things_st: mut ThingsState, kind: int, x: float, z: float) -> Thing { return thing_spawn(things_st, kind, "m", x, 0.0, z, 0.0, 0) }
function facts(things_st: mut ThingsState) -> []ThingFact { return q_drain(things_facts(things_st)) }
function facts(things_st: ThingsState) -> []ThingFact { return q_drain(things_facts(things_st)) }
test "a spawn is drawn, numbered and said" (things_st: mut ThingsState, things_test_st: ThingsTestState) {
things_clear(things_st)

View file

@ -59,12 +59,12 @@ export state TracksState {
tk_read_n: int = 0 # signs read for the first time, of every source
tk_yaw: float = 0.0 # the heading of the last sign read
tk_has_yaw: bool = false
tk_reads: Queue<TrackRead> = null
tk_reads: Queue<TrackRead> = tk_reads__new()
}
# the facts: every sign read, oldest first
export function tracks_reads(tracks_st: mut TracksState) -> Queue<TrackRead> {
if tracks_st.tk_reads == null { tracks_st.tk_reads = queue_new("tracks.reads") }
export function tracks_reads(tracks_st: TracksState) -> Queue<TrackRead> {
return tracks_st.tk_reads
}
function tk_reads__new() -> Queue<TrackRead> { return queue_new("tracks.reads") }

View file

@ -35,7 +35,7 @@ program TracksTest {
tracks_reset(tracks_st)
}
function reads(tracks_st: mut TracksState) -> []TrackRead { return q_drain(tracks_reads(tracks_st)) }
function reads(tracks_st: TracksState) -> []TrackRead { return q_drain(tracks_reads(tracks_st)) }
test "a print goes into its kind's ring and is drawn" (tracks_st: mut TracksState, tracks_test_st: mut TracksTestState) {
fresh(tracks_st, tracks_test_st)

View file

@ -51,7 +51,7 @@ export state UiState {
ca_bare: bool = false
cs_pass: int = 0
ua_sh: UiSheet = null
uc_list: []UiClass = null # filled by the compiler's registrations, before the program's globals
uc_list: []UiClass = new []UiClass # filled by the compiler's registrations, before the program's globals
cl_alpha: float = 1.0
ct_capture: string = ""
ct_capture_at: int = -1 # the frame listening began, whose own key started it

View file

@ -17,7 +17,6 @@ export property UiClass {
seen_lss: string = ""
}
export function ui_register(ui_st: mut UiState, k: UiClass) -> int {
if ui_st.uc_list == null { ui_st.uc_list = new []UiClass }
push(ui_st.uc_list, k)
return len(ui_st.uc_list)
}

View file

@ -46,4 +46,4 @@ export function update_plan_version(update_st: UpdateState, i: int) -> string {
export function update_target(update_st: UpdateState) -> string { return update_st.update__target }
export function update_total_bytes(update_st: UpdateState) -> int { return update_st.update__total_bytes }
function update__path(update_st: mut UpdateState, i: int) -> string { return update_packages(update_st) + update__sep() + update_st.update__files[i] }
function update__path(update_st: UpdateState, i: int) -> string { return update_packages(update_st) + update__sep() + update_st.update__files[i] }

View file

@ -44,7 +44,7 @@ function update__up(p: string) -> string {
# the executable's directory
export function update_dir() -> string { return update__up(UpdateWorld.exe()) }
export function update_root(update_st: mut UpdateState) -> string {
export function update_root(update_st: UpdateState) -> string {
let c = update__conf(update_st)
if len(c.root) > 0 { return c.root }
if update__mac() { return update__up(update__up(update_dir())) }
@ -52,7 +52,7 @@ export function update_root(update_st: mut UpdateState) -> string {
}
# where the packages live: never inside a macOS bundle, which is read-only and which apply replaces
export function update_packages(update_st: mut UpdateState) -> string {
export function update_packages(update_st: UpdateState) -> string {
let c = update__conf(update_st)
if len(c.packages) > 0 { return c.packages }
if update__mac() and len(c.mac_packages) > 0 { return c.mac_packages }
@ -64,7 +64,7 @@ function update__feed_file() -> string {
return "releases.win.json"
}
function update__updater(update_st: mut UpdateState) -> string {
function update__updater(update_st: UpdateState) -> string {
if update__mac() { return update_root(update_st) + "/Contents/MacOS/UpdateMac" }
return update_root(update_st) + update__sep() + "Update.exe"
}
@ -76,7 +76,7 @@ export function update_translocated() -> bool {
}
# can this copy update itself? A copy Velopack did not install downloads the game again instead.
export function update_installed(update_st: mut UpdateState) -> bool {
export function update_installed(update_st: UpdateState) -> bool {
if len(update__conf(update_st).root) > 0 { return true }
if update_translocated() { return false }
if update__mac() { return Fs.exists(update_dir() + "/UpdateMac") }

View file

@ -10,7 +10,7 @@ property UpdateAsset {
}
# this app's packages in the feed ({"Assets": [{PackageId, Version, Type, FileName, SHA256, Size}]})
function update__assets(update_st: mut UpdateState, feed: Val) -> []UpdateAsset {
function update__assets(update_st: UpdateState, feed: Val) -> []UpdateAsset {
let out = new []UpdateAsset
if feed == null or Value.kind(feed) != 6 or Value.has(feed, "Assets") == 0 { return out }
let all = Value.get(feed, "Assets")
@ -31,7 +31,7 @@ function update__assets(update_st: mut UpdateState, feed: Val) -> []UpdateAsset
# What the feed calls the FULL package of version v. Never built here: Velopack puts the channel in
# a macOS name (App-0.3.4-osx-full.nupkg) and not a Windows one, and it is both the name a patch
# writes and the name the next update looks for as its base.
function update__full_name(update_st: mut UpdateState, as: []UpdateAsset, v: string) -> string {
function update__full_name(update_st: UpdateState, as: []UpdateAsset, v: string) -> string {
for i in 0 .. len(as) { if not as[i].delta and as[i].ver == v { return as[i].file } }
return update__conf(update_st).app_id + "-" + v + "-full.nupkg"
}
@ -46,7 +46,7 @@ function update__newest_full(as: []UpdateAsset) -> int {
}
# the deltas above this version up to the newest, oldest first
function update__chain(update_st: mut UpdateState, as: []UpdateAsset, newest: string) -> []UpdateAsset {
function update__chain(update_st: UpdateState, as: []UpdateAsset, newest: string) -> []UpdateAsset {
let out = new []UpdateAsset
let mine = update__conf(update_st).version
for i in 0 .. len(as) {
@ -65,7 +65,7 @@ function update__chain(update_st: mut UpdateState, as: []UpdateAsset, newest: st
return out
}
function update__fulls_after(update_st: mut UpdateState, as: []UpdateAsset) -> int {
function update__fulls_after(update_st: UpdateState, as: []UpdateAsset) -> int {
var n = 0
for i in 0 .. len(as) { if not as[i].delta and update_newer(as[i].ver, update__conf(update_st).version) { n += 1 } }
return n

View file

@ -56,7 +56,7 @@ export state UpdateState {
update__ask_h: int = -1
update__latest: string = ""
update__notes: Val = null
update__cfg: UpdateConfig = null
update__cfg: UpdateConfig = new UpdateConfig
update__state: int = 0
update__err: int = 0
update__h: int = -1 # the request
@ -77,22 +77,20 @@ export state UpdateState {
update__rate: int = 0 # bytes a second, eased
update__rate_t: int = -1
update__rate_bytes: int = 0
update__facts: Queue<UpdateFact> = null
update__facts: Queue<UpdateFact> = update__facts__new()
}
export function update_config(update_st: mut UpdateState, c: UpdateConfig) -> void { update_st.update__cfg = c }
function update__conf(update_st: mut UpdateState) -> UpdateConfig {
if update_st.update__cfg == null { update_st.update__cfg = new UpdateConfig }
function update__conf(update_st: UpdateState) -> UpdateConfig {
return update_st.update__cfg
}
export function update_facts(update_st: mut UpdateState) -> Queue<UpdateFact> {
if update_st.update__facts == null { update_st.update__facts = queue_new("update.facts") }
export function update_facts(update_st: UpdateState) -> Queue<UpdateFact> {
return update_st.update__facts
}
function update__fact(update_st: mut UpdateState, what: int) -> void {
function update__fact(update_st: UpdateState, what: int) -> void {
let f = new UpdateFact
f.what = what
f.error = update_st.update__err
@ -101,3 +99,4 @@ function update__fact(update_st: mut UpdateState, what: int) -> void {
f.bytes = update_st.update__total_bytes
q_push(update_facts(update_st), f)
}
function update__facts__new() -> Queue<UpdateFact> { return queue_new("update.facts") }

View file

@ -50,7 +50,7 @@ function update__fetch(update_st: mut UpdateState, i: int) -> void {
update_st.update__state = UPDATE_FETCH
}
function update__hash_file(update_st: mut UpdateState) -> string {
function update__hash_file(update_st: UpdateState) -> string {
if len(update__conf(update_st).scratch) > 0 { return update__conf(update_st).scratch }
return Os.temp_dir() + "/ludic-update-hash.txt"
}
@ -80,7 +80,7 @@ function update__check(update_st: mut UpdateState, i: int) -> void {
}
# the hash the child wrote: the first line with anything on it
function update__hash_read(update_st: mut UpdateState) -> string {
function update__hash_read(update_st: UpdateState) -> string {
let s = Fs.read_text(update__hash_file(update_st))
if s == null { return "" }
let lines = Text.split(s, "\n")

View file

@ -89,7 +89,7 @@ program UpdateTest {
function seed_base() -> void { Fs.write_text(pkgs() + "/Game-1.0.0-osx-full.nupkg", "base") }
function plan_of(update_st: mut UpdateState, text: string) -> bool { return update_plan(update_st, Json.parse(text)) }
function facts_of(update_st: mut UpdateState, what: int) -> int {
function facts_of(update_st: UpdateState, what: int) -> int {
let fs = q_drain(update_facts(update_st))
var n = 0
for i in 0 .. len(fs) { if fs[i].what == what { n += 1 } }

View file

@ -5,8 +5,8 @@ import "ludic.base"
program WalletTest {
numbers float
function changes(wallet_st: mut WalletState) -> []MoneyChanged { return q_drain(wallet_changes(wallet_st)) }
function waiting(wallet_st: mut WalletState) -> int { return q_len(wallet_changes(wallet_st)) }
function changes(wallet_st: WalletState) -> []MoneyChanged { return q_drain(wallet_changes(wallet_st)) }
function waiting(wallet_st: WalletState) -> int { return q_len(wallet_changes(wallet_st)) }
test "earning and spending move the purse, and each says so" (wallet_st: mut WalletState) {
wallet_reset(wallet_st)

View file

@ -6,11 +6,10 @@ export property MoneyChanged {
export state WalletState {
wl_money: int = 0
wl_changes: Queue<MoneyChanged> = null
wl_changes: Queue<MoneyChanged> = wl_changes__new()
}
export function wallet_changes(wallet_st: mut WalletState) -> Queue<MoneyChanged> {
if wallet_st.wl_changes == null { wallet_st.wl_changes = queue_new("wallet.changes") }
export function wallet_changes(wallet_st: WalletState) -> Queue<MoneyChanged> {
return wallet_st.wl_changes
}
@ -62,3 +61,4 @@ export function wallet_system() -> System {
s.load = fn wallet_load
return s
}
function wl_changes__new() -> Queue<MoneyChanged> { return queue_new("wallet.changes") }

View file

@ -74,19 +74,19 @@ export state WeatherState {
wx_wet_today: bool = false
wx_wet_yesterday: bool = false
wx_dice: Rng = null
wx_facts: Queue<WeatherFact> = null
wx_facts: Queue<WeatherFact> = wx_facts__new()
}
# the facts, oldest first; the game drains them into its notices and sounds
export function weather_facts(weather_st: mut WeatherState) -> Queue<WeatherFact> {
if weather_st.wx_facts == null { weather_st.wx_facts = queue_new("weather.facts") }
export function weather_facts(weather_st: WeatherState) -> Queue<WeatherFact> {
return weather_st.wx_facts
}
function wx_fact(weather_st: mut WeatherState, what: int, kind: int, from: int) -> void {
function wx_fact(weather_st: WeatherState, what: int, kind: int, from: int) -> void {
let f = new WeatherFact
f.what = what
f.kind = kind
f.from = from
q_push(weather_facts(weather_st), f)
}
function wx_facts__new() -> Queue<WeatherFact> { return queue_new("weather.facts") }

View file

@ -73,7 +73,7 @@ program WeatherTest {
weather_reset(weather_st)
}
function facts(weather_st: mut WeatherState) -> []WeatherFact { return q_drain(weather_facts(weather_st)) }
function facts(weather_st: WeatherState) -> []WeatherFact { return q_drain(weather_facts(weather_st)) }
function step(weather_st: mut WeatherState, dt: float, gh: float, n: int) -> void { for i in 0 .. n { weather_run(weather_st, dt, gh) } }
function count(fs: []WeatherFact, what: int) -> int {
var n = 0

View file

@ -42,7 +42,7 @@ function wl_come_down(a: WildAnimal, x: float, z: float) -> void {
}
# a circle about home, climbing to its height: the eagle wide and high, the jay low
function wl_circle(wildlife_st: mut WildlifeState, a: WildAnimal, dt: float) -> void {
function wl_circle(wildlife_st: WildlifeState, a: WildAnimal, dt: float) -> void {
let s = wl_sp(wildlife_st, a.sp)
a.fly_h = a.fly_h + (8.0 + s.home * 0.12 - a.fly_h) * Math.min(1.0, 0.4 * dt)
let r = s.home * 0.5
@ -57,13 +57,13 @@ function wl_circle(wildlife_st: mut WildlifeState, a: WildAnimal, dt: float) ->
a.bank = 0.35
}
function wl_take_off(wildlife_st: mut WildlifeState, a: WildAnimal, h: float) -> void {
function wl_take_off(wildlife_st: WildlifeState, a: WildAnimal, h: float) -> void {
a.state = WILD_FLY
a.timer = 20.0 + wl_rnd(wildlife_st) * 40.0
a.fly_h = Math.max(a.fly_h, h)
}
function wl_land(wildlife_st: mut WildlifeState, a: WildAnimal, dh: float, dt: float) -> void {
function wl_land(wildlife_st: WildlifeState, a: WildAnimal, dh: float, dt: float) -> void {
let s = wl_sp(wildlife_st, a.sp)
a.fly_h = Math.max(0.0, a.fly_h - dt * 3.2)
a.speed = s.walk * 0.8
@ -84,7 +84,7 @@ function wl_land(wildlife_st: mut WildlifeState, a: WildAnimal, dh: float, dt: f
}
# on the ground it pecks at seed or takes a drink at the water's edge; it leaves no droppings
function wl_perch(wildlife_st: mut WildlifeState, a: WildAnimal, dh: float, dt: float) -> void {
function wl_perch(wildlife_st: WildlifeState, a: WildAnimal, dh: float, dt: float) -> void {
a.speed = 0.0
a.y = WildlifeWorld.ground(a.x, a.z)
a.bank = 0.0

View file

@ -28,12 +28,11 @@ export property WildFact {
}
export function wildlife_facts(wildlife_st: mut WildlifeState) -> Queue<WildFact> {
if wildlife_st.wl_facts == null { wildlife_st.wl_facts = queue_new("wildlife.facts") }
export function wildlife_facts(wildlife_st: WildlifeState) -> Queue<WildFact> {
return wildlife_st.wl_facts
}
function wl_fact(wildlife_st: mut WildlifeState, what: int, a: WildAnimal) -> WildFact {
function wl_fact(wildlife_st: WildlifeState, what: int, a: WildAnimal) -> WildFact {
let f = new WildFact
f.what = what
f.key = a.key

View file

@ -41,7 +41,7 @@ export function wildlife_tick_ground(wildlife_st: mut WildlifeState, a: WildAnim
}
# a charger close enough comes at the nearest player; true while it is charging
function wl_charge(wildlife_st: mut WildlifeState, a: WildAnimal, np: int, dh: float, dt: float) -> bool {
function wl_charge(wildlife_st: WildlifeState, a: WildAnimal, np: int, dh: float, dt: float) -> bool {
let s = wl_sp(wildlife_st, a.sp)
if s.charges and a.state != WILD_CHARGE and dh < WildlifeWorld.charge_reach() and not (a.calm > 0.0) {
a.state = WILD_CHARGE
@ -63,7 +63,7 @@ function wl_charge(wildlife_st: mut WildlifeState, a: WildAnimal, np: int, dh: f
# Four postures read off the alert. Staring is a REACTION, not a condition: each times out and
# hands the animal back to its business, and only a fresh rise above `seen` looks up again.
function wl_posture(wildlife_st: mut WildlifeState, a: WildAnimal, np: int, dt: float) -> void {
function wl_posture(wildlife_st: WildlifeState, a: WildAnimal, np: int, dt: float) -> void {
if wl_sp(wildlife_st, a.sp).tame or a.state == WILD_EAT { return }
if a.alert > 95.0 {
if a.state != WILD_FLEE {

View file

@ -1,9 +1,7 @@
# lures.ludic - what an animal would walk to: food of its diet, a lure of its diet, a snare it is
# small enough for (half the time: a curiosity), within 70 m - 175 m for food while feeding is taught
function wl_lure_scratch(wildlife_st: mut WildlifeState) -> void {
if wildlife_st.wl_ask == null { wildlife_st.wl_ask = new WildLure }
if wildlife_st.wl_best == null { wildlife_st.wl_best = new WildLure }
function wl_lure_scratch() -> void {
}
function wl_copy_lure(from: WildLure, to: WildLure) -> void {
@ -16,15 +14,15 @@ function wl_copy_lure(from: WildLure, to: WildLure) -> void {
to.owner = from.owner
}
function wl_draws(wildlife_st: mut WildlifeState, a: WildAnimal, l: WildLure) -> bool {
function wl_draws(wildlife_st: WildlifeState, a: WildAnimal, l: WildLure) -> bool {
let s = wl_sp(wildlife_st, a.sp)
if l.kind == WILD_SNARE { return s.size <= l.size and wl_rnd(wildlife_st) > 0.5 }
return l.diet == s.diet and l.diet != WILD_SEED
}
# the nearest thing set out that draws it, into `wl_best`; false when none does
function wl_attraction(wildlife_st: mut WildlifeState, a: WildAnimal) -> bool {
wl_lure_scratch(wildlife_st)
function wl_attraction(wildlife_st: WildlifeState, a: WildAnimal) -> bool {
wl_lure_scratch()
var bd = 70.0
var got = false
let taught = WildlifeWorld.taught()
@ -58,7 +56,7 @@ function wl_seed_scan(wildlife_st: mut WildlifeState, dt: float) -> void {
if wildlife_st.wl_seed_t > 0.0 { return }
wildlife_st.wl_seed_t = 1.0
wildlife_st.wl_seed_any = false
wl_lure_scratch(wildlife_st)
wl_lure_scratch()
for i in 0 .. WildlifeWorld.lures() {
if WildlifeWorld.lure(i, wildlife_st.wl_ask) and wildlife_st.wl_ask.kind == WILD_FEED and wildlife_st.wl_ask.diet == WILD_SEED {
wildlife_st.wl_seed_any = true
@ -68,9 +66,9 @@ function wl_seed_scan(wildlife_st: mut WildlifeState, dt: float) -> void {
}
# the nearest seed within 120 m, into `wl_best`: the one thing that brings an animal TO you
function wl_bird_seed(wildlife_st: mut WildlifeState, a: WildAnimal) -> bool {
function wl_bird_seed(wildlife_st: WildlifeState, a: WildAnimal) -> bool {
if not wildlife_st.wl_seed_any { return false }
wl_lure_scratch(wildlife_st)
wl_lure_scratch()
var bd = 120.0
var got = false
for i in 0 .. WildlifeWorld.lures() {
@ -88,7 +86,7 @@ function wl_bird_seed(wildlife_st: mut WildlifeState, a: WildAnimal) -> bool {
}
# it ate what was set out: calm for three game hours, and the game credits whoever left it
function wl_ate(wildlife_st: mut WildlifeState, a: WildAnimal, uid: int, owner: int, diet: int) -> void {
function wl_ate(wildlife_st: WildlifeState, a: WildAnimal, uid: int, owner: int, diet: int) -> void {
a.calm = 180.0
a.fed += 1
let f = wl_fact(wildlife_st, WILD_FED, a)

View file

@ -1,6 +1,6 @@
# migrate.ludic - each morning the ranges slide toward where the season wants them, and the animals
# that live in them are dragged along rather than teleported; an animal keeps inside its own
export function wildlife_ranges_migrate(wildlife_st: mut WildlifeState) -> void {
export function wildlife_ranges_migrate(wildlife_st: WildlifeState) -> void {
let rs = wildlife_ranges(wildlife_st)
let w = WildlifeWorld.winterness()
for i in 0 .. len(rs) {
@ -24,7 +24,7 @@ export function wildlife_ranges_migrate(wildlife_st: mut WildlifeState) -> void
}
# its home kept inside its range
function wl_clamp(wildlife_st: mut WildlifeState, a: WildAnimal) -> void {
function wl_clamp(wildlife_st: WildlifeState, a: WildAnimal) -> void {
let r = wildlife_range(wildlife_st, a.rg)
if r == null { return }
let d = wildlife_range_dist(r, a.home_x, a.home_z)
@ -34,7 +34,7 @@ function wl_clamp(wildlife_st: mut WildlifeState, a: WildAnimal) -> void {
}
# how many live in range `i`, legends apart
export function wildlife_range_alive(wildlife_st: mut WildlifeState, i: int) -> int {
export function wildlife_range_alive(wildlife_st: WildlifeState, i: int) -> int {
var n = 0
let all = wildlife_all(wildlife_st)
for k in 0 .. len(all) { if all[k].alive and not all[k].legend and all[k].rg == i { n += 1 } }
@ -42,7 +42,7 @@ export function wildlife_range_alive(wildlife_st: mut WildlifeState, i: int) ->
}
# how many are alive in the whole valley, legends apart
export function wildlife_total(wildlife_st: mut WildlifeState) -> int {
export function wildlife_total(wildlife_st: WildlifeState) -> int {
var n = 0
let all = wildlife_all(wildlife_st)
for k in 0 .. len(all) { if all[k].alive and not all[k].legend { n += 1 } }
@ -50,7 +50,7 @@ export function wildlife_total(wildlife_st: mut WildlifeState) -> int {
}
# the nearest range of `sp` a player has found, to (x, z), or -1
export function wildlife_range_found_near(wildlife_st: mut WildlifeState, sp: int, x: float, z: float) -> int {
export function wildlife_range_found_near(wildlife_st: WildlifeState, sp: int, x: float, z: float) -> int {
var best = -1
var bd = 99999.0
let rs = wildlife_ranges(wildlife_st)

View file

@ -1,12 +1,11 @@
# ranges.ludic - a species keeps to discs placed once, against the ground, 120-700 m out from where
# the valley starts; each winters lower, toward the timber, as far down as it summered high
export function wildlife_ranges(wildlife_st: mut WildlifeState) -> []WildRange {
if wildlife_st.wl_ranges == null { wildlife_st.wl_ranges = new []WildRange }
export function wildlife_ranges(wildlife_st: WildlifeState) -> []WildRange {
return wildlife_st.wl_ranges
}
export function wildlife_range(wildlife_st: mut WildlifeState, i: int) -> WildRange {
export function wildlife_range(wildlife_st: WildlifeState, i: int) -> WildRange {
if i < 0 or i >= len(wildlife_ranges(wildlife_st)) { return null }
return wildlife_ranges(wildlife_st)[i]
}
@ -17,7 +16,7 @@ export function wildlife_range_dist(r: WildRange, x: float, z: float) -> float {
return Math.sqrt(dx * dx + dz * dz)
}
function wl_range_clashes(wildlife_st: mut WildlifeState, sp: int, x: float, z: float) -> bool {
function wl_range_clashes(wildlife_st: WildlifeState, sp: int, x: float, z: float) -> bool {
let rs = wildlife_ranges(wildlife_st)
for j in 0 .. len(rs) { if rs[j].sp == sp and wildlife_range_dist(rs[j], x, z) < wl_sp(wildlife_st, sp).range * 1.6 { return true } }
return false
@ -83,12 +82,12 @@ function wl_pick_winter(r: WildRange) -> void {
}
# a player stood at (x, z): any range they are inside is found
export function wildlife_ranges_visit(wildlife_st: mut WildlifeState, x: float, z: float) -> void {
export function wildlife_ranges_visit(wildlife_st: WildlifeState, x: float, z: float) -> void {
let rs = wildlife_ranges(wildlife_st)
for i in 0 .. len(rs) { if not rs[i].found and wildlife_range_dist(rs[i], x, z) < rs[i].r { rs[i].found = true } }
}
function wl_found_apply(wildlife_st: mut WildlifeState) -> void {
function wl_found_apply(wildlife_st: WildlifeState) -> void {
if wildlife_st.wl_found == null { return }
let rs = wildlife_ranges(wildlife_st)
for i in 0 .. len(rs) { if i < len(wildlife_st.wl_found) { rs[i].found = wildlife_st.wl_found[i] != 0 } }

View file

@ -1,6 +1,6 @@
# react.ludic - alert (it stops and looks: the window the camera wants), wary (it puts ground between
# you without running) and fleeing; true when it is doing one of them, which is all it does this tick
function wl_react(wildlife_st: mut WildlifeState, a: WildAnimal, np: int, dt: float) -> bool {
function wl_react(wildlife_st: WildlifeState, a: WildAnimal, np: int, dt: float) -> bool {
let s = wl_sp(wildlife_st, a.sp)
if a.state == WILD_ALERT {
a.speed = 0.0
@ -29,7 +29,7 @@ function wl_react(wildlife_st: mut WildlifeState, a: WildAnimal, np: int, dt: fl
}
# walking to (or reached) something set out; true while it is
function wl_approach(wildlife_st: mut WildlifeState, a: WildAnimal, dt: float) -> bool {
function wl_approach(wildlife_st: WildlifeState, a: WildAnimal, dt: float) -> bool {
if (a.state == WILD_IDLE or a.state == WILD_WANDER) and wl_attraction(wildlife_st, a) { wl_take_lure(wildlife_st, a) }
if a.state != WILD_APPROACH { return false }
if a.lure == 0 or not WildlifeWorld.present(a.lure) {
@ -52,7 +52,7 @@ function wl_approach(wildlife_st: mut WildlifeState, a: WildAnimal, dt: float) -
}
# at a snare it is held; at food it eats for 14 s; at a lure it stands curious for 9
function wl_arrive(wildlife_st: mut WildlifeState, a: WildAnimal) -> void {
function wl_arrive(wildlife_st: WildlifeState, a: WildAnimal) -> void {
a.state = WILD_EAT
a.timer = 9.0
if a.lure_kind == WILD_FEED { a.timer = 14.0 }
@ -67,7 +67,7 @@ function wl_arrive(wildlife_st: mut WildlifeState, a: WildAnimal) -> void {
}
# eating what it came to; when it is done, food is credited and it wanders off
function wl_eat(wildlife_st: mut WildlifeState, a: WildAnimal) -> bool {
function wl_eat(wildlife_st: WildlifeState, a: WildAnimal) -> bool {
if a.state != WILD_EAT { return false }
a.speed = 0.0
if a.timer < 0.0 {

View file

@ -32,7 +32,7 @@ function wl_tick_one(wildlife_st: mut WildlifeState, a: WildAnimal, dt: float, g
}
# the gait advanced by a copy the game moves itself (a guest's copy of the host's animal)
export function wildlife_stride(wildlife_st: mut WildlifeState, a: WildAnimal, dt: float) -> void {
export function wildlife_stride(wildlife_st: WildlifeState, a: WildAnimal, dt: float) -> void {
var stride = 1.2 * a.scale
if wl_sp(wildlife_st, a.sp).flies { stride = 0.6 }
a.phase = (a.phase + a.speed * dt / stride * WL_TAU) % WL_TAU
@ -48,7 +48,7 @@ export function wildlife_release(a: WildAnimal) -> void {
}
# the animal a snare holds, by the snare's uid
export function wildlife_in_snare(wildlife_st: mut WildlifeState, uid: int) -> WildAnimal {
export function wildlife_in_snare(wildlife_st: WildlifeState, uid: int) -> WildAnimal {
let all = wildlife_all(wildlife_st)
for i in 0 .. len(all) {
let a = all[i]

View file

@ -46,7 +46,7 @@ function wl_near_sq(d: float, reach: float) -> float {
}
# alert points a second from player p at `dh` metres; 0 when nothing of them reaches it
export function wildlife_alert_rate(wildlife_st: mut WildlifeState, a: WildAnimal, p: int, dh: float) -> float {
export function wildlife_alert_rate(wildlife_st: WildlifeState, a: WildAnimal, p: int, dh: float) -> float {
let s = wl_sp(wildlife_st, a.sp)
if s.tame or a.calm > 0.0 { return 0.0 }
if (a.state == WILD_APPROACH or a.state == WILD_EAT) and a.lure != 0 and a.lure_kind == WILD_FEED and dh > 5.0 and WildlifeWorld.taught() { return 0.0 }
@ -65,7 +65,7 @@ export function wildlife_alert_rate(wildlife_st: mut WildlifeState, a: WildAnima
}
# how fast it forgets player p: standing still buys it, sitting down buys more
export function wildlife_alert_decay(wildlife_st: mut WildlifeState, a: WildAnimal, p: int) -> float {
export function wildlife_alert_decay(wildlife_st: WildlifeState, a: WildAnimal, p: int) -> float {
var d = wl_sp(wildlife_st, a.sp).forget
let still = WildlifeWorld.stillness(p)
if still == WILD_SITTING { d = d * 2.5 } else if still == WILD_STILL { d = d * 1.6 }
@ -74,7 +74,7 @@ export function wildlife_alert_decay(wildlife_st: mut WildlifeState, a: WildAnim
}
# the alert rises and falls with the player who nets it the most, and it watches them
function wl_alert(wildlife_st: mut WildlifeState, a: WildAnimal, np: int, dh: float, dt: float) -> void {
function wl_alert(wildlife_st: WildlifeState, a: WildAnimal, np: int, dh: float, dt: float) -> void {
var rise = wildlife_alert_rate(wildlife_st, a, np, dh)
var fall = wildlife_alert_decay(wildlife_st, a, np)
var who = np

View file

@ -33,47 +33,47 @@ export property WildSpecies {
}
export state WildlifeState {
wl_facts: Queue<WildFact> = null
wl_facts: Queue<WildFact> = wl_facts__new()
wl_own: []WildAnimal = null
wl_px: float = 0.0
wl_pz: float = 0.0
wl_ask: WildLure = null
wl_best: WildLure = null
wl_ask: WildLure = new WildLure
wl_best: WildLure = new WildLure
wl_seed_any: bool = false
wl_seed_t: float = 0.0
wl_ids: int = 0
wl_ranges: []WildRange = null
wl_ranges: []WildRange = new []WildRange
wl_found: []int = null # found flags a load brought before the ranges were set out
wl_seen: int = 0
wl_fed: int = 0
wl_fed_any: bool = false
wl_near_i: int = 0
wl_species: []WildSpecies = null
wl_list: []WildAnimal = null
wl_species: []WildSpecies = new []WildSpecies
wl_list: []WildAnimal = new []WildAnimal
wl_keys: int = 0
wl_dice: Rng = null
wl_dice: Rng = rng_new(97)
wl_hold: bool = false # staged: nobody thinks, everybody keeps their speed
wl_spot_ask: WildSpot = null
wl_spot_ask: WildSpot = new WildSpot
}
function wl_sp_all(wildlife_st: mut WildlifeState) -> []WildSpecies {
if wildlife_st.wl_species == null { wildlife_st.wl_species = new []WildSpecies }
function wl_sp_all(wildlife_st: WildlifeState) -> []WildSpecies {
return wildlife_st.wl_species
}
export function wildlife_species_clear(wildlife_st: mut WildlifeState) -> void { wildlife_st.wl_species = new []WildSpecies }
# the next species; returns its number
export function wildlife_species_add(wildlife_st: mut WildlifeState, s: WildSpecies) -> int {
export function wildlife_species_add(wildlife_st: WildlifeState, s: WildSpecies) -> int {
push(wl_sp_all(wildlife_st), s)
return len(wl_sp_all(wildlife_st)) - 1
}
export function wildlife_species_count(wildlife_st: mut WildlifeState) -> int { return len(wl_sp_all(wildlife_st)) }
export function wildlife_species_count(wildlife_st: WildlifeState) -> int { return len(wl_sp_all(wildlife_st)) }
export function wildlife_species(wildlife_st: mut WildlifeState, sp: int) -> WildSpecies {
export function wildlife_species(wildlife_st: WildlifeState, sp: int) -> WildSpecies {
if sp < 0 or sp >= len(wl_sp_all(wildlife_st)) { return null }
return wl_sp_all(wildlife_st)[sp]
}
function wl_sp(wildlife_st: mut WildlifeState, sp: int) -> WildSpecies { return wl_sp_all(wildlife_st)[sp] }
function wl_sp(wildlife_st: WildlifeState, sp: int) -> WildSpecies { return wl_sp_all(wildlife_st)[sp] }
function wl_facts__new() -> Queue<WildFact> { return queue_new("wildlife.facts") }

View file

@ -14,7 +14,7 @@ function wl_face(a: WildAnimal, tx: float, tz: float, rate: float, dt: float) ->
}
# true when it moved
function wl_step(wildlife_st: mut WildlifeState, a: WildAnimal, dt: float) -> bool {
function wl_step(wildlife_st: WildlifeState, a: WildAnimal, dt: float) -> bool {
let d = a.speed * dt
if d < 0.0001 { return false }
let nx = a.x - Math.sin(a.yaw) * d
@ -36,7 +36,7 @@ function wl_step(wildlife_st: mut WildlifeState, a: WildAnimal, dt: float) -> bo
return true
}
function wl_pick_target(wildlife_st: mut WildlifeState, a: WildAnimal, radius: float) -> void {
function wl_pick_target(wildlife_st: WildlifeState, a: WildAnimal, radius: float) -> void {
let ang = wl_rnd(wildlife_st) * WL_TAU
let d = wl_rnd(wildlife_st) * radius
a.tx = a.home_x + Math.cos(ang) * d
@ -50,14 +50,14 @@ function wl_at_target(a: WildAnimal, r: float) -> bool {
}
# back to wandering about home after `t` seconds of whatever it was doing
function wl_wander(wildlife_st: mut WildlifeState, a: WildAnimal, t: float) -> void {
function wl_wander(wildlife_st: WildlifeState, a: WildAnimal, t: float) -> void {
a.state = WILD_WANDER
a.timer = t
wl_pick_target(wildlife_st, a, wl_sp(wildlife_st, a.sp).home)
}
# home where it stands now, kept inside its range
function wl_rehome(wildlife_st: mut WildlifeState, a: WildAnimal) -> void {
function wl_rehome(wildlife_st: WildlifeState, a: WildAnimal) -> void {
a.home_x = a.x
a.home_z = a.z
wl_clamp(wildlife_st, a)

View file

@ -1,25 +1,23 @@
# store.ludic - the animals, their own dice, and the verbs that make and take one away
const WL_TAU: float = 6.2831853
export function wildlife_all(wildlife_st: mut WildlifeState) -> []WildAnimal {
if wildlife_st.wl_list == null { wildlife_st.wl_list = new []WildAnimal }
export function wildlife_all(wildlife_st: WildlifeState) -> []WildAnimal {
return wildlife_st.wl_list
}
export function wildlife_count_all(wildlife_st: mut WildlifeState) -> int { return len(wildlife_all(wildlife_st)) }
export function wildlife_count_all(wildlife_st: WildlifeState) -> int { return len(wildlife_all(wildlife_st)) }
# a new valley: every animal forgotten, quietly (the game has already let its drawings go)
export function wildlife_clear(wildlife_st: mut WildlifeState) -> void { wildlife_st.wl_list = new []WildAnimal }
function wl_rng(wildlife_st: mut WildlifeState) -> Rng {
if wildlife_st.wl_dice == null { wildlife_st.wl_dice = rng_new(97) }
function wl_rng(wildlife_st: WildlifeState) -> Rng {
return wildlife_st.wl_dice
}
function wl_rnd(wildlife_st: mut WildlifeState) -> float { return rng_float(wl_rng(wildlife_st)) }
function wl_rnd(wildlife_st: WildlifeState) -> float { return rng_float(wl_rng(wildlife_st)) }
# the package's dice from a known place (a spawn, a test)
export function wildlife_seed(wildlife_st: mut WildlifeState, seed: int) -> void { rng_seed(wl_rng(wildlife_st), seed) }
export function wildlife_seed(wildlife_st: WildlifeState, seed: int) -> void { rng_seed(wl_rng(wildlife_st), seed) }
# an individual exactly as given: the host's own, or the host's on a guest
export function wildlife_make(wildlife_st: mut WildlifeState, sp: int, x: float, z: float, legend: bool, yaw: float, variant: int, scale: float, nid: int) -> WildAnimal {
@ -76,14 +74,14 @@ export function wildlife_remove(a: WildAnimal) -> void {
# staged for a picture: nobody thinks, and everybody keeps the speed they were given
export function wildlife_hold(wildlife_st: mut WildlifeState, on: bool) -> void { wildlife_st.wl_hold = on }
export function wildlife_by_nid(wildlife_st: mut WildlifeState, nid: int) -> WildAnimal {
export function wildlife_by_nid(wildlife_st: WildlifeState, nid: int) -> WildAnimal {
let all = wildlife_all(wildlife_st)
for i in 0 .. len(all) { if all[i].nid == nid { return all[i] } }
return null
}
# how many of a species are alive, legends apart
export function wildlife_count(wildlife_st: mut WildlifeState, sp: int) -> int {
export function wildlife_count(wildlife_st: WildlifeState, sp: int) -> int {
var n = 0
let all = wildlife_all(wildlife_st)
for i in 0 .. len(all) { if all[i].alive and all[i].sp == sp and not all[i].legend { n += 1 } }

View file

@ -9,7 +9,7 @@ export function wildlife_reset(wildlife_st: mut WildlifeState) -> void {
q_clear(wildlife_facts(wildlife_st))
}
export function wildlife_save(wildlife_st: mut WildlifeState) -> Val {
export function wildlife_save(wildlife_st: WildlifeState) -> Val {
let v = Value.object()
sv_put_int(v, "seen", wildlife_st.wl_seen)
sv_put_int(v, "fed", wildlife_st.wl_fed)

View file

@ -33,7 +33,7 @@ function fk_setup(wildlife_st: mut WildlifeState, wildlife_tests_fake_st: mut Wi
}
# 0 deer (meadow, tracks, medium), 1 bear (forest, charges), 2 hare (small), 3 jay (flies)
function fk_species(wildlife_st: mut WildlifeState) -> void {
function fk_species(wildlife_st: WildlifeState) -> void {
let d = new WildSpecies
d.key = "deer"
d.walk = 1.1

View file

@ -19,7 +19,7 @@ program LuresTest {
spot: fn fk_spot
}
function facts(wildlife_st: mut WildlifeState) -> []WildFact { return q_drain(wildlife_facts(wildlife_st)) }
function facts(wildlife_st: WildlifeState) -> []WildFact { return q_drain(wildlife_facts(wildlife_st)) }
function set_out(wildlife_tests_fake_st: mut WildlifeTestsFakeState, uid: int, kind: int, diet: int, x: float, z: float, owner: int) -> WildLure {
let l = new WildLure
l.uid = uid

Some files were not shown because too many files have changed in this diff Show more