Immortal Sword Wandering Knight 2000 (Legend of the Sword)

✅ 可玩

仙剑狂侠2000(仙剑传奇)

xjcq2000

🔑 fluffos / Mud@2026 更新 85d6a35 2026-09-02 源码 下载 ZIP

▶ 开始游玩 · Play Now

作者叶雨飞。属于"Century(世纪)家族"武侠 MUD 引擎(与《书剑2008》 《书剑飘零II》等同源,管理层目录结构相似),但游戏内容和安全模块均为独立开发,并非简单复制。

English

By author Ye Yufei. Part of the "Century" family of wuxia MUD engines (sharing lineage with Book and Sword 2008 and Book and Sword: Adrift II, with similar admin directory structures), though its game content and security modules were independently developed rather than copied. Set in a traditional wuxia world centered on Yangzhou — its central square, shops, the provincial governor's office, and major sects (the Beggars' Sect, Quanzhen Sect, White Camel Mountain, the Five Poisons Sect, the Sun Moon Holy Cult, and more). Distinctive "banditry" and "armed escort" job systems add flavor to jianghu life, all in an orthodox Jin Yong/Gu Long-style wuxia atmosphere well suited to players who enjoy sect progression and quest systems.

README

内容亮点

在线试玩

https://mudlibs.fluffos.info/xjcq2000/

管理员账号 / Admin account

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

本地运行

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

游戏端口:40034

NOTES · 移植与修复记录

xjcq2000 — 仙剑狂侠2000 (Legend of Sword and Fairy — Crazy Hero 2000)

Archive: 仙剑传奇.rar. Port: 40034. Status: done (boots clean and quick, full registration flow verified end-to-end including a real Chinese name).

What this is

"仙剑狂侠2000", credited to 叶雨飞 ([email protected], www.518518.com). Same "Century-family" adm/single/{master,simul_efun} layout as shiji/zhonghua2/shujian2008/sjpl2 — and its is_chinese()/check_legal_name() match shujian2008's exact shape (the two-specific-byte GBK check, the i<4||i>8||i%2 bound), though master.c/securityd.c differ, so it needed its own verification rather than blind copy. ~14,292 raw files, 12,243 after .c.lpc rename — the largest lib in this batch.

Fixes applied

1. AGENTS.md §15h, exact shujian2008 shape: is_chinese()'s two-specific-byte check → single-character CJK codepoint check; check_legal_name(object ob, string name)'s bound i<4||i>8||i%2 (byte count + meaningless odd-byte-count rejection) → i<2||i>4, removed the i%2==0 gate. 2. AGENTS.md §15p (new standing policy, applied proactively): /adm/daemons/network/dns_master was in adm/etc/preload — removed it before the first boot attempt (not reactively after hitting a hang, unlike the investigation on xlqyzdb just before this lib). Result: booted cleanly in well under 20 seconds, zero compile errors, no hang — validates the proactive-exclusion policy works as intended. Also checked ftpd.lpc (also in preload) for the same risk: its socket setup is deferred via call_out(..., 2) (2-second delayed, non-blocking to preload), so it was safely left in. msgd is referenced in preload but the file doesn't exist — harmless, master.lpc's preload() gracefully skips missing files. 3. New unguarded write(read_file(...)) crash (same bug *class* as xianlvqiyuan's cat()/BANNER crash, found independently here): cmds/usr/uptime.lpc's main() did write(read_file("/log/nosave/LASTCRASH")); completely unguarded. The actual file lives at /log/static/LASTCRASH instead — a hardcoded-path-vs-actual-location mismatch (not exactly a case mismatch this time, but the same root-cause shape). read_file() returning 0 for the wrong path crashed write(0) deep in receive()/receive_message(), killing every single connection attempt (not intermittent) with zero player-visible output. Fixed by guarding the write() call with stringp() rather than relocating the file (more robust — catches the general pattern, not just this one path). Also proactively hardened the shared adm/simul_efun/file.lpc's cat() helper the same way, even though it wasn't the one that crashed this time (matches the shape found on xianlvqiyuan/xlqyzdb). 4. New conversion-tooling edge case: the raw archive had a directory literally named chuixue-jian.c (kungfu/skill/), with the .c extension baked into the directory name itself, containing two files (taiji-jian.c, liehuo-jian.c) that are ALSO real, properly-named files/directories at the parent level — an orphaned duplicate/backup folder from the original archive's history. This confused convert_lib.sh's blind .c.lpc rename: it renamed the directory itself to chuixue-jian.lpc but couldn't rename the children inside (their mv targeted the pre-rename parent path, already gone), throwing two harmless mv: cannot stat warnings. Fixed by renaming the resulting directory to chuixue-jian.orphaned-dir so it can't be mistaken for a compilable object going forward — this is disposable duplicate content, not something any code path actually references.

Interactive test result — full registration flow

Verified the complete registration path in one continuous connection: BIG5-font prompt (n) → id xjcqb → confirm y → password Pass1234 (twice) → real Chinese name 秦风 → accepted, proceeds into character attribute selection (根骨/膂力/悟性/身法 stat prompt). No novel-character-name restriction in the banned_name list (bans "金庸" — the author's own name — but no specific character names).

lpcc sweep

12,243 files, 11,695 pass / 548 fail (95.5%). Memory stayed healthy throughout the sweep — RSS peaked around 2.1GB mid-sweep (the largest lib in this batch by file count) but recovered normally, host stayed at ~14GB free, no pressure requiring an early kill. Failure tail is the usual shape (missing message_combatd/skillN/combat globals, some syntax typos) — not triaged individually per AGENTS.md §6b/§13, boot + full interactive registration test is the verification gate.

Re-verification pass (2026-07-23)

Extended the interactive test past the password prompt (the original pass stopped there) through full registration, look/score/quit. Found and fixed one new regression, same class as fix #3 above:

Driver rebuild / formatter / WASM pass (2026-07-23)

WASM-enablement pass (2026-07-23)

Standard four-change pass (AGENTS.md §1.3b/§1.3e/§1.5). Gates patched:

1. Loopback always allowedadm/daemons/band.lpc is_banned() (top of function): short-circuit return 0 for 127.0.0.1, a leading 127. prefix, and empty/malformed IP strings (WASM garbage). All BAN_D->is_banned() callers pass query_ip_number(ob), so this covers the login ban gate in adm/daemons/logind.lpc gb_big5() (line ~119). 2. Anti-flood / per-IP capadm/daemons/logind.lpc logon() (line ~96): the login_cnt > 3 per-IP concurrent-connection cap is now wrapped so it only runs for real remote IPs; loopback/malformed IPs skip it entirely (declared a new string ip; local). 3. Uptime startup gate — none in the login path (UPTIME_CMD->main() only prints uptime, is not a gate); nothing to bypass. 4. sited.lpcis_valid()'s login call site and the entire is_multi() function are already commented out in this lib, so neither is an active gate; left as-is (documented, not patched). 5. Admin account seeded — id fluffos, pw Mud@2026, name 浮浮, registered through the normal flow (BIG5 n → id → confirm → password x2 → Chinese name → gift 0/agree → email → gender). Granted (admin) via adm/etc/wizlist (fluffos (admin)). Verified (admin) status + update works.

Save files (both NOT gitignored — untracked; orchestrator must git add):

Retest: fresh registration (秦风) reaches 中央广场, score renders; fluffos (admin) + update works. The only runtime errors in debug.log are the two pre-existing content bugs (an NPC 托钵僧 heart_beat bad call_other, and /quest/poem/yard do_test bad message() arg) — unrelated to the login path, fire on any boot. Test chars removed. Note: id max length is 8 chars, so fluffos (7) fits.

Fail-closed loopback retrofit (2026-07-24)

Security correction, applied retroactively. Items 1 and 2 above originally treated an empty/non-string/malformed IP as "local" (fail-open) — a stopgap for a since-fixed WASM driver bug. Tightened to fail-closed in both spots:

Retested: fresh registration (id xjcqgate, name 秦岭峰) still reaches 中央广场 via loopback with look/score/quit all rendering correctly; fluffos login + update /adm/daemons/logind still succeeds (重新编译 /adm/daemons/logind.lpc ...成功!). No new runtime errors — debug.log shows only the same two pre-existing content bugs noted above plus the benign preload log_error()/news_b traces already documented in the "Re-verification pass" section. Test char removed.

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

A 200s passive WASM connection (AGENTS.md §10.0) surfaced ~84 Error in mudlib error handler: *Object cannot be loaded during compilation cascades during preload — many more than the ~21 traces the earlier interactive pass caught and dismissed as "purely cosmetic". Root cause, per AGENTS.md §7.10's third bullet (the bxsj/bxsj1 shape): adm/single/master.lpc's log_error() (line 121, called for every compile *warning*, not just errors) and standard_trace() (line 214) both call CHANNEL_D->do_channel(...) unguarded. securityd preloads first (before channeld, far down adm/etc/preload), so the very first #pragma/nosave-function warning during securityd's compile tries to call_other a not-yet-loaded CHANNEL_D mid-compile — forbidden — which throws, re-enters log_error()/standard_trace() for the new error, and cascades again since CHANNEL_D still isn't loaded. Every one of the 9 daemons preloaded before channeld (and any #included warning inside them) re-triggers it.

Fixed by guarding both call sites with find_object(CHANNEL_D) (mechanical §7.10 fix, no behavior change once CHANNEL_D exists):

if (find_object(CHANNEL_D))
  CHANNEL_D->do_channel(this_object(), "err", message);

Re-ran the 200s boot-watch: zero cascades, only the expected non-fatal ftpd preload failure (missing sockets package under WASM, §1.3c, caught by master.lpc's own preload() catch — same shape as xkyx3b). Native sanity retest (id xjcqrz/xjcqrs, real Chinese name, full attribute-roll → gift → email → gender flow): reaches 中央广场, score renders correctly, quit saves cleanly with zero errors in the driver log. Test char saves removed.

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

First genuine hands-on playthrough (AGENTS.md §10.7) — one continuous native session, real newbie-help-driven navigation, organic sect join and skill learning, real (non-scripted) combat through to an actual death/revival, an unclean-disconnect/reconnect test both promptly and after the full 900s NET_DEAD_TIMEOUT, and a driver stdout capture throughout. This pass found the single most severe bug yet in this project's round-two sweep: a real, non-catchable, whole-process FATAL crash — not just a caught runtime error — that killed the driver outright roughly 25 minutes into an otherwise-idle session. Also fixed five independent pre-existing compile/runtime bugs surfaced along the way (§6.6-class typos, none related to this project's conversion pipeline).

Test characters (kept as evidence, both alive and saved)

What was tested and confirmed working

THE FATAL CRASH — new bug class, draft below

FATAL ERROR: FATAL: Object 0x561e30ffeb88 /d/xingxiu/silk6 ref count 0, but not destructed (from free_svalue). — this is a driver-level consistency check, not a catchable LPC runtime error. It printed to the driver's own stdout (never to work/log/debug.log, which stayed at a constant 846 lines — its pre-existing baseline — through this entire session, crash included) and terminated the whole process, disconnecting every player. /d/xingxiu/silk6 is an ordinary room (星宿派 zone, "丝绸之路") that neither test character had ever visited; the crash surfaced instead while xjcqshen reconnected after the net- dead timeout, inside feature/dbase.lpc's set_temp("link_ob", ...), called from adm/daemons/logind.lpc's reconnect(). That call site is almost certainly an innocent bystander — a set_temp()/mapping-touch that happened to be the next free_svalue() call after the corruption already existed, not its cause.

Root-cause chain (established from the driver's own stdout, which happened to be captured to a file — this would have left literally zero evidence otherwise):

1. This lib's ambient world simulation is NOT idle even with nobody giving commands: roaming NPCs (赵爵爷, 捕头, others) have heart_beat()chat()random_move() chains that walk them through real exits via cmds/std/go.lpc, exactly like a player would. Given enough real wall-clock time (here: ~25 minutes), this ambient wandering forces lazy compilation of rooms/NPCs across the entire map, including zones neither test character ever went near (星宿, 明教, 逍遥, 武当, 大理, 红花, 黑木崖, 全真...). 2. That mass-compile surfaced several genuinely broken pre-existing files (see fixes below) — unew()/make_inventory() failures, restore_object() illegal-format errors on old board-post save data (same already-documented shape as the news_b finding above, now also hit for wiz_b/towiz_b/yuelaoting boards) — all individually caught and harmless on their own. 3. Somewhere in that sustained churn of compiling/cloning/destructing objects across nearly the whole lib, a room's (/d/xingxiu/silk6) reference count was corrupted to 0 without the object actually being destructed. The corruption is silent until the NEXT unrelated free_svalue() call happens to touch it, at which point the driver's own internal consistency check aborts the whole process.

This is exactly the shape AGENTS.md's testing methodology was built to catch and exactly the shape ordinary testing never will: it needs (a) real wall-clock idle time, not just a quick smoke test, (b) a process that was NOT restarted in between (so ambient churn can accumulate), and (c) driver stdout capture, since debug.log shows absolutely nothing. Two of this project's fixes below (broken NPC compiles that were part of the churn) are plausible contributing factors — a failed unew() on a target that never received a working program is exactly the shape of "reference grabbed to something that gets partially torn down" — but this was not proven as the exact root cause within this pass's time budget; a from-scratch reproduction attempt (fresh boot, long idle soak, no other player activity, watch for the same FATAL) was not run again given the ~25-minute-per-attempt cost. Flagged honestly as not fully root-caused, not silently presented as fixed.

Recovery verified: killed the dead process (confirmed via PID + readlink -f /proc/<pid>/cwd, not by pattern), rebooted fresh — both test characters' saved data (location, sect, skill, and — for xjcqhuo — the post-death empty inventory) survived the crash intact and reconnected normally. The on-disk save format was not corrupted by the crash; only the live process died.

Bugs found and fixed (all pre-existing, unrelated to this

project's conversion pipeline — §6.6-class typos/copy-paste bugs)

1. d/city/npc/kongkong.lpcinherit __DIR__ "gaibang_npc.lpc" but no d/city/npc/gaibang_npc.lpc file existed (three OTHER directories have their own differing copies of this file: d/gaibang/npc/, d/gaibang/npc/obj/, jobsys/gb_job1/ — none shared). d/city/npc/kongkong.lpc is itself a byte-identical duplicate of d/gaibang/npc/kongkong.lpc, so the fix was to copy its matching sibling, d/gaibang/npc/gaibang_npc.lpc, alongside it at d/city/npc/gaibang_npc.lpc (new file — git add needed). Spawned live by d/city/dongdajie2.lpc (a room actually walked through this session) — every reset() there previously threw *Inherited file '/d/city/npc/gaibang_npc' does not exist!, silently leaving that room's NPC population incomplete every time. Verified via admin update /d/city/npc/kongkong + update /d/city/dongdajie2 — both recompile clean now. 2. d/city/npc/xiaosong.lpc:57is_killing(who) passed an object where is_killing(string id) (defined in feature/attack.lpc) requires a string, throwing *Bad type for argument 1 of is_killing — a genuine hard compile error, so this file has likely never successfully compiled since whatever commit introduced the bug (every spawn attempt threw *No program in object). Fixed: is_killing(who->query("id")). Verified via admin update — compiles clean. 3. Four instances of this_player()->carry_object(...)->wear() inside create()this_player() is undefined at compile/ create()-time (no player context yet), so this evaluates to 0, throwing *Bad argument 1 to EFUN call_other() ... Got: int(0) on every single spawn — a hard runtime failure on create(), not a cosmetic warning. Every other NPC file in this lib correctly calls the bare (self-targeted) carry_object(...)->wear() instead. Found by grepping the whole lib for the pattern after fixing the first instance (per §10.7 item 7 — checking siblings for the same pattern), all four fixed identically: - quest/poem/npc/daxueshi.lpc:18 (spawned by quest/poem/yard.lpc — the room I actually walked xjcqhuo through this session, confirming this one live). - u/deng/npc/daxueshi.lpc:18 (a personal-workspace duplicate of the above, spawned by u/deng/yard.lpc). - d/honghua/npc/yuyutong.lpc:53, d/honghua/npc/xutianhong.lpc:52 (both spawned by d/honghua/goldroom.lpc/goldroom2.lpc) — found by pattern match, verified via admin update (compiles), not live-walked to, per §10.7 item 7's "flagged as unverified live" allowance. 4. d/honghua/npc/xutianhong.lpc:63ob - query("family/ master_id") (missing > — parsed as subtraction of an object, not a method call), throwing a hard compile error (*Bad argument number 1 to '-': "object ") independent of fix #3 above; this file has also likely never compiled successfully. Fixed: ob->query("family/master_id"). Verified via admin update.

None of the four restore_object() illegal-format board-save errors surfaced during the mass-compile churn (wiz_b, towiz_b, yuelaoting) were fixed — same root cause and same "degrades gracefully, known non-critical content gap" disposition already established for news_b above (old save data with unescaped literal newlines/quotes inside post text, predating this conversion pass).

Explicitly not verified live (honest accounting, §10.7 item 6)

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

状态已从过时的 limited 修正——这份档案自己的 README 里从未记录过任何缺陷说明,本轮重新测试也没有发现:管理员登录干净正常:"Are you using BIG5 font [Y|N]?"(回答 n)→id+密码→"您目前的权限是:(admin)"。

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

深度功能测试(2026-08-13,round two,新驱动重测)

针对驱动升级(quest_times/win_times %-operator 修复 + Warning/warning 大小写回退兼容)做的重测。

发现并修复:data/board/news_b.o 存档数据本身已损坏,每次登录都

触发一次被顶层捕获的运行时错误

登录后固定 1 秒的 call_out("check_news", ...) 会加载新闻留言板 /clone/board/news_b,其 setup() 无保护地调用 restore()restore_object(),而这份存档本身括号不配对([/]:371 对 339,(/):707 对 706)——raw/ 原始压缩包里的同一份存档就已经 是这个字节形状(md5sum 内容不同是编码转换导致的正常膨胀,但括号 计数在转档前后完全一致),确认是转档之前就存在的损坏数据,不是本 项目引入的回归。因为 check_news() 是通过 call_out 异步触发(不 在注册/登录的主执行路径上),崩溃只会让这一次 call_out 的执行栈 被顶层错误处理器捕获并写进 debug.log执行时段错误: *restore_object(): Illegal mapping format while restoring dbase.), 不会打断登录本身——但每一次任何人登录都会在 debug.log 里重复留 下这条噪音,且新闻板永远不可用。restore_object() 对不存在的文件 只会静默返回 0,不会抛出,所以删除这个无法再被正确解析的损坏文件 是安全的:git rm work/data/board/news_b.o。删除前后各做一次完整 的 fluffos/Mud@2026 管理员登录验证:删除前能在 debug.log 里 稳定复现这条错误,删除后同样的登录流程干净无此错误,score 显示 "【天神】"头衔正常,功能无回归(本来就不可读的新闻板,删除后 setup()restore() 只是拿到"文件不存在",走默认空白留言板路 径)。

Proactive checks(无需改动)

实测过程

管理员 fluffos/Mud@2026 用真实密码重新连线(含"Are you using BIG5 font"→n 这一步),落地在此前保存的地点,score 显示"【天神】"头衔和正确属性数值。驱动按精确 PID 结束;测试期间产 生的存档时间戳增量已 git checkout -- 还原,只提交 news_b.o 的删除。

§7.100 修复(ROOM 基类的同一"多余 replace_program()"形状,全档案扫描第 6 批)

``§7.112`` residual-gap closure (2026-08-20)

Corpus re-scan (grep -rl 'call_out("death_stage"' ... | filter for missing guard) found unguarded init()-scheduled death_stage() call_out chain(s) in d/death/npc/yanluo.lpc that the original two-wave sweep (see AGENTS.md §7.112) missed -- same reconnect-triggered duplicate-chain bug, different filename/lineage. Added the standard query_temp("death_stage_active")/set_temp/delete_temp re-entry guard, adapted per file's own exit points. Compile-verified via lpcc --batch.

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

Round-four (§10.7) follow-up — closing the three explicitly-flagged gaps (2026-08-20)

Native build-debug driver, fresh boot, debug.log wiped before boot and stayed completely absent (zero errors) through the entire pass — no compile/runtime errors from anything below. All three items from the "Explicitly not verified live" list closed:

1. Successful (funded) shop purchase — now verified, no bug. Logged in as admin fluffos, goto /d/city/zahuopu, clone /clone/money/silver 60 (auto-merges into a single "六十两白银" stack per COMBINED_ITEM's move()-time same-base_name merge), list confirmed 皮背心 at 56两, buy beixin succeeded ("你从杂货铺老板那里买下了最后一件皮背心。"), item appeared in i. First measurement looked like a bug (money appeared to go *up*, 60→64两, instead of down by 56) — root-caused via call introspection (call laoban->query_goods_value(...) confirmed the correct 5600-copper price; call silver->query_amount() confirmed a single, non-duplicated money object) to a test-methodology artifact, not a real bug: two separate clone .../silver 60 calls were issued across two different reconnects of the same persistent admin character without checking inventory in between, and COMBINED_ITEM.move()'s auto-merge silently combined them into 120 silver (12,000 copper) before the buy — 12,000 − 5,600 = 6,400 = "六十四两", exactly matching the observed number. A clean second purchase on the same character, with a known starting balance (6,400 copper) and no interleaved reconnect, deducted *exactly* 5,600 copper (6,400 → 800, "八两") as expected. Price deduction and item receipt both confirmed correct; no code change needed. (Admin's test-acquired silver/beixin items were left in inventory as evidence, consistent with other test-character saves in this NOTES file; the resulting data/*/f/fluffos.o / u/deng/log save-churn from this session was reverted via git checkout -- since no other file changed, per this project's save-churn-avoidance convention.) 2. d/wuguan/npc/muren.lpc training dummy — now verified live, clean. goto /d/wuguan/wuchang4 (one of the rooms that places npc/muren per its objects mapping) reached the dummy directly. fight muren produced a full multi-round turn-by-turn combat log (accept_fight()'s stat-mirroring worked — evenly matched, neither side landed early hits), self-halted via the safety net exactly like the liumang/girl sparring already verified in the original deep-functional pass ("看来该找机会逃跑了..." → auto-retreated to the adjacent room). No crash, no debug.log output at all. 3. d/honghua/npc/yuyutong.lpc/xutianhong.lpc post-fix — now verified live. xutianhong.lpc is reachable through normal navigation (goto /d/honghua/goldroom2, which lists /d/honghua/npc/xutianhong in its objects mapping) — look xu showed it spawned correctly, wearing "布衣(Cloth)" (confirms the fixed self-targeted carry_object("/d/honghua/cloth")->wear() in create() ran without error). Correction to this file's own earlier claim: re-checked while here — yuyutong.lpc is not actually referenced by any room's objects mapping anywhere in this lib (goldroom.lpc only has a *commented-out* line for a *different*, wizard-sandbox xutianhong copy at /u/ybl/honghua/npc/xutianhong; a corpus-wide grep -rln 'npc/yuyutong' outside the NPC file itself found nothing) — it is orphaned/unreachable through ordinary play, not merely "not reached this pass". Since the actual fixed code path (the create()-time carry_object(...)->wear() call) fires identically on new() regardless of how the object is instantiated, live-verified it directly via admin clone /d/honghua/npc/yuyutong in goldroom2: spawned cleanly, look yu showed it correctly wearing "布衣(Cloth)" too, no crash, no debug.log output. Fix confirmed to hold under live instantiation; the orphaned-reachability finding is a documentation correction, not a new bug (nothing crashes from an unreferenced file existing on disk).

Standard checklist confirmation pass (fast, per §10.7 routine)

No new bugs found or fixed this pass — all three previously-flagged gaps closed as verified clean (one initially-alarming false alarm, fully root-caused to a test-methodology artifact rather than a real defect). The /d/xingxiu/silk6 refcount-corruption root cause remains not further chased, per the task's stated lower-priority/ budget guidance — still documented as-is above, nothing new to add.

AGENTS.md §7.19 fix: enable_player() reentrancy from init()

feature/command.lpc's enable_player() (wrapper around enable_commands()) was reachable from an NPC's init(): the shared inherit/char/char.lpc setup() (called from every character's create()) itself calls enable_player(), and d/shushan/npc/zhangmen.lpc redundantly calls setup() again from inside its own init() (on top of the setup() its create() already made) -- same shape as the originally-documented mhxy zhangmen.lpc case. enable_commands() is only safe to call from create(): calling it again on an object already living() makes the driver re-invoke that same object's init() as a side effect, which recurses back into enable_player() on the same call stack until "Too deep recursion" aborts the boot on a room's first-ever visit. Fixed with a true reentrancy flag (in_enable_player_now), NOT a living() guard (which would break legitimate re-enables from revive() in feature/damage.lpc and wakeup()/wakeup2() in cmds/std/sleep.lpc, both confirmed to re-invoke enable_player() on this lib while the object is still living()). Verified via lpcc --batch single-file compile check (PASS). Part of the corpus-wide §7.19 sweep (Batch E).