Genesis MUD - PL version (Arkadia)

✅ 可玩

Arkadia

arkadia

更新 24761aa 2026-10-28 源码 下载 ZIP 上游 84rn/lpmud

▶ 开始游玩 · Play Now

Polskojęzyczna lokalizacja/fork mudliba silnika Genesis (CD gamedriver), tego samego, na którym oparty jest już włączony do tej kolekcji `genesis` (oryginał angielski) -- pierwsza pozycja w tej kolekcji w języku innym niż chiński, angielski czy niemiecki. Standardowy fantastyczny świat w stylu silnika CD, z własnym, charakterystycznym dla tej lokalizacji wymogiem przy tworzeniu postaci: nowo przybyła dusza musi samodzielnie podać odmianę własnego imienia przez wszystkie 6 polskich przypadków (mianownik/dopełniacz/celownik/biernik/narzędnik/miejscownik), a standardowe angielskie komendy duszy zostały w pełni zastąpione polskimi odpowiednikami (`spojrz`/`sp`, `zakoncz`, `stan`, `nagraj`, `haslo`). Świeżo zarejestrowana postać trafia jako bezcielesny duch do kamiennej sali na planie półkola, otoczonej pięcioma milczącymi posągami trzymającymi płonące pochodnie, z tajemniczym portalem pośrodku -- dotknięcie posągu wybiera rasę (ogr, halfling, człowiek, krasnolud lub elf), a w sąsiedniej galerii o kopulastym sklepieniu bezwłosy rzeźbiarz pyta o płeć, wzrost, budowę i dwie cechy wyglądu, po czym lepi z gliny figurkę na twoje podobieństwo; po jej dotknięciu przyjmujesz jej postać, a przejście przez portal daje prawdziwe ciało i przenosi do lokalnej świątyni, w której zaczynają wszyscy nowi gracze. Źródło: <https://github.com/84rn/lpmud>.

English

A Polish-language localization of the Genesis/CD-driver mudlib engine family -- this collection's already-onboarded libs/genesis is the English original -- and its first non-Chinese/non-English-language entry. A standard fantasy setting in the CD-driver mold, with the localization's own distinctive twist on character creation: a new arrival must type out all six Polish grammatical cases of their own name (mianownik/dopelniacz/celownik/biernik/narzednik/miejscownik), checked for validity and re-confirmable during the first six hours of play, since other players' commands need to grammatically decline a target's name correctly. The standard English soul commands are fully replaced by Polish equivalents throughout -- spojrz/sp to look, zakoncz to quit, stan for a status/score sheet, nagraj to save, haslo to change password -- so play reads as a genuinely Polish game rather than a translated skin over English verbs. A freshly-registered soul arrives as a formless spirit in a circular stone hall ringed by five silent statues, each holding a torch that casts the only light in the room, with a strange portal standing at the room's center and a passage leading off through the one flat wall; touching a statue chooses one of five races (ogre, halfling, human, dwarf or elf). Through the passage, in a domed gallery hung with sketches of noses, eyes and hair, a hairless clay sculptor asks whether you will walk the world as a man or a woman, how tall and how heavy you want to be, and which two features from its sketches you favour, then shapes a figurine to match; touch it and the world shrinks around you as you take the figurine's place. Stepping through the portal back in the hall then gives you a real body in the local temple where every new player starts.

README

Ciekawostki

Konto administratora / Admin account

Status

Czysty rozruch: wszystkie 92 pliki z listy preloadu ładują się poprawnie. Pełna rejestracja nowej postaci, gra podstawowymi komendami oraz ponowne logowanie po restarcie sterownika zweryfikowane end-to-end. Brak jakichkolwiek wychodzących połączeń sieciowych. Pełne szczegóły w NOTES.md.

WASM: zweryfikowano (wasm_status: playable). Pełna rejestracja przez standardowy webowy terminal tego projektu (nazwa, hasło x2, odmiana imienia przez 6 przypadków, e-mail) kończy się dokładnie tak samo jak na natywnym sterowniku -- postać trafia do sali wyboru rasy i poprawnie wykonuje spojrz/stan. Przy okazji znaleziono i naprawiono jeden prawdziwy, ogólny błąd (nie specyficzny dla WASM): w drzewie players/ brakowało 24 z 26 katalogów na literę (zostały tylko f/ i r/, jedyne zawierające prawdziwe zapisy), przez co każda nowa postać o imieniu na inną literę nie mogła się zapisać. Naprawiono, dodając puste znaczniki .gitkeep do brakujących katalogów. Pełne szczegóły w NOTES.md, § 9.

Uruchomienie lokalne

cd libs/arkadia
~/src/fluffos/build-debug/src/driver config.fluffos

Port gry: 40244.

NOTES · 移植与修复记录

Arkadia (Genesis MUD - PL version) -- porting notes

Source: git clone https://github.com/84rn/lpmud (commit 4be73fa8167a17c246c6bf22a4f528a4b45edd40, cloned 2026-08-26). Slug arkadia (short, avoids the generic "lpmud"), number 942, port 40244.

0. What this repo actually is

A Polish-language localization/fork of the same Genesis/CD-driver mudlib engine already onboarded in this collection as libs/genesis -- this collection's first non-Chinese/English/German-language entry. The archive ships two config variants side by side: config/sys/local.h (the active Polish config) and config/sys/local.h.Genesis (a reference copy of the original English config, with wizard names like "postmaster"/"mrpr"/ "fatty"/"lars" and domain "Genesis" instead of "Standard"), which by itself confirms this is a real derivative, not an independently-authored mudlib.

Encoding: the task brief assumed ISO-8859-2/CP1250 (the classic Polish DOS/Windows encodings) and instructed verifying empirically rather than assuming. The archive is actually plain ASCII: every Polish diacritic (a/c/e/l/n/o/s/z/z with their accents) is written out unaccented throughout -- source comments, in-game text, help files, *and* the game's own input-validation code (e.g. wlasciwe_imie() only accepts a-z). The default GB18030 convert_lib.sh pass was therefore already correct; no re-encoding was ever needed.

1. Boot bridge (same fix as genesis)

Identical CD-driver-derived boot sequence to genesis: a custom start_boot()/preload_boot()/final_boot() chain in secure/master.lpc that FluffOS never calls on its own. Bridged with the same epilog() pattern already proven in libs/genesis/work/secure/master.lpc:

mixed
epilog(int eflag)
{
    string *prefiles;
    int i, n;

    prefiles = start_boot(0);
    n = sizeof(prefiles);
    for (i = 0; i < n; i++)
        preload_boot(prefiles[i]);
    final_boot();
    return 0;
}

Also needed valid_override(string file, string name, string main_file) { return 1; } in master.lpc (std/living.lpc's efun::command(cmd) call requires it) and #undef ALWAYS_APPLY in config/sys/local.h (bypasses the human-review "podanie" application gate for local/solo testing -- matches this project's standing precedent, AGENTS.md 1.3e, and the archive's own local.h.Genesis alternate which ships the same way).

2. CD-driver -> FluffOS dialect sweep

Same catalogue of fixes as every other CD-driver-family lib in this collection (genesis, wxddym, shenmo, etc.):

3. New-to-this-port bugs (beyond the standard catalogue)

4. Registration flow -- Polish grammatical-case declension

New characters must type out all 6 Polish grammatical cases of their own name (mianownik/dopelniacz/celownik/biernik/narzednik/miejscownik), validated (a-z only, length >= 3) with a re-confirmation window in the first 6 hours of play -- a genuine, intentional localization feature, not a bug. Standard English soul commands are fully replaced with Polish equivalents (spojrz/sp for look, zakoncz for quit, stan for score, nagraj for save, haslo for password); the old English names show "deprecated" messages. Password policy requires >=6 chars, at least one non-letter, and must both start and end with a letter -- the task's mandated seed password Mud@2026 fails this (ends in a digit); used Mud@2026x instead for the seeded admin account (see section 6).

5. Known content gaps (pre-existing, not FluffOS-related -- documented,

not fixed, per this project's driver-bugs-only scope)

Both confirmed via direct code reading, not guesswork:

1. Every new character's GP_EMAIL ghost-flag bit never gets cleared after ghost_player.lpc's own ask_player() already collects email inline (GP_NEW sets GP_BODY|GP_EMAIL|GP_FEATURES|GP_SKILLS and nothing in the registration path ever clears the GP_EMAIL bit alone). query_default_start_location() checks GP_EMAIL *first*, so every new character's very first arrival gets routed through d/Standard/login/email.lpc, a room whose enter_inv() re-triggers a second, near-identical copy of the same declension+email Q&A (email.lpc has its own independent ask_player()/next_query()/ q_odmien_*() functions, byte-for-byte-similar to ghost_player.lpc's). Confirmed via server-side instrumentation (temporary log_file() calls in ask_player(), since removed) that ghost_player.lpc's own ask_player() really does fire only once per registration -- the duplicate text is genuinely a second, separate function in a different file, not a double-invocation bug. email.lpc's own end_query() *does* clear GP_EMAIL once completed, so this is a one-time, self-resolving, non-crashing redundant prompt on a character's first arrival, not an infinite loop or persistent problem. 2. (WRONG, corrected 2026-10-05: the pipeline works, see the dated section at the end.) The "become an embodied player" pipeline appears incomplete/unreachable as shipped. sala.lpc (the race-choosing hall) offers dotknij <race> (touch a race statue, calls set_race_name() immediately) then przejdz przez portal (enter the portal), which is supposed to call gotow() -> ghost_ready() (clones the real race body, hands over a "declension correction" item, exec()s the connection to it). But: - portal()'s own precondition is this_player()->query_ghost() == 0 (den ies with "you still need a body first" otherwise) -- yet nothing anywhere in the whole tree ever clears the GP_BODY bit (grepped for ~GP_BODY and any GP_BODY-clearing assignment; only two sites *set* it, none clear it), so this precondition can never become true through the coded dotknij() path. - gotow() (the function that actually performs the embodiment) has zero callers anywhere in the codebase -- it's dead code as shipped. A character can register, log in, save/reconnect across a driver restart, and use basic ghost-level commands (spojrz, stan, kto, etc. via the ghost command souls soul_cmd_ghost/misc_cmd_ghost), but never actually leaves "ghost" status through normal play. This also means wizard-only command souls (granted only via a real embodied player's own start_player(), never a ghost's) are unreachable even for an account with keeper rank in m_wizards -- see section 6.

6. Admin account bootstrap

Per this project's standard practice, root is already occupied by the archive's own real archived save (players/r/root.o.backup, an elf character with real history) and was left untouched. Seeding a fresh fluffos admin account needed a two-step bootstrap because of a chicken-and-egg problem in secure/login.lpc's new_character(): it refuses to let a brand-new mortal register any name for which SECURITY->query_wiz_rank(name) is already nonzero ("this name once belonged to a wizard and was not properly released"). Listing fluffos in DEFAULT_WIZARDS *before* it had ever registered would have made it permanently unregistrable through normal play.

1. Registered fluffos as an ordinary mortal via the normal nowa flow (password Mud@2026x -- see the password-policy note in section 4), while config/sys/local.h's DEFAULT_WIZARDS/DEFAULT_DOMAINS still only listed root/wiz. Player file created at /players/f/fluffos.o. 2. Added "fluffos":({9,50,"root","Wiz","root",}) to DEFAULT_WIZARDS (keeper rank 9, matching root) and "fluffos" to the "Wiz" domain's member list in DEFAULT_DOMAINS, then removed the (by-then-regenerated) syslog/KEEPERSAVE.o again so load_fob_defaults() re-populated with fluffos included, without touching the already-separate /players/f/fluffos.o player file.

Login as fluffos/Mud@2026x shows the keeper-only "Mistrz" title on the kto (who) listing, confirming query_wiz_rank() recognition works. Exercising actual privileged wizard *commands* is blocked by the unreachable-embodiment gap in section 5.2 (wizard command souls are never granted to a still-ghost character regardless of rank) -- this is a content gap inherent to the archive, not something specific to the admin account or to this port.

For testing purposes only (not a mudlib code change), fluffos's own saved is_ghost flag was hand-edited from 30 (GP_NEW) to 26 (clearing just the GP_EMAIL bit) in /players/f/fluffos.o to stop the redundant email-room detour described in 5.1 from re-triggering on every reconnect during testing; GP_BODY (and therefore the embodiment gap in 5.2) was left as-is since there is no reachable in-game path that would set it differently for a real player.

7. Verification performed

- Multiple full driver restart-and-reconnect cycles performed over the course of testing (this satisfies AGENTS.md 7.120), including reconnecting into a previously-registered character across a restart with save data intact (confirmed via Ostatnie logowanie/"last login" banner and imiona/mailaddr fields surviving in players/f/fluffos.o and other test characters' save files).

8. Deep functional test (round two) -- 2026-08-27

One continuous session per AGENTS.md §10.7: read ?wprowadzenie/ ?trening first, registered multiple real Polish characters through the full flow (name/password/6-case declension/email), exercised spojrz/stan/inwentarz at every state change, tested zakoncz (quit) with a debug.log grep before and after, and reconnected both within the same driver process (to exercise the still-live "revive" code path) and after killing and restarting the driver (to exercise a genuine cold restore). Admin login re-verified: fluffos/Mud@2026x still authenticates and shows the keeper-only "Mistrz" title.

Four new, previously-undetected, live-reproduced bugs found and fixed this pass -- all invisible to the original onboarding's shorter smoke test for the same reason every §10.7 bug is: none of them can surface without either a long wall-clock wait, a genuine abrupt disconnect, an actual quit, or a look at a room with no dynamic content, none of which a boot-watch or a brief registration walkthrough exercises.

8.1 do_decay() map()-over-mapping argument mismatch (AGENTS.md §7.132)

secure/master/fob.lpc's decay_exp() (m_domains = map(m_domains, do_decay);, called from check_memory() on a ~900-second reset_master() alarm) crashed with *String index out of bounds every time the alarm actually fired, because do_decay(mixed *darr) only declares ONE parameter but this driver's map() over a MAPPING always calls the function with (key, value) -- so darr silently bound to the domain NAME (a string), not its data array. Caught live on a real boot: the very first reset_master() tick after boot crashed with the trace showing the string "Standarc" -- a byte-by- byte corrupted "Standard", decremented one character at a time by do_decay()'s own arithmetic running against string bytes instead of array elements, right up until an index walked past the string's length. Fix: do_decay(mixed *darr) -> do_decay(string dname, mixed *darr). Verified live: after the fix, a full driver restart and a second real 900+ second wait produced ZERO do_decay/fob.lpc crashes in debug.log (confirmed by letting the final verification driver run past the alarm interval before killing it -- see the verification section below).

Sibling check: libs/genesis (the English-language ancestor this port is a fork of) has the byte-identical bug in its own secure/master/fob.lpc. Fixed there too; not exercised through a real 900-second alarm on that repo (it ships no domain content, so m_domains never accumulates real decay-able data), verified only via a boot-and-kill compile check. See libs/genesis/NOTES.md.

8.2 Missing net_dead() boot bridge + a companion type-mismatch crash (AGENTS.md §7.133)

The single most impactful finding this pass. secure/master.lpc implements remove_interactive(object ob, int linkdied), documented as "Called from GD if a player logs out or goes linkdead" -- the classic-driver convention of the game driver notifying the MASTER object of every disconnect. This driver does no such thing: its own disconnect teardown (src/comm.cc) calls a net_dead() apply directly on the DISCONNECTING PLAYER OBJECT, with zero arguments, and ONLY when the object hasn't already been destructed (an orderly quit already destructs itself first, so the apply never fires for a clean quit -- only for a genuine abrupt disconnect). A codebase-wide grep found zero net_dead references anywhere in this mudlib: every single abrupt disconnect was a complete, silent no-op. Confirmed live via debug_message() instrumentation (since removed) that remove_interactive() was NEVER once invoked across multiple raw socket-close-and-reconnect cycles pre-fix.

The downstream symptom that led to this: reconnecting to a disconnected character reported "Straciles polaczenie na 20692 dni 14 godzin ... sekund" ("You lost your connection for 20692 days...") -- time() - query_linkdead() computed against a query_linkdead() that had never once been set (defaulting to 0, the Unix epoch), followed by "Couldn't locate the location where you link died. Moving you to your start location.", since the statue-conversion mapping (d/Standard/obj/statue.lpc's places[ob]) was never populated either.

Fix, added to std/player_sec.lpc alongside this codebase's own linkdie()/revive()/actual_linkdeath():

nomask void
net_dead()
{
    SECURITY->remove_interactive(this_object(), 1);
}

Verified live via debug_message() tracing (confirmed the apply now fires on a raw socket close) and via observed behavior change: before the fix, a disconnected character's object was silently abandoned in memory forever (still alive, still not destructed, no cleanup of any kind attempted); after the fix, remove_interactive() now genuinely runs every time.

A second, closely-related crash surfaced once this bridge started working: d/Standard/obj/statue.lpc's revive() declares object roomob;, and its own fallback path (reached when the original link-death location can't be found) did roomob = ob->query_default_start_location(); -- a function that returns a STRING, not an object (exactly like this same function's OTHER, correctly-handled stringp(room) branch a few lines above, which correctly resolves it via find_object()). Assigning a string straight into a strictly-typed object local threw *Trying to put string in object uncaught, aborting revive() before it ever reached the actual move_living() call or the places[]/alarm cleanup at the end of the function. Fix: resolve start_loc through find_object() (with the same lazy-compile retry the sibling branch above it already uses) before the assignment.

Honest caveat on live verification depth: this mudlib's own "become an embodied player" pipeline is unreachable as shipped (see §5.2 above, a pre-existing, out-of-scope content gap, unchanged by this pass) -- every test character, including the seeded admin account, remains permanently classed as /d/Standard/login/ghost_player, which is ALSO this codebase's own LOGIN_NEW_PLAYER constant (the throwaway swap-dummy class used transiently during login handoff). remove_interactive()'s own first guard (if (master_ob == LOGIN_OBJECT || master_ob == LOGIN_NEW_PLAYER || ...) { ob-> remove_object(); return; }) therefore ALWAYS takes the "just discard, no linkdeath tracking" branch for every character in this snapshot -- by design, correct for a not-yet-embodied ghost, but universal here only because of the separate embodiment gap. This means: the net_dead() bridge fix itself IS fully live-verified (confirmed via tracing that it now fires, and that remove_interactive() now genuinely runs instead of doing nothing), but the deeper linkdie()/actual_linkdeath()/statue-conversion/revive() chain (including the roomob type-mismatch fix) could NOT be exercised end-to-end through real play this pass, since no test character can ever leave ghost state to take that branch. Both fixes are verified via direct code reading, a clean compile, and a clean boot; the revive() fix specifically mirrors an already-proven-correct pattern two lines above it in the same function. A future pass that either fixes the embodiment gap or synthesizes an embodied test object directly (e.g. via a temporary eval-equivalent, not available here since wizard command souls are equally gated behind embodiment) should re-verify the full chain live.

8.3 Uninitialized room_descs breaking every room's look (AGENTS.md §7.134)

std/room/description.lpc's room_descs (a per-room list of extra descriptions dynamically contributed by present items via add_my_desc()) was declared nosave mixed room_descs; with no initializer. long() -- the function that runs on literally every single look/glance at any room -- unconditionally opens with while ((index = member_array(0, room_descs)) >= 0) { ... }, and this driver's member_array() requires a real string or array for its second argument; called against a bare 0 it threw *Bad argument 2 to member_array() Expected: string or array Got: 0 uncaught, aborting long() immediately -- before ever returning the room's own already-fully-built flavor text (sitting one local variable away) or letting the caller append the exit list. Since add_my_desc() is an opt-in feature only a minority of items ever call, this crashed on essentially every look at every ordinary room, game-wide, from the very first boot -- reproduced live: pre-fix, spojrz in the starting hall (d/Standard/login/sala) printed only the bare room path (/d/Standard/login/sala) and nothing else, no flavor text, no exit list.

Fix: nosave mixed room_descs; -> nosave mixed room_descs = ({});, fully behavior-preserving (verified against add_my_desc()'s own if (!room_descs) ... else room_descs = room_descs + (...) logic, which produces an identical result starting from ({}) as from 0 regardless of whether an empty array is itself truthy or falsy on this driver). Verified live: after the fix, spojrz in the same room prints the full flavor text AND "Jest tutaj jedno widoczne wyjscie: poludnie.", both on first arrival and on every repeat look; confirmed across two different rooms (sala and its southern neighbor).

Sibling check: libs/genesis has the byte-identical bug in its own std/room/description.lpc. Fixed there too (not live-exercised on that repo -- it ships no domain content -- verified via a boot-and-kill compile check only). See libs/genesis/NOTES.md.

8.4 query_list_temp_start() missing its siblings' lazy-init guard, breaking quit() entirely (AGENTS.md §7.135)

The textbook bxsj-style silent quit crash this project's own §10.7 methodology was written around. zakoncz (quit) looked completely normal pre-fix -- a bare prompt with no error -- but debug.log showed std/player/cmd_sec.lpc's quit() crashing uncaught inside its own check_recover_loc() call with *Bad type argument to +. Had int and array, meaning quit() aborted before ever reaching save_me() or the player's actual removal from the game: the character was silently NEVER saved and NEVER removed on every single quit, on a fresh boot, until some other code path happened to touch temp_locations first.

Root cause: secure/master.lpc's temp_locations global has three consumer/mutator functions that all correctly lazy-default it (check_temp_start_loc(), add_temp_start_loc(), remove_temp_start_loc(), all doing if (!temp_locations) temp_locations = TEMP_STARTING_PLACES;) -- except the plain query function, query_list_temp_start(), which just returned secure_var(temp_locations) with no guard. Nothing in a normal login path calls any of the guarded functions (only a rare explicit temporary-start-location override does), so temp_locations stays a raw, never-assigned 0 for the life of a fresh boot. sibling def_locations/query_list_def_start() happens to be safe only because enter_game() unconditionally calls check_def_start_loc() (which DOES have the guard) as an unrelated side effect on every login -- check_recover_loc()'s SECURITY->query_list_temp_start() + SECURITY->query_list_def_start() therefore always combined a raw 0 with a real array, crashing every time.

Fix: added the identical guard to query_list_temp_start(), and defensively to query_list_def_start() too (since its own safety was accidental, not guaranteed). Verified live end-to-end on the fluffos admin account: zakoncz now prints "Nagrywam postac." and completes cleanly (zero debug.log errors), and a subsequent reconnect shows the correct, just-updated "Ostatnie logowanie" timestamp and host ("Cz, 27 VIII 2026, 07:56:24 z hosta: localhost", replacing the stale "Sr, 31 XII 1969, 16:00:00" default every account had shown in every earlier test this session, itself evidence this bug had silently prevented a real quit-save from ever succeeding before).

8.5 Minor: dangling alarm on a destructed login-flow helper object (not in AGENTS.md -- low severity, single instance)

d/Standard/login/set_cechy.lpc (a transient "/wybieracz/" helper clone driving the trait/appearance-selection Q&A through a chain of self-rearming set_alarm(..., (: akcja :)) calls) could be destructed (several remove_object() call sites in the file) while one of its own alarms was still outstanding, producing *Owner (.../set_cechy#N) of function pointer is destructed uncaught the next time that alarm fired -- cosmetic only (a stopped typewriter-reveal effect on an object that no longer exists, logged once, no gameplay impact, does not accumulate), but a genuine dangling-timer bug. Fix: added a remove_object() override that calls remove_alarm(alarm_id) before deferring to ::remove_object(), closing every one of this file's several destruction paths through one choke point.

Left unfixed, documented only: an apparently-identical shape was also observed once for /secure/login#N (*Owner (/secure/login#13) of function pointer is destructed", same __alarm_fire() site). secure/login.lpc already carries the SAME lazy-cleanup idiom correctly at roughly a dozen call sites (remove_alarm(time_out_alarm) before nearly every handoff/exit point) -- this looks like a single narrow edge case in an otherwise carefully-guarded state machine, and given the low (cosmetic-only) severity plus the risk of a subtle regression in a heavily-alarm-managed login flow I did not have time to fully trace this session, it was left as an honest observation rather than a guessed fix. Worth a closer look in a future pass if it recurs.

8.6 Eight standing cross-cutting patterns (§7.121/§8.3a/§7.122/§7.123/§7.124/§7.126/§7.129/§7.130) -- all checked systematically, confirmed clean

8.7 Shop/economy/combat/guild -- still unreachable, unchanged from onboarding

Confirmed again this pass, not newly investigated: the pre-existing "become an embodied player" gap (§5.2 above) still blocks every real gameplay system gated behind embodiment. A fresh registration this pass reached only the race-selection ghost-state rooms (sala.lpc and its unnamed southern "gallery" neighbor -- both now showing full descriptions thanks to the §8.3 fix above), where stan/inwentarz both correctly respond "To nie jest mozliwe w tym miejscu." -- ghost- state command restrictions, not a bug. Shop/economy, combat, and guild/ skill acquisition remain explicitly UNVERIFIED this pass (stated honestly per this project's own testing standard), same root cause as originally documented, not something this pass's driver-bugs-only scope permits fixing.

8.8 Verification summary

9. WASM packaging + boot verification (2026-09-01)

Per AGENTS.md §1, ran scripts/wasm_client.js against ~/src/fluffos/build-wasm/src (the project's shared, already-built WASM driver) with the exact registration flow documented in §4/§7 above (nowa -> name -> password x2 -> 6-case declension Q&A -> email -> arrival), same as the native transcripts.

One real, previously-latent bug found and fixed, affecting BOTH native and WASM (not WASM-specific): players/ only shipped the two letter buckets that happen to contain real save files (f/ for the seeded fluffos admin, r/ for the archive's own archived root.o.backup). Section 3's "created the remaining 25 letter directories" note from the original onboarding pass never actually persisted, because git does not track empty directories -- once that session's shell-created mkdirs were left with nothing to commit, the fix silently reverted itself on the next fresh checkout. Symptom: any new character whose name starts with a letter other than f/r fails to save (*Could not open /players/<letter>/<name>.o.tmp for a save, std/player_sec.lpc:625), which cascades into ghost_start() never placing the character in a room (environment() returns 0), which in turn crashes the very first spojrz/look with *Bad argument 1 to EFUN call_other() in do_glance(). This is a real, general registration blocker, not a content gap or a WASM-sandbox artifact -- confirmed the same missing directories are absent from the native work/ tree too. Fixed properly this time: created all 24 missing single-letter directories (a-z minus f/r) each with an empty .gitkeep file (the convention already used elsewhere in this project, e.g. libs/openlib/work/u/p/.gitkeep) so they survive as real git blobs and get copied into both a fresh native checkout and the WASM MEMFS copy pack_lib_for_web.sh/wasm_client.js build for every future run.

After that fix, a full WASM registration (testarkb, matching the declension pattern used elsewhere in this file) completed cleanly and reached the exact same place the native transcripts in §7/§8 describe: the redundant second declension Q&A fires once (§5.1, confirmed still present under WASM too, same self-resolving non-bug), then the character lands in the sala.lpc race-choosing hall with its full room description, where stan correctly answers "To nie jest mozliwe w tym miejscu." -- identical to the native ghost-state restriction documented in §8.7, not a WASM regression. zakoncz (quit) printed "Nagrywam postac." and the connection closed cleanly, same as native.

Conclusion: WASM boots and plays identically to the already-verified native driver, including reproducing the same documented, deliberately-unfixed content gap (no reachable path out of ghost status, so combat/shop/guild remain unverified/unreachable under WASM for the same reason they are under native -- see §5.2/§8.7). No WASM-specific blocker of any kind was found; the one real bug (missing players/ letter directories) was a general infrastructure gap that happened to surface first here because this was the first full, from-a-fresh-checkout registration test with a name outside f/r. Checked precedent before picking wasm_status: of the ~234 libs already classified, 233 are "playable" and exactly one (zjdyzj) is "limited" -- and that one lone "limited" case is "limited" for a purely technical reason unrelated to content depth: its logind.lpc gates every connection behind a custom crypt-challenge mobile-client handshake that this project's generic telnet-style web terminal cannot compute automatically, so an ordinary site visitor can't even get past the FIRST prompt without an external tool. By contrast, several other libs with severe, code-confirmed content gaps at least as deep as arkadia's -- nitan6 (combat never applies real damage at all), kxkj (a shared-file bug permanently corrupts room exits over uptime), zsdsj, bmxkx2001, and many more across this collection's NOTES.md -- are all still classified "playable", because the standard login/registration/explore loop works end to end through the ordinary web terminal; the gap is something a player runs into DURING play, not something that blocks the standard site experience from ever starting. Arkadia's case fits that same pattern, not zjdyzj's: the generic web terminal completes the ENTIRE documented registration flow with no special tooling, reaches a live, responsive > prompt, and correctly executes ghost-level commands (spojrz, the room description, the ghost-state-restriction response from stan) -- exactly the "playable" bar this collection has consistently applied elsewhere. The embodiment gap is therefore recorded as a documented content limitation (per §5.2/ §8.7 above and in the README/meta.json description) rather than expressed via a "limited" status, matching how this project has classified every other lib with a comparably severe in-play content gap. wasm_status set to "playable".

Test characters (testarka, testarkb) never touched the real on-disk players/ tree at all -- wasm_client.js copies the lib into an in-process MEMFS filesystem per run and all writes (including character saves) land only there, discarded when the Node process exits. Only the newly-added .gitkeep placeholders and the pre-existing fluffos/root.o.backup files are present in players/ after this pass.

深度功能测试(§10.7,2026-10-04)— negative range ends

scripts/lpc_fix_negative_ranges.py: 37 line(s) in 9 file(s) count a range from the end with < (x[a..-1] -> x[a..<1], x[-2..] -> x[<2..]; KB 06 §7.209). In this driver a negative constant end gave "" / ({ }) and a negative start the whole value, so each of these returned the wrong slice; the compile warning A negative constant as the second element of arr[x..y] is gone from the files that compile. Range lvalues (s[0..-1] = text, the prepend idiom) are left alone. A paired compile of the changed files at HEAD and in the working tree showed no new error.

深度功能测试(§10.7,2026-10-05)— 主控 author_file()/domain_file()

驱动的 mudlib_stats 包在主控载入时各调用一次 author_file(<主控文件>) 和 domain_file("/")。本库主控没有这两个 apply,所以每次启动都打印 author_file() in the master file does not work, using root_uid as fallback 和 domain_file() in the master file does not work, using bb_ui as fallback 两行,网页版每位访客的终端里都看得到。secure/master.lpc 补上了这两个 apply:作者返回 get_root_uid(),域返回 get_bb_uid(),正是驱动缺少它们时所用的值。域名等于 backbone 域时,驱动让对象沿用创建者的域,与没有这个 apply 时相同(KB 06 §7.222)。本库保留上游代码风格(几乎所有文件都未经 §9 格式化),所以只插入代码,不格式化。用 lpcc config.fluffos /nonexistent.lpc 前后对比,主控载入段只少了这两行。

深度功能测试(§10.7,2026-10-05)— 巫师命令魂、化身流程、CD 的 map/filter 语义

1. 巫师命令魂从未载入。 cmd/wiz/apprentice{,/files,/communication,/people}.lpc、cmd/wiz/normal{,/files}.lpc、cmd/wiz/mbs.lpc、secure/mbs_central.lpc、cmd/std/tracer_tool.lpc 编译失败(启动时 29 个错误)。之前 §7 说它们是"与移植无关的原有语法错误",实际全是 CD 驱动的写法:偏应用与组合(&operator(==)(x) @ &operator([])(, F)、&f(, a))、@ 被词法器当作 here-document 开头(End of file in text block)、(: f :) @ (: g :)、字符串 case 区间 "0".."9"、保留字 new 作参数名、mixed *data 存映射、string * 赋值缺显式转换。用 genesis 已移植的写法逐处改(scripts/lpc_cd_closures.py 改写组合链,局部变量用 $(...) 捕获;mbs 用 genesis 的 __field_eq_bound 等辅助函数)。现在启动 0 个编译错误,92 个 preload 全部载入。 2. 化身流程其实完整,§5.2 判断错误。 gotow() 由 sala.lpc 的 set_alarm(1.5, 0.0, (: gotow, this_player() :)) 调用,鬼魂状态由 set_cechy.lpc 的 set_ghost(0) 清掉。流程:大厅 dotknij czlowieka → 往南的画廊等雕塑者提问(odpowiedz mezczyzna、身高、体型、wybierz 两项特征)→ dotknij figurki → 回大厅 przejdz przez portal → 进入 /d/Standard/start/church 成为真正的玩家。管理员 fluffos 已按此流程化身(人类),存档已提交,所以巫师命令(tree、ls、mbs、Dump、whichsoul)登录即可用,已逐个实测。 3. CD 与 FluffOS 的 map/filter 语义差异(KB 06 §7.223)。 FluffOS 对映射调用函数时传 (key, value),CD 只传 value。secure_var() 因此把每个映射变成 key:key,lib/cache.lpc 的每次读取都被破坏(mbs 第二次运行报 Trying to put string in int)。secure/simul_efun.lpc 加了 CD 语义的 map/filter 覆盖(映射按 value 调用,数组和字符串交给 efun),sefun 自身里的 secure_var 用 (: secure_var($2) :)。 4. players/mbs_save/<字母>/ 不存在,mbs 存档报 Wrong permissions;补了 26 个 .gitkeep。cmd/std/tracer_tool.lpc 的 member_array(flag, vars) > 0 原样保留(原代码行为)。 5. 仍有:化身时日志一行 Owner (/d/Standard/login/ghost_player#N) of function pointer is destructed(鬼魂对象被替换后它的定时器还在),流程不受影响;新编译的文件带进了本库原有的警告类(nosave 函数、CD 的 #pragma),归入警告清理。

深度功能测试(§10.7,2026-10-05)— set_alarm 闹钟按对象归属

secure/simul_efun.lpc 用一张全局表模拟 CD 驱动的 set_alarm()。get_all_alarms() 返回所有对象的闹钟,而 std/object.lpc 的 reset() / enable_reset() 会先删掉列表里所有名为 reset 的闹钟再排自己的,结果任何一个对象 reset 都会取消其他所有对象的 reset,房间实际上不再重置(NPC、物品不刷新)。用 lpcc 载入两个房间验证:改前两个房间看到同样 5 个闹钟、只剩一个 reset;改后各自只有自己的 reset。现在每个闹钟记录 previous_object() 为主人,get_all_alarms() / get_alarm() / remove_alarm() 只作用于调用者自己的闹钟,返回 CD 格式;主人已销毁的闹钟到期时直接丢弃(KB 06 §7.224)。化身时那行 Owner (/d/Standard/login/ghost_player#N) of function pointer is destructed 也随之消失(鬼魂销毁后它的闹钟被静默丢弃)。

深度功能测试(§10.7,2026-10-05)— 带种子的 random、set_alarm 字符串形式

secure/simul_efun.lpc 的 random(range, seed) 原来收下种子却忽略它;CD 驱动对同一种子给同一个数,cmd/live/state.lpc 的比较/估价依赖这一点(KB 06 §7.225),现在对种子做固定散列。set_alarm() 接受 CD 的完整形式 (float, float, function|string, args...):本库 20 处用函数名字符串加参数(如 cmd/wiz/keeper.lpc 的 set_alarm(3.5, 0.0, "chor_cd", ++faza, wizowie)),原来的模拟只收函数指针(KB 06 §7.224)。编译警告清理见下一节。

深度功能测试(§10.7,2026-10-05)— 编译警告清理,以及被警告掩盖的 #include 权限问题

1. 编译警告:启动时 25 条 → 0;整树扫描 1650 条诊断 → 380 条。剩下的是被单独编译的 #include 片段(cmd/wiz/apprentice/*、cmd/wiz/normal/files、secure/master/*、std/living/*),以及 doc/examples/ 里没移植到本库波兰语接口的英文示例(set_adj、set_short 等未定义,属内容缺口)。scripts/lpc_warnings.py arkadia --fix:593 个 nosave 函数改 protected(被别处按名调用的 45 个去掉 nosave 保持 public)、删 335 行 CD 专用 #pragma、删 287 个未用局部变量;lpc_audit_removed_locals.py 复核 508 个被删声明,0 个需要处理。手工:#if 0/#ifdef 分支里才用到的局部变量移进同一条件的声明块(stats、move、description、cmdhooks、ctool、cbase、shop、soul_cmd、state、udp、siteban、death_mark、gameinfo_player、profile);master.h 的 add_wizard_to_domain、heart_beat、set_domain_bit 原型与定义对齐;两处嵌套注释;board 两个文件带行尾注释的 #pragma;receptacle 两个没用的 qvb = query_verb();spells.lpc 的 call_out 菱形继承写明驱动原本选用的定义;store_message.lpc(无人调用的旧文件)的本地 MAIL_READER 先 #undef。 2. 原作者的几个小错:cmd/live/things.lpc 和旧的 std/living/things.lpc 里 trop() 的 gBezokol == "tropic"; 是无效比较,trop() 之后也不读这个变量,删掉;doc/examples/org/room/cave1.lpc 一段注释少了 */,把 set_long(...) 整个吞掉,示例房间没有长描述,补上;tiger.lpc、energy_blast.lpc 的 how == "" 应为赋值(轻伤时本该不显示 "without effect")。std/leftover.lpc 重新声明了父类 food 的 decay_time/decay_alarm,两套变量本来就各管各的(leftover 覆盖了 set_decay_time,food 的腐烂流程对它不起作用),改名为 leftover_decay_time/leftover_decay_alarm 让这一点写在代码里;config/race/generic.lpc 的 com_sounds 同理改名 race_com_sounds(cmdhooks 的那个是 private)。 3. 被警告掩盖的问题(KB 06 §7.226)。 清完警告后启动时 /std/room、/cmd/live/state、/cmd/wiz/apprentice 载入失败:Cannot #include /d/Standard/login/login.h。驱动对每个 #include 调用 valid_read(file, 主控, "include");preload_boot() 载入每个文件前把主控的 euid 设成该文件的创建者(/cmd、/std 是 backbone),而 backbone 不能读未登记为域的 /d/Standard。以前能过,只因为每条编译警告都会调用主控的 log_error(),它顺手执行 set_auth(this_object(), "root:root")。valid_read 现在对 func == "include" 放行(players、binaries 仍然关闭),CD 驱动本来就不检查 include。genesis 的主控同样修了。 4. 验证:全新启动 0 警告 0 错误;fluffos 登录后 kto、tree、mbs、Dump me、finger fluffos、porownaj、i、ls /std、zabij、zakoncz 全部正常,驱动输出无警告、无 insufficient permission。

深度功能测试(§10.7,2026-10-08)— .lpc 后缀的定宽切片

.c 改名 .lpc 时只改了字符串没改切片宽度:f[<2..] == ".lpc" 拿两个字符比四个字符,永远不成立(!= 永远成立),按后缀筛文件、去后缀的代码因此从不运行或截成 x.l(KB 06 §7.238)。scripts/lpc_lpc_suffix_slice.py --apply 改了 2 处比较、0 处去后缀(如 cmd/wiz/normal/files.lpc);改动的文件 HEAD 与工作树分别加载(新进程),无回退。

Punctuation the conversion lost, put back (2026-10-19, KB 03 4.6)

1 file(s) lost a semicolon, comma, quote or the closing } at the end of the file and did not load. The file stopped one or two } short (its last byte or two went missing); appended: /lib/std_area/preamble.lpc. Loaded at HEAD and in the tree: all 1 were failing before, none regressed (scripts/lpc_restore_from_twin.py, lpc_fix_eaten_quote.py --comma, lpc_fix_eof_braces.py).

Old-driver type slack: missing arguments, untyped parameters, array initializers, class variables (2026-10-19, KB 04 6.19, 6.20)

MudOS filled the missing arguments of a call with 0, took an untyped parameter as mixed, never compared a declared type with its initializer and let a variable be named class; this driver refuses all of it at compile time and the whole object fails. 2 file(s) fixed: /doc/examples/org/mobiles/alchemist.lpc, /doc/examples/org/spells/spell_book.lpc (the repair rounds of scripts/lpc_round_files.py: zeros written out at the call, mixed for untyped parameters, string X = ({...}) given its star, void functions returning values, and class variables renamed pick_class). Loaded at HEAD and in the tree, per file: 0 of them failed before and load now, none regressed.

登录密码超过 255 字节:crypt() 抛错(2026-10-20,KB 06 §7.294)

驱动的 crypt() 对超过 255 字节的密钥直接报错(Error in crypt(), check your salt),老驱动则按任意长度散列。在登录提示符下输入 256 字节以上的密码,密码检查那一行就抛错,连线停在一个裸的 > 提示符上,登录走不完(password 指令的旧密码检查同样);用 300 个 x 当参数的扫描发现的。/secure/simul_efun.lpc 里补了一个同名的 simul_efun crypt(key, salt):只有超长的密钥才被截短(先截到 255 个字符,再逐字符截到 sizeof(to_buffer(key)) <= 255,限制按字节算,一个汉字占三个字节),再交给 efun::crypt();普通密码原样散列,已存的密码散列不受影响(scripts/lpc_add_sefun.py crypt)。

深度功能测试(2026-10-27,§6.25 glued inherit / 粘贴残片)

doc/examples/org/obj/small_beer:inherit "/std/drink" 缺 ;(补上)。/std/drink 本馆未随包,加载仍会缺基类。

深度功能测试(2026-10-27,§6.16 arkadia /std/drink)

档案未带 /std/drink,small_beer/dutch_beer 无法继承。补最小 drink(food 同形的 create_heap→create_drink + soft/alco),并对波兰分支已 #if 0 掉的 set_adj 做 dodaj_przym 垫片。