info.html · 介绍 · play.html · 游玩 · llms.txt · 下载与本地运行 · ZIP · GitHub
一个货真价实的金庸多部小说混搭地图,而非单一原著设定的武侠 MUD:除了与 `jyqxc`/`jyqxc2` 家族共有的华山、武当、少林、丐帮等经典门派外,还收录了天龙寺(《天龙八部》)、黑木崖(《笑傲江湖》日月神教总坛)、桃花岛(《射雕英雄传》)与神龙教香堂(《鹿鼎记》),把多部金庸原著的地标拼接进同一个江湖世界。归档里还带着一份未被使用的 `adm/obj/master.lpc`,恰好和 `jyqxc`/`fy2mg`/`xkx2017` 那套框架字节相同,但实际启动用的是另一份 `/adm/single/master`,这份"看起来同源"的档案其实从未被真正加载过,只是血统追溯上的一个巧合红鲱鱼;原始压缩包本身也有个小陷阱——扩展名是 `.rar`,内容却是带 `../` 成员路径的 POSIX tar 归档。
English
A wuxia MUD whose map is a genuine Jin Yong multi-novel mashup rather than a single-book setting: alongside the standard Huashan/Wudang/Shaolin/Beggars' Sect roster shared with the jyqxc/jyqxc2 family, it includes Tianlongsi (the Tianlong Monastery from Demi-Gods and Semi-Devils), Heimuya (Black Wood Cliff, home of the Sun Moon Holy Cult from The Smiling, Proud Wanderer), Taohua/Peach Blossom Island (Legend of the Condor Heroes), and a Mystic Dragon Cult hall (The Deer and the Cauldron). One archival curiosity: extracted from a mislabeled ".rar" that is actually a POSIX tar file, it also carries an unused adm/obj/master.lpc byte-identical to the jyqxc/fy2mg/xkx2017 framework master, but the game actually boots from a different file, /adm/single/master, so this look-alike was never really loaded — a red herring for lineage-tracing rather than a real shared codebase link.
README
内容亮点
- 本次修复中发现一个极其隐蔽的 bug:
SIMUL_EFUN_OB宏指向了一个 未被使用的死代码文件,导致每一个新玩家quit退出游戏都会失 败——表面上看连线像是报错断开了,实际上角色仍然留在游戏世界里, 连线根本没有真正关闭(详见下方 bug 修复说明)。
注册流程
new 触发注册 → 英文 id(3-12 个英文字母)→ 确认创建(y/n)→ 中文
名字(1-6 个中文字)→ 密码(≥5 字元)→ 确认密码 → 天赋确认(y/n)
→ 电子邮件地址 → 性别(m/f)。
本次修复的关键 bug
- 最重要的一个:
include/globals.h里的SIMUL_EFUN_OB宏指向 一个未被使用的死代码文件/adm/single/simul_efun.lpc(早期重构留 下的重复文件),而config.fluffos的simulated efun file实际 指向/adm/obj/simul_efun.lpc——两者路径不一致。这导致feature/move.lpc里remove()的安全检查(校验previous_object()是否等于SIMUL_EFUN_OB)对每一次通过destruct()触发的物件摧毁都会失败,具体表现为:每一个新玩家 退出游戏(quit)都会失败——因为quit的自动丢弃背包逻辑会摧毁 任何不值钱的物品,而新角色出生就带着一件不值钱的布衣。这个 bug 很 隐蔽:连接看起来打印了一个被拦截的运行时错误然后就断开了,但实际 上角色仍然停留在游戏世界里,连线从未真正关闭。已将宏指向真正被 使用的文件(这和之前某个 lib 里securityd.lpc/securd.lpc两份 文件的陷阱是同一种教训——即使宏名字看起来"显然正确",也要用config.fluffos或实际调用链去验证它到底指向哪个文件)。 adm/daemons/logind.lpc:make_body()里的seteuid(getuid())会 把create()刚设置好的 euid 重置为空字符串,已改为显式seteuid(ROOT_UID)。check_legal_name():沿用旧版 GBK 字节长度界,已改为按字符数 (1-6)+ 逐字符判断。adm/daemons/securityd.lpc:valid_write()的save_object分支 比较file参数时忘记驱动会附加存档扩展名,已修复为file == qsf || file == qsf + 扩展名。- 一处真正损坏的留言板存档(
data/board/kedian_b.o某条留言的作者 字段里混入了原始的、非 UTF-8 的 GBK 字节),导致进入那个房间就必 然崩溃look。尝试过按 GBK 部分重新解码,但剩下的字节不足以安全 完整地修复,最终选择直接删除这个损坏的存档文件,而不是冒险做局部 字节级修补。
管理员账号 / Admin account
- id:
fluffos - 密码 / password:
Mud@2026 - 权限 / level:
(admin)
管理员名单存储在纯文本文件 adm/etc/wizlist 里。
警告:这是一个公开的默认密码,仅供本地/浏览器试玩。正式对外开服前
请务必修改此密码。
在线试玩
https://mudlibs.fluffos.info/xkxlb/
本地运行
cd libs/xkxlb
~/src/fluffos/build-debug/src/driver config.fluffos游戏端口:40202。
NOTES · 移植与修复记录
WASM 修复摘要(迁移自 meta.json 的 group_note)
从一个扩展名错误的 .rar(实际是带有 ../ 成员路径的 POSIX tar)提取;启动靠 /adm/single/master(树里还打包了一份未使用的 adm/obj/master.lpc,碰巧和 jyqxc/fy2mg/xkx2017 框架家族字节相同,但不是真正被加载的那份);启动干净,零修复。完整 WASM 修复:给 band.lpc 加了本地回环放行;修复了 logind.lpc 的 make_body() 里 seteuid(getuid()) 把 euid 重置掉的 bug;修复了 check_legal_name() 过时的 GBK 字节长度界限;给 securityd.lpc 的 get_status() 加上了防御性保护;修复了 securityd.lpc 的 valid_write() 里经典的 §7.49 存档扩展名不匹配 bug。最大的发现:include/globals.h 里的 SIMUL_EFUN_OB 指向一份过时、未使用的 /adm/single/simul_efun.lpc(早期重构留下的死代码副本,虽然在树里但没有被 config.fluffos 的"simulated efun file"设定引用),而不是 config.fluffos 真正加载、定义了 destruct() 覆写的那份真正的 /adm/obj/simul_efun.lpc。这破坏了 feature/move.lpc 的 remove() 安全检查(它会核对 previous_object() 是否等于 SIMUL_EFUN_OB)——每一次经由那个覆写路由的物件销毁都会失败——具体表现为:每一个新玩家的 quit 都会失败,因为 quit 的自动丢弃背包逻辑会销毁任何不值钱的丢弃道具(每个新角色出生就带着一件)。这个 bug 很隐蔽:连线会打印一个被捕获的运行时错误、看起来像是断开了,但角色其实仍然在线,世界那一侧的连线从未真正关闭。已把宏指向真正的档案来修复(和之前某个 lib 里 securityd.lpc/securd.lpc 重复档案陷阱是同一种直觉——哪怕宏名字看起来"显然正确",也要用 config.fluffos/真实调用链去验证它到底指向哪个文件)。另外修复了一份真正损坏的留言板存档(data/board/kedian_b.o 的某条留言作者字段里有原始的非 UTF-8 GBK 字节,导致每次在那个房间 look 都崩溃)——直接删除了这份损坏的存档档案,而不是冒险做局部字节级重新编码。管理员账号通过纯文本的 adm/etc/wizlist 档案播种。注册流程到进入游戏世界、look/score、以及一次正确完成的 quit 都已干净验证——建议在任何共享这种 SIMUL_EFUN_OB/重复 simul_efun 档案形态的档案上都专门重新测试一下 quit。
§7.86 跨库扫描修复(留言板 post 崩溃)
BULLETIN_BOARDinherit+ 多余replace_program()致命形状(AGENTS.md §7.86,post命令崩溃):全档案 18 处命中,已删除多余的replace_program(...)调用(保留inherit),逐文件保留原有行尾格式(CRLF/LF 按文件原样)。本次为跨库 §7.86 扫描修复(触发原因:该 bug 已在 6+ 个互不相关的血统家族独立确认,属于近乎普遍的拷贝粘贴模式),仅做编译检查(驱动干净启动、端口正常监听),未做完整 §10.7 深度游玩测试。
深度功能测试(2026-08-13,round two,新驱动重测)
针对驱动升级(quest_times/win_times %-operator 修复 + Warning/warning
大小写回退兼容)做的重测,同时也是这份档案第一次真正的 §10.7 深
度游玩测试(此前只做过 WASM 阶段的注册流程验证)。
发现并修复的 PROGRAMMING bug
1. log_error()(adm/single/master.lpc,实际生效的 master
file)完全没有严重度检查(AGENTS.md §7.34-class):已加上
strsrch(message, "arning:") == -1 判断。
2. log_file()(adm/simul_efun/file.lpc)完全没有
assure_file() 保护(AGENTS.md §7.11-class):已加上前向声明
+ assure_file(LOG_DIR + file);。
3. §8.9 食物/饮水初始化判断的对象错了:adm/daemons/
logind.lpc 的 enter_world() 里 !user->query("food") &&
!user->query("water") && ob->query("age") == 14 判断的
ob->query("age") 拿的是登录阶段用完即弃的连线桩物件,永远没有
age 这个属性,条件恒为假,每个新角色食物/饮水永远初始化成
0。改成 user->query("age") == 14。live 测试确认:修复前注册
score 食物/饮水两栏全空(□□□),修复后重连(这个判断在
enter_world() 里每次登录都会重新求值,只要 food/water 仍
是 0 就会补发)同一账号立即变满格(■■■)。
Proactive checks(无需改动)
win_times的%-operator 修复确认存在且正确:d/city2/npc/refereew.lpc:176、u/wind/refereew.lpc:176、u/wind/refereew2.lpc:184均已用to_int(query("win_times")) % N。feature/dbase.lpc未发现 tybxjh/wlhd 那种密码写保护,不适用。- 留言板存档括号计数怀疑(未采取行动):用简单的方括号/圆括号 配对启发式扫描全部
data/board/*.o,bonze_b、gaibang_b、gaibang_r、huashan_b、shaolin_b、taohua_b、towiz_b、wiz_b、wudang_b、xiaoy_b、xueshan_b共 11 份显示括号不配 对(kedian_b.o那份真正确认损坏的存档 WASM 阶段已经删除)。这 个启发式本身不可靠(留言内容里出现的普通括号标点也会误报),本 轮完整注册/look/score/重连流程没有触发任何一份的restore_object()报错,debug.log全程干净,没有实际证据证明 这些是真损坏(不像xkx2017那批,有确认的存档头缺失+live 崩溃 复现)。按"没有真实复现就不动"的纪律,本轮未删除任何一份,留给 以后如果真的踩到崩溃再处理。
实测过程
管理员 fluffos/Mud@2026(adm/etc/wizlist 早已播种,但从未真
正注册过)用完整注册流程创建,落地"客店",score 显示"【天神】"
头衔。随后单独一步做了真实断线重连+密码验证:用刚设的密码重
新连线成功登录(顺带验证了 #3 的食物/饮水修复对已存在账号的自愈效
果)。全程 debug.log 无运行时错误。驱动按精确 PID 结束;管理员
存档已提交。
§7.100 扫描修复(ROOM 基类多余 replace_program())
#define ROOM "/inherit/room/room":删除 791 处多余的、独立成行的
replace_program(ROOM);(保留 inherit ROOM;),与 jqxz2008/
jyqxc/xiakexing3 系列同一血统同一形状。clone/misc/
roommaker.lpc 同样有两套模板——"造一间空房间"的 heredoc 本来干
净,"克隆我所在的房间"命令的字符串拼接模板把同一枚多余的
replace_program(ROOM); 烤进了每一个新克隆的房间,已同步修正。已
用 build-debug 驱动干净启动验证(0 个新增编译错误,端口正常监
听);未做完整 §10.7 深度游玩测试。
§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.
深度功能测试(2026-09-01,round three,首次真正完整的 §10.7 深度游玩测试)
本轮之前,本档案唯一挂名"深度功能测试"的那一节实际只覆盖了注册/重
连和三个孤立 bug 修复的验证(见上面 2026-08-13 那节自己在末尾承认的
"此前只做过 WASM 阶段的注册流程验证",且更早的 §7.86 扫描修复也明确
写着"未做完整 §10.7 深度游玩测试")。本轮用一个全新角色(云飞扬 /
yunfeiyang)从零走完注册 → 移动 → 留言板 → 战斗 → 死亡/复活 → 拜师
的完整流程,是这份档案第一次真正的全流程 §10.7 测试。
发现并修复的 PROGRAMMING bug:3 份存档级损坏的留言板
2026-08-13 那轮曾用方括号配对启发式扫描出 11 份"疑似"损坏的留言 板存档,但因为没有真实复现,按"没有真实复现就不动"的纪律未采取行 动。本轮实际走到了其中两处并当场触发了真实崩溃,另一处经静态字节 分析确认是同一 bug 类:
1. /clone/board/gaibang_b(丐帮弟子留言板,/d/city/pomiao 土地
庙):玩家第一次真正走到这个房间(经 dongmen→ml1..ml7 迷宫
路径)时,restore_object(): Invalid utf8 string while restoring
dbase 从 bboard.lpc 的 setup()→restore() 未捕获地抛出,
整个 go(进房间)命令失败,玩家被弹回上一个房间。字节级检查确
认 data/board/gaibang_b.o 与 raw/xkx/data/board/gaibang_b.o
完全字节一致(不是本项目引入的新损坏),整份文件是从未转码过
的原始 GBK(gb18030 可以干净、完整地解码,也没有真正的
\r\n 需要按引号感知规则折叠——文件里的换行全部是这份存档格式
自带的裸 \r)。用与 AGENTS.md 里 fy2/fy2qh 那次相同的手法
修复:整份文件按 gb18030 解码、重新编码为 UTF-8。live 验证:
修复后重进该房间干净,read 1 能正确显示全部 5 条历史留言(含
一处这类老式存档里常见的、原本就存在于归档里的终端转义符残留
[A[A,原样保留未改动)。
2. /clone/board/towiz_b(玩家意见留言板,/d/wizard/guest_room,
武庙西北竹门内):同样的 Invalid utf8 string 崩溃,经
open door → northwest 触发。但这份文件的损坏比 gaibang_b 更
深一层,不是单纯未转码:字节级排查发现内容中间夹杂着大量原始
ANSI 光标控制码(\x1b[D/\x1b[C——某个上古年代客户端在编辑留
言、按方向键时被原样录了进去),其中一段控制码恰好插在一个双字
节 GBK 字符的中间,把后面所有字符的双字节对齐全部冲散——
gb18030/gbk/big5 全部无法完整解码整份文件,是真正字节级
丢字节式的损坏,不是编码判断错误、也无法靠换编码挽救。按本档案
早先处理 kedian_b.o(WASM 阶段,同样"不可恢复、宁可直接删除
也不冒险做局部字节修补")的先例,直接删除了这份存档。踩坑一
次:只删了明文 towiz_b.o,重启驱动后同一个崩溃原样重现——
原来 FluffOS 的 restore_object() 在明文 .o 不存在时会自动透
明回退读取同名 .o.gz(这份存档恰好还留着一份 gzip 压缩备份
towiz_b.o.gz,内容是同一份损坏数据),只删 .o 不删 .o.gz
等于什么也没修。补删 .o.gz 后重启驱动再测,房间干净加载,留
言板显示"没有任何留言"(预期中的空板)。
3. /clone/board/taohua_b(桃花岛弟子留言板,/d/taohua/dating):
未做现场复现(该房间需要额外的地图/渡海路线,超出本轮时间
预算),但静态字节分析确认了与 towiz_b 完全相同性质的损坏:对
比同一条留言里 title 字段与 msg 字段本应相同的前缀,可以看
到 msg 字段中途缺失了至少一个字节,导致其后所有双字节 GBK 配
对全部错位,gb18030/gbk/big5 均无法完整解码。该文件与
raw/ 归档原件字节级一致(非本项目引入),触发机制
(restore_object() 遇到无效 UTF-8 时未捕获地抛出运行时错误)
已经在另外两份文件上现场验证过两次,判定为同一 bug 类的第三个
实例,直接应用了同样的"删除不可恢复存档"补救(这份没有 .gz
备份需要额外处理)。
其余 8 份此前被方括号启发式误报的留言板(bonze_b、huashan_b、
shaolin_b、wiz_b、wudang_b、xiaoy_b、xueshan_b、
gaibang_r)经直接 UTF-8 有效性检查全部确认是假警报——本身就是
合法 UTF-8,之前的方括号计数启发式只是被留言正文里的普通括号标点
误导,未发现新问题,未做任何改动。至此,2026-08-13 那轮遗留的"11
份疑似损坏留言板"这个悬而未决的问题彻底关闭:3 份真损坏(已修
复),8 份假警报(确认无恙)。
验证过但确认无需修复(AGENTS.md §7.117 / §7.19)
cmds/skill/bai.lpc的一处括号错位(AGENTS.md §7.117 "sj" 同款 形状):(string)me->query("family/master_id" == "feng qingyang")一行里==先于query()求值,等价于调用query(0),如果真的走到这条分支会在feature/dbase.lpc的strsrch(prop, '/')里因参数类型错误崩溃。但现场验证(用两个真 实测试角色yunfeiyang/chengfeng:yunfeiyang对已在场的chengfeng执行recruit chengfeng,再让chengfeng执行bai yunfeiyang)证实这条分支在本档案里彻底不可达:bai.lpc自己在更早处就有if (userp(ob)) return notify_fail("现在不能拜玩家为师了。\n");, 玩家之间互相拜师被无条件挡住;这条括号错位的分支只有当师父是 NPC 时才可能触发,而 NPC 自动收徒(attempt_apprentice()→command("recruit ..."))走的是recruit.lpc自己那条已经正 确加了me->query("family") &&首次收徒判空守卫的完成分支 (文件里 1995 年的注释 "fix a bug in 1st time recruit" 就是证 据),根本不会让bai.lpc里那条括号错位的分支执行到。确认为 死代码,按"只修真实可触发的 bug"纪律未改动。- §7.19 reentrancy 模式:全档案搜索所有
void/int init() { ... }函数体,没有一处调用setup()/enable_player()/enable_commands();唯一的enable_player()调用点在inherit/char/char.lpc的setup()(由create()触发,属于合 法的一次性调用),没有从init()被间接触发的路径。确认本档案 不受影响。
实测过程
全新账号 yunfeiyang(中文名"云飞扬")走完注册流程,落地"客
店",score/look 正常。在客店留言板 post 了一条测试留言,随
后 read 1 正确读回。经北大街→中央广场,主动 kill liumang(命中
的是"流氓头",武功比新手玩家强得多),真实打到力竭、半昏迷、最
终"你死了",【谣言】 死亡广播正常。死亡后被送进"鬼门关",
d/death/npc/wgargoyle.lpc 的白无常走的是自动 5 阶段
call_out("death_stage", 5, ...) 对话链(不是 d/death/inn1.lpc
那条需要玩家主动 ask <自己> about 回家 的隐藏彩蛋路线——两条路都
存在,但真正的默认复活机制是白无常这条),约 25 秒后自动
reincarnate() 并把玩家扔到 REVIVE_ROOM(武庙),score 显示
"潜能"从 99 掉到 50(正确的死亡惩罚),称号重置为"平民"。随后走
完北大街→中央广场→东大街→东门→(青竹林迷宫)→土地庙的完整路
线,对丐帮九袋长老"鲁有脚"执行 bai lu,一次性被收为"丐帮第十
九代弟子",score 正确显示新门派与师父。全程只在两处地图上第一
次探索到的留言板房间触发过运行时错误(已修复,见上),其余移动/
战斗/死亡/复活/拜师全程 debug.log 干净。驱动按精确 PID 结束并重
启验证过一次(确认两处崩溃彻底消失;唯一一次"删了 .o 还是崩"的
意外是漏删了 towiz_b.o.gz 压缩回退文件,补删后重启复测干净)。
深度功能测试(§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)— tail() simul_efun
scripts/lpc_add_tail.py --apply: cmds/wiz/tail.lpc calls tail(file), an efun of the MudOS this archive ran on that FluffOS does not have (Undefined function tail: the command did not compile). adm/simul_efun/file.lpc now defines void tail(string file): the last 10 lines of the file, written to the player. Load check (HEAD against the working tree): 1 of the 1 tail command file(s) failed to load at HEAD, all load now, and the simul_efun file loads. KB 04 §6.2.
深度功能测试(§10.7,2026-10-05)— 房间列出的物件缺档时房间照常加载
房间基类 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-05)— 巫师留言板存档 data/board/*.o.gz
巫师留言板 wiz_b / towiz_b 以 .o.gz 存档(1996 年的帖子)。本机驱动 restore_object() 优先读 .o.gz,而留言板用 save_object(file) 写明文 .o,所以本机上新帖每次重启都退回旧快照;网页版驱动没有 zlib,只读 .o,而归档自带的 .o 是读不出的二进制。本库原有的明文 wiz_b.o 是更新的 22 条(1996-06 起),保留;.gz 里较早的 47 条(1996-02 起)转成 UTF-8 存为 wiz_b.bak,不被载入但保留下来。删除 .o.gz(KB 01)。用 lpcc 载入留言板核对条数(jqxz2008:wiz_b 47 条、towiz_b 115 条)。
深度功能测试(§10.7,2026-10-06)— 白驼山掌门欧阳锋编译不过
d/baituo/ouyangfeng.lpc 有两处笔误,整个 NPC 从未编译成功:greeting() 里 write("你是谁?我要杀了你!哈 ̄哈 ̄哈 ̄") break; 缺分号,inquiry_map() 里 object me = this - player();(应为 this_player())。白驼山派的掌门因此不存在,拜师、问路(inquiry_map)都无从谈起。两处改正后,新进程里 HEAD 加载失败、工作树加载成功。同一文件在 14 个 xkx 系的库里一字不差。
深度功能测试(§10.7,2026-10-07)— 空的 if (current_water == 0) {}
3 个房间的 valid_leave() 里有一行什么也不做的 if (current_water == 0) {}(编译警告 Expression has no side effects),删去,行为不变:d/xingxiu/nanjiang2.lpc、d/xingxiu/nanjiang3.lpc、d/xingxiu/shanjiao.lpc。
深度功能测试(§10.7,2026-10-07)— 兵器的 actions 函数指针
set("actions", (: WEAPON_D, "query_action" :));:旧 MudOS 把 (: 字符串, "函数" :) 当作 call_other 函数指针,本驱动把它当作表达式函数指针,求值只得到字符串 "query_action"。没有对应兵器技能时 feature/attack.lpc 直接用兵器的 actions,COMBAT_D 拿到的不是 mapping,reset_action() 后仍不是,记一条 bad action 就不出招——拿着这些兵器打不出攻击。改成别的兵器早已用的 (: call_other, WEAPON_D, "query_action" :)(KB 04 §6.10):inherit/weapon/throwing.lpc、inherit/weapon/fork.lpc、inherit/weapon/whip.lpc、inherit/weapon/sword.lpc、inherit/weapon/weapon.lpc、inherit/weapon/axe.lpc、等共 10 个。改动的文件在 HEAD 与工作树分别加载(新进程),无回退。
深度功能测试(§10.7,2026-10-07)— 编译警告整理
scripts/lpc_warnings.py xkxlb --fix 加 scripts/lpc_fix_no_effect.py --apply,共改动 217 个 .lpc 和 8 个 .h(多为删去未用的局部变量)。HEAD 与工作树分别加载(新进程):200 -> 200 通过,无回退;改过的头文件的 36 个包含者 34 -> 34 通过。启动时警告 13 -> 0;新进程登录(输入名字)正常。
- 2026-10-10:编译警告第二轮(按驱动报告逐条修):按位 & 改逻辑运算 0 处,返回类型/原型 13 处,NPC+F_UNIQUE 的 init() 0 个,带初始化的未用局部变量 1 个,只在 #if 分支用的声明移进分支 0 个文件;改动 11 个文件,HEAD 与工作树各载入一次无回退(11 objects; HEAD PASS 11, tree PASS 11; regress 0; newly loading 0),这些文件的警告 13 -> 0。
- 2026-10-10(续):第二轮编译警告整理(
lpc_fix_unused_init.py)删掉了只在不启用的#if分支里用到的局部变量声明(如include/net/ftpdsupp.h中#ifdef GUEST_WIZARD_FTP分支的file),启用该选项时会编译失败;声明已放回所用的分支里,工具已改为跳过这种情况(交给lpc_move_decl.py)。
编译警告收尾(2026-10-12)
scripts/toolkit_fix.sh 一轮(冗余继承 34 处)后,用 scripts/lpc_twin_port.py adopt xiakexing3 xkxlb --pre fa4f24186c2~1 搬来孪生库 xiakexing3 同日的修法(kungfu/skill/hubo.lpc 写明 skill::clean_up(),include/net/ftpdconf.h 改定义 VALID_READ/VALID_WRITE 前 #undef),再删去 kungfu/skill/dugu-jiujian.lpc、huashan-jianfa.lpc 招式表后面多余的一行 ;,能编译的文件警告清零。改动的 36 个对象 HEAD 与工作树各载入一次:HEAD PASS 29,tree PASS 32,regress 0。新载入的 3 个是明教 d/mingjiao/npc/yinwufu、yinwulu、yinwushou:基类已有 F_UNIQUE,叶子再继承一次触发 Illegal to redefine 'nomask' function 'violate_unique',从前载不进来。
- 2026-10-14:新驱动(FluffOS 970d9f09)报
Float value truncated to int(#1426)。3 个文件 3 处:赋值、初始化、return 改写成to_int(...)(值不变,只是写明截断)。改动的对象新进程各载入一次,无回退(scripts/lpc_fix_float_trunc.py,KB 04 §6.10)。 - 2026-10-14:1 个存档文件(留言板 1 个;
data/board/tiandi_b.o)还是原档案的 GBK 编码,没有转成 UTF-8,restore_object()报Invalid utf8 string后对象以空数据启动(表情守护进程没有表情、留言板没有帖子、玩家无法载入)。scripts/lpc_save_encoding.py逐个按 GB18030 解码,结果按存档格式解析通过才写回(KB 03 §4)。
- 2026-10-14:2 个文件用了颜色宏(
HIW、NOR)却没有#include <ansi.h>(首个错误syntax error, unexpected L_STRING);开头补上(KB 04 §6.1、§6.3)。新进程比对 HEAD 与工作树:5 个对象,新增载入 4,回退 0。
无门派玩家的 family 映射(2026-10-15,KB 05 §7.30 第三种)
mapping fam = ob->query("family"); 之后直接 fam["family_name"]:没有门派(新人或叛师后)的玩家在学习、练功、拜师、进入门派房间时报 Value being indexed is zero,而不是作者写好的提示。4 处在声明行加上 if (!mapp(fam)) fam = ([ ]);(scripts/lpc_fix_family_guard.py)。
其他体系的属性名(2026-10-15,KB 06 §7.241 第三类,--any-file)
另有 3 个文件(绝招、状态、物品、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,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。6 处补上 if (!mapp(fam)) fam = ([ ]);(刚 recruit_apprentice() 之后的除外)。
技能名拼错(2026-10-15,KB 06 §7.249)
query_skill() 里的技能名拼错了,或用的是本库改名前的旧名;本库没有这个技能,调用永远得 0:门槛(< N 就拒绝)永远过不去,相关功夫或绝招学不了、用不了;内功互斥(> N 就拒绝)从不生效;公式里这一项一直是 0。经汉字名(提示文字或中文名词典)或纯拼写差异(_/-、少一个连字符、相邻字母颠倒)核对后,改为本库的技能名(scripts/lpc_fix_skill_typo.py):beimin-shengong→beiming-shengong(jiuyang-shengong、liumai-shenjian、taiji-shengong);mizongxinfa→mizong-xinfa(longxiang/fanchang)。
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,而不是得到拒绝。7 处(6 个文件)改为 dbase 路径查询 query("family/master_name"):有门派时值相同,没有时得 0;原有的判断照常生效(scripts/lpc_fix_family_index.py)。给映射赋值的写法未动。
NPC 带着本库没有的物品,载入失败(2026-10-15,KB 06 §7.73)
11 个文件、15 处在 create() 里 carry_object("<本库没有的文件>")->wear()(或 wield()、set_amount()):carry_object() 得 0,接着的调用报 Bad argument 1 to EFUN call_other(),NPC 根本载入不了,该有它的房间里就少了这个人。多是从别的系统搬来的 NPC 用了原系统的物品路径(最常见:/d/xiaoyao/npc/obj/cloth、/d/xiaoyao/npc/obj/blade、/d/city/obj/tudao)。每处改为 { object carried_ob = carry_object(...); if (carried_ob) carried_ob->wear(); }(scripts/lpc_guard_carry_object.py):NPC 照常出现,只是不带这件东西;文件补回来(或是虚拟对象)照样会带上。载入检查:改动的文件改前能载入 0 个,改后 11 个(11 个原来载入不了),没有退步。
去掉的预定义宏 SAVE_EXTENSION(2026-10-18,KB 04 §6.11)
老版 MudOS 给每个 LPC 对象预先定义了 SAVE_EXTENSION(".o");FluffOS 的 ChangeLog(COMPAT_BUSTER 一条)把它删了,改用 __SAVE_EXTENSION__。本库没有自己 #define 这个宏,用到它的文件一律 Undefined variable 'SAVE_EXTENSION',整个对象载入不了。改成 __SAVE_EXTENSION__(scripts/lpc_fix_predefined_macro.py):adm/daemons/network/netmail.lpc、clone/npc/meng-zhu.lpc、cmds/arch/purge.lpc、cmds/usr/suicide.lpc、d/quanzhou/npc/tang.lpc、d/quanzhou/npc/tang3.lpc、d/taishan/tang3.lpc、include/net/ftpdsupp.h。tang3/tang/meng-zhu 是武林盟主一类的 NPC,原来一个都载入不了;suicide 是自杀指令;purge 是清除玩家档案的巫师指令;netmail 是网络邮件守护进程(本库缺 mailer.h 等头文件,改后仍载入不了)。改后用 lpcc 逐个载入这些对象:6 个通过,1 个还有别的错误(adm/daemons/network/netmail:/adm/daemons/network/netmail.lpc:17: error: Cannot #include mailer.h)。
水潭里 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/obj/shuitan.lpc。改后用 lpcc 逐个载入这些对象:1 个通过。
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 载入不了,刷出它的房间也少一个人。本库有 1 个对象设了本库没有文件的武功(4 个名字,最多的是 xiake-force、xiake-strike、xiake-steps)。三处都改成 return:这一门武功不给、不映射,对象照常载入,只是少了它(缺的武功本身仍是内容缺口)。抽样载入这些对象:1 个里 0 个通过,其余 1 个停在别的错误上(kungfu/class/xiake/master:*No program in object '/kungfu/class/xiake/master'!)。(scripts/lpc_guard_set_skill.py)
通向不存在房间的出口,按对面房间的回头出口改正(2026-10-18,KB 06 §7.257)
房间出口 "west": __DIR__"xxx" 指向的文件本库没有,玩家走过去就被卡住(笔误、改过名的房间,或者没带进档案的编号房间)。对面的房间存在、并且它相反方向的出口正好指回这个房间,说明出口原本就是通向它:/d/emei/duguangtai 的 north:huazangzn → huazangan;/d/emei/jietuopo 的 west:guanyitang → guanyintang;/d/emei/jiulaodong 的 northeast:jiudaoguai4 → jidaoguai4;/d/mingjiao/jmqshulin6 的 west:jmqjiguan → jmqshenmu。改动后每个出口都能解析到本库的文件(scripts/lpc_fix_dead_exits.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 映射不到,门派弟子用普通轻功/拳脚)。按核对过的对照表改正,共 4 处、3 个文件:xinxiu-duzhang→xingxiu-duzhang(2 处)、tiaji-jian→taiji-jian(2 处)。(scripts/lpc_fix_skill_names.py)
set_name 的 id 参数传成字符串(2026-10-19,KB 06 §7.260)
set_name("海口大碗", "bowl"); 把物品的 id 写成了字符串,本库的 set_name(string name, string *id) 要的是数组,驱动在编译时报 Bad type for argument 2 of set_name ( string * vs string ),整个物件载入不了;旧驱动不检查参数类型,字符串里照样找得到这个词,物品能用 id 称呼。改成 ({ "bowl" }),共 2 个文件:/d/baituo/npc/obj/bowl.lpc、/d/baituo/obj/bowl.lpc。(scripts/lpc_fix_set_name_id.py)
laozhe 的 command("give yancao to", me)(2026-10-19,KB 06 §7.266)
d/heimuya/npc/laozhe.lpc(黑木崖的老者)的 init() 里写着 command("give yancao to", me);,command() 只收一个字符串,驱动报 Too many arguments to 'command',整个 NPC 载入不了。照 cctx、fys 等库已经改好的写法,改成 command("give yancao to " + ob->query("id"));(ob 是刚进房间的玩家)。
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 文件。
玩家打造兵器模板没有打造者时(2026-10-19,KB 06 §7.275)
/d/npc/m_weapon/weapon/m_blade.lpc、/d/npc/m_weapon/weapon/m_club.lpc、/d/npc/m_weapon/weapon/m_staff.lpc、/d/npc/m_weapon/weapon/m_sword.lpc、/d/npc/m_weapon/weapon/m_whip.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)
转换时丢掉的分号、逗号、引号或文件末尾的 },共 1 个文件,修前 HEAD 载入失败。别的库里同路径的完好副本只比这里少几个标点,按它补回(括号里是那个库):/d/city2/npc/zhengmen.lpc(jqxz2008)。修后与 HEAD 逐个对比载入:这 1 个物件全部载入,没有退步(scripts/lpc_restore_from_twin.py、lpc_fix_eaten_quote.py --comma、lpc_fix_eof_braces.py)。
旧驱动的类型宽松:缺省参数、无类型形参、数组初始化、class 变量(2026-10-19,KB 04 §6.19、§6.20)
原来的 MudOS 把调用少传的参数补 0、把没写类型的形参当 mixed、不检查变量的声明类型与初始值,也允许变量叫 class;这个驱动在编译时全部拒绝,整个物件载入失败。修了 1 个文件:/d/heimuya/ren.lpc(scripts/lpc_round_files.py 的修复轮:调用处补写 0、无类型形参补 mixed、string X = ({...}) 补星号、void 函数的返回值,以及 class 变量改名 pick_class)。逐个文件在 HEAD 和改后载入对比:这些文件里 1 个原来载入失败、现在载入,没有退步。
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 处)。
行编辑器指令编译失败:(: this_object(), ({ "do_to", me, arg }) :)(2026-10-20,KB 06 §7.284)
Illegal to use local variable in functional.:call_other 形式的函数指针 (: ob, ({ "函数", 参数 }) :) 的数组里只能是常量,写了局部变量 me / arg 整个指令就编译不过,to 这类先开编辑器、再回调自己的指令因此从未能用。改成 (: call_other, this_object(), "do_to", me, arg :)(参数在建立指针时绑定,编辑器再把输入的文字接在最后,do_to(me, arg, text) 收到全文;scripts/lpc_fix_functional_locals.py)。改动:/cmds/usr/to.lpc(1 处)、/cmds/wiz/to.lpc(1 处)。
call_out_info() 的每一项只有 3 个元素(2026-10-20,KB 06 §7.287)
驱动返回的是 ({ 物件, 函数, 延迟 }),不带 call_out 的参数,旧代码读第 4 项 info[i][3](callouts 指令、calloutd、cod 工具)一读就报 Array index out of bounds,指令从第一行起什么也打印不出来。改为 (sizeof(info[i]) > 3 ? info[i][3] : 0)(scripts/lpc_fix_callout_info.py)。改动:/cmds/arch/callouts.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)。
sefun cat():缺文件时 write(0) 报错(2026-10-20,KB 06 §7.297)
void cat(string file) { write(read_file(file)); }:文件不存在(压缩包没带的欢迎/公告文件,或只有运行中的 mud 才会写的日志)时 read_file() 回 0,write(0) 在本驱动里报 Bad argument 1 to receive(),调用者(登录对话、cat 指令)被中断;老驱动什么也不打印。改成 write(read_file(file) || "");(scripts/lpc_fix_cat_unchecked.py)。改动:/adm/simul_efun/file.lpc。
翻页器 start_more(read_file(...)):文件缺失时 explode(0)(2026-10-20,KB 06 §7.300)
东方故事系的翻页器 void start_more(string msg) { ... explode(msg, "\n") ... } 被这样调用:start_more(read_file(HELP_DIR + "help/topics"))、start_more(read_file(NEWS))。压缩包没带的文件使 read_file() 回 0,explode(0, ...) 在本驱动里报 Bad argument 1 to explode()(不带参数的 help 指令就是这样出错的),老驱动把 0 当空文本。在 start_more 开头加了 if (!stringp(msg)) return;(scripts/lpc_fix_start_more.py)。改动:/feature/more.lpc。
存档里的乱码文件:restore_object() 报 Illegal file format(2026-10-20,KB 06 §7.316)
存档里有一批数据文件是乱码:开头是 ?adm、?inh、?clo、?obj(#/adm/… 的第一个字节被换成了 ?),后面是随机字节,没有任何驱动读得了。adm/daemons/chinesed 在预载时 restore() 读 data/e2c_dict.o,首次登录时起始房间的留言板 /clone/board/kedian_b 读 data/board/*_b.o;restore_object() 对不是文本的文件抛 Illegal file format,调用处的 catch()(KB 06 §7.255)保住了房间和精灵,但本库 master 的 error_handler() 把调用栈返回给驱动,每次启动和首次登录都在控制台打印一次或两次 错误讯息被拦截。现在共用的 feature/save.lpc 的 restore() 先读文件第一个字节,不是 # 就返回 0(读被 master 拒绝时 read_bytes() 返回 0,仍由 restore_object() 决定,和以前一样);留言板和字典从空开始,第一次 save() 写出合法文件,乱码文件原样留在树里。实测:启动和登录都没有报错,已保存的角色重新连线照常加载。
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 个文件)。
存档里的 .c 文件名改成 .lpc(2026-10-21,KB 03 §4.2 第 9 项)
存档里写着 "/d/city/npc/wei.c" 这样的文件名;extract 时源文件已经全部改成 .lpc,而驱动对带扩展名的路径只认字面,new() / load_object() / move() 都找不到它,调用方多半把失败当成「没有这个东西」悄悄跳过。本库 3 个存档共 6 处按 scripts/lpc_fix_save_dotc.py 改成 .lpc(只改 .lpc 存在而 .c 不存在的字符串;玩家存档、备份、留言板、巫师目录和文件索引缓存不动)。改动:/d/shaolin/npc/obj/kat.o(1 处)、/d/shaolin/obj/kat.o(1 处)、/d/shenlong/obj/lxlx.o(4 处)(共 3 个存档)。
巫师命令不带参数时对 0 调用 efun(2026-10-21,KB 06 §7.336)
巫师(管理员)把命令敲成不带参数时,驱动把 0 传给字符串参数;下面的命令第一句就把这个 0 交给 efun,运行时报 Bad argument 1 to ...,这条指令从来没有用过。用 scripts/lpcc_bare.py 不登录、在一次 lpcc 求值里以 0 调用 main() 逐个确认后,由 scripts/lpc_fix_bare_arg.py 在第一处使用参数的语句前加守卫:文件自带 int help(object me) 的,守卫是 if (!arg) return help(me);(help() 定义在 main() 之后的 1 个文件补了原型 int help(object me);,否则编译报 Undefined function help)。改动(1 个文件,括号里是接住 0 的 efun):/cmds/wiz/test.lpc(present)。加载检查 HEAD 与工作树对照,没有退步。
blockade / recover:data/keep 不存在,解封之后世界仍然锁着(2026-10-21,KB 06 §7.340)
管理员扫描里 blockade 报 Error copying file from /data/user/f/fluffos.o to /data/keep/fluffos, Error: No such file or directory,随后的 recover 在第一个 cp() 上死于 */data/keep/fluffos: lstat failed,来不及执行最后的 LOGIN_D->set_madlock(0):封锁解不开。data/keep/ 是运行时目录,git 克隆里没有空目录。blockade 在第一次写之前 if (file_size("/data/keep") != -2) mkdir("/data/keep");(mkdir() 失败答 0,不抛错),recover 对没有保存档的玩家 if (file_size(src) < 0) continue;,其余照常恢复、照常解锁(scripts/lpc_fix_keep_dir.py,hy5 上实测:没有保存档时 recover 答“时空解封完毕”,blockade 建出 data/keep 并保存,recover 取回并删除)。改动(2 个文件):/cmds/adm/recover.lpc、/cmds/arch/blockade.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.,同一个动词的其他处理函数不再尝试(不是最新的一条就悄悄跳过)。删除了 1 条注册(1 个文件,scripts/lpc_fix_dead_add_action.py),动词留给别的处理函数:/inherit/misc/fboard.lpc(do_list)。最多的函数名: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.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 个函数没有补(inquiry 1):原型还在函数体丢了、或者根本没写过,没有可以直接补回的捐赠(别的库同一路径的文件里没有这个函数,或者它还要用本库没有的辅助函数、签名不同),不编造:/d/huashan/npc/teller.lpc:tell_fortune。
运行期目录 log/nosave 不存在,写日志的 write_file() 直接报错(2026-10-22,KB 03 §4.3 补充)
这个库的 11 个文件里有 16 处 write_file("/log/nosave/...") / log_file("nosave/...")(static 改 nosave 时连字符串里的日志路径一起改了,原来是 log/static/):nosave/CRASHES、nosave/CALL_PLAYER、nosave/PURGE 等。压缩包和站点包里没有这个目录,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 的新进程):补目录前报上面的错误,补后写成功。
(: 函数名 :) 指针指向本库没有的函数:只含这个指针的行加了注释(2026-10-22,KB 06 §7.355 补充)
inquiry / item_desc / chat_msg* 里的 (: 函数名 :) 指向本对象(含包含文件、继承的父类)没有函数体的函数:用到时(ask、look、NPC 闲聊)驱动抛 *Undefined lfun pointer called: 函数名,这一拍心跳的后半段被跳过。这些函数没有可以补回的来源(别的库同一路径的文件里没有,或者它还要用本库没有的东西),所以 1 个文件里 1 行只含这个指针的行("算命": (: tell_fortune :),)加了注释,原文保留并写明原因,这一项当作没有这个话题 / 物品 / 闲聊条目(scripts/lpc_fix_dangling_lfun.py;#include 的文件在库里缺失的对象、指针不在整行上的写法没动)。 前提(function_exists())和加载检查(HEAD 与工作区对比,本库改动的 .lpc 文件)的结果见 KB 06 §7.355:没有一个回归。
汉字按字节切片的老写法没有换成按字符:改法名 "澄" + name[2..3]、辈分判断 name[0..1] == "澄" 等 17 处(2026-10-22,KB 06 §7.360)
原档按字节算字符串区间(一个汉字 2 字节):name[2..3] 是名字的第二个字,name[0..1] == "澄" 问名字是不是以「澄」开头。转成 UTF-8 之后,这个驱动的区间和 strlen() 都按字符算(strlen("澄观") 是 2,"澄观"[0..1] 是两个字),老算术原样留着、意思全变:拜入少林 / 武当 / 峨嵋等派的玩家被改成错误的法名(二字名 张三 变成一个字的 澄,更长的名字取到第三个字);各派掌门的辈分判断(name[0..1] == "澄")永远不成立。
本库 17 处(12 个文件):拼名字的赋值 9 处、与汉字常量比较 8 处。例:name[2..3] → name[1..1](/kungfu/class/shaolin/cheng.h:156);name[0..1] → name[0..0](/kungfu/class/shaolin/qing-fa.lpc:104);name[0..1] == "慧" → name[0..0] == "慧"(/kungfu/class/shaolin/cheng.h:140)。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,不要重跑。
黑木崖脚下的老者:init() 里留着调试语句,每个走进 /d/heimuya/road1 的人都触发运行时错误(2026-10-22,KB 06 §7.361)
d/heimuya/npc/laozhe.lpc 的 init() 在 ::init() 之后有 what = new(__DIR__ "obj/yancao"); sprintf("%s aaa\n", what);:调试遗留,%s 收字符串或数字、不收对象,于是 (s)printf(): Incorrect argument to type %s. (arg: 0) 每次有人进入乱石坡都抛一次,后面的 call_out("greeting", ...) 永远不执行,老者不再搭话(还每次白克隆一个烟草)。两行都注释掉(同系的 haiyang2 / hy / hy5 / cctx / fqyy2 早就注释了)。证明:scripts/lpc_reach_census.py xiakexing2017 --load --walk(一个普通 NPC 访客走进每个加载成功的房间):HEAD 336/337,改后 337/337。
血条 / 表情标题按字节算显示宽度(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(一格两个空格)。本库 4 处(2 个文件)。证明(lpcc_eval.py hhsj):tribar_graph(6,9,12) 在 HEAD 画出整条 12 个■,改后为 6 个■+3 个□;麻将 strlen(tempB)/2 是两字符牌码,未改。
jmqshenmu 截断 init(2026-10-27,KB 04 §6.25 Also)
d/mingjiao/jmqshenmu 在 void init() { 处文件结束。补上 } 使房间可加载(本库未收齐 climb/jmqdating 时不做内容补写)。证明:HEAD 失败;改后加载。
深度功能测试(2026-10-27,§6.25 one-arg message_vision)
message_vision("…") 补第二参(me / TP / this_player())。