wip(0.S3): packages and examples migrated again from their pre-0.S sources in one run

ludic migrate state packages <every example program> packages/ludic.lab/example/plate.ludic
  1804 vars into 126 states, 64 into lets; 23498 edits in 460 files

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
This commit is contained in:
Orkun ÇAKILKAYA 2026-09-25 15:31:34 +03:00
parent 5ffe50ed02
commit 19fcf60599
459 changed files with 17862 additions and 17603 deletions

View file

@ -2,88 +2,88 @@
# the jobs' own dice seeded by the day, so a board never moves anyone else's rolls
export function jobs_board_ok(b: int) -> bool { return b >= 0 and b < BOARD_COUNT }
function jobs__at(b: int, s: int) -> int {
jobs__ensure()
return jobs__off[b] + s
function jobs__at(jobs_st: mut JobsState, b: int, s: int) -> int {
jobs__ensure(jobs_st)
return jobs_st.jobs__off[b] + s
}
# a whole number in [lo, hi] from the jobs' dice: what JobsWorld.roll draws with
export function jobs_roll(lo: int, hi: int) -> int {
jobs__ensure()
return rng_between(jobs__dice, lo, hi)
export function jobs_roll(jobs_st: mut JobsState, lo: int, hi: int) -> int {
jobs__ensure(jobs_st)
return rng_between(jobs_st.jobs__dice, lo, hi)
}
# inside JobsWorld.roll: what goes up in the slot being filled
export function jobs_post(b: int, s: int, kind: int, param: int, need: int, money: int, rep: int) -> void {
let k = jobs__at(b, s)
jobs__pk[k] = kind
jobs__pp[k] = param
jobs__pn[k] = need
jobs__pm[k] = money
jobs__pr[k] = rep
jobs__ph[k] = 0
jobs__ps[k] = JOBS_ACTIVE
jobs__pd[k] = JobsWorld.day()
export function jobs_post(jobs_st: mut JobsState, b: int, s: int, kind: int, param: int, need: int, money: int, rep: int) -> void {
let k = jobs__at(jobs_st, b, s)
jobs_st.jobs__pk[k] = kind
jobs_st.jobs__pp[k] = param
jobs_st.jobs__pn[k] = need
jobs_st.jobs__pm[k] = money
jobs_st.jobs__pr[k] = rep
jobs_st.jobs__ph[k] = 0
jobs_st.jobs__ps[k] = JOBS_ACTIVE
jobs_st.jobs__pd[k] = JobsWorld.day()
let e = JobsWorld.evidence(kind, param)
jobs__pb[k] = 0
if e > 0 { jobs__pb[k] = e }
jobs_st.jobs__pb[k] = 0
if e > 0 { jobs_st.jobs__pb[k] = e }
}
function jobs__clear(k: int) -> void {
jobs__pk[k] = -1
jobs__pp[k] = -1
jobs__pn[k] = 0
jobs__ph[k] = 0
jobs__ps[k] = JOBS_OFFERED
function jobs__clear(jobs_st: mut JobsState, k: int) -> void {
jobs_st.jobs__pk[k] = -1
jobs_st.jobs__pp[k] = -1
jobs_st.jobs__pn[k] = 0
jobs_st.jobs__ph[k] = 0
jobs_st.jobs__ps[k] = JOBS_OFFERED
}
# take a slot down and ask the game for what replaces it
function jobs__repost(b: int, s: int) -> void {
let k = jobs__at(b, s)
function jobs__repost(base_st: mut BaseState, jobs_st: mut JobsState, b: int, s: int) -> void {
let k = jobs__at(jobs_st, b, s)
let day = JobsWorld.day()
rng_seed(jobs__dice, jobs__seed + day * 7 + b * 7919 + s * 104729 + jobs__serial[b] * 31)
jobs__serial[b] += 1
jobs__clear(k)
rng_seed(jobs_st.jobs__dice, jobs_st.jobs__seed + day * 7 + b * 7919 + s * 104729 + jobs_st.jobs__serial[b] * 31)
jobs_st.jobs__serial[b] += 1
jobs__clear(jobs_st, k)
JobsWorld.roll(b, s)
if jobs__pk[k] >= 0 { jobs__fact(JOBS_F_OFFERED, -1, b, s, 0, jobs__pn[k]) }
if jobs_st.jobs__pk[k] >= 0 { jobs__fact(base_st, jobs_st, JOBS_F_OFFERED, -1, b, s, 0, jobs_st.jobs__pn[k]) }
}
# a new day, on the boards this machine keeps: an empty or stale post is replaced, and one
# finished on an earlier day
export function jobs_morning() -> void {
jobs__ensure()
export function jobs_morning(base_st: mut BaseState, jobs_st: mut JobsState) -> void {
jobs__ensure(jobs_st)
let day = JobsWorld.day()
for b in 0 .. BOARD_COUNT {
let bd = JobBoards[b]
if not JobsWorld.owns(bd.scope) { continue }
for s in 0 .. bd.slots {
let k = jobs__off[b] + s
let finished = jobs__ps[k] == JOBS_DONE and day > jobs__pd[k]
if jobs__pk[k] < 0 or finished or day - jobs__pd[k] >= bd.keep { jobs__repost(b, s) }
let k = jobs_st.jobs__off[b] + s
let finished = jobs_st.jobs__ps[k] == JOBS_DONE and day > jobs_st.jobs__pd[k]
if jobs_st.jobs__pk[k] < 0 or finished or day - jobs_st.jobs__pd[k] >= bd.keep { jobs__repost(base_st, jobs_st, b, s) }
}
}
}
function jobs__post_moved(b: int, s: int, have: int) -> void {
let k = jobs__off[b] + s
let was = jobs__ph[k]
jobs__ph[k] = have
if jobs__ph[k] > jobs__pn[k] { jobs__ph[k] = jobs__pn[k] }
if jobs__ph[k] > was { jobs__fact(JOBS_F_PROGRESSED, -1, b, s, jobs__ph[k], jobs__pn[k]) }
if jobs__ps[k] != JOBS_ACTIVE or jobs__ph[k] < jobs__pn[k] { return }
jobs__ps[k] = JOBS_READY
jobs__fact(JOBS_F_COMPLETED, -1, b, s, jobs__ph[k], jobs__pn[k])
if JobBoards[b].auto { jobs_post_hand_in(b, s) }
function jobs__post_moved(base_st: mut BaseState, jobs_st: mut JobsState, b: int, s: int, have: int) -> void {
let k = jobs_st.jobs__off[b] + s
let was = jobs_st.jobs__ph[k]
jobs_st.jobs__ph[k] = have
if jobs_st.jobs__ph[k] > jobs_st.jobs__pn[k] { jobs_st.jobs__ph[k] = jobs_st.jobs__pn[k] }
if jobs_st.jobs__ph[k] > was { jobs__fact(base_st, jobs_st, JOBS_F_PROGRESSED, -1, b, s, jobs_st.jobs__ph[k], jobs_st.jobs__pn[k]) }
if jobs_st.jobs__ps[k] != JOBS_ACTIVE or jobs_st.jobs__ph[k] < jobs_st.jobs__pn[k] { return }
jobs_st.jobs__ps[k] = JOBS_READY
jobs__fact(base_st, jobs_st, JOBS_F_COMPLETED, -1, b, s, jobs_st.jobs__ph[k], jobs_st.jobs__pn[k])
if JobBoards[b].auto { jobs_post_hand_in(base_st, jobs_st, b, s) }
}
export function jobs_post_hand_in(b: int, s: int) -> bool {
export function jobs_post_hand_in(base_st: mut BaseState, jobs_st: mut JobsState, b: int, s: int) -> bool {
if not jobs_board_ok(b) or s < 0 or s >= JobBoards[b].slots { return false }
let k = jobs__at(b, s)
if jobs__ps[k] != JOBS_READY { return false }
jobs__ps[k] = JOBS_DONE
jobs__total[b] += 1
JobsPay.reward(JobBoards[b].scope, jobs__pm[k], jobs__pr[k])
jobs__fact(JOBS_F_HANDED_IN, -1, b, s, jobs__ph[k], jobs__pn[k])
if JobBoards[b].refill { jobs__repost(b, s) }
let k = jobs__at(jobs_st, b, s)
if jobs_st.jobs__ps[k] != JOBS_READY { return false }
jobs_st.jobs__ps[k] = JOBS_DONE
jobs_st.jobs__total[b] += 1
JobsPay.reward(JobBoards[b].scope, jobs_st.jobs__pm[k], jobs_st.jobs__pr[k])
jobs__fact(base_st, jobs_st, JOBS_F_HANDED_IN, -1, b, s, jobs_st.jobs__ph[k], jobs_st.jobs__pn[k])
if JobBoards[b].refill { jobs__repost(base_st, jobs_st, b, s) }
return true
}

View file

@ -6,69 +6,69 @@ function jobs__matches(want_kind: int, want_param: int, kind: int, param: int) -
}
# `n` of (kind, param) happened here: every job and post of a scope this machine keeps
export function jobs_count(kind: int, param: int, n: int) -> void { jobs__count(-1, kind, param, n) }
export function jobs_count(base_st: mut BaseState, jobs_st: mut JobsState, kind: int, param: int, n: int) -> void { jobs__count(base_st, jobs_st, -1, kind, param, n) }
# the same for one scope alone, kept or not: another member's deed arriving at the host
export function jobs_count_in(scope: int, kind: int, param: int, n: int) -> void { jobs__count(scope, kind, param, n) }
export function jobs_count_in(base_st: mut BaseState, jobs_st: mut JobsState, scope: int, kind: int, param: int, n: int) -> void { jobs__count(base_st, jobs_st, scope, kind, param, n) }
function jobs__takes(only: int, scope: int) -> bool {
if only >= 0 { return scope == only }
return JobsWorld.owns(scope)
}
function jobs__count(only: int, kind: int, param: int, n: int) -> void {
jobs__ensure()
function jobs__count(base_st: mut BaseState, jobs_st: mut JobsState, only: int, kind: int, param: int, n: int) -> void {
jobs__ensure(jobs_st)
for i in 0 .. JOB_COUNT {
let d = Jobs[i]
if jobs__st[i] != JOBS_ACTIVE or not jobs__takes(only, d.scope) { continue }
if jobs_st.jobs__st[i] != JOBS_ACTIVE or not jobs__takes(only, d.scope) { continue }
if not jobs__matches(d.kind, d.param, kind, param) { continue }
let was = jobs__hv[i]
jobs__hv[i] = was + n
jobs__moved(i, was)
let was = jobs_st.jobs__hv[i]
jobs_st.jobs__hv[i] = was + n
jobs__moved(base_st, jobs_st, i, was)
}
for b in 0 .. BOARD_COUNT {
if not jobs__takes(only, JobBoards[b].scope) { continue }
for s in 0 .. JobBoards[b].slots {
let k = jobs__off[b] + s
if jobs__ps[k] != JOBS_ACTIVE or not jobs__matches(jobs__pk[k], jobs__pp[k], kind, param) { continue }
jobs__post_moved(b, s, jobs__ph[k] + n)
let k = jobs_st.jobs__off[b] + s
if jobs_st.jobs__ps[k] != JOBS_ACTIVE or not jobs__matches(jobs_st.jobs__pk[k], jobs_st.jobs__pp[k], kind, param) { continue }
jobs__post_moved(base_st, jobs_st, b, s, jobs_st.jobs__ph[k] + n)
}
}
}
function jobs__recheck_one(i: int) -> void {
function jobs__recheck_one(base_st: mut BaseState, jobs_st: mut JobsState, i: int) -> void {
let d = Jobs[i]
if jobs__st[i] != JOBS_ACTIVE or d.kind < 0 or not JobsWorld.owns(d.scope) { return }
if jobs_st.jobs__st[i] != JOBS_ACTIVE or d.kind < 0 or not JobsWorld.owns(d.scope) { return }
let e = JobsWorld.evidence(d.kind, d.param)
if e <= jobs__hv[i] { return }
let was = jobs__hv[i]
jobs__hv[i] = e
jobs__moved(i, was)
if e <= jobs_st.jobs__hv[i] { return }
let was = jobs_st.jobs__hv[i]
jobs_st.jobs__hv[i] = e
jobs__moved(base_st, jobs_st, i, was)
}
# every job under way against what the state already proves: work done before it was taken counts
# for a written job; a post counts only what came after it went up
export function jobs_recheck() -> void {
jobs__ensure()
for i in 0 .. JOB_COUNT { jobs__recheck_one(i) }
export function jobs_recheck(base_st: mut BaseState, jobs_st: mut JobsState) -> void {
jobs__ensure(jobs_st)
for i in 0 .. JOB_COUNT { jobs__recheck_one(base_st, jobs_st, i) }
for b in 0 .. BOARD_COUNT {
if not JobsWorld.owns(JobBoards[b].scope) { continue }
for s in 0 .. JobBoards[b].slots {
let k = jobs__off[b] + s
if jobs__ps[k] != JOBS_ACTIVE or jobs__pk[k] < 0 { continue }
let e = JobsWorld.evidence(jobs__pk[k], jobs__pp[k])
if e >= 0 and e - jobs__pb[k] > jobs__ph[k] { jobs__post_moved(b, s, e - jobs__pb[k]) }
let k = jobs_st.jobs__off[b] + s
if jobs_st.jobs__ps[k] != JOBS_ACTIVE or jobs_st.jobs__pk[k] < 0 { continue }
let e = JobsWorld.evidence(jobs_st.jobs__pk[k], jobs_st.jobs__pp[k])
if e >= 0 and e - jobs_st.jobs__pb[k] > jobs_st.jobs__ph[k] { jobs__post_moved(base_st, jobs_st, b, s, e - jobs_st.jobs__pb[k]) }
}
}
}
# offers newly open are said once; the first look after a reset says none of them
function jobs__offers() -> void {
jobs__ensure()
function jobs__offers(base_st: mut BaseState, jobs_st: mut JobsState) -> void {
jobs__ensure(jobs_st)
for i in 0 .. JOB_COUNT {
let now = jobs_offered(i)
if now and not jobs__seen[i] and jobs__primed { jobs__fact(JOBS_F_OFFERED, i, -1, -1, 0, Jobs[i].need) }
jobs__seen[i] = now
let now = jobs_offered(jobs_st, i)
if now and not jobs_st.jobs__seen[i] and jobs_st.jobs__primed { jobs__fact(base_st, jobs_st, JOBS_F_OFFERED, i, -1, -1, 0, Jobs[i].need) }
jobs_st.jobs__seen[i] = now
}
jobs__primed = true
jobs_st.jobs__primed = true
}

View file

@ -1,96 +1,96 @@
# jobs.ludic - the written jobs: offered by standing and story, taken, readied, handed in and paid
export function jobs_ok(i: int) -> bool { return i >= 0 and i < JOB_COUNT }
export function jobs_state(i: int) -> int {
jobs__ensure()
return jobs__st[i]
export function jobs_state(jobs_st: mut JobsState, i: int) -> int {
jobs__ensure(jobs_st)
return jobs_st.jobs__st[i]
}
export function jobs_have(i: int) -> int {
jobs__ensure()
return jobs__hv[i]
export function jobs_have(jobs_st: mut JobsState, i: int) -> int {
jobs__ensure(jobs_st)
return jobs_st.jobs__hv[i]
}
export function jobs_ready_now(i: int) -> bool { return jobs_state(i) == JOBS_READY }
export function jobs_ready_now(jobs_st: mut JobsState, i: int) -> bool { return jobs_state(jobs_st, i) == JOBS_READY }
# taken and not yet paid
export function jobs_under_way(i: int) -> bool {
let s = jobs_state(i)
export function jobs_under_way(jobs_st: mut JobsState, i: int) -> bool {
let s = jobs_state(jobs_st, i)
return s == JOBS_ACTIVE or s == JOBS_READY
}
# on offer: not taken, the scope's standing and the story far enough, and the game allowing it
export function jobs_offered(i: int) -> bool {
export function jobs_offered(jobs_st: mut JobsState, i: int) -> bool {
let d = Jobs[i]
if jobs_state(i) != JOBS_OFFERED { return false }
if jobs_state(jobs_st, i) != JOBS_OFFERED { return false }
return JobsWorld.rep(d.scope) >= d.minrep and JobsWorld.stage() >= d.minstage and JobsWorld.open(i)
}
export function jobs_take(i: int) -> bool {
if not jobs_ok(i) or jobs_state(i) != JOBS_OFFERED { return false }
jobs__st[i] = JOBS_ACTIVE
jobs__hv[i] = 0
jobs__recheck_one(i)
export function jobs_take(base_st: mut BaseState, jobs_st: mut JobsState, i: int) -> bool {
if not jobs_ok(i) or jobs_state(jobs_st, i) != JOBS_OFFERED { return false }
jobs_st.jobs__st[i] = JOBS_ACTIVE
jobs_st.jobs__hv[i] = 0
jobs__recheck_one(base_st, jobs_st, i)
return true
}
# a count has moved: a job with a need is ready when it is met
function jobs__moved(i: int, was: int) -> void {
function jobs__moved(base_st: mut BaseState, jobs_st: mut JobsState, i: int, was: int) -> void {
let d = Jobs[i]
if d.need > 0 and jobs__hv[i] > d.need { jobs__hv[i] = d.need }
if jobs__hv[i] > was { jobs__fact(JOBS_F_PROGRESSED, i, -1, -1, jobs__hv[i], d.need) }
if jobs__st[i] == JOBS_ACTIVE and d.need > 0 and jobs__hv[i] >= d.need { jobs_ready(i) }
if d.need > 0 and jobs_st.jobs__hv[i] > d.need { jobs_st.jobs__hv[i] = d.need }
if jobs_st.jobs__hv[i] > was { jobs__fact(base_st, jobs_st, JOBS_F_PROGRESSED, i, -1, -1, jobs_st.jobs__hv[i], d.need) }
if jobs_st.jobs__st[i] == JOBS_ACTIVE and d.need > 0 and jobs_st.jobs__hv[i] >= d.need { jobs_ready(base_st, jobs_st, i) }
}
# the game's own play: a step counter, a mask of targets met
export function jobs_set_have(i: int, v: int) -> void {
let was = jobs_have(i)
jobs__hv[i] = v
jobs__moved(i, was)
export function jobs_set_have(base_st: mut BaseState, jobs_st: mut JobsState, i: int, v: int) -> void {
let was = jobs_have(jobs_st, i)
jobs_st.jobs__hv[i] = v
jobs__moved(base_st, jobs_st, i, was)
}
export function jobs_add_have(i: int, n: int) -> void { jobs_set_have(i, jobs_have(i) + n) }
export function jobs_add_have(base_st: mut BaseState, jobs_st: mut JobsState, i: int, n: int) -> void { jobs_set_have(base_st, jobs_st, i, jobs_have(jobs_st, i) + n) }
export function jobs_mark(i: int, bit: int) -> void { jobs_set_have(i, jobs_have(i) | (1 << bit)) }
export function jobs_mark(base_st: mut BaseState, jobs_st: mut JobsState, i: int, bit: int) -> void { jobs_set_have(base_st, jobs_st, i, jobs_have(jobs_st, i) | (1 << bit)) }
# everything in hand
export function jobs_ready(i: int) -> void {
if jobs_state(i) != JOBS_ACTIVE { return }
jobs__st[i] = JOBS_READY
jobs__fact(JOBS_F_COMPLETED, i, -1, -1, jobs__hv[i], Jobs[i].need)
export function jobs_ready(base_st: mut BaseState, jobs_st: mut JobsState, i: int) -> void {
if jobs_state(jobs_st, i) != JOBS_ACTIVE { return }
jobs_st.jobs__st[i] = JOBS_READY
jobs__fact(base_st, jobs_st, JOBS_F_COMPLETED, i, -1, -1, jobs_st.jobs__hv[i], Jobs[i].need)
}
export function jobs_hand_in(i: int) -> bool {
if not jobs_ok(i) or jobs_state(i) != JOBS_READY { return false }
export function jobs_hand_in(base_st: mut BaseState, jobs_st: mut JobsState, i: int) -> bool {
if not jobs_ok(i) or jobs_state(jobs_st, i) != JOBS_READY { return false }
let d = Jobs[i]
jobs__st[i] = JOBS_DONE
if d.group >= 0 and d.group < JOBS_GROUPS { jobs__done_n[d.group] += 1 }
jobs_st.jobs__st[i] = JOBS_DONE
if d.group >= 0 and d.group < JOBS_GROUPS { jobs_st.jobs__done_n[d.group] += 1 }
JobsPay.reward(d.scope, d.money, d.rep)
jobs__fact(JOBS_F_HANDED_IN, i, -1, -1, jobs__hv[i], d.need)
jobs__fact(base_st, jobs_st, JOBS_F_HANDED_IN, i, -1, -1, jobs_st.jobs__hv[i], d.need)
return true
}
# finished and paid in one go, whatever the count says
export function jobs_complete(i: int) -> bool {
if not jobs_ok(i) or not jobs_under_way(i) { return false }
jobs_ready(i)
return jobs_hand_in(i)
export function jobs_complete(base_st: mut BaseState, jobs_st: mut JobsState, i: int) -> bool {
if not jobs_ok(i) or not jobs_under_way(jobs_st, i) { return false }
jobs_ready(base_st, jobs_st, i)
return jobs_hand_in(base_st, jobs_st, i)
}
# the state outright: the host's word for a party job, a test
export function jobs_set(i: int, state: int, have: int) -> void {
jobs__ensure()
jobs__st[i] = state
jobs__hv[i] = have
export function jobs_set(jobs_st: mut JobsState, i: int, state: int, have: int) -> void {
jobs__ensure(jobs_st)
jobs_st.jobs__st[i] = state
jobs_st.jobs__hv[i] = have
}
export function jobs_done(group: int) -> int {
jobs__ensure()
export function jobs_done(jobs_st: mut JobsState, group: int) -> int {
jobs__ensure(jobs_st)
if group < 0 or group >= JOBS_GROUPS { return 0 }
return jobs__done_n[group]
return jobs_st.jobs__done_n[group]
}
export function jobs_set_done(group: int, n: int) -> void {
jobs__ensure()
if group >= 0 and group < JOBS_GROUPS { jobs__done_n[group] = n }
export function jobs_set_done(jobs_st: mut JobsState, group: int, n: int) -> void {
jobs__ensure(jobs_st)
if group >= 0 and group < JOBS_GROUPS { jobs_st.jobs__done_n[group] = n }
}

View file

@ -1,36 +1,36 @@
# lists.ludic - the written jobs as a screen lists them: a vendor's, the taken, the ones to show
# a vendor's offers and the ones it can take back, in a group (-1 every vendor)
export function jobs_at(group: int, vendor: int) -> []int {
export function jobs_at(jobs_st: mut JobsState, group: int, vendor: int) -> []int {
let out = new []int
for i in 0 .. JOB_COUNT {
let d = Jobs[i]
if d.group != group or (vendor >= 0 and d.vendor != vendor) { continue }
let s = jobs_state(i)
if s == JOBS_DONE or (s == JOBS_OFFERED and not jobs_offered(i)) { continue }
let s = jobs_state(jobs_st, i)
if s == JOBS_DONE or (s == JOBS_OFFERED and not jobs_offered(jobs_st, i)) { continue }
push(out, i)
}
return out
}
# every job of a group taken at some point, done ones too
export function jobs_taken(group: int) -> []int {
export function jobs_taken(jobs_st: mut JobsState, group: int) -> []int {
let out = new []int
for i in 0 .. JOB_COUNT { if Jobs[i].group == group and jobs_state(i) != JOBS_OFFERED { push(out, i) } }
for i in 0 .. JOB_COUNT { if Jobs[i].group == group and jobs_state(jobs_st, i) != JOBS_OFFERED { push(out, i) } }
return out
}
# the first `most` of a group under way
export function jobs_shown(group: int, most: int) -> []int {
export function jobs_shown(jobs_st: mut JobsState, group: int, most: int) -> []int {
let out = new []int
for i in 0 .. JOB_COUNT {
if len(out) >= most { break }
if Jobs[i].group == group and jobs_under_way(i) { push(out, i) }
if Jobs[i].group == group and jobs_under_way(jobs_st, i) { push(out, i) }
}
return out
}
# the first under way and not yet met, or -1
export function jobs_first_open(group: int) -> int {
for i in 0 .. JOB_COUNT { if Jobs[i].group == group and jobs_state(i) == JOBS_ACTIVE { return i } }
export function jobs_first_open(jobs_st: mut JobsState, group: int) -> int {
for i in 0 .. JOB_COUNT { if Jobs[i].group == group and jobs_state(jobs_st, i) == JOBS_ACTIVE { return i } }
return -1
}

View file

@ -1,12 +1,12 @@
# posts.ludic - what is on a board, slot by slot, and a board as the host says it
export function jobs_post_kind(b: int, s: int) -> int { return jobs__pk[jobs__at(b, s)] }
export function jobs_post_param(b: int, s: int) -> int { return jobs__pp[jobs__at(b, s)] }
export function jobs_post_need(b: int, s: int) -> int { return jobs__pn[jobs__at(b, s)] }
export function jobs_post_have(b: int, s: int) -> int { return jobs__ph[jobs__at(b, s)] }
export function jobs_post_money(b: int, s: int) -> int { return jobs__pm[jobs__at(b, s)] }
export function jobs_post_rep(b: int, s: int) -> int { return jobs__pr[jobs__at(b, s)] }
export function jobs_post_state(b: int, s: int) -> int { return jobs__ps[jobs__at(b, s)] }
export function jobs_post_day(b: int, s: int) -> int { return jobs__pd[jobs__at(b, s)] }
export function jobs_post_kind(jobs_st: mut JobsState, b: int, s: int) -> int { return jobs_st.jobs__pk[jobs__at(jobs_st, b, s)] }
export function jobs_post_param(jobs_st: mut JobsState, b: int, s: int) -> int { return jobs_st.jobs__pp[jobs__at(jobs_st, b, s)] }
export function jobs_post_need(jobs_st: mut JobsState, b: int, s: int) -> int { return jobs_st.jobs__pn[jobs__at(jobs_st, b, s)] }
export function jobs_post_have(jobs_st: mut JobsState, b: int, s: int) -> int { return jobs_st.jobs__ph[jobs__at(jobs_st, b, s)] }
export function jobs_post_money(jobs_st: mut JobsState, b: int, s: int) -> int { return jobs_st.jobs__pm[jobs__at(jobs_st, b, s)] }
export function jobs_post_rep(jobs_st: mut JobsState, b: int, s: int) -> int { return jobs_st.jobs__pr[jobs__at(jobs_st, b, s)] }
export function jobs_post_state(jobs_st: mut JobsState, b: int, s: int) -> int { return jobs_st.jobs__ps[jobs__at(jobs_st, b, s)] }
export function jobs_post_day(jobs_st: mut JobsState, b: int, s: int) -> int { return jobs_st.jobs__pd[jobs__at(jobs_st, b, s)] }
export function jobs_slots(b: int) -> int {
if not jobs_board_ok(b) { return 0 }
@ -14,38 +14,38 @@ export function jobs_slots(b: int) -> int {
}
# the slots with something posted, in order
export function jobs_posted(b: int) -> []int {
export function jobs_posted(jobs_st: mut JobsState, b: int) -> []int {
let out = new []int
for s in 0 .. jobs_slots(b) { if jobs_post_kind(b, s) >= 0 { push(out, s) } }
for s in 0 .. jobs_slots(b) { if jobs_post_kind(jobs_st, b, s) >= 0 { push(out, s) } }
return out
}
# how many of a board's posts are paid
export function jobs_posts_done(b: int) -> int {
export function jobs_posts_done(jobs_st: mut JobsState, b: int) -> int {
var n = 0
for s in 0 .. jobs_slots(b) { if jobs_post_kind(b, s) >= 0 and jobs_post_state(b, s) == JOBS_DONE { n += 1 } }
for s in 0 .. jobs_slots(b) { if jobs_post_kind(jobs_st, b, s) >= 0 and jobs_post_state(jobs_st, b, s) == JOBS_DONE { n += 1 } }
return n
}
export function jobs_total(b: int) -> int {
jobs__ensure()
return jobs__total[b]
export function jobs_total(jobs_st: mut JobsState, b: int) -> int {
jobs__ensure(jobs_st)
return jobs_st.jobs__total[b]
}
# a slot outright: the host's board on a guest, a test
export function jobs_post_set(b: int, s: int, kind: int, param: int, need: int, have: int, money: int, rep: int, state: int, day: int) -> void {
let k = jobs__at(b, s)
jobs__pk[k] = kind
jobs__pp[k] = param
jobs__pn[k] = need
jobs__ph[k] = have
jobs__pm[k] = money
jobs__pr[k] = rep
jobs__ps[k] = state
jobs__pd[k] = day
export function jobs_post_set(jobs_st: mut JobsState, b: int, s: int, kind: int, param: int, need: int, have: int, money: int, rep: int, state: int, day: int) -> void {
let k = jobs__at(jobs_st, b, s)
jobs_st.jobs__pk[k] = kind
jobs_st.jobs__pp[k] = param
jobs_st.jobs__pn[k] = need
jobs_st.jobs__ph[k] = have
jobs_st.jobs__pm[k] = money
jobs_st.jobs__pr[k] = rep
jobs_st.jobs__ps[k] = state
jobs_st.jobs__pd[k] = day
}
export function jobs_set_total(b: int, n: int) -> void {
jobs__ensure()
jobs__total[b] = n
export function jobs_set_total(jobs_st: mut JobsState, b: int, n: int) -> void {
jobs__ensure(jobs_st)
jobs_st.jobs__total[b] = n
}

View file

@ -1,39 +1,39 @@
# save.ludic - a scope's jobs and boards in a section of their own, by key: a job the game has since
# removed is dropped, a new one starts offered
function jobs__reset_scope(sc: int) -> void {
jobs__ensure()
function jobs__reset_scope(jobs_st: mut JobsState, sc: int) -> void {
jobs__ensure(jobs_st)
for i in 0 .. JOB_COUNT {
if Jobs[i].scope != sc { continue }
jobs__st[i] = JOBS_OFFERED
jobs__hv[i] = 0
jobs_st.jobs__st[i] = JOBS_OFFERED
jobs_st.jobs__hv[i] = 0
}
for b in 0 .. BOARD_COUNT {
if JobBoards[b].scope != sc { continue }
for s in 0 .. JobBoards[b].slots { jobs__clear(jobs__off[b] + s) }
jobs__total[b] = 0
jobs__serial[b] = 0
for s in 0 .. JobBoards[b].slots { jobs__clear(jobs_st, jobs_st.jobs__off[b] + s) }
jobs_st.jobs__total[b] = 0
jobs_st.jobs__serial[b] = 0
}
jobs__primed = false
jobs_st.jobs__primed = false
}
function jobs__save_scope(sc: int) -> Val {
function jobs__save_scope(jobs_st: JobsState, sc: int) -> Val {
let v = Value.object()
let js = Value.object()
for i in 0 .. JOB_COUNT {
if Jobs[i].scope != sc or jobs__st[i] == JOBS_OFFERED { continue }
sv_put_ints(js, Jobs[i].key, [jobs__st[i], jobs__hv[i]])
if Jobs[i].scope != sc or jobs_st.jobs__st[i] == JOBS_OFFERED { continue }
sv_put_ints(js, Jobs[i].key, [jobs_st.jobs__st[i], jobs_st.jobs__hv[i]])
}
Value.put(v, "jobs", js)
let bs = Value.object()
for b in 0 .. BOARD_COUNT {
if JobBoards[b].scope != sc { continue }
let o = Value.object()
sv_put_int(o, "total", jobs__total[b])
sv_put_int(o, "serial", jobs__serial[b])
sv_put_int(o, "total", jobs_st.jobs__total[b])
sv_put_int(o, "serial", jobs_st.jobs__serial[b])
let slots = new []int
for s in 0 .. JobBoards[b].slots {
let k = jobs__off[b] + s
let row = [jobs__pk[k], jobs__pp[k], jobs__pn[k], jobs__ph[k], jobs__pb[k], jobs__pm[k], jobs__pr[k], jobs__ps[k], jobs__pd[k]]
let k = jobs_st.jobs__off[b] + s
let row = [jobs_st.jobs__pk[k], jobs_st.jobs__pp[k], jobs_st.jobs__pn[k], jobs_st.jobs__ph[k], jobs_st.jobs__pb[k], jobs_st.jobs__pm[k], jobs_st.jobs__pr[k], jobs_st.jobs__ps[k], jobs_st.jobs__pd[k]]
for f in 0 .. len(row) { push(slots, row[f]) }
}
sv_put_ints(o, "slots", slots)
@ -43,13 +43,13 @@ function jobs__save_scope(sc: int) -> Val {
return v
}
function jobs__load_scope(sc: int, v: Val) -> void {
jobs__reset_scope(sc)
function jobs__load_scope(jobs_st: mut JobsState, sc: int, v: Val) -> void {
jobs__reset_scope(jobs_st, sc)
if Value.has(v, "jobs") != 0 {
let js = Value.get(v, "jobs")
for i in 0 .. JOB_COUNT {
let p = sv_ints(js, Jobs[i].key)
if Jobs[i].scope == sc and len(p) == 2 { jobs_set(i, p[0], p[1]) }
if Jobs[i].scope == sc and len(p) == 2 { jobs_set(jobs_st, i, p[0], p[1]) }
}
}
if Value.has(v, "boards") == 0 { return }
@ -57,15 +57,15 @@ function jobs__load_scope(sc: int, v: Val) -> void {
for b in 0 .. BOARD_COUNT {
if JobBoards[b].scope != sc or Value.has(bs, JobBoards[b].key) == 0 { continue }
let o = Value.get(bs, JobBoards[b].key)
jobs__total[b] = sv_int(o, "total", 0)
jobs__serial[b] = sv_int(o, "serial", 0)
jobs_st.jobs__total[b] = sv_int(o, "total", 0)
jobs_st.jobs__serial[b] = sv_int(o, "serial", 0)
let r = sv_ints(o, "slots")
for s in 0 .. JobBoards[b].slots {
if s * 9 + 8 >= len(r) { break }
let k = jobs__off[b] + s
let k = jobs_st.jobs__off[b] + s
let q = s * 9
jobs_post_set(b, s, r[q], r[q + 1], r[q + 2], r[q + 3], r[q + 5], r[q + 6], r[q + 7], r[q + 8])
jobs__pb[k] = r[q + 4]
jobs_post_set(jobs_st, b, s, r[q], r[q + 1], r[q + 2], r[q + 3], r[q + 5], r[q + 6], r[q + 7], r[q + 8])
jobs_st.jobs__pb[k] = r[q + 4]
}
}
}

View file

@ -1,28 +1,30 @@
# state.ludic - each job's state and count, the posts on the boards, the done counts, the dice and
# the facts. Made on first use, so the registries are complete by then.
var jobs__st: []int = null
var jobs__hv: []int = null
var jobs__seen: []bool = null # an offer already said
var jobs__primed: bool = false # the first tick after a reset learns the offers quietly
var jobs__done_n: []int = null # handed in, per group
export state JobsState {
jobs__st: []int = null
jobs__hv: []int = null
jobs__seen: []bool = null # an offer already said
jobs__primed: bool = false # the first tick after a reset learns the offers quietly
jobs__done_n: []int = null # handed in, per group
jobs__off: []int = null
jobs__pk: []int = null # kind, -1 empty
jobs__pp: []int = null
jobs__pn: []int = null
jobs__ph: []int = null
jobs__pb: []int = null # the evidence when it went up
jobs__pm: []int = null
jobs__pr: []int = null
jobs__ps: []int = null
jobs__pd: []int = null # the day it went up
jobs__total: []int = null # handed in, per board
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
}
# the posts, every board's slots end to end from jobs__off[b]
var jobs__off: []int = null
var jobs__pk: []int = null # kind, -1 empty
var jobs__pp: []int = null
var jobs__pn: []int = null
var jobs__ph: []int = null
var jobs__pb: []int = null # the evidence when it went up
var jobs__pm: []int = null
var jobs__pr: []int = null
var jobs__ps: []int = null
var jobs__pd: []int = null # the day it went up
var jobs__total: []int = null # handed in, per board
var jobs__serial: []int = null # posts made, per board: each roll its own seed
var jobs__seed: int = 1000
var jobs__dice: Rng = null
var jobs__q: Queue<JobsFact> = null
function jobs__ints(n: int, v: int) -> []int {
let out = new []int
@ -30,39 +32,39 @@ function jobs__ints(n: int, v: int) -> []int {
return out
}
function jobs__ensure() -> void {
if jobs__st != null { return }
jobs__st = jobs__ints(JOB_COUNT, JOBS_OFFERED)
jobs__hv = jobs__ints(JOB_COUNT, 0)
jobs__seen = new []bool
for i in 0 .. JOB_COUNT { push(jobs__seen, false) }
jobs__done_n = jobs__ints(JOBS_GROUPS, 0)
jobs__off = new []int
function jobs__ensure(jobs_st: mut JobsState) -> void {
if jobs_st.jobs__st != null { return }
jobs_st.jobs__st = jobs__ints(JOB_COUNT, JOBS_OFFERED)
jobs_st.jobs__hv = jobs__ints(JOB_COUNT, 0)
jobs_st.jobs__seen = new []bool
for i in 0 .. JOB_COUNT { push(jobs_st.jobs__seen, false) }
jobs_st.jobs__done_n = jobs__ints(JOBS_GROUPS, 0)
jobs_st.jobs__off = new []int
var n = 0
for b in 0 .. BOARD_COUNT {
push(jobs__off, n)
push(jobs_st.jobs__off, n)
n += JobBoards[b].slots
}
jobs__pk = jobs__ints(n, -1)
jobs__pp = jobs__ints(n, -1)
jobs__pn = jobs__ints(n, 0)
jobs__ph = jobs__ints(n, 0)
jobs__pb = jobs__ints(n, 0)
jobs__pm = jobs__ints(n, 0)
jobs__pr = jobs__ints(n, 0)
jobs__ps = jobs__ints(n, JOBS_OFFERED)
jobs__pd = jobs__ints(n, 0)
jobs__total = jobs__ints(BOARD_COUNT, 0)
jobs__serial = jobs__ints(BOARD_COUNT, 0)
jobs__dice = rng_new(jobs__seed)
jobs_st.jobs__pk = jobs__ints(n, -1)
jobs_st.jobs__pp = jobs__ints(n, -1)
jobs_st.jobs__pn = jobs__ints(n, 0)
jobs_st.jobs__ph = jobs__ints(n, 0)
jobs_st.jobs__pb = jobs__ints(n, 0)
jobs_st.jobs__pm = jobs__ints(n, 0)
jobs_st.jobs__pr = jobs__ints(n, 0)
jobs_st.jobs__ps = jobs__ints(n, JOBS_OFFERED)
jobs_st.jobs__pd = jobs__ints(n, 0)
jobs_st.jobs__total = jobs__ints(BOARD_COUNT, 0)
jobs_st.jobs__serial = jobs__ints(BOARD_COUNT, 0)
jobs_st.jobs__dice = rng_new(jobs_st.jobs__seed)
}
export function jobs_facts() -> Queue<JobsFact> {
if jobs__q == null { jobs__q = queue_new("jobs.facts") }
return jobs__q
export function jobs_facts(base_st: mut BaseState, jobs_st: mut JobsState) -> Queue<JobsFact> {
if jobs_st.jobs__q == null { jobs_st.jobs__q = queue_new(base_st, "jobs.facts") }
return jobs_st.jobs__q
}
function jobs__fact(what: int, job: int, b: int, s: int, have: int, need: int) -> void {
function jobs__fact(base_st: mut BaseState, jobs_st: mut JobsState, what: int, job: int, b: int, s: int, have: int, need: int) -> void {
let f = new JobsFact
f.what = what
f.job = job
@ -77,17 +79,17 @@ function jobs__fact(what: int, job: int, b: int, s: int, have: int, need: int) -
f.rep = Jobs[job].rep
f.scope = Jobs[job].scope
} else {
f.kind = jobs__pk[jobs__off[b] + s]
f.param = jobs__pp[jobs__off[b] + s]
f.money = jobs__pm[jobs__off[b] + s]
f.rep = jobs__pr[jobs__off[b] + s]
f.kind = jobs_st.jobs__pk[jobs_st.jobs__off[b] + s]
f.param = jobs_st.jobs__pp[jobs_st.jobs__off[b] + s]
f.money = jobs_st.jobs__pm[jobs_st.jobs__off[b] + s]
f.rep = jobs_st.jobs__pr[jobs_st.jobs__off[b] + s]
f.scope = JobBoards[b].scope
}
q_push(jobs_facts(), f)
q_push(base_st, jobs_facts(base_st, jobs_st), f)
}
# the base of every roll: a post's seed is this, the day, the board, the slot and how many before
export function jobs_config_seed(seed: int) -> void {
jobs__seed = seed
jobs__dice = rng_new(seed)
export function jobs_config_seed(jobs_st: mut JobsState, seed: int) -> void {
jobs_st.jobs__seed = seed
jobs_st.jobs__dice = rng_new(seed)
}

View file

@ -1,39 +1,39 @@
# system.ludic - two systems, one per owner: "jobs" is this player's (personal jobs and boards, the
# done counts, the tick), "jobs.party" the party's, saved with the world
export function jobs_reset() -> void {
jobs__reset_scope(JOBS_SELF)
for g in 0 .. JOBS_GROUPS { jobs__done_n[g] = 0 }
q_clear(jobs_facts())
export function jobs_reset(base_st: mut BaseState, jobs_st: mut JobsState) -> void {
jobs__reset_scope(jobs_st, JOBS_SELF)
for g in 0 .. JOBS_GROUPS { jobs_st.jobs__done_n[g] = 0 }
q_clear(base_st, jobs_facts(base_st, jobs_st))
}
export function jobs_party_reset() -> void { jobs__reset_scope(JOBS_PARTY) }
export function jobs_party_reset(jobs_st: mut JobsState) -> void { jobs__reset_scope(jobs_st, JOBS_PARTY) }
export function jobs_save() -> Val {
jobs__ensure()
let v = jobs__save_scope(JOBS_SELF)
sv_put_ints(v, "done", jobs__done_n)
export function jobs_save(jobs_st: mut JobsState) -> Val {
jobs__ensure(jobs_st)
let v = jobs__save_scope(jobs_st, JOBS_SELF)
sv_put_ints(v, "done", jobs_st.jobs__done_n)
return v
}
export function jobs_load(v: Val, version: int) -> void {
jobs__load_scope(JOBS_SELF, v)
export function jobs_load(jobs_st: mut JobsState, v: Val, version: int) -> void {
jobs__load_scope(jobs_st, JOBS_SELF, v)
let d = sv_ints(v, "done")
for g in 0 .. JOBS_GROUPS {
jobs__done_n[g] = 0
if g < len(d) { jobs__done_n[g] = d[g] }
jobs_st.jobs__done_n[g] = 0
if g < len(d) { jobs_st.jobs__done_n[g] = d[g] }
}
}
export function jobs_party_save() -> Val {
jobs__ensure()
return jobs__save_scope(JOBS_PARTY)
export function jobs_party_save(jobs_st: mut JobsState) -> Val {
jobs__ensure(jobs_st)
return jobs__save_scope(jobs_st, JOBS_PARTY)
}
export function jobs_party_load(v: Val, version: int) -> void { jobs__load_scope(JOBS_PARTY, v) }
export function jobs_party_load(jobs_st: mut JobsState, v: Val, version: int) -> void { jobs__load_scope(jobs_st, JOBS_PARTY, v) }
function jobs__tick(t: Tick) -> void {
jobs__offers()
jobs_recheck()
function jobs__tick(base_st: mut BaseState, jobs_st: mut JobsState, t: Tick) -> void {
jobs__offers(base_st, jobs_st)
jobs_recheck(base_st, jobs_st)
}
export function jobs_system() -> System {

View file

@ -15,50 +15,52 @@ program JobsTest {
def JobBoards daily { slots: 3, keep: 1, auto: true, refill: false }
def JobBoards ada { slots: 2, keep: 7, scope: JOBS_PARTY }
var rep: int = 0
var stage: int = 0
var day: int = 1
var guest: bool = false
var fish: int = 0 # the state's count of fish
var paid: int = 0
var paid_rep: int = 0
var paid_scope: int = -1
state JobsTestState {
rep: int = 0
stage: int = 0
day: int = 1
guest: bool = false
fish: int = 0 # the state's count of fish
paid: int = 0
paid_rep: int = 0
paid_scope: int = -1
}
function world_rep(sc: int) -> int { return rep }
function world_stage() -> int { return stage }
function world_day() -> int { return day }
function world_owns(sc: int) -> bool { return sc == JOBS_SELF or not guest }
function world_evidence(kind: int, param: int) -> int {
if kind == K_FISH { return fish }
function world_rep(jobs_test_st: JobsTestState, sc: int) -> int { return jobs_test_st.rep }
function world_stage(jobs_test_st: JobsTestState) -> int { return jobs_test_st.stage }
function world_day(jobs_test_st: JobsTestState) -> int { return jobs_test_st.day }
function world_owns(jobs_test_st: JobsTestState, sc: int) -> bool { return sc == JOBS_SELF or not jobs_test_st.guest }
function world_evidence(jobs_test_st: JobsTestState, kind: int, param: int) -> int {
if kind == K_FISH { return jobs_test_st.fish }
return -1
}
function world_roll(b: int, s: int) -> void {
let need = jobs_roll(2, 4)
if b == BOARD_DAILY { jobs_post(b, s, K_WOOD, -1, need, 7, 2) } else { jobs_post(b, s, K_FISH, -1, need, 9 * need, 3) }
function world_roll(jobs_st: mut JobsState, b: int, s: int) -> void {
let need = jobs_roll(jobs_st, 2, 4)
if b == BOARD_DAILY { jobs_post(jobs_st, b, s, K_WOOD, -1, need, 7, 2) } else { jobs_post(jobs_st, b, s, K_FISH, -1, need, 9 * need, 3) }
}
function pay(sc: int, money: int, r: int) -> void {
paid += money
paid_rep += r
paid_scope = sc
function pay(jobs_test_st: mut JobsTestState, sc: int, money: int, r: int) -> void {
jobs_test_st.paid += money
jobs_test_st.paid_rep += r
jobs_test_st.paid_scope = sc
}
bind JobsWorld { rep: fn world_rep, stage: fn world_stage, day: fn world_day, owns: fn world_owns, evidence: fn world_evidence, roll: fn world_roll }
bind JobsPay { reward: fn pay }
function fresh() -> void {
rep = 0
stage = 0
day = 1
guest = false
fish = 0
paid = 0
paid_rep = 0
jobs_reset()
jobs_party_reset()
function fresh(base_st: mut BaseState, jobs_st: mut JobsState, jobs_test_st: mut JobsTestState) -> void {
jobs_test_st.rep = 0
jobs_test_st.stage = 0
jobs_test_st.day = 1
jobs_test_st.guest = false
jobs_test_st.fish = 0
jobs_test_st.paid = 0
jobs_test_st.paid_rep = 0
jobs_reset(base_st, jobs_st)
jobs_party_reset(jobs_st)
}
function count_of(what: int) -> int {
let fs = q_drain(jobs_facts())
function count_of(base_st: mut BaseState, jobs_st: mut JobsState, what: int) -> int {
let fs = q_drain(base_st, jobs_facts(base_st, jobs_st))
var n = 0
for i in 0 .. len(fs) { if fs[i].what == what { n += 1 } }
return n
@ -70,166 +72,166 @@ program JobsTest {
expect_eq(BOARD_COUNT, 2)
}
test "a gate of standing and story" {
fresh()
expect(jobs_offered(JOB_CATCH))
expect(not jobs_offered(JOB_DEER))
rep = 10
expect(jobs_offered(JOB_DEER))
expect(not jobs_offered(JOB_STILL))
stage = 2
expect(jobs_offered(JOB_STILL))
expect_eq(len(jobs_at(0, -1)), 3)
test "a gate of standing and story" (base_st: mut BaseState, jobs_st: mut JobsState, jobs_test_st: mut JobsTestState) {
fresh(base_st, jobs_st, jobs_test_st)
expect(jobs_offered(jobs_st, JOB_CATCH))
expect(not jobs_offered(jobs_st, JOB_DEER))
jobs_test_st.rep = 10
expect(jobs_offered(jobs_st, JOB_DEER))
expect(not jobs_offered(jobs_st, JOB_STILL))
jobs_test_st.stage = 2
expect(jobs_offered(jobs_st, JOB_STILL))
expect_eq(len(jobs_at(jobs_st, 0, -1)), 3)
}
test "counted by events, readied, handed in and paid" {
fresh()
jobs_count(K_FISH, 0, 1)
expect_eq(jobs_have(JOB_CATCH), 0)
expect(jobs_take(JOB_CATCH))
jobs_count(K_FISH, 0, 2)
expect_eq(jobs_state(JOB_CATCH), JOBS_ACTIVE)
jobs_count(K_FISH, 0, 5)
expect_eq(jobs_have(JOB_CATCH), 3)
expect(jobs_ready_now(JOB_CATCH))
expect_eq(count_of(JOBS_F_COMPLETED), 1)
expect(jobs_hand_in(JOB_CATCH))
expect(not jobs_hand_in(JOB_CATCH))
expect_eq(paid, 30)
expect_eq(paid_rep, 5)
expect_eq(jobs_done(0), 1)
expect_eq(count_of(JOBS_F_HANDED_IN), 1)
test "counted by events, readied, handed in and paid" (base_st: mut BaseState, jobs_st: mut JobsState, jobs_test_st: mut JobsTestState) {
fresh(base_st, jobs_st, jobs_test_st)
jobs_count(base_st, jobs_st, K_FISH, 0, 1)
expect_eq(jobs_have(jobs_st, JOB_CATCH), 0)
expect(jobs_take(base_st, jobs_st, JOB_CATCH))
jobs_count(base_st, jobs_st, K_FISH, 0, 2)
expect_eq(jobs_state(jobs_st, JOB_CATCH), JOBS_ACTIVE)
jobs_count(base_st, jobs_st, K_FISH, 0, 5)
expect_eq(jobs_have(jobs_st, JOB_CATCH), 3)
expect(jobs_ready_now(jobs_st, JOB_CATCH))
expect_eq(count_of(base_st, jobs_st, JOBS_F_COMPLETED), 1)
expect(jobs_hand_in(base_st, jobs_st, JOB_CATCH))
expect(not jobs_hand_in(base_st, jobs_st, JOB_CATCH))
expect_eq(jobs_test_st.paid, 30)
expect_eq(jobs_test_st.paid_rep, 5)
expect_eq(jobs_done(jobs_st, 0), 1)
expect_eq(count_of(base_st, jobs_st, JOBS_F_HANDED_IN), 1)
}
test "the state already proves the work" {
fresh()
fish = 2
jobs_take(JOB_CATCH)
expect_eq(jobs_have(JOB_CATCH), 2)
fish = 3
jobs_recheck()
expect(jobs_ready_now(JOB_CATCH))
test "the state already proves the work" (base_st: mut BaseState, jobs_st: mut JobsState, jobs_test_st: mut JobsTestState) {
fresh(base_st, jobs_st, jobs_test_st)
jobs_test_st.fish = 2
jobs_take(base_st, jobs_st, JOB_CATCH)
expect_eq(jobs_have(jobs_st, JOB_CATCH), 2)
jobs_test_st.fish = 3
jobs_recheck(base_st, jobs_st)
expect(jobs_ready_now(jobs_st, JOB_CATCH))
}
test "a param narrows the count" {
fresh()
rep = 10
jobs_take(JOB_DEER)
jobs_count(K_PHOTO, 3, 1)
expect_eq(jobs_have(JOB_DEER), 0)
jobs_count(K_PHOTO, 4, 1)
expect(jobs_ready_now(JOB_DEER))
test "a param narrows the count" (base_st: mut BaseState, jobs_st: mut JobsState, jobs_test_st: mut JobsTestState) {
fresh(base_st, jobs_st, jobs_test_st)
jobs_test_st.rep = 10
jobs_take(base_st, jobs_st, JOB_DEER)
jobs_count(base_st, jobs_st, K_PHOTO, 3, 1)
expect_eq(jobs_have(jobs_st, JOB_DEER), 0)
jobs_count(base_st, jobs_st, K_PHOTO, 4, 1)
expect(jobs_ready_now(jobs_st, JOB_DEER))
}
test "the game's own play readies a job with no need" {
fresh()
jobs_take(JOB_STILL)
jobs_mark(JOB_STILL, 2)
expect_eq(jobs_have(JOB_STILL), 4)
expect_eq(jobs_state(JOB_STILL), JOBS_ACTIVE)
expect(jobs_complete(JOB_STILL))
expect_eq(paid, 60)
expect_eq(jobs_done(1), 1)
test "the game's own play readies a job with no need" (base_st: mut BaseState, jobs_st: mut JobsState, jobs_test_st: mut JobsTestState) {
fresh(base_st, jobs_st, jobs_test_st)
jobs_take(base_st, jobs_st, JOB_STILL)
jobs_mark(base_st, jobs_st, JOB_STILL, 2)
expect_eq(jobs_have(jobs_st, JOB_STILL), 4)
expect_eq(jobs_state(jobs_st, JOB_STILL), JOBS_ACTIVE)
expect(jobs_complete(base_st, jobs_st, JOB_STILL))
expect_eq(jobs_test_st.paid, 60)
expect_eq(jobs_done(jobs_st, 1), 1)
}
test "a guest counts its own and leaves the party's to the host" {
fresh()
guest = true
jobs_take(JOB_TEN)
jobs_take(JOB_CATCH)
jobs_count(K_FISH, 0, 2)
expect_eq(jobs_have(JOB_TEN), 0)
expect_eq(jobs_have(JOB_CATCH), 2)
jobs_count_in(JOBS_PARTY, K_FISH, 0, 4)
expect_eq(jobs_have(JOB_TEN), 4)
expect_eq(jobs_have(JOB_CATCH), 2)
test "a guest counts its own and leaves the party's to the host" (base_st: mut BaseState, jobs_st: mut JobsState, jobs_test_st: mut JobsTestState) {
fresh(base_st, jobs_st, jobs_test_st)
jobs_test_st.guest = true
jobs_take(base_st, jobs_st, JOB_TEN)
jobs_take(base_st, jobs_st, JOB_CATCH)
jobs_count(base_st, jobs_st, K_FISH, 0, 2)
expect_eq(jobs_have(jobs_st, JOB_TEN), 0)
expect_eq(jobs_have(jobs_st, JOB_CATCH), 2)
jobs_count_in(base_st, jobs_st, JOBS_PARTY, K_FISH, 0, 4)
expect_eq(jobs_have(jobs_st, JOB_TEN), 4)
expect_eq(jobs_have(jobs_st, JOB_CATCH), 2)
}
test "an offer is said once it opens, never for what was open at the reset" {
fresh()
test "an offer is said once it opens, never for what was open at the reset" (base_st: mut BaseState, jobs_st: mut JobsState, jobs_test_st: mut JobsTestState) {
fresh(base_st, jobs_st, jobs_test_st)
jobs_system().tick(tick_new(0.1, 1, 0.0))
expect_eq(count_of(JOBS_F_OFFERED), 0)
rep = 10
expect_eq(count_of(base_st, jobs_st, JOBS_F_OFFERED), 0)
jobs_test_st.rep = 10
jobs_system().tick(tick_new(0.1, 2, 0.0))
expect_eq(count_of(JOBS_F_OFFERED), 1)
expect_eq(count_of(base_st, jobs_st, JOBS_F_OFFERED), 1)
}
test "a board rolled by the day, the same every time" {
fresh()
day = 3
jobs_morning()
expect_eq(len(jobs_posted(BOARD_DAILY)), 3)
expect_eq(len(jobs_posted(BOARD_ADA)), 2)
let a = jobs_post_need(BOARD_DAILY, 0) * 100 + jobs_post_need(BOARD_DAILY, 1) * 10 + jobs_post_need(BOARD_DAILY, 2)
fresh()
day = 3
jobs_morning()
let b = jobs_post_need(BOARD_DAILY, 0) * 100 + jobs_post_need(BOARD_DAILY, 1) * 10 + jobs_post_need(BOARD_DAILY, 2)
test "a board rolled by the day, the same every time" (base_st: mut BaseState, jobs_st: mut JobsState, jobs_test_st: mut JobsTestState) {
fresh(base_st, jobs_st, jobs_test_st)
jobs_test_st.day = 3
jobs_morning(base_st, jobs_st)
expect_eq(len(jobs_posted(jobs_st, BOARD_DAILY)), 3)
expect_eq(len(jobs_posted(jobs_st, BOARD_ADA)), 2)
let a = jobs_post_need(jobs_st, BOARD_DAILY, 0) * 100 + jobs_post_need(jobs_st, BOARD_DAILY, 1) * 10 + jobs_post_need(jobs_st, BOARD_DAILY, 2)
fresh(base_st, jobs_st, jobs_test_st)
jobs_test_st.day = 3
jobs_morning(base_st, jobs_st)
let b = jobs_post_need(jobs_st, BOARD_DAILY, 0) * 100 + jobs_post_need(jobs_st, BOARD_DAILY, 1) * 10 + jobs_post_need(jobs_st, BOARD_DAILY, 2)
expect_eq(a, b)
expect(jobs_post_need(BOARD_DAILY, 0) >= 2 and jobs_post_need(BOARD_DAILY, 0) <= 4)
expect(jobs_post_need(jobs_st, BOARD_DAILY, 0) >= 2 and jobs_post_need(jobs_st, BOARD_DAILY, 0) <= 4)
}
test "a daily pays the moment it is met and waits for the morning" {
fresh()
day = 2
jobs_morning()
let need = jobs_post_need(BOARD_DAILY, 1)
jobs_count(K_WOOD, -1, need)
expect_eq(jobs_post_state(BOARD_DAILY, 1), JOBS_DONE)
expect(jobs_posts_done(BOARD_DAILY) >= 1)
expect_eq(paid, 7 * jobs_posts_done(BOARD_DAILY))
jobs_morning()
expect_eq(jobs_post_state(BOARD_DAILY, 1), JOBS_DONE)
day = 3
jobs_morning()
expect_eq(jobs_post_state(BOARD_DAILY, 1), JOBS_ACTIVE)
test "a daily pays the moment it is met and waits for the morning" (base_st: mut BaseState, jobs_st: mut JobsState, jobs_test_st: mut JobsTestState) {
fresh(base_st, jobs_st, jobs_test_st)
jobs_test_st.day = 2
jobs_morning(base_st, jobs_st)
let need = jobs_post_need(jobs_st, BOARD_DAILY, 1)
jobs_count(base_st, jobs_st, K_WOOD, -1, need)
expect_eq(jobs_post_state(jobs_st, BOARD_DAILY, 1), JOBS_DONE)
expect(jobs_posts_done(jobs_st, BOARD_DAILY) >= 1)
expect_eq(jobs_test_st.paid, 7 * jobs_posts_done(jobs_st, BOARD_DAILY))
jobs_morning(base_st, jobs_st)
expect_eq(jobs_post_state(jobs_st, BOARD_DAILY, 1), JOBS_DONE)
jobs_test_st.day = 3
jobs_morning(base_st, jobs_st)
expect_eq(jobs_post_state(jobs_st, BOARD_DAILY, 1), JOBS_ACTIVE)
}
test "a post counts only what came after it went up, and is replaced when handed in" {
fresh()
fish = 5
jobs_morning()
let need = jobs_post_need(BOARD_ADA, 0)
jobs_recheck()
expect_eq(jobs_post_have(BOARD_ADA, 0), 0)
fish = 5 + need
jobs_recheck()
expect_eq(jobs_post_state(BOARD_ADA, 0), JOBS_READY)
expect(jobs_post_hand_in(BOARD_ADA, 0))
expect_eq(paid_scope, JOBS_PARTY)
expect_eq(jobs_total(BOARD_ADA), 1)
expect_eq(jobs_post_state(BOARD_ADA, 0), JOBS_ACTIVE)
test "a post counts only what came after it went up, and is replaced when handed in" (base_st: mut BaseState, jobs_st: mut JobsState, jobs_test_st: mut JobsTestState) {
fresh(base_st, jobs_st, jobs_test_st)
jobs_test_st.fish = 5
jobs_morning(base_st, jobs_st)
let need = jobs_post_need(jobs_st, BOARD_ADA, 0)
jobs_recheck(base_st, jobs_st)
expect_eq(jobs_post_have(jobs_st, BOARD_ADA, 0), 0)
jobs_test_st.fish = 5 + need
jobs_recheck(base_st, jobs_st)
expect_eq(jobs_post_state(jobs_st, BOARD_ADA, 0), JOBS_READY)
expect(jobs_post_hand_in(base_st, jobs_st, BOARD_ADA, 0))
expect_eq(jobs_test_st.paid_scope, JOBS_PARTY)
expect_eq(jobs_total(jobs_st, BOARD_ADA), 1)
expect_eq(jobs_post_state(jobs_st, BOARD_ADA, 0), JOBS_ACTIVE)
}
test "a stale post comes down after its days" {
fresh()
jobs_morning()
day = 7
jobs_morning()
expect_eq(jobs_post_day(BOARD_ADA, 0), 1)
day = 8
jobs_morning()
expect_eq(jobs_post_day(BOARD_ADA, 0), 8)
test "a stale post comes down after its days" (base_st: mut BaseState, jobs_st: mut JobsState, jobs_test_st: mut JobsTestState) {
fresh(base_st, jobs_st, jobs_test_st)
jobs_morning(base_st, jobs_st)
jobs_test_st.day = 7
jobs_morning(base_st, jobs_st)
expect_eq(jobs_post_day(jobs_st, BOARD_ADA, 0), 1)
jobs_test_st.day = 8
jobs_morning(base_st, jobs_st)
expect_eq(jobs_post_day(jobs_st, BOARD_ADA, 0), 8)
}
test "each scope saves its own, by key" {
fresh()
jobs_take(JOB_CATCH)
jobs_count(K_FISH, 0, 2)
jobs_take(JOB_TEN)
jobs_count(K_FISH, 0, 1)
day = 2
jobs_morning()
let body = jobs_save()
let world = jobs_party_save()
let need = jobs_post_need(BOARD_ADA, 1)
fresh()
jobs_load(body, 1)
expect_eq(jobs_have(JOB_CATCH), 3)
expect_eq(jobs_state(JOB_TEN), JOBS_OFFERED)
jobs_party_load(world, 1)
expect_eq(jobs_have(JOB_TEN), 1)
expect_eq(jobs_post_need(BOARD_ADA, 1), need)
expect_eq(jobs_post_day(BOARD_DAILY, 0), 2)
test "each scope saves its own, by key" (base_st: mut BaseState, jobs_st: mut JobsState, jobs_test_st: mut JobsTestState) {
fresh(base_st, jobs_st, jobs_test_st)
jobs_take(base_st, jobs_st, JOB_CATCH)
jobs_count(base_st, jobs_st, K_FISH, 0, 2)
jobs_take(base_st, jobs_st, JOB_TEN)
jobs_count(base_st, jobs_st, K_FISH, 0, 1)
jobs_test_st.day = 2
jobs_morning(base_st, jobs_st)
let body = jobs_save(jobs_st)
let world = jobs_party_save(jobs_st)
let need = jobs_post_need(jobs_st, BOARD_ADA, 1)
fresh(base_st, jobs_st, jobs_test_st)
jobs_load(jobs_st, body, 1)
expect_eq(jobs_have(jobs_st, JOB_CATCH), 3)
expect_eq(jobs_state(jobs_st, JOB_TEN), JOBS_OFFERED)
jobs_party_load(jobs_st, world, 1)
expect_eq(jobs_have(jobs_st, JOB_TEN), 1)
expect_eq(jobs_post_need(jobs_st, BOARD_ADA, 1), need)
expect_eq(jobs_post_day(jobs_st, BOARD_DAILY, 0), 2)
}
}