Naruto

✅ 可玩

火影

huoying

🔑 fluffos / Mud@2026 更新 66a3bd8 2026-10-28 源码 下载 ZIP

▶ 开始游玩 · Play Now

本游戏自称 火影(英文 Naruto),`master.lpc`/`simul_efun.lpc` 等文件头把底层引擎归功于 Annihilator(muds.net)的 "Neolith 0.0.2"(2000 年9月),是 "ES2"(东方故事Ⅱ)引擎家族的一员,与本项目中的武汉站、雪影奇缘同宗,血缘上也与 es1_win、esI、kxkj、haiyang2 等更远支相关。以日本动漫《火影忍者》为题材(`globals.h` 里甚至留有一行被注释掉的 `MUD_NAME`"火影忍者"),登录界面带有取材自台湾站点的精美 ANSI 彩色 ASCII 艺术 Logo。存档里的忍术/查克拉技能与装备模板库其实相当可观,但内容并不完整:实机测试确认这份快照里实际可通行的房间只有巫师公会设施(公告板、举报处、议事厅等 5 间),并未随附可探索的忍者村/江湖地图,`START_ROOM` 直接硬编码指向巫师公会——更像是引擎与框架的技术快照,而非完整的关卡内容包。

English

The game calls itself Huoying (Naruto); its master.lpc/simul_efun.lpc/chinese.lpc headers credit the underlying engine to Annihilator (muds.net) as "Neolith 0.0.2" (09/07/2000), placing it in the same ES II (Eastern Story II) engine family as this project's wuhanzhan (A Chinese Odyssey) and yueyingqiyuan (Moon Love Story), and more distantly es1_win/esI/kxkj/haiyang2. Themed after the Naruto anime -- globals.h even carries a commented-out MUD_NAME of "火影忍者" ("Fire Shadow Ninja") -- with a fairly elaborate ANSI color ASCII-art login banner sourced from a Taiwanese site. Content is honestly thin: the archive carries a substantial jutsu/chakra-skill/equipment template library, but live testing found only five navigable rooms, all wizard-guild facilities (noticeboard, complaints desk, meeting hall) -- START_ROOM is hardcoded straight to the wizard guild, with no explorable ninja-village map shipped in this snapshot.

README

内容亮点

在线试玩

https://mudlibs.fluffos.info/huoying/

管理员账号 / Admin account

警告:Mud@2026 是本地游玩用的公开默认密码。若要正式对外开放主机,
请先修改此密码(或从 wizlist 中删除该账号)。

本地运行

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

游戏端口:40059。

NOTES · 移植与修复记录

huoying — 火影 / "Naruto" (ES2 mudlib, Annihilator lineage)

Archive: 火影.rar (archive #65; byte-identical duplicate 火影 (1).rar already flagged in AGENTS.md's Duplicate archives table and NOT re-processed). Port: 40059. Status: done (boots clean, full registration flow verified end-to-end with a real Chinese name including reconnect + quit, lpcc sweep 98.1% pass).

What this is

config.cfg's own name field says 火影 (matches the archive title), and the header comment identifies the underlying engine: Neolith 0.0.2 by Annihilator (09/07/2000) — this is the ES2 mudlib lineage (Annihilator, muds.net), the same family as wuhanzhan/kxkj/ yueyingqiyuan (archives #53/#54/#58) — confirmed via master.lpc's own copyright header ("This program is a part of ES2 mudlib... Annihilator <[email protected]>") repeated verbatim across master.lpc, simul_efun.lpc, chinese.lpc, logind.lpc, securityd.lpc, virtuald.lpc, etc.

include/globals.h has #define MUD_NAME_INTERMUD "Naruto", #define MUD_NAME_ABBR "Naruto", and a commented-out #define MUD_NAME "火影忍者" ("Naruto" literally, "Fire Shadow Ninja") — confirms the lib is genuinely Naruto-themed, not just coincidentally named. The archive's own included 火影说明.txt (author's readme, by "AKAI", 2006.09) says it was found on a Taiwan site and redistributed because it looks especially good over ZMUD's ANSI-art client — this checks out at connect time: the MOTD includes real, quite elaborate ANSI-art banner graphics (a large multi-color logo) that render correctly once terminal codes pass through untouched.

Root: raw/火影/ (one level, not nested further). config.cfg: master file : /adm/obj/master, simulated efun file : /adm/obj/simul_efun, mudlib directory : .. Modest-sized archive: 572 raw files, 466 real LPC (.c→.lpc) source files — no bundled driver source, no mega-lib concerns.

Conversion (convert_lib.sh)

Clean pass, no manual stragglers found afterward (verified with the standard file -b re-scan for .lpc/.h files, and grep for .c" leftovers/directories literally named *.c — zero hits on both). Numbers: 572 files total, 471 converted GB18030→UTF-8, 70 already-UTF-8, 0 lossy, 31 skipped-binary (real binaries: mudos.exe, .b binary dumps, a few .o genuinely-binary saves). 466 .lpc files after rename, 168 literal .c" refs fixed automatically, 42 files touched by static→nosave.

New encoding gotcha found here: a config file can be genuinely

MIXED GBK+BIG5, and GB18030 decode does NOT error on the BIG5 bytes

config.cfg's name : 火影 line is correctly GBK (bb f0 d3 b0 decodes to 火影 under GBK/GB18030) — but the file's own header comment block (# Neolith 0.0.2 ..., # Annihilator (09/07/2000)) and its default fail message/default error message values are genuinely BIG5-encoded (Traditional Chinese), left over from the original Taiwan author and apparently never touched by whoever re-encoded the rest of the lib's .lpc source to Simplified/GBK for redistribution. Confirmed byte-for-byte with Python (b'\xab\xfc\xa5O...'.decode('big5') → "指令錯誤,請輸入 help cmds 了解各項指令用法..." — coherent Traditional Chinese; the same bytes under GBK decode to visible mojibake: "���O岿粇�A叫块�J help cmds..."). The dangerous part: iconv -f GB18030 does NOT throw an error on these BIG5 byte sequences — GBK/BIG5 byte-ranges overlap enough that the bytes decode to *some* valid-looking (but wrong) codepoints, so convert_lib.sh's lossy-conversion detection (which only catches genuine decode *failures*) can't catch this at all. Manually identified the 4 affected lines (grep -na '[^\x00-\x7F]' config.cfg to enumerate every non-ASCII line, then spot-decoded each candidate both ways and compared for coherent output) and rebuilt config.fluffos decoding those specific lines with BIG5 and everything else with GB18030. Low real-world impact here (only affects 2 cosmetic player-facing messages plus code comments, not gameplay), but this is a new variant worth watching for on any other Taiwan-origin ES2/Neolith-family lib: a per-line mixed-encoding file where the wrong codec still "succeeds" silently is a strictly harder case than the previously-documented whole-file BIG5-fallback scenario, since there's no error to trigger a retry — only a manual read-through catches it. Did NOT find this issue anywhere in the actual .lpc source tree (spot-checked several files, including long room/item descriptions — all read as coherent Simplified Chinese, i.e. genuinely GBK throughout).

Fixes applied (mudlib-side, before/during first boot)

1. AGENTS.md §4 — master.lpc's valid_read/valid_write lazy

load_object(SECURITY_D) recursion, confirmed via lpcc before ever attempting a full driver boot

The original code already wrapped the lazy load in catch():

nosave int valid_read( string file, mixed user, string func ) {
    object ob;
    if( !catch(ob = load_object(SECURITY_D)) && objectp(ob) )
        return (int)SECURITY_D->valid_read(file, user, func);
    return 1;
}

This looked like it should already be safe (§4's catalog entry describes the UNGUARDED variant as the bug) — but running lpcc on logind.lpc (which pulls in the full chain including securityd.lpc) produced exactly §4's signature symptom anyway: a flood of Too deep recursion. / Error in error handler: *Too deep recursion. rooted at master.lpc:292 (the valid_read line). Root cause is exactly as §4 describes: catch() only protects the control flow of *that specific call* — it does nothing to prevent the driver's own error-reporting path from calling back into valid_read/valid_write (to check permission to write the error/log) as a brand-new outer call, which retries the same disallowed load_object() again, ad infinitum, overflowing the C++ call stack regardless of the inner catch(). Lesson for future libs: don't assume a catch()-wrapped load_object(SECURITY_D) is automatically safe just because it superficially matches the "fixed" shape — always verify with a real lpcc compile of a file that pulls in the daemon chain (not just eyeballing the source) before concluding §4 doesn't apply.

Fix: added the standard re-entrancy-flag guard (loading_security_d) to both valid_write and valid_read in master.lpc, matching the shape already in the catalog. Re-ran lpcc on logind.lpc afterward: zero recursion, zero errors, full compile chain succeeds (confirmed by reading the complete lpcc output, not just grepping for "error").

2. AGENTS.md §15h — is_chinese() GBK-byte-range check and

check_legal_name()'s byte-count bounds/loop, in adm/simul_efun/chinese.lpc and adm/daemons/logind.lpc

Verified via the interactive registration test below (a real 2-character name "秦风" and a 3-character name "王小虎" both accepted correctly and advanced past check_legal_name to world entry) — not just a standalone lpcc-dumped function check.

3. Port-hardcoded master.lpc connect() dispatch via MUD_PORT —

new gotcha, not previously in the catalog

master.lpc's connect(int port) switches on the literal incoming port number (case MUD_PORT: ... case HTTP_PORT: ...), where MUD_PORT/ HTTP_PORT are #defined in include/globals.h to the archive's *original* hardcoded ports (8000/8015). Since every lib in this batch gets assigned a different sequential port (here, 40059) that has no relationship to the archive's original port numbers, the switch fell through with no matching case and no default, so connect() implicitly returned nothing — every single connection attempt was rejected outright at the TCP layer with Can not accept connection from ... due to error in connect()., before logon() or any LPC login code ever ran at all (no compile error, no debug.log error beyond that one line — this is a classic "boots clean, but every real connection instantly fails" trap, easy to miss if you only check for compile errors and the "Accepting telnet connections" banner). Fixed by updating MUD_PORT in globals.h from 8000 to 40059 to match config.fluffos's actual port number. Check for this on any other lib in this ES2/Neolith lineage (or any lib whose master.lpc connect() dispatches on a literal port number) — grep master.lpc for connect(int port) and a switch/if on the parameter, and cross-check every compared constant against the lib's actual assigned port before the first real client-connect test (a bare lpcc sweep or a telnet-less driver boot will NOT catch this, since connect() is only exercised by a real incoming socket).

4. AGENTS.md §15w — log_error() broadcasting compile *warnings* to

players as scary "compile-time error" messages

master.lpc's log_error(file, message) (bound to APPLY_LOG_ERROR) unconditionally did if(this_player(1)) efun::write("编译时段错误﹕" + message) for every message reaching it — and this driver funnels every soft compile *warning* (Illegal to declare nosave function, Unused local variable, Unknown #pragma, ignored, etc. — all harmless, expected noise from this batch's static→nosave conversion and old #pragmas) through that same apply, not just genuine fatal errors like the original author assumed. Reproduced directly: the very first registration test (character "秦风") spammed dozens of 编译时段错误:... warning: ... lines to the connecting player as soon as gender selection triggered the lazy compile of /std/char.lpc and its ~30-file inherit chain (/feature/char/*.lpc, /std/room.lpc, /std/bboard.lpc, etc.). Fixed by gating the player-facing efun::write on the message NOT containing the substring "warning:" (kept the unconditional file-log write for every message, warnings included). Re-ran the identical registration test afterward (fresh id "qiufeng") — zero spam, debug.log still cleanly split into a normal boot-time trace, not evidence the warnings simply stopped occurring.

5. A pre-existing single-file typo, world/eq/leg/gai.lpc (§10-family:

missing/misplaced string-literal quote)

set_name(HIG"阿盖\"NOR, ({ "gai" }) ); has a stray backslash directly before the closing quote of the "阿盖" name literal — confirmed present byte-for-byte in the RAW pre-conversion archive too (5c 22 right after the GBK bytes for "盖"), so this is a genuine original-author typo, not conversion fallout. The escaped quote makes the string literal swallow everything up to the next real unescaped quote, producing a cascade of confusing "Illegal character 0xNN" errors on later, perfectly-valid UTF-8 Chinese text further down the same file (once the parser is desynced from being "inside a string" when it shouldn't be, subsequent real string literals get read as raw source tokens instead). Fixed by removing the stray backslash: set_name(HIG"阿盖"NOR, ({ "gai" }) );. Low-impact (a single leg-armor item, "阿盖" — an obvious Naruto/Rock Lee/"Gai-sensei" reference given the theme), but a one-line fix worth taking since it was trivial and matches a cataloged pattern.

Checked and confirmed NOT applicable (verified by reading the actual

source, not assumed)

adm/etc/preload — DNS/intermud daemon (§15p)

Already had /adm/daemons/network/dns_master commented out in the ORIGINAL archive (#/adm/daemons/network/dns_master — the # was already there pre-conversion, not something this pass added). Preload list left as-is (11 active entries: securityd, virtuald, logind, cmd_d, chinesed, emoted, aliasd, fingerd, channeld, natured, enterd) — boots in a few seconds, no hang observed.

Boot + registration-flow verification

Booted ~/src/fluffos/build-debug/src/driver config.fluffos from libs/huoying/ (per AGENTS.md §6 — log directory is CWD-relative; created libs/huoying/log/ as a sibling of config.fluffos, separate from libs/huoying/work/log/). Clean boot: all 11 preload daemons load with only cosmetic warnings (Unknown #pragma, ignored, Unused local variable, Illegal to declare nosave function — all expected/harmless per §3/§15w), Accepting telnet connections on 0.0.0.0:40059. / Initializations complete., zero fatal errors in debug.log.

Full registration-flow transcript (via scripts/mudclient.py, one continuous connection), reading adm/daemons/logind.lpc's actual input_to callback chain first (logon→get_id→confirm_id→ new_password→confirm_password→get_email→get_gender→get_name→ enter_world) rather than inferring it from prompt text — no hidden pre-id gate found in this lib (unlike §15q/precedent libs):

--send "qiufeng"        # English id (get_id, 3-10 lowercase letters)
--send "y"               # confirm new-character creation (confirm_id)
--send "test12345"       # password (new_password, >=5 chars)
--send "test12345"       # password confirmation (confirm_password)
--send "[email protected]"  # email (get_email, format-checked)
--send "f"                # gender (get_gender)
--send "秦风"            # REAL Chinese name (get_name -> check_legal_name)
--send "look"
--send "quit"

Result: prompts advanced correctly at every step; "秦风" (2 real Chinese characters) was accepted by check_legal_name (no rejection message), immediately followed by 目前权限:(player) (confirms make_body/enter_world executed, not a silent stall) and then the full MOTD banner, the game's opening-room description ("巫师神殿" — Wizard's Temple), and 你连线进入这个世界。 ("You have connected into this world.") — full success into actual gameplay, not just past the name prompt. Zero "编译时段错误"/error text of any kind reached the player after the §15w fix (compare against the FIRST test run, before that fix, which did show ~40 lines of warning-spam during this exact same step).

Second pass, reconnect + quit (separate connection, same character):

--send "qiufeng"
--send "test12345"      # get_passwd (existing save found)
--send "look"
--send "quit"

Result: 重新连线完毕。 ("Reconnect complete") → room re-displayed correctly (with a wandering NPC, "龙虾", visibly present) → 你重新连线回到这个世界。 → look re-displayed the room → quit → 欢迎下次再来!你(qiufeng) 离开游戏。 (clean disconnect message). Confirms save/restore and the full session lifecycle work, not just first-time character creation.

Third pass with a fresh id and a 3-character Chinese name ("王小虎") also succeeded identically, confirming the fix isn't a fluke tied to one specific name length.

lpcc sweep

scripts/lpcc_check.sh libs/huoying/config.fluffos libs/huoying/work: 457/466 pass (98.1%). Remaining 9 failures, all read individually (not just pattern-matched) and confirmed independent, pre-existing archive gaps/incompatibilities rather than conversion bugs — left unfixed per the "breadth over depth" policy, documented here as known issues:

Process notes

2026-07-23 re-verification pass (driver rebuild + formatter + WASM)

WASM-enablement pass (2026-07: loopback-allow + throttle exemptions + admin seeding)

Standard pass per AGENTS.md §1.3b/e + §1.5. Gates found and patched (loopback = 127.0.0.1/127.*/empty/non-string/malformed IP, defending against the WASM query_ip_number() garbage-return bug):

- :120 — ENABLE_ANTISPAM per-IP registration throttle in logon() ("创造的人物太多" ≥10 registrations per IP per reset → reject); - :180 — ENABLE_BAN_SITE banned_ip/banned_hostname pattern gate in get_id() (both lists ship empty, but the gate is live); - :589 — check_ip() per-account IP whitelist (okip property): loopback always passes.

Admin account: fluffos / Mud@2026 / 浮浮, registered through the real native flow (id → y → password ×2 → email → gender m → Chinese name). Granted (admin) via adm/etc/wizlist (added fluffos (admin) alongside the original acme (admin)). Verified after restart: login shows 目前权限﹕(admin), wizard-vision file paths visible in room descriptions, update /world/area/wizard/guildhall recompiles the room. Save files (must be committed): work/data/user/f/fluffos.o, work/data/login/f/fluffos.o.

Retest: fresh registration (秦风/ceshizhe) end-to-end + look/score/quit clean; fluffos login + update clean; a stray typo character (flufos) created during testing was deleted; one single "Too long evaluation" eval-cost overrun was observed once in world/area/wizard NPC-inventory creation during a first-touch lazy-compile burst (content-side, did not recur on subsequent sessions, unrelated to this pass's patches); data/chinese.o runtime churn reverted.

Dual-mode verification pass (2026-07-24)

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

One continuous native-driver session via scripts/mudclient.py (port 40059), test character qftester/秦风 (password Test1234, [email protected], male).

Verified working, zero runtime errors in debug.log/driver stdout across the whole session (only harmless pre-existing compile warnings — unused locals, unknown #pragma): full registration wizard (id → confirm → password ×2 → email → gender → Chinese name), MOTD pagination, look/score/i all render correctly with no ANSI/formatting corruption, clean quit, prompt reconnect after both a clean quit and a simulated net-dead (raw socket abrupt-close) disconnect — both resumed in the exact correct room with no state loss and no §7.20/§7.36-class stranding.

Scope-limiting discovery, not a bug: include/login.h's START_ROOM is hardcoded to /world/area/wizard/guildhall.lpc (the wizard-staff guildhall — bug-report board, academy, propose room, meeting room, "black magic" bug-squashing room), and world/area/ contains only the wizard/ subtree — there is no other room/zone anywhere in this archive. Confirmed this is a property of the archive itself, not a conversion gap: substantial NPC/weapon/food/item template content exists under world/npc, world/eq, world/item, etc. (466 .lpc files total), but with no non-wizard rooms to place any of it in, none of it is reachable through normal navigation. This means the lib is playable end-to-end for what geography exists, but the round-two checklist's combat/skill-learning/sect-join/shop steps could not be exercised — not because of a bug, but because there is genuinely no ordinary-player game world to test them in. Documenting honestly rather than fabricating a test of content that isn't there.

Not verified live (only reachable via a genuinely unfinished part of the archive, or requiring a full 900s wait not attempted this pass given the above): a full-duration net-dead force-quit; skill learning; sect/ faction join; shop purchase; combat/death. The training-dummy object world/npc/stake.lpc (accept_fight() unconditionally returns 1, a real safe-sparring NPC) exists in the archive but isn't placed in any reachable room either.

No bugs found or fixed this pass — the lib is clean for everything actually reachable. No code changes; test character save data removed after testing.

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

Naruto 题材的 ES2/Neolith 引擎 mudlib(火影);这是正统、可游玩的原版——hy2(078,火影 (2).rar)是同一份压缩包的第二次上传,确认除排版外逐字节相同,而且它自己的 duplicate_of 已经正确指回这个 slug。这份档案自己的 duplicate_of 之前被误设成一个不存在的压缩包文件名(火影.rar),现已清除。

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

§7.114 fix: private input_line() broke multi-line to/board/mail/chfn input (2026-08-19)

Same ES2-ancestry bug as zzhj/shzs/dfgs2 (AGENTS.md §7.114): work/feature/user/edit.lpc (this lib's F_EDIT mixin, inherited by obj/user.lpc) declared its input_to() re-arm target private: private void input_line(string line, string text, function callback). The recursive re-arm from inside input_line() silently failed to register once reached through the inherited mixin, so any multi-line .-terminated input session (board post, to, mail, chfn) dropped everything after the first line. Fix: dropped private.

Live-verified on a fresh driver boot (port 40059), fresh character (秦三八/qinsanba): to say → two lines of text → . → resulting say output showed both lines (你说道﹕test line one\ntest line two), not truncated after line 1. Killed the driver by exact PID when done.

Files modified this pass:

§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). 7 live

replace_program(ROOM); occurrences: 5 room files under world/area/wizard/*.lpc (bug.lpc, propose.lpc, newbie.lpc, guildhall.lpc, academy.lpc) plus this lib's own room-building tool obj/roommaker.lpc's string-builder template (mixed tab/space-indent variant, hand-fixed). 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.126 sibling-sweep fix: stale pre-.lpc extension in AREA save data (2026-08-28)

Flagged in AGENTS.md §7.126 as a sibling worth checking (originally found on naruto, same ES2/Neolith "Annihilator" AREA-engine lineage). std/area/map.lpc's file_path() has the identical macro-placeholder resolution shape as naruto's, with no strip of a stale trailing .c left over from this project's own .c→.lpc conversion pass. Unlike naruto (210 affected save files), this lib's built-out AREA-grid world is much smaller — only 2 .o save files exist under world/area/, with exactly 1 stale __DIR__...c" reference (world/area/wizard/wizard.o). Fixed with the identical choke-point strip in file_path() regardless of the small blast radius, since the fix is a no-op for already-correct .lpc-suffixed values and costs nothing to apply. Verified via a clean native driver boot; not independently live-reproduced by walking onto the specific affected exit tile (small enough impact that a from-scratch reproduction wasn't warranted given the fix is a verbatim, already live-verified port from naruto).

§10.7 deep functional test, round three (2026-09-01): actually exercising the wizard-guildhall's own content

Given round two's finding that the entire reachable game world is the 5-room wizard guildhall (bug/black-magic room, academy, propose room, meeting room, guildhall itself — world/area/ has no other subtree), this pass's angle was to actually USE every one of those rooms' real commands rather than just visiting them, plus adversarial input and a fresh look at the enable_commands()/net-dead/currency bug classes flagged this session on unrelated lineages.

Bug board (bug.lpc room → /daemon/board/bug, the §7.86 fix): live-verified for real this time — west to the black-magic room, post <title> / body / . succeeded cleanly, read 1 displayed the posted message correctly, board listing updated ([ 1 张留言 ]). Also threw adversarial post content at it (%n%d%s in the title, %s plus odd characters in the body) — the board's title/body fields are stored and displayed as plain data, never passed through sprintf/printf as part of a format string, so no crash. Zero debug.log errors.

Academy (/daemon/board/design) and propose room (/daemon/board/propose): both are the same BULLETIN_BOARD base class as the bug board with just a different board_id/location — confirmed by reading daemon/board/design.lpc and propose.lpc alongside bug.lpc (near-identical create() bodies). No separate custom command surface beyond the inherited board verbs already exercised above, so a second live post there would just be retesting the identical inherited code path — not repeated.

Meeting room (meetingroom.lpc) — real bug found and fixed (new catalog entry, see below): its own say/start/over verbs are a genuinely custom, non-board command surface. start/over are wizard-gated and log cleanly via a safely-parameterized sprintf. But say's own meeting-transcript logger built its sprintf format string by directly concatenating the raw player-typed message onto a string literal, instead of passing the message as a %s-bound argument. Live-reproduced as fluffos (admin) with an active meeting: typing say hello %s world %d test while meeting_trigger was set threw *(s)printf(): More arguments specified than passed. (arg: 1) straight to the player's screen (caught by the driver's own top-level command handler, so it doesn't crash the process, but it's a real, easily-triggered runtime error visible to any non-wizard player in the room during a meeting, not just the wizard who started it). Fixed by splitting the format string from the data: sprintf("%s说道﹕%s\n", this_player()->name(1), msg). Verified live: after a wizard update of the room, the identical %s/%d-laden message now logs and speaks normally with zero errors. New AGENTS.md §-worthy bug class: a user-supplied string spliced directly into a sprintf/printf format string (as opposed to passed as a %s argument) lets any embedded % directive in player input crash the call — grep pattern sprintf("[^"]*"\s*\+\s*<var> (a literal format-string prefix concatenated with a variable, not passed as a trailing argument) is a good detector. Checked the rest of this lib's sprintf call sites for the same shape (cmds/usr/tell.lpc, cmds/usr/reply.lpc) — both already correctly pass the user message as a %s argument, not spliced into the format text, so they're safe; only meetingroom.lpc had the bug.

Sibling check: naruto (same ES2/Neolith "Annihilator" lineage, already cross-referenced for the §7.126 AREA-save fix) has the byte-shape-identical bug in its own world/area/wizard/meetingroom.lpc's say() — fixed there too (sprintf("%s說道﹕%s\n", this_player()->name(1), msg)), verified with a standalone lpcc config.fluffos /world/area/wizard/meetingroom compile (clean, no errors) since naruto's own driver wasn't booted this pass.

§7.19-class reentrancy check: grepped every file calling enable_commands/enable_player for a co-located init() (the shape that crashes a room's first-ever visit via NPC setup()/reset_me() recursion). Only hit is feature/char/command.lpc's own enable_player(), called from the player's own login/reconnect path, not from any NPC's init() — no candidate NPC in this lib's tiny reachable world has this shape. Not applicable here.

Currency/query_autoload() check (the severe fysjmb/Fengyun- lineage §7.199 bug): std/money.lpc here already has string query_autoload() { return query_amount() + ""; } live and uncommented — not the Fengyun lineage, not affected.

Net-dead / tell_room() 2-arg wrapper crash (the dtsl §10.7 severity escalation): huoying was already confirmed clean for the related heart_beat-loss-on-reconnect bug class in an earlier corpus sweep (2026-08-19 batch 1). This pass additionally confirms the message()/tell_room() wrapper itself is already on the safe, guarded form (adm/simul_efun/message.lpc's message("tell_room", str, ob, exclude || ({}));, applied as the §15s fix at onboarding) — not re-triggered by anything exercised this pass. Did not attempt the full 900s net-dead wait live (no new evidence surfaced this pass suggesting this lib's user_dump() path has the unguarded-wrapper shape that made it worth the wait on dtsl); low remaining-risk given the wrapper fix is already in place and independently verified.

Adversarial input: over-length email (5000 chars) correctly rejected by the existing 64-char bound with a clean re-prompt, no crash; a name containing a stray Latin %s inside otherwise-Chinese text was rejected/re-prompted by check_legal_name() with no error; board posts with %n%d%s-laden titles/bodies rendered as inert plain text. Zero debug.log runtime errors across the whole adversarial pass.

Files modified this pass:

Test character saves (advtest, hytestone) and incidental board/ admin-account save churn removed after testing; driver killed by exact PID.

深度功能测试(§10.7,2026-10-05)— tail() simul_efun

scripts/lpc_add_tail.py --apply: cmds/wiz/tail.lpc calls tail(file), an efun of the MudOS this archive ran on that FluffOS does not have (Undefined function tail: the command did not compile). adm/simul_efun/file.lpc now defines void tail(string file): the last 10 lines of the file, written to the player. Load check (HEAD against the working tree): 1 of the 1 tail command file(s) failed to load at HEAD, all load now, and the simul_efun file loads. KB 04 §6.2.

深度功能测试(§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 两行,网页版每位访客的终端里都看得到。adm/obj/master.lpc 补上了这两个 apply:作者返回 get_root_uid(),域返回 get_bb_uid(),正是驱动缺少它们时所用的值。域名等于 backbone 域时,驱动让对象沿用创建者的域,与没有这个 apply 时相同(KB 06 §7.222)。两个新函数不加 nosave(本主控其余函数的 nosave 会触发 Illegal to declare nosave function 警告,属于本库尚未做的警告清理)。用 lpcc config.fluffos /nonexistent.lpc 前后对比,主控载入段只少了这两行。

深度功能测试(§10.7,2026-10-05)— 编译警告清理

1. 编译警告:启动时 约 30 条 → 0,整树扫描 215 条 → 0。scripts/lpc_warnings.py --fix:28 个 nosave 函数改 protected(被别处按名调用的 4 个去掉 nosave 保持 public)、删 CD/MudOS 专用 #pragma、删 112 个未用局部变量、29 处无效转义(BIG5 第二字节 0x5C 转码后残留的 \,如 不允許\你,KB 03)、2 处补 varargs;lpc_audit_removed_locals.py 复核 175 个被删声明,标出的 apply 是本文件的 apply() 函数调用,不是被删的变量。手工:logind 的 #if 0 分支变量移入同条件声明块,httpd 删无用的 q = query_ip_port()。 2. std/room/hockshop.lpc 的 remove() 声明为 int(父类 room 是 void),而且没有调用 ::remove(),当铺被销毁时不会像其他房间那样清理它放出去游荡的 NPC。改为 void remove() { save(); ::remove(); }。logind 的 init_new_body() 里只声明不用的 penalty 删除。 3. version 用了旧驱动的 __DRIVER__ 宏(本驱动没有,指令编译失败),改为只印 __VERSION__。cmds/adm/socket.lpc 调用 MudOS 的 dump_socket_status(),改用 socket_status(),并以 #ifdef __PACKAGE_SOCKETS__ 保护(KB 01 §1.3(c))。 4. 仍无法编译、无人引用的孤立文件(不改,属内容缺口):obj/water.lpc(F_DRINK、feature/drink 不在本档案)、world/item/mj.lpc(ansi2.h)、world/item/gobang.lpc(path.h),都是从别的库带进来的。 5. 验证:§9 格式化(4 个文件只调整 :: 前的空格)后全新启动 0 警告;fluffos 登录 → who、version、tell、reply、socket、score、quit 全部正常。

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

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

表情档读不出来(2026-10-15,KB 03 §4.4)

data/emoted.o 的结尾是 ]),],少了最后一个 )(raw/ 原档就是这样),restore_object() 报 Illegal mapping format,表情系统一个表情都没有。补上括号,驱动核对能读回。

存档读不出来:字符串里的换行、空行(2026-10-15,KB 03 §4.4)

data/questd.o、world/area/wizard/hockshop.o:字符串里有原样的换行(save_object() 存成 \r,restore_object() 逐行读,原样的换行让字符串收不了尾),或有空行(Illegal file format),读档的对象(留言板、NPC、玩家)从空白开始。换行改写成 \r、删去空行(scripts/lpc_save_encoding.py --from-raw),驱动核对全部能读回(scripts/lpc_save_restore_check.py)。

move() no longer raises on a destination file that does not exist (2026-10-18, KB 06 7.96)

move() of feature/move.lpc used err = catch(dest = load_object(dest)) as an existence test, but load_object() of a missing file returns 0 and the catch never fires; dest->receive_object() then raised Bad argument 1 to EFUN call_other(). A bulletin board whose location is a wizard's room the archive lacks died in std/bboard.lpc setup() and took the room that creates it along. if (!objectp(dest)) return 0; after the catch: the move fails and the object stays where it is. The sampled boards already loaded, so this is a safeguard.

if (x = 常量):条件里写成赋值的比较(2026-10-20,KB 06 §7.290)

if (arg = "button" || arg = "按钮")、if (!arg || arg = "") return 0;、else if (check = 0 && tempB != ""):把 == 写成了 =,条件的值就是那个常量,分支对所有非零数和任何字符串(连 "" 都算)永远成立、对 0 永远不成立,变量还被覆盖;驱动对此没有任何警告。每一处 = 改成 ==(scripts/lpc_fix_cond_assign.py,共 3 处)。改动:/world/item/mj.lpc(3 处)。

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

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

sefun cat():缺文件时 write(0) 报错(2026-10-20,KB 06 §7.297)

void cat(string file) { write(read_file(file)); }:文件不存在(压缩包没带的欢迎/公告文件,或只有运行中的 mud 才会写的日志)时 read_file() 回 0,write(0) 在本驱动里报 Bad argument 1 to receive(),调用者(登录对话、cat 指令)被中断;老驱动什么也不打印。改成 write(read_file(file) || "");(scripts/lpc_fix_cat_unchecked.py)。改动:/adm/simul_efun/file.lpc。

翻页器 start_more(read_file(...)):文件缺失时 explode(0)(2026-10-20,KB 06 §7.300)

东方故事系的翻页器 void start_more(string msg) { ... explode(msg, "\n") ... } 被这样调用:start_more(read_file(HELP_DIR + "help/topics"))、start_more(read_file(NEWS))。压缩包没带的文件使 read_file() 回 0,explode(0, ...) 在本驱动里报 Bad argument 1 to explode()(不带参数的 help 指令就是这样出错的),老驱动把 0 当空文本。在 start_more 开头加了 if (!stringp(msg)) return;(scripts/lpc_fix_start_more.py)。改动:/feature/user/more.lpc。

存档里的 .c 文件名改成 .lpc(2026-10-21,KB 03 §4.2 第 9 项)

存档里写着 "/d/city/npc/wei.c" 这样的文件名;extract 时源文件已经全部改成 .lpc,而驱动对带扩展名的路径只认字面,new() / load_object() / move() 都找不到它,调用方多半把失败当成「没有这个东西」悄悄跳过。本库 1 个存档共 1 处按 scripts/lpc_fix_save_dotc.py 改成 .lpc(只改 .lpc 存在而 .c 不存在的字符串;玩家存档、备份、留言板、巫师目录和文件索引缓存不动)。改动:/world/area/wizard/hockshop.o(1 处)(共 1 个存档)。

chpass:先把参数写进日志,再对它 sscanf(2026-10-21,KB 06 §7.336)

管理员扫描里 chpass 不带参数报 Bad argument 1 to sscanf() Expected: string Got: 0.(cmds/adm/chpass.lpc):指令先 log_file("nosave/CHPASS", ... arg)(%s 吃得下 0),再 sscanf(arg, "%s %s", userid, new_passwd)。静态扫描只看第一次提到参数的语句,现在会越过这种只是打印或记录的提及;在记录之前加 if (!arg) return notify_fail("指令格式:chpass <使用者代号> <密码>\n");。

log/ 下的日志子目录没有人建:写日志的 write_file() / log_file() 报错(2026-10-22,KB 06 §7.358)

这个库的代码往 log/ 的 2 个子目录写日志:log/http(obj/http.lpc)、log/intermud(adm/intermud/i2d.lpc)。压缩包、git clone 和站点包里都没有这些目录(本地启动没有写过它们,gen_keep_dirs.py 没记),write_file() 对不存在的目录抛 *Wrong permissions for opening file /log/dlog/money for append. "No such file or directory",调用它的函数在写日志那一行中断,后面的奖励、标志、步骤都没有执行。本库的 log_file() 是 write_file(LOG_DIR + file, text),目录不存在就抛同样的错误(实测)。把 log/http、log/intermud 记进 scripts/wasm_keep_dirs.txt(scripts/lpc_keep_log_dirs.py;站点和 pristine 树按它建空目录)。证明(scripts/lpcc_eval.py,在 /adm/daemons 这类目录下的求值对象里写 /log/zzdirprobe/...,新进程)见 KB 06 §7.358 的实测表。

按字节写的汉字循环、茶馆猜诗和同盟频道标题(2026-10-23,KB 06 §7.363)

老档按字节做「一个汉字」:while (i--) if (i % 2 == 0 && !is_chinese(name[i..<0])) 只检查偶数下标,奇数位上的拉丁字母(张a)会过;茶馆猜诗 mixup() 用 strlen(str)/2 再 j=j+j、str[k..k+1] 交换两字节;泥潭系 channeld 的 switch (strlen(fname)) case 4/6/8/10 和 strlen(family)==4/6 按字节长度给同盟 / 门派名加空格。本驱动的 strlen() 和区间都按字符算。scripts/lpc_fix_byte_char.py:去掉奇偶项、把区间改成 name[i..i],按字符重写 mixup() 并把 strlen(first)>=14 折成 7,频道标题的 case / 门派长度改成字符数(对照 aoxiangtianji)。本库 汉字循环 / is_chinese 区间 1 个文件。证明(scripts/lpcc_eval.py):sjplii 的 check_legal_name 在 HEAD 接受「张a」、改后拒绝,两边都接受「张三」;xkx100 的 clubpoem->mixup("离离原上草") 得到「离离原草上」(真交换汉字);nitan_san 两字同盟名得到 【 兄 弟 】。关键对象加载通过。

深度功能测试(2026-10-27,§6.10 未知 pragma save_binary/optimize)

删除本库中 FluffOS 不认的 #pragma save_binary / #pragma optimize… 行。