info.html · 介绍 · play.html · 游玩 · llms.txt · 下载与本地运行 · ZIP · GitHub
笑傲江湖之重出江湖由作者 AKAI 打造,脱胎自"夕阳再现-江湖风云2-风云再起"引擎(属于"夕阳再现/XYZX"系列衍生分支,与本项目收录的多部同系列作品——如《侠客风云》《西阳再现疯狂版》等——师出同门,但游戏内容各自独立开发),是经典金庸《笑傲江湖》题材的江湖世界:新角色从南大街的客店起步,围绕"武庙""铁枪庙"等地展开门派与个人历练;除膂力、悟性、根骨、身法四项常规武侠属性外,还设有福缘、容貌两项隐藏天赋,会悄悄影响解谜结果与NPC对玩家的印象;连线时有一道隐藏的客户端版本号校验(必须先输入 `2060`),并设有"普通密码"与"管理密码"两套独立密码——archive 名称中的"服务端+客户端"其实指的是同一套游戏支持两种连线协议(普通 telnet 客户端和 TOMUD 菜单客户端),并不是额外附带了一个独立的客户端程序。
English
By author AKAI, this Smiling-Proud-Wanderer game grew out of the "Sunset Reappears — Jianghu Fengyun 2 — Storm Rising Again" engine lineage, a branch of the broader Sunset Reappears/XYZX family shared with several other archives in this collection, though its content was developed independently. New characters start at an inn on South Street and build their jianghu reputation around locations like the Wu Temple and Iron Spear Temple. Beyond the four familiar wuxia attributes, it tracks two hidden talents — fate and appearance — that quietly influence puzzle outcomes and how NPCs regard the player. Connecting requires a hidden client-version handshake (players must type "2060" first), and the game runs an unusual dual-password scheme: a normal login password plus a separate management PIN. The archive name's "server + client" actually refers to support for two connection protocols on the same game — plain telnet and a TOMUD menu client — not a bundled standalone client program.
README
内容亮点
- 修复过一处历史遗留 bug:原始存档的
include/command.h把巫师指令 搜索路径定义为空数组,导致任何被提升为巫师权限的账号连look/quit等最基本指令都会失效;现已指向与普通玩家相同的指令目录。 - 深度功能测试还修复了一处更严重的历史遗留 bug:
log_file()从未确保 目标目录存在,导致注册流程最后一步的日志写入必然崩溃,进而让每一个 新角色都卡在空白的>提示符——没有欢迎横幅、没有任何可用指令、也没 有存档,且屏幕和debug.log都不会显示任何错误。现已修复。
在线试玩
https://mudlibs.fluffos.info/xajhzcjh/
管理员账号 / Admin account
- ID:
fluffos - 密码 / Password:
Mud@2026 - 管理密码 / Management PIN:
FluffMgmt1—— 本 lib 特有的第二套密码 ("wizpwd"),与巫师权限无关,只是一个自助改密 PIN。 - 显示名 / Display name: 浮浮
- 权限 / Level:
(admin)—— 本 libsecuritydwiz_levels 中的最高级, 通过adm/etc/wizlist授予(fluffos (admin))。
警告:这是一个公开的默认密码,仅供本地/浏览器试玩。正式对外开服前
请务必修改此默认密码(以及管理密码 PIN)。
本地运行
cd libs/xajhzcjh
~/src/fluffos/build-debug/src/driver config.fluffos游戏端口:40070。
NOTES · 移植与修复记录
xajhzcjh — 「笑傲江湖」之「重出江湖」 (archive #76)
Archive: 笑傲江湖服务端+客户端.rar ("Laughing in the Wind, server + client
bundle"). Port: 40070. Status: done (boots clean, full registration
flow verified twice end-to-end including real post-login commands look
and score).
Triage: client-vs-mudlib determination
Despite the archive's name suggesting a bundled player client (following
the precedent of archive #24, TOMud_VC源代码.rar, which really was
client-only), this archive is genuine LPC mudlib source, no separate
client bundled at all:
- The entire archive is one directory,
mud4/, with a classic wuxia-mudlib layout:adm/{daemons,obj,simul_efun,etc},clone/,cmds/,d/(rooms/zones),feature/,inherit/,kungfu/(skills/classes),meskill/,quest/,topten/,data/,log/,doc/,include/— 12378 raw files, 11413 of them.c(LPC source). - No MFC/VC++/dialog/client-shaped files anywhere — searched for the archive-#24 precedent's markers (
MainFrm.cpp,DialogXxx.cpp,*Sock.cpp,.dsp/.dsw/.vcproj/.sln/.rc/resource.h/stdafx.*): zero hits. The only non-source binaries are two **prebuilt Windows MudOS *driver* executables** (mud4/mudos22.exe,mud4/"new mudos.exe") — i.e. the "服务端" (server) half of the archive's name refers to these bundled driver binaries, not to anything we need (we use our own FluffOS build). Both ignored per the established "ignore bundled drivers" precedent. - The "客户端" (client) half of the archive's name is explained by the bundled readme (
mud4/碧血残阳说明.txt, the author's own writeup): this mudlib supports two connection protocols on two different ports — a plain telnet/ZMUD port and a "TOMUD" menu-client protocol port (tomud连入端口:8888 / ZMUD连入端口:6666per the readme) — i.e. "client" here means "which of the two wire protocols you dial in on", not a bundled GUI program. Confirmed live:adm/obj/master.lpc'sconnect(int port)sets a cosmetic"tomud"temp flag whenport == TOMUD_PORT(#define TOMUD_PORT 9999); no separate client source exists anywhere to implement that protocol on the other end. - A handful of files carry non-LPC extensions from what look like editor artifacts (
.java× 15,.vns× 20 underkungfu/skill/,d/heimuya/, etc.) — inspected several; these are ordinary LPC/text content that happened to get renamed with an odd extension at some point in the archive's history (mud4/clone/misc/mailbox.javastarts with normal LPC header comments, not Java), not a real Java/VNS client component. Left as-is (not part of the.c→.lpcrename scope either way).
Conclusion: proceeded with the full standard conversion pipeline.
Lineage
Not related to any of the three existing "Laughing in the Wind" libs
(explicitly checked per task instructions, via md5sum/diff against
raw archives and directory-layout comparison):
nitan6(archive #22): NT/nitan/Lonely lineage,nitan/nitan/adm/ kernel/...layout. This archive usesadm/{daemons,obj,simul_efun}(noadm/kernel/at all) — structurally unrelated.xo/xo_final(archives #28/#29): TMI-2/ES2 lineage,mudlib/secure/{system,daemon}/xo_new/secure/...layout (asecure/tree). This archive has nosecure/directory anywhere — structurally unrelated.- Also cross-checked against
ylfyxa3(archive #68, also themed 笑傲江湖 within the 夕阳再现 family this archive turned out to belong to, see below): differentadm/simul_efun/chinese.cmd5 (961d77af...here vsc7c5c596...there), differentadm/obj/ master.cmd5, and a very different file count (12378 raw here vs 17380 there raw) — confirmed a distinct fork, not a duplicate.
This archive IS a member of the 夕阳再现 (Xiyangzaixian)/"XYZX" lineage
already established across archives #46 (xyzxfk), #47
(xyzxfy2), #48 (xyzx3), #55 (wmkj),
#59 (jhfy), #68 (ylfyxa3), and #71
(bixiecanyang) — confirmed via the bundled readme (碧血残阳说明.txt,
titled "关于笑傲江湖-重出江湖的说明", explicitly self-identifying its
base as "夕阳再现-江湖风云2-风云再起", credited to author "AKAI",
same author credited in bixiecanyang's own readme) and via md5sum:
adm/daemons/chinesed.lpc: byte-identical (fe293044de377c1fff169db903a6b2b3) tobixiecanyang,xyzxfk,xyzxfy2, andjhfy's copies.adm/simul_efun/chinese.lpc(theis_chinese()file): byte-identical (961d77af057bb93db320af05be5883fc) tobixiecanyang's copy specifically.adm/daemons/securityd.lpc: differs frombixiecanyang(own md570fc2c07...vs032452f5...) — this archive's own securityd is a much simpler ACL (valid_readunconditionally returns 1, noexclude_read/trusted_readtables at all) than bixiecanyang's/ fengyun2's shared custom ACL.adm/obj/master.lpcandadm/daemons/logind.lpc: both differ from every sibling (own content, own line counts) — same pattern as every other fork pair in this family: shared low-level engine utility files (chinesed,chinese.lpc), fully independent site-specific daemons/game content otherwise.config.bxcy(the raw config filename) is again present here too, matching the same filename-convention fingerprint already noted for bixiecanyang/dtsl2 — further (weak, config-template-only) evidence of the shared AKAI-lineage ancestry, not itself a content match. Content differs from bixiecanyang's ownconfig.bxcy(differentname/port/path fields, as expected for an independently-run site).
This archive's own in-game identity is 「笑傲江湖」之「重出江湖」
("Laughing in the Wind" — "Return to Jianghu"), a *different*, independent
game-content fork within the same shared 夕阳再现 engine family — not a
duplicate of any processed archive (12378 raw files here vs bixiecanyang's
~13580, ylfyxa3's ~17380, etc; distinct master.lpc/
logind.lpc/securityd.lpc content in every case).
Fixes applied
Ported/cross-checked against the 夕阳再现-family playbook (bixiecanyang/#71, xyzxfy2/#47) where lineage matches, plus fresh findings from this archive's own content:
1. AGENTS.md §15h (adm/simul_efun/chinese.lpc's is_chinese()): GBK
lead-byte range check (strlen(str)>=2 && str[0] > 160 && str[0] <
255) → CJK Unicode codepoint range check (strlen(str)>=1 &&
str[0] >= 0x4e00 && str[0] <= 0x9fff).
2. AGENTS.md §15h (adm/daemons/logind.lpc's check_legal_name()):
byte-count bound strlen(name) < 2 || > 10 → character-count bound
< 1 || > 5 (matches the message's own stated "1 到 5 个中文字"); the
sliding-window gate i%2==0 && !is_chinese(name[i..<0]) had its
i%2==0 && dropped so every character position is checked (same
reasoning as bixiecanyang: is_chinese() only inspects index 0 of
whatever's passed, so a full-length suffix slice is functionally a
single-character check either way).
3. AGENTS.md §15z (3 files: include/globals.h, adm/obj/master.lpc,
adm/obj/simul_efun.lpc): each carried an #ifndef
__SENSIBLE_MODIFIERS__ / #define nosave static / #define protected
static compatibility shim, and convert_lib.sh's blanket
static→nosave sed rewrote the shim's own lines to #define nosave
nosave / #define protected nosave (silently aliasing protected to
nosave). Neutralized the whole shim (replaced with a one-line
comment) in all 3 files. New nuance for the catalog: this
driver build's own predefine table (dumped at boot) DOES include
#define __SENSIBLE_MODIFIERS__ — meaning the #ifndef guard is
actually false here and the buggy branch is dead code at compile
time regardless. The textual sed-collision still happened (the sed
doesn't know about #ifdef state), so the fix was still applied as
free, harmless insurance, but it may not have been live either way on
this particular driver build/config. Worth checking __SENSIBLE_
MODIFIERS__'s presence in the predefine dump on future libs before
assuming §15z is *always* a live bug versus just a latent one.
4. AGENTS.md §3 counterexample (7 files): the same blanket sed hit
log_file("static/XXX", ...) string literals (a real on-disk log
subdirectory name), rewriting them to "nosave/XXX". Reverted all
occurrences back to "static/XXX" in: clone/misc/dan.lpc,
adm/simul_efun/override.lpc (×5), adm/daemons/securityd.lpc,
adm/obj/master.lpc (×5), cmds/std/give.lpc, cmds/std/suicide.lpc,
and adm/daemons/复件 securityd.lpc (see item 10 below).
5. AGENTS.md §14 (adm/obj/master.lpc's valid_override): upgraded
from the 2-arg signature to the documented 3-arg (file, name,
main_file) form, checking main_file == SIMUL_EFUN_OB || main_file ==
MASTER_OB in addition to the original file check — simul_efun.lpc
is a pure #include composer (pulls in object.lpc, message.lpc,
etc, several with efun:: overrides), so file alone never equals
SIMUL_EFUN_OB for those fragments. No live boot/registration failure
observed without this fix (consistent with the catalog's note this may
never surface on a real boot) but applied as free insurance.
6. AGENTS.md §15s (adm/simul_efun/message.lpc's tell_room()): the
dominant 2-arg call form (275+ of 332 call sites in this archive)
leaves varargs object *exclude at its default int 0, which then
flows straight into message("tell_room", str, ob, exclude) — this
driver's message() rejects a raw int 0 for its 4th
(void|object|object*) argument. Fixed at the shared root:
exclude || ({}). Also found and fixed the same shape in shout()
(a variant not previously seen written exactly this way): message(
"shout", str, users(), this_player()) — this_player() can itself be
0 outside a genuine player context, hitting the identical rejection;
fixed by wrapping in me ? ({ me }) : ({}).
7. New §15b-style gap (adm/simul_efun/message.lpc): two functions
called throughout the lib but never defined anywhere —
message_combatd(msg, me, you) (called from adm/daemons/itemd.lpc
and 2 kungfu/skill/ files) and message_sort(msg, me, you) (called
4× from adm/daemons/itemd.lpc). Both aliased to the already-defined
message_vision() (identical 3-arg shape), added right after it in the
same file (safe ordering, no §15aa risk since message_vision is
textually first).
8. §15ac-style bare macro (3 files: d/quanzhou/npc/tang3.lpc,
d/taishan/tang3.lpc, adm/daemons/network/netmail.lpc): bare
SAVE_EXTENSION (never defined anywhere in this lib) → this driver's
real autogenerated __SAVE_EXTENSION__ constant.
9. AGENTS.md §15ab (clone/user/login.lpc's receive_message()): the
pre-login connection object's copy was missing the !stringp(str)
guard that the post-login player body's copy (feature/message.lpc)
already has — added proactively as insurance (no live crash observed
here since the two files this pattern usually trips on, motd/
welcome, both exist with real content in this archive, but the gap
is real and cheap to close).
10. Orphaned backup file (adm/daemons/复件 securityd.lpc, Chinese for
"copy of securityd.c" — a stray backup with a different, older, and
genuinely broken shape than the real securityd.lpc, not referenced
by anything in the tree): renamed to
复件securityd.orphaned-backup so it can't be mistaken for a live
compilable object (same treatment as AGENTS.md §12's precedent).
11. AGENTS.md §15w (adm/obj/master.lpc's log_error()): broadcast
to the connected player was unconditional (if (this_player(1))
efun::write(...)) even for ordinary compile *warnings*, not just real
errors. Gated the broadcast on the message NOT containing
"warning:" (log-file write is unchanged/unconditional).
12. New content-gap fix, single shared root (d/city/obj/cloth.lpc,
file did not exist at all in the raw archive — d/city/obj/ only
shipped box/gourou/jitui/table/zhubang.lpc): 47 different NPC
files spread across at least a dozen different zones (city2,
wudujiao, tangmen, guanwai, village, mingjiao, quanzhou,
lingshedao, gumu, kungfu/class/{gumu,npc}, migong, etc.) all
hardcode the literal carry_object("/d/city/obj/cloth")->wear(); as
their standard starting-garment call (clearly one shared boilerplate
template copy-pasted verbatim into dozens of zone-specific NPC files,
never updated to each zone's own local obj/cloth.lpc the way most
other zones' NPCs correctly do), and since the target never existed,
carry_object(...) returned 0 and ->wear() on it crashed silently
during each NPC's own create() (the crash is swallowed with no
printed diagnostic — same silent-nested-compile-failure shape as
AGENTS.md §15d, just triggered by a genuinely-missing file instead of
an ACL denial). This was the single highest-impact lpcc-sweep fix:
restoring ONE file (copied verbatim from the byte-for-byte-identical
sibling template at d/city/npc/obj/cloth.lpc/d/village/npc/obj/
cloth.lpc/d/tangmen/obj/cloth.lpc — all three are the same
"basic starting cloth" boilerplate, confirmed by direct comparison
before reconstructing, not fabricated content) dropped the lpcc
sweep's failure count from 336 to 285 in one shot (see "lpcc sweep"
below for the exact before/after numbers).
13. 3 small genuine pre-existing typos found via the lpcc sweep:
- d/baituo/obj/bowl.lpc and d/baituo/npc/obj/bowl.lpc:
set_name("海口大碗", "bowl") — second arg is a bare string where
set_name() expects string* (the alias-list idiom used
everywhere else in this lib, e.g. set_name("布衣", ({ "cloth" }))).
Fixed to ({ "bowl" }).
- clone/book/lbook5.lpc and clone/book/pixie_book.lpc: each had a
literal duplicate int query_autoload() { return 1; } declaration
(copy-paste artifact) causing "Redeclaration of function". Removed
the redundant second copy in both.
- d/npc/m_weapon/weapon/m_bian.lpc: two void create() definitions
— the first is the complete, correct item setup (name/weight/
wield-messages/init_whip); the second is a short, clearly
incomplete leftover fragment (unit/no_get/no_drop/setup()
only). Removed the second (dead/incomplete) one, keeping the first.
14. 5-file iconv-eaten-newline fix (matches the documented Encoding
gotcha: iconv -c's invalid-byte recovery can eat the adjacent REAL
newline too, merging a @LONG...LONG text block's closing tag onto
the preceding text line): d/heimuya/tang.lpc, d/heimuya/npc/
tang.lpc, d/heimuya/shenggu.lpc, d/quanzhen_old/manglin1.lpc,
d/quanzhen_old/manglin2.lpc — all 5 showed error: End of file in
text block from a merged ...文本.LONG ); (or CRLF 。LONG\r\n)
line. Confirmed against the raw pre-conversion bytes in each case
(an invalid/truncated GBK byte immediately followed by a literal
newline) before inserting the newline back in at the exact point
indicated by the raw byte layout — not a guess. All 5 verified
compiling clean afterward via standalone lpcc.
Confirmed NOT needed (verified by reading source)
- §4 (lazy security-daemon
load_objectrecursion invalid_read/valid_write):master.lpc'svalid_writeonlyfind_object(SECURITY_D)(returns0if absent, never lazily loads it);valid_readdoes the same, defaulting to1(allow) if absent. Noload_object()call anywhere in either apply. - §7 (
get_root_uid/get_bb_uid): both present and correct inmaster.lpc(return ROOT_UID;/return BACKBONE_UID;). - §15l (
destruct(SIMUL_EFUN_OB)in master'screate()):create()is a one-linewrite("master: 成功加载.\n");— no destruct/reload dance present. - §15n (custom
securityd.lpcACL denying "(player)"-status reads, blocking mid-connection lazy compiles): this lib'ssecurityd.lpc'svalid_readunconditionallyreturn 1;— no ACL table exists at all to deny anything. Confirmed further by zero "Read access denied" indebug.logacross two full interactive sessions. - §8c (
this_player()-override footgun invalid_read/valid_write): greppedsecurityd.lpcfor theif (this_player()) user = this_player();shape — not present. - §15u (dormant "phone-home license check" self-destruct function): grepped
securityd.lpc/master.lpcforchecking_status/mass deletion/shutdown()-gated-on-opaque-check shapes — none found. - §8d/§15o (
get_include_path()/ local<header.h>-next-to-its-user angle-bracket includes):convert_lib.sh's automatic local-include-to- quotes pass converted 22 such includes to quoted form during conversion; a follow-up scripted check confirmed zero remaining case-sensitivity mismatches between any#includetarget and its actual on-disk filename. Nomaster.lpc get_include_path()addition needed. - Nitan-family simul_efun-dbase architecture bug (§15): not present.
adm/obj/simul_efun.lpcis a pure#includecomposer;feature/ dbase.lpcimplements real localset/query/deletemethods directly (correct inherit-based architecture, not the bare-simul_efun pattern). - §8e (
tail()missing-efun bug): notail(call anywhere in the lib. - §8f (
TYPE * name1, name2;array-modifier-doesn't-propagate bug): spot-checked ~15 of the 42 grep hits for this shape across the lib — every one is an intentional array+scalar declaration (e.g.object *enemy, ob;whereobis later assigned a single element and used as a scalar throughout), the correct/intended idiom in this lineage, not the Dead-Souls-specific "both should be arrays" bug. No fix applied. - §15p (DNS/intermud daemon preload hang):
adm/etc/preloadis entirely empty in this archive (just blank/CRLF lines) — nothing preloads at all in this lib (confirmed live: the boot log goes straight from "Loading master file" to "Accepting telnet connections", no preload activity logged).network/dns_master.lpcexists on disk but is never referenced fromlogind.lpc's connection path — grepped forDNS_MASTER/dns_master/gb_big5/Mud_name(inlogind.lpc, zero hits. Nothing to exclude. - §15x (hardcoded
MUD_PORTmismatch silently rejecting every connection):master.lpchas#define TOMUD_PORT 9999, but — exactly like bixiecanyang's finding — it's only used to set a cosmetic"tomud"temp flag, never to reject a connection. Confirmed no rejection via two successful end-to-end interactive tests on port 40070 (≠ 9999). - §15q-shaped hidden gate — but here it IS live, unlike bixiecanyang: see "Registration flow" below — this archive's version of the gate is NOT conditioned on the
TOMUD_PORT/"tomud"flag the way bixiecanyang's was (structurally unreachable there); hereget_versionis the unconditional FIRST callback on every connection, so the literal"2060"handshake must always be sent first. Confirmed by readinglogind.lpc'slogon()directly (no gatingifaround theinput_to("get_version", ...)call) and by the live transcript (the gate fired on both test runs).
Registration flow (read from logind.lpc's actual input_to chain)
logon() → get_version (unconditional; the prompt reads "请输入您
的英文名字:" — textually indistinguishable from a normal id prompt, but
the real check is arg[0..3] != "2060"; sending anything else prints an
"警告!本游戏必须使用TOMUD客户端..." alert and disconnects — a live
instance of AGENTS.md §15q) → English id (get_id; "new" branches to
registration) → GetNewId (english id, must not be "new"/"quit",
must be unused) → confirm_id (y/n) → get_name (Chinese name,
1-5 characters; typing a name directly skips the get_resp y/n loop
entirely — that loop only fires for the empty-input → random_name()
path) → new_wizpwd (an "admin password", ≥5 chars) → confirm_
wizpwd → new_password (the real login password, ≥5 chars, must
differ from the admin password) → confirm_password →
select_gift (attribute roll, 0-4; 0 = system-random via get_gift's
y/n accept loop) → get_email ([email protected] format required) →
get_gender (m/f) → enter_world().
banned_name list: 你/你的/我/我的/自己/屁/他/他的/她/她的/它/它的/鬼王/
风云/流氓/爸/妈/祖先/祖宗/爷/奶/毛泽东/邓小平/江泽民/【/】/马克思/恩格斯/
列宁/抄/手淫/老百姓 — checked before testing; neither "秦风" nor "林风"
match any entry.
Interactive test #1 — full registration + post-login commands, real name "秦风"
Single continuous mudclient.py session, in order:
2060→ passes the client-version gate, reaches the id prompt.new→ enters the registration sub-flow.qinfeng→ accepted as the new english id, "...您确定吗(y/n)?" prompt.y→ confirms, shows the "give yourself a name" banner.秦风(real Chinese name) → accepted silently on the first try, no rejection, straight to "请设定您的管理密码:" — confirms the §15h fix works end-to-end.- (a stray extra
yin my script landed on the admin-password prompt instead of a nonexistentget_respconfirmation — rejected for being too short, exactly asnew_wizpwd's own length check should, thenadmin12345/admin12345succeeded for wizpwd+confirm,player12345/player12345for the real password+confirm — incidental but useful confirmation that the length-check rejection path also works correctly) 0→ system-random gift roll (膂力20/悟性20/根骨23/身法17).y→ accepts the rolled gift.[email protected]→ accepted as email.m→ male gender.- Character actually entered the game world, landing at
/d/quanzhou/tieqiang(铁枪庙/"Iron Spear Temple", one of the 4 configuredstart_rooms), saw real NPCs (乌鸦×4/"crows") and room content render correctly.〖有间客栈〗channel broadcast "听说又来了 一位叫做秦风的少年侠士" with the correct real name embedded. look→ re-displayed the exact same room correctly (confirmed by the identical room-description block appearing a second time in the transcript, immediately following the entry banner/system alert).quit→ dropped the starting "布衣" garment and disconnected gracefully with "欢迎下次再来!" ("welcome back next time").
Zero real error:/"Read access denied"/"Bad argument"/"Too deep
recursion" lines anywhere in debug.log for this session — only the same
benign Unknown #pragma, ignored / Unused local variable compile
*warnings* seen throughout every other lib in this family.
Interactive test #2 (after ALL fixes above, fresh driver restart) — real name "林风", female, incl. score
Per AGENTS.md's own diagnosis-technique note ("LPC objects don't recompile
just because their source file changed on disk; you must restart the
driver process"), the driver was killed and rebooted fresh after every
fix in this NOTES.md was applied (several touched
adm/simul_efun/message.lpc, a file every room/NPC's heartbeat/emote
path depends on) before this second, independent verification run:
2060→new→linfeng→y→林风(real Chinese name) → accepted silently, straight to wizpwd prompt (no stray extra input this time) →wizpass12/wizpass12→realpass34/realpass34→0→y(gift roll: 膂力29/悟性22/根骨15/身法14) →[email protected]→f(female).- Character entered the game world at
/d/city/wumiao(武庙/"Yue Fei Temple"), with the gender-correct starting garment ("粉红绸衫"/pink silk garment, not the male "布衣") and gender-correct in-game description ("你是一位十四岁的女性人类..."). look→ re-displayed the room correctly (room description block repeated a second time in the transcript).score→ a full, correctly-rendered character sheet: age/gender/ birth-time flavor text, all 4 attributes (膂力/悟性/根骨/身法) matching the rolled values, 精/气 (essence/qi) bars, combat attack/defense power, food/water bars, kill count, 潜能 (potential)/实战经验 (combat experience) — confirms the post-login command-dispatch pipeline works for more than justlook(a second, entirely differentcmds/command file), satisfying AGENTS.md §15ae's standing policy with a stronger signal than a single command would.quit→ dropped the "粉红绸衫" garment and disconnected gracefully.
Zero real error:/"denied"/"crash"/"undefined"/"bad argument" lines in
debug.log for this second, post-fix session either (grepped explicitly,
excluding the harmless config-table dump lines that happen to contain the
word "error"/"crash" in key names like mudlib error handler/trap
crashes).
lpcc sweep
Ran 3 times (before content-gap fix / after the d/city/obj/cloth.lpc
content-gap fix / after all remaining typo fixes), memory monitored
throughout (well within budget — 11413 files, never dropped below ~17GB
free on this 23GB host, nowhere near the §6b mega-lib danger zone):
| Pass | Pass | Fail | Total | Pass rate | |---|---|---|---|---| | 1 (pre-fix) | 11076 | 336 | 11412 | 97.06% | | 2 (after cloth.lpc fix) | 11128 | 285 | 11413 | 97.50% | | 3 (final, after typo fixes) | 11138 | 275 | 11413 | 97.59% |
Triage of the failures (per AGENTS.md §6b's "categorize before fixing" guidance):
- ~211 of the final 275 failures are a "blank" shape (
Fail to load object X.with zero further diagnostic text) — spot-checked ~6 of these across different zone clusters (d/migong/lev7/dong99,/kungfu/class/ xueshan/jiamu,d/migong/lev7/dong82) by re-running them standalone via barelpcc: every one compiled clean in isolation, confirming this is the documented §6b/§15d-shaped false-positive category (a file that's fine on its own but shows as failed when it's one of 11000+ objects compiled into a single shared-VM batch session — some state/ordering interaction across the giant batch, not a per-file bug). Verified this isn't purely "batch size" by re-running just the 256 originally-blank files as their OWN smaller batch: most (240/256) still failed even at 1/45th the batch size, ruling out a simple size/table-capacity threshold — the real common thread turned out to be the missing-content cascade below, not batch size per se. - The single highest-leverage real cause, found and fixed: 47 files'
carry_object("/d/city/obj/cloth")->wear()referencing a file that genuinely didn't exist in the raw archive at all (see fix #12 above) — this alone explains the bulk of the "blank" shape's drop from 256 to 211 files between sweep passes 1 and 2/3 (a missing target makescarry_object()return 0, and->wear()on that crashes silently during the referencing NPC's owncreate(), exactly matching the "no visible diagnostic" symptom). - The 74→(post-fix)~64 failures with real diagnostic text were triaged by error-message category (per §6b/§8g): fixed all the genuinely cheap, real, non-network-daemon ones (2× Redeclaration, 2× Bad-type set_name, 5× iconv-eaten-newline, the message_combatd/ message_sort gaps, the 3× SAVE_EXTENSION macro, the m_bian duplicate create()); confirmed the
is_root-undefined-function cluster (5×) is dead code inside the never-#includedadm/simul_efun/override.lpc(see below); confirmed theCannot #include {uid,config,daemons, mailer}.hcluster (12×) and theUndefined function {member_group, data_netmail_file, mud_name, file_exists}cluster (6×) are entirely insideadm/daemons/network/*intermud/DNS daemon files, never preloaded (preload is empty) and never referenced fromlogind.lpc's live connection path — out of scope, matches the project's established "don't chase unreached network daemons" precedent. The remaining scattered "Undefined variable"/syntax-error singletons (mostly insidefeature/vendor_sale.lpc, see below, and a handful of one-offkungfu/skill//d/-zone files not on any preload/registration path) are noted here as known, low-impact gaps rather than hand-fixed one at a time, consistent with the project's "prioritize breadth over exhausting every last content bug" policy. feature/vendor_sale.lpc(a shop/vendor-NPC feature file,#included by/inherited intokungfu/class/npc/xiaoer.lpc— 2 files affected): genuinely, severely mangled in the raw, pre-conversion archive itself (confirmed viadiffagainst the raw.c— byte-identical, not something our pipeline introduced) — roughly the back third of the file (pay_back/do_deposit/do_setprice) is missing semicolons and closing parens on nearly every line, looks like a botched find/replace or half-finished edit from the original 1999-era author (file header says "modify by ronger 99/02"). Per AGENTS.md's guidance on genuinely broken pre-existing content of this scale (as opposed to a single-line typo), left unfixed and documented here rather than guessing at the intended reconstruction of a decades-old half-edited shop-payment function — a real, pre-existing archive content gap, not a driver-compat bug.adm/simul_efun/override.lpc/user.lpc/util.lpc: containefun::overrides (snoop,shutdown,destruct, etc.) and callis_root()(undefined), but none of these three files are#included byadm/obj/simul_efun.lpcor anything else in the tree (confirmed via grep) —simul_efun.lpcimplements its own inlinesnoop/shutdown/destructoverrides directly instead. These 3 files are dead/orphaned content from an earlier engine revision; their lpcc-sweep failures are pure noise, not live bugs.
Re-verification pass (2026-07-23)
Clean re-boot confirmed (zero fatal errors, empty etc/preload boots in
well under 5 seconds). Ran the full registration + look/score/quit
flow once more in a single continuous connection (id qinchuan, real
Chinese name 秦川, male): 2060 client-version gate → new → id →
y confirm → Chinese name accepted → admin password (2x) → real
password (2x) → gift roll 0/y → email → gender m → entered the
world at 客店/"the inn", saw real NPC (店小二/innkeeper) and board
content, look re-rendered the room correctly, score produced the
full character sheet, quit disconnected cleanly ("欢迎下次再来!"). Zero
runtime errors in debug.log. No code changes needed — clean
re-confirmation of the original pass's findings.
Config notes
config.fluffos adapted from the raw config.cfg (name "夕阳再现", the
generic engine name — the live banner shows the game's real identity,
「笑傲江湖」之「重出江湖」). Dropped obsolete keys per driver warnings:
address server ip, address server port, reserved size, binary
directory, swap file. Port set to 40070; mudlib directory points
at this lib's work/; log directory is the usual /log (sibling of
config.fluffos, driver always launched via cd into this directory
first, per AGENTS.md §6).
Encoding
convert_lib.sh reported 29 lossy conversions (invalid bytes dropped) out
of 12378 files — all but 5 (see fix #14 above) turned out to be genuinely
harmless (either non-code data/save files, or code positions where the
dropped byte didn't touch anything load-bearing). No stragglers found by
the standard post-conversion file -b sweep beyond one false positive
(d/emei/shenshuige.lpc, a normal, fully-valid UTF-8 room file that file
misclassifies as "data" for unrelated heuristic reasons — confirmed by a
full Python UTF-8 decode, not a real encoding problem).
Driver rebuild / formatter / WASM pass (2026-07-23)
- LPC formatter run over all
work/*.lpc: 11,413 total, 11,324 written, 35 already-idempotent, 54 refused (self-check errors, expected on messy legacy code). One formatter regression found and fixed (same bug class as found live-breaking a sibling lib this pass):clone/misc/board.lpc'sshort()hadreturn ::name(1) + "(" + capitalize(::query("id")) + ")";mangled intocapitalize (: : query("id")\n)\n+ ")"— the formatter corrupts the::methodname(...)parent-call scope operator when immediately followed by(. Fixed by hand-restoring the original single-line form. (A second, unrelated: :match ind/migong/12gong/renma.lpcturned out to be ASCII-art map content inside a string/comment block, not code — left untouched.) - Native retest against the freshly-rebuilt driver: clean boot, zero fatal/syntax errors. Full registration flow (client-version gate
2060→new→ id → confirm → real Chinese name → admin password ×2 → real password ×2 → gift roll → email → gender) plus post-login commands re-verified in one continuous connection (idqinchuanc, real Chinese name秦川岭, genderm): entered the game world (this run landed at 北疆小镇/a Xinjiang-themed town rather than the 客店/inn from the prior pass's run — expected variance from the gift/race roll, not a bug),lookshowed real room + NPC content, the character sheet displayed correctly,quitdisconnected cleanly with "欢迎下次再来!". Zero runtime errors indebug.log. - WASM test: boots clean (only the expected non-fatal preload warnings). Found a genuine, reproducible WASM-harness/mudlib timing gotcha, not a mudlib bug:
adm/daemons/logind.lpc'slogon()hasif (uptime() < 10) { write("游戏服务器正在启动过程中,请稍等10秒后再 连线。\n"); destruct(ob); return; }— a deliberate 10-second post-boot grace period, present in the original archive, that natively is a non-issue (the real-world overhead of spawning the driver process,ssport-checking, and starting a Python client naturally exceeds 10 seconds by the time a real connection attempt lands). Underwasm_client.js,fluffos_connect()is called synchronously immediately afterfluffos_boot()returns, with no equivalent real-world gap — so every WASM test attempt hits this gate deterministically and the connection is destructed before the English-name prompt is ever reached. Confirmed this isn't recoverable by waiting longer via--send/--idleafter connecting (theuptime()check runs once, atlogon()time, which is effectively t≈0 in the WASM harness's clock) — the harness would need to delay thefluffos_connect()call itself by 10+ simulated seconds, which its current CLI surface doesn't expose. Not patched — modifying the shared harness is out of this pass's scope, and the mudlib's own 10-second gate is intentional, pre-existing design, not a bug. Documenting as a known WASM-testing limitation distinct from thequery_ip_number()one.
WASM-enablement pass (2026-07-24)
Standard four-change pass (AGENTS.md §1.3b/§1.3e/§1.5). Gates patched:
1. Loopback always allowed — adm/daemons/band.lpc: added an
is_local_site(site) helper (fail-closed, see retrofit note below)
and short-circuited:
- is_banned() (called from logind.lpc's logon() ban check) →
local always returns 0 (not banned);
- vaild_allow_address() (the account's own allow_ip allowlist
check, logind.lpc) → local always returns 1 (allowed), regardless
of whatever allow_ip list the account has configured.
2. Uptime startup gate — adm/daemons/logind.lpc's logon() had
if (uptime() < 10) { ...destruct(ob)... } (documented as a known,
pre-existing, non-blocking-natively design gate in the "Driver
rebuild / WASM pass" section above). Now only applies to non-loopback
connections: if (!is_local && uptime() < 10) { ... }.
3. Anti-flood throttles exempt loopback — logind.lpc's logon():
the per-IP concurrent-connection cap (ban_cnt > 8) now skips local
connections; get_id()'s per-IP concurrent-player cap (ip_cnt > 8)
is now also skipped for local connections (wiz_level(arg) < 2 &&
!BAN_D->is_local_site(...)).
4. Admin account seeded — id fluffos, pw Mud@2026, name 浮浮,
registered via the real flow (2060 client-version gate → new → id
→ y confirm → Chinese name → admin/"management" password →
confirm → real password → confirm → gift 0/y → email → gender
m). Granted (admin) via adm/etc/wizlist (fluffos (admin)).
- This lib's registration flow has an unusual double-password
step: besides the real login password, it also asks for a
wizpwd ("管理密码"/"management password") — despite the name,
reading logind.lpc's get_passwd()/reset_wizpwd() confirms
this is NOT related to wizard/admin status at all — it's a
self-service password-reset PIN (typing it at the normal password
prompt triggers "you typed the management password, please reset
your normal password"). Set to FluffMgmt1 (≥5 chars, must differ
from the real password) — document this as a secondary recovery
PIN, distinct from the Mud@2026 login password, since a future
agent re-seeding this account needs both.
- Genuine pre-existing bug found while verifying admin access:
include/command.h defines ADM_PATH/WIZ_PATH/IMM_PATH (and
the other unused historical rank macros BOS_PATH/ARC_PATH/
ANG_PATH/APR_PATH/GEN_PATH) as ({}) — an EMPTY command
search path — confirmed identical in the raw, unconverted archive
(not a conversion artifact). feature/command.lpc's
enable_player() calls set_path(ADM_PATH) for any account whose
wizhood() is "(admin)", so promoting fluffos via wizlist (the
documented, standard admin-grant mechanism) left the account with
ZERO working commands — not just wizard commands, but ordinary
ones too (look, quit, everything), since
commandd.lpc's find_command() searches exactly the directories
in path and an empty list matches nothing. No wizard-only command
files exist anywhere in this lib to legitimately populate these
macros with, so fixed by aliasing all of them to the same
directories as PLR_PATH (/cmds/std/, /cmds/usr/,
/cmds/skill/) — promoted accounts keep normal command access
instead of being silently locked out of the game entirely. This is
outside the standard four-item WASM-enablement scope but was
necessary to satisfy §1.5's "verify a wizard command actually
works" step at all.
Save files (untracked, NOT gitignored — orchestrator must git add):
work/data/login/f/fluffos.o(login save: password + wizpwd)work/data/user/f/fluffos.o(player body save)
Fail-closed loopback retrofit (2026-07-24)
Security correction, applied together with the initial patch above (this lib was patched fresh in this same pass, so it was written fail-closed from the start rather than needing a later retrofit):
int is_local_site(string site) {
if (!stringp(site)) return 0;
if (site == "127.0.0.1" || site == "::1") return 1;
if (strlen(site) >= 4 && site[0..3] == "127.") return 1;
return 0;
}An unparseable/empty IP is treated as remote/untrusted, not loopback — deliberately, since the original code already rejected missing/malformed IPs outright and there is no longer a WASM driver bug to work around.
Retest (2026-07-24)
Both done against a fresh driver restart (to pick up the command.h
fix, which is compile-time):
- Fresh normal registration: id
gatechk/gatetestchar(two runs, one before and one after the command.h fix — command.h only affects wizard-level accounts, so ordinary(player)registration was unaffected either way), real Chinese name (秦岭/王小江), reaches the world at a real room (北疆小镇),look/scorerender correctly,quitdisconnects cleanly with "欢迎下次再来!". Test char saves removed after verification. - fluffos login + wizard command: before the
command.hfix, a logged-in fluffos session showed "(admin)" in the banner but every subsequent command (includinglook) silently failed with ambient NPC chatter as the only output (ROOT CAUSE: the emptyADM_PATHbug above, not a login/gate problem — the account WAS correctly admin, it just couldn't run anything). After the fix: fluffos login →lookcorrectly re-renders the current room →quitdisconnects cleanly. Zero new runtime errors indebug.log(only the same benignUnknown #pragma/Unused local variablecompile warnings seen on every boot of this lib).
WASM 修复摘要(迁移自 meta.json 的 group_note)
"夕阳再现"衍生引擎上的一款独立游戏。状态已从过时的 limited 修正——这份档案自己的 README 里从未记录过任何缺陷说明,本轮重新测试也没有发现:这个版本需要 Tomud 客户端版本握手(第一行字面回答"2060",和本项目其它地方已经记录过的家族共同模式一致)——实测确认:2060→id→密码→"★ 您目前权限:(admin)",quit 干净。
§7.86 跨库扫描修复(留言板 post 崩溃)
BULLETIN_BOARDinherit+ 多余replace_program()致命形状(AGENTS.md §7.86,post命令崩溃):全档案 98 处命中,已删除多余的replace_program(...)调用(保留inherit),逐文件保留原有行尾格式(CRLF/LF 按文件原样)。本次为跨库 §7.86 扫描修复(触发原因:该 bug 已在 6+ 个互不相关的血统家族独立确认,属于近乎普遍的拷贝粘贴模式),仅做编译检查(驱动干净启动、端口正常监听),未做完整 §10.7 深度游玩测试。
深度功能测试 / Deep functional test (AGENTS.md §10.7)
Status: done. One real programming bug found and fixed (registration- breaking, every single new character); everything else — combat, organic skill/sect acquisition, quit/reconnect persistence — verified live and clean.
Environment setup gap (not a code bug, noted for the record)
This session's fresh checkout had no log/ directory at all (gitignored,
libs/*/log/ + libs/*/work/log/), so the FIRST boot attempt crashed
before the connection handler ever printed a prompt: *Wrong permissions
for opening file /log/debug.log for append. "No such file or directory",
followed by Error in mudlib error handler (the driver's own error
reporting couldn't even write *itself* because the directory was missing).
Fixed by mkdir -p log work/log before booting — this project's two
distinct log roots for this lib: the driver's own debug.log
(log directory config key, resolves against the launch CWD == lib root,
confirmed via ls libs/xajhzcjh/log/) vs. mudlib-level write_file()/
log_file() calls using the LPC-virtual /log/ path (resolves against
work/, confirmed via libs/xajhzcjh/work/log/dbgtrace appearing there
during live instrumentation) — two genuinely separate roots for two
genuinely separate log mechanisms, not a typo. Both are the standard,
already-documented (§7.44) "runtime dir doesn't exist in a fresh
checkout" setup step, not something to fix in code.
Bug found and fixed: log_file() never calls assure_file() — breaks EVERY new registration (AGENTS.md §7.11, new confirmed sibling instance)
Symptom, 100% reproducible across 5+ independent registration attempts
in this session: a brand-new character completes the ENTIRE registration
ritual (client-version gate → id → Chinese name → wizpwd → password →
gift → email → gender) with every prompt rendering correctly, then lands
on a bare > prompt with zero world-entry banner (no MOTD, no "你连
线进入这个世界" line, no ★ 您目前权限), zero working commands
(look/score/i all return the driver's generic default fail
message, "什么?", because enable_player() never ran), and zero
save file ever written to work/data/{login,user}/<letter>/<id>.o. No
error appears anywhere — not on the player's screen, not in debug.log.
This exactly matches AGENTS.md §7.11's already-documented xajhxo
sibling-instance shape (same TMI-2/夕阳再现-adjacent family pattern, same
get_gender() call site) — this is now a second confirmed instance in
the same 夕阳再现/XYZX lineage (libs/xyzxfy2 and libs/ylfyxa3 were
ALSO independently found and fixed with the identical shape in their own
deep-test passes — adm/simul_efun/file.lpc's log_file()/assure_file()
pair is a shared low-level utility copy-pasted across this whole family,
so check it FIRST on any future 夕阳再现-lineage dive rather than
rediscovering this from scratch).
Root cause: adm/daemons/logind.lpc's get_gender() — the LAST step
of the registration input_to() chain, executed right after the gender
prompt, immediately before init_new_player()/enter_world() — calls
log_file("login/newid.log", sprintf(...)) to record the new account in
a per-lib registration log. adm/simul_efun/file.lpc's log_file() was a
bare write_file(LOG_DIR + file, text) with no directory-existence guard
at all. On a fresh work/ tree, work/log/login/ has never been created
(nothing in this archive's own boot path creates it), so this
write_file() throws *Wrong permissions for opening file
/log/login/newid.log for append. "No such file or directory" — and
since nothing in get_gender() catches it, the uncaught error aborts the
rest of that function, meaning CHANNEL_D->do_channel(...),
init_new_player(user), and — critically — enter_world(ob, user) never
run. enter_world() is where user->setup() (which calls
enable_player(), wiring up every player command) and user->save()/
ob->save() live, so skipping it silently strands the new character with
no commands, no save, and no visible sign anything went wrong.
Confirmed via live catch()-wrapped instrumentation (temporarily added
then reverted, not part of the shipped fix) that this exact call is the
one throwing: err=*Wrong permissions for opening file
/log/login/newid.log for append. "No such file or directory", and that
wrapping it (or fixing the shared root) lets enter_world() run to
completion with the full banner, working commands, and a real save file.
Fix (adm/simul_efun/file.lpc, matching this lineage's established
assure_file()-before-write_file() convention exactly, same shape as
xyzxfy2/ylfyxa3's own fixes): added assure_file(LOG_DIR + file);
as the first line of log_file(), plus a one-line forward declaration
(void assure_file(string file); before log_file()'s own definition)
since assure_file() is textually defined further down in the same file
and this driver's compiler doesn't resolve forward references without an
explicit prototype (same convention logind.lpc itself already uses
elsewhere). This is the shared-root-cause fix (AGENTS.md §6.4): it covers
every log_file() call site in the tree, not just get_gender()'s,
including any future subdirectory nobody has thought to pre-seed yet.
Formatter: ran format-corpus.mjs on the touched file — 0 written
(already idempotent with the fix applied), 0 errors. Checked the 3 §9
blind-spot greps on this file specifically: clean (no : : split, no
\ n corruption).
Registration + state verification (multiple independent live sessions, post-fix)
Raw-socket Python test client (scripts/mudclient.py-equivalent, written
ad hoc this session — tmux/telnet kept dying mid-session in this
particular container for unrelated reasons, see below) driving one
continuous connection each time:
秦岚(idquicka) — full registration → world entry at 武庙 (wumiao), banner/MOTD/permission line all render,look/score/iall work. Save file confirmed on disk. (Used for the root-cause instrumentation pass; re-verified clean again as the final post-fix smoke test with a fresh boot.)文剑(idwenjianc) — registration → world entry at 武庙 →look/score/i→ walked to 北大街,fight scavenger(收破烂的): correctly invoked the safe-sparaccept_fight()path (human NPC,can_speakset) but the scavenger declined in-character ("小兄弟 饶命!小的这就离开!" / "看起来收破烂的并不想跟你较量。") — a real, clean exercise of the mechanism with a negative outcome, not a bug (see combat mechanism notes below). Continued to 丽春院 (an age-gated room, see content-observation note below) →apprentice kongkongfailed because kongkong was never reached.score/i→quitclean.林牧(idlinmuc) — registration → world entry at 铁枪庙 (tieqiang, one of the 4start_rooms) →fight wuya(a 乌鸦/crow): this is a beast-race NPC, not human, so it has nocan_speakandfight.lpcsilently routes it through the REALkill_ob()branch instead of the safe spar (see below) — character took a few points of real combat damage (survived fine, "气" bar stayed full) before moving away broke off the fight.apprentice limochou(a nearby quanzhou-local NPC copy, noattempt_apprenticeoverride) got the correct default-reject dispatch (你想拜谁为师?, meaningpresent()didn't even find her by that name — a harmless test-script naming miss, not a bug).score/i→quitclean.杨飞(idyangfei, passwordplaypass456) — the complete end-to-end run: registration → world entry at 北疆小镇 (beijiang) →look/score/i→ walked east to 巴依家院 →fight bayi(a human NPC,attitude: heroism): accepted ("巴依说道:既然小兄弟赐教, 老头子只好奉陪。"), a real multi-round sparring exchange followed ("你挥拳攻击巴依的后心...但是巴依已有准备"/"巴依对准你的腰间用力挥出 一拳...你受了几处伤,不过似乎并不碍事" — flavor text matching the documented "只会消耗体力,不会真的受伤" non-lethal design) →look/scoreafter combat → walked to 天山山路 (near 灵鹫宫, ~5 hops from beijiang) →apprentice shihou(matched 狮吼子/"Shihou zi", a 星宿派/Xingxiu-sect NPC with an unconditionalattempt_apprentice()accept) succeeded completely: "狮吼子说道:好吧,我就收下你了。" → "你跪了下来向狮吼子恭恭敬敬地磕了四个响头,叫道:「师父!」" → "恭喜您成为星宿派的第三代弟子。" — confirmed viascore: title changed from 布衣平民 to 【武林人物】星宿派第三代弟子. →score/i→quitclean ("你丢下一件布衣" / "欢迎下次再来!").
- Reconnect after a real ~1-hour wall-clock gap (this session's own
root-cause investigation + NOTES.md drafting time, not a sleep):
logged back in with yangfei/playpass456 → landed back at the
exact saved room (天山山路) → score confirmed full state
persistence: title still 星宿派第三代弟子, "你的师父是狮吼子。"
(master field persisted), all 4 attributes unchanged (19/22/18/21) →
quit clean again. No quit-retention lockout or grace-period logic
exists in cmds/usr/quit.lpc for new accounts (confirmed by reading
it: unconditional me->save(); destruct(me);, no deletion path) —
didn't need the "kill the raw connection instead" fallback.
log/debug.log grepped after every one of the above sessions for real
error:/denied/crash/undefined/bad argument lines (excluding the
benign Unknown #pragma/Unused local variable compile warnings and the
literal string "mudlib error handler" in a config dump key): zero real
errors in the entire final (post-fix) test corpus.
Combat mechanism (read from cmds/std/fight.lpc, then live-verified both branches)
fight <target> is this lib's dedicated safe-sparring command — its own
help text says so explicitly ("这种形式的战斗纯粹是点到为止,因此只会
消耗体力,不会真的受伤"/"purely a courtesy bout, only costs stamina, no
real injury"), distinct from kill (real, lethal) and hit. Critical
nuance this lib's own source reveals, worth reading before picking a test
target in ANY sibling of this lineage: fight.lpc's main() branches
on obj->query("can_speak") — if the target can't speak, the "polite
challenge" flow is skipped ENTIRELY and it falls straight into
me->fight_ob(obj); obj->kill_ob(me);, i.e. a real, lethal fight,
even though the player typed fight, not kill. can_speak is set to 1
only by adm/daemons/race/human.lpc's setup_human() — so it's
effectively "is this NPC human" — every non-human race (beasts, etc.) is
UNSAFE to fight despite the command's name and help text. Confirmed
live on both sides: fight wuya (race 野兽/beast, no can_speak) →
real kill_ob() combat, took actual damage. fight bayi (default race,
human, can_speak set) → real accept_fight()-mediated safe spar,
non-lethal flavor text only. Lesson for future dives in this lineage:
"a clearly-safe humanoid NPC" isn't just stylistic advice here — picking
an animal NPC for the "safe" combat test would have been actively unsafe
on this exact codebase.
Default accept_fight() (inherit/char/npc.lpc) requires the target NOT
be already fighting, above 90% jing/qi, and NOT have attitude: friendly
(friendly NPCs always decline — matches the scavenger/维吾尔族妇女
rejections seen live). heroism/aggressive/killer/unset attitudes all
accept by default. No dedicated "training dummy" NPC was actually reached
live this pass (the d/*/npc/mu-ren.lpc "练功木人" with no_die: 1 seen
during source review would have been an even stronger choice, but bayi
already gave a clean, complete, accepted spar).
Skill/sect acquisition — organic path (live, succeeded) and admin shortcut (confirmed absent)
Organic path: apprentice <target> (aliased bai, cmds/skill/
apprentice.lpc) → for an NPC target with a working attempt_apprentice()
override, an unconditional acceptor recruits immediately in one command
(see 狮吼子/Shihou-zi run above — full success, title + master field both
persisted through a reconnect). Most class-master NPCs
(kungfu/class/<sect>/*.lpc) gate acceptance on stats/gender/karma (read
several: kungfu/class/gaibang/hong.lpc wants str>=20 && con>=25,
.../liang.lpc wants str>=25, .../zuo-qu.lpc wants male, etc.) — but
a handful (kungfu/class/xingxiu/{azi,shihou,tianlang,zhaixing}.lpc, at
least) accept unconditionally. Default attempt_apprentice()
(inherit/char/npc.lpc) always politely declines for any NPC without an
override (verified live: apprentice tuobo-seng/apprentice limochou
against non-master NPCs both got the correct in-character decline/
not-found response, no crash).
Admin shortcut: confirmed absent. This lib ships no cmds/adm/ or
cmds/wiz/ directory at all (ls cmds/ → only skill/, std/,
usr/) — matches the already-documented include/command.h finding
(§1.5 admin-seeding pass, this same NOTES.md above) that this archive
never shipped any wizard-only command files. There is no in-game
admin command anywhere in this lib to directly grant a skill or sect
membership to a player — the organic apprentice/learn/study/
practice commands are the only path, for admins and players alike.
发现但判定为既有设计、未改动的现象 (observations, not bugs)
- 丽春院 (brothel room) blocks entry for a 14-year-old character with "小朋友不要到那种地方去!!" ("kid, don't go to that kind of place!!"). Every fresh character is born age 14 (
adm/daemons/race/human.lpc:if (undefinedp(my["age"])) my["age"] = 14;), so this room — and its resident NPC 孔空儿/kongkong (an otherwise-unconditional gaibang recruiter) — is unreachable by any brand-new character until they age up in-game. Sensible, deliberate content gating, not a bug; just meant picking a different apprentice target for this pass's live test. 收破烂的/scavenger declining afightchallenge and fleeing ("小兄弟饶命!") is intentional per-NPC characterization (a coward/thief archetype), not the safe-spar mechanism malfunctioning — the sameaccept_fight()call correctly ran and correctly returned a decline;attitudejust wasn't set to something that accepts by default for this particular NPC (or it has its own override not investigated further, out of scope once the mechanism itself was already confirmed working elsewhere).- Wuya (crow) escalating a typed
fightinto a realkill_ob()fight is fully explained byfight.lpc's owncan_speakbranch (documented above under "Combat mechanism") — read as intentional design (animals don't have a "point to stop" courtesy fight the way humans do in this lineage's combat model), not a bug, though it IS a genuine safety trap for a careless player (or a careless test pass) expectingfightto always mean "safe" against any target regardless of species.
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.
深度功能测试(2026-08-13,round two,新驱动重测)
针对升级后的驱动(quest_times/win_times %-operator 修复 + Warning/
warning 大小写驱动兼容回退)做的第二轮 §10.7 重测。
环境笔记:build/src/driver 在本次会话的宿主 CPU 上崩溃(非本 lib 问题)
scripts//AGENTS.md 惯用的 /home/sunyc/src/fluffos/build/src/driver
本次会话启动即崩溃:Illegal instruction 于
evthread_use_pthreads——反汇编确认该函数被编译成使用 AVX 指令
(vmovq/vpinsrq/vinsertf128),而本次会话实际落地的宿主 CPU 是
Intel(R) Xeon(R) CPU L5520(Nehalem,2009 年,/proc/cpuinfo
flags 里最高只到 sse4_2,完全没有 AVX)——一个构建/宿主 CPU 不匹配
的环境问题,与 xajhzcjh 自身代码无关。改用同仓库另一份构建
/home/sunyc/src/fluffos/build-debug/src/driver(未启用相同的
AVX 代码生成路径)成功干净启动、监听 40070、完成本轮全部测试。记录此
坑供后续同一宿主上的 session 参考:如果 build/src/driver 启动即
"Illegal instruction",先试 build-debug/src/driver,不要误判为
lib 本身的问题。
发现并修复的 PROGRAMMING bug
1. adm/daemons/logind.lpc 里两处遗留的 printf("%O\n", ob); 调试
残留(AGENTS.md §7.34 的形状,与 xajh4gkb round two 独立确认的同一
位置形状一致):分别在确认中文名字后进入密码设置的两条并行分支
——get_resp()(接受随机产生的名字)第 532 行、get_name()(手动
输入名字被接受)第 565 行——每次注册确认名字后都会把 ob 的
file_name(如 /clone/user/login#0)原样打印给玩家。Live 实测
已复现:用测试号 testqqchen 走完整注册流程,屏幕上在"请设定您
的管理密码"提示前出现了裸的 /clone/user/login#0。两处均删除该行,
只保留紧邻的 ob->set("name", ...)。round one 的 NOTES 完全没有提
到这两行,是本轮新发现(round one 覆盖了这个文件的其它 bug 类,唯
独漏了这个)。修复后用第二个测试号 verqqchen(女性分支)重新走完
整注册流程确认:不再出现任何裸路径泄漏,正常进入游戏世界,男女分
支各自的起始服装(布衣 vs 粉红绸衫)都正确。
§7.34 log_error() / §7.11 log_file():round one 已修复,本轮确认仍在位
adm/obj/master.lpc's log_error() 仍有大小写不敏感的
strsrch(message, "arning:") == -1 判断;adm/simul_efun/file.lpc's
log_file() 仍在 write_file() 前调用 assure_file(LOG_DIR + file)
(含正确的前向声明)。两处均未见回归。
§5/dbase.lpc 密码守卫检查:不适用
feature/dbase.lpc 的 set(prop, data) 是纯粹的无守卫赋值(读取整份
文件确认),没有任何 wizhood()/password 相关的特殊分支——跟
tybxjh/wlhd 那个 bug 形状完全不同,这个 lib 没有对应问题。
管理员播种验证:wizlist 条目确有对应存档,本轮做了真正的断线重连
adm/etc/wizlist 里 fluffos (admin) 这条 round one 就已写入,
data/login/f/fluffos.o、data/user/f/fluffos.o 也确实存在(不像本
轮重测系列里其他几个 lib 那样"wizlist 里看起来对但从未真正注册过")。
本轮用 fluffos/Mud@2026 走了一次登陆(2060 → id → 密码),入世
后横幅确认 ★ 您目前权限:(admin),look/east/west/score 全部
正常。强制验证步骤:quit 断线后用一个全新的 tmux 会话重新连接,
2060 → fluffos → Mud@2026 完成一次真正的断线-密码-重连,密码验
证通过,管理员权限保持 (admin),落回原来存档的房间(武庙)——不是
只看世界进入和权限横幅就下结论。存档文件的 last_on/combat_exp 字
段随之更新(score 命令触发的正常游玩状态变化),已随本次提交一并
纳入。
移动/驱动兼容性检查
east→west 往返移动、score 多次未触发任何"Too long evaluation"
崩溃或其他异常,debug.log 全程(262 行,逐行读过)只有一贯的
Unknown #pragma/Unused local variable 编译期警告,与 round one 记
录的基线一致,零真实 error/denied/crash/undefined。
quest_times/win_times %-operator 修复:抽查确认在位
d/city2/npc/refereew.lpc 现有 to_int(query("win_times")) % 5,是
corpus-wide 2026-08-12 sweep(commit c571a53629f)已经打过补丁的写
法,无需额外改动。
未在本轮测试
拜师门派、商店购物、完整战斗到死亡/复活循环——round one 已用多个测试
号做过完整覆盖(安全切磋 vs 真实战斗的 can_speak 分支、组织化拜师
成功案例、跨重连状态持久化),本轮认为不需要重复;本轮重点是驱动升级
后的回归检查 + 正常游玩中顺手发现的 bug(本次即发现了新的 §7.34 实
例)。
AGENTS.md §7.100 修复(2026-08-19,批次三)
ROOM 基类冗余 replace_program(ROOM); 自崩溃地雷(详见 AGENTS.md
§7.100):4239 处命中。自带建房工具 clone/misc/roommaker.lpc 的
字符串拼接模板同样修复。
git diff --stat:4238 files changed, 1 insertion(+), 4239 deletions(-),
与预期精确吻合。
验证:build-debug 驱动真实冷启动,端口 40070 正常监听。既有管理
员账号 fluffos/Mud@2026(经本 lib 要求的 "2060" 客户端版本握手)
登录,您目前权限:(admin) 确认,武庙→北大街→北门多房间走访无
误,quit 干净退出,全程无新增 "cannot replace"/"cannot bind" 日
志行。
§7.30 uninitialized-mapping accessor sweep (2026-08-20)
Corpus-wide mechanical sweep of the feature/skill.lpc shared-lineage
bug (confirmed independently on xiakexing2017/jqxz2015/haiyang2
via round-four testing): 4 accessor(s) in this file returned a raw
never-initialized mapping instance variable (defaults to int 0,
not ([]), until first assigned), crashing any unguarded
keys()/sizeof()/indexing caller for a fresh/untrained character.
Fixed at the accessor level (mapp(x) ? x : ([])) per the documented
remedy. Verified via lpcc --batch static compile check only (not a
live boot) as part of a large mechanical sweep; not individually
functionally re-tested live on this lib.
深度功能测试(§10.7,2026-10-04)— negative range ends
scripts/lpc_fix_negative_ranges.py: 5 line(s) in 2 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;);reset() 的 default: 拿到 0 就跳过这一项(if (!objectp(ob[list[i]][j])) continue;)。档案里没有的 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-07)— 空的 if (current_water == 0) {}
5 个房间的 valid_leave() 里有一行什么也不做的 if (current_water == 0) {}(编译警告 Expression has no side effects),删去,行为不变:d/gaochang/room11.lpc、d/gaochang/room12.lpc、d/gaochang/room13.lpc、d/gaochang/room14.lpc、d/xingxiu/shanjiao.lpc。
深度功能测试(§10.7,2026-10-10)— 编译警告整理
scripts/lpc_warnings.py xajhzcjh --fix 加 scripts/lpc_fix_no_effect.py --apply,共改动 390 个 .lpc 和 4 个 .h(多为删去未用的局部变量)。HEAD 与工作树分别加载(新进程):367 -> 367 通过,无回退;改过的头文件的 39 个包含者 39 -> 39 通过。启动时警告 0 -> 0;新进程登录(输入名字)正常。
深度功能测试(§10.7,2026-10-10)— 编译警告整理的剩余部分(手工与新工具)
整理后余下 42 条警告,全部处理:
- 11 处
bitwise operation on boolean values(五毒教d/wudujiao/的毒囊与洞穴:if (arg != "ba" & arg != "huo ba")),&改&&(新脚本scripts/lpc_fix_bitwise_bool.py,按驱动报告的行改唯一一个单独的&/|)。 - 17 个 NPC 的
int init()与/feature/attack.lpc的void init()不符,函数体没有返回值,改为void;三个裁判clear_title()的原型写成int,定义返回string(arg + clear_title(...)拼称号),原型改正;kungfu/class/xiakedao/yufu.lpc的accept_object原型void改为与定义一致的int(新脚本scripts/lpc_fix_return_types.py)。 - 8 个文件在
NPC/MONEY/BLADE之外又继承F_CLEAN_UP(clean_up() inherited from both),删去多余的继承(lpc_diamonds.py)。工具同时被修正:它原先把clone/misc/objmaker.lpc、roommaker.lpc里 here-document 模板中的inherit ITEM;/inherit ROOM;当作代码。 clone/misc/board.lpc的transfer只在#ifdef BACKUP_B分支里用,声明移进分支;kungfu/skill/huashan-jian.lpc多余的;删去。
42 个改动文件 HEAD 与工作树各载入一次:39 -> 39 通过,无回退,警告 42 -> 0。
- 2026-10-15:
kungfu/skill/guangming-blade.lpc(光明刀法)是从五虎断门刀抄来的,query_action()里仍按wuhu-duanmendao的等级挑招式:没练五虎断门刀的人出招时一招都匹配不上,a_action为 0,接着赋值报错。改为按guangming-blade自己的等级。(武功运行期探针发现。)
内力/精力当作伤害种类(2026-10-15,KB 06 §7.241 第二类)
本库 feature/damage.lpc 的 receive_damage() 不接受 jingli/neili/force 等种类,me->receive_damage("jingli", 30) 之类在练功、绝招、吸取时报 F_DAMAGE: 伤害种类错误。13 处改为 add(type, -N)(scripts/lpc_fix_damage_calls.py 第二步)。
无门派玩家的 family 映射(2026-10-15,KB 05 §7.30 第三种)
mapping fam = ob->query("family"); 之后直接 fam["family_name"]:没有门派(新人或叛师后)的玩家在学习、练功、拜师、进入门派房间时报 Value being indexed is zero,而不是作者写好的提示。9 处在声明行加上 if (!mapp(fam)) fam = ([ ]);(scripts/lpc_fix_family_guard.py)。
东方故事/西游记体系的技能文件(2026-10-15,KB 06 §7.241 第三类)
这些 kungfu/skill 文件来自 gin/kee/sen/force 体系,本库人物只有 jing/qi/neili:receive_damage("kee", 30) 报 伤害种类错误,query("force") 永远为 0,技能学不了也练不了。按 kee→qi、gin/sen→jing、force→neili、max_force→max_neili、force_factor→jiali 改了属性名(scripts/lpc_port_es_props.py),共 8 个文件。
其他体系的属性名(2026-10-15,KB 06 §7.241 第三类,--any-file)
另有 6 个文件(绝招、状态、物品、NPC 等,不限于 kungfu/skill)来自 gin/kee/sen/force 体系,同样按 kee→qi、gin/sen→jing、force→neili 改名(scripts/lpc_port_es_props.py --any-file)。
family 映射(补)(2026-10-15)
mapping fam = (mapping)me->query("family");(带类型转换的写法)同样直接取下标,1 处补上 if (!mapp(fam)) fam = ([ ]);。
治疗/疗伤的属性名(2026-10-15,KB 06 §7.241)
receive_heal()/receive_curing() 也只接受本库的种类。5 个文件(多为只调用 receive_heal/receive_curing 的药物、NPC)来自其他体系,按本库的属性名改名(scripts/lpc_port_es_props.py --any-file)。
message_vision(msg, environment(me), me)(2026-10-15,KB 06 §7.242)
把房间当成了动作者:message_vision() 取房间的 name() 得 0,replace_string(msg, "$N", 0) 报错。在状态(中毒)里,这个错误发生在 apply_condition(name, duration - 1) 之前,状态永不结束,心跳里后面的恢复也每次被跳过。改为 message_vision(msg, me):/kungfu/condition/sanpoison。
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。3 处补上 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.246)
perform 指令允许直接点名招式(如 perform stick.ban),这些绝招读了 me->query_temp("weapon") 却从不检查,空手时 weapon->name() 报错(有的已先扣了内力)。在赋值后补 if (!objectp(weapon)) return notify_fail("你必须手持兵器才能使用这一招。\n");(scripts/lpc_fix_perform_weapon.py):dagou-bang/ban。
把经验、属性、内力当技能读(2026-10-15,KB 06 §7.247)
当前内力、精这类名字有时指的是内功技能,逐处读过后手改:落英缤纷 luoying-shenjian/lybf:自己的注释说成功率由“精神高低”决定,两处 query_skill("jing") 改为 query("jing")。
碧海生潮曲空手报错(2026-10-15,KB 06 §7.246)
iceforce/roar(碧海生潮曲)先 ob = me->query_temp("weapon"),再直接拿 base_name(ob) 判断是不是玉箫;空手 exert roar 时 base_name(0) 报错,提示“你必须先找一只玉萧来才可以吹--曲”根本出不来。条件前补 !objectp(ob) ||。
iceforce「chillgaze」从未编译通过(2026-10-15)
iceforce/chillgaze 原档在第一个 return notify_fail(...) 后多了一个 },exert() 就此结束,后面的语句全落在函数外,skill、damage 也没有声明,文件编译失败,这个 exert 从来用不了。照 bixiecanyang、hc、xyzx3 已修好的版本删去多余的 }、补上 int skill, damage;,其余字句不变,只是缩进进函数体。
技能名拼错(2026-10-15,KB 06 §7.249)
query_skill() 里的技能名拼错了,或用的是本库改名前的旧名;本库没有这个技能,调用永远得 0:门槛(< N 就拒绝)永远过不去,相关功夫或绝招学不了、用不了;内功互斥(> N 就拒绝)从不生效;公式里这一项一直是 0。经汉字名(提示文字或中文名词典)或纯拼写差异(_/-、少一个连字符、相邻字母颠倒)核对后,改为本库的技能名(scripts/lpc_fix_skill_typo.py):douzhuan-xignyi→douzhuan-xingyi(/d/mr/npc/obj/shu1、/d/mr/obj/shu1);beimin-shengong→beiming-shengong(/d/quanzhen_old/kungfu/skill/xiantian-qigong);jinwu-dao→jinwu-daofa(jinwu-daofa);mizongxinfa→mizong-xinfa(longxiang/fanchang);yihua-jimu→yihua-jiemu(yihua-jiemu);zhenfen-xinfa→zhenfeng-xinfa(zfwy-bu)。
文件首行注释少了一个斜杠(2026-10-15)
首行的说明注释只剩一个 /(如 /kuangwu.c金蛇狂舞、/ cloth.txt //),文件第一行就语法错误、编译失败:全真教的布衣 /d/quanzhen_old/obj/cloth 因此从来载入不了。补回斜杠成为 // 注释,现在都能载入。
技能名拼错:技能文件里拼错自己的名字(2026-10-15,KB 06 §7.249)
技能自己的文件(或它的绝招目录)里,query_skill() 读的是差一个字母的自己的名字,永远得 0:“基本功夫要高过本技能”之类的限制从不生效,按等级取招、计算伤害的那一项一直是 0。改为本技能的名字(scripts/lpc_fix_skill_typo.py 的 self 判据):hujian-daofa→hujia-daofa(hujia-daofa);jinggang-quan→jingang-quan(jingang-quan);xuantie-jiafa→xuantie-jianfa(xuantie-jianfa);xuanxie-jianfa→xuantie-jianfa(xuantie-jianfa)。
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,而不是得到拒绝。8 处(6 个文件)改为 dbase 路径查询 query("family/master_name"):有门派时值相同,没有时得 0;原有的判断照常生效(scripts/lpc_fix_family_index.py)。给映射赋值的写法未动。
用兵器的绝招空手施展时报错(内联写法)(2026-10-15,KB 06 §7.246)
绝招不存兵器变量,直接写 (me->query_temp("weapon"))->query("name")(或在拒绝判断里写 (weapon = me->query_temp("weapon"))->query("skill_type")),之前又没检查兵器:空手 perform 时报 Bad argument 1 to EFUN call_other(),内力等往往已经扣掉。在第一次用到它的那条语句前补上“你必须手持兵器才能使用这一招”的拒绝(scripts/lpc_fix_perform_weapon.py):yunv-jian/suxin。
存档读不出来:字符串里的换行、空行(2026-10-15,KB 03 §4.4)
clone/gift/npc/bingqipu.o:字符串里有原样的换行(save_object() 存成 \r,restore_object() 逐行读,原样的换行让字符串收不了尾),或有空行(Illegal file format),读档的对象(留言板、NPC、玩家)从空白开始。换行改写成 \r、删去空行(scripts/lpc_save_encoding.py --from-raw),驱动核对全部能读回(scripts/lpc_save_restore_check.py)。
移进不存在的巫师房间(2026-10-15,KB 06 §7.251)
用完的物品、要“离开”的 NPC、掷在空中的兵器被移进巫师的工作室(/u/llm/、/u/wind/),本库没有这些房间。本库的 move() 用 load_object() 找目的地,找不到就返回 0,不报错,东西留在原处:被雇来打晕或杀人的李凌(d/city2/npc/liling2)办完事后没有离开,留在原地(d/city2/npc/liling2 本身还载入不了:create() 里 carry_object() 的物品文件缺失或编译失败,见 KB 06 §7.73,另行处理);婚礼结束(d/nanyang/npc/meipo 的 last_marry)时月老没有离开喜堂,每办一次婚礼喜堂里就多一个月老;喜宴结束后喜来福(d/nanyang/npc/xi-laifu)没有退回内堂,每办一次婚礼迎宾楼就多一个喜来福。3 个文件改为移进本库的虚空房间 VOID_OB(/clone/misc/void),与原作把它们“停放”在巫师房间的用意相同(haiyang2 的维护者把月老送进 /d/city/empty,也是同样的做法)。
玉女剑法「合壁」用一次就永久改动经验和剑法(2026-10-15,KB 06 §7.253)
收尾的 hebi() 声明时没有参数(void hebi() { object me, target, env; int i, j, o, p, count; ...),call_out 传进去的人和数值全被同名的局部变量(0)挡住,开头的 if (!me && !target) return; 每次都返回:合壁的攻击、闪避加成和 hebi 标记要到重新登录才消失。更糟的是夫妻判断写成了 target->querry("id")(没有这个函数,得 0),没成亲的人 marry/id 也是 0,于是人人都被当成夫妻:自己的玉女剑法和经验乘以玉女素心功的级数/80(至少变成浮点数,160 级以上翻倍),随后给对方 set_skill("combat_exp", ...) 时报 No such skill,收尾的 call_out 也就没排上,乘过的等级和经验永远不还原。测试里用一次合壁,经验 100000 变成 200000.0、剑法 100 变成 200.0。改正:hebi() 按它自己再次 call_out 时传的八个参数声明,perform 的 call_out 去掉多余的 h, k,querry 改为 query,给对方的 set_skill("combat_exp") 改为与上一行一样的 set("combat_exp")。测试里加成照常生效,hebi() 结束时还原并清除标记,没成亲的人经验和剑法不变。
NPC 带着本库没有的物品,载入失败(2026-10-15,KB 06 §7.73)
75 个文件、104 处在 create() 里 carry_object("<本库没有的文件>")->wear()(或 wield()、set_amount()):carry_object() 得 0,接着的调用报 Bad argument 1 to EFUN call_other(),NPC 根本载入不了,该有它的房间里就少了这个人。多是从别的系统搬来的 NPC 用了原系统的物品路径(最常见:/d/city/obj/gangjian、/d/city/obj/changjian、/d/city/obj/tiejia)。每处改为 { object carried_ob = carry_object(...); if (carried_ob) carried_ob->wear(); }(scripts/lpc_guard_carry_object.py):NPC 照常出现,只是不带这件东西;文件补回来(或是虚拟对象)照样会带上。载入检查:改动的文件改前能载入 0 个,改后 77 个(77 个原来载入不了),没有退步;其余 1 个另有原因(多为 set_skill() 了本库没有的武功)。
物品清单把名字的第一个字吃掉(2026-10-18,KB 07 §8.1)
inventory、房间的物品列表(feature/move)和部分 look 把同名物品合并计数,键是 query("unit") + short(),只有一件时按 key[2..] 去掉量词。量词是一个汉字,在原来的 GBK 里占 2 字节,[2..] 正好去掉量词;转成 UTF-8 以后一个汉字只占一个下标,这一刀把名字的第一个字也切掉了(「把长剑」只显示「剑」,带颜色的名字切掉的是转义序列开头)。改为 [1..](scripts/lpc_fix_unit_cut.py):feature/move.lpc。
水潭里 ging_cost 是 jing_cost 的笔误(2026-10-18)
shuitan 先算 jing_cost,倒水时却扣 receive_damage("jing", ging_cost),ging_cost 从没声明过:Undefined variable 'ging_cost',整个物件载入不了。改成 jing_cost:d/shaolin/npc/obj/shuitan.lpc。改后用 lpcc 逐个载入这些对象:1 个通过。
全真心法 valid_learn() 里没声明的 lvl(2026-10-18)
kungfu/skill/quanzhen-xinfa.lpc 的 valid_learn() 判断 me->query("gender") == "无性" && lvl > 49,可是函数里只有 nk、nf、nh、ns 四个变量,没有 lvl:Undefined variable 'lvl',这门心法的文件载入不了,学它、用它都失败。nh 正是全真心法的等级(nh = query_skill("quanzhen-xinfa", 1)),改成 nh > 49。改后用 lpcc 逐个载入这些对象:1 个通过。
kungfu/skill/qingyi-jian 第一式的 skill_name 丢了收尾引号(2026-10-18,KB 03 §4.6)
"skill_name" : "大悲式, 的收尾引号没了(转码时跟半个汉字一起丢了),字符串连到下一行,damage_type 成了代码:Illegal character 0xe5,整个武功载入不了。补回 ",(同系的 bixiecanyang、syxjl 等库里有完好的同名文件)。载入:通过。
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 载入不了,刷出它的房间也少一个人。本库有 6 个对象设了本库没有文件的武功(9 个名字,最多的是 hunyuan-force、ruyi-blade、taxue-steps)。三处都改成 return:这一门武功不给、不映射,对象照常载入,只是少了它(缺的武功本身仍是内容缺口)。抽样载入这些对象:6 个里 6 个通过。(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 映射不到,门派弟子用普通轻功/拳脚)。按核对过的对照表改正,共 23 处、21 个文件:yan-fly→yanfly(3 处)、xinxiu-duzhang→xingxiu-duzhang(2 处)、tiaji-jian→taiji-jian(2 处)、kongmingquan→kongming-quan(2 处)、shaolin-shnfa→shaolin-shenfa(2 处)、taiji-shenfong→taiji-shengong(2 处)、lingbo-weibu→lingboweibu(2 处)、poyu-qua→poyu-quan(1 处)等共 15 个名字。(scripts/lpc_fix_skill_names.py)
全局头文件丢了 2 个宏(2026-10-19,KB 04 §6.16)
/include/globals.h 里没有定义 WIELD_CMD、MAILDIR,用到它们的物件(名单里 2 个)编译时报 Undefined variable/Undefined function,整个物件载入不了(编译器在第一个未定义的名字上停下,后面的错误和警告都看不到)。同系的库在各自的头文件里都有这几行:照其中和本库共有文件最多的那个库,原样补到 /include/globals.h 最后一个 #define 之后,宏体里出现的路径在本库里都存在。补完后名单里有 1 个载入,其余还差别的东西。(scripts/lpc_restore_defines.py)
找不到父类函数的 ::fn() 调用(2026-10-19,KB 06 §7.259)
/d/city3/jiulou2/obj/food.lpc共 1 个物件里写着 ::create();、::init(); 这类调用,而它们继承的基类并没有这个函数。老驱动把这种调用当成什么都不做、返回 0 的空调用,本驱动在编译时报 Unable to find the inherited function 'init'.,整个物件载入不了。这些物件的错误只有这一种(其他错误清掉之后才露出来的),逐个删掉这些调用(return ::fn(...) 改成 return 0;)。(scripts/lpc_fix_dangling_super.py)
区域物件的零碎修正(2026-10-19,KB 06 §7.267–§7.271)
/d/board/mingjiao_b.lpc的location从不存在的/d/mj/guangming-ding改成/d/mingjiao/guangming-ding(载入明教留言板失败会让光明顶房间载入不了)- 5 个 NPC 文件、5 处
create()里的this_player()->carry_object(改成carry_object((没人在场时this_player()是 0,NPC 载入不了;有玩家在场时衣服武器落到玩家手里)
逐个物件与 HEAD 对比载入,没有退步。
一行写完的源文件还原(2026-10-19,KB 06 §7.272)
下列 5 个文件的整个源码挤在开头的一行 // 注释里(档案的编辑器丢了换行),驱动只编译出一个空程序,物件载入后没有名字、没有 id、拿不到手上:/d/quanzhen_old/obj/allow-letter.lpc、/d/quanzhen_old/obj/greenrobe.lpc、/d/quanzhen_old/obj/greyrobe.lpc、/d/quanzhen_old/obj/hanzhu.lpc、/d/quanzhen_old/obj/shenmu.lpc。scripts/lpc_uncollapse.py 按语句、语句块、#include 重新分行,再过一遍格式化。还原后逐个载入没有退步,new() 出来的物件有名字和属性。
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 文件。
玩家打造兵器模板被 NPC 带上(2026-10-19,KB 06 §7.275)
/d/npc/m_weapon/weapon/m_club.lpc、/d/npc/m_weapon/weapon/m_sword.lpc(共 2 个)的 create() 用 this_player() 读打造数据(me->query("weapon/lv") 等)。NPC 的 weapon 属性是兵器文件名(字符串),NPC 在别的 NPC 的命令环境里 carry_object() 这个模板时,set_desc() 里 switch (w_lv) 拿到的是那个字符串,驱动报 Bad argument 1 to switch,房间和 NPC 都载入不了(旧驱动里 switch 落到 default)。把 if (me) { 改成 if (me && mapp(me->query("weapon"))) {,玩家打造的流程不变。
玩家打造兵器模板没有打造者时(2026-10-19,KB 06 §7.275)
/d/npc/m_weapon/weapon/m_hammer.lpc、/d/npc/m_weapon/weapon/m_staff.lpc、/d/npc/m_weapon/weapon/m_whip.lpc、/d/quanzhen/npc/obj/m_sword.lpc、/d/quanzhen_old/npc/obj/m_sword.lpc(共 5 个)的 create() 开头 me = this_player(); 之后无条件读 me->query("weapon/name") 等打造数据。房间刷新时没有人在场(me 为 0),或者 NPC 在别的 NPC 的命令环境里 carry_object() 这个模板(NPC 的 weapon 属性是文件名字符串),旧驱动里读出来是 0 或字符串,switch 照样落到 default;新驱动报 Bad argument 1 to EFUN call_other() / Bad argument 1 to switch,NPC 和它所在的房间载入不了(--walk 普查里一个玩家走进房间就触发)。在 //读入数据 之后加 if (!me || !mapp(me->query("weapon"))) { setup(); return; }:没有打造者就留一个没有名字的空模板,玩家打造的流程不变。
补回丢失的标点(2026-10-19,KB 03 §4.6)
转换时丢掉的分号、逗号、引号或文件末尾的 },共 2 个文件,修前 HEAD 载入失败。别的库里同路径的完好副本只比这里少几个标点,按它补回(括号里是那个库):/kungfu/skill/huang.lpc(bixiecanyang)。一行文字在逗号前丢了结尾的引号(下一行是同一个表的下一项),补上:/kungfu/skill/kunlun-zhang.lpc。修后与 HEAD 逐个对比载入:这 2 个物件全部载入,没有退步(scripts/lpc_restore_from_twin.py、lpc_fix_eaten_quote.py --comma、lpc_fix_eof_braces.py)。
玩家买店用的 feature/vendor_sale.lpc 补回(2026-10-19,KB 03 §4.6 第四轮)
/feature/vendor_sale.lpc(/kungfu/class/npc/xiaoer.lpc 继承它)从 pay_back 起约 160 行的行尾丢了最后一个字符(; ) { },else { 只剩 els,msg 只剩 ms),另有一行 if(wizardp(who) || getuid(who)==owner_id) 被拼进了前面的 log_file( 调用里。文件载入失败,继承它的物件也跟着失败。别的库(ldtx、ldtxii、xhcii、syxjl、hy3)里有这个文件的完好副本,但那是另一个版本:没有作者后来加的投标公告(string mesg; 和 message("channel:chat", ...))。所以按完好副本补回丢失的字符(scripts/lpc_restore_from_twin.py --diff --extra),公告两段原样保留;被拼到别处的 if(...) 放回完好副本里它所在的 write("\n盈利 之前;message_vision("channel:chat", ...) 多出来的第一个参数删掉(message_vision 的签名是 (string, object, object),每次 bid 在扣完款之后都会报错)。补完后文件和继承它的物件都能载入,没有警告,也没有退步(HEAD 上两个都载入失败)。
== !"字符串" 多出来的 !(2026-10-19,KB 06 §7.280)
!"taoist" 是整数 0,x == !"taoist" 就是“x 等于 0”,作者为其余所有人写的那一支永远走不到。具体是:龙女对古墓弟子的机关暗门提示永远给不出来(5 处);孙婆婆的“你去吧”只对 class 没设置的人生效;性别检查(“你不是女的,无法领会其中至阴之理”)永远不拦人,男的照样能学玉女心法。全部改成 != "字符串"(scripts/lpc_fix_not_literal_cmp.py):/kungfu/class/gumu/long.lpc(5 处)、/kungfu/class/gumu/sunpopo.lpc(1 处)、/kungfu/skill/yunu-xinfa.lpc(1 处)。同样的行在 xkx 一系的 35 个库里都有。
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/changan/ca2.lpc(1 处)。
登录密码超过 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)。
翻页器 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/more.lpc。
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) ||)。改动:/d/migong/obj/npc1.lpc、/inherit/char/npc.lpc(共 2 个文件)。
不带参数的指令对 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 与工作树对照,没有退步。
睡袋:/cmds/adm/bag 本库没有,使用者被留在聋哑状态(2026-10-21,KB 06 §7.344)
clone/misc/sleepbag.lpc、sleepbag2.lpc 的 do_sleep() 在设好 block_msg/all、no_get 和房间的 sleeping_person 之后调用 "/cmds/adm/bag"->main(me, "<休息中>")。这条巫师指令只有 hc、tianxiawuxue 带着,本库没有:call_other() couldn't find object '/cmds/adm/bag',玩家之后什么消息也收不到(look 一片空白),十秒后的 wakeup call_out 没有排上,房间一直 no_fight。城里的小贩 xiaofan 卖这个睡袋,没有人在扫描里买过它。bag 的全部内容就是 me->disable_player(msg)(feature/command.lpc 里的 nomask void disable_player(string type),没有权限检查),两个文件都改成直接 me->disable_player("<休息中>");。chidi 上实测:sleep 之后十秒 "你一觉醒来,只觉精力充沛",look 正常(HEAD 上玩家被留在空白屏里,log/debug.log 有 trace)。改动:/clone/misc/sleepbag.lpc、/clone/misc/sleepbag2.lpc。
香烟 smoke.lpc:do_smoking() 读没赋值的 me(2026-10-21,KB 06 §7.348)
smoke 指令的第一句是 jing = me->query("jing"),me 声明了没赋值,每次抽烟都抛 Bad argument 1 to call_other()。补 me = this_player();(后面的 this_player() 调用不变)。改动:/d/emei/user-room/melodies/smoke.lpc。
注册到不存在函数的 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.,同一个动词的其他处理函数不再尝试(不是最新的一条就悄悄跳过)。删除了 33 条注册(32 个文件,scripts/lpc_fix_dead_add_action.py),动词留给别的处理函数:/d/changan/qinhuang/shidao5.lpc(do_train)、/d/city/chatroom2.lpc(do_jump)、/d/city/npc/wei.lpc(do_sell)、/d/city/npc/xiaoer2.lpc(do_buy、do_list)、/d/city2/qishi.lpc(do_pass)、/d/city3/npc/sister.lpc(do_vendor_list)、/d/flypproom/npc/flypp.lpc(do_sell)、/d/npc/m_weapon/npc/jia.lpc(do_levelup)、/d/quanzhen/npc/haodatong.lpc(do_decide)、/d/quanzhen/npc/mayu.lpc(do_decide) 等共 32 个文件。最多的函数名:do_send 15 处、do_decide 7 处、do_train 2 处、do_sell 2 处、do_list 2 处。
对象路径里的 ..: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")。
缺失物品的 new() / carry_object() 调用链加了保护(2026-10-22,KB 06 §7.73 补充)
new(路径)->move(...); / carry_object(宏("x"))->wear(); 这类语句,路径指向的文件在这个压缩包里没有:new() 返回 0,->move() 在 0 上报 Bad argument 1 to EFUN call_other()。在 create() 里这个对象永远加载不了,在 reset() 里第一个缺失物品之后的刷新每次 reset 都被跳过。3 个文件里 3 处(new)改成 { object new_ob = new(路径); if (new_ob) new_ob->move(...); }(scripts/lpc_guard_carry_object.py --new:路径按这个文件自己看到的宏解析,宏名冲突、虚拟对象路径一律跳过)。 对这 3 个改动文件做加载检查(HEAD 与工作区对比):HEAD 能加载 2 个,现在 2 个(新增可加载 0 个,回归 0 个)。
调用了、但这个库自己的守护进程里没有的函数(2026-10-22,KB 06 §7.354)
MACRO->函数() 调用的函数在这个库的守护进程里不存在:call_other() 对不存在的函数不报错、只返回 0,所以这些功能(时间显示、昼夜事件、名字检查、价格文字……)一直没起作用。同一血统另一个库的同名守护进程里有这些函数,原文照抄到本库守护进程末尾(scripts/lpc_port_function.py;调用处传的参数个数、函数体用到的函数 / 全局变量 / 宏 / 字符串键都在本库里有,已核对;守护进程在 HEAD 和工作区都能加载,每个函数用固定参数各调用一次:HEAD 返回 0,现在返回正常的值):/adm/daemons/chinesed.lpc ← aoxiangtianji:chinese_month()(2 处调用);/adm/daemons/natured.lpc ← aoxiangtianji:room_event_fun()(9 处调用);/adm/daemons/natured.lpc ← chidi:outdoor_room_outcolor()(1 处调用)。
(: 函数 :) 指针指向对象自己没有定义的函数(2026-10-22,KB 06 §7.355)
item_desc / inquiry / chat_msg_combat 里的 (: 函数名 :) 指向本对象(含包含文件、继承的父类)没有函数体的函数:编译不报错,用到时驱动报 *Undefined lfun pointer called: 函数名(look 某物、ask NPC about 话题 直接出错,战斗 / 闲聊里的指针在 NPC 的 chat() 里出错,这一拍心跳的后半段被跳过)。scripts/lpc_scan_callout_targets.py --kinds=lfun。 还剩 1 个函数没有补(item_desc 1):原型还在函数体丢了、或者根本没写过,没有可以直接补回的捐赠(别的库同一路径的文件里没有这个函数,或者它还要用本库没有的辅助函数、签名不同),不编造:/d/yihua/lianhuachi.lpc:look_CAI。
运行期目录 log/nosave 不存在,写日志的 write_file() 直接报错(2026-10-22,KB 03 §4.3 补充)
这个库的 1 个文件里有 1 处 write_file("/log/nosave/...") / log_file("nosave/...")(static 改 nosave 时连字符串里的日志路径一起改了,原来是 log/static/):/log/nosave/KILL_PLAYER 等。压缩包和站点包里没有这个目录,write_file() 在目录不存在时抛 *Wrong permissions for opening file /log/nosave/... for append. "No such file or directory",调用它的函数(杀人记录、重启记录、call 日志……)当场中断。把 log/nosave 记进 scripts/wasm_keep_dirs.txt(站点和 pristine 树都按它建空目录);没有把字符串改回 static。证明(scripts/lpcc_eval.py,catch(write_file("/log/nosave/ZZTEST", ...)),fqyy2 / hy5 / bmxkx2001 的新进程):补目录前报上面的错误,补后写成功。
读不到的留言板:"/clone/board/x"->foo(); 在 create() 里报错(2026-10-22,KB 06 §7.357)
xkx 系的房间在 setup() 之后写 "/clone/board/gaibang_r"->foo(); 来加载留言板(foo() 本来就没有定义,只为了触发加载)。这个库没有这个文件,call_other() 报 *call_other() couldn't find object '/clone/board/gaibang_r',对象留在内存里、load_object() 却抛错:玩家第一次走进房间就看到错误,写在 create() 中间的还会切掉后半段。scripts/lpc_fix_missing_foo.py 把 1 条单独成行的语句(/d/board/dali_b;/d/dali/guangchang.lpc)注释掉并写明原因(别的房间里同样的语句本来就是作者自己注释掉的)。证明和 45 个库的整体加载检查见 KB 06 §7.357。
不带前导斜杠的物品路径:缺失物品的 new() / carry_object() 调用链加了保护(2026-10-22,KB 06 §7.73 补充)
carry_object("d/city/obj/jiasha")->wear(); 这类路径不带前导斜杠的写法在这个驱动里按根目录解析(new("d/city/obj/changjian") 能加载 /d/city/obj/changjian),所以和带斜杠的一样:文件不在压缩包里时 new() 返回 0,->wear() 在 0 上报 Bad argument 1 to EFUN call_other(),整个 NPC 加载不了。此前的保护工具把这种写法当作「相对当前目录,没法判断」跳过了。4 个文件里 4 处(d/city/obj/gangjian、d/city/obj/pink_cloth)改成带保护的块(scripts/lpc_guard_carry_object.py)。 对这 4 个改动文件做加载检查(HEAD 与工作区对比):HEAD 能加载 0 个,现在 4 个(新增可加载 4 个,回归 0 个)。
(: 函数名 :) 指针指向本库没有的函数:只含这个指针的行加了注释(2026-10-22,KB 06 §7.355 补充)
inquiry / item_desc / chat_msg* 里的 (: 函数名 :) 指向本对象(含包含文件、继承的父类)没有函数体的函数:用到时(ask、look、NPC 闲聊)驱动抛 *Undefined lfun pointer called: 函数名,这一拍心跳的后半段被跳过。这些函数没有可以补回的来源(别的库同一路径的文件里没有,或者它还要用本库没有的东西),所以 1 个文件里 1 行只含这个指针的行("CAI": (: look_CAI :),)加了注释,原文保留并写明原因,这一项当作没有这个话题 / 物品 / 闲聊条目(scripts/lpc_fix_dangling_lfun.py;#include 的文件在库里缺失的对象、指针不在整行上的写法没动)。 前提(function_exists())和加载检查(HEAD 与工作区对比,本库改动的 .lpc 文件)的结果见 KB 06 §7.355:没有一个回归。
写死的 "/路径"->函数() 指向库里没有的文件:改成现存的同名文件(2026-10-22,KB 06 §7.359)
1 处语句级的 call_other 字面量路径,库里没有这个文件(区域改了名 / 大小写不对 / 差一个字母 / 文件挪了地方):"/d/mj/obj/baihong-jian"->move()(/d/mingjiao/npc/yingwang.lpc)→ "/d/mingjiao/obj/baihong-jian"。call_other() 对不存在的对象抛 couldn't find object,所在函数当场中断。改成库里现存、并且定义了被调用函数的文件(scripts/lpc_fix_call_path.py;巫师目录、备份目录、名字不同的兄弟文件都不算候选)。 其中殷天正(白眉鹰王)的 do_answer():玩家念对暗语(answer 怜我世人,忧患实多;保护教主,同抗外敌)时把白虹剑 move 给玩家,区域目录改名 mingjiao 之后这个路径没跟着改,回答暗语只得到 couldn't find object,剑永远发不出来。
汉字按字节切片的老写法没有换成按字符:改法名 "澄" + name[2..3]、辈分判断 name[0..1] == "澄" 等 19 处(2026-10-22,KB 06 §7.360)
原档按字节算字符串区间(一个汉字 2 字节):name[2..3] 是名字的第二个字,name[0..1] == "澄" 问名字是不是以「澄」开头。转成 UTF-8 之后,这个驱动的区间和 strlen() 都按字符算(strlen("澄观") 是 2,"澄观"[0..1] 是两个字),老算术原样留着、意思全变:拜入少林 / 武当 / 峨嵋等派的玩家被改成错误的法名(二字名 张三 变成一个字的 澄,更长的名字取到第三个字);各派掌门的辈分判断(name[0..1] == "澄")永远不成立。
本库 19 处(14 个文件):拼名字的赋值 11 处、与汉字常量比较 8 处。例:name[2..3] → name[1..1](/kungfu/class/emei/jingxin.lpc:101);name[0..1] → name[0..0](/kungfu/class/shaolin/qing-fa.lpc:100);name[0..1] == "慧" → name[0..0] == "慧"(/kungfu/class/shaolin/cheng.h:108)。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,不要重跑。
按字节写的汉字循环、茶馆猜诗和同盟频道标题(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-23,KB 06 §7.365)
老档把汉字当两字节:bar_string[0..(val * N / max) * 2 - 1] 把「格数」换成字节下标,半格血条在本驱动(按字符算区间)上会整条画满;巫师表情 edemote 的 repeat_string("─", 13 - (strlen(emotion) / 2)) 也会少减汉字宽度。scripts/lpc_fix_display_pad.py:去掉 CJK 血条 / 空白条上的 * 2(jings/qis 赋值和 blank_string3[0..(23-a)] 的 23→11 一并改),表情标题去掉 / 2;ASCII 空格的 none_string / empty_string 仍保留 * 2(一格两个空格)。本库 2 处(1 个文件)。证明(lpcc_eval.py hhsj):tribar_graph(6,9,12) 在 HEAD 画出整条 12 个■,改后为 6 个■+3 个□;麻将 strlen(tempB)/2 是两字符牌码,未改。
Beyond 出口仍指向 /u/beyond(2026-10-23,KB 06 §7.368)
宁波 / 苏州 / 慕容等区域已进 /d/ningbo、/d/suzhou、/d/mr、/d/hz,出口与任务物路径仍写 /u/beyond/…。scripts/lpc_fix_beyond_exits.py 在目标 .lpc 存在时改写(murong→mr)。本库 1 处。证明:sjplii xikou HEAD 西向 /u/beyond/ningbo/aywsi,改后 /d/ningbo/aywsi 可加载;bxsj hubian1 三向均可加载。
hanbing `random 反引号(2026-10-27,KB 04 §6.25 Also)
hanbing-mianzhang / hanbing-mianzhang2 在 random( 前多了一个反引号,驱动按模板字面量读到 EOF。删掉。证明:HEAD 失败;改后加载。
set("long" 丢引号(2026-10-27,KB 04 §6.25 Also)
set("long", 后直接跟汉字(无 " / @LONG),驱动报 Illegal character。用同路径完好手足覆盖(fyue_room←jhfy;hudi5/6←zxty08nxgbb;quanzhen_old/hudi*←xyzxfy2)。证明:HEAD 失败;改后加载。
深度功能测试(2026-10-27,§6.25 zhongling tell_object 引号错位)
d/wanjiegu/npc/zhongling(及同路径副本)的 tell_object("who, 钟灵脱下一双绣花鞋。\n") 把对象参数写进了字符串;改为 tell_object(who, "…")。证明:原文错位;改后加载,语料残渣 0。
深度功能测试(2026-10-27,§6.25 one-arg message_vision)
message_vision("…") 补第二参(me / TP / this_player())。
深度功能测试(2026-10-27,§6.10 未知 pragma save_binary/optimize)
删除本库中 FluffOS 不认的 #pragma save_binary / #pragma optimize… 行。