info.html · 介绍 · play.html · 游玩 · llms.txt · 下载与本地运行 · ZIP · GitHub
A real, historically-operated English-language fantasy MUD ("Primal Darkness", 1999-2010, mud.primaldarkness.com), Nightmare-mudlib lineage, and one of the largest libs in this collection at ~32,000 source files with two decades of genuinely-authored content behind it. Character creation offers 30 playable races running from the ordinary (human, elf, dwarf, gnome) to the exotic (illithid mind-flayers, half-dragons, driders, archangels, basilisks) -- a fresh human lands in Tirun, a hand-built hub city with a real street grid (Honin Road, Ganthus Road, Wayward/Parthos Roads) centered on Central Park, an inter-city coach line out to a second full city (Lodos), and guild halls where classes/subclasses (e.g. mage into sorceror) are earned organically by walking in and training rather than picked at creation. Beyond Tirun: Helgrath is a cold northern town built around Wilndur Square's fountain and its Yull Boulevard/Market Road crossroads; Aekari is a crystal-veined cavern dungeon; Pastarlon is an active warzone where the drow of Zolenia are besieging the town of Arlon; and Inferi Island's volcanic "Eye of Hell" is an elite-rated quest zone built around a menace that's supposedly lurked there for decades. The archive preserves real historical player and wizard save data from the mud's actual operating years, including colorful admin titles ("Archon Avatar", "Realms Avatar") carried over from the original site.
README
A real, historically-operated English-language MUD (1999-2010) built on the Nightmare mudlib lineage -- one of the largest libraries in this collection, at roughly 32,000 source files. Genuinely authored content throughout, not a stock skeleton: dozens of hand-built domains (aekari, citrin, distopia, durst, forest, frozen, guilds, helgrath, helves, inferi_island, lodos, marshes, metaisland, pastarlon, roston, saahr, tirun, and more), a 30-race character-creation system, guilds, and years of accumulated wizard-built content and real player history preserved from the original archive.
Source: ehershey/pd on GitHub. The mudlib itself lives at
libraries/beta-ii/ inside that repository (a bundled Flash client and
driver binaries/scripts were excluded during conversion -- this
collection always uses its own driver).
Highlights
- Race-pick character creation: a short new-character ritual (name, password, gender, email) drops you into a creation-limbo room where you
read listto see the 30 available races andpick <race>to finalize your character -- stats roll automatically and you're placed into the real starting area (Tirun Central Park) fully equipped. - Large, genuinely hand-built world: dozens of named domains with real room descriptions, NPCs, quests, and guild content, plus an in-game newbie helper NPC and a first-time player news feed.
- An identity-profile system: the mud tracks which characters have connected from the same IP (a LAN/multi-account disclosure feature, not a bug) -- expect a one-time "is this a new identity or an existing one?" prompt on your first-ever connection from a given address.
Play
Connect and answer the name/password/gender/email prompts to register,
then read list and pick <race> to finish character creation.
look, score, inventory, and say all work as expected once
you're in the world; quit saves you and disconnects cleanly, and
reconnecting with the same name/password brings you back to the exact
room and equipment you left with.
Status
Boots clean natively and plays correctly end-to-end: registration, race selection, movement through real authored rooms, and the restore/reconnect path were all verified live, repeatedly, across multiple independent test accounts.
WASM status: playable. Shared WASM driver. adm/simul_efun/mail.lpc
SMTP helpers are #ifndef __PACKAGE_SOCKETS__ no-ops so the eager
simul_efun compiles. New-character registration (wasmpd / Test12345
/ new identity / pick human) into Tirun Central Park, plus look
/ score ("Newbie Wasmpd the boy", 600 gold) / quit ("Reality
suspended."), verified with scripts/wasm_client.js. The seeded
fluffos admin password did not match Mud@2026 under WASM (old
crypt). Play: https://mudlibs.fluffos.info/pd/
Admin account
fluffos / see the standard corpus password -- seeded via this
lineage's (superuser)/(assist)/(allowed)/(creator)/
(approval)/(mudlib) groups in adm/db/groups.db plus a non-mortal
position title in its save file (this lineage gates wizard status on
both group membership AND an in-play "position"/title, not group
membership alone). Verified live via update <path>, which exercises
both the read and compile halves of the ACL.
Onboarding notes
See NOTES.md in this directory for the full technical bring-up log.
The headline finding: two independent, corpus-wide, silently-broken
codepaths, both fixed and verified live --
1. The command-dispatch daemon's directory-scan used stale
.c-extension slice arithmetic left over from before this
collection's standard .c→.lpc rename, corrupting every single
command's registered key so literally every verb except quit
returned the generic "What?" fail message, for every player, from
the very first boot (AGENTS.md §7.118, a previously-catalogued bug
class -- this is its largest-scale confirmed instance).
2. The login object's account-restore path silently failed to grant
itself read access to the player's own save file, due to a
double misunderstanding of what this driver's export_uid() efun
actually does -- meaning a fresh registration worked perfectly, but
reconnecting to ANY already-created account silently landed the
player in a session with zero working commands, including quit
itself (a new catalog entry, AGENTS.md §8.22).
Also fixed: eight base-class setter functions (set_id and seven
siblings) declared with parameter types narrower than the vast
majority of the corpus's own call sites use (AGENTS.md §7.127 --
~8,800 of this lib's original ~10,000 compile failures came from just
these eight functions); a genuinely lost keep.h header reconstructed
from surviving directory evidence; and a handful of smaller,
lower-blast-radius compile-compat fixes detailed in NOTES.md.
NOTES · 移植与修复记录
pd — technical notes
Source: gh repo clone ehershey/pd (cloned 2026-08-28). Mudlib root at
libraries/beta-ii/ inside that repo (a bundled FMud/ Flash client
and bin/ driver binaries/scripts, both siblings of libraries/ at
the repo root, were never copied into raw/ — excluded by construction,
not by a later filter). Number 952, port 40254. Status: done —
boots clean natively, full registration-to-gameplay playthrough AND the
restore/reconnect path verified live and repeatedly.
What this lib is
A real, historically-operated English-language MUD ("Primal Darkness",
1999-2010, mud.primaldarkness.com/www.primaldarkness.com), Nightmare
mudlib lineage (adm/obj/master.lpc credits "Descartes of Borg 03
august 1993, Nightmare Mudlib Version 3.0"). One of the largest libs
onboarded this session: 32,436 .c/.h files (72,244 total files
including data/docs/logs), all pure ASCII (already_utf8=71949,
converted=51, lossy=78 per convert_lib.sh — the 78 lossy bytes were
all a single garbled —/bullet character in a handful of // author
comment headers, purely cosmetic, no functional impact). No GB18030/BIG5
conversion needed at all.
Real, extensive, genuinely-authored content confirmed across dozens of
domains: aekari, citrin, distopia, durst, forest, frozen,
guilds, helgrath, helves, inferi_island, lodos, marshes,
metaisland, pastarlon, roston, saahr, tirun, and more — not
stock/placeholder content. Real historical player and wizard save data
ships with the archive (adm/save/users/, adm/save/boats/,
wizards/<name>/), which is why several early test registrations
collided with pre-existing real historical account names (brennik,
ashlyn both turned out to be real accounts from the original site —
picked less-common fantasy names for later tests to avoid this).
4 bin/*.mud configs (primal/tna/whit/builders) in the excluded
bin/ directory confirm multiple named instances of the same codebase
historically — primal.mud was used as the template for this lib's
config.fluffos (port/paths/limits adapted, everything else preserved).
§2.2 on-sight checklist
master.lpc'sload_object/get_root_uid/get_bb_uidall read normally; noget_include_path()existed at all — added one (see "Compile-time fixes" below).- No
securityd/is_chinese/check_legal_name— not applicable (English lib, no Chinese-name gating anywhere in this lineage). adm/db/preload.dbpreloads a normal, small daemon set (/daemon/command,castle_d,race_d,localpost,remotepost,letter,economy_d,events_d, a network daemon,web) — nodns_master/intermud entries.- No hardcoded
MUD_PORT/PORTNOconstant anywhere (grepcame back empty) — this lib reads its port purely fromconfig.fluffos, so none of the §5.3 "port baked into source" trap applies. - No
command_hookprivate/nomask overrides; noefun::set/query/deleteusage; no bareswitch...defaultgrammar issue; noed_start/ed_cmd/query_ed_modeusage. - Genuine, dormant, on-demand outbound
socket_connect()calls exist (daemon/plains_d.lpc'sconnect_plainswalk()to a hardcoded209.85.145.196:3000,adm/daemon/link_d.lpc'sconnect_server()to63.84.93.196:2349,adm/simul_efun/mail.lpc's SMTP relay, and a full Intermud-Chat implementation indaemon/imc_socket.lpc) — but, unlikeimud's always-on I3 connection, none of these fire automatically at boot or preload time: they're all gated behind a player/wizard command (a "plainswalk" cross-mud portal feature, a mud-to-mud link-server handshake, sending in-game mail, and an IMC chat network respectively), and none of the daemons that own them are inpreload.db. Confirmed no automatic network activity across several full boot+playthrough cycles. Flagging here per the §2.2 standing discipline anyway, since a future wizard actually running theplainswalkor mud-link commands would attempt a real outbound connection to a long-dead historical IP (harmless — it'll just time out — but worth knowing before assuming this lib is fully network-sandboxed like the rest of the corpus). - Inbound-listening sockets confirmed harmless:
daemon/network.lpc(UDP),daemon/webservices/main.lpc(port 12333),daemon/web.lpc(port 8500),wizards/whit/network.lpc(UDP 6123) — these just open extra local listening ports that nothing external will ever connect to in this environment; not a security or stability concern.
Conversion (convert_lib.sh)
Ran scripts/convert_lib.sh libs/pd/raw/beta-ii libs/pd/work (default
GB18030 encoding — a no-op given the pure-ASCII source, confirmed
before running by sampling files with a Python decode round-trip). Full
run took ~26 minutes given the file count. Mechanical fixups the script
applied: 21,629 literal .c" reference rewrites, 3,713 local
angle-bracket #include <x.lpc> → quoted conversions, 1,017 files'
static → nosave. Two script-vs-directory-structure edge cases found
and hand-fixed afterward (neither is a new bug class, both are
consequences of the rename step encountering something odd mid-run):
- A directory literally named
myfile.c(wizards/kabaal/room/myfile.c/{room1,room2,room3,room4}.c) —find's-name '*.c'glob (no-type f) matched the directory too, renaming it tomyfile.lpcin the same pass that was still trying to rename its now-stale-pathed children, so those 4 files were left as.cinside the renamed parent and never got the encoding/literal-.c-ref fixup pass applied. Manually renamed the 4 files and re-ran the literal-.c-reference fixup on just them (8 references fixed). These 4 rooms' own exits reference a typo'dmyfile/roomN.cpath (missing the trailing.c/.lpcon the directory segment itself) that never resolved even in the original archive — a pre-existing, unreachable dead-end in what is clearly a wizard's personal test scratchpad (wizards/kabaal/room/), left as-is per scope (content, not a conversion regression). - A genuinely lost
keep.hheader: 68 files underwizards/whit/keep/(#include <keep.h>) failed with "Cannot #include keep.h" — the file doesn't exist anywhere in the raw archive, not a conversion artifact. Reconstructedinclude/domains/keep.hfrom surviving evidence:ROOMS,GARDEN, andWEPare unambiguous (they mirror the surrounding directory layout, exactly matching this codebase's own convention — compareinclude/domains/tundra.h'sSERVER/ROOMSpair), andGARDEN_SERVERwas fully verifiable sincewizards/whit/keep/rooms/garden/server.lpcalready exists on disk — a mechanical restoration, not invented content.
Compile-time fixes (lpcc_check.sh)
Given the scale (~32K files), ran the memory-capped sweep in chunks
(fresh lpcc --batch VM per chunk, ulimit -v capped) rather than one
continuous batch — a single continuous process accumulates enough
resident object memory to hit std::bad_alloc well before reaching the
end of a corpus this size (confirmed: ~750 files consumed 8GB in one
continuous run). Final full-corpus pass: 31,923/31,935 files covered,
29,610 pass, 2,313 fail (down from ~9,988 failures before any fixes —
a handful of memory-dense pockets, mostly large coordinate-grid room
areas, needed a second smaller-chunk pass to get full coverage; 12
files in one chunk that hit a hard abort even at 50-file granularity
remain untested, all inside the same already-known-dead
wizards/amun/builders/ staging tree described below).
Dominant class: base-class setters declared narrower than the corpus uses them (AGENTS.md §7.127)
~8,800 of the original ~10,000 failures (88%) came from just 8
functions in std/object.lpc/std/room.lpc/std/monster.lpc/
std/lacky.lpc/std/living.lpc/std/vault.lpc (plus their bak/
test/wizard-personal sibling copies, since this driver compiles every
.lpc in the tree standalone):
| Function | Declared as | Corpus actually calls it with | Fix |
|---|---|---|---|
| set_id | string | array, 7,350+ sites | mixed, coerce scalar→1-elem array |
| set_swarm | int | int OR string (mixed real usage) | mixed, no coercion (only used as a boolean flag) |
| set_languages | string * | array OR scalar | mixed, coerce scalar→1-elem array |
| set_alignment | int | int OR quoted numeric string | mixed + to_int() before arithmetic |
| set_long | string | string OR function (dynamic descriptions — query_long() already functionp()-checks) | mixed |
| set_short | string | string OR function (same as above) | mixed |
| set_door_func | string (3rd arg) | string OR function (query_door_func() already declared mixed) | mixed |
Each was confirmed against every other real definition/override of
the same function in the corpus before widening — in every case
(set_id most starkly: every non-base override already declares
string *) the base declaration was the sole outlier, not the callers.
See AGENTS.md §7.127 for the general "how to apply" writeup, now
updated with this lib as its largest confirmed instance.
daemon/command.lpc's dispatch table (AGENTS.md §7.118 — see "Two severe bugs" below)
Missing/shadowed local headers (AGENTS.md §6.1 family)
keep.h— see "Conversion" above (genuinely lost, reconstructed).drowpath.h(wizards/stormbringer/roston/drowpath/) andvplain.h(wizards/nulvect/builders/vplain/) both exist on disk but are#include <x.h>'d from a subdirectory one level below where the header actually lives (rooms//mobs/) — outside what this lib's newmaster::get_include_path()(added since this lib had none at all) searches (its own directory only, not ancestors). 17 files total; fixed by converting those specific includes to absolute quoted paths (#include "/wizards/.../drowpath.h") rather than wideningget_include_path()to search ancestor directories corpus-wide, since only these two cases were found.adm/save/boats.old/(133 files, a stray backup copy of old boat source sitting inside what's otherwise a save-data directory) failed with "Illegal to inherit after defining global variables" — their shared#include <ocean.h>(which, unlike every other header these files use, declares a real initialized globalstring *ocean_map) came beforeinherit PIER;in file order. Fixed by moving#include <std.h>(needed for thePIERmacro itself) + theinheritline ahead of the other two#includes in all 133 files — purely a reordering, no logic changed. This directory is unreachable from the live game (adm/save/is data, not loaded content) but was cheap and mechanical to fix regardless.
Remaining ~2,300 failures: concentrated in confirmed-unreachable backup/draft directories
A grep sweep of the remaining failure list shows this is NOT a new
systemic class — it's a long tail of syntax errors, MudOS-only-efun
gaps (dump_socket_status(), old-style (: val1, val2 :) functional
literals), and one duplicate-function-declaration case
(wizards/amun/builders/marshes/ — 158 files with their own local
sp_sap() override AND #include <amun.h>, which ALSO defines
sp_sap() with different logic; the "live" copy of this same content
under d/inferi_island/marshes/ has no such conflict), overwhelmingly
concentrated in directories whose own names say "not live content":
guildbak/, /old/, wizards/*/builders/, cmds/oldskills/,
*.nul/*.bak-suffixed files. Spot-checked wizards/amun/builders/
marshes/ specifically: zero references to that path exist anywhere
outside itself in the whole corpus — confirmed genuinely unreachable
from the live room network, not merely low-traffic. Logged here per
this project's content-vs-programming-bug scope line rather than
chased file-by-file; none of it affects the live, playable game.
Two severe, corpus-wide bugs found and fixed
Both discovered because the standard §10.1 playthrough script
initially only exercised fresh registration — the project's own
§8.20/§8.22-style lesson about the restore path needing its own
explicit test applied literally here.
1. Command dispatch totally broken (AGENTS.md §7.118, largest
confirmed instance) — daemon/command.lpc's rehash() builds its
verb→file table with choses[j] = choses[j][1..strlen(choses[j])-3],
arithmetic written for the original .c (2-char) extension; after
this collection's standard .c→.lpc (4-char) rename it silently
registered every verb one character too long ("_look.lpc" →
"look.l" instead of "look"), so literally every command except
quit (registered directly via add_action(), not through this
table) returned the driver's generic "What?" fail message for
every player, from the very first boot. Fixed with the established
-5 arithmetic. Verified live: before the fix, a fresh character's
look/score/inventory/say all returned "What?"; after, all
four (plus read list/pick <race> during creation) produced
correct output.
2. Existing-account restore/reconnect totally broken (new, AGENTS.md
§8.22) — adm/obj/login.lpc's check_password() needs to
temporarily read the connecting player's own save file (to compare
the stored password hash), via a classic "borrow root through the
master object" handoff:
master()->load_player_from_file(name, ob) →
export_uid(ob); ob->restore_player(name);. Two compounding
misreadings of what this driver's export_uid() actually does
(confirmed against the driver's own f_export_uid() C source):
it's a silent no-op unless the target's OWN euid is currently
unset (every object already has one, from create()'s own
seteuid(getuid())), and even when it fires it only ever sets the
target's UID, never its euid — it's a one-time ownership-transfer
primitive, not a privilege grant. So restore_player()'s own
restore_object() call always failed master::check_access()'s
permission check on /adm/save/users/... with *restore_object:
read permission denied, uncaught, silently aborting
check_password() (and everything queued after it) with zero
trace in debug.log — a brand-new registration worked perfectly (it
never calls this function at all), but reconnecting to ANY existing
account — including one that had just registered and cleanly quit
moments earlier — landed the player in a session with literally zero
working commands, quit included, no error visible anywhere.
Diagnosed via message()/debug_message() instrumentation (plain
write() produces no visible output during this lineage's pre-body
login sequence, hence its own code always using
message("logon", ..., this_object())). Fixed with two additions
mirroring this lineage's own working SAVE-side handoff
(save_player()/actually_save_player(), which happens to work by
accident of a different code shape): a new self-only
nomask void clear_euid() { seteuid(0); } on the shared
std/object.lpc base class, called by master.lpc's
load_player_from_file() right before export_uid() (so the
export actually fires and sets the UID to Root as intended), plus an
explicit seteuid(UID_ROOT); added to std/user/save.lpc's
restore_player() right before restore_object() (succeeds because
the UID export_uid() just set makes master::valid_seteuid()'s own
uid==UID_ROOT special case pass). Applied identically to
master2.lpc and the std/test//wizards/nulvect/std/ sibling
copies. Verified live end-to-end on two independent accounts:
register → quit → reconnect with the same password → correct
restoration of room/inventory/equipment, look/score/inventory/
quit all producing correct output (all of which returned "What?"
before the fix).
Admin account seeding (§1.5)
Registered fluffos through the normal registration flow (real driver,
real prompts). This lineage's wizard-status check is two-part —
wizardp() (a real efun, checks an in-memory O_IS_WIZARD flag set by
setup() whenever the saved position field is anything outside
({"player","high mortal","ambassador"})) AND archp()/admp()
(wizardp(ob) && member_group(name,"superuser")) — so BOTH halves
needed seeding: added fluffos to adm/db/groups.db's (superuser),
(assist), (allowed), (creator), (approval), and (mudlib)
groups (matching every real historical admin account's own membership
pattern), and set fluffos.o's saved position field from the default
"player" to "Root Avatar" (a non-mortal title, matching this
lineage's own convention of colorful custom titles like "Archon
Avatar"/"Realms Avatar" for its real admins). Verified live: logging
in shows the extra Immortal/Arch news pages wizards get, and
update /std/object succeeds ("/std/object: updated and loaded."),
exercising both the read and compile halves of the file ACL.
WASM status
Not yet attempted — out of scope for this onboarding pass per the
assigned task (native boot/playthrough only). wasm_status: "pending"
in meta.json.
WASM measurement (2026-09-03)
meta.json was already playable from the 2026-08-31 deploy-unblock;
the README still said "not yet packaged." Cold-boot under the shared
~/src/fluffos/build-wasm failed: eager adm/simul_efun/mail.lpc
calls socket_create/socket_bind/socket_error (SMTP outbound),
so the whole simul_efun object was not loadable. Wrapped those
bodies in #ifndef __PACKAGE_SOCKETS__ no-ops (native unchanged).
Wizard network.lpc / daemon/web.lpc socket failures remain
graceful preload skips.
Verified with scripts/wasm_client.js: new character wasmpd →
name-policy enter → y → Test12345 twice → male →
[email protected] → real name → identity new → read list (30
races including human) → pick human → Tirun Central Park →
score ("Newbie Wasmpd the boy", 600 gold, 70 stat / 5 skill
points) → quit ("Reality suspended. See you another time!").
The seeded fluffos admin rejected Mud@2026 ("Invalid password";
driver also logged the old-crypt 8-char warning) — not chased; new
registration is enough for the gallery path. Shop/combat/death were
not exercised this pass. The MEMFS copy does not write wasmpd
back to the host.
LPC formatter (§9)
Run 2026-08-31 (catch-up pass) — the original onboarding couldn't
run node (PATH issue, since fixed via ~/.zshenv). Ran
format-corpus.mjs over all 31,936 .lpc files under work/: 31,709
reformatted, 84 already-clean, 143 refused (messy legacy code). Ran all
three §9 blind-spot checks: :: split (0 hits), case-label/comment
merge (86 candidate spots across 8 files, manually diff-reviewed, all
intact), and pre-existing-unbalanced-quote garbling (1 hit,
std/obj/deed.lpc — a genuine original-source typo, fixed by hand and
reformatted). Re-booted and re-verified the full live playthrough
(registration, look, score, quit, restore/reconnect) — all correct.
§10.7 deep functional test (2026-08-31, round two)
Full continuous playthrough on the native driver (build-debug), going
beyond the onboarding pass's registration/restore verification above —
specifically to independently re-confirm the restore-path fix (§8.22)
holds for a SECOND, unrelated account, and to exercise gameplay systems
(race pick, class/subclass acquisition, safe-sparring, domain travel,
long-sit daemon watch) the onboarding pass didn't reach. Test
character: id Vulmarrow, password Test12345, male human, class
Mage/subclass Sorceror — kept (not cleaned up) as a representative
playthrough character. Save file: work/adm/save/users/v/vulmarrow.o.
Bug found and fixed: two objects pass a bare int to a string-typed setter, so this driver's strict compile-time type check rejects them and they never load
/d/nopk/standard/cemetary/mon/monument.lpc:12 and
/d/nopk/standard/rain_forest/obj/statue.lpc:8 both called
set_prevent_get(1) — std/object.lpc's real declaration is
void set_prevent_get(string str) (494 other call sites across the
corpus correctly pass a message string, e.g. fighter/dummy.lpc's
set_prevent_get("You can't take that out of the ground!")) — so both
objects hit Bad type for argument 1 of set_prevent_get ( string vs int
) and never compiled at all (*No program in object '...'! every time
anything tried to new() them). This is the mirror image of the
already-catalogued AGENTS.md §7.127 pattern (there, a shared base
setter was declared narrower than the corpus's real usage; here the
base declaration is correct and these two call sites are the outliers)
— narrow enough (2 files, not a systemic class) that it doesn't warrant
its own new AGENTS.md entry, but worth noting as the same general
"literal-argument-type mismatch on an otherwise-correct setter" shape.
Found via the long-sit boot watch below: a wandering errand boy NPC's
move_around() heart_beat wandered into
/d/nopk/standard/cemetary/gravyar9, whose reset() tried to
new() the broken monument.lpc, throwing a real (if silent-to-players)
error every reset cycle — exactly the class of bug §10.0 exists to
catch (invisible to registration/login smoke testing, only surfaces
once a lazily-reset room with wandering NPC traffic is hit). Fixed by
giving each object a real message string matching the established
convention ("The monument/statue is far too heavy to carry.").
Verified with a targeted lpcc --batch recompile of just these two
paths — both compile clean, no more FAIL/error lines — and
confirmed no recurrence of the No program in object error across a
fresh driver boot plus the full long-sit idle window below.
What was tested and confirmed working
- Registration and race pick: full flow (name → name-policy confirm → password → gender → email → real name → identity-profile prompt) into the race-selection void room,
read list(all 30 races render),pick human→ landed correctly in Tirun Central Park with starting gear (boots, chainmail, helmet, newbie guide) and 600 gold. - Movement/exploration into 3 distinct domains: Tirun (walked the hand-built street grid — market square, Honin Road, Ganthus Road, Wayward/Parthos Roads — using a small BFS script built from parsing every room's
set_exits()ind/nopk/tirun/, since the town is large enough that blind wandering wasn't practical); the North Forest (d/nopk/standard/forest1-3, reached via the north gate, a genuinely calm/monster-free newbie corridor by design); and Lodos (a full second city, reached via the/d/coach/inter-city coach system —coach to lodosfrom the western coach house, correct in-transit flavor text, arrival with newbie fare correctly free — money stayed at 600 gold throughout). - Safe-sparring found and used before real combat:
d/nopk/tirun/ fighter/dummy.lpc(reached viaenter fighter hall→ south from the Sparring Hall) is this lib's designated safe target — itsattack dummyhandler is pure narration keyed offrandom(this_player ()->query_skill("melee")), no real damage exchanged either direction; used repeatedly with zero HP loss before any real fight was attempted (none was attempted this pass — see Death/respawn below). - Skill/guild (class/subclass) acquisition, organic path: walked to the mage hall (
enter mage halloff East Honin Road),preview→become mage(class set, skill points 5→25), then BFS-navigated to the sorceror hall (enter sorceror halloff East Wayward Avenue),preview→become sorceror(subclass set, skill points →31, alignment flipped to Godly, title updated to "novice sorceror").spells/skillsboth rendered correctly afterward (amissileattack spell newly available, full skill-point table). No separate admin-only shortcut command for class/subclass assignment was found — greppedcmds/creator/for aset-style utility and found only a generic environment-variableset(unrelated); the only path to a class/subclass in this lineage is thebecomecommand inside the relevant hall, whether run by a mortal or (via a wizard's genericforce) an admin. Documented honestly rather than guessing at a shortcut that doesn't exist. quit,debug.loggrep, reconnect after a real gap — 3 independent passes, specifically to re-verify §8.22 (found during onboarding) holds for an account other than the one onboarding tested: (1) same-session quit+immediate reconnect — correct password accepted, full state (class/subclass/HP/money/skills) restored, zero newdebug.loglines; (2) killed and rebooted the native driver entirely (picking up themonument.lpc/statue.lpcfix), reconnected — same clean result; (3) after that reboot, left one idle connection open for the full ~220-second long-sit window (below), THEN reconnected a real ~5 real-minutes-elapsed gap later — password accepted, full state restored again, zero newdebug.loggrowth across the entire boot+idle+reconnect+quit cycle (debug.logline count identical before and after). This independently reconfirms §8.22's fix is not an artifact of the one account onboarding happened to test.- Shop/economy: the weaponsmith shop (
enter weaponsmith shopoff Ganthus Road) correctly lists its repair-only service viaread sign(100 gold/level of disrepair — nolist/buyinventory verb, a repair-only shop by design, not a bug); the inter-city coach fare system (above) is a real, working economy transaction (newbie-tier fare correctly waived, gold unchanged) — a full paid transaction (mid/elite fare, or a buy-from-peddler transaction withRejik, whosereset()-gated appearance insquare1didn't line up with this pass's timing) was not reached; flagging this as budgeted, not fully exercised, per the project's own explicit fallback for shop/economy coverage. - Death/respawn: not verified live this pass — time-budgeted out in favor of the long-sit watch and the 3-way reconnect re-verification above, both judged higher-value given this lib's already-known restore-path history. Flagging honestly as unverified rather than silently skipping it.
- Long-sit boot watch (§10.0, native-driver equivalent): no WASM build exists for this lib yet (§ WASM status below), so used the native equivalent — rebooted fresh (with the
monument.lpc/statue.lpcfix applied), opened one idle raw-socket connection, and sat through a full ~220-second window without logging in, while a wanderingerrand boyNPC's heart_beat continued triggeringreset()on the (now-fixed) cemetery room in the background. Zero newdebug.logentries during the entire window — confirms the fix above actually closed the only lazily-triggered failure this pass found, and surfaced no others.