feat(packages): ludic.jobs - written jobs gated by standing and story, boards of posts rolled by the day on their own dice, progress counted from events and read back from state, handing in, rewards through a port, facts, a save section per scope
Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
This commit is contained in:
parent
e146c7a337
commit
411206e45a
14 changed files with 984 additions and 0 deletions
235
packages/ludic.jobs/tests/jobs_test.ludic
Normal file
235
packages/ludic.jobs/tests/jobs_test.ludic
Normal file
|
|
@ -0,0 +1,235 @@
|
|||
# jobs_test.ludic - written jobs gated by standing and story, counted by events and by state, readied
|
||||
# and paid through a fake purse; a board rolled from the day; the party's scope; the save by key
|
||||
import "ludic.jobs"
|
||||
import "ludic.base"
|
||||
program JobsTest {
|
||||
numbers float
|
||||
const K_FISH: int = 0
|
||||
const K_PHOTO: int = 1
|
||||
const K_WOOD: int = 2
|
||||
|
||||
def Jobs catch { group: 0, kind: K_FISH, need: 3, money: 30, rep: 5 }
|
||||
def Jobs deer { group: 0, kind: K_PHOTO, param: 4, need: 1, money: 20, rep: 2, minrep: 10 }
|
||||
def Jobs ten { group: 0, kind: K_FISH, need: 10, money: 70, rep: 12, scope: JOBS_PARTY }
|
||||
def Jobs still { group: 1, need: 0, money: 60, rep: 12, minstage: 2 }
|
||||
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
|
||||
|
||||
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 }
|
||||
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 pay(sc: int, money: int, r: int) -> void {
|
||||
paid += money
|
||||
paid_rep += r
|
||||
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 count_of(what: int) -> int {
|
||||
let fs = q_drain(jobs_facts())
|
||||
var n = 0
|
||||
for i in 0 .. len(fs) { if fs[i].what == what { n += 1 } }
|
||||
return n
|
||||
}
|
||||
|
||||
test "the registry is the game's" {
|
||||
expect_eq(JOB_COUNT, 4)
|
||||
expect_eq(jobs_find("ten"), JOB_TEN)
|
||||
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 "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 "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 "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 "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 "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 "an offer is said once it opens, never for what was open at the reset" {
|
||||
fresh()
|
||||
jobs_system().tick(tick_new(0.1, 1, 0.0))
|
||||
expect_eq(count_of(JOBS_F_OFFERED), 0)
|
||||
rep = 10
|
||||
jobs_system().tick(tick_new(0.1, 2, 0.0))
|
||||
expect_eq(count_of(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)
|
||||
expect_eq(a, b)
|
||||
expect(jobs_post_need(BOARD_DAILY, 0) >= 2 and jobs_post_need(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 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 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 "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)
|
||||
}
|
||||
}
|
||||
Loading…
Add table
Add a link
Reference in a new issue