info.html · 介绍 · play.html · 游玩 · llms.txt · 下载与本地运行 · ZIP · GitHub
一个 ES2/XKX 血统的传统中文 MUD,除了华山、武当、少林、丐帮、峨嵋、 明教等常见门派场景外,还有一整片嘉峪关(西北边塞)主题地图——沙漠场景、城门、当铺一应俱全,是这一血统家族里比较少见的西北边塞题材延伸。`niaoren`(鳥人世界)是从同一套源码分支出来、重新包装成金庸题材的独立版本,两者血缘极近(注册流程里天赋选择的提示文字几乎逐字相同),详见 `niaoren/README.md`。新玩家一走出欢迎室就会遇到主动搭话的"接客童子"NPC,现场介绍吃喝取物买卖睡觉等基本生存指令,盘缠不够还会主动奉上,全程不必先去翻帮助文件。
English
A traditional ES2/XKX-lineage wuxia MUD featuring the familiar sects (Huashan, Wudang, Shaolin, Beggars' Sect, Emei, Ming Cult) alongside a distinctive northwestern frontier region around Jiayuguan, complete with desert scenes, a city gate, and a pawnshop — an unusually large excursion into frontier themes for this family of games. Newcomers are actively guided by an NPC greeter just outside the welcome room who offers basic survival commands and travel funds.
README
内容亮点
- 除了华山、武当、少林、丐帮、峨嵋、明教等常见门派场景,
d/jyguan/是一整片嘉峪关边塞荒漠地图(多个"荒漠"场景加城门、当铺),是这 批档案里比较少见的西北边塞题材延伸。 - 曾有一处真实的死代码陷阱:
globals.h的SIMUL_EFUN_OB/MASTER_OB宏原本指向未被使用的/adm/single/副本,而真正生 效的/adm/obj/版本才带有destruct()/remove()安全检查—— 不修的话迟早会重演"每个新玩家 quit 都失败"的经典故障(详见下方 bug 修复说明)。 - 移动到欢迎室外的第一个房间会遇到"接客童子"NPC,主动介绍 eat/drink/get/buy/sell/sleep 等基本生存指令,还会主动提示没有 盘缠(路费)可以直接找他要——一整条由 NPC 主动搭话驱动的新手引 导,不需要玩家先去翻帮助文件。
注册流程
英文名字(3-12 个英文字母)→ 确认创建(y/n)→ 中文名字 → 密码(≥5 字元)→ 确认密码 → 天赋确认(y/n)→ 电子邮件地址 → 性别(m/f)。
本次修复的关键 bug
include/globals.h里的SIMUL_EFUN_OB和MASTER_OB两个宏都指 向未被使用的死代码文件/adm/single/{master,simul_efun}.lpc,而config.fluffos的master file/simulated efun file实际指向/adm/obj/{master,simul_efun}.lpc——两者路径不一致(和之前某些 lib 里securityd.lpc/securd.lpc或SIMUL_EFUN_OB的陷阱是同一种 教训)。真正被使用的simul_efun.lpc带有destruct()/remove()安全检查覆盖,而死代码副本没有——如果不修,迟早会重演"每个新玩家quit都失败"的经典故障。已将两个宏都指向真正被使用的文件。adm/daemons/httpd.lpc(纯 HTTP 服务器,全篇无条件调用socket_*)在 WASM 下无法编译;按"禁用整个文件的入口点"方式清空 为 no-op。
深度功能测试新发现的 bug(详见 NOTES.md)
feature/command.lpc(真正生效的玩家指令分发中枢)的command_hook声明为private nomask,在这个驱动上继承后会静默 破坏 NPCcommand()自呼叫路径(AGENTS.md §8.3a)。已去掉private,保留nomask。adm/daemons/logind.lpc的get_name()有一行调试用的printf("%O\n", ob),会把登录物件的内部路径(如/clone/user/login#1)直接打在"您的中文名字:"和"请设定您的密 码:"两个提示之间,每一个新玩家都会看到(AGENTS.md §7.34)。已 删除。adm/daemons/logind.lpc的食物/饮水初始化判断条件混用了两个不同 的物件——!user->query("food") && !user->query("water") && ob->query("age") == 14——前两个读user(玩家身体),最后一个 却读ob(登录连线物件,全代码库没有任何地方给它设过 age)。这 个条件因此永远为假,每一个全新玩家食物/饮水槽永远是空的,一 进游戏就会看到"你饿得直冒金星"的挨饿提示。已改成user->query("age")(新增 AGENTS.md §8.9)。修复前后各注册一个 全新角色对照验证:修复前食物/饮水槽全空,修复后全满。
管理员账号 / Admin account
- id:
fluffos - 密码 / password:
Mud@2026 - 权限 / level:
(admin)
管理员名单存储在纯文本文件 adm/etc/wizlist 里;账号本身通过正常注
册流程创建。
警告:这是一个公开的默认密码,仅供本地/浏览器试玩。正式对外开服前
请务必修改此密码。
本地运行
cd libs/cctx
~/src/fluffos/build-debug/src/driver config.fluffos游戏端口:40161。
NOTES · 移植与修复记录
WASM 修复摘要(迁移自 meta.json 的 group_note)
ES2/XKX 血统代码库(襄阳关/嘉峪关场景内容)。完整 WASM 修复:(1)过时的 SIMUL_EFUN_OB 和 MASTER_OB 宏都指向了未被使用的 /adm/single/{master,simul_efun}.lpc 死代码副本,而 config.fluffos 实际使用的 master/simul_efun 文件是 /adm/obj/{master,simul_efun}.lpc(真正的 simul_efun.lpc 带有旧版本缺少的 destruct()/remove() 覆写,和 §7.58 类的 bug 是同一类,在它搞坏 quit 之前就被排查出来了);(2)adm/daemons/httpd.lpc(纯 HTTP 服务器,无条件调用 socket_*)按 §7.52 的整文件入口点掏空模式处理掉了。排版格式化工具的第三类盲点检查(CJK 重新加空格)在约 40 个"误报"(原文本来就有的装饰性房间名/诗词间距)里抓到了一处真正的损坏:d/huashan/map.lpc(一张密集的 ASCII 地图)——已直接还原,没有手工修补。管理员账号(fluffos/Mud@2026)通过真实注册流程 + adm/etc/wizlist 播种。
深度功能测试(第二轮,2026-08-03)
此前的验证只做到浅层冒烟测试。本轮启动前先主动检查了本次会话已经
反复确认过的 private command_hook 模式,提前修复了一处;随后完整
走通了注册流程,过程中又发现并修复了两个真实 bug:一处是本会话已
经在别的档案上见过的经典"调试信息泄漏",另一处是全新发现、已经写
进 AGENTS.md §8.9 的一类新 bug——多物件函式里读错了物件。
主动排查发现并修复:feature/command.lpc 的 private command_hook
和本次会话在 hell/jym 上已经修过的同一个 AGENTS.md §8.3a 模式:
inherit/char/char.lpc 通过 F_COMMAND 继承的 feature/command.lpc
把 command_hook 声明成 private nomask,在这个驱动上继承后会降
级为 DECL_HIDDEN,导致对 ORIGIN_EFUN(NPC 自己用 command()
efun 说话)的分发静默失效。启动前 grep 直接命中,已去掉 private,
保留 nomask。
注册流程中发现并修复:get_name() 里一行调试用的 printf("%O", ob)
adm/daemons/logind.lpc 的 get_name() 在校验完中文名字之后有一行
printf("%O\n", ob);——这是 AGENTS.md §7.34 已经收录的经典模式(
esI/xianlvqiyuan 都出现过同一类问题):原作者调试用的物件路径
打印,从未清理就随档案一起流通了出去。实测复现:注册时"您的中文名
字:"提示之后,紧接着会看到一行 /clone/user/login#1(登录物件自
己的内部路径),然后才是"请设定您的密码:"提示——每一个新玩家注册
时都会看到这行内部实现细节。已直接删除这一行,属于 AGENTS.md §7.34
明确记载的"删掉即可,从不服务于任何玩家可见目的"的一类修复,已列入
该条目"确认实例"名单。
注册流程中发现并修复:食物/饮水初始化门槛读错了物件(新增 AGENTS.md §8.9)
adm/daemons/logind.lpc 的 enter_world()(exec(user, ob) 之后
的角色进世界流程)里,食物/饮水一次性初始化的判断条件是
!user->query("food") && !user->query("water") && ob->query("age")
== 14——链条里前两个条件读的都是 user(刚创建的玩家身体物件),
唯独最后一个读的是 ob(临时的登录连线物件)。clone/user/user.lpc
的 update_age()(由 setup() 调用,在这个判断之前就已经执行过)
确实会把 user 自己的 age 设成 14,但整个代码库里没有任何地方给
ob 这个物件设置过 age(已通过对全代码库 set("age" 逐一核对确
认——所有命中都落在 user/NPC 类别上,登录物件类完全没有)。
ob->query("age") 因此永远回传驱动默认值 0,判断条件永远为假,
max_food_capacity()/max_water_capacity() 从未真正套用到任何一
个新角色身上——每一个全新玩家一进游戏世界食物和饮水槽都是空的,
第一次 look/score 就会触发"你饿得直冒金星,实在是顶不住了"的
挨饿提示。已把 ob->query("age") 改成 user->query("age"),和判断
链条里其它条件保持对象一致。修复前后各注册一个全新角色对照验证:
修复前 score 的食物/饮水槽全空,伴随挨饿提示;修复后两条槽全满,
没有挨饿提示。
完整验证:从注册到探索
用全新账号在原生驱动上完整走通:英文 id(3-12 个英文字母)→ y 确认
→ 中文名字(无泄漏问题)→ 密码 + 确认 → 天赋确认(y/n)→ 电子邮件
→ 性别 → 进入"欢迎光临驰骋天下"的欢迎室,食物/饮水槽全满(如上)。
e 移动到下一个房间,"接客童子"NPC 主动搭话,介绍 eat/drink/get/
buy/sell/sleep 等基本生存指令,并主动提示"如果你没有盘缠的话,可以
问我要"——是一整条 command()-efun 驱动的 NPC 对话链路,间接印证
了 command_hook 修复的必要性。断线后用同一账号重新登录,"重新连
线完毕",直接回到游戏内状态,移动/NPC 对话依然正常。quit 干净退
出(丢下一件不值钱的布衣,"欢迎下次再来!")。debug.log 只有驱动启
动期的诊断噪音(找不到旧版二进制路径、反向地址解析被拒绝),没有
来自本次实际游玩会话的运行时错误。
未覆盖范围(诚实说明)
预算集中在验证三处修复和基础移动/NPC 对话链路,没有走到:门派拜师、 战斗系统、经济系统(buy/sell/盘缠)。这些留给下一轮,目前的验证边 界如上所述。
深度功能测试(第三轮,2026-08-18)——补完经济/战斗,发现并修复一个 §7.11 类新实例(8 个排行榜档案全部写入失败)
补完上一轮留下的门派拜师、战斗系统、经济系统测试,过程中发现并修 复一个此前未被注意到的 §7.11 类 bug。
- **发现:
adm/daemons/toptend.lpc的topten_save()对/topten/*.txt(8 个排行榜档案:rich/exp/pker/neili/shen1/shen2/ per1/per2/age)做无保护的write_file(),而档案本身从未打包过/topten/这个目录:debug.log里出现 "Wrong permissions for opening file /topten/rich.txt for overwrite. No such file or directory",调用链是enter_world()→get_gender()(注册流程最后一步,性别选择)→topten_checkplayer()→topten_add()→topten_save()——也就 是说每一个新角色注册**都会触发这条写入。好消息是topten_save()自己对write_file()的返回值做了检查(if (!write_file(...)) return notify_fail(...)),所以这不是一个未捕获异常,不会像 xkyxciii/hhsj 那两个实例一样打断整个注册流程或角色创建——注册、 进入游戏世界、look/score/fight/buy/sell全部正常。但代 价是:这份档案的排行榜系统(富豪榜/经验榜/PK榜等 8 种排行)从第 一次开机起就从未真正写入过一条记录,是个悄悄彻底失效的功能。 - 修复:
adm/simul_efun/file.lpc里本来就有的assure_file()帮助函式,在write_file()之前补一行assure_file(f_name);—— 和 AGENTS.md §7.11 已经确立的标准修复手法完全一致。现场验证: 重启全新驱动进程,全新注册一个角色,debug.log里不再出现任何 "Wrong permissions"/"rich.txt" 记录,work/topten/目录下 8 个 排行榜档案全部成功创建并写入了内容。 - 经济系统验证:昆明"聚朋茶馆"的茶小二支持
list/buy(买到 一碗大碗茶,正确扣钱、正确加入背包);南大街"当铺"的老板支持sell/value(对不值钱的物品正确返回"一文不值",没有崩溃)。list/buy/sell三个指令全程零报错。 - 战斗系统验证:
help combat文档明确的安全切磋指令是fight(非致命,打到一方昏迷/认输/逃走为止),不是kill。在"近日古 楼"对"捕快"使用fight bu,触发真实的攻防交换(命中/闪避描述、 伤害叙述),本次测试角色落败被打晕("你的眼前一黑,接著什么也 不知道了...."),look/score在昏迷期间正确地不返回任何输出 (不是 bug——help combat本身就说明昏迷期间指令会被封锁),过 一段真实时间后角色自动恢复知觉,look恢复正常。全程符合文档描 述的设计,没有发现异常。 - 门派拜师未覆盖:
bai <师傅>(cmds/skill/bai.lpc)需要在同 一房间内对一个query("family")非空的 NPC 使用,但确认这类"开 山立派"的师傅 NPC(通过create_family()建立门派)散布在d/heimuya、d/huashan、d/shaolin、d/wudang等各门 派专属地图区域,离本轮测试角色所在的昆明新手区有相当距离,本轮 时间预算内没有找到合理的步行路径。留给下一轮,如果继续测试建议 直接用巫师账号goto快速定位一个师傅 NPC 而不是徒步摸索地图。 - 本轮结论:经济系统和战斗系统均验证正常工作,额外发现并修复一个 真实的、影响所有新角色注册(虽然是非致命的)的排行榜写入失败 bug。门派拜师系统本身代码逻辑读起来是合理的(
bai.lpc有完整的 错误提示和状态检查),但受限于地图导航复杂度,本轮未能实际验证。
§7.86 跨库扫描修复(留言板 post 崩溃)
BULLETIN_BOARD、W_BOARDinherit+ 多余replace_program()致命形状(AGENTS.md §7.86,post命令崩溃):全档案 33 处命中,已删除多余的replace_program(...)调用(保留inherit),逐文件保留原有行尾格式(CRLF/LF 按文件原样)。本次为跨库 §7.86 扫描修复(触发原因:该 bug 已在 6+ 个互不相关的血统家族独立确认,属于近乎普遍的拷贝粘贴模式),仅做编译检查(驱动干净启动、端口正常监听),未做完整 §10.7 深度游玩测试。
第四轮回归测试(2026-08-19)——针对 §7.111/§7.112/§7.113/§7.114/§7.90 逐项核查 + 全新角色完整 §10.7 游玩,结论:全部清洁,无需修复
本轮是在 AGENTS.md 新增 §7.111–§7.114 之后对 cctx 做的一次针对性回归,
cctx 此前没有被 §7.113(netdead 重连不恢复 heart_beat)的两批语料
库扫描覆盖到(不在扫描名单内),因此本轮对这一条做了最仔细的从零核查
和真实存活验证,而不是照抄扫描结论。
- §7.111(
master.lpc的standard_trace()对error["object"]==0未加保护而崩溃):adm/obj/master.lpc(真正被config.fluffos使用的 master 文件)已经是objectp(error["object"]) ? file_name(error["object"]) : "(driver)"的安全写法,早已修复(推测是此前某次 67 库扫描时处理的),本轮无 需改动。 - §7.112(
init()里无保护的call_out("death_stage", ...),重连时enable_commands()重放init()导致链条重复):全档案定位到三 处call_out("death_stage"命中——d/death/npc/wgargoyle.lpc、d/death/npc/bgargoyle.lpc、d/shaolin/npc/yu-zu2.lpc——逐一检查, 三处全部已经带有query_temp("death_stage_active")前置判断 +set_temp/delete_temp配对保护,已经是正确写法,无需改动。 另外d/shenlong/npc/pang.lpc虽然文件名貌似相关,实际是完全不同 的门派宗师 NPC(join/do_skills逻辑),与 death_stage 模式无关。 - §7.113(netdead 重连不恢复 heart_beat,永久性无法自然痊愈的软锁) ——本轮重点:追踪真实的
LOGIN_D(/adm/daemons/logind)reconnect(object ob, object user, int silent):在"同一 id 已经 netdead"和"confirm_relogin 顶替旧连线"两条分支下都会被调用,且函数 体里无条件执行user->reconnect()(->跨物件呼叫,this_object()正确落在玩家身体物件上)。clone/user/user.lpc自己的reconnect()则无条件set_heart_beat(1)——链路完全正确,是本项目 中已经确认过的"正确血统"写法,与另外 62 个已核对过的库一致。 现场验证(不仅仅是静态读码,按任务要求做了真实存活验证):用全 新角色rfourtst注册进游戏,先用fight/kill让角色受伤/陷入 半昏迷/甚至真正死亡(触发d/death/npc/wgargoyle.lpc"白无常" 完整的 death_stage 判词流程,角色被判"阳寿未尽"送回土地庙复活,是 这个死亡系统的正常非致命结局,不是 bug),然后用裸 socket 脚本反复 模拟掉线(不发quit,直接断开 TCP 连线触发net_dead())→ 等待 → 用同一账号密码重新连线(触发logind.lpc的 netdead 重连分支)。 重连后紧跟着的score显示<精>/<气>血条仍处于受伤状态(27 格中 20 格),随后在同一条连线内每隔 8 秒重复score: t=0s→20/27格,t=8s→24/27格,t=16s→27/27(满血)——血条持续、可观测 地自然恢复,直接证明heart_beat()→heal_up()在 netdead 重连后 确实在正常运作,不是"角色仍可操作但心跳已死"的隐蔽软锁。整个测试 过程中debug.log没有出现任何运行期报错(只有编译期的 Unused-local-variable 警告噪音)。结论:cctx本项不需要修复, 可以从 §7.113 语料库扫描的"待核查"名单里正式排除。 - §7.114(
inherit进来的 mixin 里input_to()回调函数被声明成private导致多行输入续行静默失败):feature/edit.lpc的input_line(string line, string text, function callback)没有加private修饰符——即使这份 mixin 是通过inherit/char/char.lpc的F_EDIT间接继承给obj/clone/user/user.lpc使用,也不受这个 bug 影响。现场验证:用chfn指令(复用同一个edit()/input_line()续行机制)走了两轮"多行输入 + 裸.结束"(自我介绍 两行、签名一行),每一行都被正确累积,两次都在裸.后正确跳转到 下一步提示,没有出现"什么?"这种续行落空的症状。本轮未额外找到可 达的留言板房间做post测试(d/kunming/kedian.lpc里唯一挂载的kedian_k留言板调用是注释掉的死代码,kedian_b这个真正生效的 留言板挂在d/city/kedian.lpc,本轮测试角色的行动范围内没有找到通 往那里的路径)——但chfn用的是与留言板完全相同的底层机制,已经 足以确认这条链路本身是好的。 - §7.90(
config.fluffos的 maximum evaluation cost):确认为5000000,此前已修复过,本轮无需改动。 - 完整 §10.7 全新角色游玩:全新账号
rfourtst完整走通注册(英 文名→确认→中文名→密码→天赋→邮箱→性别)→ 食物/饮水槽满(§8.9 修复 依然生效)→ 移动探索(欢迎室→选择"云南"分支→昆明客栈/南大街/茶馆/ 近日古楼/北大街/王府大门)→ 经济系统(茶馆list/buy买大碗茶成 功扣钱入包)→ 战斗系统(fight bing对王府亲兵非致命切磋,正确陷 入昏迷,call_out("revive", ...)在 30-130 秒随机延迟后正常唤醒, 期间score正确无输出,符合help combat文档)→ 真实死亡 (kill bing打到"你死了",进入白无常判词死亡流程,被判还阳送回 土地庙,装备/潜能按预期扣减,不是 bug)→ 多次真实断线重连(heart_ beat 持续正常工作,见上)→ 干净quit退出。全程debug.log除编 译期变量未使用警告外没有任何运行期报错。结论:本轮零新增 bug,cctx在当前完整检查清单下状态清洁。 - 本轮留下的唯一空白:因地图路径限制,没有走到一个真正生效的留 言板房间做
post测试(用chfn间接验证了同一机制),也没有重复 验证经济系统的sell(第三轮已验证过sell/value正常,本轮只 重新确认了buy);门派拜师系统本轮继续未测试(同第三轮记录的理 由——需要巫师goto才能合理到达)。这些都不是回归重点(§7.111~ §7.114 才是),留给后续如果继续深挖。
§7.100 sweep (2026-08-19)
Fixed the corpus-wide inherit ROOM; ... replace_program(ROOM); redundant-replace bug (AGENTS.md §7.100). 2081 live occurrences deleted: 2073 via scripted sweep (fix_710_room.py), plus 8 hand-fixed: 5 real .lpc source files under d/quanzhou/shaolin/xingsu/binaries/ (a real-content directory misleadingly named like a compiled-binaries dir — the sweep script's binaries-directory exclusion, meant to protect driver-compiled artifacts, false-negatived on it; caught by this batch's mandatory post-sweep work/-wide recheck) fixed with the same scripted logic applied directly; clone/misc/roommaker.lpc's string-builder template; d/shenlong/lwta2.lpc (call shared a line with unrelated code: setup(); replace_program(ROOM); set("outdoors", "shenlong");); d/gumu/bingqifang.lpc (space before semicolon). ~70 already-commented-out instances left untouched. Verified via build-debug driver boot: clean compile, zero new "cannot replace"/"cannot bind" debug.log lines; confirmed serving via raw-socket connect on port 40161. Pre-existing untracked test-account debris under data/{login,user}/ confirmed left untouched.
§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-08-24)——补上前三轮都推迟的最后一项空白,测试清洁,无需修复
前三轮一直把门派拜师(bai/apprentice)测试推迟,理由是师傅 NPC
都在 d/heimuya/d/huashan/d/shaolin/d/wudang 这几张离新手区很
远的地图上。本轮直接用巫师账号 goto 快速定位,补完这最后一项空白。
- 按 AGENTS.md §7.117 的写法专门核查了
cmds/skill/bai.lpc和cmds/skill/apprentice.lpc(两个文件字节相同):确认收徒确认分 支里的"背叛师门"判断已经带有正确的存在性守卫——if (me->query("family") && ((string)me->query("family/family_name") != (string)ob->query("family/family_name")))——和已经关闭的 §7.117 语料库扫描给出的标准修复形状完全一致,不是尚未扫到的漏网实例, 无需修复。 - 顺带发现一处形状相似但未构成崩溃的死代码:同一个确认分支里紧 跟着一段风清扬专属彩蛋逻辑,
if (((string)me->query("family/ master_id" == "feng qingyang")) || ((string)me->query("family/ master_name" == "风清扬")))——==在query()的括号内先被求值, 所以实际传给query()的是布尔比较结果(恒为 0 的 int),而不是 字符串属性名,和 AGENTS.md §7.117 收录的sj崩溃实例是同一类"括 号位置放错"手误。区别在于sj那份dbase.lpc会在strsrch()上真崩溃,而cctx这份feature/dbase.lpc的query(int, ...)能在undefinedp(dbase[prop])分支里安然处理非字符串 key,不抛任 何错误,只是静默返回假值——现场验证:整个拜师流程走完debug.log零运行期报错。净效果是"风清扬门下弟子数"这个纯彩蛋计 数器(/log/nosave/FENG)对任何师傅(包括真的风清扬)都永远不会 触发,是一处已经死掉但从不出错、也没有任何玩家可见负面影响的花絮 功能——按本项目"没有错误信号(崩溃/debug.log/明确断裂路径)大概率 是设计使然"的判断标准,不touch,只记录在此供将来参考,不作为本轮 修复项。 - 现场验证:巫师账号
goto /d/shaolin/fzlou2(方丈室),对少林 寺方丈玄慈大师bai xuanci——他的attempt_apprentice()明确要求 申请者已经是本派某一辈分以上的弟子("你辈份不合,不能越级拜师", 即少林方丈这一角色的收徒逻辑本来就是给已有身份的少林弟子做"升 级",不是给外人做入门拜师),对全新角色正确拒绝,符合设计,不是 bug;bai cancel正常取消挂起的拜师意向。再goto /d/heimuya/ house1,对日月神教西方失败bai xifang——attempt_apprentice()只检查悟性门槛(query_int() >= 20),全新角色资质达标,直接recruit,双方确认拜师礼成功完成:「师父!」磕头动作 +恭喜您 成为日月神教的第三代弟子提示。随后score正确显示日月神教第三 代弟子 巫师甲和你的师父是西方失败,确认门派/师父信息真正落地到 角色状态,不只是一句提示文字。全程debug.log除编译期未使用变量 警告外零运行期报错。测试角色(巫师/管理员账号fluffos)用完后quit干净退出并删除其存档,driver 已停止。 - 结论:门派拜师系统功能正常,本轮零新增 bug。至此
cctx第三轮 记录的"经济系统和战斗系统均验证正常工作……门派拜师系统本轮未能实 际验证"这一唯一空白正式补齐关闭,四轮 §10.7 深度功能测试全部完 成。
深度功能测试(§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)— here-document terminators
scripts/lpc_fix_heredoc_terminator.py --all --apply: 5 here-document block(s) repaired (4 with the terminator glued to the last text line, 1 with it indented), so End of file in text block no longer hides the room or object behind them: d/heimuya/shenggu.lpc, d/heimuya/tang.lpc, d/heimuya/npc/tang.lpc, d/city/library.lpc, cmds/hufa/ban.lpc. The terminator must start its line (the lexer's own test, KB 04 §6.10); a glued one lost its newline in the GBK -> UTF-8 conversion together with a half character, which stays out.
深度功能测试(§10.7,2026-10-04)— paths named in another case
The archive comes from a case-insensitive host: files are stored as BAGUA0.lpc, longjing.C, d/SHAOLIN/, the code names them in lower
case (__DIR__ "bagua0", "tea/longjing", "/d/shaolin/..."), so the rooms, NPCs and items behind them could not be loaded (a .C file is
not an .lpc file; KB 03 §4.5). scripts/lpc_case_paths.py --convert --apply cctx: 2 file(s) renamed to lower case (.C -> .lpc,
.H -> .h) and 0 path reference(s) in 0 file(s) rewritten to the new spelling; 0 skipped, 0 ambiguous. Load check of the 5 objects that were renamed, edited or name a renamed path (HEAD against the working tree, an object is the same under any spelling of its path): 3 PASS -> 5 PASS, 0 that loaded before fail now, 2 more load.
2 files moved (2 .C); mostly under d/shenlong/JIULOU.C (1), d/shenlong/LGFROAD1.C (1). A rescan with scripts/lpc_warnings.py cctx is still due: the renamed files are compiled for the first time.
深度功能测试(§10.7,2026-10-05)— room base survives a raising NPC
scripts/lpc_resilient_room.py --apply: make_inventory() of inherit/room/room.lpc loads each inventory object as if (catch(ob = new(file)) || !objectp(ob)) return 0;. new() of a file that is not there returns 0 (the room just lacks that NPC), but new() of a file whose create() raises (a skill file for set_skill() this archive never had, a carry_object() item that is not there, a header that never shipped) raised inside the room and the room did not load at all. The wrong-case renames of this lib (the section above) make the NPCs behind them reachable for the first time, so a room that holds one with such a content gap would have gone from "NPC missing" to "room missing"; now it loads without that NPC, as it did before. The room base compiles and loads with the change (HEAD against the working tree). KB 03 §4.5.
深度功能测试(§10.7,2026-10-05)— tail() simul_efun
scripts/lpc_add_tail.py --apply: cmds/app/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: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;全库 6281 个对象 HEAD 对工作树的加载检查:6094 -> 6170,新增 76 个可加载,无回退。
深度功能测试(§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-08)— 编译警告整理
scripts/lpc_warnings.py cctx --fix 加 scripts/lpc_fix_no_effect.py --apply,共改动 350 个 .lpc 和 6 个 .h(多为删去未用的局部变量)。HEAD 与工作树分别加载(新进程):325 -> 325 通过,无回退;改过的头文件的 115 个包含者 115 -> 115 通过。启动时警告 13 -> 0;新进程登录(输入名字)正常。
附带:HEAD 时连线画面会把启动时的编译警告(/adm/daemons/band.lpc:63:1: warning: Unused local variable 'i')直接显示给玩家;这次整理后连线画面不再出现警告。
- 2026-10-10:编译警告第二轮(按驱动报告逐条修):按位 & 改逻辑运算 0 处,返回类型/原型 12 处,NPC+F_UNIQUE 的 init() 0 个,带初始化的未用局部变量 0 个,只在 #if 分支用的声明移进分支 0 个文件;改动 11 个文件,HEAD 与工作树各载入一次无回退(11 objects; HEAD PASS 10, tree PASS 10; regress 0; newly loading 0),这些文件的警告 12 -> 0。
深度功能测试(§10.7,2026-10-12):编译警告收尾
- 起点(能编译的文件中):64 条
F() inherited from both A and B、16 条Redeclaration of global variable、2 条Extra ';'(另有三个小贩文件各 28 条重复声明,但它们原本编译失败)。 inherited from both64 条全是同一文件经两条路径进入:16 个 NPC/物件在inherit NPC;之外又inherit F_CLEAN_UP;(12 处)或F_SKILL;(4 处),而 NPC(/inherit/char/npc)本身已含这两个特性。删去多余的inherit,文件里没有clean_up::/skill::这类限定调用,行为不变。- 小贩
d/city2/npc/xiaofan.lpc、d/shaolin/npc/xiao-fan.lpc、d/taishan/npc/xiao-fan.lpc写成inherit NPC; inherit F_VENDOR;,而/feature/dealer.lpc(F_VENDOR)自己就inherit NPC,于是整套角色基类被继承两次,is_busy/enable_player等 nomask 函数“被重定义”,三个文件一直编译失败,这三个小贩从来没出现过。照d/lanzhou/npc/xiaofan.lpc的写法只留inherit F_VENDOR;,现在能载入,84 条重复声明警告一并消失。 d/dali/huanggong/npc/dao.lpc和bak1/dao.lpc的int ask_dan(); ;删去多余分号。- 未发现 §7.239(空壳函数压过真函数)型问题:没有两个不同文件定义同名函数的菱形。
- 剩余:
kungfu/skill/shenghuo-lingfa/xiyanling.lpc的Expression has no side effects是语法错误后的恢复噪声,该文件本身不能编译,不在本轮范围。 - 结果:能编译的文件中警告 82 -> 0;全库 6177 -> 6180 个文件能编译。改动 21 个
.lpc,HEAD 与工作树各载入一次(新进程):21 个对象载入无回退(HEAD PASS 13, tree PASS 16; regress 0; newly loading 3),其余 5 个两边都因运行期权限/数据问题失败,与本次改动无关。
- 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 个文件因
Type of returned value doesn't match function return type ( int vs void )整份不编译:声明为void(或没写类型)的函数却返回值,旧驱动照样把值交给调用者。调用者要用返回值的(add_action 处理函数、命令、辅助函数)改为它实际返回的类型:serve_cai()。新进程比对 HEAD 与工作树:1 个对象,新增载入 1,回退 0(scripts/lpc_fix_void_return.py,KB 04 §6.3)。
- 2026-10-14(补):上面改成有返回值的函数里残留的空
return;改为return 0;(值不变,消除Non-void functions must return a value)。
- 2026-10-14:1 个文件用了颜色宏(
HIW、NOR)却没有#include <ansi.h>(首个错误syntax error, unexpected L_STRING);开头补上;2 个文件的函数声明为int(或void)却返回字符串、对象(int query_seal() { return "…"; }),旧驱动照样把值交给调用者;改为实际返回的类型(scripts/lpc_fix_void_return.py)(KB 04 §6.1、§6.3)。新进程比对 HEAD 与工作树:3 个对象,新增载入 3,回退 0。
无门派玩家的 family 映射(2026-10-15,KB 05 §7.30 第三种)
mapping fam = ob->query("family"); 之后直接 fam["family_name"]:没有门派(新人或叛师后)的玩家在学习、练功、拜师、进入门派房间时报 Value being indexed is zero,而不是作者写好的提示。7 处在声明行加上 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)。
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):/d/gvmt/npc/yuzu。
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。5 处补上 if (!mapp(fam)) fam = ([ ]);(刚 recruit_apprentice() 之后的除外)。
圣火令法「吸焰令」从未编译通过(2026-10-15)
shenghuo-lingfa/xiyanling 原档 else if (!objectp(weapon = target->query_temp("weapon")) 少一个右括号,文件编译失败,这一招从来用不了;后面的兵器判断 skill_type != "tieling" || skill_type != "shenghuo-ling" 恒为真,就算编译通过也只会说“你使用的武器不对”。补上括号,兵器判断照同目录的 duo 改为 skill_type != "lingfa"(本库的铁令、圣火令都是 lingfa 类兵器,shenghuo-lingfa 也只能 enable 为 lingfa)。
技能名拼错(2026-10-15,KB 06 §7.249)
query_skill() 里的技能名拼错了,或用的是本库改名前的旧名;本库没有这个技能,调用永远得 0:门槛(< N 就拒绝)永远过不去,相关功夫或绝招学不了、用不了;内功互斥(> N 就拒绝)从不生效;公式里这一项一直是 0。经汉字名(提示文字或中文名词典)或纯拼写差异(_/-、少一个连字符、相邻字母颠倒)核对后,改为本库的技能名(scripts/lpc_fix_skill_typo.py):beimin-shengong→beiming-shengong(bahuang-gong、hamagong、huagong-dafa、huntian-qigong、hunyuan-yiqi、jiuyang-shengong 等 14 个文件);mizongxinfa→mizong-xinfa(longxiang/fanchang);tanzhi_shentong→tanzhi-shentong(tanzhi-shentong/hui)。
银索金铃「点穴」对空手的对手报错(2026-10-15,KB 06 §7.246)
yinsuo-jinling/dian 失手时三种描写之一是“真气贯注”加对手兵器的名字,对手空手时 ob 为 0,三次失手有一次报错。改为 (objectp(ob) ? ob->query("name") : "全身")(泥潭一系原本就写作“真气贯注全身”)。
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)。给映射赋值的写法未动。
存档读不出来:字符串里的换行、空行(2026-10-15,KB 03 §4.4)
data/mail/s/smile.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/wind/),本库没有这些房间。本库的 move() 用 call_other(dest, "???") 载入目的地,找不到文件就报 call_other() couldn't find object,后面的语句都不执行:被雇来打晕或杀人的李凌(d/city2/npc/liling2、d/jingzhou/npc/liling2)办完事要离开时报错,留在原地(d/city2/npc/liling2、d/jingzhou/npc/liling2 本身还载入不了:create() 里 carry_object() 的物品文件缺失或编译失败,见 KB 06 §7.73,另行处理)。2 个文件改为移进本库的虚空房间 VOID_OB(/clone/misc/void),与原作把它们“停放”在巫师房间的用意相同。
NPC 带着本库没有的物品,载入失败(2026-10-15,KB 06 §7.73)
48 个文件、63 处在 create() 里 carry_object("<本库没有的文件>")->wear()(或 wield()、set_amount()):carry_object() 得 0,接着的调用报 Bad argument 1 to EFUN call_other(),NPC 根本载入不了,该有它的房间里就少了这个人。多是从别的系统搬来的 NPC 用了原系统的物品路径(最常见:/d/mingjiao/obj/baipao、/d/dali/huanggong/npc/bak1/obj/junfu、/d/tangmen/obj/zhuyebiao1)。每处改为 { object carried_ob = carry_object(...); if (carried_ob) carried_ob->wear(); }(scripts/lpc_guard_carry_object.py):NPC 照常出现,只是不带这件东西;文件补回来(或是虚拟对象)照样会带上。载入检查:改动的文件改前能载入 0 个,改后 37 个(37 个原来载入不了),没有退步;其余 10 个另有原因(多为 set_skill() 了本库没有的武功)。
水潭里 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 载入不了,刷出它的房间也少一个人。本库有 10 个对象设了本库没有文件的武功(7 个名字,最多的是 tiannong-shengong、lingbo-steps、shaozhe-jian)。三处都改成 return:这一门武功不给、不映射,对象照常载入,只是少了它(缺的武功本身仍是内容缺口)。抽样载入这些对象:10 个里 7 个通过,其余 3 个停在别的错误上(d/dali/huanggong/npc/bak1/duanyu:*No program in object '/d/dali/huanggong/npc/bak1/duanyu'!;d/dali/huanggong/npc/duanyu:*No program in object '/d/dali/huanggong/npc/duanyu'!……)。(scripts/lpc_guard_set_skill.py)
通向不存在房间的出口,按对面房间的回头出口改正(2026-10-18,KB 06 §7.257)
房间出口 "west": __DIR__"xxx" 指向的文件本库没有,玩家走过去就被卡住(笔误、改过名的房间,或者没带进档案的编号房间)。对面的房间存在、并且它相反方向的出口正好指回这个房间,说明出口原本就是通向它:/d/changan/taibaiju1 的 up:zuixianlou2 → taibaiju2;/d/emei/duguangtai 的 north:huazangzn → huazangan;/d/emei/jietuopo 的 west:guanyitang → guanyintang;/d/emei/jiulaodong 的 northeast:jiudaoguai4 → jidaoguai4;/d/mj/temp/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 映射不到,门派弟子用普通轻功/拳脚)。按核对过的对照表改正,共 2 处、2 个文件:xinxiu-duzhang→xingxiu-duzhang(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)
全局头文件丢了 1 个宏(2026-10-19,KB 04 §6.16)
/include/globals.h 里没有定义 MAILDIR,用到它们的物件(名单里 1 个)编译时报 Undefined variable/Undefined function,整个物件载入不了(编译器在第一个未定义的名字上停下,后面的错误和警告都看不到)。同系的库在各自的头文件里都有这几行:照其中和本库共有文件最多的那个库,原样补到 /include/globals.h 最后一个 #define 之后,宏体里出现的路径在本库里都存在。名单里的物件除了这几个宏之外还有别的错误,暂时仍载入不了。(scripts/lpc_restore_defines.py)
出口指向不存在的房间(2026-10-19,KB 06 §7.257)
下列房间的出口写的文件不存在,而对面恰好只有一个房间的出口指回本房间,所以按对面的房间改正(笔误、大小写、路径少了一级):
/d/chongyang/qzroad4.lpc的southwest出口:qzroad3.c.lpc→qzroad3
改后房间照常载入(与 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 03 §4.7、KB 04 §6.10)
d/city2/bingqiku.lpc(东厂兵器库)把北面的出口注释掉了(bingyin1这个房间不存在),却留着create_door("north", ...),驱动报Room: create_door: attempt to create a door without exit.,房间载入不了。删掉那一行门。
逐个载入与 HEAD 对比,没有退步。
玉蜂的年龄(2026-10-19,KB 06 §7.273 同类)
d/gumu/npc/yufeng.lpc(玉蜂)的 create() 写 age = this_player()->query("age") + random(40);:房间刷新时没有人在场,this_player() 是 0,旧驱动答 0,新驱动报 Bad argument 1 to EFUN call_other(),古墓密林 d/gumu/milin2–milin4 里的蜜蜂刷不出来,--walk 检查时这几个房间也走不进去。改成 (this_player() ? this_player()->query("age") : 0) + random(40),有玩家在场时年龄仍随玩家。同类写法在别的库多半是玩家召唤物(mind_beast 等,在命令里创建),不是缺陷;只修了普查(reach census)报告的这一处。
玩家打造兵器模板没有打造者时(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 04 §6.15、§6.18)
宏有定义、基类文件却不在档案里:继承它的对象载入时报 Inherited file '…' does not exist!,编译扫描看不到这一类(scripts/lpc_missing_inherits.py 能列出)。同系的库里有同一个文件,原样拷来(scripts/lpc_restore_bases.py);基类和继承它的对象 include 而本库没有的头文件一起带来。每个基类补回后单独载入,再载入使用它的对象,载不进来、或一个用户也载不进来的撤掉了。
/inherit/recordable_room←xkxyb:1/1 个继承它的对象载入
逐个与 HEAD 对比载入,没有退步。
补回丢失的标点(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 个原来载入失败、现在载入,没有退步。
== !"字符串" 多出来的 !(2026-10-19,KB 06 §7.280)
!"taoist" 是整数 0,x == !"taoist" 就是“x 等于 0”,作者为其余所有人写的那一支永远走不到。具体是:龙女对古墓弟子的机关暗门提示永远给不出来(5 处);孙婆婆的“你去吧”只对 class 没设置的人生效;性别检查(“你不是女的,无法领会其中至阴之理”)永远不拦人,男的照样能学玉女心法。全部改成 != "字符串"(scripts/lpc_fix_not_literal_cmp.py):/d/gumu/milin1.lpc(1 处)、/d/gumu/milin2.lpc(1 处)、/d/gumu/milin3.lpc(1 处)、/d/gumu/milin4.lpc(1 处)、/d/gumu/milin_in.lpc(1 处)、/d/gumu/milin_out.lpc(1 处)、/d/gumu/npc/shaofu.lpc(5 处)、/d/gumu/obj/bpzhen.lpc(1 处)、/kungfu/class/gumu/long.lpc(5 处)、/kungfu/class/gumu/sunpopo.lpc(1 处)、/kungfu/skill/yunu-xinfa.lpc(1 处)。同样的行在 xkx 一系的 35 个库里都有。
x == "a" || "b":后面的字符串常量永远为真(2026-10-19,KB 06 §7.281)
if (arg == "yuyou" || "yu you") 里的 "yu you" 是非空字符串,永远为真,整个条件对任何 arg 都成立;作者要的是每个字符串都和变量比较。在每个字符串前补上变量和运算符(scripts/lpc_fix_literal_or.py;forrest2.lpc 是 dir == "north" && "south",手工改成 (dir == "north" || dir == "south") && ...):/d/shaolin/cjlou2.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)。改动:/d/mj/temp/shanmen.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。
华山论剑排行榜:第一场比武就读不到 /data/ladder.txt(2026-10-20,KB 06 §7.326)
比武裁判在一场比武结束时先 list = explode(read_file("/data/ladder.txt"), "\n"),读完再 rm 并 write_file 写回;/data/ladder.txt 是比武本身写出来的,全新的树里没有,第一场比武结束就是 Bad argument 1 to explode(),排行榜永远建不起来。把写回之前的那一次读改成 read_file(...) || ""(空表走原来的 lost == -1 && win == -1 分支,把第一对名字写进去);写回之后的第二次读文件已经存在,没有动。加载检查各 1/1。
NPC 的 chat() 在 chat_msg 为空数组时下标越界(2026-10-21,KB 06 §7.334)
NPC 基类的 chat() 是 if (arrayp(msg = query(...))) { if (random(100) < chance) { rnd = random(sizeof(msg)); if (stringp(msg[rnd])) ...,不检查列表是否为空。本库现有的 NPC 文件里没有字面写成空 chat_msg 的(扫描只认 set("chat_msg", ({ })));守卫挡的是运行时才为空的列表和以后新增的 NPC。在 random(100) < chance 前面加 sizeof(msg) &&(scripts/lpc_fix_chat_empty.py;if (random(100) > chance) return 0; 的写法是 !sizeof(msg) ||)。改动:/inherit/char/npc.lpc(共 1 个文件)。
存档里的 .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 个存档)。
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/blockade.lpc、/cmds/adm/recover.lpc。
socket:dump_socket_status() 在本库没有(2026-10-21,KB 06 §7.291)
管理员扫描里 socket 指令(/cmds/hufa/socket.lpc)编译不了:write(dump_socket_status()); 用的是 MudOS 有、本驱动没有的 efun。2026-10-20 的补丁只按名字找了巫师目录里的同名指令,这一条在 cmds/bos、cmds/hufa、cmds/island、cmds/ser 这类目录里;用 scripts/lpc_add_sefun.py dump_socket_status 在 /adm/obj/simul_efun.lpc 末尾补了一个由 socket_status() 构造表格的 simul_efun(没有 sockets 包的构建,比如 WASM,只打印表头)。指令 HEAD 编译失败,现在通过。
华山比武裁判 observe()(cctx):残留的 ob->set_amount(2)(2026-10-21,KB 06 §7.348)
别的库里裁判给胜者发银子:ob = new("clone/money/silver"); ob->set_amount(2); ob->move(ob2);。cctx 把发钱的几行删了,只剩 ob->set_amount(2);:第一名选手输的那几场(一半)裁判抛错。去掉这一句和没用的 object ob;。改动:/d/huashan/npc/referee.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.,同一个动词的其他处理函数不再尝试(不是最新的一条就悄悄跳过)。删除了 10 条注册(4 个文件,scripts/lpc_fix_dead_add_action.py),动词留给别的处理函数:/d/city2/fotang.lpc(do_qiao、do_unlock)、/d/shenlong/npc/byw.lpc(do_buy、do_list、do_sell、do_value)、/d/shenlong/npc/haiw.lpc(do_buy)、/inherit/misc/fboard.lpc(do_list)。最多的函数名:do_qiao 2 处、do_unlock 2 处、do_buy 2 处、do_list 2 处、do_sell 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/quanzhou/shaolin/wudang/npc/xiaocui.lpc(__DIR__ "../obj/nuerxiang" → "/d/wudang/obj/nuerxiang"), /d/wudang/npc/xiaocui.lpc(__DIR__ "../obj/nuerxiang" → "/d/wudang/obj/nuerxiang")。
目标文件的位置也改了:d/quanzhou/shaolin/wudang/npc/xiaocui.lpc 不在 d/wudang/npc/ 里,../obj/nuerxiang 指向它自己区域下的一个不存在的路径;女儿香茶杯在 /d/wudang/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 个文件里 4 处(new)改成 { object new_ob = new(路径); if (new_ob) new_ob->move(...); }(scripts/lpc_guard_carry_object.py --new:路径按这个文件自己看到的宏解析,宏名冲突、虚拟对象路径一律跳过)。 对这 3 个改动文件做加载检查(HEAD 与工作区对比):HEAD 能加载 3 个,现在 3 个(新增可加载 0 个,回归 0 个)。
(: 函数 :) 指针指向对象自己没有定义的函数(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 个函数没有补(inquiry 3):原型还在函数体丢了、或者根本没写过,没有可以直接补回的捐赠(别的库同一路径的文件里没有这个函数,或者它还要用本库没有的辅助函数、签名不同),不编造:/d/dali/huanggong/npc/bak1/duanyu.lpc:ask_about_betray、/d/dali/huanggong/npc/duanyu.lpc:ask_about_betray、/d/mj/npc/tong.lpc:ask_water。
运行期目录 log/nosave 不存在,写日志的 write_file() 直接报错(2026-10-22,KB 03 §4.3 补充)
这个库的 10 个文件里有 15 处 write_file("/log/nosave/...") / log_file("nosave/...")(static 改 nosave 时连字符串里的日志路径一起改了,原来是 log/static/):nosave/CRASHES、nosave/PURGE、/log/nosave/FENG 等。压缩包和站点包里没有这个目录,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 把 2 条单独成行的语句(/clone/board/mingjiao_b、/clone/board/gumu_b;/d/mj/zongtan.lpc、/d/gumu/damen.lpc)注释掉并写明原因(别的房间里同样的语句本来就是作者自己注释掉的)。证明和 45 个库的整体加载检查见 KB 06 §7.357。
log/ 下的日志子目录没有人建:写日志的 write_file() / log_file() 报错(2026-10-22,KB 06 §7.358)
这个库的代码往 log/ 的 2 个子目录写日志:log/cmds(cmds/ang/edit.lpc)、log/trace(d/emei/putao.lpc)。压缩包、git clone 和站点包里都没有这些目录(本地启动没有写过它们,gen_keep_dirs.py 没记),write_file() 对不存在的目录抛 *Wrong permissions for opening file /log/dlog/money for append. "No such file or directory",调用它的函数在写日志那一行中断,后面的奖励、标志、步骤都没有执行。本库的 log_file() 是 write_file(LOG_DIR + file, text),目录不存在就抛同样的错误(实测)。把 log/cmds、log/trace 记进 scripts/wasm_keep_dirs.txt(scripts/lpc_keep_log_dirs.py;站点和 pristine 树按它建空目录)。证明(scripts/lpcc_eval.py,在 /adm/daemons 这类目录下的求值对象里写 /log/zzdirprobe/...,新进程)见 KB 06 §7.358 的实测表。
(: 函数名 :) 指针指向本库没有的函数:只含这个指针的行加了注释(2026-10-22,KB 06 §7.355 补充)
inquiry / item_desc / chat_msg* 里的 (: 函数名 :) 指向本对象(含包含文件、继承的父类)没有函数体的函数:用到时(ask、look、NPC 闲聊)驱动抛 *Undefined lfun pointer called: 函数名,这一拍心跳的后半段被跳过。这些函数没有可以补回的来源(别的库同一路径的文件里没有,或者它还要用本库没有的东西),所以 3 个文件里 3 行只含这个指针的行("叛师": (: ask_about_betray :), "茶": (: ask_water :),)加了注释,原文保留并写明原因,这一项当作没有这个话题 / 物品 / 闲聊条目(scripts/lpc_fix_dangling_lfun.py;#include 的文件在库里缺失的对象、指针不在整行上的写法没动)。 前提(function_exists())和加载检查(HEAD 与工作区对比,本库改动的 .lpc 文件)的结果见 KB 06 §7.355:没有一个回归。
汉字按字节切片的老写法没有换成按字符:改法名 "澄" + 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 个文件):拼名字的赋值 10 处、与汉字常量比较 9 处。例: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,不要重跑。
长度检查按字节写,旁边的提示按汉字写:2 处(2026-10-22,KB 06 §7.362)
老档的 strlen() 数字节(一个汉字 2 字节),转成 UTF-8 后它数字符:提示写「必须是 2 到 6 个中文字」的检查还是 strlen(name) < 4 || strlen(name) > 12,于是两三个字的房名、帮会名、群名、聊天室名、称号被提示自己说允许的那句话拒绝,上限却是提示的两倍;留言板的标题检查 i < 4 || i > 24 || i % 2 还会拒绝所有奇数个字的标题(post 你好吗)。本库 2 处(1 个文件):if ((strlen(name) < 2) || (strlen(name) > 12)) {(/adm/daemons/logind.lpc:547)。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 区间 3 个文件。证明(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(一格两个空格)。本库 4 处(2 个文件)。证明(lpcc_eval.py hhsj):tribar_graph(6,9,12) 在 HEAD 画出整条 12 个■,改后为 6 个■+3 个□;麻将 strlen(tempB)/2 是两字符牌码,未改。
tianluo-diwang 知识武功引号剥离(2026-10-27,KB 04 §6.25 Also)
kungfu/skill/tianluo-diwang.lpc(Kayin 古墓知识武功短桩)丢了 inherit SKILL 后的 ; 以及几乎所有引号(return knowledge、query(dex)、汉字通知里字间插空格)。按原意重写成可加载的 knowledge skill(未并入带招式的战斗版手足)。证明:HEAD 加载失败;改后加载成功。
jmqshenmu 截断 init(2026-10-27,KB 04 §6.25 Also)
d/mj/temp/jmqshenmu 在 void init() { 处结束。补 }。证明:HEAD 失败;改后加载。
深度功能测试(2026-10-27,§6.25 one-arg message_vision)
message_vision("…") 补第二参(me / TP / this_player())。