Ultimate Hell: Legend of Xuanyuan

✅ 可玩

终极地狱之轩辕传说

zhongjidiyu

🔑 fluffos / Mud@2026 更新 8d5ab4a 2026-09-04 源码 下载 ZIP

▶ 开始游玩 · Play Now

MUD 内部标识为 `hell.local`,属于 ES II 引擎系列,与 `es1_win`/`xkx2001`/`rzrmud` 等同属一支,master 文件署名一路写明 "for ES II mudlib" → "Annihilator" → "Xiang for XKX" → "Doing Lu for hell",是一款以"轩辕传说"为主题的武侠/仙侠向 MUD。压缩包自带的说明文件明确写着"这是供学习研究用的底层源码,不建议直接拿来架设正式对外服务器"——这份存档本身是一个"骨架版",只保留了新手村、死亡结算等少数区域,长安城、武当、少林等大部分门派/城市场景并未包含在这个压缩包里;新角色刚进游戏时属于"未出生"状态,需要先找水笙姑娘用 `register <邮箱>` 注册邮箱,再走一遍"投胎做人"流程选定资质属性才能正式踏入江湖。本项目里还有另外两个名字也带"终极地狱"字样的压缩包(`zjdyaryl`、`zjdyzj`),那两个属于"地狱"分支下的另一条独立血脉,与本作并非同一款游戏,三者内容互不相同,只是碰巧同名。

English

A Xuanyuan-legend-themed wuxia/xianxia MUD, internally identified as hell.local and part of the ES II engine family alongside es1_win/xkx2001/rzrmud in this collection, its master file's authorship trail running through 'for ES II mudlib' to 'Annihilator', 'Xiang for XKX', and 'Doing Lu for hell'. The archive's own bundled notes describe it as a stripped-down reference build 'for study purposes, not recommended for a public server' — only the newbie village and death-handling rooms are included, with the major sect/city zones (Chang'an, Wudang, Shaolin, etc.) referenced in code but absent from this package. New characters start 'unborn': they must first find the NPC Shuisheng to register an email with the register command, then go through a stat-rolling 'reincarnation' (投胎做人) ritual before actually entering the world. Two other archives in this collection also happen to carry 'Ultimate Hell' in their name (zjdyaryl and zjdyzj) — those belong to a separate branch of the 'Hell' lineage and are different games entirely, sharing only the coincidental title; all three have otherwise unrelated content.

README

内容亮点

在线试玩

https://mudlibs.fluffos.info/zhongjidiyu/

管理员账号 / Admin account

警告:这是一个公开的默认密码,仅供本地/浏览器试玩。正式对外开服前
请务必修改这两个密码。

本地运行

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

游戏端口:40072

NOTES · 移植与修复记录

zhongjidiyu — 终极地狱之轩辕传说 (Ultimate Hell: The Legend of Xuanyuan)

Archive: 终极地狱.rar (archive #78 of ~100). Port: 40072. Status: done (boots clean, full registration flow verified with two real Chinese names in separate continuous connections, post-login commands look/score/quit all confirmed producing correct real output).

What this is

Self-extracts to a nested revive/ root (not top-level) containing a raw readme (说明文件.txt, GBK-encoded, filename itself needed a manual re-encode pass after extraction — see "Extraction gotcha" below) that reads (translated): "This is the bottom-layer source code released by doing... released for study purposes, not for running a live server with." Live banner reads "终极地狱之轩辕传说" ("Ultimate Hell: The Legend of Xuanyuan"), MUD_NAME in the raw config is hell.local. adm/single/master.c's own header credits the full lineage: for ES II mudlib / original from Lil / rewritten by Annihilator (11/07/94) / modified by Xiang for XKX (12/15/95) / updated by Doing Lu for hell (2K) — this is the same "ES II" lineage already seen across ~20 prior libs (es1_win/esI/xkx2001/rzrmud/xo/ bmxkx2001/kxkj/yueyingqiyuan/wuhanzhan/haiyang2/ yanhuangwuhun/yhyxs/xuanjianlu/shenzhou/shenmo/ kxkj1/etc.), specifically closest in file layout (adm/single/{master,simul_efun}.c, adm/daemons/, adm/simul_efun/) to xkx2001(#25)/rzrmud(#23)/bmxkx2001(#45). securityd.c's own header credits "[email protected]" then "Modified by Xiang for XKX" then "Updated by DOing Lu for ULTRA HELL" — same chain. MudOS v22pre11-era target.

IMPORTANT — cross-check flagged for the main session: two OTHER archives sharing the "终极地狱" name are being processed concurrently by sibling agents in this same batch: archive #79 (终极地狱之爱若幽兰1.166正式版.rar) and archive #80 (终极地狱-指间mud版服务端.rar). This agent could not cross-check against them (concurrent extraction). The main session should diff/md5sum core files (master.c/chinese.c/securityd.c/logind.c) across all three once all are done to determine whether they're the same game at different snapshots, forks of one lineage, or unrelated codebases that happen to share a title — per this project's repeated lesson (shujian2008 vs sjpl2, xianlvqiyuan vs xlqy_new2007, etc.) that similar Chinese titles are NOT a reliable lineage signal on their own.

Extraction gotcha

The archive's own readme file extracted with a GBK-encoded filename that unrar's locale handling left as raw undecodable bytes (˵\udcc3\udcf7\udcceļ\udcfe.txt — Python surrogate-escaped). Renamed it to its correct decoded name (说明文件.txt) via a small Python os.fsencode/gb18030-decode script rather than leaving the mojibake filename in work/.

Fixes applied (proactive, per AGENTS.md catalog, before first boot)

New/notable bugs found (not yet in AGENTS.md's numbered catalog)

1. virtuald.lpc's "virtual object" fallback treats file_size() == -1 (nonexistent) as truthy "file exists"compile_object(file) walks file's path components and does if (file_size(name + ".lpc")) { ob = name->query_virtual_room(...); }. Since file_size() returns -1 for a missing path (a nonzero int, so truthy), this ALWAYS "succeeds" into calling name->query_virtual_room() for a name that doesn't exist as an object either — which triggers the driver to lazily load_object(name), which fails (file doesn't exist), which calls master::compile_object(name) AGAIN as the driver's standard "couldn't find this file, try a virtual object" fallback, which calls virtuald.compile_object(name) again... recursing until Inherit chain too deep: > 30 aborts it. This isn't cosmetic: it fired continuously (every NPC-patrol heartbeat tick referencing a room in the missing /d/city//d/city3 zones — see gap #2 below) and, before it was fixed, appeared to be eating enough eval-cost/CPU each tick that the FIRST test session's character landed with a corrupted room state (fell back to START_ROOM which itself doesn't exist either, see next item). Fix: file_size(name + ".lpc") >= 0 (a real, existing file) instead of a bare truthy check. This is a genuine, driver-lineage-wide engine bug independent of missing content — worth checking any other ES-II-family lib with a virtuald.lpc/"virtual object" fallback for the same bare-truthy-file_size() shape. 2. Missing zone content, confirmed real archive gap (§13): /d contains ONLY death/, pk/, register/ — every city/sect zone (/d/city, /d/city3, /d/wudang, /d/xuedao, /d/beijing, /d/shaolin, /d/xingxiu, /d/heimuya, dozens more) referenced by START_ROOM (/d/city/kedian), cmds/chat/enterworld.lpc, npcd.lpc's patrol tables, mapd.lpc's map data, and 48 clone/board/*_b.lpc bulletin boards is genuinely absent — this really is the "bottom-layer source code... for study" skeleton release its own readme describes, not a full world pack. Also affects a whole sub-feature: /data/room/moman/* (a "house" template set, 绿竹苑) that #includes /d/room/roomnpc/roomnpc.h (also missing, defines is_owner()/owner_is_present()) — 9 files affected, all under the same missing /d/room/ tree. Because START_ROOM itself (/d/city/kedian) doesn't exist, logind.lpc's own fallback-to- START_ROOM path is dead code that always fails too — but this is masked in practice because REGISTER_ROOM (/d/register/entry, which DOES exist, home to NPCs 水笙/狄云) is what a genuinely fresh (! registered) player actually uses, so the missing /d/city never surfaces during ordinary registration. Documented, not fabricated. 3. d/register/npc/diyun.lpc unguarded factory-chain call (§15e): carry_object("/d/city/obj/cloth.lpc")->wear() in this NPC's create()/d/city/obj/cloth.lpc is part of the missing /d/city zone (gap #2), so carry_object() correctly returns 0, and the unguarded ->wear() on it threw Bad argument 1 to EFUN call_other() every time this NPC's create() ran (i.e. every time /d/register/entry, the REAL register room, reset) — which, because the error was inside a catch(load_object(startroom)) in logind.lpc, made the ENTIRE register-room load look like it failed, sending every new character to the (also nonexistent) START_ROOM fallback instead of the real, populated register room. This was the single highest-impact fix in this pass — before it, characters landed with a broken/empty environment and look/score appeared to produce no output at all. Fixed with the standard if (objectp(cloth)) cloth->wear(); guard; the NPC simply goes unclothed (acceptable, matches precedent). 4. Genuinely broken/orphaned, never-loaded daemon files (not fixed, not reachable in normal play — same category as §12's "orphaned non-LPC file", just for an incomplete .lpc instead): adm/daemons/ cruised.lpc ("漫游精灵", cross-server player roaming) uses vfd/ socket_info without ever declaring them, references STREAM_BINARY without #include <net/socket.h>, and has a CAHNNEL_D typo (for CHANNEL_D) — none of CRUISE_D is even #defined anywhere, and nothing else in the lib references it; not in preload. adm/daemons/ quest/girl.lpc similarly references undeclared rcv_npcs/ supply_objs globals and is never loaded by anything else either. Both read as genuinely incomplete/abandoned files from the original author, consistent with the archive's own "study source, not a full release" disclaimer. 5. Pre-existing typos, fixed (unrelated to encoding/rename, confirmed via raw-byte diff against the original archive): - inherit/condition/damo.lpc:225: if (! intp(cnd["level"]) || ! intp(cnd["remain"] || ! stringp(cnd["id"]))) — a misplaced closing paren (should close after cnd["remain"], not after cnd["id"]). - Same file, a genuine corrupted byte in the RAW archive (not our conversion): a stray invalid 0xf7 byte immediately before a closing quote at raw byte offset 7414 (inside "发作身亡了") made the whole file fail strict GB18030 decoding, so convert_lib.sh fell back to iconv -c (lossy), whose "eats an adjacent real byte" recovery heuristic then corrupted a LATER, unrelated string literal ("长长的吁" @ line 278) into 5 invalid UTF-8 bytes — the exact xo_final/tianxia pattern documented in AGENTS.md's Encoding section. Fixed by stripping the single stray byte from the RAW bytes directly (confirmed via bytes.decode('gb18030') raising UnicodeDecodeError at that exact offset) and re-decoding the whole file cleanly, rather than patching the already-corrupted UTF-8 output. - adm/simul_efun/util.lpc never #include <ansi.h> despite using NOR/HIY/HIW/HIR/HIG/HIC/WHT/BCYN throughout — silent in a real boot only because simul_efun.lpc (which #includes this file) already pulls in ansi.h itself first (§6b: works fine composed, fails standalone under lpcc). Added the #include directly for correctness/self-sufficiency (harmless, header-guarded). - inherit/misc/quest.lpc's set_information(string key, string info) — narrower than QUEST_D's own mixed info, and 5 quest template files (clone/quest/{explore,judge,search,shen,supply}.lpc) pass a function-pointer closure ((: ask_npc :)), not a string — widened to mixed info (matches AGENTS.md's already-cataloged "quest set_information signature" bug class, e.g. yhyxs).

Confirmed NOT needed (checked, not present)

Testing methodology note (worth flagging for future libs)

This lib sets user->set("env/prompt", "time") for every new player — a live, once-per-second clock prompt re-drawn from the character's own heart_beat() (inherit/char/char.lpc), independent of the driver's write_prompt()/process_input() applies. scripts/mudclient.py's --idle pacing logic resets its "quiet" timer on ANY received byte, including these once-a-second heartbeat prompt redraws — with the default/ larger --idle values used successfully on most other libs (1.0–3.5s), the heartbeat's constant ~1s drip meant the "idle" condition was never satisfied, so queued --send lines for look/score/quit were silently never actually transmitted at all (confirmed via -dconnections driver debug output: zero get_user_command() calls for those lines). This looked EXACTLY like the §15ae "commands silently do nothing" failure mode and cost significant diagnostic time (traced through add_action, exec()/interactive-transfer, process_input()/APPLY_PROCESS_INPUT, even a raw byte-level socket script) before the actual cause — a test-tool pacing artifact specific to libs with a persistent per-second heartbeat prompt, not a mudlib bug — was found. Fix for testing: use a SHORT --idle (0.3–0.5s, shorter than the heartbeat period) on any lib with a live/clock-style env/prompt, or use a raw socket script that sends after a fixed wait rather than an idle-detection loop. Worth promoting to AGENTS.md as its own catalog entry for the next lib with a similar live-prompt feature.

Registration flow shape

get_id (English id, 3-10 letters) → confirm_id (y/n, only for a NEW id) → get_surname (Chinese, ≤2 chars, optional/blank-skippable) → get_name (Chinese, ≤2 chars, combined surname+name must be ≥2 chars, checked against NAME_D->invalid_new_name() for banned Jin Yong character names and near-duplicate existing names) → new_ad_password/ confirm_ad_password (a SEPARATE "admin/recovery password", ≥5 chars) → new_password/confirm_password (the regular login password, ≥5 chars) → get_type (1-5, character "build" archetype, blank defaults to 5/balanced) → get_gender (m/f) → enter_world(). No hidden BIG5/GB prompt, no client-version gate, no anti-flood throttle found in band.lpc (only is_banned(site) — a real IP-ban list, not a per-connection registration throttle).

Interactive test result

Full registration + post-login flow verified in two separate continuous connections with real Chinese names "秦风" (male) and "林枫" (female, type 耐力型), both reaching the actual populated starting room "世外桃源" (with NPCs 水笙/狄云 present, exits west/east/north/south). Both sessions then sent look (re-displayed the correct room description), score (correctly responded "还没有出生呐,察看什么?" — a legitimate game-rule message, since neither test character completed the additional register <email> + "投胎做人" reincarnation step the unregistered banner describes; this is real command execution, not a silent failure), and quit (correctly responded "欢迎下次再来!" and disconnected). Zero debug.log errors in the final clean runs beyond the confirmed-harmless versiond.lpc socket_bind cosmetic line. command_hook's private removal (§15ae) confirmed working via this real post-login-command test, per the project's standing policy.

lpcc sweep

1169 files, 1072 pass / 97 fail (91.7%). All 97 failures triaged into already-understood categories, none require further fixing:

Files touched (for reference)

adm/simul_efun/chinese.lpc, adm/daemons/logind.lpc, adm/daemons/ named.lpc, adm/daemons/securityd.lpc, adm/single/master.lpc, feature/command.lpc, adm/simul_efun/message.lpc, clone/user/user.lpc, adm/etc/preload, adm/daemons/virtuald.lpc, d/register/npc/diyun.lpc, adm/npc/luban.lpc, inherit/condition/damo.lpc, adm/simul_efun/ util.lpc, inherit/misc/quest.lpc, plus the ~30-file "nosave/"static/ revert (§3 counterexample) and directory creation (log/, log/static/, log/user/, binaries/).

Re-verification pass: driver rebuild + formatter + WASM (2026-07)

WASM-enablement pass (2026-07): loopback gates + admin seeding

Standard pass per AGENTS.md §1.3b/§1.3c/§1.3e/§1.5:

WASM long-sit boot-watch pass (2026-07)

200s scripts/wasm_boot_watch.sh sit: the quest-daemon heart_beat() "Bad argument 1 to call_other"/"Bad argument 2 to present()" errors (clone/quest/judge.lpc, .../search.lpc, .../supply.lpc, .../shen.lpc) reappeared, matching the already-documented pre-existing "skeleton archive's missing zones" class (recorded above, unrelated to the VERSION_D guards) — confirmed still the same already-known class, no new fix needed. ftpd.lpc/versiond.lpc sockets-absent preload errors also match the already-documented §1.3c class (caught, cosmetic). One genuinely new proactive fix: this lib shares inherit/item/combined.lpc (private void destruct_me(), call_out-self-invoked when a money stack hits amount 0) and adm/simul_efun/object.lpc (file_owner() return name bug) with sibling zhonghua2, where both fired live during that lib's sit — ported both fixes here proactively (dropped private on destruct_me; file_owner() now return dir) even though neither triggered visibly in this lib's own 200s window. Retest: fresh registration (id zjdsanb) into 世外桃源, look/score(pre-投胎 message)/quit clean, no regressions.

深度功能测试 / Deep functional test (round two, per AGENTS.md §10.7)

Native driver only (~/src/fluffos/build-debug/src/driver config.fluffos from libs/zhongjidiyu/), scripts/mudclient.py --idle 0.5-0.6 throughout (this lib's live per-second clock prompt requires it, §15an/AGENTS.md §8.3 item 1 — reconfirmed still necessary). Read help/newbie and help/intro first, in full, before touching the client — they document the actual intended flow precisely: 水笙 register <email>decide → walk to one of 世外桃源's 4 exits and out to pick a 性格/character trait → out again into 阎罗殿 (Hall of Yama) → wash (roll 4 innate stats) → born <地名> (choose birthplace, triggers reincarnation and moves the player to their starting zone). Safe sparring is the ordinary fight command ("较量" — per help/intro, stops before either side dies); skill learning is bai (apprentice) then xue (learn) from an NPC teacher; sect/faction join happens the same way, via bai-ing a sect NPC.

One continuous session, two test characters (both left in place as evidence): hufengbo/秦风 (male, 猛士型, admin password Admin@2026, regular password Mud@2026) and muyunqing/林枫 (female, 耐力型, same password scheme). Both completed real registration through register+decide+personality-room+wash end-to-end, confirmed via look/score/i at every step. Admin account fluffos/浮云 (seeded by an earlier pass) also used, with goto, to reach content a fresh player account cannot (see below).

Confirmed still correctly applied, not re-diagnosed as new:

Bug found #1 (NEW) — a failed born corrupts a real account into a permanently no-environment login, and enter_world()'s own fallback chain doesn't actually catch it. This is the highest-impact finding of this pass. Root cause, two parts, both fixed:

1. d/register/yanluodian.lpc's do_born() persisted startroom/born/born_family to the player's SAVE data unconditionally, BEFORE checking whether the destination object actually resolved (obj = load_object(dest)/find_object(dest)). Since every born destination in this skeleton archive points into a missing zone (/d/city, /d/beijing, etc. — none exist, see gap #2 above), literally every born attempt "fails" (prints "牛头一呆, 搔搔头说:怎么好像有问题...") — but the state was ALREADY written by then. This flips enter_world()'s own !stringp(user->query("born")) safety net (which would otherwise keep an unborn player parked safely in BORN_ROOM/阎罗殿 on every future login) to false, so it stops applying. 2. adm/daemons/logind.lpc's enter_world() then tries to resolve the now-persisted (broken) startroom. Its own fallback logic only wrapped catch(load_object(startroom)), not the subsequent user->move(startroom) — and load_object() on a path that simply doesn't exist (with no virtual-object fallback) returns 0 without throwing, so the catch() sees "no error" and falls into the UNGUARDED user->move(startroom). feature/move.lpc's move() does call_other(dest, "???") as its very first destination-resolution step, which genuinely throws (*call_other() couldn't find object '/d/city/kedian'.) for a nonexistent path — uncaught here, aborting enter_world() mid-function. Confirmed live: reconnecting as the already-"born" hufengbo printed "你无法进入这个世界,可能你的档案 出了一些问题" and then look returned "你的四周灰蒙蒙地一片,什么 也没有" — the exact §7.22 "no environment at all" symptom, but via a distinct mechanism (neither an eval-cost abort nor a compile error — a plain unguarded call_other() inside an un-catch()-wrapped move()). score still worked (doesn't need an environment), which is what made this state look survivable at a glance — look/movement were the ones silently dead. This lib's own hardcoded START_ROOM fallback (/d/city/kedian) is ALSO one of the missing paths, so even the "else" branch's intended recovery was reaching for a target that doesn't exist either.

Fix, two parts (both live-verified — see below): - d/register/yanluodian.lpc: moved the !objectp(obj) failure check to immediately after obj is computed, in BOTH the plain-string and the family/世家 branches, before any me->set(...) call. A failed born now leaves the account's startroom/born fields untouched, exactly as if born had never been attempted. - adm/daemons/logind.lpc's enter_world(): wrapped the actual user->move(startroom) in catch() too (not just load_object()), and added a THIRD fallback level — if even START_ROOM fails to load/move into (true on this specific archive), fall back to BORN_ROOM (阎罗殿, always present) instead of leaving the player with no environment at all.

Live verification: before the fix, reconnecting as hufengbo (who had already borned to a missing destination in a prior session) reproduced the crash exactly as described, with *call_other() couldn't find object '/d/city/kedian'. in debug.log. After the fix (driver restarted to pick it up), the SAME already-corrupted hufengbo account now lands in 阎罗殿 via the BORN_ROOM fallback (kicked onward to 虚空/void by 地藏王's own already-correct "you're already born, get out" NPC logic — a real, pre-existing, working game mechanic, not a bug), and look/score/movement/quit all work normally from there — no more no-environment state. Separately, a FRESH character (muyunqing) that ran wash+born <missing dest> AFTER the fix correctly stayed in the "not yet born" state (score → "还没有出生呐,察看什么?", still standing in 阎罗殿 with 地藏王 still willing to hand over the newbie book) on both the immediate next command and a later real reconnect — confirming the root-cause fix (part 1) prevents the corruption from happening at all for any new account, while the defense-in-depth fix (part 2) also protects any account that manages to reach a broken startroom by some other path. No new debug.log errors from any of this.

Doesn't match any existing catalog entry exactly — closest are §7.14 ("missing post-registration destination room... guard the move with load_object()/fallback to START_ROOM") and §7.22 (the "no environment at all" symptom shape) but the specific mechanism (a catch() that only wraps the probe call, not the actual unguarded move() right after it, PLUS a state-mutation-before-validation ordering bug in the caller) is new. Worth a full write-up as a candidate new §7.x entry — see final report.

Bug found #2 (matches AGENTS.md §8.3a's addendum exactly, not new) — feature/action.lpc's eval_function() was still private. Found live: apply() with insufficient permission: ... function: eval_function, origin: internal, needs: private, has: hidden fired in debug.log during ordinary play (a delayed-effect call_out against our own test character's body). This is the SAME file and SAME function name as the xuanjianlu-derived precedent already in §8.3a's addendum ("the shared 'delayed status effect' primitive used by 130+ kungfu-skill/drug files"). The lib's own "WASM long-sit boot-watch pass" note (above) proactively ported §8.3a's addendum fix for inherit/item/combined.lpc's destruct_me() and adm/simul_efun/object.lpc's file_owner() from sibling zhonghua2, but missed this THIRD instance — feature/action.lpc itself apparently wasn't part of that proactive sweep. Fixed identically: dropped private, kept the function otherwise unchanged. Proactively grepped the whole lib (every call_out("name", ...) site cross-referenced against a same-file private declaration of name) for any other instance — found none: every other flagged hit is a call_out target defined in a standalone daemon/NPC/command file that is never inherited elsewhere (confirmed via grep -rl 'inherit.*"<path>"'), so the DECL_PRIVATE→DECL_HIDDEN-once-inherited mechanism doesn't apply to them.

Bug found #3 (matches AGENTS.md §7.25 exactly, not new, but a genuinely new instance/location) — inherit/room/room.lpc's shared make_inventory() had no guard, crashing the ENTIRE afterlife zone's first-ever visit. d/death/npc/wgargoyle.lpc ("白无常") and d/death/npc/bgargoyle.lpc ("黑无常") both call set_skill("dodge", ...) in their own create() — and this archive's /kungfu/skill/ directory is entirely absent (not just the /d/city-style zone rooms already documented in gap #2 — the base skill-file tree itself is missing, a broader gap than previously written up). feature/skill.lpc's set_skill() correctly error()s on a missing skill file, but that error() fires DURING the NPC's create(), which new() propagates as an uncaught throw — and inherit/room/room.lpc's make_inventory() (ob = new(file); ob->set(...); ob->move(...); return ob;, called from every room's reset(), lib-wide) had zero catch() around any of it. Live-reproduced via admin goto /d/death/gate (DEATH_ROOM, where every player death sends them via feature/damage.lpc's die()): the room's FIRST-EVER reset() this boot aborted entirely, so goto silently failed to move the admin there at all (landed back at start with only a debug.log trace: *F_SKILL: No such skill (dodge), blamed at wgargoyle.lpc's create() via room.lpc's make_inventory()). Same shape independently confirmed for bgargoyle.lpc in /d/death/gateway.

Fix: wrapped make_inventory()'s new()/set()/move() chain in catch(), returning 0 on any failure (destructing a partially-constructed object first if new() itself did return one); and guarded the ONE call site in reset()'s case 1: branch that dereferenced the result without an objectp() check (ob[list[i]]->is_character()) — the default: (multi-object) branch already continued past the equivalent dereference for a freshly-(re)- made entry, so it didn't need the same guard. Live-verified this unblocked the ENTIRE death/afterlife zone, not just the one room: after the fix, admin goto successfully reached and looked at all 8 death-zone rooms (gate/鬼门关, road1/road2/road3/鬼门大道, inn1/小店, inn2/黑店, god1/天堂, god2/圣殿, block/空房间, gateway/酆都城门) with zero further errors beyond the two now-gracefully-caught missing-skill NPCs — this whole zone is otherwise 100% present and intact in the archive, just unreachable-on-first-visit before this fix. Matches §7.25's established pattern and fix precisely; the missing /kungfu/skill/ tree itself is left alone as a genuine archive content gap (not fabricated) — 白无常/黑无常 simply never spawn, same graceful-degradation outcome §7.25 already prescribes for this shape.

Confirmed content gap, broader than previously documented: the /kungfu/skill/ directory (referenced by include/globals.h's SKILL_D(x) macro, "/kungfu/skill/" + x) does not exist AT ALL in this archive — not one basic skill file (dodge, force, unarmed, etc., all named in help/newbie's own example cha output) is present, beyond the previously-documented missing /d/city-style zone rooms. This means even IF a player could reach a populated zone, xue/learn-style skill acquisition would have nothing to actually load. Documented here, not fabricated — matches the archive's own "study source, skeleton release" disclaimer.

Safe-sparring / skill-teacher / sect-join — confirmed NOT reachable live, by design of this skeleton archive, not a bug. Every currently-existing room in the archive (d/register/*, d/pk/*, d/death/*) explicitly sets no_fight: 1 — the fight command (§ help/intro's "较量") is real, present, and correctly wired (cmds/std/fight.lpc exists and is a normal add_action command), but there is no reachable room anywhere in this archive where combat is actually enabled. The bai(apprentice)/xue (learn) skill-teacher path and every sect-join NPC live under the missing /d/<sect> zones (§13/gap #2) and, per the finding above, even the underlying skill FILES they'd teach don't exist either. d/pk/ ("屠人场" — a PK tournament arena, 乌老大's sign/join commands) is a distinct, unrelated feature (scheduled PvP, not the newbie-doc's safe fight spar) and is itself a dead end too (west exit → /d/changan/..., missing). Consistent with, and extends, this lib's own already-documented "skeleton archive" gap — not attempted to fabricate.

Shop purchase / combat / death — explicitly NOT tested live, and cannot be, given the above. No shop, no fightable NPC, and no death trigger is reachable by an ordinary player account in this archive's current content. Code review only: feature/damage.lpc's die() calls me->move(DEATH_ROOM) (/d/death/gate, confirmed to exist and — after Bug #3's fix — load cleanly) and DEATH_ROOM->start_death(me); this path was not exercised by an actual player death since no live combat path exists to trigger it.

quit + debug.log grep, both unclean (net-dead) and clean-quit reconnect, both prompt and after a real wall-clock gap: all tested, all clean.

Files touched, this pass

WASM 修复摘要(迁移自 meta.json 的 group_note)

尽管标题相似,但和 hell 那对"终极地狱"没有关系。状态已从过时的 limited 修正——这份档案自己的 README 和 group_note 里从未记录过任何缺陷说明,本轮重新测试也没有发现:管理员登录(fluffos/Mud@2026)干净正常,'目前权限:(admin)'。另外还发现并修复了一个和手足档案 zjdyaryl/zjdyzj 共有的真实 bug:clone/user/login.lpc 的 query_save_file() 只防范了 id 不是字符串的情况(!stringp(id)),没有防范空字符串的情况——对 "" 取 id[0] 会回传整数 0,而 sprintf 的 %c 格式会拒绝这个值('Incorrect argument to type %c, must be valid UTF8 char'),在任何 id 被输入之前,第一次自动呼叫 query_save_file() 就会崩溃。已通过额外检查 id == "" 修复。

§7.86 跨库扫描修复(留言板 post 崩溃)

§7.100 sub-threshold instance (2026-08-20)

Found during the §7.100 tail-sweep (below the original 166-lib survey's

=100-occurrence threshold, never checked). 39 live

replace_program(ROOM); occurrences across 38 files: 18 clone/megazine/*.lpc rooms, clone/misc/void.lpc, a 12-file d/pk/turen*.lpc cluster, a 6-file d/death/*.lpc cluster, plus this lib's own room-building tool clone/misc/roommaker.lpc (both a standalone line and a separate string-builder template line, both fixed) — so newly-built rooms were inheriting the bug too. A full post-fix grep confirms 0 live occurrences remain. Verified via a clean native driver boot (zero new debug.log errors, port listening, killed by exact PID after ~8s).

§7.30 uninitialized-mapping accessor sweep (2026-08-20)

Corpus-wide mechanical sweep of the feature/skill.lpc shared-lineage bug (confirmed independently on xiakexing2017/jqxz2015/haiyang2 via round-four testing): 5 accessor(s) in this file returned a raw never-initialized mapping instance variable (defaults to int 0, not ([]), until first assigned), crashing any unguarded keys()/sizeof()/indexing caller for a fresh/untrained character. Fixed at the accessor level (mapp(x) ? x : ([])) per the documented remedy. Verified via lpcc --batch static compile check only (not a live boot) as part of a large mechanical sweep; not individually functionally re-tested live on this lib.

Shop + 拜师 (2026-09-04 librarian loop) — cheap-confirm, no re-boot

The existing deep-test body already records, with concrete evidence, that this archive is a skeleton: every shipped room is no_fight: 1, shop/sect NPCs and skill files live under missing /d/<sect> trees, and "No shop, no fightable NPC" was an explicit live-test conclusion rather than a heading-only TODO. This pass re-read that section and did not re-boot. Still no reachable shop or bai path to exercise.