feat(packages): ludic.npc - the other people in a place: kinds, spots, acts, names and lines as open registries (a kind's routine is steps by the hour - a spot, an act, how long - with its own start and plan as function values, readable from .lres), a census on the half hour by weight (after dark only who stays out) with an extra the place asks for, walking round what is in the way and never into the water or up a scramble, no act where the place says nobody stops, facing a player within notice and back to the errand, leaving only out of every player's sight, unique names, posts that never walk (a vendor), lines by prio and chance with the story's words through a port and choices, a guest's copy of a host's people; greeted, talked and arrived as facts
Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
This commit is contained in:
parent
73a376ac6c
commit
029a1ebba2
23 changed files with 1664 additions and 0 deletions
49
packages/ludic.npc/names.ludic
Normal file
49
packages/ludic.npc/names.ludic
Normal file
|
|
@ -0,0 +1,49 @@
|
|||
# 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
|
||||
var np_recent: []string = null # the last few names that left
|
||||
|
||||
export function npc_name_used(n: string) -> bool {
|
||||
if NpcWorld.taken(n) { return true }
|
||||
let all = npc_walkers()
|
||||
for i in 0 .. len(all) { if all[i].active and all[i].name == n { return true } }
|
||||
let posts = npc_posts()
|
||||
for i in 0 .. len(posts) { if posts[i].active and posts[i].name == n { return true } }
|
||||
if np_recent != null { for i in 0 .. len(np_recent) { if np_recent[i] == n { return true } } }
|
||||
return false
|
||||
}
|
||||
|
||||
# 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(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)
|
||||
if n == 0 { return "" }
|
||||
let start = npc_between(0, n - 1)
|
||||
for k in 0 .. n {
|
||||
let name = pool[(start + k) % n]
|
||||
if not npc_name_used(name) { return name }
|
||||
}
|
||||
return pool[start]
|
||||
}
|
||||
|
||||
function np_left(name: string) -> void {
|
||||
if np_recent == null { np_recent = new []string }
|
||||
push(np_recent, name)
|
||||
if len(np_recent) <= 8 { return }
|
||||
let keep = new []string
|
||||
for i in len(np_recent) - 8 .. len(np_recent) { push(keep, np_recent[i]) }
|
||||
np_recent = keep
|
||||
}
|
||||
|
||||
# how many pairs share a name, the place's own names included
|
||||
export function npc_name_clashes() -> int {
|
||||
var dup = 0
|
||||
let all = npc_walkers()
|
||||
for i in 0 .. len(all) {
|
||||
let p = all[i]
|
||||
if not p.active { continue }
|
||||
if NpcWorld.taken(p.name) { dup += 1 }
|
||||
for k in i + 1 .. len(all) { if all[k].active and all[k].name == p.name { dup += 1 } }
|
||||
}
|
||||
return dup
|
||||
}
|
||||
Loading…
Add table
Add a link
Reference in a new issue