A Journey to the West

✅ 可玩

西游记 (A Journey to the West)

xiyouji

🔑 fluffos / Mud@2026 更新 51f555e 2026-09-01 源码 下载 ZIP

▶ 开始游玩 · Play Now

登录画面自称"A Journey to the West",版本号 2.01,最早制作于 1996-1998 年;本项目考证认为它极可能是"ES II / 西游记"这一整个引擎家族(包括 xyj2000f、mhxy、xiyouji2003、xiyouji2006、xiyouji450、shenmo 等众多同题材姊妹游戏在内)最早的祖先版本——文件时间戳最早,且没有任何后续站点加上的"破解者"署名痕迹;游戏以《西游记》原著世界观为背景,玩家从长安城出发游历天下,探索盘丝洞、五指山、南海等小说中的经典地点,作为整个西游记 MUD 世系的源头,世界内容相对朴素、原始,适合用来对比后续各分支如何演化。

English

Self-titled "A Journey to the West," version 2.01, originally created 1996-1998. This project's research concludes it is very likely the earliest ancestor of the entire "ES II / Journey to the West" engine family (which includes xyj2000f, mhxy, xiyouji2003, xiyouji2006, xiyouji450, shenmo, and other sibling games in this collection) — its files carry the earliest timestamps and show none of the "cracker" credit lines later sites added. Set in the world of the original novel, players set out from Chang'an to explore the story's iconic locations (the Silk-Web Cave, Five-Finger Mountain, the South Sea, and more). As the wellspring of the whole Journey to the West MUD lineage its world content is comparatively simple, the most primitive form in the series and a useful baseline for comparing how the later branches evolved.

README

内容亮点

在线试玩

https://mudlibs.fluffos.info/xiyouji/

管理员账号 / Admin account

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

本地运行

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

游戏端口:40079

NOTES · 移植与修复记录

西游记.rar → xiyouji (archive #84)

Lineage: confirmed the likely ANCESTOR of the whole "ES II / XYJ" 西游记 family, not a duplicate of any already-done sibling

Per the task's explicit instruction, read libs/xyj2000f/NOTES.md (#15), libs/mhxy/NOTES.md (#19), libs/mhxyqd/NOTES.md (#56), libs/shenmo/NOTES.md (#73), libs/xiyouji2003/NOTES.md (#81) first, then diffed/md5sum'd this archive's adm/obj/master.c, adm/daemons/chinesed.c (the translator daemon; the byte-check daemon is adm/simul_efun/chinese.c here), and adm/daemons/logind.c against the raw pre-conversion files of all five before doing any conversion work.

Findings:

Conclusion: this archive is a genuine, distinct member of the "ES II / XYJ" lineage shared with xyj2000f (#15), mhxy/ mhxyqd (#19/#56), shenmo (#73), and xiyouji2003 (#81) — almost certainly their common ancestor snapshot (oldest file timestamps, least site-specific modification) — but NOT a byte-duplicate of any of them. Known-lineage fixes (§15h chinese-detection, dns_master preload exclusion, master.lpc valid_write/valid_read shape) were ported proactively; fixes specific to a LATER snapshot's added features (convertd.lpc's Greek-table typo, §8h) were independently re-discovered here since this codebase's own copy of convertd.lpc has the bug too (see below) — expected, since §8h itself is documented as recurring across the whole family.

Flag for later cross-check: archives #82 and #83 (processed concurrently by sibling agents, not yet available to read at the time of this pass) are also 西游记-themed per the task description. A future pass should diff this archive's adm/obj/master.c/adm/simul_efun/chinese.c/ adm/daemons/logind.c against whatever libs/<slug>/raw/ those two archives extract to, to determine if either is an even-closer sibling or duplicate of this one. (One such sibling, working under slug xiyouji2006, was observed running concurrently on this same host during this pass — its own separate NOTES.md should be consulted once available.)

Fixes applied (with rationale)

1. §15h — GBK byte-range Chinese-detection bug, in adm/simul_efun/chinese.lpc's is_chinese(): replaced the byte-range check (strlen(str)>=2 && str[0]>160 && str[0]<255) with a CJK Unicode codepoint range check (strlen(str)>=1 && str[0]>=0x4e00 && str[0]<=0x9fff). Without this, every real Chinese name is silently rejected at registration (§15h's core, most-impactful finding across the whole project). Also fixed check_legal_name() in adm/daemons/logind.lpc: halved the byte-calibrated length bounds (strlen<2strlen<1, strlen>12strlen>6, matching what the error message already says: "一到六个中文字" = 1 to 6 Chinese characters) and dropped the i%2==0 && byte-alignment gate on the per-character is_chinese() sliding check (every UTF-8 index is already one full character, not every-other-byte). 2. §15p — proactively excluded /adm/daemons/network/dns_master from adm/etc/preload before the first boot attempt. This lib's preload list had it listed (confirmed via adm/daemons/network/ dns_master.c's presence and its own hardcoded remote boot-server dependency). 3. §15ai — a dns_master-absence shutdown(1) gate in logind.lpc's encoding() callback. Found on read-through, exactly as the task description flagged as a known risk of the §15p exclusion: a "mirror-IP-verification" check (if(!find_object(DNS_MASTER) || !"/adm/daemons/band"->check_ip(...)) shutdown(1);) that unconditionally treated "daemon never loaded" (guaranteed true here, since we exclude it) as "verification failed" and called shutdown(1) on the entire driver process on the very first connection. Fixed by changing the guard from !find_object(...) to find_object(...) && ... — daemon absent now degrades to "skip the gate" instead of "gate failed", matching the established fix pattern. Applied proactively before ever booting (read the code first, per the task's explicit instruction to check every catalog section against the actual source before boot). 4. §8h — convertd.lpc's Greek/CJK-table stray-backslash typo, recurring exactly as documented for xyj2000f/mhxy: 45 separate lines (not just the usual handful) had a stray literal backslash immediately before the closing quote of a two-character string entry ("α\","α",, "功\","功",, etc — one base character + a trailing Private-Use-Area companion codepoint that is itself completely legitimate content in this BIG5/GB conversion table, confirmed by cross-checking ~1000 other *unaffected* lines with the identical "char + PUA companion" shape compiling fine). Root-caused via lpcc's exact error line + a Python pass over the decoded file finding every line with an odd number of trailing backslashes before the closing ",/" — not a blind sed (this file's CRLF-preserving §8h counterexample was specifically checked for and confirmed absent: the fix script here operated on already-LF-normalized decoded text and verified zero remaining hits afterward). 5. §3's blanket staticnosave sed collided with "static/CRASHES"- and "static/PURGE"-style log-path string literals (the exact counterexample already documented for moniHuafu, archive #57): adm/obj/master.lpc (4 occurrences, "static/CRASHES"), adm/daemons/securityd.lpc + adm/daemons/ss.lpc (1 each, "static/promotion"), cmds/usr/suicide.lpc ("static/SUICIDE"), cmds/arch/purge.lpc/purgehouse.lpc ("static/PURGE"), cmds/wiz/call.lpc ("static/CALL_PLAYER") — all reverted from the sed's "nosave/..." back to the original "static/...", confirmed against the raw pre-conversion files first (cross-checked with iconv-decoded originals to be certain these strings were genuinely "static in the archive, not something the encoding pass introduced). 6. §15w — log_error()/APPLY_LOG_ERROR broadcasting every compile WARNING (not just real errors) to the connected non-wizard player. Found live during the FIRST full interactive registration test: the default error message (你发现事情不大对了,但是又说不上来。) spammed ~26 times during ordinary post-registration play (the first-ever lazy compile of every never-preloaded room/feature file reached by make_body()/enter_world()std/char.lpc's #pragma, feature/*.lpc's unused-local-variable warnings, etc — all harmless, but all routed through master.lpc's log_error(), which didn't distinguish a warning from a fatal error). Fixed by gating the player-facing broadcast on strsrch(message, "warning:")==-1 (still logs everything to home + "log" regardless). Re-verified with a fresh registration after the fix and restart: zero spam. 7. Absolute angle-bracket #include, §15t pattern #1: d/obj/books-nonskill/book-qujing.lpc had #include </d/qujing/obstacle.h> (an absolute path inside angle brackets, which this driver's <...> resolver never special-cases) — converted to quoted form #include "/d/qujing/obstacle.h". Confirmed book-qujing is real, referenced content (d/westway/npc/laoren.lpc, d/city/npc/jieding.lpc both new()/carry_object() it), not dead content — worth fixing, not just noting. 8. ..-relative #include, §15t pattern #2: d/ourhome/honglou/npc/niu.lpc had #include "../honglou.h" (this driver disallows .. in #include paths outright) — repointed to the real absolute quoted path "/d/ourhome/honglou/honglou.h". 9. §8d-style local header one directory removed from its user: three files under d/kaifeng/npc/old/ (shan.lpc, zhi.lpc, bei.lpc) #include <quest_ak.h>/<reporting.h>, which exist one directory UP at d/kaifeng/npc/ (this driver's get_include_path() fix only prepends the COMPILING file's own directory, not its parent, so this doesn't resolve automatically) — every OTHER file referencing these headers already lives directly alongside them and compiles fine. Fixed narrowly (not a generalized parent-directory search, to avoid unintended side effects elsewhere) by copying both headers into d/kaifeng/npc/old/ too. 10. Pre-existing typo, §10-shaped missing closing quote: d/obj/books-nonskill/hmeng014.lpc had string name = "《红楼梦》 第十四回; (missing closing " before the ;), confirmed against 12+ sibling hmeng0NN.lpc files in the same directory which all use the correct "..."; form — fixed to match. 11. Pre-existing typo, corrupted/dropped-byte argument: data/ armor.lpc's do_closecommand() had ob->set_alias(cmd, "); (an unterminated string literal swallowing the next several lines, cascading into a wall of "Illegal character" errors reported much further down the file) — confirmed via the raw pre-conversion bytes that this was originally set_alias(cmd, "<one genuinely-undecodable byte>");, dropped by the lossy iconv -c recovery pass, and confirmed via the sibling do_opencommand() function IN THE SAME FILE (ob->set_alias(cmd,0);) what the correct call shape actually is — fixed to ob->set_alias(cmd,0); to match. 12. Mapping-literal syntax typo: d/gao/obj/pen.lpc's is_container() had set("objects", (["/u/bula/gao/obj/kaoji"]) ); — a mapping literal with a bare key and no :value, which this driver rejects as a syntax error (compared against d/changan/playerhomes/h_croc.lpc's own, valid, set("objects", ([ path:1, path:1 ])); usage of the same "objects" property) — added the missing :1. The referenced target (/u/bula/gao/obj/kaoji) still doesn't exist anywhere in the archive (genuine content gap, not fabricated), so this only takes the file from a hard compile error to a graceful missing-content no-op. 13. Orphaned junk data mistakenly caught by the .c.lpc rename, §12 pattern: obj/file.c (416 bytes of literal random binary noise, file reports "data", confirmed unreferenced anywhere via grep -rn "/obj/file\b") — renamed to obj/file.orphaned-junk so it no longer pollutes the lpcc sweep's pass/fail signal. 14. Corrupted pre-existing NPC-vendor save data, §15m-adjacent: four data/npc/boss/*.o files (city_kongfang.o, city_weiluqi.o, laosun.o, yangzhongshun.o) are genuinely random/binary garbage (confirmed byte-identical to the raw un-touched archive via md5sum — not something our conversion pipeline broke), which would throw *restore_object(): Illegal file format at runtime the first time a player actually visits the NPC that owns one (found via the lpcc sweep compiling /d/city/bookstore in isolation, which clones its bookseller NPC). Moved out of the way into data/npc/boss/ corrupted-original-backup/ (not deleted) so restore() finds nothing and proceeds cleanly, matching the established zhonghua2 precedent — this was NOT triggered during the real boot/registration test (the bookstore isn't on the path from the start room), so it wasn't blocking anything we tested, but is a real latent crash for normal play. 15. §14 — valid_override() given the documented 3rd main_file parameter. master.lpc's copy was the old 2-arg form, and adm/simul_efun/object.lpc (an #included fragment of simul_efun.lpc, not that file itself) defines its own destruct() override calling efun::destruct() — the 2-arg check's file == SIMUL_EFUN_OB test is false for this fragment (file is the physical object.lpc, not simul_efun.lpc), which per the docs is exactly the scenario the 3rd parameter exists to fix. Applied proactively; per the catalog's own note this may never surface as a real boot symptom, but the fix is free and correct.

What was checked and confirmed NOT needed

Fullwidth punctuation / mojibake escape sequences (harmless, not fixed)

daemon/class/fighter/oldstuff/champion.lpc (5 hits) and obj/npc/ garrison.lpc (2 hits) both have a stray literal backslash immediately before a bare Chinese character inside a string ("水烟阁传功\使", "许\多武林人物") — confirmed pre-existing in the raw archive, and confirmed non-fatal (warning: Unknown escape sequence, not an error) both via the lpcc sweep and by cross-referencing that these two files are never reached by the registration/look/score test path. Left as-is per the project's policy of fixing only what a real error/lpcc-FAIL demonstrates matters, not every cosmetic warning.

Genuine archive-content gaps (not fixed, not fabricated)

Re-verification pass (QA sweep, later session)

Re-tested the full flow end-to-end again this pass (still clean, zero 执行时段错误 in debug.log). Found and fixed one real, shared-lineage bug while cross-checking against sibling xiyouji450's own re-verification pass: adm/daemons/logind.lpc's get_name() had a stray, pre-existing debug leftover printf("%O\n", ob); right after a new player's Chinese name is accepted -- dumps a raw internal object reference (e.g. /obj/login#0) straight to the connecting player, on every single registration. Purely cosmetic (never affected registration itself -- confirmed the Chinese name still gets set and stored correctly either way) but visibly unprofessional. The exact same leftover was found in all three other siblings in this session's batch (xiyouji2003 -- 2 occurrences, xiyouji2006, xiyouji450), confirming shared lineage at the source level; removed in all four. Re-verified with a fresh registration (qfrong/秦荣) after restarting the driver: no stray object-reference text anywhere in the transcript, look/score/ quit all still correct.

Boot + registration + post-login command test (the actual verification)

Booted ~/src/fluffos/build-debug/src/driver config.fluffos from libs/xiyouji/ (via the tool's run_in_background, after one earlier attempt via nohup setsid ... & disown died to the documented unexplained-external-SIGTERM issue — matches AGENTS.md's own note about this exact symptom on this host). debug.log shows only compiler WARNINGS (unused locals, #pragma notices, "Illegal to declare nosave function" — all cosmetic/non-fatal) and ends cleanly with Accepting telnet connections on 0.0.0.0:40079. / Initializations complete. — zero fatal errors, zero segfaults, zero "Too deep recursion".

Full registration + post-login command transcript (via scripts/ mudclient.py 127.0.0.1 40079 --timeout 25 --idle 0.6, one continuous connection, real Chinese name), final confirmation run with a never-before- used id (qfengyu) after the §15w fix landed and the driver was restarted:

--send "gb"                        -> GB/BIG5 charset prompt accepted
--send "no"                        -> student age-gate declined
--send "qfengyu"                   -> English id (new, unregistered)
--send "y"                         -> confirmed new-character creation
--send "秦风"                       -> REAL Chinese name, ACCEPTED on the
                                       first try (confirms §15h fix)
--send "test1234"                  -> password set
--send "test1234"                  -> password confirmed
--send "[email protected]"       -> email
--send "m"                         -> gender: male
--send "y"                         -> accepted the rolled stat block
--send "look"                      -> full room description of 南城客栈
                                       (South-City Inn), NPCs/board listed
--send "score"                     -> full character sheet: 【平民】普通
                                       百姓 秦风(Qfengyu), age/birth date,
                                       all 8 stats, HP/MP bars, food/water
                                       bars, kill counts, 潜能:99
--send "quit"                      -> clean disconnect, "欢迎下次再来!"

Zero occurrences of the log_error() default-error-message spam this time (confirms fix #6 above); zero silent/no-op commands (confirms add_action dispatch works, ruling out §15ae); zero missing-environment symptom (confirms the character actually landed inside /d/city/kezhan, ruling out §15aj). An earlier interactive test (before the §15w fix, id qfeng/qinfeng) reached the identical successful outcome but with ~26 spurious default-error-message lines interleaved — that repro is what found bug #6 in the first place.

debug.log after this session: only compile warnings from the lazy first-time compile of std/char.lpc, its inherited feature/*.lpc files, std/room.lpc, d/city/kezhan.lpc, feature/equip.lpc, std/bboard.lpc, obj/mailbox.lpc — all cosmetic, zero errors.

lpcc_check.sh sweep results

First pass (before the fixes in items 4/7-14 above): 4921/4988 pass (98.7%), 67 failures. Second pass (after fixes): 4931/4987 pass (98.9%), 56 failures (file.lpc's rename-away accounts for the total dropping by 1). Memory stayed healthy throughout both runs (free -h never dropped below ~4.4GB free on this 23GB host) — well below the OOM-risk threshold noted in AGENTS.md §6b, so no need to back off.

Remaining 56 failures triaged by category, all either genuine archive-content gaps (documented above) or expected lpcc-isolation artifacts per §6b (a room/NPC create() calling into another object or the skill system before anything else is loaded in a bare single-file compile — e.g. /d/qujing/pingding/shilang1's "Eval interrupted... cost limit reached" during an isolated NPC-attack-loop compile, or /adm/ simul_efun/object.lpc failing standalone since it's an #include-only fragment of simul_efun.lpc) — none affect the real boot or the registration/look/score test, which is the actual completeness gate per AGENTS.md's "Definition of done".

Directories/files created that weren't in the raw archive

Standing scratch-file hygiene

No boot_stdout.log/trace_lpcc.json/similar left in libs/xiyouji/'s top level or work/ (checked and removed a stray work/trace_lpcc.json before finishing). lpcc_batch_raw.log and lpcc_fail.log at the top level are the standard lpcc_check.sh output artifacts, kept per the same convention every other already-done lib in this project follows.

Driver-rebuild retest + LPC reformat + WASM pass (this session)

WASM-enablement pass (loopback-allow + admin seed)

Applied the standard WASM-first changes (AGENTS.md §1.3b/§1.3e/§1.5):

1. Loopback always allowed through ban gatesadm/daemons/band.lpc: added is_local_ip(string ip) helper (127.*, empty/non-string, or non-dotted-quad => local) and short-circuited all three entry points the login flow calls: is_banned(), create_char_banned(), is_strict_banned() (each now return 0 immediately for local IPs). These gates were not actively blocking (shipped ban lists are empty) but are patched per standing policy so runtime-added bans can never lock out local/ WASM play. 2. Uptime startup gate: none in this lib (checked logind.lpc). 3. Anti-flood throttles: none per-IP in this lib. The "玩家已经太多" gates are global player-count caps, not per-IP throttles — left intact. SECURITY_D->match_wiz_site() returns 1 when a wizard has no wiz_sites entry, so it does not block fluffos — left intact. 4. Admin account seeded — id fluffos, password Mud@2026, display name 浮浮 (male), registered through the real flow (gbno student gate → id → y → name → password ×2 → email → gender → accept talents). Granted (admin) via adm/etc/wizlist (fluffos (admin)), read by securityd.lpc::create(). Verified after restart: re-login shows 目前权限:(admin), update /adm/daemons/band recompiled OK, goto worked. Save files: work/data/user/f/fluffos.o + work/data/login/f/fluffos.o (untracked, NOT gitignored — orchestrator must git add).

Retest: fresh registration (fluffos itself) reached 南城客栈 as (player), look correct; fluffos re-login as (admin) with working wizard commands; log/debug.log clean (0 errors).

深度功能测试 / Deep functional test (2026-07-24)

Second lineage in the project's round-two deep-playthrough pass (after bxsj, a completely different codebase/lineage — see libs/bxsj/NOTES.md's "深度功能测试" for the worked-example this pass follows). Played as an ordinary new player through registration, exploration, safe combat, organic skill-learning and sect-joining, a real quit, and a real-wall-clock-gap reconnect, native driver (build-debug). Read doc/help/newbie in full first (the single highest-value planning resource, exactly as the methodology predicts — it named the fight-vs-kill safety distinction, apprentice/learn syntax, and the general command set up front). doc/help/ also has ~90 other topic files (combat, menpai, individual sect writeups, etc.) but no separate general-help directory beyond it.

Test characters (both kept, not cleaned up, as representative playthrough evidence):

Bug found and fixed: unbounded init()/reset() recursion crashes the FIRST visit to any of the game's 9 sect-entrance rooms

This is a genuinely new bug class for this project's catalog — not the §7.16 rank-decay class (bxsj's bug), and not any previously-cataloged shape. Filed as file:line d/jjf/npc/zhangmen.lpc:36/623 (the crash site) and std/room.lpc:25 (reset(), the structural root).

- maximum call depth : 30 in config.fluffos is a dead setting on this driver build — raising it to 150 (the driver's own hardcoded default) had zero effect on the crash. Checked the actual driver source (~/src/fluffos/src/vm/internal/base/ interpret.cc): the enforced limit is the compile-time constant CFG_MAX_CALL_DEPTH (150); the config key is registered in rc.cc but never read by the interpreter. The archive's own "(unused currently)" comment on this key is, unusually, accurate for this driver build (most of this file's "(unused currently)" comments are stale — see logind.lpc's call-depth-adjacent settings elsewhere in this project's other libs — so don't generalize this either way without checking the specific key). Left the config value unchanged (30, the archive default) with a comment recording this so a future agent doesn't re-spend the time. If a lib's crash trace shows "Too deep recursion" at a depth that looks legitimately-deep-but-finite (not cyclic), the fix has to be an actual code change, not a config tweak, on this driver. - Disabling *only* create_identity()'s call from init() still crashed (blamed reset_me() / feature/dbase.lpc's query_temp() instead). Disabling reset_me()/restore()/fully_recover() too (leaving init() almost empty) *still* crashed, now blamed on me->setup()/std/char.lpc's setup(). This is what established that the recursion isn't really "inside" any one of zhangmen.lpc's own functions — it's that init() itself was being re-entered on the same object, so whatever code happened to be running when the call-depth limit hit varied by exact timing. - Applying *only* the std/room.lpc reentrancy guard (without the zhangmen.lpc init() guard) still crashed. Applying *only* the zhangmen.lpc init() guard (confirmed via git stash isolation, without the room.lpc guard) was the point at which live retesting stopped reproducing the crash across several repeated fresh-boot attempts — but std/room.lpc's setup() calling reset() synchronously (see root cause #1) is real, structural, and shared by every room in the game, so the guard was kept anyway as defense in depth even though the zhangmen.lpc-side guard alone was sufficient in this specific reproduction.

What was tested and confirmed working

Methodology notes (for the broader pass this seeds)

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

西游记/xiyouji.org 家族的祖先快照(1996-98)。

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

深度功能测试第二轮 / Deep functional test round two (2026-08-15, post driver-upgrade re-test)

驱动于 2026-08-12 升级后的重测。标准检查清单发现并修复三处问题:

1. config.fluffosmaximum evaluation cost400000(已知 风险区间)提升到 5000000。 2. adm/simul_efun/file.lpclog_file() 没有 assure_file() 目录预建保护,补上调用及前向声明;cat() 补上 read_file() || "" 空值防护。 3. obj/user.lpc::reconnect()(AGENTS.md §7.108,第十三条独立确 认的血统——本档案是 xiyouji.org 大家族本身的祖先快照,§7.17/ §7.19 等多条既有条目的血统源头,这次在它自己身上也确认了同一类 bug)adm/daemons/logind.lpc 有同款 exec(old_link, user); 踢掉重复登录写法,reconnect() 缺少 enable_commands()。按 §7.108 记录的写法预防性修复,现场用两个真实连线复现"保持第一个 连线不断开→第二个连线登录→答 y 踢掉旧连线"验证:score 修复后 立即正常显示完整角色档案。

cmds/wiz/update.lpc(§7.106)与 master.lpc::log_error()(§7.10 的 "arning:" 大小写无关写法)均已是正确写法,均无需改动;本档案无 adm/daemons/closed.lpc,不受 §7.107 影响。

现场验证摘要

驱动干净启动,管理员 fluffos/Mud@2026 登录(GB/BIG5 选择→未成 年人关卡"no"→id+密码)确认 目前权限:(admin)update /adm/daemons/logind 成功验证真实写入权限。踢掉重复登录重连路径现 场验证通过(见上)。debug.log 全程干净(387 行,无真实错误)。

本轮修改的文件

§7.100 sweep (2026-08-19)

Fixed the corpus-wide inherit ROOM; ... replace_program(ROOM); redundant-replace bug (AGENTS.md §7.100). 172 live occurrences deleted: 171 via scripted sweep (fix_710_room.py), plus 1 hand-fixed roommaker-tool template (obj/roommaker.lpc, simple string-builder variant). 2 already-commented-out instances left untouched. No real .lpc source found under work/data/. Verified via build-debug driver boot: clean compile, zero new "cannot replace"/"cannot bind" debug.log lines; confirmed serving via raw-socket connect on port 40079.

§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): 3 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.

深度功能测试第三轮 / Deep functional test round three-plus-four (2026-08-21) — CLEAN PASS, no new bugs

Round-two (2026-08-15, above) had explicitly flagged two gaps: no successful shop purchase completed live, and death/respawn not live-tested at all. This pass closes both, plus adds a first-ever live test of the mail system, and re-confirms the §7.108 reconnect fix and the corpus-wide §7.112 death_stage() reentrancy guard (already present in d/death/npc/pang.lpc via the earlier 7ff1b78860d sweep commit — not previously exercised live on THIS lib). Native build-debug driver, existing character shenqy/沈青云 (still apprenticed to 秦富, 将军府第四代弟子) plus admin fluffos.

Economy/shop purchase (round-two's gap #1): the player-side economy is not a wallet integer — money is a physical carried item (/obj/money/{coin,silver,gold,thousand-cash}, feature/finance.lpc's can_afford()/pay_money() scan present("coin_money", me) etc.). Granted shenqy 5000 coin via clone /obj/money/coin + call coin->set_amount(5000) + give coin to shenqy (admin). buy huasheng from xiao er then succeeded (你向店小二买下一碟花生豆), confirming the full economy code path (money-item detection, price deduction, item creation) works correctly. Note for future testers: std/char/npc.lpc's add_money(string type, int amount) only exists on the NPC mixin, not the player one — call shenqy->add_money(...) returns 0 (no-op) on a real player object; the clone+give path above is the correct way to grant a player money live.

Death/respawn (round-two's gap #2, now fully closed): call shenqy->die() (admin) triggered the complete cycle cleanly — corpse left behind, die()'s DEATH_ROOM->start_death() call is a benign undefined-function no-op (same shared-lineage artifact noted elsewhere in this project, confirmed harmless again here), player moved to /d/death/gate (阴阳界) as a ghost. d/death/npc/pang.lpc's death_stage() ran its full 5-message, 25-second judge dialogue (崔判官...) via the already-guarded death_stage_active temp-flag pattern (§7.112 fix, present since the earlier corpus sweep) with zero reentrancy issues, then called reincarnate() and moved the player to REVIVE_ROOM (荒郊小店). debug.log clean throughout (grepped for non-warning lines across the whole session: zero hits). Potential (潜能) dropped from 99 to 50 as an intended death penalty (COMBAT_D->victim_penalty()); HP shown at 35/100 post-revive is correspondingly partial, not a crash artifact.

Mail system (new — not covered by any prior pass on this lib): obj/mailbox.lpc itself is dead/orphaned content (not placed in any room's objects mapping, same class as round-two's noted muren.lpc gap) — the *live* entry point is d/ourhome/npc/bigeye.lpc (邮差 千里眼/Bigeye, the NPC standing in the start room), whose inquiry mapping wires "mail"/"信"/"收信" etc. to receive_mail(), which clones a personal MAILBOX_OB into the player only when the player is physically standing in their own startroom. ask bigeye about mail → received a personal mailbox → from correctly reported empty → mail fluffos (compose flow: title → body → . to end → save-copy y/n) sent successfully, and admin fluffos got a real live notification (千里眼跟您说:有您的信!快来一下!). Full round-trip confirmed working, zero errors.

Reconnect (spot-check re-verification of round-two's §7.108 fix, unmodified since b24f99518c4): disconnected shenqy's telnet session uncleanly (killed the tmux pane) and reconnected fresh with the same id/password — 重新连线完毕, score immediately showed full correct state (title, 潜能 50 matching the post-death value from this session).

Verdict: no new bugs found this round — a clean confirmatory pass that closes both gaps round-two left open. Test character shenqy's save state (money, death/revive location, mailbox) was left as-is per this project's standing convention of keeping test characters as representative playthrough evidence, not reset.

AGENTS.md §7.19: enable_player() reentrancy guard (2026-09-01)

Same corpus-wide bug class as mhxy/wuhanzhan: feature/command.lpc's enable_player() wraps enable_commands() and is unconditionally reachable from an NPC's init() via setup()/reset_me() (confirmed on this lib's own d/*/npc/zhangmen*.lpc-family NPCs, matching mhxy's originally-documented d/xueshan/npc/zhangmen.lpc pattern). Calling enable_commands() on an object that's already living() makes the driver re-invoke that object's init() as a side effect; since init() calls back into enable_player(), that is genuine same-call-stack reentrancy that repeats until "Too deep recursion" aborts a room's first-ever visit.

Fixed with a true reentrancy flag (nosave private int in_enable_player_now;), NOT a bare if (living(this_object())) return; guard — this lib's feature/damage.lpc revive() and cmds/std/sleep.lpc wakeup()/wakeup2() all legitimately re-invoke enable_player() while the object is still living() (that's how a fainted/asleep character gets commands back), so a living()-gated guard would silently break every one of those real re-enables. enable_player()'s single body has no early return statements, so the flag is set at entry and cleared once, before the function's fall-through end. Verified with a single-file lpcc compile check (exit 0, no errors) against feature/command.lpc.