feat(packages): ludic.hints - a rail of things that are true now and can be acted on now: cards as an open registry (urgency, a glyph or an item's picture, the chip's line, three steps and how not to be here again) asked through a port whether each is true, the most urgent few once a pass in registry order within an urgency, a card opened off the rail, walked along it and put down when its subject stops being true, and "I know this" muting kept by the card's key (a key this build lacks is carried through); opened, closed, muted and unmuted as facts
Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
This commit is contained in:
parent
1005a677f2
commit
fe9d28bf4e
12 changed files with 540 additions and 0 deletions
3
packages/ludic.hints/tests/cards.lres
Normal file
3
packages/ludic.hints/tests/cards.lres
Normal file
|
|
@ -0,0 +1,3 @@
|
|||
# cards.lres - two cards from a file, after the test's own defs
|
||||
bear { urgency: HINTS_URGENT, line: "Bear near", title: "A bear", icon: "bear" }
|
||||
fire { urgency: HINTS_NOTE, line: "Light the fire", later: "Carry three logs." }
|
||||
162
packages/ludic.hints/tests/hints_test.ludic
Normal file
162
packages/ludic.hints/tests/hints_test.ludic
Normal file
|
|
@ -0,0 +1,162 @@
|
|||
# hints_test.ludic - the rail sorted by urgency and capped, ties in registry order, the card walked
|
||||
# along it and put down when it stops being true, muting by key across a save, cards from a file
|
||||
import "ludic.hints"
|
||||
import "ludic.base"
|
||||
program HintsTest {
|
||||
numbers float
|
||||
def Hints thirsty { urgency: HINTS_NOTE, line: "Thirsty - drink", title: "Water", s1: "Drink at a shore", pic1: "water", item2: 7 }
|
||||
def Hints parched { urgency: HINTS_URGENT, line: "You must drink now", title: "Water, now" }
|
||||
def Hints rain { urgency: HINTS_TIP, line: "Rain coming" }
|
||||
def Hints cold { urgency: HINTS_WARN, line: "Cold" }
|
||||
def Hints night { urgency: HINTS_TIP, line: "Night soon" }
|
||||
def Hints from "cards.lres"
|
||||
|
||||
var on: []bool = null
|
||||
var showing: bool = true
|
||||
|
||||
function fake_true(i: int) -> bool { return on[i] }
|
||||
function fake_showing() -> bool { return showing }
|
||||
bind HintsWorld { true_now: fn fake_true, showing: fn fake_showing }
|
||||
|
||||
function fresh() -> void {
|
||||
on = new []bool
|
||||
for i in 0 .. HINT_COUNT { push(on, false) }
|
||||
showing = true
|
||||
hints_config(3, 1.0)
|
||||
hints_reset()
|
||||
hints_mutes_load(Value.list())
|
||||
}
|
||||
|
||||
function count(what: int) -> int {
|
||||
let fs = q_drain(hints_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, and a file adds to it" {
|
||||
expect_eq(HINT_COUNT, 7)
|
||||
expect_eq(hints_find("parched"), HINT_PARCHED)
|
||||
expect_eq(Hints[HINT_BEAR].urgency, HINTS_URGENT)
|
||||
expect(Hints[HINT_FIRE].later == "Carry three logs.")
|
||||
expect(hints_step_icon(HINT_THIRSTY, 1) == "water")
|
||||
expect_eq(hints_step_item(HINT_THIRSTY, 2), 7)
|
||||
expect(hints_step_text(HINT_THIRSTY, 1) == "Drink at a shore")
|
||||
}
|
||||
|
||||
test "the most urgent true cards, capped, ties in registry order" {
|
||||
fresh()
|
||||
for i in 0 .. HINT_COUNT { on[i] = true }
|
||||
hints_tick(1.0)
|
||||
expect_eq(hints_count(), 3)
|
||||
expect_eq(hints_at(0), HINT_PARCHED)
|
||||
expect_eq(hints_at(1), HINT_BEAR)
|
||||
expect_eq(hints_at(2), HINT_COLD)
|
||||
on[HINT_PARCHED] = false
|
||||
on[HINT_BEAR] = false
|
||||
hints_tick(0.5)
|
||||
expect_eq(hints_at(0), HINT_PARCHED) # not a second yet: the rail holds
|
||||
hints_tick(0.6)
|
||||
expect_eq(hints_at(0), HINT_COLD)
|
||||
expect_eq(hints_at(1), HINT_THIRSTY)
|
||||
expect_eq(hints_at(2), HINT_FIRE)
|
||||
}
|
||||
|
||||
test "nothing on the rail while it is not showing" {
|
||||
fresh()
|
||||
on[HINT_COLD] = true
|
||||
showing = false
|
||||
hints_sort()
|
||||
expect_eq(len(hints_rail()), 0)
|
||||
expect_eq(hints_count(), 0)
|
||||
showing = true
|
||||
hints_sort()
|
||||
expect_eq(len(hints_rail()), 1)
|
||||
}
|
||||
|
||||
test "the key opens the picked chip, the arrows walk round, the key puts it down" {
|
||||
fresh()
|
||||
on[HINT_COLD] = true
|
||||
on[HINT_THIRSTY] = true
|
||||
on[HINT_RAIN] = true
|
||||
hints_sort()
|
||||
hints_key()
|
||||
expect_eq(hints_card(), HINT_COLD)
|
||||
hints_move(1)
|
||||
expect_eq(hints_card(), HINT_THIRSTY)
|
||||
expect(hints_hot(1))
|
||||
hints_move(-1)
|
||||
hints_move(-1)
|
||||
expect_eq(hints_card(), HINT_RAIN)
|
||||
hints_key()
|
||||
expect_eq(hints_card(), -1)
|
||||
expect_eq(count(HINTS_F_OPENED), 4)
|
||||
}
|
||||
|
||||
test "the card follows its subject as the rail re-sorts, and goes when it is no longer true" {
|
||||
fresh()
|
||||
on[HINT_THIRSTY] = true
|
||||
on[HINT_RAIN] = true
|
||||
hints_sort()
|
||||
hints_open(1)
|
||||
expect_eq(hints_card(), HINT_RAIN)
|
||||
on[HINT_COLD] = true
|
||||
hints_sort()
|
||||
expect_eq(hints_card(), HINT_RAIN)
|
||||
expect_eq(hints_pick(), 2)
|
||||
on[HINT_RAIN] = false
|
||||
hints_sort()
|
||||
expect_eq(hints_card(), -1)
|
||||
expect_eq(count(HINTS_F_CLOSED), 0) # it went; nobody put it down
|
||||
}
|
||||
|
||||
test "I know this: muted off the rail, counted, given back" {
|
||||
fresh()
|
||||
on[HINT_COLD] = true
|
||||
on[HINT_THIRSTY] = true
|
||||
hints_sort()
|
||||
hints_key()
|
||||
hints_mute_card()
|
||||
expect_eq(hints_card(), -1)
|
||||
expect(hints_muted(HINT_COLD))
|
||||
expect_eq(hints_mute_count(), 1)
|
||||
expect_eq(count(HINTS_F_MUTED), 1)
|
||||
hints_tick(0.0) # the next pass comes at once
|
||||
expect_eq(hints_at(0), HINT_THIRSTY)
|
||||
expect_eq(hints_count(), 1)
|
||||
hints_unmute_all()
|
||||
hints_tick(0.0)
|
||||
expect_eq(hints_at(0), HINT_COLD)
|
||||
expect_eq(count(HINTS_F_UNMUTED), 1)
|
||||
}
|
||||
|
||||
test "mutes are kept by key, and a key this build lacks is carried through" {
|
||||
fresh()
|
||||
hints_mute(HINT_NIGHT, true)
|
||||
hints_mute(HINT_BEAR, true)
|
||||
let l = hints_mutes_save()
|
||||
expect_eq(Value.count(l), 2)
|
||||
Value.add(l, Value.str("gone_card"))
|
||||
Value.add(l, Value.int(3)) # not a key: ignored
|
||||
hints_mutes_load(l)
|
||||
expect(hints_muted(HINT_NIGHT))
|
||||
expect(hints_muted(HINT_BEAR))
|
||||
expect(not hints_muted(HINT_RAIN))
|
||||
expect_eq(hints_mute_count(), 2)
|
||||
let back = hints_mutes_save()
|
||||
expect_eq(Value.count(back), 3)
|
||||
expect(Value.as_str(Value.at(back, 2)) == "gone_card")
|
||||
hints_mutes_load(null)
|
||||
expect_eq(hints_mute_count(), 0)
|
||||
}
|
||||
|
||||
test "as a system it ticks the rail" {
|
||||
fresh()
|
||||
core_clear()
|
||||
core_add(hints_system())
|
||||
core_reset_all()
|
||||
on[HINT_FIRE] = true
|
||||
core_tick_all(tick_new(1.0, 1, 0.0))
|
||||
expect_eq(hints_at(0), HINT_FIRE)
|
||||
}
|
||||
}
|
||||
Loading…
Add table
Add a link
Reference in a new issue