info.html · 介绍 · play.html · 游玩 · llms.txt · 下载与本地运行 · ZIP · GitHub
游戏登录后自报家门为"地狱泥潭---爱若幽兰"(压缩包标题为"终极地狱之爱若幽兰"),属于 ES II → XKX → "地狱"(Hell/Doing 血统)引擎家族,与 `hell`、`zjdy2008wzb`、`zjdywzb`、`zjdyzj`、`zjmudhell` 共六个档案共享同一个门派江湖世界(逐字节地图比对显示与 `zjdy2008wzb` 高达 95% 一致,与最近的姊妹版 `zjdyzj`(指间MUD版)也有 94% 一致——两者 master 文件内容几乎完全相同,与 `zjdywzb`、`zjmudhell` 则更疏远、约 73-79%),是同一份原作世界反复重制的六个版本之一而非各自独立的游戏;与 `zjdyzj` 不同,本作保留了普通 telnet 注册流程而没有接入手机客户端专属协议层,也和名字同样带"终极地狱"字样、但内容完全不同的 `zhongjidiyu` 没有任何关系,只是名字碰巧相似。
English
Introduces itself in-game as 'Hell's Quagmire — Ai Ruo You Lan' (the archive's own title is 'Ultimate Hell: Ai Ruo You Lan'). Part of the ES II to XKX to 'Hell' branch of the engine family, and part of a six-way 'Hell'/Doing-lineage map family with this collection's hell, zjdy2008wzb, zjdywzb, zjdyzj, and zjmudhell — a byte-level, line-ending-normalized room-tree comparison found it 95% identical to zjdy2008wzb and 94% identical to its closest sister zjdyzj ('Fingertip MUD' edition, sharing the same 'Hell' engine core down to near-identical master-file content), with that same map only ~73-79% identical to zjdywzb/zjmudhell — one shared authored wuxia world reused across all six builds, not a handful of coincidentally similar titles. Unlike zjdyzj, this build keeps a plain telnet registration flow rather than a mobile-client protocol layer. Not the same game as zhongjidiyu, another archive in this collection that also happens to carry 'Ultimate Hell' in its name.
README
内容亮点
- 同样是"地狱"世界观下的武侠向 MUD,主题偏"爱若幽兰"这一支线剧情,整体 系统架构和
zjdyzj基本一致(角色创建、门派、装备系统 等),但没有那个版本专属的手机客户端协议层,可以直接用普通 telnet 客户端游玩。 - 修复了一个原始存档就有的老 Bug:每次重启后的第一次登录所有命令都 无效(连 quit 都提示"什么?",第二次登录才正常),现已修复。
- 又修复了一个每次连线都会触发的独立 bug:
clone/user/login.lpc的query_save_file()只判断了 id 是不是字符串,没有判断是不是空 字符串——连线的第一时间 id 还没设置好,id[0]在空字符串上取值 会得到整数 0,sprintf的%c格式一遇到这个 0 就直接报错崩溃, 表现症状和上面那条老 bug 很像(同样是"看起来命令全部失灵"),但 根源不同,两个都已修复(姊妹档案zhongjidiyu、zjdyzj也有同样的问题,一并修好了)。
在线试玩
https://mudlibs.fluffos.info/zjdyaryl/
管理员账号 / Admin account
- ID:
fluffos中文名: 浮云 - 普通密码(日常登录用):
Mud@2026 - 管理密码(找回/改密用):
Admin@2026(本 lib 强制两个密码不能相同, 因此管理密码与标准约定不同,特此说明) - 权限:
(admin)(最高级;通过adm/etc/wizlist授予)。 - 该账号尚未做游戏内"注册邮箱 + 投胎"流程,
score会显示"还没有出生呐", 属正常现象。
警告:这是一个公开的默认密码,仅供本地/浏览器试玩。正式对外开服前
请务必修改这两个密码。
本地运行
cd libs/zjdyaryl
~/src/fluffos/build-debug/src/driver config.fluffos游戏端口:40073。
NOTES · 移植与修复记录
终极地狱之爱若幽兰 (Ultimate Hell: Love Like Orchid) — archive #79
Source archive: archives/终极地狱之爱若幽兰1.166正式版.rar
Slug: zjdyaryl (matches the archive title; no discrepancy —
the config's own name field is №㊣地狱泥潭---爱若幽兰㊣№......, i.e.
"地狱泥潭" (Hell Nitan/Swamp) + "爱若幽兰" (Love Like Orchid), matching
the archive title exactly). Port: 40073.
Real mudlib root: the archive's top level is
终极地狱之爱若幽兰1.166正式版/, containing:
doing/config.revive(the real config file) +doing/doing_hell/— the actual mudlib (this is what got extracted/converted).doing/mudos.dll+doing/osxp.exe— a prebuilt Windows MudOS driver, ignored (we use our own FluffOS build).客户端1.166/— a Windows GUI mud client (mud.exe,.OCX,.CHMhelp), not part of the mudlib, ignored.套装说明/文件/— documentation with illustrative example.csnippets (score.c,arm.c,equip.c,attribute.c,skills.c,suit.c,skill.c) showing site admins how to add equipment "suits" — NOT the real mudlib source, just docs, ignored (not converted).angelus1.166说明(务必看看).txt— readme; in-game banner credits author "ANGELSS" and a QQ contact number.
Lineage: confirmed ES II → XKX → "hell" fork via adm/single/master.lpc's
own header credit chain: "for ES II mudlib / original from Lil / rewritten
by Annihilator (11/07/94) / modified by Xiang for XKX (12/15/95) / updated
by Doing Lu for hell (2K)", and adm/daemons/securityd.lpc's matching
"Modified by Xiang for XKX / Updated by DOing Lu for ULTRA HELL". Same
adm/single/{master,simul_efun}.lpc + adm/daemons/* "Century"-style
layout as es1_win/esI/xkx2001/rzrmud/bmxkx2001/
kxkj/yueyingqiyuan/wuhanzhan/yanhuangwuhun/haiyang2/
kxkj1/xuanjianlu/shenzhou/shenmo. NOT related to the
nitan/NT/Lonely lineage despite "泥潭" appearing in the display name —
that word is just part of this fork's own branding ("Hell Swamp"), not a
signal of the NT/nitan/Lonely engine family; confirmed via feature/
dbase.lpc (real local set/query/delete methods, not the bare
simul_efun dbase-sharing architecture bug of §15).
CROSS-CHECK FLAG for the main session: archives #78 (终极地狱.rar)
and #80 (终极地狱-指间mud版服务端.rar) share the "终极地狱" name and were
being processed by sibling agents concurrently with this one — could NOT
cross-check lineage/duplication against them here. Per this project's
repeated experience (documented many times in TODO.md — sjpl2
vs shujian2008, xianlvqiyuan vs xlqy_new2007, kxkj1 vs
kxkj, etc.), similar/identical Chinese titles are NOT
a reliable lineage signal — verify via diff/md5sum on core files
(master.c, chinese.c, securityd.c, logind.c) once all three
archives are done, rather than assuming they're the same game or
unrelated just from the shared name.
Fixes applied
Proactive (applied before first boot, from the AGENTS.md catalog)
1. §15h is_chinese() (adm/simul_efun/chinese.lpc) — GBK byte-range
check (str[i] < 176 || str[i] >= 248, paired-byte loop) replaced with
a CJK Unified Ideographs codepoint range check (0x4e00..0x9fff), one
character per index. Standard fix; this WAS the blocker for real
registration in every earlier-processed lib until §15h was discovered.
2. §15h deep named.lpc fix (adm/daemons/named.lpc) — this lib has
the full "nitan-family-shaped" deep pattern despite not being nitan
lineage:
- PATH(name) macro: name[0..1] (first GBK byte-pair) → name[0..0]
(first character).
- strlen(name) < 2 (×3 call sites: remove_name, who_is,
invalid_new_name's initial null-check) → strlen(name) < 1.
- invalid_new_name's combined-length gate strlen(name) < 4 → < 2.
- Sliding-window substring checks: name[i..i+3] (4-byte/2-char
window) → name[i..i+1]; name[i..i+5] (6-byte/3-char window) →
name[i..i+2]; loop bound i <= l - 4 → i <= l - 2; inner guard
i + 6 <= l → i + 3 <= l.
3. §15h logind.lpc check_legal_name — byte-width bound maxlen
halved (strlen(name) > maxlen → > maxlen / 2; lower bound < 2 →
< 1), plus the separate combined surname+given-name length check
(strlen(fname) < 4 → < 2) in get_name(). Both match the
in-game prompt text exactly ("不要超过两个汉字" = max 2 characters;
"姓和名的组合至少要有两个汉字" = combined min 2 characters).
4. §14 valid_override 3-arg upgrade (master.lpc) — added the
main_file parameter and an main_file == SIMUL_EFUN_OB/MASTER_OB
check, insurance for any efun::-override fragment #included into
simul_efun.lpc/master.lpc rather than being that file itself.
5. §8d/§15o get_include_path() (master.lpc) — was completely
absent; added the standard "prepend the compiling file's own
directory" implementation so mid-connection lazy compiles of any
same-directory #include resolve correctly (compile-time-only/preload
compiles already work via the config's include directories, but a
live compile triggered from inside a connection needs this apply).
6. §15n securityd.lpc custom-ACL allowlist — this lib has a
genuinely custom exclude_read/trusted_read ACL (not the simpler
find_object(SECURITY_D)-only master.lpc pattern), so added the
standard switch(func) { case "load_object": case "recompile_object":
case "include": return 1; } early-allow to valid_read() before any
euid/status logic — compiling/including code should never be gated by
a fresh, not-yet-authenticated connection's (player) ACL status.
7. §15p dns_master preload exclusion — /adm/daemons/network/
dns_master was present in adm/etc/preload; commented out (the
master.lpc's own update_file() already strips #-prefixed lines,
confirmed by reading it before relying on the comment-out).
8. §15ae command_hook private bug — feature/command.lpc declared
its central add_action dispatch hook as private nomask int
command_hook(string arg). This driver treats private as hidden from
add_action's external dispatch once inherited into another object
(the player body class here) — would have silently broken every
post-login command (including look) with zero visible error anywhere.
Dropped private, kept nomask. Confirmed via testing this was the
single most important fix — verified look/score/i all actually
dispatch and produce real output, not silence.
9. §15w log_error() warning-spam gate (master.lpc) — applied
proactively as insurance: gated the player-facing broadcast
(efun::write/tell_object) on the message NOT containing
"warning:", so ordinary compile warnings (e.g. the nosave-function
warnings from fix #10 below) don't spam a connected wizard-level
player during any lazy compile. Everything still gets logged to
/log/log unconditionally.
Found reactively (boot + lpcc sweep)
10. §3 static→nosave blanket sed, and its counterexample —
convert_lib.sh's automated pass touched 128 files. As expected from
the moniHuafu precedent, this lib ALSO uses a "static/xxx" naming
convention extensively — both as log_file("static/XXX", ...) paths
(a REAL /log/static/ directory ships in the raw archive) and as
dbase property-key namespacing (->query("static/marry"),
->query("static/sadly"), etc — internally self-consistent either
way, but reverted anyway for clarity/no-surprises). Found 51
files with "nosave/... string-literal corruption after the sed;
reverted all of them back to "static/... with a scoped
quote-anchored sed ("nosave/ → "static/), verified zero remaining
"nosave/ hits afterward. feature/treemap.lpc's nosave nomask
(originally static nomask) function declarations compile fine — no
ordering/collision issue there.
11. §15s message()-wrapper crash (adm/simul_efun/message.lpc) —
the local message(mixed arg, string message, mixed target, mixed
exclude) override forwarded straight to efun::message(...), but
tell_room()'s common 2-arg form (tell_room(room, msg), no
exclude) leaves exclude at its varargs default of raw int 0,
which this driver's real message() efun rejects (Expected: object,
array, Got: int(0)). This crashed every do_channel() broadcast
at preload time (channeld.lpc → message() → simul_efun's message())
— 8+ daemons hit it during preload alone (natured, punishd, storyd,
eventd, memoryd, backupd, ftpd, cpud, questd). Fixed once at the
shared root: normalize exclude to ({}) when it's neither an
object nor an array before delegating to the real efun. Confirmed
fully resolved — zero Bad argument 4 to EFUN message() errors in a
fresh boot after the fix (down from ~10 per boot before it).
12. §2 .c→.lpc rename-width bug ([0..<3] → [0..<5]) — found
5 genuine sites (all listing/stripping a *.lpc-glob'd filename's
extension): adm/daemons/storyd.lpc, adm/daemons/eventd.lpc,
adm/single/importer.lpc (one of its two [0..<3] sites — the
sprintf("...item/%c/%s", ..., item_name[0..<3]) one, explicitly
commented "去掉后面的 .c 字样" / "strip the trailing .c"), and
adm/npc/luban.lpc (2 sites, both stripping a player-built room's
.lpc filename before a DBASE_D->clear_object() call). Left
alone: importer.lpc's OTHER [0..<3] site inside
get_user_list() — that one strips a DIFFERENT, unrelated
(2-char, .o-shaped) save-data filename extension, not something
our .c→.lpc rename touched; it's part of a legacy migration tool
not on the registration/gameplay path, so left as pre-existing
(possibly already buggy, out of scope).
13. §15b is_killing() type mismatches (direct calls passing an
object where the function declares string id, only caught by this
driver's static type checker on DIRECT calls, not ->-based
call_other):
- clone/user/user.lpc's accept_kill(object ob) — is_killing(ob)
→ is_killing(ob->query("id")). This is the player body class
— broke make_body() silently, exactly matching this bug's
documented signature (registration completes through gender
selection, then the character never actually lands, with zero
visible error). Confirmed by testing: after the fix, both test
runs reached the actual starting room.
- d/city/npc/guidao.lpc's ask_me() — is_killing(who) →
is_killing(who->query("id")) (a quest/story NPC, not on the
critical registration path, but fixed anyway since it was found via
the sweep).
14. New §8g-shaped shared-root bug: inherit/misc/quest.lpc's
set_information() parameter too narrowly typed — declared void
set_information(string key, string info), but QUEST_D's own real
set_information(object qob, string key, mixed info) already accepts
(and many quest files pass) a function pointer (e.g.
set_information(NPC_NAME, (: ask_npc :))) as the "info" — this thin
wrapper's own narrower string info parameter rejected every such
call with Bad type for argument 2 ( string vs function ). Fixed at
the single shared root (info retyped mixed), resolving 7 quest
clone files at once: supply, explore, capture, deliver,
judge, shen, search.
15. Genuine pre-existing typos found via the lpcc sweep (none related
to encoding/rename — confirmed by checking the raw archive):
- inherit/condition/damo.lpc had two independent bugs in one
file, both cascading into confusing-looking downstream noise:
(a) line 215, return name + HIM "发作身亡了; — missing closing
" before the semicolon. This single dropped quote swallowed
~13 lines of subsequent code as string-literal content, surfacing
as a "syntax error, unexpected L_IDENTIFIER" at a COMPLETELY
different line (228) and "Illegal character 0xe9/0x95/0xbf" errors
at yet another line (281) that are actually perfectly valid UTF-8
bytes for 长/长/的/吁 — pure lexer-desync fallout from the one
missing quote, not real illegal-character bugs (matches §9/§10's
documented cascading-noise pattern exactly). (b) line 228 itself,
independently: intp(cnd["remain"] || ! stringp(cnd["id"])) was
missing a ] — intp() was being called with a whole boolean
OR-expression as its argument instead of just cnd["remain"];
fixed to intp(cnd["remain"]) || ! stringp(cnd["id"]). Fixing both
resolved this file plus its 3 sibling clones (kungfu/condition/
damo_luanqi, damo_shangshen, damo_zheyuan, all of which
inherit it) — 4 files from 2 bugs in 1 shared file.
- kungfu/class/generate/girl.lpc:579 — query_per() called with 0
args where feature/attribute.lpc's int query_per(string arg)
requires 1 (the parameter is never actually used in the function
body, and every OTHER of the 5 real call sites elsewhere goes
through ->query_per()/call_other, which this driver's strict
arg-count check doesn't enforce the same way as a direct call).
Fixed by passing 0 explicitly.
- d/village/npc/obj/shoes.lpc — a set("icon","05047"); statement
got accidentally interleaved mid-argument into a set("long",
...) call (set("long", \n set("icon","05047"); \n"这是...");),
splitting one statement into a syntax error. Reordered so each
set() call is complete on its own.
- d/baituo/obj/bowl.lpc + d/baituo/npc/obj/bowl.lpc (identical
duplicate content shipped in two different zone directories) —
set_name("海口大碗", "bowl") passed a bare string where
set_name(string name, string *id) requires an array; fixed both
to set_name("海口大碗", ({ "bowl" })).
Confirmed NOT needed (checked, absent)
- §4 (lazy
load_object-in-valid_read/valid_writerecursion) —master.lpc'svalid_read/valid_writeonly dofind_object (SECURITY_D), noload_object()call at all; nothing to guard. - §7
get_root_uid/get_bb_uid— already present and correct inmaster.lpc. - §15l
SIMUL_EFUN_OBdestruct inmaster.lpc create()— not present;create()just doeswrite("master: loaded successfully.\n"). - §15z
#define nosave static/#define protected staticcompatibility shim — not present anywhere in this lib. - §15ag
ed_start/ed_cmd/query_ed_mode— zero matches anywhere in the tree; this lib's editor path doesn't use them. - §15u dormant "phone-home license check" self-destruct function — read through
securityd.lpc/master.lpcin full, found no such function. - §15x hardcoded
MUD_PORTconnection gate —master.lpc'sconnect()doesn't check any port constant at all; the only port-dependent code isversiond.lpc's admin-only "version sync" feature, which reads the port dynamically viaget_config (__MUD_PORT__)(not hardcoded) and is non-fatal anyway (see below). - §8e
tail()missing efun — not called anywhere reachable in this session's testing or the lpcc sweep. - §15ab
receive_message()missing!stringpguard —clone/user/ login.lpc'scat()/color_cat()(inadm/simul_efun/file.lpc) ARE unguarded against a missing file (write(read_file(file))with nostringpcheck), matching the general risk pattern — but every file path actually referenced during connection setup (WELCOME,MOTD,UNREG_MOTD,WIZLIST) exists on disk with matching case, so this null-string path is never actually exercised by this archive's content. - §15k case-sensitive data-file mismatch — checked every hardcoded path constant in
include/login.hagainst the actual on-disk filename case; all matched exactly. - §15ac bare
SAVE_EXTENSION— the only match found (cmds/arch/p2.lpc) is a genuine local#define SAVE_EXTENSION ".o"in that same file, not a reference to a nonexistent global constant. - §15af
log_error()callingwizardp()/lazy-loading the security daemon during a compile warning —master.lpc'slog_error()only checksthis_player(1)/this_player()directly, nowizardp()call. - §15/§15v nitan-family simul_efun dbase architecture bug /
LONELY_IMPROVED-gatedefun::family — confirmed not this lineage;feature/dbase.lpcimplements genuine real localset/query/deletemethods (per-object storage viainherit), not a bare simul_efun call pattern.
Confirmed harmless, left unfixed (documented, not chased further)
versiond.lpc/DNS-daemon config-ID mismatch (§15ad-shaped):adm/ daemons/versiond.lpc'sin_server()(fired viacall_out2s after boot, sinceRELEASE_SERVER()=="local"inadm/etc/config) callsget_config(__MUD_PORT__) + VERSION_PORT— on this driver that produces the STRING"12"(not int40085), sosocket_bind(vfd, "12")throws*Bad argument 2 to socket_bind() Expected: int Got: "12". Confirmed harmless:versiond's real job (version_ok = 1) already completes synchronously, several lines earlier in the samesetup()call, before this broken call ever fires. Appears exactly once per boot indebug.log, every single time (both before and after all other fixes) — not chased further, matches the §15ad precedent exactly. The same underlying config-ID/get_configmismatch also fires (harmlessly) inside the standalonelpcc-sweep compiles ofadm/daemons/network/services/ping_q.lpcandadm/ daemons/network/messaged.lpc(both DNS/intermud daemons, both excluded from real gameplay by thedns_masterpreload exclusion — theirstartup_udp()hits the sameget_config()-returns-a-string bug with a different numeric offset, again non-fatal, again not chased).- **11
adm/daemons/story/*.lpcfiles fail the lpcc sweep by design, not bug:anthem,bizhen,jiuyang,sanfenjian,shenzhao,master,pangtong,baguadao,huanyin,jiuzhuan,mengzi. Each one'screate()calls aselect_character()/select_characters()that filtersall_interactive()for an eligible currently-connected** player and callsdestruct(this_object())if none qualifies — by design, these are one-shot "random story/encounter" triggers that only exist transiently while a real player is online. In a barelpcccompile-and-load test (no interactive connections at all), every one of them immediately self-destructs, which the sweep script correctly (but misleadingly) reports as "Fail to load object" / FAIL. Verified this shape in a sample (anthem,master) and confirmed all 11 share the identicalall_interactive()-gated pattern — genuinely not a bug, a §6b-class "divorced from real runtime context" sweep artifact. adm/single/importer.lpcfails the sweep with zero error text at all (Fail to load object, no diagnostic anywhere, not even indebug.log). This is a legacy data-migration/import admin tool (not on the preload list, not reachable from registration or ordinary gameplay) — not chased further per this project's stated policy of not sinking deep debugging time into every edge case across ~100 archives; noted here for whoever revisits it.
Verification
Boot: ~/src/fluffos/build-debug/src/driver config.fluffos from
libs/zjdyaryl/, port 40073. Clean boot, Accepting
telnet connections on 0.0.0.0:40073. Initializations complete. — zero
fatal errors, only the one known-harmless versiond.lpc socket_bind()
line in debug.log (present on every boot, before and after all fixes).
Full registration + post-login flow, verified in two separate
driver sessions, each a SINGLE continuous mudclient.py connection:
- Run 1 (before the sweep-driven fixes, i.e. only the proactive fixes applied): English id
qinfeng→ confirm new idy→ surname秦→ given name风→ admin password ×2 → normal password ×2 → character type1(猛士型/warrior) → genderm→ reached the actual starting room 世外桃源 ("Peach Blossom Spring", a 连城诀-novel-themed room with NPCs 狄云/水笙 present) →look(redisplayed the room correctly) →score(returned "还没有出生呐,察看什么?" — a legitimate pre-birth/pre-registration gate: new characters mustregister <email>then choose attributes/"投胎做人" (be reincarnated) beforescorehas real content to show; confirmed intentional via the welcome banner's own text, NOT a crash or silent failure) →quit(clean "欢迎下次再来!"). - Run 2 (after ALL sweep-driven fixes, fresh reboot): English id
qinling→ surname秦→ given name岭→ character type2(智慧型/wisdom) → genderf→ reached the SAME starting room with correctly gender-specific starting equipment (散花衣/绣花小鞋 vs run 1's 黑色劲装/牛皮靴) →look,score(same legitimate pre-birth message, consistent),i(inventory — correctly listed 2 items with weight%) all produced real, correct output →quitclean. debug.login both sessions: zero new errors beyond the single pre-existing harmlessversiond.lpcboot-time line.- Confirmed
add_action-dispatchedcommand_hookinfeature/ command.lpcis NOTprivate(per the §15ae standing policy) — was foundprivateinitially, fixed, and the fix was empirically verified bylook/score/iall actually producing dispatched output rather than silence.
lpcc_check.sh sweep: 7303 total .lpc files. First pass (before
sweep-driven fixes): 7272 pass / 31 fail (99.6%). After fixing the
genuine bugs found (damo.lpc ×2, quest.lpc shared-root, girl.lpc,
guidao.lpc, shoes.lpc, bowl.lpc ×2): 7289 pass / 14 fail (99.81%) —
the remaining 14 are all confirmed-expected noise (11 story-daemon
self-destruct-when-no-players files + 2 DNS/intermud config-ID-mismatch
daemons + 1 legacy importer with no diagnostic), documented above, none
of them real bugs worth fixing.
Driver was launched via Bash's run_in_background-equivalent
(setsid nohup ... & disown) each time and killed by exact PID after
each test — no pkill -f pattern used.
Status for TODO.md
playable / done — full registration + post-login command flow
verified end-to-end twice, 99.81% lpcc pass rate, zero unexplained
debug.log errors. Cross-check against archives #78/#80 flagged above for
the main session once all three are complete.
Re-verification pass: driver rebuild + formatter + WASM (2026-07)
- LPC formatter applied to all
.lpcunderwork/(7,303 total, 7,273 written, 25 unchanged, 5 self-checked errors left untouched). - Native re-test against the freshly rebuilt driver (
~/src/fluffos/build-debug/src/driver): clean boot, only the pre-existing benignversiond.lpc/socket_bind()line indebug.log. Full registration flow re-verified end-to-end with a fresh id/real Chinese surname+given-name (aryretest/秦岚), admin + regular password, character type 2 (智慧型), gender f, reaching 世外 桃源 with correct gender-specific starting gear (鹅黄夹袄/绣花小鞋);look/score(correct pre-投胎 message)/quitall produced correct output. - WASM test (
scripts/wasm_client.jsagainstbuild-wasm/src): boots, but every connection is disconnected immediately after the banner, before the id prompt appears — root cause is DIFFERENT from thezhonghua2/zhongjidiyufinding in this same batch, and is a test-harness gap, not a mudlib bug or a WASM-driver limitation:clone/user/login.lpc'slogon()unconditionally callslog_file( "static/logon", ...)as its very first statement, with nocatch(). This lib genuinely ships a real/log/static/directory in the raw archive (see fix #10 above — thestatic↔nosavenaming collision section), so natively this always succeeds. Butscripts/ wasm_client.js'scopyDir()deliberately skips copying the CONTENTS of anylog/directory (to avoid wasting time/memory on runtime-churn log data) and only recreates the barelog/directory itself in the in-memory FS — it does not recreatelog/'s real SUBdirectories (static/,user/,channel/,file/, etc.), solog_file( "static/logon", ...)throwsWrong permissions for opening file /log/static/logon for append. "No such file or directory"uncaught, and the driver'snew_conn_handler()disconnects the connection beforeLOGIN_D->logon()(the real registration flow) is ever reached. Confirmed via the raw harness log (the error appears, then immediatelynew_conn_handler: logon() on object clone/user/ login#0 has failed, the user is disconnected., well before anyversiond-related message). Flagged for the orchestrating session:scripts/wasm_client.js'scopyDir()should also recreatelog/'s known real subdirectories (or generically walk the on-disklog/tree creating directories-only, skipping only file contents) — this likely affects every OTHER lib in the project whoselogon()/registration path writes to alog/<subdir>/path unconditionally at connection time, not just this one. Not something I patched myself sincescripts/wasm_client.jsis a shared script used by other agents' concurrent sessions. Separately, this lib ALSO shares the exact same unguardedVERSION_D->is_version_ok()pattern found onzhonghua2/zhongjidiyuin this batch (confirmed by grep —adm/daemons/ logind.lpchas the identicalcatch(MUDLIST_CMD->main()); ... if (!VERSION_D->is_version_ok() ...)shape with no catch on the second call), so even after a harness fix for thelog/static/gap, this lib would likely still hit that second, WASM-driver-level (socketspackage unavailable) limitation — not chased further since the first blocker (harness-level) already fully explains the observed failure. (The VERSION_D gate is now patched — see the 2026-07 WASM-enablement pass below.)
WASM-enablement pass (2026-07): loopback gates + admin seeding
Standard pass per AGENTS.md §1.3b/§1.3c/§1.3e/§1.5:
adm/daemons/band.lpc: newis_local_site(site)helper;is_banned()returns 0 for loopback/empty/malformed IPs.adm/daemons/logind.lpclogon()(~line 76) andget_id()(~line 139):VERSION_D->is_version_ok()gates guarded withfind_object(VERSION_D)(absent ⇒ version ok) — removes the WASM-blocking uncaught throw documented above.adm/daemons/closed.lpcheart_beat()andadm/daemons/questd.lpcstart_all_quest(): same guard (both preloaded).- The
iplimit > 3per-IP cap inlogon()is already#if 0-disabled upstream; no uptime()/anti-flood gates otherwise. - NEW pre-existing bug found & fixed — first login after every boot had ALL commands dead (
update, evenquit→ 什么?), working only from the second login on:logind.lpc check_ok()lazily loadsMESSAGE_D(/adm/daemons/network/messaged), whosecreate()→startup_udp()→socket_bind(fd, "10")throws (the §15ad get_config-returns-string port bug), uncaught, aborting the rest of that first login's setup after enter_world (command path never set). Fixed twice over:messaged.lpc create()nowcatch()esstartup_udp()(the UDP intermud messaging is non-essential and also can't work under WASM), andcheck_ok()wraps theMESSAGE_D->find_chatter()call incatch()(under WASM messaged fails to compile entirely, so the call itself would throw). Verified: first login after a fresh boot now has working commands. - §15aa second instance fixed (
adm/simul_efun/message.lpc): the localmessage()override lacked a forward declaration, so textually-earlier callers (tell_roomet al) bound to the raw efun — surfaced asBad argument 4 to EFUN message()whenupdatemoved the player (tell_room with exclude=0) despite the earlier §15s normalization inside the override. Added the top-of-filevarargs void message(...)forward declaration (same fix as sibling zhongjidiyu) and made the definitionvarargs. - Admin seeded:
fluffos/ 浮云, rank(admin)viaadm/etc/wizlist. Two-password lineage: 管理密码Admin@2026, 普通密码Mud@2026(must differ — deviation documented in README). Registered as plain player first, wizlist entry + restart after. Verified: 目前权限: (admin),update /d/register/entry.lpc→ 成功, clean quit, no errors. - Retest: fresh registration (
regtest/秦风) into 世外桃源 + relogin as regtest (restore path OK — this lib's sec_id checksum is the real implementation, unlike sibling zhongjidiyu's broken stub) + look/ score/quit correct; test saves removed. debug.log: only the known versiond socket_bind line plus the now-catch()ed messaged socket_bind (logged as intercepted) — no new error classes.
WASM long-sit boot-watch pass (2026-07)
200s scripts/wasm_boot_watch.sh sit: ftpd.lpc/versiond.lpc
sockets-absent preload errors match the already-documented §1.3c class
(caught by master.lpc's preload catch(), cosmetic); versiond
compile-and-fail recurs twice in one boot (two separate unguarded
callers reach load_object), same known class, harmless. Proactively
ported two fixes found live on sibling zhonghua2 (shares the
identical inherit/item/combined.lpc and adm/simul_efun/object.lpc
byte-for-byte): dropped private on combined.lpc's destruct_me()
(call_out-self-invocation denied under private→DECL_HIDDEN
inheritance, so spent-down money stacks never self-destruct), and
fixed object.lpc's file_owner() (return name → return dir,
misattributes 3-level-deep /u/<wiz>/<subdir>/<file> log_error writes).
Neither fired visibly in this lib's own sit. Retest: fresh registration
(id arysanb) into 世外桃源, look/quit clean, no regressions.
WASM 修复摘要(迁移自 meta.json 的 group_note)
'hell'/Doing-Lu 引擎基础版。状态已从过时的 limited 修正——本轮修复了一个真实的 bug:clone/user/login.lpc 的 query_save_file() 只防范了 id 不是字符串的情况(!stringp(id)),没有防范空字符串的情况——对 "" 取 id[0] 会回传整数 0,而 sprintf 的 %c 格式会拒绝这个值('Incorrect argument to type %c, must be valid UTF8 char'),在任何 id 被输入之前,第一次自动呼叫 query_save_file() 就会崩溃(每一次连线尝试都会现场触发,把 id 提示搞坏)。已通过额外检查 id == "" 修复(手足档案 zhongjidiyu(052)和 zjdyzj(054)上也应用了同样的修复)。修复后重新验证管理员登录(fluffos/Mud@2026)干净正常,'目前权限:(admin)',quit 正常。
§7.86 跨库扫描修复(留言板 post 崩溃)
BULLETIN_BOARDinherit+ 多余replace_program()致命形状(AGENTS.md §7.86,post命令崩溃):全档案 44 处命中,已删除多余的replace_program(...)调用(保留inherit),逐文件保留原有行尾格式(CRLF/LF 按文件原样)。本次为跨库 §7.86 扫描修复(触发原因:该 bug 已在 6+ 个互不相关的血统家族独立确认,属于近乎普遍的拷贝粘贴模式),仅做编译检查(驱动干净启动、端口正常监听),未做完整 §10.7 深度游玩测试。
深度功能测试 / Deep functional test (AGENTS.md §10.7)
Native driver only (~/src/fluffos/build/src/driver, -DPACKAGE_DB=OFF
ASAN/UBSAN preset), booted from the lib root (libs/zjdyaryl/, port
40073) per §5.2. Client: scripts/mudclient.py (raw-socket, single
continuous connection per invocation) — scripts/tmux_mud.sh was tried
first but this container has no telnet binary at all, so every
session below is a mudclient.py invocation carrying the full
send-sequence in one shot (one TCP connection = one continuous session).
Pre-boot environment gotcha (not a code bug)
First boot in this container hit *Wrong permissions for opening file
/log/log for append. "No such file or directory" (spammed once per
preloaded daemon, caught by master.lpc's own catch(), non-fatal) —
neither libs/zjdyaryl/log/ (lib-root, for debug.log itself, driver
CWD-relative per §5.2) nor libs/zjdyaryl/work/log/{static,user}/
(mudlib-virtual-root, for log_file()/assure_file() targets like
clone/user/login.lpc's log_file("static/logon", ...)) existed yet in
this fresh container — both are gitignored runtime directories that a
prior pass's WASM-enablement notes assumed were already present. Created
both (mkdir -p log log/static log/user, lib-root and work/
respectively) before the real test boot; zero Wrong permissions lines
in every subsequent boot. Not committed (gitignored), noted here so a
future dive in a fresh container doesn't misread the same symptom as a
regression in the already-fixed log_file()/assure_file() pair
(adm/simul_efun/file.lpc's log_file() genuinely still lacks its own
assure_file() guard, matching this lineage's known §7.11 shape, but
every actual call site either goes through an already-assure_file()d
caller — e.g. channeld.lpc — or targets a directory that exists once
the above mkdir -p is done; no live crash reproduced from it this
pass).
Newbie material
clone/misc/newbie.lpc("新手必读") is a read book → HELP_CMD->main(me,
"feature") pointer, but the real onboarding path is entirely
NPC-driven: land in 世外桃源 (d/register/entry.lpc) →
水笙(shuisheng)'s greeting()/do_register() prompts register
<email> → decide → walk to one of 4 personality-NPC rooms (east =
陆天抒/"光明磊落") → out → 阎罗殿(yanluodian.lpc) → wash (roll the
4 stats per chosen 猛士/智慧/耐力/敏捷/均衡 type) → born <地名> (e.g.
born 扬州人氏) lands in a real starting city (/d/city/kedian).
Registration + state verification (two independent continuous sessions)
- 卫长风 (id
weifeng, male, 敏捷型): full register→decide→east→ out→wash→born 扬州人氏in one connection,look/score/iat every state change (pre-birth还没有出生呐message pre-born, correct gender-appropriate starting gear post-born), landed in 客店 →westto 北大街. - 蓝天 (id
lantian, female, 耐力型): identical flow, independently verified gender-specific gear (绣花小鞋/粉红绸衫) and stat allocation (根骨 highest, matching 耐力型). - Cosmetic note, not a bug: the starting
clothclone's displayed name re-rolls a random flavor variant on each freshcreate()(短打劲装 / 黑色劲装 across weifeng's own sessions) — core inventory count, weight% and all persisted stats stayed exactly consistent across reconnects.
Combat mechanism
Read cmds/std/fight.lpc before testing, per this session's standing
lead: confirmed the exact can_speak-gated split it was looking for —
obj->query("can_speak") true → routes through obj->accept_fight(me)
(decline-or-spar, "点到为止...不会真的受伤" per fight's own help text);
false → unconditionally obj->kill_ob(me), a real fight. Default
accept_fight() (inherit/char/npc.lpc) itself calls kill_ob()
directly when !can_speak, so the split is enforced at both call sites,
consistently — existing, intentional design, not a bug (matches the
pattern already documented project-wide; did not test the non-can_speak
branch against a live creature, by design, since that branch is
genuinely lethal).
Live test: fight ouyang ke (欧阳克, a human/can_speak story NPC at
北大街) correctly invoked accept_fight() — declined in-character
("在下怎么可能是小兄弟的对手?" / "看起来欧阳克并不想跟你较量。") because
its attitude is "friendly" and its qi/jing were both at 100%
(inherit/char/npc.lpc's default accept_fight(): "friendly" +
≥75% qi/jing → decline). A real, clean exercise of the safe branch with
a negative outcome — no damage, no crash, no error. (This same fight
attempt is also what first reproduced the eval_function bug below, via
combatd.lpc's post-fight-request start_call_out().)
Skill/sect acquisition — both paths
- Organic:
apprentice ouyang kecorrectly dispatchedattempt_apprentice()→permit_recruit()(kungfu/class/ouyang/ ouyang.h) → declined in-character ("你不是我们欧阳家的人,我怎能收你 为徒?") because the test character'sborn_familywasn't 欧阳世家. Confirmed the full mechanism runs end-to-end without error; a successful join would requireborn 欧阳世家instead ofborn 扬州人氏at registration (not repeated with a 3rd character, given time budget — the declining path already provesapprentice→attempt_apprentice→permit_recruitall resolve and execute correctly, which is what this session was actually checking for afterpermit_recruit()initially looked suspiciously undefined by a too-narrow grep — see below). - Admin shortcut:
cmds/arch/setsk.lpc(setsk [<对象>] <技能> <级别>,(arch)-gated) — confirmed working live on the admin account itself (setsk force 30→ 目标:浮云(fluffos) 设定技能:force 等级: 30;setsk force 0→ 取消技能:force).cmds/wiz/copyskill.lpc((wizard)-gated, copies an existing character's whole skill/stat set onto another) is a second, independent shortcut. Could not testsetsk/copyskillagainst the offline test characters directly (both commands require the *target* to be a currently-loaded/onlineliving()object, not just a save file — correct, intentional behavior, reproduced as "目标不存在,如果是设定自身技能,目标参数可 作缺省。" when targeting an offlinelantian), so verified the mechanism on the admin's own account instead. - False-alarm investigated and cleared:
permit_recruit()(called unqualified from every sect-master NPC'sattempt_apprentice(), 125+ call sites underkungfu/class/*/) appeared completely undefined anywhere in the tree on a first grep — worth flagging since an undefined local function call would be a genuine crash-on-every- apprentice-attempt bug. Root cause of the false alarm: my own filter excludedkungfu/class/from the search entirely. Each sect actually defines its ownpermit_recruit()in a shared per-sect header (kungfu/class/ouyang/ouyang.h,kungfu/class/quanzhen/quanzhen.h, etc., byte-identical to siblingzjdyzj/zjdywzb/zjdy2008wzb),#included by every NPC file in that sect directory. Confirmed vialpcc --batchcompilingkungfu/class/ouyang/ouyangkecleanly and the liveapprenticetest above actually reachingpermit_recruit()'s real decline logic. No bug here — noted so a future pass doesn't re-walk the same dead end.
quit / reconnect / persistence
cmds/usr/quit.lpc has no new-account grace-period or delete-on-quit
logic (checked before testing) — ordinary quit is always safe here,
no need to simulate a raw disconnect instead. Existing design, not a
bug: non-wizards get all non-equipped, non-autoload inventory dropped on
quit (anti-hoarding-while-offline mechanic).
weifeng: registered → played → reconnected mid-test (prior connection had ended without an explicitquit, so the driver correctly treated the next connection as "重新连线完毕" / link-dead reconnect rather than a fresh login — same character, same room) →look/quitclean ("欢迎下次再来!").lantian: registered → played → cleanquit→ driver fully restarted (killed by exact PID, rebooted with themaximum evaluation costfix below applied) → real wall-clock gap while this fix was written up and the driver reboot completed → reconnected: name/gender/stats/location/inventory/born/registeredstatus all persisted correctly from the on-disk save, unchanged.debug.logafter every session in this pass: zero unexplained errors (grepped bothlibs/zjdyaryl/log/debug.log, the onlydebug.logthis lib produces — no separatework/log/debug.logexists,log directoryis lib-root-relative per §5.2 here).
Bugs found and fixed
1. §8.3a addendum, 3rd confirmed instance: feature/action.lpc's
eval_function() declared private. private→DECL_HIDDEN
demotion-on-inheritance (this file is inherited into every
character via inherit/char/char.lpc) silently blocks the
call_out("eval_function", ...) dispatch that start_call_out()
(this file's own general-purpose "run this function after a delay"
primitive) relies on — 91 files across the tree call
start_call_out(), including adm/daemons/combatd.lpc and 80+
kungfu/skill//kungfu/special/ buff/poison/powerup files. Reproduced
live: debug.log showed apply() with insufficient permission: ...
ob: clone/user/user#N, function: eval_function, origin: internal,
needs: private, has: hidden immediately after an ordinary declined
fight command (which schedules a combatd.lpc recovery callback via
start_call_out()). Fix: dropped private
(void eval_function(function fun) { evaluate(fun); }). Re-tested the
identical fight decline post-fix, fresh boot: zero further
eval_function/insufficient permission lines. Also fixed the
identically-shaped clone/questob/letter.lpc:private void
eval_function(...) for consistency — not confirmed live-triggered
(nothing in that file actually schedules a call_out("eval_function"
itself, so it may be dead code), but same bug shape, same trivial fix,
zero risk.
2. §7.90, 5th confirmed instance (new lineage): maximum evaluation
cost : 2000000 (config.fluffos) was too tight — not tripped by
registration or movement, but by ordinary background daemon activity:
adm/daemons/quest/capture.lpc's periodic heart_beat() spawning a
kungfu/class/generate/capturenpc3 NPC whose randomly-chosen
setup_family() branch (from_xueshan()) hit Eval interrupted: ...
cost limit reached, limit: 2000000 usec mid-set_skill()/ACL-check,
roughly 20 minutes into an otherwise-idle boot with no player nearby.
Fix: raised to 5000000 (established §7.90 remedy value, already
used by 30+ other libs). Verified: fresh boot + full replay of both
registration sessions + the fight/apprentice/setsk tests above,
zero further cost limit reached lines in debug.log.
发现但判定为既有设计、未改动的现象 (observations, not bugs)
fightcommand'scan_speaksplit (safe spar vs. realkill_ob()) — confirmed intentional, documented in the command's ownhelp fighttext; only thecan_speakbranch was exercised, by design.- 欧阳克 declining
fight(friendly attitude, full qi/jing) and 欧阳克 decliningapprentice(wrongborn_family) — both correct, in-character existing gating logic, not bugs. - Starting
clothclone's cosmetic flavor-name re-roll across sessions — cosmetic only, no data-persistence issue (see above). setsk/copyskillrequiring a *loaded* (online) target object rather than accepting an offline save file — correct, intentional behavior for a live-stat-copy command, not a limitation worth changing.
WASM 未验证说明
Not re-verified under WASM this pass (native-only, per this project's
current WASM build blocker). Confirm via:
curl -sS "$HTTPS_PROXY/__agentproxy/status" — emsdk's
storage.googleapis.com dependency is denied by the proxy, unchanged
from every other lib checked this session. This lib's own prior
WASM-enablement pass (2026-07, above) already covers WASM-specific gates
(VERSION_D, messaged.lpc socket_bind, loopback allow); the two fixes
in this pass (eval_function visibility, eval-cost ceiling) are
driver-behavior-general and apply identically under WASM once it's
buildable again in this environment.
深度功能测试第二轮 / Deep functional test round 2 (2026-08-15, post driver-upgrade re-test)
Round-two re-verification against the current native build-debug driver
(post-upgrade — pulls in PRs #1343/#1344 and the corpus-wide %-operator
float-crash fix). Standard checklist + live playthrough-style verification.
The prior pass's own reconnect test only covered the link-dead/wall-clock-
gap path, not the kick-duplicate-login confirmation path — this round adds
that.
Findings:
1. AGENTS.md §7.107 (adm/daemons/closed.lpc's load_all_users()
calling login_ob->restore()/user_ob->restore() with no catch()
guard): a corrupted closed-cultivation account's save data would throw
uncaught, aborting the whole heart_beat() tick before the cleanup
(destruct()+map_delete()) runs, and retrying forever. Fixed by
wrapping both restore() calls in catch() with an ok flag, same
pattern as the other confirmed instances of this class this window.
2. AGENTS.md §7.108 (clone/user/user.lpc's reconnect() missing
enable_commands()): confirmed active LOGIN_D (adm/daemons/logind.lpc)
calls user->reconnect() on the character body after exec(old_link,
user). Fixed by adding enable_commands(); as the first statement.
Live-verified with two concurrent telnet sessions: session 2 logged in
as fluffos (this lib's regular login password Mud@2026), confirmed
the "赶出去,取而代之吗?(y/n)" prompt with y, and the resulting
session correctly dispatched look (real room description). score
returned "还没有出生呐" — expected content-gated response for this
still-unregistered admin account (not a bug; same pattern as
previously confirmed on sibling lib xkxz2), confirmed harmless by
cross-checking with look.
3. adm/simul_efun/file.lpc: log_file() never called assure_file()
before write_file(); added the call (plus a forward declaration).
cat()'s write(read_file(file)) had no null-guard; changed to
write(read_file(file) || "").
4. Already correct, no change needed: cmds/wiz/update.lpc already
guards with environment(me) &&. adm/single/master.lpc's
log_error() already uses the case-agnostic "arning:" filter
(AGENTS.md §7.10). maximum evaluation cost was already 5000000
(raised in an earlier pass per this NOTES.md's own §8.3a section).
Live verification summary: booted the native driver on port 40073 (the
known-harmless, previously-documented versiond.lpc socket_bind()
argument-type error fired again at boot as expected, non-fatal;
Initializations complete / Accepting telnet connections both
printed). Logged in as the seeded fluffos admin (Mud@2026), confirmed
real write access via update /adm/simul_efun/file (recompiled
successfully). Ran the two-session kick-duplicate-login reconnect test
described above and confirmed the §7.108 fix live — this specific path
(distinct from the link-dead reconnect this lib's earlier passes already
covered) had not been exercised before. No new error classes in
log/debug.log beyond the known versiond/boot-time line. Killed the
driver by exact PID when done.
本轮修改的文件 / Files modified this round:
libs/zjdyaryl/work/adm/daemons/closed.lpclibs/zjdyaryl/work/clone/user/user.lpclibs/zjdyaryl/work/adm/simul_efun/file.lpc
AGENTS.md §7.100 fix (2026-08-19): redundant replace_program(ROOM) landmine
Same corpus-wide bug as the batch-1-6 sweep (ROOM macro
"/inherit/room/room" from include/globals.h). Deleted 2,315 live
standalone replace_program(ROOM); lines under work/ via
fix_710_room.py, plus hand-fixed the room-building tool's
string-builder template (work/clone/misc/roommaker.lpc). No .lpc
files under work/data/, so no false-negative risk. Remaining matches
after the fix are all pre-existing //-commented.
Verified: clean build-debug boot (zero new compile errors, zero
"cannot replace"/"cannot bind" in debug.log), live admin login
(fluffos/Mud@2026) into the game world, look/quit worked
cleanly (score's "还没有出生呐" is pre-existing admin-account
behavior). Incidental data/{login,user}/f/fluffos.o save drift from
the login test was reverted via git checkout HEAD before
committing.
§7.30 uninitialized-mapping accessor sweep (2026-08-20)
Corpus-wide mechanical sweep of the feature/skill.lpc shared-lineage
bug (confirmed independently on xiakexing2017/jqxz2015/haiyang2
via round-four testing): 5 accessor(s) in this file returned a raw
never-initialized mapping instance variable (defaults to int 0,
not ([]), until first assigned), crashing any unguarded
keys()/sizeof()/indexing caller for a fresh/untrained character.
Fixed at the accessor level (mapp(x) ? x : ([])) per the documented
remedy. Verified via lpcc --batch static compile check only (not a
live boot) as part of a large mechanical sweep; not individually
functionally re-tested live on this lib.
深度功能测试(2026-09-04,round three,shop + 拜师)
新角度:扬州醉仙楼购物 + 丐帮李斧头拜师。round one 只测了 apprentice
ouyang ke 的 born_family 拒收(「你不是我们欧阳家的人」),没有真实
收徒,也没有商店购买。round two(2026-08-15)只补了 kick-duplicate 重连。
sibling zjdy2008wzb 2026-08-19 已经走过华山店 buy jitui +
bai li futou。
本轮没有新的 programming bug。enter_world() 已经是
ob->set("registered", user->query("registered"))(从 user 抄到 login,
和 xkxz2 Bug 2 方向相反)。log_file() 已有 assure_file()。
log_error() 已有 arning: 闸门。env/prompt 是 "null",不是每秒时钟。
实测过程
管理员 fluffos / Mud@2026 / 浮云。第一输入是「您的英文名字」,没有
BIG5 提示。端口 40073。连线有大量 Tomud 控制码(licon/lbadd),不影响
指令派发。is_admin() 是 VERSION_D->is_release_server() || admin_flag
== 1222,本环境 is_release_server() 为真,clone /clone/money/gold
一次成功。
原先 registered:0、score「还没有出生呐」。走完 register
[email protected] → decide → west/out(阴险奸诈)→ wash →
born 扬州人氏,落地扬州客店。born 后弹出游戏规则 pager(ENTER/q),
下一条指令被 pager 吃掉,不影响后续 clone。
goto /d/city/zuixianlou,list 包子五十文 / 烤鸡腿八十文 / 烤鸭一两
白银又五十文 / 牛皮酒袋一两白银。扬州店小二没有丐帮穷叫化踢人。
buy jitui 成功。i 剩九十九两白银 + 二十文铜钱(10000−80 = 9920)。
goto /d/gaibang/underhs(舍身崖下),李斧头 id li /
kungfu/class/gaibang/li-futou.lpc,只收男性。apprentice li 一次成功:
「恭喜您成为丐帮的第二十代弟子。」score「丐帮第二十代传人」、师父李斧头。
save.lpc 真正双存。
save 后不 quit 丢 socket(此时 user.o registered:1、login.o
仍是 0),重启驱动强迫走 enter_world()。重连落地客店而不是世外桃源,
注意事项是普通欢迎而不是「您还没有注册」,score 仍是丐帮二十代 / 李斧头
/ 扬州人氏,银子铜钱还在。烤鸡腿是 F_FOOD,不进 autoload,重启后不在
身上——不是存档 bug。
live debug.log 是 libs/zjdyaryl/log/debug.log(Boot Time Fri Sep 4
03:32:59 2026),无 error: / Too deep recursion。mudlib work/log/log
只有开机编译警告。管理员存档未提交。
深度功能测试(§10.7,2026-10-04)— negative range ends
scripts/lpc_fix_negative_ranges.py: 4 line(s) in 1 file(s) count a range from the end with < (x[a..-1] -> x[a..<1], x[-2..] -> x[<2..]; KB 06 §7.209). In this driver a negative constant end gave "" / ({ }) and a negative start the whole value, so each of these returned the wrong slice; the compile warning A negative constant as the second element of arr[x..y] is gone from the files that compile. Range lvalues (s[0..-1] = text, the prepend idiom) are left alone. A paired compile of the changed files at HEAD and in the working tree showed no new error.
深度功能测试(§10.7,2026-10-05)— 任务表里的 .c 路径与任务守护进程的防护
cmds/std/look.lpc 夜间检查的 !present("fire", this_player()) 前加 objectp(this_player()) &&(房间 reset() 销毁物品时 /feature/move.lpc 的 remove() 会调用 look_room(),此时没有 this_player(),present(…, 0) 报 Bad argument 2 to present())。
验证:改动过的 cmds/std/look.lpc 在新进程里加载,HEAD 通过 1 个、工作树通过 1 个(共 1 个),无回退。
深度功能测试(§10.7,2026-10-05)— 房间列出的物件缺档时房间照常加载
房间基类 inherit/room/room.lpc:make_inventory() 用 catch() 包住 new(file),做不出来就返回 0;reset() 的 case 1: 拿到 0 就跳过这一项(if (!objectp(ob[list[i]])) break;)。档案里没有的 NPC 或物品(或 create() 出错的物件)原先会让列出它的房间整个加载失败(Bad argument 1 to environment(),或对 0 的 call_other()),连带这个房间后面的区域;现在房间照常加载,只是少了那个物件,下次 reset() 再试(KB 05 §7.25;scripts/lpc_resilient_room.py、scripts/lpc_room_reset_guard.py)。
验证:探针(scripts/lpc_room_reset_probe.py:房间基类列出一个不存在的物件,再调用 reset())HEAD 单件 崩溃、多件 崩溃,工作树 单件 OK、多件 OK。
深度功能测试(§10.7,2026-10-06)— 与 zhonghua2 同源的三处编译警告
include/npc/indian.lpc与masia.lpc共用全局名ma_sname/ma_pname;两个头文件被同一个守护进程(npcd等)一起包含时,后包含的印度名表覆盖马来名表,generate_ma_name()生成的是印度名字。印度表改名in_sname/in_pname(KB 04 §6.10)。cmds/std/team/swear.lpc:结义失败提示被多余的;截成两句,fail只剩"……可惜现在有人不在,$N",后半句"的提议只好作罢。"丢了;接回去。
验证:改动的文件和包含 npc/indian 的守护进程在 HEAD 与工作树分别加载(scripts/lpc_listcheck.sh,新进程),无回退。
深度功能测试(§10.7,2026-10-07)— 编译警告整理
scripts/lpc_warnings.py zjdyaryl --fix 加 scripts/lpc_fix_no_effect.py --apply,共改动 543 个 .lpc 和 14 个 .h(多为删去未用的局部变量)。HEAD 与工作树分别加载(新进程):536 -> 536 通过,无回退;改过的头文件的 128 个包含者 127 -> 127 通过。
本库与其他指间 MUD 一样在 globals.h 里 #define nosave nosave,扫描器看不出旧 static 函数改成的 nosave 函数(Illegal to declare nosave function),按扫描诊断把 10 个文件的 28 处改成 protected(master、treemap、questd、dbased、cmwhod 等),这 10 个文件和 adm/daemons/natured.lpc(删去空语句 lt[LT_MON];)在 HEAD 与工作树分别加载 11 -> 11 通过。启动时警告 52 -> 0;新进程登录(新人物确认)正常。
深度功能测试(§10.7,2026-10-11):“无副作用表达式”警告复查(批 6)
- 补齐前几批漏掉的同码副本:
your_temp["guarding"];补= 0(反击后清除防守姿态,含u/下的 combatd 拷贝);(: WEAPON_D, "query_action" :)改为(: call_other, WEAPON_D, "query_action" :)(KB 04);mysql_d.lpc的空MSG宏改成空函数;gigicook.lpc的arg == menu_list[0]改为=。 - 改动文件:adm/daemons/test.lpc
- 改动的对象 HEAD 与工作区都能载入,无回退。
深度功能测试(§10.7,2026-10-11):“无副作用表达式”警告复查(同码收尾)
- 改动文件:cmds/wiz/who1.lpc
- 与前几批同型:
youming.lpc空DEBUG宏改空函数;who1.lpc孤立的分隔线字符串删去;jing.lpc被分号截断的“惨叫一声,血流如注。”接回上一句;_dashi.lpc三行只造不调的(: call_other, __FILE__, "…_name_skill", who :);改成注释(行为不变)。 - 载入无回退。
深度功能测试(§10.7,2026-10-12):编译警告收尾
能编译的文件里的警告 3 -> 0(lpc_warnings.py zjdyaryl 重扫:7290 个文件可编译,剩下的诊断都在本来就编译不过的文件里)。与 zjdyzj 同码:zjdyzj 当天的修复(提交 15d40f6ba6a)改的 3 个文件在这里都是 token 级孪生,用 lpc_twin_port.py adopt 搬过来;ZJ 登录协议代码没有动。
真问题: clone/misc/swmuding.lpc 神木王鼎自己声明了一张 13 种毒虫的 mapping insects,可读表的是基类 clone/misc/muding.lpc 的函数,它们读的是基类那份普通木鼎表,叶子的表从来没用上。改名 sw_insects,在 create() 里赋给基类的 insects。
其余: feature/food.lpc、feature/liquid.lpc 的 do_effect() 改为 varargs int do_effect(object me) 并 return 1;,与 eat/drink 读取返回值的重载(d/guanwai/obj/wan.lpc、d/xiakedao/obj/pigpart.h)同型。
验证:改动文件、所有继承 F_FOOD/F_LIQUID 的物品、包含 pigpart.h 的文件、eat/drink 命令共 206 个对象,HEAD 与工作树各用新进程载入:205 -> 205 通过,regress 0;删除声明审计 0 项待看。206 个对象载入无回退。
负数伤害当作消耗(2026-10-15,KB 06 §7.241)
receive_damage("neili", -52)、receive_damage("qi", -12) 之类把 add() 的负数写进了 receive_damage():本库 feature/damage.lpc 对负数伤害报错(或归零),练功/运功时报 F_DAMAGE: 伤害值为负值 或消耗失效。已改为正数伤害,内力/精力类改为 add(type, -N)(scripts/lpc_fix_damage_calls.py):/kungfu/skill/duanyun-fu、/kungfu/skill/feifeng-whip。
family 映射(再补)(2026-10-15,KB 05 §7.30)
mapping fam; fam = (mapping)ob->query("family");(先声明后赋值)和泥潭式的 query("family", me) 同样直接取下标:无门派的新人拜师(attempt_apprentice/recognize_apprentice)、NPC 的 greeting、房间的 valid_leave、ask_me 等报 Value being indexed is zero。2 处补上 if (!mapp(fam)) fam = ([ ]);(刚 recruit_apprentice() 之后的除外)。
find_player() 只认在世界里的身体(2026-10-15,KB 07 §8.26)
simul_efun 的 filter_player() 加上 environment(ob):注册中途断线留下的、不在任何房间的身体不再被当成玩家,两个以上时 find_player() 不会再报 The player(<id>) has existed in the world.(wllz3 实测过的问题)。本库若注册流程不会留下带玩家 uid 的身体,这一改动不改变行为。
技能名拼错(2026-10-15,KB 06 §7.249)
query_skill() 里的技能名拼错了,或用的是本库改名前的旧名;本库没有这个技能,调用永远得 0:门槛(< N 就拒绝)永远过不去,相关功夫或绝招学不了、用不了;内功互斥(> N 就拒绝)从不生效;公式里这一项一直是 0。经汉字名(提示文字或中文名词典)或纯拼写差异(_/-、少一个连字符、相邻字母颠倒)核对后,改为本库的技能名(scripts/lpc_fix_skill_typo.py):choushui-zhang→chousui-zhang(chousui-zhang);cuhixiao-jifa→chuixiao-jifa(xiaoao-jianghu);lenyue-shengong→lengyue-shengong(lengyue-shengong);matrial-cognize→martial-cognize(qiankun-danuoyi/nuoyi);taiji-shengon→taiji-shengong(taiji-shengong)。
技能名拼错:技能文件里拼错自己的名字(2026-10-15,KB 06 §7.249)
技能自己的文件(或它的绝招目录)里,query_skill() 读的是差一个字母的自己的名字,永远得 0:“基本功夫要高过本技能”之类的限制从不生效,按等级取招、计算伤害的那一项一直是 0。改为本技能的名字(scripts/lpc_fix_skill_typo.py 的 self 判据):shicheng-liulang→shicheng-liulong(shicheng-liulong);xuanyuan-arror→xuanyuan-arrow(xuanyuan-arrow)。
柔云步法「柔云纵」有时报错(2026-10-15,KB 06 §7.251)
rouyun-steps/zong 随机把人送到三个房间之一:精、精力已经扣了,“乘云而去了”也说了,送不过去时人留在战斗里并报错。第三个是巫师的测试房 /u/deaner/test1,库里没有;改为 /d/city/guangchang(hy、jym 等库原本就用这个)。
family 映射内联取下标(2026-10-15,KB 05 §7.30)
ob->query("family")["master_name"]、me->query("family")["family_name"](泥潭式为 query("family", ob)[...])直接对门派映射取下标:没有门派的人(新玩家、叛师者、大多数 NPC)在 NPC 的打招呼和问话、绝招的门派判断、房间的 valid_leave 里报 Value being indexed is zero,而不是得到拒绝。1 处(1 个文件)改为 dbase 路径查询 query("family/master_name"):有门派时值相同,没有时得 0;原有的判断照常生效(scripts/lpc_fix_family_index.py)。给映射赋值的写法未动。
没有对手的绝招全部报错:message_combatd()(2026-10-15)
指间版 message_combatd(msg, me, you, ...) 为客户端加了图标和伤害行,直接读 you->query_temp("armor/armor")、you->query("qi")。不对别人出手的招(混天气功、龙象功等的 roar,先天功 shield,金刚不坏体 jingang ……)只传 msg, me,you 是 0,每次使用都报错,绝招探测里本库有 28 个这样的招。照同系 zjmudhell、wxddym、wdxtym 的写法,伤害行包进 if (you),取护甲图标前也先判断 you;28 个招全部能用了。
set_skill() 遇到本库没有文件的武功不再抛错(2026-10-18,KB 06 §7.256)
feature/skill.lpc 里的 set_skill()、map_skill()、prepare_skill() 碰到没有武功文件的名字就 error("F_SKILL: No such skill (…)"),调用它们的 NPC create() 整个中断:NPC 载入不了,刷出它的房间也少一个人。本库目前没有对象设了缺失的武功;三处都改成 return:这一门武功不给、不映射,对象照常载入,只是少了它(缺的武功本身仍是内容缺口)。(scripts/lpc_guard_set_skill.py)
武功名拼错的 NPC(2026-10-19,KB 06 §7.258)
set_skill("kunlun-shnfa", …)、map_skill("dodge", "shaolin-shnfa") 这样的调用把武功名拼错了:本库没有这个武功文件,有的是拼对的那个。以前这种 NPC 在 create() 里报 No such skill 载入不了;武功缺失时跳过之后它们能载入,可是少了那门武功(set_skill 被跳过,map_skill 映射不到,门派弟子用普通轻功/拳脚)。按核对过的对照表改正,共 12 处、9 个文件:changquana→changquan(4 处)、tiaji-jian→taiji-jian(2 处)、taiji-shenfong→taiji-shengong(1 处)、yan-fly→yanfly(1 处)、lingboweibu→lingbo-weibu(1 处)、jiahua-neigong→jiaohua-neigong(1 处)、zhoangnan-zhi→zhongnan-zhi(1 处)、jinggang-zhi→jingang-zhi(1 处)。(scripts/lpc_fix_skill_names.py)
RANK_D 对 0 的称呼(2026-10-19,KB 06 §7.273)
adm/daemons/rankd.lpc 的 query_respect()、query_rude()、query_self()、query_self_rude() 里 4 个函数开头补上 if (!objectp(ob)) ob = this_object();。NPC 在 create() 里写 "…" + RANK_D->query_respect(this_player()) + "…"(inquiry 对话、chat_msg),驱动自己跑 reset() 时没有人在场,this_player() 是 0。旧驱动里 0->query("age") 返回 0,称呼走默认分支;新驱动直接报 Bad argument 1 to EFUN call_other(),房间的 make_inventory() 吞掉错误,被打死的 NPC 再也刷新不回来。用 scripts/lpc_reach_census.py --walk 找到(xkx100 的武当弟子、一灯、汴梁书生…);修在守护程序里,不动 1,800 个 NPC 文件。
从 work/ 里删掉 tar 的 PaxHeader/ 记录(2026-10-19,KB 02 §2.2)
压缩包的制作者把 tar 的 pax 扩展头记录(49 path = ...、20 ctime = ...,每个不超过 262 字节)当成文件打进了包里,放在 PaxHeader/ 目录(有的嵌套两层)。转换时 .c 结尾的被改名成 .lpc,在扫描里成了编译不过的“物件”。这些是元数据,不是 mudlib 内容:2 个文件从 work/ 删除(raw/ 里仍然有)。
x != "a" || x != "b" 和 x == "a" && x == "b":同一个值的比较链永远成立/永远不成立(2026-10-20,KB 06 §7.282)
if (arg != "wan" || arg != "丸") return notify_fail(...) 对任何 arg 都为真,dir == "south" && dir == "north" 永远为假:条件下面的守卫要么永远拦、要么永远不拦。作者要的是“既不是 A 也不是 B”(&&)或“是 A 或 B”(||)。!= 链的 || 改成 &&(仅当条件下面是 return 的拒绝/守卫),== 链的 && 改成 ||(scripts/lpc_fix_cmp_chain.py)。改动:/d/mingjiao/shanmen.lpc(1 处)。
member_array('/', str) 改为 strsrch(str, "/"):字符字面量的 member_array 按字节搜索(2026-10-20,KB 06 §7.283)
member_array('/', str) 里的 '/' 是整数,驱动按 UTF-8 字节搜索,返回字节偏移(带第三个参数时起点也是字节);最新的 FluffOS(923cdbc0)在字符串里有非 ASCII 文字时,对每个调用点警告一次(Warning: member_array(int, string) searches BYTES)。而 str[0..idx-1] 按字符切,中文字符串会在错误的位置截断。改为 strsrch(str, "/")(找不到同样返回 -1,按字符计数;scripts/lpc_fix_member_array_char.py,JSON 编码器等少数几处手改)。改动:/cmds/arch/sameip.lpc(1 处)。
登录密码超过 255 字节:crypt() 抛错(2026-10-20,KB 06 §7.294)
驱动的 crypt() 对超过 255 字节的密钥直接报错(Error in crypt(), check your salt),老驱动则按任意长度散列。在登录提示符下输入 256 字节以上的密码,密码检查那一行就抛错,连线停在一个裸的 > 提示符上,登录走不完(password 指令的旧密码检查同样);用 300 个 x 当参数的扫描发现的。/adm/single/simul_efun.lpc 里补了一个同名的 simul_efun crypt(key, salt):只有超长的密钥才被截短(先截到 255 个字符,再逐字符截到 sizeof(to_buffer(key)) <= 255,限制按字节算,一个汉字占三个字节),再交给 efun::crypt();普通密码原样散列,已存的密码散列不受影响(scripts/lpc_add_sefun.py crypt)。
get_config(__MUD_PORT__) 经旧版 runtime_config.h 得到字符串(2026-10-20,KB 06 §7.302)
本库的 include/runtime_config.h 是老 MudOS 的编号(整数设置从 15 起,本驱动从 256 起),get_config(__MUD_PORT__) 读到的是另一项设置(字符串),(int) 又只是编译期标注,于是 socket_bind(fd, LOCAL_PORT()) 报 Bad argument 2 to socket_bind(),版本守护进程 port = get_config(__MUD_PORT__) + VERSION_PORT 是字符串相加。头文件自己的注释写明 get_config(__MUD_PORT__) == __PORT__,所以代码里的这个调用(连同外面的 (int) / to_int())改成了驱动的预定义 __PORT__(scripts/lpc_fix_mud_port.py)。改动:/include/getconfig.h(1 处)。
NPC 的 chat() 在 chat_msg 为空数组时下标越界(2026-10-21,KB 06 §7.334)
NPC 基类的 chat() 是 if (arrayp(msg = query(...))) { if (random(100) < chance) { rnd = random(sizeof(msg)); if (stringp(msg[rnd])) ...,不检查列表是否为空。本库现有的 NPC 文件里没有字面写成空 chat_msg 的(扫描只认 set("chat_msg", ({ })));守卫挡的是运行时才为空的列表和以后新增的 NPC。在 random(100) < chance 前面加 sizeof(msg) &&(scripts/lpc_fix_chat_empty.py;if (random(100) > chance) return 0; 的写法是 !sizeof(msg) ||)。改动:/inherit/char/npc.lpc(共 1 个文件)。
不带参数的指令对 0 调用 efun:不在 wiz / adm 目录里的指令(2026-10-21,KB 06 §7.336)
指令敲成不带参数时,驱动把 0 传给字符串参数;下面的指令第一句就把这个 0 交给 efun,运行时报 Bad argument 1 to ...。它们在 cmds/std、cmds/usr、cmds/bos、cmds/app 这类目录里,上一轮的扫描只看巫师目录。用 scripts/lpcc_bare.py 不登录、在一次 lpcc 求值里以 0 调用 main() 逐个确认后,由 scripts/lpc_fix_bare_arg.py --all-dirs 在第一处使用参数的语句前加守卫:没有 help() 的是 return notify_fail("…\n");。改动(1 个文件,括号里是接住 0 的 efun):/cmds/std/actionavailable.lpc(sscanf)。加载检查 HEAD 与工作树对照,没有退步。
注册到不存在函数的 add_action(2026-10-21,KB 06 §7.349)
add_action("函数", "动词") 绑定的函数,在对象本身、它包含的头文件、它继承的父类和继承它的子类里都没有定义(scripts/lpc_scan_callout_targets.py 静态解析,子类用传递闭包复核,scripts/lpc_verify_handlers.py 运行时 function_exists() 复核)。驱动从玩家最新的一条动作往回找,遇到这样的句子就报 *Function for verb 'drop' not found.,同一个动词的其他处理函数不再尝试(不是最新的一条就悄悄跳过)。删除了 5 条注册(4 个文件,scripts/lpc_fix_dead_add_action.py),动词留给别的处理函数:/adm/npc/referee.lpc(do_halt)、/d/beijing/hg_w.lpc(do_body)、/d/tulong/yitian/npc/obj/ling2.lpc(do_du)、/inherit/misc/fboard.lpc(do_list)。最多的函数名:do_halt 2 处、do_body 1 处、do_du 1 处、do_list 1 处。
对象路径里的 ..:new(__DIR__ "../obj/x") 报 Read access denied(2026-10-22,KB 06 §7.351)
__DIR__ 是当前文件所在目录(带结尾斜杠),__DIR__ "../obj/x" 就是 /d/zhiye/npc/../obj/x;驱动的 legal_path() 不接受带 .. 的路径,new() / load_object() 直接抛 *Read access denied.(实测,find_object() 对它答 0)。走库自己的 carry_object() / 房间 objects 表的路径,库的基类会先规范化,能用;直接把路径交给 new() / clone_object() / load_object() / move() 的不行,调用到那一步才报错。改成规范化后的绝对路径(scripts/lpc_fix_dotdot_dir.py --direct):/d/wudang/npc/xiaocui.lpc(__DIR__ "../obj/nuerxiang" → "/d/wudang/obj/nuerxiang")。
调用了、但这个库自己的守护进程里没有的函数(2026-10-22,KB 06 §7.354)
MACRO->函数() 调用的函数在这个库的守护进程里不存在:call_other() 对不存在的函数不报错、只返回 0,所以这些功能(时间显示、昼夜事件、名字检查、价格文字……)一直没起作用。同一血统另一个库的同名守护进程里有这些函数,原文照抄到本库守护进程末尾(scripts/lpc_port_function.py;调用处传的参数个数、函数体用到的函数 / 全局变量 / 宏 / 字符串键都在本库里有,已核对;守护进程在 HEAD 和工作区都能加载,每个函数用固定参数各调用一次:HEAD 返回 0,现在返回正常的值):/adm/daemons/natured.lpc ← chidi:outdoor_room_outcolor()(1 处调用);/adm/daemons/chinesed.lpc ← hhsj:find_skill()(1 处调用)。
汉字按字节切片的老写法没有换成按字符:改法名 "澄" + name[2..3]、辈分判断 name[0..1] == "澄" 等 15 处(2026-10-22,KB 06 §7.360)
原档按字节算字符串区间(一个汉字 2 字节):name[2..3] 是名字的第二个字,name[0..1] == "澄" 问名字是不是以「澄」开头。转成 UTF-8 之后,这个驱动的区间和 strlen() 都按字符算(strlen("澄观") 是 2,"澄观"[0..1] 是两个字),老算术原样留着、意思全变:拜入少林 / 武当 / 峨嵋等派的玩家被改成错误的法名(二字名 张三 变成一个字的 澄,更长的名字取到第三个字);各派掌门的辈分判断(name[0..1] == "澄")永远不成立;NPC 的称呼和提示里取到两个字而不是一个字。
本库 15 处(10 个文件):拼名字的赋值 8 处、与汉字常量比较 6 处、to_chinese()[..] 1 处。例:name[0..1] → name[0..0](/kungfu/class/emei/tobebonze.h:40);name[2..3] → name[1..1](/kungfu/class/shaolin/cheng.h:164);chk[0..1] == "你" → chk[0..0] == "你"(/adm/npc/ganjiang.lpc:532)。scripts/lpc_fix_gbk_slice.py 把下标按字符重算(社区的 UTF-8 版 xkx100utf8 里就是同样的写法,作对照);没有改的:截断(name = name[0..7],现在最多 8 个字,只是放宽)、ASCII 的区间(fname[0..3] == "room"、ctime(time())[4..19])和上下文看不出是汉字的区间。证明(scripts/lpcc_eval.py,bixiecanyang;其余各库是同一份文本):让澄字辈掌门 attempt_apprentice() 一个名叫「张三」的访客,HEAD 的法名是 慧,改后是 慧三;抽样 28 个库的 HEAD / 工作树加载对比 0 退步。工具不幂等([0..3] 折半得 [0..1],又是对齐区间),改过的文件记在 scripts/gbk_slice_converted.txt,不要重跑。
长度检查按字节写,旁边的提示按汉字写:2 处(2026-10-22,KB 06 §7.362)
老档的 strlen() 数字节(一个汉字 2 字节),转成 UTF-8 后它数字符:提示写「必须是 2 到 6 个中文字」的检查还是 strlen(name) < 4 || strlen(name) > 12,于是两三个字的房名、帮会名、群名、聊天室名、称号被提示自己说允许的那句话拒绝,上限却是提示的两倍;留言板的标题检查 i < 4 || i > 24 || i % 2 还会拒绝所有奇数个字的标题(post 你好吗)。本库 2 处(1 个文件):if ((strlen(name) < 4) || (strlen(name) > 12)) {(/adm/npc/luban.lpc:1735)。scripts/lpc_fix_strlen_gate.py 以提示为准:条件里每个 strlen 门槛都恰是提示所说数字的两倍才折半,存长度的变量(i = strlen(arg);)的门槛和 || i % 2 奇偶项、其后循环的 i % 2 == 0 && 一并处理;提示里有英文 / 字母 / 字节的不动。证明(scripts/lpcc_eval.py,bxsj 的留言板,求值对象继承 NPC 并重写 edit() 记录调用,command("post 标题")):HEAD 拒绝「你好」和「你好吗」、放行 23 个字的标题;改后接受前两个、拒绝第三个;shenmo 的 named.lpc invalid_new_name("张三"):HEAD 回 名字只能是2-4个中文字。,改后回 0。抽样 24 + 15 个库的 HEAD / 工作树加载对比 0 退步。
按字节写的汉字循环、茶馆猜诗和同盟频道标题(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)。本库 channeld 同盟 / 门派标题 1 个文件。证明(scripts/lpcc_eval.py):sjplii 的 check_legal_name 在 HEAD 接受「张a」、改后拒绝,两边都接受「张三」;xkx100 的 clubpoem->mixup("离离原上草") 得到「离离原草上」(真交换汉字);nitan_san 两字同盟名得到 【 兄 弟 】。关键对象加载通过。
中文名 / 验证码仍按 GBK 取「两字节一字」(2026-10-23,KB 06 §7.373)
pname = pname[(random(sizeof(pname)) & 0xFFFE)..<1]; pname = pname[0..1]; 在按字符计下标时会取出两个汉字。scripts/lpc_fix_pname_slice.py 去掉掩码并把收尾改成 [0..0](pname/pname2/sec_name/str/str1)。本库 4 处。证明:nt1 生成名长度 2–4;HEAD 常见 3–5。
yuanwai 孤儿 call_out announce_success(2026-10-27,KB 06 §7.349 Also)
d/changan/npc/yuanwai.lpc(及 aoxiangtianji 的 d/city 副本)在 check_daughter 里 call_out("announce_success", …),但本文件从未定义该函数;同系也无实现。到点会 *Undefined function*。cry_daughter 已完成认亲与赠书,删除这对 remove_call_out/call_out。证明:扫描 HIT call_out→announce_success 且无定义;改后残渣 0。
深度功能测试(2026-10-27,§6.25 zhongling tell_object 引号错位)
d/wanjiegu/npc/zhongling(及同路径副本)的 tell_object("who, 钟灵脱下一双绣花鞋。\n") 把对象参数写进了字符串;改为 tell_object(who, "…")。证明:原文错位;改后加载,语料残渣 0。
深度功能测试(2026-10-27,§6.10 未知 pragma save_binary/optimize)
删除本库中 FluffOS 不认的 #pragma save_binary / #pragma optimize… 行。