info.html · 介绍 · play.html · 游玩 · llms.txt · 下载与本地运行 · ZIP · GitHub
ES2/Annihilator 系架构衍生的武侠 mudlib,"泥潭"系列的一支,共 13000+ 个 `.lpc` 文件,属性存储代码为独立编写、并非与 nt6/nt1 分支同源。同样设有"出生仪式"关卡(`d/register/` 区域,`regroom.lpc` 等文件名甚至和 nt6/nt6nitan6win 完全相同),但具体文案与实现各自独立——直接比对内容可确认不是同一份代码,而是"泥潭"系里多个团队各自独立开发出的相近设计范式,地图规模也和 nt6 系相近。
English
A wuxia mudlib built on the ES2/Annihilator engine lineage, part of the broader 'Mire' (nitan/NT) family but with its own independently written attribute-storage code. At roughly 13,000 source files, it has its own version of the 'birth ceremony' registration ritual seen in nt6, right down to matching file names, an interesting case of convergent design within the same broader engine scene despite being coded independently.
README
本次修复的关键 bug
1. 经典 §8.1 GBK 字节区间 is_chinese() 判断错误,而且是独
立复现的(不是 nt6 那种同源共享代码,是不同代码库各自写出了
同一类问题):
- adm/simul_efun/chinese.lpc 的 is_chinese() 用字节区间判
断(str[i] < 161、str[0] < 176 之类),已改成正确的码点
区间检查。
- logind.lpc 的 get_surname()/get_name() 用
check_legal_name(arg, 4),但提示语写的是"不要超过两个汉
字"——4 是没有减半的旧字节数上限,改成 2;姓名组合起来的
检查 strlen(fname) < 4 同理改成 < 2。
- named.lpc 的 invalid_new_name() 用 strlen(name) < 2 判
断"是否为空名字",会把任何单字给名(比如"风")都当空名字拒
绝,改成 < 1。
2. §1.3e uptime() < 30 启动宽限期检查:logind.lpc 的
logon() 一开始就会挡掉这个检查,而 WASM 沙箱每次连线都紧接
在驱动启动之后,必然触发。已对 127.0.0.1(本地/WASM 测试连
线)放行。
3. §7.52 socket 精灵编译失败,这份档案里有两个:
- adm/daemons/network/dns_master.lpc:小型专用 daemon,直接
整个清空 socket 相关函数。
- adm/daemons/versiond.lpc:大型多功能"版本同步发布"精
灵,有 32 处其他档案调用它的非 socket 功能(is_version_ok()/
query() 等),不能整个禁用;只清空了里面含
socket_create/socket_bind/socket_accept/socket_write/
socket_close 等呼叫的 13 个函数/回调,其余公开接口原样保留。
4. §7.50 accept_kill() 的 is_killing() 参数类型错误:
user.lpc 的 accept_kill(object ob) 直接把物件传给
is_killing(),但这个函数要的是字符串 id——和这个档案里其他呼
叫点用的 ob->query("id") 不一致,导致整个 clone/user/user
编译失败(角色创建的 make_body() 依赖这个档案)。这是本项目
里已经在 nt1/wxddym/zjmudhell/hell 独立复现过四次的同一类
copy-paste bug,改成 is_killing(ob->query("id")) 即可。
内容亮点
内容与出生仪式详见上方简介;is_killing() 参数类型不匹配这一类
bug 在本项目里已经独立出现过五次(nt1/wxddym/zjmudhell/
hell,加上这份档案),是同一种复制粘贴笔误在完全不同代码库间反
复出现的典型案例。
注册流程
选择编码 GB 或 BIG5 → 英文名字(3-10 个英文字母)→ 确认建立新角 色(y/n)→ 中文姓氏(1-2 个汉字,可留空)→ 中文名字(1-2 个汉 字,姓名合计至少 2 个汉字)→ 管理密码(至少 5 位)→ 确认管理密码 → 普通密码(至少 3 位,不能和管理密码相同)→ 确认普通密码 → 性别 (m/f)→ 进入游戏世界。
真正的"score"要求角色先完成一段在 /d/register/ 区域和创世神话
NPC 对话的"出生仪式"才会被标记为"已出生",和 nt6/nt6nitan6win 是
同一类设计,不是 bug,本次验证范围内没有走完整这段剧情。
管理员账号 / Admin account
- id:
fluffos - 密码 / password:
AdminPass1(管理密码)/loginpw1(普通 密码,双密码机制) - 权限 / level:
(admin)
管理员身份通过正常注册流程创建,注册完成后已确认自动落在巫师专属 的"巫师休息室",验证了权限判定正确生效。
警告:这是一个公开的默认密码,仅供本地/浏览器试玩。正式对外开服前
请务必修改此密码。
本地运行
cd libs/nte
~/src/fluffos/build-debug/src/driver config.fluffos游戏端口:40115。
NOTES · 移植与修复记录
WASM 修复摘要(迁移自 meta.json 的 group_note)
泥潭二——一个和 nt6/nitan 不同的 ES2/Annihilator 衍生血统(feature/dbase.lpc 自己已经有完整的双参数 set/query/delete 架构,没有 §7.15 那个 bug)。WASM 修复:(1)经典的 §8.1 GBK 字节区间 is_chinese() bug(生效的那份和一份注释掉的死代码副本都用字节区间判断;已把生效的那份换成码点检查)加上两处独立反复出现的长度界限没减半变体——logind.lpc 的 check_legal_name(arg, 4)(应为 2,对应它自己"不超过两个汉字"的提示)在 2 处呼叫点、它的姓名合并检查 strlen(fname) < 4(应为 < 2)、以及 named.lpc 的 invalid_new_name() 里 strlen(name) < 2(应为 < 1,会把任何单字给名当成"空名字"拒绝)。(2)logind.lpc 的 logon() 里 §1.3e 的 uptime()<30 闸门——对本地回环放行。(3)在两个各自独立的精灵上做了 §7.52 socket 精灵掏空:dns_master.lpc(小型、单一用途,整个掏空)和 versiond.lpc(大型多用途的版本同步精灵,它的 is_version_ok()/query() 等非 socket 函式有 32 个外部呼叫者——只掏空了 13 个碰 socket 的函式/回呼,按既定的"大型多用途精灵"方针保留了其余公开接口)。(4)user.lpc 的 accept_kill() 里 §7.50 的 is_killing(ob) 物件/字符串不匹配——和 nt1/wxddym/zjmudhell/hell 上看到的同一个反复出现的复制粘贴 bug。通过 adm/etc/wizlist 把 fluffos/AdminPass1+loginpw1(双密码机制)播种为管理员,确认注册后被带到巫师专属起始房间。完整的注册→look→quit(包括 quit 的新账号删除确认)流程在排版格式化前后都验证过;格式化工具没有引入任何损坏(三类盲点检查都干净——两处大 diff 分别是 versiond.lpc 自己的掏空和 combatd.lpc 合法的 if-else-if 伤害讯息阶梯合并,不是损坏)。和 nt6/nt6nitan6win 相同的、游戏内"完成出生仪式对话之前不算出生"的内容关卡会影响刚注册角色的 score——不是 bug,不在本轮范围内。
§7.86 跨库扫描修复(留言板 post 崩溃)
BULLETIN_BOARDinherit+ 多余replace_program()致命形状(AGENTS.md §7.86,post命令崩溃):全档案 55 处命中,已删除多余的replace_program(...)调用(保留inherit),逐文件保留原有行尾格式(CRLF/LF 按文件原样)。本次为跨库 §7.86 扫描修复(触发原因:该 bug 已在 6+ 个互不相关的血统家族独立确认,属于近乎普遍的拷贝粘贴模式),仅做编译检查(驱动干净启动、端口正常监听),未做完整 §10.7 深度游玩测试。
2026-08-12 深度功能测试 / Deep functional test (AGENTS.md §10.7)
这是这份档案第一次真正的 §10.7 round-two 完整游玩测试(此前只有上面的 WASM 注册验证和 §7.86 跨库编译扫描,均未做过完整游玩)。nte 和 ntii(泥潭 II)共享同一套基础设施档案家族(§7.42/§7.81 记录的"content NPC named master.c"自动检测陷阱,两者互为近亲),本轮逐一验证 ntii 那份 §10.7 记录 的四类 bug 是否在 nte 上独立复现——全部确认复现,逐一修复,详见下文。
DB_SAVE 检查:include/ntsql.h 第 9/13 行定义了 DB_SAVE 1/
AUTO_SAVE 1,和 ntii 完全相同的假阳性——这个驱动构建没有编译进任何 SQL
后端,db_connect()/db_set_player()/db_query_player() 优雅降级为 0,
TX_SAVE 文字档存档照常工作,不是 nitan170911 式的硬依赖,不需要本地
MySQL 基础设施。
驱动升级 + 干净启动
用新编译的 ~/src/fluffos/build-debug/src/driver 启动
(cd libs/nte && ~/src/fluffos/build-debug/src/driver config.fluffos,
端口 40115)。第一次干净启动就命中了和 ntii 完全相同的 message() 4 参数
错误洪流(见下文第 1 条),先修复四类 bug 后再重新启动,确认
log/debug.log 干干净净:543 行(和 ntii 记录的"修复后同样的启动流程仅
543 行"逐字吻合,进一步印证两份档案这批基础设施档案确实逐字节共享),零
Bad argument/couldn't find object/级联错误,端口正常监听。本轮共启动
驱动 3 次(每次修复后重新验证一次干净启动,含最后为拾取手动修复的
adm/etc/wizlist 而做的第三次重启,见下文)。
to_int() 任务计数器修复验证:一次性测试对象直接复现
会话上文诊断出的生产崩溃(killer->query("questXX_times") % 500 在拿到
损坏成 float 的属性值时因 % 运算符拒绝 float 左操作数而崩溃)复核确认
to_int(...) % 500 的正确形状已经存在于:adm/daemons/combatd.lpc(第
2476/2547/2619 行)、cmds/std/whisper.lpc(第 185/190/195/200 行)、
kungfu/class/ultra/{dugu,huang,kuihua,shenni}.lpc(各自的 quest_count
计算行)——全部已经是修复后的形状,无需改动。
拜师门派 NPC(独孤求败/黄裳/魁花/南海神尼)都在扬州新手区以外的深山,预算
内不现实,改用一次性测试对象直接复现同一个表达式形状:adm/daemons/
qftest.lpc(临时脚手架,测试完已删除,git status 确认未残留):
mapping bad_data = (["k": 97467776479476432.000000]);
mixed bad = bad_data["k"];用巫师账号 fluffos 的 update 指令触发 create():
- 修复前形状(
bad % 500):执行时段错误:*Bad argument 1 to % Expected: int Got: 97467776479476432.000000.——与生产崩溃报告的错误文 本逐字一致。 - 修复后形状(
to_int(bad) % 500):create()把结果写入/qftest_result.log:test_fix returned: 432,独立验证int(97467776479476432.0) % 500 == 432。
结论:to_int() 修复针对确切的报告故障条件被直接验证有效——目标性复现
(targeted repro),不是靠一次真实完整任务达成。
ntii 血统四类候选 bug:全部独立复现,逐一修复
1. adm/simul_efun/message.lpc 的 message() 包装函式非 varargs:
diff 确认修复前和 ntii 修复前的版本逐字节相同。第一次干净启动就在注册
期间狂刷"Bad argument 4 to EFUN message() Expected: object, array, Got:
int(0)."。修复(第 315-317 行):
``lpc
varargs void message(mixed arg, string message, mixed target, mixed exclude) {
efun::message(arg, message, target, exclude || ({}));
}
`
修复后重启验证:干净启动,零 Bad argument` 错误。
2. inherit/misc/quest.lpc 的 set_information() 把第二参数声明为
string,QUEST_D->set_information() 本身已经正确接受 mixed:
clone/quest/{search,capture,shen,supply,defend,deliver,judge,trace,
explore}.lpc 九个任务档案全部用闭包 (: ask_xxx :) 呼叫,被这个过窄
的本地包装函式硬性拒绝,编译错误"Bad type for argument 2 of
set_information ( string vs function )",随机任务生成子系统从这份档案
第一次编译起就完全瘫痪,无启动期崩溃症状(AGENTS.md §7.81 已有先例,
本次是 nitan 血统家族内的第二个独立确认实例,紧接着 ntii)。修复
(第 111 行):string info → mixed info。现场验证:修复后用
fluffos 账号 update /adm/daemons/eventd 时,紧接着的心跳周期里就
看到"【系统报告】任务精灵:进程(DELIVER)利用布料创建了一个任务。"这
类此前从未出现过的系统报告消息;后续测试过程中陆续见到 SEARCH/TRACE/
CAPTURE/JUDGE 等多个进程的任务创建报告——随机任务系统第一次真正开始
运作。
3. adm/single/master.lpc 的 log_error() 无条件把编译诊断(含纯
warning)转发给 this_player()(AGENTS.md §7.103 已有先例):新注
册流程期间,/include/globals.h:4 的"Unknown #pragma, ignored."
warning 在每一个被懒编译的档案上都原样刷屏给刚注册的新玩家,带着吓人
的"编译时段错误:"前缀。修复(第 184-189 行):加
strsrch(message, "warning:") == -1 守卫,纯 warning 不再转发给玩家
(仍写入 log 档案),真正的 error 转发行为不变。
4. str[0..<N] 后缀切片 off-by-(N-1) 错误(AGENTS.md §7.80 已有先
例):全档案定点核对 ntii 记录的 7 处命中位置,逐一确认同样命中:
adm/daemons/eventd.lpc 第 22 行、adm/daemons/storyd.lpc 第 50 行
(get_dir(*.lpc) 结果用 [0..<3] 剥离扩展名,只剥掉 2 个字符而不是
4 个)、adm/npc/luban.lpc 第 1431/2573 行、cmds/wiz/mem1.lpc 第
80 行、cmds/adm/refsum.lpc 第 37/43 行。全部改成 [0..<5]。验
证:fluffos 账号 update /adm/daemons/eventd//storyd 均"重新编
译...成功!",/luban//mem1//refsum 三个也确认编译通过。
新发现的第五类 bug:force_quit() 无确认静默删除新账号(本轮实测踩中,非猜测)
cmds/usr/quit.lpc 的 force_quit()(由 clone/user/user.lpc 的
net_dead()→user_dump(DUMP_NET_DEAD) 在断线 NET_DEAD_TIMEOUT
=900 秒/15 分钟后自动呼叫)对"在线时长不满 30 分钟"(mud_age < 1800)
的账号无条件 UPDATE_D->remove_user() 删除,完全没有交互式 quit 路径
(cmds/usr/quit.lpc 第 51-56 行 + confirm())要求的"y/n 确认"。
这不是代码审查猜出来的,是本轮测试真实踩中的:第一个测试角色"秦云舒"
(nteqingxue)走完了注册/性格/天赋/投胎/新手礼物/安全切磋/拜师两条路径
后,因为每次 mudclient.py 调用都开一条新连线、测试间隔用 --timeout 让
连线自然断开而非显式 quit,多次这样的断线累计超过 15 分钟净空窗口、而
角色的真实在线时长(mud_age)始终没攒够 30 分钟——于是在某次测试之间,
data/login/n/、data/user/n/ 下这个角色的存档被静默、完整地删除了,没
有任何警告,也没有走过交互式 quit 那句"退出该游戏将删除你的账号,你确定
要放弃该帐号而退出吗?(y/n)"的确认(我们对这个提示始终选择的是 n,即
明确拒绝删除)。这直接违反了 §10.1 验证栏要求的"reconnect 验证状态"前提
——账号本身都不在了。
对照交互式路径(cmds/usr/quit.lpc confirm()):选 n 只会打印"您选择
了放弃退出(quit),继续游戏。",完全不会删除,也不会真的断线——新账号如果
不想被删,交互路径下唯一的办法是"不要真的 quit"。force_quit() 本该是
"玩家事实上已经不在了(真断线超时),系统代为收尾"的兜底路径,却把这个场
景直接等同于交互式确认过的"y",在完全没有征得同意(甚至没有机会征得同
意——此时根本没有真人在线可以回答)的情况下执行了相同的破坏性操作。这不
是"内容/设计判断"(真正的交互式确认机制清楚地表明设计意图是"要问过玩家",
force_quit() 只是漏掉了这个安全阀),判定为程序 bug,修复:
// cmds/usr/quit.lpc 第 178-182 行(修复前)
if (me->query("mud_age") < 1800 && !me->query("jieti")) {
UPDATE_D->remove_user(me->query("id"));
return 1;
}
me->save();删除整个无确认删除分支,直接落入下面已有的安全 save() + move(VOID_OB)
+ destruct() 收尾路径(和"账号 ≥30 分钟"账号走的是同一条安全收尾逻辑,
只是不再对"账号 <30 分钟"这个子集特殊处理成删除)。
现场验证:注册全新测试账号 fqverify(验证,mud_age=0),用巫师账
号直接呼叫 ob->user_dump(1)(DUMP_NET_DEAD,和真实 15 分钟断线超时触
发的完全同一条代码路径:user_dump()→command("quit") 失败后
→QUIT_CMD->force_quit()),修复前这个调用会经由
UPDATE_D->remove_user() 删除 data/login/f/fqverify.o、
data/user/f/fqverify.o 两个存档;修复后再次执行同样的调用,两个存档文
件依然存在(用 ls 直接确认)。测试完删除了 adm/daemons/fqtest.lpc 这
个一次性验证脚手架和 fqtest_result.log。
AGENTS.md 新 bug class 候选:这类"交互路径有确认,自动/超时收尾路径 复用同一段销毁逻辑却跳过确认"的模式,很可能不止 nte/ntii 这一个血统会有 (任何带"新账号断线锁定/删除"策略、且实现了 netdead 自动收尾的 ES2 系血 统都值得一查)——本轮时间有限,未去 sibling 档案里逐一排查,留给下一轮或 sibling 命中时再确认是否要提升为正式 §7.x 条目。
完整游玩测试
第一个角色 秦云霞→秦云舒(nteqingxue)(因为上一段记录的 bug,此角
色在测试过程中途被静默删除,下方记录的所有交互结果本身仍然真实有效——问
题只出在"角色事后消失了",不是"交互当时就有问题"):register 邮箱 →
choose 均衡型 → select 光明磊落 → wash(先天天赋 19/24/18/19)→
born 扬州人氏,全程零编译错误落地客店,look/score 均输出正确。武庙
南贤处 ask nan about gift 拿到开站礼物,fen 悟性 4 后 score 确认悟
性 24→28(真实数值变化)。
- 安全切磋机制:南大街(
/d/city/nandajie1)的"流氓头" (attitude: peaceful)接受切磋,fight liu完整走完拳脚交替的回合序 列,气血/精神耗尽后角色正确触发"看来该找机会逃跑了..."自动脱战逃入相 邻房间,全程无崩溃——和 ntii 记录的结论完全一致(同一个 NPC、同一个 房间、同一段判定逻辑)。 - 拜师/门派——两条路径都测了:organic 路径对"流氓头"(无
family属性)正确报错"流氓头既不属於任何门派,也没有开山立派,不能拜师。", 不崩溃;admin 捷径路径用巫师账号fluffos(goto传送到"流氓头"身 边)执行copyskill liu,成功触发复制效果("凌霄口中念念有词,只见 一道红光笼罩了你和流氓头。")。真正拥有family的门派 NPC 都在远离 新手区的深山,预算内未能走到。 - quit 保留窗口:
mud_age/在线时长不满 30 分钟,quit触发"退出该 游戏将删除你的账号,你确定要放弃该帐号而退出吗?"——选择n保留账 号,即时反馈"您选择了放弃退出(quit),继续游戏。",交互路径本身没有问 题(问题出在上面记录的force_quit()非交互兜底路径)。 tmux_mud.sh的 CJK 传输损坏再次命中(非 bug,AGENTS.md §10.2 已 有前例,和 ntii 记录的几乎一模一样):choose 均衡型通过tmux_mud.sh发送后,本地 telnet 客户端掉进自己的telnet>命令提示 符("衡型"/"?Invalid command"),后续同样的choose 均衡型命令重发 也再次触发。改用scripts/mudclient.py(原始 socket,无本地 telnet/pty)在新连线上重发完全相同的输入序列一次成功,且全程用mudclient.py走完了注册到出生的完整仪式,验证了这确实是本地 telnet CLI 的传输层问题,不是is_chinese()或注册逻辑的 bug。
第二个角色 德标(dbgtestx):注册 → choose 均衡型 → select
光明磊落 → wash(先天天赋 膂力24/悟性21/根骨17/身法18)→ born
扬州人氏,全程零编译错误落地客店,look/score 正确。这个角色专门
用来补做"quit/reconnect 隔一段真实时间"这一项(避免重蹈"秦云舒"的覆
辙——本次测试前已经修好了 force_quit(),但为保险起见仍然选择"显式
save + 断线,不主动 quit"的路径):save 后("档案储存完毕。")断
开连线,用 Monitor/后台等待了 80 秒真实墙钟时间(远小于 15 分钟
netdead 阈值,但足以验证真实断线重连,不是同一进程内的状态残留),重新
连线走了完整登录流程("这个角色已经存在,请输入该角色的密码" → 密码验
证 → 正常登入,非静默重连),look/score 显示的房间与数值(膂力
24/悟性 21/根骨 17/身法 18)与断线前完全一致——确认标准的存档/重连路径
本身没有问题。全程 debug.log 复核:除了下面记录的两处已知/自愈的噪音
外没有新的 Bad argument/couldn't find object/级联错误。
管理员账号种子
fluffos(凌霄)/普通密码 Mud@2026、管理密码 Admin@2026,(admin)
权限已由既有 adm/etc/wizlist 条目(第 11 行 fluffos (admin),来自更
早一轮 WASM 验证时播种的记录)授予——但该条目此前从未有对应的原生存档
(data/login/f/、data/user/f/ 都不存在),本轮走正常注册流程种下。
- 密码字段未持久化(和 ntii 记录的完全同一个现象):注册流程走完 性别选择、正常落地巫师休息室之后,
clone/user/login.lpc的密码字段 (password/ad_password)没有被写入data/login/f/fluffos.o(只有purename/surname/id/body等字段),具体根因未深挖。按 §1.5 建 议的"编辑存档数据而不是 code"方案处理:用驱动自己的crypt()efun (不是外部工具算出来再猜)——写一个一次性脚手架adm/daemons/ pwtest.lpc,create()里呼叫crypt("Mud@2026", "$1$fluffos1$")/crypt("Admin@2026", "$1$fluffos2$")并把结果写到日志档案,再把这两 个真实由驱动算出的哈希直接写入data/login/f/fluffos.o的password/ad_password字段。验证:fluffos/Mud@2026登录成功 ("重新连线完毕"),update指令确认写 ACL 真实可用。测试完删除了pwtest.lpc。 wizlist条目在测试过程中途丢失(未完全查明根因,记录为观察 项):update指令某一刻突然全部返回"什么?"(未识别指令),排查发现adm/etc/wizlist里fluffos (admin)那一行不见了(securityd.lpc只在驱动启动时读取一次WIZLIST建立内存态wiz_status,之后任何set_status()调用都会用内存态整体重写这个文件——如果内存态在某个时 点丢失了fluffos这一条,随后任何人触发的一次set_status()都会把 这次"丢失"写实到磁盘)。怀疑和更早一次"用错误密码登录导致destruct(ob)"的失败尝试有关(有一次在密码字段还没修好之前尝试登录fluffos触发了密码错误!断线),但没有在代码里定位到确切的 "登录失败→撤销 wizlist 权限"的因果链,未在 code 层面动手,只是手动把fluffos (admin)那一行重新加回adm/etc/wizlist,重启驱动令securityd.lpc重新读取生效(验证:update恢复正常)。留给以后需要 时再深挖确切根因。goto后跨驱动重启环境异常:巫师账号用goto /d/city/nandajie1离开巫师休息室后,save/quit不会自动写入startroom(startroom只在valid_startroom的房间里由save命令主动写入,goto本身不 设置),驱动重启后重新连线,环境变成"你的四周灰蒙蒙地一片,什么也没 有。"(environment(me)为 0,之前触发过一次update的present(file, environment(me))传参 0 报"Bad argument 2 to present()")。手动goto /d/wizard/wizard_room后自愈,纯粹是巫师测 试工具使用习惯问题(goto到非valid_startroom房间后没有存盘), 不影响任何真实玩家路径,未修改代码。
未修复的观察项
AUTO_SAVE宏定义了(include/ntsql.h第 13 行)但全档案没有任何 地方真的检查这个宏或据此设置周期性存档,master.lpc也没有shutdown()apply 在驱动优雅关闭时统一存档所有在线玩家:和 ntii 记 录的完全同一个观察,未验证是否本轮又实测命中(本轮驱动重启前均已显式save/未挂起真实进度),只是确认这份档案本身也缺这套保障,留给以后 评估。- 心跳级冷启动开销:随机任务系统修复后同样触发了 AGENTS.md §10.8 记录的既有类别——
debug.log里出现约 34 处Eval interrupted/Too long evaluation(maximum evaluation cost700000,比 ntii 会话 中途被外部调高到 5000000 的那份低);均为懒编译大片地图触发的瞬时超 时,自愈(后续同一账号照常登入/存档),不是可以钉死到具体 file:line 的独立 bug,按 §10.8 惯例记录、未修。 help newbie内容与实际注册流程不符(水笙/decide/桃源四出口 vs 实际的盘古/choose/select/wash/born):和 ntii 记录的完全同一个 内容/文档过时问题,不是程序 bug,未修改。
本轮结论
这是 nte 第一次真正的 §10.7 round-two 完整游玩测试。驱动升级后逐一核对
了 ntii 那份 §10.7 记录的四类 bug(message() 4 参数、set_information()
类型收窄、log_error() 警告泄露、str[0..<N] 切片 off-by),全部独立
确认在 nte 上复现,逐一用相同的最小改动修复并现场验证(含随机任务系统
修复后现场看到任务精灵开始正常产生任务)。to_int() 任务计数器修复复核
确认已在生产诊断点亮的三个文件里正确落地,并用一次性测试对象做了目标性
复现验证。额外独立发现并修复了第五类 bug:force_quit()(netdead 超
时自动收尾路径)无确认静默删除 <30 分钟账号,本轮测试自己的第一个角色
"秦云舒"就是真实受害者,修复后用 user_dump(1) 直接复现验证存档不再被删
除。完整走通了注册→性格选择→天赋分配→投胎→新手礼物→安全切磋→拜师
(organic 失败路径 + admin 捷径成功路径)→显式 save+真实断线 80 秒 + 重
连持久化(第二个角色)的连续会话。整体信心:高——核心系统(注册、任务奖
励防崩溃、随机任务生成、战斗、拜师两条路径、断线重连持久化、巫师权限)均
已验证正常,五类 bug 全部修复并现场验证,唯一遗留的是需要更大范围基础设
施改动(周期性存档、地图冷启动开销)或属于内容/设计判断(help newbie
过时文本、goto 后未设 startroom)而未动手的观察项,均已诚实记录。
AGENTS.md §7.100 修复(2026-08-19,批次五)
ROOM 基类冗余 replace_program(ROOM); 自崩溃地雷(详见 AGENTS.md
§7.100):3252 个房间文件的 create() 里紧跟 inherit ROOM; 之后
都有这一行多余调用,永久设下"待替换"标记,第一次对该房间对象绑
定闭包就会崩溃。自带建房工具 clone/misc/roommaker.lpc 的字符串
拼接代码生成模板里也烤了同一个地雷。
修复:脚本化删除所有房间文件里独立成行的 replace_program(ROOM);,
加上 roommaker.lpc 里手动摘除字符串拼接片段。git diff --stat:
3252 files changed,与预期精确吻合(85 处仍存在的匹配全部是既有
注释,未改动)。
验证:build-debug 驱动真实冷启动,端口 40115 正常监听,
debug.log 全程干净。既有管理员账号 fluffos/Mud@2026 登录正常
(巫师休息室/巫师会客室多房间走访 down/up),quit 干净退出,全程
无新增 "cannot replace"/"cannot bind" 日志行。
``§7.112`` residual-gap closure (2026-08-20)
Corpus re-scan (grep -rl 'call_out("death_stage"' ... | filter for missing guard) found unguarded init()-scheduled death_stage() call_out chain(s) in d/death/npc/bai.lpc, d/death/npc/hei.lpc that the original two-wave sweep (see AGENTS.md §7.112) missed -- same reconnect-triggered duplicate-chain bug, different filename/lineage. Added the standard query_temp("death_stage_active")/set_temp/delete_temp re-entry guard, adapted per file's own exit points. Compile-verified via lpcc --batch.
§7.30 uninitialized-mapping accessor sweep (2026-08-20)
Corpus-wide mechanical sweep of the feature/skill.lpc shared-lineage
bug (confirmed independently on xiakexing2017/jqxz2015/haiyang2
via round-four testing): 5 accessor(s) in this file returned a raw
never-initialized mapping instance variable (defaults to int 0,
not ([]), until first assigned), crashing any unguarded
keys()/sizeof()/indexing caller for a fresh/untrained character.
Fixed at the accessor level (mapp(x) ? x : ([])) per the documented
remedy. Verified via lpcc --batch static compile check only (not a
live boot) as part of a large mechanical sweep; not individually
functionally re-tested live on this lib.
2026-08-21 深度功能测试 / Deep functional test round-four (AGENTS.md §10.7)
本轮补做上一轮 round-two 测试预算内没走到的三项真实游玩:真实战斗
死亡/复活、真实商店购物、真实拜师门派(非 copyskill 捷径)。用既
有巫师账号 fluffos(密码见上文,未变)和新注册的测试角色
nteqzco(秦紫辰,密码已设置,此处不重复记录明文)。
第六类 bug:adm/simul_efun/file.lpc 的 log_file() 未加
assure_file() 守卫(AGENTS.md §7.11 实例)
本轮测试真实踩中,不是猜测。 为准备商店购物测试,巫师账号
clone /clone/money/gold 时直接崩出一段执行时段错误:
执行时段错误:*Wrong permissions for opening file /log/nosave/clone for append.
"No such file or directory"
物件:/adm/single/simul_efun
呼叫来自:/cmds/wiz/clone.lpc 的 main() 第 76 行
呼叫来自:/adm/single/simul_efun.lpc 的 log_file() 第 13 行adm/simul_efun/file.lpc 的 log_file()(第 11-14 行)直接
write_file(LOG_DIR + file, text),完全没有目录守卫,而它自己的
assure_file() 帮助函式(第 16-38 行)就定义在正下方,却从未被呼
叫——AGENTS.md §7.11 已经记录过至少 6 个互不相关血统的同一拷贝粘
贴形状(xajhxo/zjmudhell/ldtx/jyqxc2013fwq 等)。归档从未
带上 /log/nosave/ 目录(.gitignore 里 libs/*/work/log/ 整棵
子树都不追踪,纯属驱动运行期产物),所以任何触发 log_file() 的操
作(clone 指令的审计记录只是第一个撞上的)都会抛出未捕获错误。
修复(第 11-15 行):
void assure_file(string file);
void log_file(string file, string text) {
seteuid(ROOT_UID);
assure_file(LOG_DIR + file);
write_file(LOG_DIR + file, text);
}验证:干净重启驱动(debug.log 543 行基线不变),巫师账号
clone /clone/money/gold 不再报错,正常显示"黄金复制成功,放在你
的物品栏。"。已提交(commit 4041d1f9ccb)并推送。
观察项,本轮未确认/未修:同一 write_file(..., 1)(覆写模式,
AGENTS.md §7.11 记录过这个变体是硬抛错而不是优雅返回 0)硬编码形
状还出现在 d/city2/npc/liu.lpc、d/city2/song/obj/{bingfu,
lingjian}.lpc、adm/daemons/ward.lpc,全部写入
/quest/quest_jun/song/... 系列路径——work/quest/quest_jun/song/
目录在这份归档里确实不存在(ls 确认)。这是「宋朝守城/军粮」支线
任务(d/city2 是另一个城区,不在扬州新手区),本轮未实际触发(未
走到那条任务线),按项目一贯纪律不做未经现场复现的预防性修复,留
给以后走到 city2 那条任务线时再确认/修。toptend.lpc 的排行榜
写入路径(AGENTS.md §7.11 举过的另一个实例)本档案 data/topten/
五个文件已经存在,未受影响。
真实战斗 → 死亡 → 复活(非安全切磋)
流氓头(南大街 /d/city/nandajie1)只支持非致命切磋——真正会死人的目
标是"财主大门"(/d/city/caizhu)的两只"大狼狗"(wolfdog.lpc):
attitude: peaceful 但 init() 里对任何进入房间的 interactive 玩家无
条件排 call_out("kill_ob", 1, ob),真正会主动扑上来,且 cmds/std/
kill.lpc 对 NPC 目标确认没有任何安全闸门(和本次会话其余 10+ 个已确认
的同类库一致)——kill wolf 直接开打,不问玩家意愿。
先用巫师账号 fluffos 亲身撞了一次(未预期,属于真实巧合):goto
到财主大门后,大狼狗自动发起攻击,fluffos 战斗数值偏低(管理员身份不
等于战斗强度),几个回合后被真实打死——完整死亡文本链("你的眼前一黑"→
"你扑在地上挣扎了几下,腿一伸,口中喷出几口鲜血,死了!")→ 正确传送到
死亡结界"鬼门关"(/d/death/gate)。因为 fluffos 是巫师,d/death/
npc/bai.lpc/hei.lpc(本档案自己上面 §7.112 补丁刚修过的那两个文件)
的 init() 都显式跳过巫师(wizardp(previous_object()) 为真时直接
return),巫师复活改走另一对专门给巫师用的 NPC
(wgargoyle.lpc/bgargoyle.lpc,条件相反,只在 wizardp 为真时触
发)——核对后发现这两个档案在全档案任何房间的 objects 映射里都从未
被引用,是死代码(grep -rn 全档案确认),巫师死后事实上卡在死亡结
界里无法通过 NPC 触发复活(真正的出路是十殿阎罗 yanluo.lpc 的问答闯
关小游戏,或孟婆汤 mengpo.lpc 需要 combat_exp >= 1000000000 的巫师
专属高门槛,均为大型内容子系统,超出本轮验证范围,不影响任何真实玩家路
径,未改代码)。
改用新注册的普通测试角色 nteqzco 正式补做这项测试:走到财主大门
kill wolf,完整真实战斗回合序列(无安全脱战),气血耗尽后同样真实死
亡→传送鬼门关。这次角色不是巫师,bai.lpc(鬼门关的"白无常")的
init() 正常触发,death_stage() 五阶段对话(间隔 5 秒/次)现场逐条
观察完整跑完,这是本档案 §7.112 补丁(2026-08-20 才修的 bai.lpc/
hei.lpc 补丁)第一次被真实死亡流程实际触发——五个阶段每一个出口分
支都正确调用了 delete_temp("death_stage_active"),没有卡死或重入,
最终 ob->reincarnate() + 传送到 REVIVE_ROOM(武庙)成功落地,
score 确认状态正常。中途因为验证 §7.11 修复而重启过一次驱动,测试角
色当时刚好处于死亡对话流程中途,重连后存档位置卡在"鬼门关"→"酆都城
门"(重启前的存档时间点,clone/user/user.lpc 的 die() 在
::die() 后立刻 save(),但 death_stage() 复活时的位置变更本身不
会主动存盘)——这是我们自己驱动重启造成的测试假象,不是代码 bug(没有
任何错误讯号),继续沿死亡对话链往深处走,hei.lpc(酆都城门的"黑无
常")同一套五阶段对话也完整跑完,成功复活。全程 debug.log 复核干净,
零新增错误。
真实商店购物
用巫师 clone /clone/money/gold + give gold to nteqzco 的既定资助模
式(触发并修复了上面第六类 bug),给测试角色一两黄金(合一万文铜钱)。
到"醉仙楼"(/d/city/zuixianlou)"店小二"(xiaoer2.lpc,真实
F_DEALER/vendor_goods 商店)buy baozi:「你从店小二那里买下了一
个包子。」价格五十文铜板,购买后 i 确认找零正确(一万文 → 九十九两
白银 + 五十文铜钱 = 9950 文,换算无误),包子实物到手。全程无错误。
真实拜师门派(非 copyskill 捷径)
修正上一轮 NOTES 的一个不准确表述:"拜师门派 NPC 都在扬州新手区以
外的深山"——这只对"独孤求败/黄裳/魁花/南海神尼"这几个特定"7.90 到
to_int() 复现"顺手查过的名字成立,不是全局结论。实际上有一个真正可拜
(attempt_apprentice() 已实现、permit_recruit() 门槛很低)的门派招
募 NPC 就在新手区city范围内:丐帮的"空空儿"(kungfu/class/gaibang/
kongkong.lpc),固定放置在"丽春院"(/d/city/lichunyuan,南大街东
侧)。他的 attempt_apprentice() 只检查 permit_recruit()(未曾背
叛过丐帮、未同时拜过别的门派)——对全新角色直接通过,没有任何战斗力/声
望门槛(相比之下 kungfu/class/quanzhen/*.lpc、.../tangmen/tangfang.
lpc 等"全真七子"/"唐门"级别的招募 NPC 大多要求已有相当技能等级或声望,
更适合已入门玩家的"晋阶"而非"新手首次拜师")。
kongkong.lpc 会 random_move() 到处游荡,第一次到访扑空("你想拜谁
为师?"——他人不在场),追过去几个房间也没追上;后来发现自己的命令用
错了目标别名——set_name("空空儿", ({"kong kong", "beggar", "qi gai",
"kong"})),游戏内实际可用别名是"kong kong"(带空格)或"kong",不是我
最初尝试的无空格"kongkong"(纯属操作失误,不是 bug)。改用 bai
kong,且巫师顺手 clone 了几个额外的"空空儿"副本帮忙"钉"在房间里避
免再次扑空,最终 bai kong 成功:
你想要拜空空儿为师。
空空儿说道:好吧,希望小兄弟能好好学习本门武功,将来在江湖中闯出一番作为。
空空儿决定收你为弟子。
你跪了下来向空空儿恭恭敬敬地磕了四个响头,叫道:「师父!」
恭喜您成为丐帮的第二十代弟子。score 确认门派/师承字段真实写入:【门派】丐帮、【师承】空空儿、称号
"小叫化"/"丐帮第二十代传人"。全程无错误。
标准检查清单快速过一遍(§7.90/§7.100/§7.111/§7.112/§7.79/§7.108/§7.30 + 4 个已收尾的跨库 grep 模式)
全部干净,无新发现:
- §7.90:本档案上一轮已经记录过随机任务系统修复后的
Eval interrupted冷启动噪音类别,本轮未见新增独立实例。 - §7.100:全档案
grep -rn 'replace_program(ROOM)'只命中一处d/heimuya/dating2.txt(内容数据档案,非编译.lpc,不受影响)。 - §7.111:
adm/single/master.lpc的standard_trace()第 277 行 已经是error["object"] ? file_name(error["object"]) : "0"的守卫 形状,干净。 - §7.112:
d/death/npc/{bai,hei,wgargoyle,bgargoyle}.lpc四个档 案的death_stage()每个出口分支都正确清理重入守卫(详见上文真实死 亡测试现场验证bai.lpc/hei.lpc;wgargoyle.lpc/bgargoyle.lpc代码本身也干净但是全档案未引用的死代码,见上文)。 - §7.79:全档案没有任何裸 2 参数
addn(呼叫,本条不适用。 - §7.108:
clone/user/user.lpc的reconnect()第 397 行已经有enable_commands(),干净。 - §7.30:
feature/skill.lpc的 5 个 accessor 已经是 2026-08-20 当天早些时候的批次修复(mapp(x) ? x : ([])),干净。 - 四个已在别处全收尾的跨库模式:
combatd.lpc的bounce除零 (grep 无命中)、chacha.lpc(find无命中)、natured.lpc的!userp(ob[i])) destruct(ob[i])僵尸物件模式(grep 无命中)、go.lpc的sizeof(exit[arg])off-by-two(grep 无命中,现有形状 是正常的undefinedp(exit[arg])检查)——全部干净。
force_quit() 无确认删除 bug(上一轮第五类 bug)在 ntii 的核对结果:未复现,ntii 本身是安全的
按上一轮 NOTES 留下的"AGENTS.md 新 bug class 候选"去核对 sibling
ntii 的 cmds/usr/quit.lpc:ntii 的 force_quit()(第 165-189
行)从未呼叫 UPDATE_D->remove_user()——只有 save() +
move(VOID_OB) + destruct(me),删除逻辑完全局限在交互式 confirm()
分支(第 191 行起,仅在玩家显式输入 y 时才触发)。也就是说 ntii 这
份档案的 force_quit()/confirm() 从一开始就是分离的两条独立逻辑,不
像 nte(修复前)那样把两条路径的销毁逻辑合并复用——这不是同一个
bug 的另一个实例,是两份档案在这个函式上本来就是不同的代码形状,
ntii 自己的 NOTES.md 也没有任何相关记录(说明它从未需要修)。范围缩
小:这个 bug class 候选在 nte/ntii 这对最近的 sibling 里只命中了
nte 一份,未来如果要跨库扫这个模式,ntii 可以从候选列表里排除,但
不代表其他更远的 ES2/Annihilator 血统档案同样安全,仍值得个别核实。
本轮结论
三项此前从未测试的真实游玩全部走通且验证正确:真实战斗死亡与复活(含
§7.112 补丁第一次真实触发验证)、真实商店购物(价格/找零/实物到手)、
真实拜师门派(非管理捷径,bai kong 完整走通,字段正确)。额外独立发
现并修复第六类 bug:log_file() 缺 assure_file() 守卫
(AGENTS.md §7.11 实例,已修复/验证/提交/推送)。标准检查清单全项通
过,无新发现。顺手核对 ntii 的 force_quit(),确认该档案本来就是安
全的代码形状,不需要移植修复。整体信心:高。
深度功能测试(§10.7,2026-10-04)— negative range ends
scripts/lpc_fix_negative_ranges.py: 4 line(s) in 1 file(s) count a range from the end with < (x[a..-1] -> x[a..<1], x[-2..] -> x[<2..]; KB 06 §7.209). In this driver a negative constant end gave "" / ({ }) and a negative start the whole value, so each of these returned the wrong slice; the compile warning A negative constant as the second element of arr[x..y] is gone from the files that compile. Range lvalues (s[0..-1] = text, the prepend idiom) are left alone. A paired compile of the changed files at HEAD and in the working tree showed no new error.
深度功能测试(§10.7,2026-10-05)— 房间列出的物件缺档时房间照常加载
房间基类 inherit/room/room.lpc:make_inventory() 用 catch() 包住 new(file),做不出来就返回 0;reset() 的 case 1: 拿到 0 就跳过这一项(if (!objectp(ob[list[i]])) break;)。档案里没有的 NPC 或物品(或 create() 出错的物件)原先会让列出它的房间整个加载失败(Bad argument 1 to environment(),或对 0 的 call_other()),连带这个房间后面的区域;现在房间照常加载,只是少了那个物件,下次 reset() 再试(KB 05 §7.25;scripts/lpc_resilient_room.py、scripts/lpc_room_reset_guard.py)。
验证:探针(scripts/lpc_room_reset_probe.py:房间基类列出一个不存在的物件,再调用 reset())HEAD 单件 崩溃、多件 崩溃,工作树 单件 OK、多件 OK。
深度功能测试(§10.7,2026-10-06)— 与 zhonghua2 同源的三处编译警告
include/npc/indian.lpc与masia.lpc共用全局名ma_sname/ma_pname;两个头文件被同一个守护进程(npcd等)一起包含时,后包含的印度名表覆盖马来名表,generate_ma_name()生成的是印度名字。印度表改名in_sname/in_pname(KB 04 §6.10)。cmds/std/team/bunch.lpc:结义失败提示被多余的;截成两句,fail只剩"……可惜现在有人不在,$N",后半句"的提议只好作罢。"丢了;接回去。clone/drug/fengdong.lpc:if (... < 10000) max1 / 2;是空语句,改成max1 /= 2;(经验不足一万的对手,分身技能减半)。
验证:改动的文件和包含 npc/indian 的守护进程在 HEAD 与工作树分别加载(scripts/lpc_listcheck.sh,新进程),无回退。
深度功能测试(§10.7,2026-10-07)— 编译警告整理
先用 scripts/lpc_twin_port.py adopt nitan_ceshi nte 把 nitan_ceshi 警告整理提交(ae7fbb619a5)里的改动搬到约 980 个修改前与它一致的文件(逐文件核对非 ASCII 文字:除 nitan_ceshi 自己删掉的以外没有丢失或改动)。剩下的再跑 scripts/lpc_warnings.py nte --fix:无用局部变量 698 个、varargs 14 处,共改动 1251 个 .lpc 和若干 .h。
手工(与 nitan_ceshi 相同):adm/daemons/logind.lpc、fingerd.lpc 里只在 #ifdef DB_SAVE 或 #ifndef NO_FEE 分支用的局部变量,声明挪进同样的条件里;adm/daemons/combatd.lpc 删去空语句 your_temp["guarding"];。cmds/std/team/swear.lpc 结义失败提示"的提议只好作罢。"与上一句隔着空行,前次的整理漏了它;接回去(lpc_fix_no_effect.py 原先会把它当作无用语句删掉,已改为只删空的 "\n";)。
HEAD 与工作树分别加载(新进程):1245 -> 1245 通过,无回退;改过的头文件的 290 个包含者 289 -> 289 通过。
启动时警告 112 -> 0;新进程登录(英文名、新人物确认)正常。
深度功能测试(§10.7,2026-10-08)— .lpc 后缀的定宽切片
.c 改名 .lpc 时只改了字符串没改切片宽度:f[<2..] == ".lpc" 拿两个字符比四个字符,永远不成立(!= 永远成立),按后缀筛文件、去后缀的代码因此从不运行或截成 x.l(KB 06 §7.238)。scripts/lpc_lpc_suffix_slice.py --apply 改了 4 处比较、0 处去后缀(如 adm/daemons/taskd.lpc);改动的文件 HEAD 与工作树分别加载(新进程),无回退。
- 2026-10-10:编译警告第二轮(按驱动报告逐条修):按位 & 改逻辑运算 0 处,返回类型/原型 2 处,NPC+F_UNIQUE 的 init() 0 个,带初始化的未用局部变量 1 个,只在 #if 分支用的声明移进分支 4 个文件;改动 7 个文件,HEAD 与工作树各载入一次无回退(7 objects; HEAD PASS 7, tree PASS 7; regress 0; newly loading 0),这些文件的警告 8 -> 0。
- 2026-10-12:
adm/npc/obj/xiang.lpc写着int remove() { save(); },盖掉了feature/move.lpc的remove(string euid)——这些存盘箱子/柜子被销毁时不从携带者身上减负重、不清 handing(KB 06 §7.239 变体,nitan_ceshi/tianxiawuxue 同类)。改成varargs void remove(string euid) { save(); ::remove(euid); }。HEAD 与工作树各载入一次,regress 0(载不进的文件在 HEAD 就载不进)。
深度功能测试(§10.7,2026-10-12):编译警告收尾
能编译的文件里的警告 9 条(7 个文件)-> 0(toolkit_fix.sh nte 后重扫:13040 个文件可编译,剩下的诊断都在本来就编译不过的文件里)。这几处 nitan170911(e7b0eac1a63)、nitan6(3264a2e14e1)、nitan_ceshi(0d3c177da02)当天都修过,本库代码与它们有出入(twin_port 判为 differs),照它们的做法手工改;adm/npc/obj/xiang.lpc 的 remove() 已在 233a95604a4 修过。
真问题:
clone/misc/swmuding.lpc神木王鼎:自己的 13 种毒虫表mapping insects从来没被用过——读表的是基类clone/misc/muding.lpc的函数,它们读基类那份 8 种虫的木鼎表。改名sw_insects,create()里赋给基类的insects。d/mingjiao/npc/hu.lpc胡青牛:给玩家疗伤的回调叫recover(object ob),盖掉了 NPC 基类自己的void recover()(回满气血)。改名heal_patient,call_out一并改;基类的recover()恢复原样。clone/misc/cruise-ob.h(随身物品存储的 cruise-ob):varargs int remove() { save(); }盖掉了 F_MOVE 的remove(euid),物件销毁时不卸装备、不从携带者负重里扣除。该物件继承 F_OBSAVE,F_MOVE 的remove()本来就会先save(),删掉叶子的版本。
其余:
feature/food.lpc、feature/liquid.lpc的do_effect()改为varargs int do_effect(object me)并return 1;,与 eat/drink 读返回值的重载(d/gumu/obj/fengmi.lpc、d/xiakedao/obj/pigpart.h)同型。clone/obj/genmap.lpc:find_exits()里#include "harbor.h"引入的三张港口表本函数一张都不用,删掉这行包含及注释。clone/drug/pldan.lpc多余的inherit F_CLEAN_UP;(ITEM 已带,toolkit_fix.sh删)。
验证:改动文件、所有继承 F_FOOD/F_LIQUID 的物品、包含 pigpart.h/cruise-ob.h 的文件、muding、eat/drink 共 308 个对象,HEAD 与工作树各用新进程载入:307 -> 307 通过,regress 0;删除声明审计 0 项待看。308 个对象载入无回退。
- 2026-10-14:新驱动(FluffOS 970d9f09)报
Float value truncated to int(#1426)。13 个文件 20 处:赋值、初始化、return 改写成to_int(...)(值不变,只是写明截断);x op= 浮点先把浮点转成整数再运算(系数小于 1 时 x 直接变 0),改为x = to_int(x op ...):/adm/daemons/combatd.lpc(gain *=)、/kungfu/class/generate/killed.lpc(exp *=)、/kungfu/class/generate/killed.lpc(pot *=)、/kungfu/class/generate/killed.lpc(weiwang *=)、/kungfu/class/generate/killed.lpc(score *=)、/kungfu/skill/yunv-xinfa/xiuxi2.lpc(xj_gain *=)、/kungfu/skill/yunv-xinfa/xiuxi2.lpc(xj_gain *=)。改动的对象新进程各载入一次,无回退(scripts/lpc_fix_float_trunc.py,KB 04 §6.10)。
- 2026-10-14:2 个文件用了颜色宏(
HIW、NOR)却没有#include <ansi.h>(首个错误syntax error, unexpected L_STRING);开头补上(KB 04 §6.1、§6.3)。新进程比对 HEAD 与工作树:2 个对象,新增载入 2,回退 0。
负数伤害当作消耗(2026-10-15,KB 06 §7.241)
receive_damage("neili", -52)、receive_damage("qi", -12) 之类把 add() 的负数写进了 receive_damage():本库 feature/damage.lpc 对负数伤害报错(或归零),练功/运功时报 F_DAMAGE: 伤害值为负值 或消耗失效。已改为正数伤害,内力/精力类改为 add(type, -N)(scripts/lpc_fix_damage_calls.py):/kungfu/skill/duanyun-fu、/kungfu/skill/feifeng-whip、/kungfu/skill/pangen-cuojiefu、/kungfu/skill/yiwei-dujiang。
内力/精力当作伤害种类(2026-10-15,KB 06 §7.241 第二类)
本库 feature/damage.lpc 的 receive_damage() 不接受 jingli/neili/force 等种类,me->receive_damage("jingli", 30) 之类在练功、绝招、吸取时报 F_DAMAGE: 伤害种类错误。17 处改为 add(type, -N)(scripts/lpc_fix_damage_calls.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),共 1 个文件。
转码吃掉的引号(2026-10-15,KB 03)
原档在右引号前有一个孤立的 GBK 前导字节,转 UTF-8 时连引号一起丢了(如 return name + HIM "发作身亡了;),字符串一直延续到后面,文件编译失败:/inherit/condition/damo。补回引号(scripts/lpc_fix_eaten_quote.py)。其中 /inherit/condition/damo.lpc 不能编译时,所有 damo_*(达摩)中毒状态都载入失败。
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):bingpo-blade/ningxie、duanyun-fu/hong、huashan-sword/long.bak、xue-dao/xuemo、yunu-sword/yijian。
技能名拼错(2026-10-15,KB 06 §7.249)
query_skill() 里的技能名拼错了,或用的是本库改名前的旧名;本库没有这个技能,调用永远得 0:门槛(< N 就拒绝)永远过不去,相关功夫或绝招学不了、用不了;内功互斥(> N 就拒绝)从不生效;公式里这一项一直是 0。经汉字名(提示文字或中文名词典)或纯拼写差异(_/-、少一个连字符、相邻字母颠倒)核对后,改为本库的技能名(scripts/lpc_fix_skill_typo.py):matrial-cognize→martial-cognize(qiankun-danuoyi/nuoyi、qiankun-danuoyi/yi);qianzhu-wandu→qianzhu-wandushou(/kungfu/class/emei/zh、qianzhu-wandushou/tuxi);xuantian-wuji→xuantian-wujigong(liangyi-jian、taxue-wuhen);choushui-zhang→chousui-zhang(chousui-zhang);cuhixiao-jifa→chuixiao-jifa(xiaoao-jianghu);feilong--cuff→feilong-cuff(feilong-cuff/dan);hengshan-jianfa→hengshan-jian(/d/henshan/tianquan-hole);lenyue-shengong→lengyue-shengong(lengyue-shengong);xiawuxiang→xiaowuxiang(jidao-shaqi);yaowang-mishu→yaowang-miaoshu(yaowang-miaoshu)。
技能名拼错:技能文件里拼错自己的名字(2026-10-15,KB 06 §7.249)
技能自己的文件(或它的绝招目录)里,query_skill() 读的是差一个字母的自己的名字,永远得 0:“基本功夫要高过本技能”之类的限制从不生效,按等级取招、计算伤害的那一项一直是 0。改为本技能的名字(scripts/lpc_fix_skill_typo.py 的 self 判据):xuanyuan-arror→xuanyuan-arrow(xuanyuan-arrow)。
密宗猴拳「震」最重的一档报错(2026-10-15)
/kungfu/skill/mizong-houquan/zhen 按伤害分档写描述:前几档都是 pmsg = ...,最后一档(伤害 ≥ 80,也就是最重的一击)却写成 pmsg += ...,而 pmsg 没有初值,本驱动里 0 += 字符串 直接报错,这一招打得最狠时反而中断。改为 pmsg = ...。
地图数据库 mapdb 的空档防护(2026-10-15,KB 06 §7.250)
genmap 第一次载入时 if (!restore()) save(); 会在地图建好之前写出只有文件头的 data/npc/map.o;mapdb 读它成功后 map 为 0,所有查询都对 0 取下标(nitan170911、shenzhou 等 10 个库就带着这样的文件)。没有 map.o 时 query_random_room_path() 又对空数组取下标。mapdb(/clone/obj/mapdb.lpc)加一个 restore():读档后 map 不是映射就重置为 ([]);地图为空时 query_random_room_path() 返回 0。
临济庄「幽冥桩」的两处笔误(2026-10-15,KB 06 §7.245、§7.250)
linji-zhuang/youming:killer->querry(...)、me->querry(...) 调用的是不存在的函数,永远得 0,恶人比值只按 PK 数算,改为 query;visit_room() 先拿 range 作判断、后从参数里取 range,判断时它还是 0,效果遇到没载入的房间就停,两行取值挪到前面。
柔云步法「柔云纵」有时报错(2026-10-15,KB 06 §7.251)
rouyun-steps/zong 随机把人送到三个房间之一:精、精力已经扣了,“乘云而去了”也说了,送不过去时人留在战斗里并报错。第三个是巫师的测试房 /u/deaner/test1,库里没有;改为 /d/city/guangchang(hy、jym 等库原本就用这个)。
秋林拾叶「随风而舞」成功时报错(2026-10-15,KB 06 §7.252)
qiulin-shiye/wu 把房间的出口映射当数组:mapping *obb = query("exits", env),成功时 me->move(obb[0]),映射里没有键 0,移动到 0 报错(没有出口的房间则是对 0 取下标)。改为 yanhuangwuhun 一系的写法:从 values(exits) 里随机选一个出口。
用兵器的绝招空手施展时报错(内联写法)(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):shenlong-jian/anxi。
存档读不出来:字符串里的换行、空行(2026-10-15,KB 03 §4.4)
help/newsd.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/aln/、/u/lonely/、/u/smallfish/),本库没有这些房间。本库的 move() 用 call_other(dest, "???") 载入目的地,找不到文件就报 call_other() couldn't find object,后面的语句都不执行:药(人参,clone/drug/cb_renshen)吃下后药效已经生效,随后报错:call_out("destroy", 31) 没有排上,药一直留在身上,药效过去后可以再吃;婚礼最后一步(adm/npc/hongniang、adm/npc/meipo、d/suzhou/npc/meipo 的 last_marry)先把月老送走,在这里报错:新人不会被送上花轿去迎宾楼,喜宴没有了;喜宴结束、礼金付出之后,喜来福(d/suzhou/npc/xi-laifu)退回内堂时报错,留在楼上。5 个文件改为移进本库的虚空房间 VOID_OB(/clone/misc/void),与原作把它们“停放”在巫师房间的用意相同(haiyang2 的维护者把月老送进 /d/city/empty,也是同样的做法)。
物品清单把名字的第一个字吃掉(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):d/city2/look.lpc。
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 载入不了,刷出它的房间也少一个人。本库有 3 个对象设了本库没有文件的武功(15 个名字,最多的是 xinyuegong、taizuquan、liangyi-dao)。三处都改成 return:这一门武功不给、不映射,对象照常载入,只是少了它(缺的武功本身仍是内容缺口)。抽样载入这些对象:3 个里 3 个通过。(scripts/lpc_guard_set_skill.py)
通向不存在房间的出口,按对面房间的回头出口改正(2026-10-18,KB 06 §7.257)
房间出口 "west": __DIR__"xxx" 指向的文件本库没有,玩家走过去就被卡住(笔误、改过名的房间,或者没带进档案的编号房间)。对面的房间存在、并且它相反方向的出口正好指回这个房间,说明出口原本就是通向它:/d/dragon/lake 的 east:/d/tulong/lake1 → /d/dragon/lake1;/d/dragon/lake2 的 northeast:/d/tulong/lake1 → /d/dragon/lake1。改动后每个出口都能解析到本库的文件(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 映射不到,门派弟子用普通轻功/拳脚)。按核对过的对照表改正,共 25 处、13 个文件:yunu-xinjing→yunv-xinjing(7 处)、jinyin-baiguzhao→jiuyin-baiguzhao(4 处)、changquana→changquan(4 处)、tiaji-jian→taiji-jian(2 处)、shenkongxing→shenkong-xing(2 处)、taiji-shenfong→taiji-shengong(1 处)、shaolin-shnfa→shaolin-shenfa(1 处)、yan-fly→yanfly(1 处)等共 11 个名字。(scripts/lpc_fix_skill_names.py)
die_reason 的参数个数(2026-10-19,KB 04 §6.10)
/kungfu/condition/damo_luanqi.lpc、/kungfu/condition/damo_shangshen.lpc、/kungfu/condition/damo_zheyuan.lpc 里的 string die_reason() 覆盖了基类的 die_reason(string name),驱动报 Number of arguments to 'die_reason' disagrees with previous definition。补上 varargs,调用处不用改;改后与 HEAD 逐个物件对比载入,没有退步。
出口指向不存在的房间(2026-10-19,KB 06 §7.257)
下列房间的出口写的文件不存在,而对面恰好只有一个房间的出口指回本房间,所以按对面的房间改正(笔误、大小写、路径少了一级):
/d/huanggon/qihedian.lpc的south出口:/d/city2/zhengmen→/d/huanggon/tinglang3
改后房间照常载入(与 HEAD 逐个对比,没有退步),出口现在指向存在的房间。
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.274)
/d/baituo/obj/lingshezhang.lpc:set("wposition", "/d/baituo/obj/lingshezhang.lpc")被//*** ADDED BY SCATTER ***注释吞掉
scripts/lpc_fix_swallowed_statement.py 把换行放回去。逐个载入与 HEAD 对比,没有退步。
补回丢失的标点(2026-10-19,KB 03 §4.6)
转换时丢掉的分号、逗号、引号或文件末尾的 },共 1 个文件,修前 HEAD 载入失败。别的库里同路径的完好副本只比这里少几个标点,按它补回(括号里是那个库):/d/baituo/npc/obj/bowl.lpc(cctx)。修后与 HEAD 逐个对比载入:这 1 个物件全部载入,没有退步(scripts/lpc_restore_from_twin.py、lpc_fix_eaten_quote.py --comma、lpc_fix_eof_braces.py)。
x == "a" || "b":后面的字符串常量永远为真(2026-10-19,KB 06 §7.281)
if (arg == "yuyou" || "yu you") 里的 "yu you" 是非空字符串,永远为真,整个条件对任何 arg 都成立;作者要的是每个字符串都和变量比较。具体是:吃任何东西(eat 后面不管写什么)都会吃掉紫草;valid_combo() 对任何组合都返回真。在每个字符串前补上变量和运算符(scripts/lpc_fix_literal_or.py;forrest2.lpc 是 dir == "north" && "south",手工改成 (dir == "north" || dir == "south") && ...):/clone/medicine/zicao.lpc(1 处)、/kungfu/skill/meinv-quan.lpc(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)。具体是:valid_learn() 对任何性格都拒绝。改动:/kungfu/skill/qiankundanuoyi.lpc(1 处)、/kungfu/skill/zhonghua-aojue.lpc(1 处)。
member_array('/', str) 改为 strsrch(str, "/"):字符字面量的 member_array 按字节搜索(2026-10-20,KB 06 §7.283)
member_array('/', str) 里的 '/' 是整数,驱动按 UTF-8 字节搜索,返回字节偏移(带第三个参数时起点也是字节);最新的 FluffOS(923cdbc0)在字符串里有非 ASCII 文字时,对每个调用点警告一次(Warning: member_array(int, string) searches BYTES)。而 str[0..idx-1] 按字符切,中文字符串会在错误的位置截断。改为 strsrch(str, "/")(找不到同样返回 -1,按字符计数;scripts/lpc_fix_member_array_char.py,JSON 编码器等少数几处手改)。改动:/adm/daemons/vrm_server.lpc(1 处)、/cmds/arch/sameip.lpc(1 处)。
if (x = 常量):条件里写成赋值的比较(2026-10-20,KB 06 §7.290)
if (arg = "button" || arg = "按钮")、if (!arg || arg = "") return 0;、else if (check = 0 && tempB != ""):把 == 写成了 =,条件的值就是那个常量,分支对所有非零数和任何字符串(连 "" 都算)永远成立、对 0 永远不成立,变量还被覆盖;驱动对此没有任何警告。每一处 = 改成 ==(scripts/lpc_fix_cond_assign.py,共 3 处)。改动:/adm/daemons/competed.lpc(1 处)、/adm/daemons/xinruid.lpc(1 处)、/cmds/wiz/roomlong.lpc(1 处)。
登录密码超过 255 字节:crypt() 抛错(2026-10-20,KB 06 §7.294)
驱动的 crypt() 对超过 255 字节的密钥直接报错(Error in crypt(), check your salt),老驱动则按任意长度散列。在登录提示符下输入 256 字节以上的密码,密码检查那一行就抛错,连线停在一个裸的 > 提示符上,登录走不完(password 指令的旧密码检查同样);用 300 个 x 当参数的扫描发现的。/adm/single/simul_efun.lpc 里补了一个同名的 simul_efun crypt(key, salt):只有超长的密钥才被截短(先截到 255 个字符,再逐字符截到 sizeof(to_buffer(key)) <= 255,限制按字节算,一个汉字占三个字节),再交给 efun::crypt();普通密码原样散列,已存的密码散列不受影响(scripts/lpc_add_sefun.py crypt)。
ctell:MTEXT 在没选中的头文件分支里(2026-10-21,KB 04 §6.16)
include/globals.h 末尾 #ifdef DOING_IMPROVED #include "ntsql.h" #else #include "tomud.h" #endif;DOING_IMPROVED(带数据库的版本)没有定义,用的是 tomud.h,它没有 MTEXT(ntsql.h 里有:#define MTEXT(x) TMI("ptext "+x),和 PTEXT 同形,同系的 dtsl2、xyzx3、xyj2006zzzhx 的 tomud.h 都有这一行)。cmds/std/ctell.lpc 四处用 MTEXT(...):Undefined function MTEXT,整个命令加载失败。在 tomud.h 补上这一行。nte 和 ntii 的 ctell.lpc 逐字节相同,同一处改法;加载检查 HEAD 0、树 1。没有改:fee(DB_STR 和 DATABASE_D 只在数据库版本里,没有数据库,整个命令是死功能)。
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 个文件)。
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 取回并删除)。改动(1 个文件):/cmds/arch/recovermud.lpc。
不带参数的指令对 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 与工作树对照,没有退步。
拼错的 call_out() / input_to() 目标(KB 06 §7.349,2026-10-21)
计时器或输入提示给驱动的函数名和文件里定义的差一个字母;驱动对不存在的函数静默不理,所以对应的计时从来没有触发过。调用和配套的 remove_call_out() 改成已定义的拼法:ruanweijia / yuxiao:return_to_zhang → return_to_huang(携带者在战斗时的重试从不发生,宝物一直留在玩家手里);张无忌:destrory → destroy。改动:/clone/lonely/ruanweijia.lpc、/clone/lonely/yuxiao.lpc、/kungfu/class/mingjiao/zhangwuji.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.,同一个动词的其他处理函数不再尝试(不是最新的一条就悄悄跳过)。删除了 22 条注册(16 个文件,scripts/lpc_fix_dead_add_action.py),动词留给别的处理函数:/adm/npc/referee.lpc(do_halt)、/clone/drug/guiyuan.lpc(do_pour)、/clone/drug/huiyang-san.lpc(do_pour)、/clone/drug/shedan.lpc(do_pour)、/clone/drug/yangxin.lpc(do_pour)、/clone/drug/yulu-wan.lpc(do_pour)、/d/baituo/npc/obj/shedan.lpc(do_pour)、/d/baituo/npc/shedan.lpc(do_pour)、/d/beijing/npc/dangpuzhang.lpc(do_expiate)、/d/beijing/npc/tiegongji.lpc(do_bcun、do_bqu) 等共 16 个文件。最多的函数名:do_pour 7 处、do_bcun 3 处、do_bqu 3 处、do_halt 2 处、do_expiate 2 处。
缺失物品的 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 都被跳过。6 个文件里 11 处(new)改成 { object new_ob = new(路径); if (new_ob) new_ob->move(...); }(scripts/lpc_guard_carry_object.py --new:路径按这个文件自己看到的宏解析,宏名冲突、虚拟对象路径一律跳过)。 对这 6 个改动文件做加载检查(HEAD 与工作区对比):HEAD 能加载 6 个,现在 6 个(新增可加载 0 个,回归 0 个)。
调用了、但这个库自己的守护进程里没有的函数(2026-10-22,KB 06 §7.354)
MACRO->函数() 调用的函数在这个库的守护进程里不存在:call_other() 对不存在的函数不报错、只返回 0,所以这些功能(时间显示、昼夜事件、名字检查、价格文字……)一直没起作用。同一血统另一个库的同名守护进程里有这些函数,原文照抄到本库守护进程末尾(scripts/lpc_port_function.py;调用处传的参数个数、函数体用到的函数 / 全局变量 / 宏 / 字符串键都在本库里有,已核对;守护进程在 HEAD 和工作区都能加载,每个函数用固定参数各调用一次:HEAD 返回 0,现在返回正常的值):/adm/daemons/natured.lpc ← aoxiangtianji:outdoor_room_event()(2 处调用)。
(: 函数 :) 指针指向对象自己没有定义的函数(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。 还剩 3 个函数没有补(item_desc 3):原型还在函数体丢了、或者根本没写过,没有可以直接补回的捐赠(别的库同一路径的文件里没有这个函数,或者它还要用本库没有的辅助函数、签名不同),不编造:/d/yihua/lianhuachi.lpc:look_CAI、/d/yihua/lianhuachi1.lpc:look_CAI、/d/yihua/lianhuachi2.lpc:look_CAI。
运行期目录 log/nosave 不存在,写日志的 write_file() 直接报错(2026-10-22,KB 03 §4.3 补充)
这个库的 71 个文件里有 126 处 write_file("/log/nosave/...") / log_file("nosave/...")(static 改 nosave 时连字符串里的日志路径一起改了,原来是 log/static/):nosave/using、nosave/party_quest、nosave/security 等。压缩包和站点包里没有这个目录,write_file() 在目录不存在时抛 *Wrong permissions for opening file /log/nosave/... for append. "No such file or directory",调用它的函数(杀人记录、重启记录、call 日志……)当场中断。把 log/nosave/guilei 记进 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: 函数名,这一拍心跳的后半段被跳过。这些函数没有可以补回的来源(别的库同一路径的文件里没有,或者它还要用本库没有的东西),所以 3 个文件里 3 行只含这个指针的行("CAI": (: look_CAI :),)加了注释,原文保留并写明原因,这一项当作没有这个话题 / 物品 / 闲聊条目(scripts/lpc_fix_dangling_lfun.py;#include 的文件在库里缺失的对象、指针不在整行上的写法没动)。 前提(function_exists())和加载检查(HEAD 与工作区对比,本库改动的 .lpc 文件)的结果见 KB 06 §7.355:没有一个回归。
汉字按字节切片的老写法没有换成按字符:改法名 "澄" + name[2..3]、辈分判断 name[0..1] == "澄" 等 20 处(2026-10-22,KB 06 §7.360)
原档按字节算字符串区间(一个汉字 2 字节):name[2..3] 是名字的第二个字,name[0..1] == "澄" 问名字是不是以「澄」开头。转成 UTF-8 之后,这个驱动的区间和 strlen() 都按字符算(strlen("澄观") 是 2,"澄观"[0..1] 是两个字),老算术原样留着、意思全变:拜入少林 / 武当 / 峨嵋等派的玩家被改成错误的法名(二字名 张三 变成一个字的 澄,更长的名字取到第三个字);各派掌门的辈分判断(name[0..1] == "澄")永远不成立;NPC 的称呼和提示里取到两个字而不是一个字。
本库 20 处(13 个文件):拼名字的赋值 10 处、与汉字常量比较 9 处、to_chinese()[..] 1 处。例:name[2..3] → name[1..1](/kungfu/class/emei/fengling.lpc:133);name[0..1] → name[0..0](/kungfu/class/emei/tobebonze.h:41);chk[0..1] == "你" → chk[0..0] == "你"(/adm/npc/ganjiang.lpc:542)。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,不要重跑。
长度检查按字节写,旁边的提示按汉字写:14 处(2026-10-22,KB 06 §7.362)
老档的 strlen() 数字节(一个汉字 2 字节),转成 UTF-8 后它数字符:提示写「必须是 2 到 6 个中文字」的检查还是 strlen(name) < 4 || strlen(name) > 12,于是两三个字的房名、帮会名、群名、聊天室名、称号被提示自己说允许的那句话拒绝,上限却是提示的两倍;留言板的标题检查 i < 4 || i > 24 || i % 2 还会拒绝所有奇数个字的标题(post 你好吗)。本库 14 处(7 个文件):if ((strlen(name) < 4) || (strlen(name) > 12)) {(/adm/npc/luban.lpc:1767);if ((strlen(mission) < 4) || (strlen(mission) > 20)) {(/cmds/adm/mission.lpc:57)。scripts/lpc_fix_strlen_gate.py 以提示为准:条件里每个 strlen 门槛都恰是提示所说数字的两倍才折半,存长度的变量(i = strlen(arg);)的门槛和 || i % 2 奇偶项、其后循环的 i % 2 == 0 && 一并处理;提示里有英文 / 字母 / 字节的不动。证明(scripts/lpcc_eval.py,bxsj 的留言板,求值对象继承 NPC 并重写 edit() 记录调用,command("post 标题")):HEAD 拒绝「你好」和「你好吗」、放行 23 个字的标题;改后接受前两个、拒绝第三个;shenmo 的 named.lpc invalid_new_name("张三"):HEAD 回 名字只能是2-4个中文字。,改后回 0。抽样 24 + 15 个库的 HEAD / 工作树加载对比 0 退步。
按字节写的汉字循环、茶馆猜诗和同盟频道标题(2026-10-23,KB 06 §7.363)
老档按字节做「一个汉字」:while (i--) if (i % 2 == 0 && !is_chinese(name[i..<0])) 只检查偶数下标,奇数位上的拉丁字母(张a)会过;茶馆猜诗 mixup() 用 strlen(str)/2 再 j=j+j、str[k..k+1] 交换两字节;泥潭系 channeld 的 switch (strlen(fname)) case 4/6/8/10 和 strlen(family)==4/6 按字节长度给同盟 / 门派名加空格。本驱动的 strlen() 和区间都按字符算。scripts/lpc_fix_byte_char.py:去掉奇偶项、把区间改成 name[i..i],按字符重写 mixup() 并把 strlen(first)>=14 折成 7,频道标题的 case / 门派长度改成字符数(对照 aoxiangtianji)。本库 汉字循环 / is_chinese 区间 7 个文件;channeld 同盟 / 门派标题 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(一格两个空格)。本库 9 处(2 个文件)。证明(lpcc_eval.py hhsj):tribar_graph(6,9,12) 在 HEAD 画出整条 12 个■,改后为 6 个■+3 个□;麻将 strlen(tempB)/2 是两字符牌码,未改。
中文名 / 验证码仍按 GBK 取「两字节一字」(2026-10-23,KB 06 §7.373)
pname = pname[(random(sizeof(pname)) & 0xFFFE)..<1]; pname = pname[0..1]; 在按字符计下标时会取出两个汉字。scripts/lpc_fix_pname_slice.py 去掉掩码并把收尾改成 [0..0](pname/pname2/sec_name/str/str1)。本库 10 处。证明:nt1 生成名长度 2–4;HEAD 常见 3–5。
无参数时命令对 0 的调用(2026-10-27,KB 06 §7.336 Also)
巫师/管理员命令在通过权限门之后仍会把 0 交给 sscanf / read_file / find_living 等。lpc_fix_bare_arg.py 在首次使用参数前加上 if (!arg)(或 help(me) / GetHelp())。本库本批改动见该提交。
无参数时命令对 0 的调用(玩家/--all-dirs 残留,2026-10-27,KB 06 §7.336 Also)
无参数命令把 0 交给 present / sscanf / file_exists 等会运行时报错。lpc_fix_bare_arg.py --all-dirs 在首次使用参数前加守卫。多行 if (arg && !sscanf)(吐纳默认消耗)与已有 can_learn/get_object 守卫的误报已回退;本库本批改动见该提交。
yuanwai 孤儿 call_out announce_success(2026-10-27,KB 06 §7.349 Also)
d/changan/npc/yuanwai.lpc(及 aoxiangtianji 的 d/city 副本)在 check_daughter 里 call_out("announce_success", …),但本文件从未定义该函数;同系也无实现。到点会 *Undefined function*。cry_daughter 已完成认亲与赠书,删除这对 remove_call_out/call_out。证明:扫描 HIT call_out→announce_success 且无定义;改后残渣 0。
深度功能测试(2026-10-27,§6.25 zhongling tell_object 引号错位)
d/wanjiegu/npc/zhongling(及同路径副本)的 tell_object("who, 钟灵脱下一双绣花鞋。\n") 把对象参数写进了字符串;改为 tell_object(who, "…")。证明:原文错位;改后加载,语料残渣 0。
深度功能测试(2026-10-27,§6.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… 行。