info.html · 介绍 · play.html · 游玩 · llms.txt · 下载与本地运行 · ZIP · GitHub
游戏内标题为《武林群侠传》之炎黄武魂,`master.lpc` 文件头注明完整传承脉络:"for ES II mudlib... updated by Doing Lu for hell (2K), modified by Linux@lxtx for yh 2003.3";文件级比对显示本档案与同系列 `yanhuangwuhun`(对方标题干脆加了个"Ⅱ"以示区分)96% 的同名档案逐字节相同、共享同一张 73 区地图,又与另一支同源快照 `yhyxs`(《炎黄英雄史》/皇朝再现)有 87-89% 的重合度,三者其实是同一套 2003 年"yh"分支代码的三次不同品牌打包;三者都继承了 `hell` 的地府轮回投胎仪式(阎罗殿、忘忧池),本档案把创角简化为猛士/智慧/耐力/敏捷/均衡五选一的角色类型菜单,姓名分开输入,管理密码与登陆密码双密码制且没有电子邮箱步骤,地图上还新增了"药王谷"场景,管理员权限按 ID 字符串查表即时生效、无需重新登录。
English
In-game the title reads "Tales of Wulin Heroes: Soul of Yan-Huang" — the master.lpc header traces the full ancestry: ES II → Annihilator → Xiang's XKX → Doing Lu's hell (2K) → Linux@lxtx's 2003 "yh" branch. A file-level comparison found this archive is a near-duplicate of this collection's yanhuangwuhun (96% of common files byte-identical, same 73-zone map) — that sibling even appends a "II" to its own in-game title to tell the two apart. It's also closely related (87-89% overlap) to sibling yhyxs, a third, differently-branded snapshot of the same lxtx-2003 codebase ("Chronicle of Yan-Huang Heroes"). All three inherit hell's underworld reincarnation ritual (Yama's Hall, the Pool of Forgetfulness), though this build simplifies chargen to a direct five-way archetype pick (Warrior/Sage/Endurance/Agility/Balanced) with split surname/given-name entry, dual admin/login passwords, and no email step.
README
内容亮点
- 与同血统手足
yhyxs/yanhuangwuhun(yh2003 分支)一样,转档管 线遗漏了 3 个无后缀的纯文本档案:help/rules(游戏规则,投胎完 成时自动展示)和纸牌小游戏说明clone/game/{8,21}_hlp,一直是 原始 GB18030 字节,本轮已按 §4.1 的既有先例转码为 UTF-8。
本次修复的关键 bug
1. 经典的 §8.1 GBK 字节区间 is_chinese() 问题(奇偶校验 +
176-247/161-254 字节区间判断)——改成逐码点的
0x4e00-0x9fff 判断,且改成检查每一个字符,而不只是第一个。
2. 三处同源的"字节数减半"长度边界 bug,都需要按这台驱动逐码点
字符串索引的方式减半:check_legal_name() 的下限
(strlen<2→strlen<1)和上限(maxlen→maxlen/2);
get_name() 里姓名合并后的最短长度判断
(strlen(fname)<4→<2);以及 named.lpc 的
invalid_new_name() 滑窗查重逻辑(下限 2→1,切片
name[i..i+3]/name[i..i+5]→name[i..i+1]/name[i..i+2],
循环上限 l-4→l-2,判断门槛 i+6<=l→i+3<=l)。修复前,单
字姓氏(比如"张")会被误判"太长",任何两字全名都会被误判"太
短"。
3. master.lpc(注意路径是少见的 adm/single/master.lpc,不是
常见的 adm/obj/master.lpc)的 valid_read()/valid_write()
直接转发给 SECURITY_D,没有标准的
user == this_object() 短路判断——补上后修复了注册流程中
new() 静默失败卡死的问题。
4. versiond.lpc 的 in_server() 计算
get_config(__MUD_PORT__) + VERSION_PORT 在这台 WASM 驱动
下没有得到预期的整数,导致端口变成了字符串拼接结果
"12",每次开机都会在 socket_bind() 上崩溃报错"Bad argument
2"。按 AGENTS.md §7.52(做法和 hell 系同一份 versiond.lpc几
乎一致)掏空了全部 13 个碰 socket 的函式(in_server、
connect_server、clear_syn_info 里的 socket_close 循环、
send_command、send_client_pending_msg、syn_finish 里的
socket_close、in_listen_callback、in_write_callback、
in_close_callback、cmd_close、send_pending_msg、
send_result、remove_connection 里的 socket_close),周围
不碰 socket 的版本追踪逻辑原样保留。
5. §7.50 is_killing(object) 与 is_killing(string id) 类型不
匹配,在 15 处呼叫点(kungfu/skill/*.lpc 10 处、
clone/user/user.lpc、clone/lonely/sheying.lpc、
d/city/npc/guidao.lpc、cmds/std/surrender.lpc、
cmds/std/ansuan.lpc)统一改成 ->query("id") 包装。
adm/daemons/ftpd.lpc 和 adm/daemons/network/dns_master.lpc 都
已经在 adm/etc/preload 里被注释掉,而且除了各自 network/ 目录
下的兄弟档案外没有其它呼叫者,属于完全休眠状态,本次没有改动。
后续 §10.7 深度功能测试(2026-08-07)额外发现并修复(详见
NOTES.md):
6. 项目 4 当时只是给 versiond.lpc 一个受害者打了补丁(AGENTS.md
§7.52 掏空 socket 呼叫),没有修根——同一份坏掉的
include/runtime_config.h 索引编号还坑了 messaged.lpc(跨服
UDP 聊天精灵,tell/chat 等指令依赖它),且它是每一次新登
录都可能触碰到的懒加载路径,不是可以随手掏空的休眠精灵。这
次把 include/runtime_config.h 整份换成驱动自带的权威版本,逐
一处理了三处仍在用旧符号的呼叫点。
7. adm/simul_efun/message.lpc 的 message() 包装函式只声明了 4
个必填参数,但同文件 tell_object()/write() 两处只传 3 个参
数——每次干净重启在预加载阶段就会炸(AGENTS.md §7.88 的第二个
独立实例),且和手足档案 zjdywzb 一样卡在角色创建"选品质"必
经步骤上。已改成 varargs,缺参数补 || ({})。
8. 任务系统共享的 inherit/misc/quest.lpc 的 set_information()
包装函式参数类型(string)比它转发的精灵(mixed)窄,导致
全部 8 种随机任务档案永远编译不出来(AGENTS.md §7.81 的第二个
独立实例,另一次发生在完全不同血统的 nt1 上)。已放宽为
mixed,一次性修好全部 8 个任务档案。
管理员账号 / Admin account
- ID:
wlqxztest(WASM 阶段播种,密码为当时自设、本次会话无 法复用);fluffos/MudLogin2026(本轮 §10.7 深度测试按 AGENTS.md §1.5 标准约定新增播种,两个 id 并存)。 - 权限 / Level:
(admin),通过/adm/etc/wizlist授予(这份 档案的 wizlist 是按 ID 字符串直接查表,新注册的角色无需重新登 录即可立刻看到管理权限),登录后自动显示"目前权限:(admin)"确 认生效;update/config等需要实际写权限的指令均已实测成功。
警告:对外公开架设前请务必修改此密码。
注册流程提示(供后续测试参考)
英文 ID → y(确认创建新角色)→ 中文姓氏 → 中文名字 → 管理密码 +
确认 → 登陆密码 + 确认 → 角色类型菜单(1-5,例如 5 均衡型)
→ 性别(m/f)→ 进入游戏(世外桃源)。score 需要先在游戏内完成
"出生"这一步才有数据,这是游戏设计本身的限制,不是 bug。
本地运行
cd libs/yhwhpublicfi
~/src/fluffos/build-debug/src/driver config.fluffos游戏端口:40132。
NOTES · 移植与修复记录
WASM 修复摘要(迁移自 meta.json 的 group_note)
炎黄武魂public-final-2016-12-08——一个 Doing 血统的构建版本(master.lpc 的档头注明'ES II mudlib... updated by Doing Lu for hell (2K), modified by Linux@lxtx for yh 2003.3'),游戏内标题是《武林群侠传》之炎黄武魂。注册流程用姓+名分开输入(get_surname/get_name),有双重管理员+登录密码,一个 5 选项的角色类型菜单(猛士/智慧/耐力/敏捷/均衡)代替天赋重投,没有电子邮件步骤。WASM 修复了:(1)经典的 §8.1 GBK 字节区间 is_chinese()(奇偶门槛加 176-247/161-254 字节区间检查)重写成对每一个字符(不只是第一个)都做逐码点 0x4e00-0x9fff 循环检查。(2)三处各自独立的、来自同一个 §8.1 血统的字节数翻倍长度界限 bug,全部减半以匹配这个驱动按码点计的字符串索引方式:check_legal_name() 的最小界限(strlen<2 → strlen<1)和它的最大长度界限(maxlen → maxlen/2),get_name() 里姓+名合并后的最小长度(strlen(fname)<4 → <2),以及 named.lpc 的 invalid_new_name() 滑动窗口近似名字去重检查(最小值 2→1,窗口切片 name[i..i+3]/name[i..i+5] → name[i..i+1]/name[i..i+2],循环界限 l-4 → l-2,闸门 i+6<=l → i+3<=l)——不修的话,像'张'这样的单字姓氏会被拒绝为'太长',任何两个字的全名都会被拒绝为'太短'。(3)master.lpc 的 valid_read()/valid_write()(不同寻常地位于 adm/single/master.lpc,不是常见的 adm/obj/master.lpc)在转发给 SECURITY_D 之前缺少标准的 'user == this_object()' 短路判断——两处都已加上,修复了那种静默的 new() 注册卡死失败模式。(4)versiond.lpc 的 in_server() 呼叫 get_config(__MUD_PORT__) + VERSION_PORT,期待一个整数,但 WASM 驱动的 get_config(__MUD_PORT__) 在这里没有解析成期待的类型,产生一个字符串拼接出来的端口号('12'),在每次启动时都触发'Bad argument 2 to socket_bind()'崩溃;按照 AGENTS.md §7.52(和 hell/hell 家族对同一个 versiond.lpc 血统几乎一字不差的先例一致),把全部 13 个碰 socket 的函式(in_server、connect_server、clear_syn_info 里的 socket_close 循环、send_command、send_client_pending_msg、syn_finish 里的 socket_close、in_listen_callback、in_write_callback、in_close_callback、cmd_close、send_pending_msg、send_result、remove_connection 里的 socket_close)都掏空成 no-op/notify_fail,保留周围不碰 socket 的版本追踪逻辑不变。(5)§7.50 类的 is_killing(object) 对 is_killing(string id) 类型不匹配,修复了 15 处呼叫点(kungfu/skill/*.lpc 的 10 处命中、clone/user/user.lpc、clone/lonely/sheying.lpc、d/city/npc/guidao.lpc、cmds/std/surrender.lpc、cmds/std/ansuan.lpc),全部用标准的 ->query("id") 包装函式修复。adm/daemons/ftpd.lpc 和 adm/daemons/network/dns_master.lpc 都处于休眠状态(在 adm/etc/preload 里被注释掉,除了各自 network/ 子目录之外没有其它运行时呼叫者)——保持原样未做改动。管理员账号播种:wlqxztest (admin) 加入 adm/etc/wizlist(wiz_levels 顶层是 (admin);wizlist 查找只按 ID 字符串,所以一个刚注册的角色马上就能显示管理员状态,不需要额外的存档/重新登录步骤)。注册流程多次完整验证过:英文 id→y(确认新角色)→姓→名→管理员密码+确认→登录密码+确认→角色类型菜单(1-5,用的 5)→性别(m/f)→进入世外桃源,全程干净。管理员权限已通过'目前权限:(admin)'确认。score 指令需要先在游戏内完成一个单独的'出生'步骤才能报数据,这是有意为之的游戏设计门槛,不是 bug,保持原样。LPC 格式化工具对全部 10751 个档案运行(写入 10715 个,6 个针对杂乱历史代码的转档之前就存在的错误,30 个未改动)。没有 :: 父类呼叫拆分命中,没有 case 标签带尾随注释的候选,没有 CJK 重新加空格/转义损坏命中。格式化后用同样的完整注册流程重新验证过——干净,管理员权限依然是 (admin)。
§7.86 跨库扫描修复(留言板 post 崩溃)
BULLETIN_BOARDinherit+ 多余replace_program()致命形状(AGENTS.md §7.86,post命令崩溃):全档案 61 处命中,已删除多余的replace_program(...)调用(保留inherit),逐文件保留原有行尾格式(CRLF/LF 按文件原样)。本次为跨库 §7.86 扫描修复(触发原因:该 bug 已在 6+ 个互不相关的血统家族独立确认,属于近乎普遍的拷贝粘贴模式),仅做编译检查(驱动干净启动、端口正常监听),未做完整 §10.7 深度游玩测试。
深度功能测试(§10.7,2026-08-07)
本轮之前 yhwhpublicfi 只做过 WASM 阶段的注册冒烟测试和 §7.86 的编
译级扫描修复,从未做过完整的 §10.7 深挖。这次用原生驱动
(~/src/fluffos/build-debug/src/driver,端口 40132)从 AGENTS.md
已知 bug 类别清单逐项排查,并与同血统手足档案 zjdywzb/zjdy2008wzb
(同为 Doing 系 "hell" 血统的独立分支,本 session 早前已深挖)做了
对照检查。全程用 scripts/mudclient.py(--idle 0.5-0.6)驱动;
scripts/tmux_mud.sh 在一次 born <地名> <名字> 的中文+空格组合输
入上出现了 AGENTS.md §10.2 记录过的本地 telnet 二进制吞字节现象(连
接卡死、后续任何指令包括 look 都没有任何回应),改用
mudclient.py(裸 socket,不经过本地 telnet 进程)后同一条指令立刻
正常执行——按文档指引确认是传输层问题,不是服务器端 bug。
找到并修复的 bug
- §7.88 复现,位置不同:
message()包装函式同一个 4 参数必填/ 3 参数呼叫的缺口,这次在预加载阶段就会炸:adm/simul_efun/ message.lpc的message(mixed arg, string message, mixed target, mixed exclude)声明了 4 个必填参数直接透传给efun::message(), 但同一份档案里tell_object()(message("tell_object", str, ob)) 和write()(message("write", str, this_player())/message("write", str, previous_object()))两处呼叫都只传了 3 个 参数。第一次干净重启驱动就立刻在预加载期间炸出*Bad argument 4 to EFUN message() Expected: object, array, Got: int(0).(adm/daemons/analectad.lpc的create()经channeld.lpc的do_channel()触发),说明这不是要等玩家操作才 会撞上的边缘情况,而是每次开机都会命中的系统级频道广播路径。和zjdywzb一样,这条崩溃也埋伏在角色创建"选品质"一步——在"桃源石 屋"对 NPC 花铁干out离开时,hua.lpc的check_leave()先呼叫command("chat ..."),触发同一处崩溃,把valid_leave()判断房 间放行"之前"的呼叫链整个打断(房间不放行离开,角色永远卡在桃源 石屋,紧跟着的me->set("character", ...)也永远不会跑)。修复:varargs void message(...),缺失的exclude参数补上|| ({})兜底(和同一文件里tell_room()已经用的写法一致)。 实测:修复前干净重启后预加载阶段必现该崩溃;修复并重启后预加载 期间零错误,且新角色在"桃源石屋"对花铁干out一次成功,顺利进 入"阎罗殿"。 - §7.89 复现,第三处受害对象:这次不是
versiond.lpc而是messaged.lpc(跨服 UDP 聊天精灵),且每个新连线的第一次登录都 可能命中:include/runtime_config.h的索引编号和驱动真实内部 编号不一致(和zjdywzb/ds386是同一类问题)——此前一轮 WASM 修复已经发现并"修好"了这个问题在versiond.lpc里的表现(按 §7.52 掏空了in_server()等函式里的全部 socket 呼叫),但那只 是给一个受害者打了补丁,没有修根。这次深挖发现同一份坏掉的runtime_config.h还坑了另一个完全独立的精灵:adm/daemons/network/messaged.lpc(MESSAGE_D,一个跨服 UDP 聊 天/私聊路由精灵,游戏内tell/chat/"缥缈虚空"聊天室子系统重 度依赖它,不是可以随手掏空的休眠精灵)。logind.lpc的check_ok()(每一次没有存量在线/断线重连身体的登录都会走到, 不分巫师还是普通玩家)无条件呼叫MESSAGE_D->find_chatter(ob->query("id")),这是这份档案里第一次 触碰MESSAGE_D的地方,触发它的懒编译;其create()→startup_udp()→socket_bind(socket_id, my_port)里my_port = LOCAL_PORT() + MESSAGE_PORT,而LOCAL_PORT()依赖的get_config(__MUD_PORT__)——__MUD_PORT__在这份档案自带的坏头 文件里编号成CFG_INT(0)= 14,但驱动真实的内部第 14 号槽位是 一个字符串型配置(__MUD_IP__)——取到的是空字符串而不是整数,"" + 10在这台驱动上做的是字符串拼接而不是数字加法((int)强制转型对这种类型不匹配的场景是编译期语法糖、并不真正在运行时 强制转换),my_port变成字符串"10"。传给socket_bind()直 接因参数类型不对被拒绝报错,把check_ok()从中间截断——这一步 之后的make_body()/enter_world()永远不会跑。用真实游玩会话 实测复现:一次约 12 分钟的连续测试会话中,这个崩溃只在某次连线 第一次真正触碰MESSAGE_D(不是重连/不是已有身体分支)时出现过 一次,之后该精灵已经常驻内存,不会再重复。这次没有再用"单点掏空 某个精灵的 socket 函式"的补丁思路,而是做了根因修复:把include/runtime_config.h整份换成驱动自带的权威版本 (~/src/fluffos/src/include/runtime_config.h),然后逐一处理三 处仍在用旧符号的呼叫点——versiond.lpc(__SAVE_BINARIES_DIR__, 只用于一行路径前缀比较)别名到__MUD_LIB_DIR__(新头文件里始终 有值,和zjdywzb/ds386先例一致);cmds/arch/config.lpc的__ADDR_SERVER_IP__(一行纯展示用的巫师config指令输出,这个 驱动版本压根没有 addr_server 概念)直接删除这一行;同一个指令里 的__BIN_DIR__——虽然新头文件里这个符号本身还在,但这台驱动的read_config()从来不往这个槽位写值(rc.cc的STR_FLAGS表里 根本没有对应的配置项),直接get_config()会抛错而不是安静地 返回空字符串,所以额外包了一层catch(),取不到就显示"(未 知)"而不是让巫师的config指令崩溃。同时在logind.lpc的check_ok()里给MESSAGE_D->find_chatter()呼叫加了find_object(MESSAGE_D)前置判断(AGENTS.md §1.3c 的标准写法), 作为双重保险。实测:修复并重启驱动后,用巫师账号tell fluffos hello主动触发messaged.lpc的懒加载,debug.log零socket_bind/错误记录,指令正常回应"这个用户没有登录,你无法和 他交谈。";巫师config指令完整跑出 Mud 名称/Mudlib 路径/执行 档路径(空白但不崩溃)三行加上运行时配置表,无任何报错。 - (新增 AGENTS.md §7.81 第三例)任务系统共享的
set_information()包装函式参数类型比它转发的精灵窄,导致全部 8 种随机任务永远编译 不出来:inherit/misc/quest.lpc(被clone/quest/下每一个任 务档案inherit)声明了void set_information(string key, string info),只是单纯转发给adm/daemons/questd.lpc/questd2.lpc的set_information(object qob, string key, mixed info)——精灵那边 第三参数本来就是mixed。但clone/quest/{capture,shen,judge, deliver,search,trace,supply,explore}.lpc(全部 8 个任务类型)的register_information()都是set_information(NPC1_NAME, (: ask_npc1 :))这种传闭包的写法——对精灵的mixed契约完全合法, 却被本地这层过窄的string info类型声明在编译期直接拒绝 (Bad type for argument 2 of set_information ( string vs function )),8 个任务档案全部编译失败。因为这是clone/下的 内容档案编译错误,不是启动期的致命错误(new()一个编译失败的 档案只会得到一个空程式对象),完全没有任何启动期症状——真正暴露 出来是各任务类型自己的精灵(adm/daemons/quest/{capture,shen, judge,deliver,search,trace,supply,explore}.lpc)的heart_beat()周期性呼叫start_quest()尝试实例化对应的clone/quest/*档案 时,反复报*No program in object '/clone/quest/capture'!这类 错误——8 个任务类型各自独立、周期性地反复报错,debug.log里 快速堆积。这正是 AGENTS.md §7.81 已经在完全不同血统档案nt1上记录过的形状(同样是inherit/misc/quest.lpc的set_information窄类型 wrapper,同样是那 8 个任务档案名字), 这是该 bug 类别的第二次独立确认,跨越两个完全无关的血统家族 (NT/nitan 家族 vs 本档案的 Doing/hell 家族),进一步证实这是这 一类"共享 wrapper 类型比它转发的精灵窄"的通用陷阱,不是某个血统 自己的独有问题。修复:把string info改成mixed info(单文件 改动,一次性修好全部 8 个任务档案,内容档案本身完全不用动)。实 测:修复并重启驱动后,用巫师账号对全部 8 个clone/quest/*档案逐一update,全部显示"成功!";debug.log全程零"No program in object"/"Bad type"记录。 - 一次性会话结论:README 已记录的 §7.52 versiond.lpc 掏空补丁本 身没有问题(
in_server()等 13 处 socket 呼叫掏空后确认没有残 留,versiond.lpc独立编译、独立运作正常)——只是当时的排查止步 于"这一个精灵不再崩溃",没有意识到runtime_config.h的编号错位 是可以坑到任意精灵的系统级根因,这次借着深挖顺手补上了真正的根 因修复。
转档遗漏:三个从未转码的 GBK 遗留文本档案(AGENTS.md §4.1)
用整棵 work/ 树的 Python UTF-8 解码扫描(排除 backup/、字体、
二进制存档等已知非文本内容)找到 3 个仍是原始 GB18030 字节、从未
被转档管线处理过的无后缀纯文本档案,和 §4.1 记录的 yhyxs/
yanhuangwuhun(同为 yh2003 血统的手足档案)一字不差是同一批档
案:
help/rules——"游戏规则"说明,d/register/yanluodian.lpc的do_born()在每一个新角色完成投胎的那一刻自动呼叫HELP_CMD->main(me, "rules")展示;也可以用help rules主动查 看。实测:修复前新角色投胎完成的瞬间和手动help rules都会看到 整屏乱码;用iconv -f GB18030 -t UTF-8转码后,同一个已投胎角 色的help rules显示完整、语法通顺的"游戏规则"正文("本游戏改 编自微尘的「终极地狱」……"),无乱码。clone/game/8_hlp、clone/game/21_hlp——clone/game/pai.lpc(客店茶房一带的纸牌小游戏道具)用read_file(__DIR__ + arg + "_hlp")动态拼路径读取的"玩 8 张"/"玩 21 点"游戏说明,helppai指令会触发。转码后直接 GB18030 解码验证内容通顺("牌桌玩8张使用 方法:""牌桌玩21点使用方法:"),未在实机上找到牌桌道具触发helppai做二次确认(预算有限,未追踪道具具体摆放位置),按 §4.1 的既有先例视为同一批遗漏内容,一并修复。
kungfu/skill/huashan-quan/MFM1992、clone/game/{8,21}_hlp 之外的
clone/game/ 目录里还有几个类似命名的档案——检查过没有任何 .lpc
引用 MFM1992,是未被任何代码路径引用的死档案(file(1) 误判成
"OpenPGP Secret Key",实际是随机二进制游戏数据),未做处理。
adm/etc/font/ 下的位图字库档案(Asc12/Hzk16 等)本来就是二进
制,不在转档范围内。
已确认没有踩中的已知 bug 类别
- §7.68 幽灵卡死重试守卫:本轮测试全程没有触发角色死亡(见下), 未观察到相关现象;不适用/未触发,按文档要求不主动移植该修复。
- §8.3a/§8.3b 指令表:
yhwhpublicfi本身已经在更早一轮的 repo-wideprivate command_hook扫描里被列入并修好(AGENTS.md §8.3a 命中列表),这次复核commandd.lpc(若存在)未见sscanf(...".c"...)残留形状;look/score/i/kill/post/tell/update等指令全部正常响应。 - §8.9 食物/饮水初始化:
logind.lpc第 769 行本来就是if (user->query("age") == 14),读的就是刚setup()过的user对象本身,不是登录桩对象ob——不适用,无需修复。 - §7.92
user_cwd():adm/simul_efun/path.lpc的user_cwd()本来就是"/u/" + name(扁平路径),和这份档案本 来就是扁平的u/(只有u/ivy一个巫师目录)完全匹配——不适用。 - §7.94 指令档案丢失
.lpc后缀:cmds/下大量.c.bak/.alias档案乍看像是这个类别,但逐一核对后每个.c.bak都有对 应的、内容正常的同名.lpc现役档案(look.c.bak↔look.lpc、score.c.bak↔score.lpc、set.c.bak↔set.lpc等),这些只是 历史备份,不是丢失后缀——不适用。 - §8.10 版本握手重试误路由:
logind.lpc的三处input_to("get_id", ob)都是同一个get_id()自身的重试分支 (非法英文名/取消确认后请求重新输入),没有类似 Tomud 家族那种get_id()/get_id1()两段式版本握手结构——不适用。 - §8.11
@TEXT内嵌宏未展开:走查过logind.lpc/yanluodian.lpc里所有玩家可见的多行@TEXT块,未发现内嵌未 展开的#define常量名。
实机游玩记录
用新注册的测试角色「秦风」(yhwhtest,均衡型,天性阴险奸诈,出
生地"扬州人氏")完整跑了一遍:
1. 完整投胎仪式:英文 id → y → 中文姓"秦"(单字,验证 WASM
阶段修的字节界限 bug 没有回归)→ 中文名"风"(双字)→ 管理密码
+确认 → 登录密码+确认 → 角色类型菜单选"5"(均衡型)→ 性别
m → 世外桃源。对花铁干 out(触发本轮新修的 §7.88 message()
崩溃点)→ 阎罗殿,地藏王塞了本"天书"。washto 20 20 20 20(四
项天赋各 20,合计 80)→ born 扬州人氏 → 进入"客店",score
显示膂力/悟性/根骨/身法各 20、天性"阴险奸诈"、出生地"扬州人
氏",和实际操作路径完全对得上。
2. 移动:客店 → south → 客店茶房(扬州客栈茶园)→ north 回客
店;另一条路线 west → 北大街 → south → 中央广场 → south → 南大
街,沿途房间描述、出口列表、NPC 列表均正常显示,无一处
"No such object"/环境缺失。
3. 留言板:post board 打开内建行编辑器,输入标题正文,.
结束,"留言完毕";look board 显示"[ 1] board ... 秦风-
yhwhtest",退出重连后未读计数正确显示"1 张留言,1 张未读"——
确认 §7.86 的跨库修复在这份档案上真实生效,不只是编译期检查。
4. 战斗:南大街对"流氓头"(四位流氓中带头的强化个体,比普通
"流氓"更硬)发起 kill,双方多回合正常拳脚攻防(命中/闪避/擦
伤消息、伤害数字提示),秦风连续中招约 24-40 点伤害后触发游戏
自带的"看来该找机会逃跑了……"自动脱战机制,安全撤到隔壁"赌场"
房间,没有死亡,也没有任何崩溃或异常。之后专门去挑一般"流氓"
(数值更弱)重新开战,同样正常攻防几回合后再次自动脱战,全程
debug.log 干净。没有触发死亡/复活循环——这台驱动的自动逃
跑机制在低等级角色明显劣势时会主动撤离,属于正常设计(help
newbie 也提到"如果在游戏过程中你不幸身亡,则死后从鬼门关复活
回来,到扬州的武庙,继续游戏",说明死亡复活确有实现,但本轮预
算内没有人为构造出一定会死的场景来强制触发;如实记录为未验证
实况,不是"没有实现")。
5. 退出/重连(存档路径):真实 quit 后立即重连命中"你距上次
退出只有 N 秒钟,请稍候再登录"的退出保留窗口(设计如此,不是
bug);等待超过该窗口后重新登录,你上次光临… 时间戳正确、位
置正确还原到"客店"(上次 quit 前所在房间),留言板未读数正确
保留——存档/还原路径确认正常。
6. 管理员账号:按 AGENTS.md §1.5 标准约定新增播种了 fluffos/
MudLogin2026(这份档案此前 WASM 阶段播种的是非标准 id
wlqxztest,密码在当时的会话里已自设、这次无法复用,予以保
留、并列存在),加入 adm/etc/wizlist。实测 update
/adm/daemons/eventd、update /clone/quest/*(见上)、config
指令均成功,确认 (admin) 权限真实生效,不只是登录横幅显示。
一处走查但判定为内容问题、未改动
d/register/yanluodian.lpc的paizi提示文字 "投胎乃人生大事,切记不可草率!washto选好天赋之后,就输入 born <中文地名>。" 里washto和后面的中文之间缺一个空格/标点 (washto其实是这份档案真实的指令名,不是"wash"+"to"两个词), 读起来容易让人以为要打"wash"再打"to"。help/newbie里同样残留 了"投胎前需要先 register 邮箱地址"的旧版流程说明,和这份档案已 经取消电子邮件步骤、实测register指令也回应"你不是已经注册过 了吗?不用再注册了"的现状不符。这两处都是纯文字表述问题,不影 响任何实际指令的执行(washto/born本身运作完全正常),按 §10.7 的范围界定(只修程式 bug,不做内容/文案判断)如实记录, 未改动。
§7.100 修复(ROOM 基类多余 replace_program(),2026-08-19)
- 与其它同类档案一样,
inherit ROOM;(/inherit/room/room)后面跟着 一个多余、有害的replace_program(ROOM);,给几乎每个房间物件都埋 下了一个"首次绑定 closure 就崩溃"的休眠地雷。删除了全部 3373 处存 活的独立调用行(40 处已注释掉的历史遗留行保持原样未动);房间构 建工具clone/misc/roommaker.lpc的字符串拼接模板 (str += "...replace_program(ROOM);...")里的同一形状也一并手动 修掉,避免玩家用工具新建的房间继续继承这个 bug。git diff --stat核对为 3373 文件纯删除 + roommaker.lpc 的 1 行改写,和脚本自报数字 完全一致。真实驱动干净启动,用本轮之前播种的fluffos/MudLogin2026管理员账号登录((admin)权限确认生效),在投胎前 的世外桃源区域走了 6+ 个房间(entry↔roomn↔rooms 往返),debug.log 全程零"cannot replace"/"cannot bind"行。之前批次搁置这份档案是因 为以为只有非标准的wlqxztest管理员账号可用,重新核对 README 后 发现本轮 §10.7 深测已经按标准约定并行播种了fluffos/MudLogin2026,不需要再逆向工程注册流程。
``§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/bgargoyle.lpc, d/death/npc/wgargoyle.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.
第四轮 §10.7 深测:死亡/复活闭环补测(2026-08-20)
本轮专门补测上一轮(2026-08-07)明确标记"未验证实况"的死亡/复活
循环——上次实战里角色在自动脱战机制(约 24-40 点伤害后主动撤离)
介入前始终没有真正死过。这次先读代码理清了机制(不是靠继续苦练
碰运气):feature/damage.lpc 的 unconcious()(qi/jing < 0 时触发,
COMBAT_D->player_escape() 郭靖救场,送去"郭府大厅"疗伤,不是真死)
和 die()(eff_qi/eff_jing < 0,或没有 player_escape 接住时才真正
执行)是两个独立分支——player_escape() 只有在"击晕者当前正在和你
交战"这个条件成立时才会拦截,管理员 smash 指令(cmds/arch/
smash.lpc)走的是 receive_damage("qi",1,killer) + ob->die() 直接
调用,killer 不处于与目标的实际战斗状态,player_escape() 直接
判 0 放行,所以 smash <目标> 是一条繁殖代价最低、完全合法(arch
权限指令)的真死路径,不需要去找"打不过就跑"这个自动脱战机制的
反例。
发现并修复的真 bug(不在死亡路径本身,而是新角色 born 流程里,
测试过程中意外撞见):adm/daemons/updated.lpc 的 born_player()
第 312 行 get_dir("/kungfu/special/")(不带通配符)会把
kungfu/special/ 目录下所有条目都列进来,包括 5 个从未清理掉的历史
.c.bak 残留档(guibian.c.bak/guimai.c.bak/qinzong.c.bak/
shenyan.c.bak/tiandao.c.bak——这 5 个的 .lpc 现役版本本来就在
第 321 行的"转世特技排除名单"里,说明这些残留档正是该被排除的那批)。
第 318 行 sscanf(files[i], "%s.lpc", files[i]) 对不以 .lpc 结尾的
档名(比如 guibian.c.bak)匹配失败,files[i] 保持原样不变,导致
排除名单的字符串比较("guibian" vs "guibian.c.bak")对不上,这
5 个残留档全部原样留在候选池里参与 random() 抽取特殊技能。一旦被
抽中,SPECIAL_D(special)->name()(#define SPECIAL_D(x)
("/kungfu/special/" + x))呼叫 /kungfu/special/guibian.c.bak 这个
不存在的物件,直接在 born 指令执行时炸出
*call_other() couldn't find object '/kungfu/special/guibian.c.bak'.——
实测第一次新建角色 born 就撞上了(约 5/28 的概率)。修复参考同一
份档案里其它地方(storyd.lpc/eventd.lpc/quest/explore.lpc)已经
在用的写法,把 get_dir("/kungfu/special/") 改成
get_dir("/kungfu/special/*.lpc"),让通配符本身过滤掉非 .lpc 档
案,不再依赖脆弱的 sscanf 后缀剥离。修复前后各完整跑了一次注册到
born 的全流程验证:修复前必现上述崩溃;修复后新角色 deathtest
干净通过 born,debug.log 零错误。
死亡/复活全流程实测(deathtest 新角色,均衡秉性由武林类型菜单
随机分到"心狠手辣"):管理员 fluffos 账号对已完成投胎的
deathtest 使用 smash deathtest(跨房间也能命中,smash.lpc 支持
远程雷劈),角色立即"死了!",ghost=1,move(DEATH_ROOM) 送入
"鬼门关"(/d/death/gate)。房间内 npc/bai.lpc(白无常)的 init()
在检测到 previous_object()->is_ghost() && !wizardp(...) 后自动排队
death_stage() 五段对话(每 5 秒一句),全程无需玩家主动输入。最后
一句"罢了罢了,你走吧"之后自动 reincarnate()(ghost=0,
eff_qi/eff_jing 满血)、清空随身物品(DROP_CMD->do_drop() 逐件
丢弃,实测复活后 i 显示"身上没有任何东西")、move(REVIVE_ROOM)——
REVIVE_ROOM 宏定义为 /d/city/wumiao("武庙"),和 help newbie
文档写的"死后从鬼门关复活回来,到扬州的武庙"完全对得上。复活后
score 正确显示"你到目前为止总共到黑白无常那里串门一次"(死亡计数
从 0 变 1)、"你最后一次是被雷劈死了"(死因文案正确),角色可以正常
接受后续指令(look/i 均正常响应)。全程(含此前 fluffos 管理员
账号自测的一次死亡+recover+goto手动归位)debug.log 零错误记录。
(旁注:管理员账号 wizardp(previous_object()) 为真时 bai.lpc/
hei.lpc 的 init() 会直接 return,不会自动播放死亡对话——这是
有意为之的设计(巫师不走凡人复活流程),不是 bug;用管理员账号
fluffos 自测死亡路径时借 recover+goto 指令手动归位,不代表
死亡对话本身对巫师账号是坏的。)
环境问题,非代码 bug,已在本地建目录但未提交:smash 触发的
die() 调用链(combatd.lpc 的 killer_reward() 第 1534 行)里有
一处 log_file("nosave/killrecord", ...),本仓库这份档案的
work/log/nosave/ 目录此前从未被创建过(log/ 整体在 .gitignore
里,不受版本控制,驱动启动时也不会自动建这个子目录——手足档案
zjdywzb/xkyxciii 等的本地 work/log/nosave/ 目录已经在,佐证这
纯粹是运行环境搭建缺口,不是代码问题)。第一次触发时 log_file()
因目录不存在直接报错,把整个 die() 调用链从 killer_reward() 那
一行截断,角色被判定"死了"但从未真正进入 ghost/移动到死亡房间/清
除随身物品——是一个值得记录的连带观察:die() 对 log_file() 失败
没有任何防护,一旦该次写入失败(不管什么原因),死亡流程会卡在
"喊了台词但状态没变"的半失败态,但这是运行环境问题触发的,不是这
份代码本身的缺陷,mkdir -p work/log/nosave 后问题消失,未做代码
改动。
标准检查清单快速核对结果(均确认干净,不重新推导):
- §7.90(
config.fluffoseval-cost):maximum evaluation cost : 5000000,健康值,未改动。 - §7.100(
replace_program(ROOM)):全档案 15 处命中全部是//注释掉的历史行或.c.bak备份档,无一处存活,确认此前的 跨库扫描修复在这份档案上完全生效。 - §7.108(
reconnect()调用enable_commands()):clone/user/user.lpc第 281-287 行reconnect()第一行就是enable_commands(),确认干净。 - §7.111(
standard_trace()):adm/single/master.lpc的standard_trace()/error_handler()本轮死亡测试过程中被真实的log_file()报错和killrecord目录缺失错误各触发过一次,现场 输出的错误堆栈格式完全正常("执行时段错误:""程式:""物件:" "呼叫来自:"),确认无需修复。 - §7.112(
death_stage()重入守卫):d/death/npc/bai.lpc(本轮 死亡测试实际触发的档案)连同hei.lpc/d/death22/npc/{bai,hei}.lpc/bgargoyle.lpc/wgargoyle.lpc逐一读了完整源码,每个提前 return 分支和终态分支都正确配对set_temp/delete_temp,本轮死亡测试是 这份档案第一次真实走完这条路径(此前从未有真实死亡触发过),实测 过程零重入/零残留death_stage_active现象。 - §7.79(
addn()两参数):全档案唯二 2 处命中都在cmds/skill/death.lpc里且已被注释掉,不适用。 - §7.30(
feature/skill.lpc存取函式空 mapping 防护):上一次 §7.30 语料库扫描已经对这份档案做过修复(见上一节),本轮未重新 验证。
§7.125 sibling-sweep fix: premature set("registered", 1) defeats the registration gate (2026-08-28)
Flagged in AGENTS.md §7.125 as a sibling worth checking (originally
found on zhyx, same yh2003/ES2 lineage). Confirmed byte-identical:
adm/daemons/logind.lpc's enter_world() unconditionally ran
user->set("registered", 1); //user->set("born",1); right after
handing out starting clothing, on every login — permanently
short-circuiting the register-room's exit gate and channeld's
registration check from a character's first-ever login onward, since
d/register/npc/shuisheng.lpc's do_decide() (the correct, sole
place this flag should be set, confirmed present and correct in this
lib too) could never matter — the flag was already permanently 1
before the player ever got a chance to register. Fixed by deleting the
premature line in enter_world(). Verified via a clean native driver
boot only (not an independent live walk-out-of-the-room reproduction
on this specific lib — the bug shape and remedy are a verbatim port of
an already live-verified fix from the shared-lineage sibling zhyx).
深度功能测试(§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/swear.lpc、cmds/std/team/swear.lpc:结义失败提示被多余的;截成两句,fail只剩"……可惜现在有人不在,$N",后半句"的提议只好作罢。"丢了;接回去。
验证:改动的文件和包含 npc/indian 的守护进程在 HEAD 与工作树分别加载(scripts/lpc_listcheck.sh,新进程),无回退。
深度功能测试(§10.7,2026-10-07)— 编译警告整理
先用 scripts/lpc_twin_port.py adopt nitan_ceshi yhwhpublicfi 把 nitan_ceshi 警告整理提交(ae7fbb619a5)里的改动搬到修改前与它一致的文件(逐文件核对非 ASCII 文字:除 nitan_ceshi 自己删掉的以外没有丢失或改动),再用 scripts/lpc_nitan_family_fixes.py yhwhpublicfi(adm/daemons/combatd.lpc 删去空语句 your_temp["guarding"]; 等)。剩下的再跑 scripts/lpc_warnings.py yhwhpublicfi --fix 加 scripts/lpc_fix_no_effect.py --apply(d/tiezhang、d/wudu 几个房间删去 return 后面永远执行不到的 "\n";),共改动 831 个 .lpc 和若干 .h。以上都不改变行为。
HEAD 与工作树分别加载(新进程):826 -> 826 通过,无回退。
启动时警告 86 -> 0;新进程登录正常。
(adm/daemons/combatd2.lpc 副本里同样的 your_temp["guarding"]; 也删去。)
深度功能测试(§10.7,2026-10-08)— .lpc 后缀的定宽切片
.c 改名 .lpc 时只改了字符串没改切片宽度:f[<2..] == ".lpc" 拿两个字符比四个字符,永远不成立(!= 永远成立),按后缀筛文件、去后缀的代码因此从不运行或截成 x.l(KB 06 §7.238)。scripts/lpc_lpc_suffix_slice.py --apply 改了 1 处比较、0 处去后缀(如 adm/daemons/huanjing2003/room_master_hj.lpc);改动的文件 HEAD 与工作树分别加载(新进程),无回退。
- 2026-10-12:
clone/misc/swmuding.lpc(神木王鼎)自己声明了一张mapping insects虫表,与继承的clone/misc/muding.lpc的insects同名;读表的是木鼎的代码,读到的是木鼎自己的表,神木王鼎的虫表从来没用上(Redeclaration of global variable 'insects')。改名sw_insects,create()里insects = sw_insects;交给木鼎(nitan170911、wxddym、zjdy 系同修)。HEAD 与工作树各载入一次,regress 0。
编译警告收尾(2026-10-13)
scripts/lpc_twin_port.py adopt yanhuangwuhun yhwhpublicfi 搬来 yanhuangwuhun 整理(89552da089f)里与本库逐 token 相同的 12 个文件,能编译的文件警告清零;改动的 13 个对象在 HEAD 与工作树各载入一次:HEAD PASS 12,tree PASS 12,regress 0。
adm/daemons/huanjing2003/四国 NPC/宝物与room_readygo_hj.lpc:同一条声明里先裸声明再带初值声明的变量去掉裸的那份。feature/food.lpc、feature/liquid.lpc的do_effect()改varargs int,与重载它、被eat/drink用返回值的物品同型;adm/daemons/network/cmwhod.lpc的nosave函数改protected;adm/daemons/vrm_server.lpc多余的;删去。- 镖师钱正伦
d/beijing/npc/qianzhenglun.lpc记次数的count遮住基类feature/shell.lpc的同名变量,改名my_count(同 yanhuangwuhun)。
- 2026-10-14:新驱动(FluffOS 970d9f09)报
Float value truncated to int(#1426)。1 个文件 1 处:赋值、初始化、return 改写成to_int(...)(值不变,只是写明截断)。改动的对象新进程各载入一次,无回退(scripts/lpc_fix_float_trunc.py,KB 04 §6.10)。
- 2026-10-14:1 个文件把
array单独当类型用(array names;),本驱动当成普通名字,报Illegal lvalue整份不编译;改为mixed *,每个声明都带星号(scripts/lpc_fix_array_type.py)(KB 04 §6.1、§6.3)。新进程比对 HEAD 与工作树:1 个对象,新增载入 1,回退 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。
内力/精力当作伤害种类(2026-10-15,KB 06 §7.241 第二类)
本库 feature/damage.lpc 的 receive_damage() 不接受 jingli/neili/force 等种类,me->receive_damage("jingli", 30) 之类在练功、绝招、吸取时报 F_DAMAGE: 伤害种类错误。4 处改为 add(type, -N)(scripts/lpc_fix_damage_calls.py 第二步)。
无门派玩家的 family 映射(2026-10-15,KB 05 §7.30 第三种)
mapping fam = ob->query("family"); 之后直接 fam["family_name"]:没有门派(新人或叛师后)的玩家在学习、练功、拜师、进入门派房间时报 Value being indexed is zero,而不是作者写好的提示。1 处在声明行加上 if (!mapp(fam)) fam = ([ ]);(scripts/lpc_fix_family_guard.py)。
转码吃掉的引号(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_*(达摩)中毒状态都载入失败。
技能按另一门武功的等级取招(2026-10-15,KB 06 §7.243)
这些技能文件是从别的武功复制改名来的,query_action() 仍用原武功的等级查招式表:只会本技能的人等级为 0,取不到招,每次出招都报错。改为读本技能自己的等级(scripts/lpc_fix_action_level.py):dacidabei-shou。
find_player() 只认在世界里的身体(2026-10-15,KB 07 §8.26)
simul_efun 的 filter_player() 加上 environment(ob):注册中途断线留下的、不在任何房间的身体不再被当成玩家,两个以上时 find_player() 不会再报 The player(<id>) has existed in the world.(wllz3 实测过的问题)。本库若注册流程不会留下带玩家 uid 的身体,这一改动不改变行为。
技能名拼错(2026-10-15,KB 06 §7.249)
query_skill() 里的技能名拼错了,或用的是本库改名前的旧名;本库没有这个技能,调用永远得 0:门槛(< N 就拒绝)永远过不去,相关功夫或绝招学不了、用不了;内功互斥(> N 就拒绝)从不生效;公式里这一项一直是 0。经汉字名(提示文字或中文名词典)或纯拼写差异(_/-、少一个连字符、相邻字母颠倒)核对后,改为本库的技能名(scripts/lpc_fix_skill_typo.py):choushui-zhang→chousui-zhang(chousui-zhang);cuhixiao-jifa→chuixiao-jifa(xiaoao-jianghu);hengshan-jianfa→hengshan-jian(/d/henshan/tianquan-hole);lenyue-shengong→lengyue-shengong(lengyue-shengong);matrial-cognize→martial-cognize(qiankun-danuoyi/nuoyi);taiji-shengon→taiji-shengong(taiji-shengong);yaowang-mishu→yaowang-miaoshu(yaowang-miaoshu)。
技能名拼错:技能文件里拼错自己的名字(2026-10-15,KB 06 §7.249)
技能自己的文件(或它的绝招目录)里,query_skill() 读的是差一个字母的自己的名字,永远得 0:“基本功夫要高过本技能”之类的限制从不生效,按等级取招、计算伤害的那一项一直是 0。改为本技能的名字(scripts/lpc_fix_skill_typo.py 的 self 判据):jiujin-shengong→jiuyin-shengong(jiuyin-shengong/perform/zhang);xuanyuan-arror→xuanyuan-arrow(xuanyuan-arrow)。
family 映射内联取下标(2026-10-15,KB 05 §7.30)
ob->query("family")["master_name"]、me->query("family")["family_name"](泥潭式为 query("family", ob)[...])直接对门派映射取下标:没有门派的人(新玩家、叛师者、大多数 NPC)在 NPC 的打招呼和问话、绝招的门派判断、房间的 valid_leave 里报 Value being indexed is zero,而不是得到拒绝。1 处(1 个文件)改为 dbase 路径查询 query("family/master_name"):有门派时值相同,没有时得 0;原有的判断照常生效(scripts/lpc_fix_family_index.py)。给映射赋值的写法未动。
回龙杖「神龙摆尾」从来用不出(2026-10-15,KB 06 §7.246)
if (!objectp(me->query_temp("weapon") || weapon->query("skill_type") != "staff")):括号放错,objectp() 包住了整个 ||,拿着兵器时 objectp(1) 为假,永远“双手应该持杖”;空手时又去读从未赋值的 weapon,报错。改为先存兵器再判断。
set_skill() 遇到本库没有文件的武功不再抛错(2026-10-18,KB 06 §7.256)
feature/skill.lpc 里的 set_skill()、map_skill()、prepare_skill() 碰到没有武功文件的名字就 error("F_SKILL: No such skill (…)"),调用它们的 NPC create() 整个中断:NPC 载入不了,刷出它的房间也少一个人。本库目前没有对象设了缺失的武功;三处都改成 return:这一门武功不给、不映射,对象照常载入,只是少了它(缺的武功本身仍是内容缺口)。(scripts/lpc_guard_set_skill.py)
武功名拼错的 NPC(2026-10-19,KB 06 §7.258)
set_skill("kunlun-shnfa", …)、map_skill("dodge", "shaolin-shnfa") 这样的调用把武功名拼错了:本库没有这个武功文件,有的是拼对的那个。以前这种 NPC 在 create() 里报 No such skill 载入不了;武功缺失时跳过之后它们能载入,可是少了那门武功(set_skill 被跳过,map_skill 映射不到,门派弟子用普通轻功/拳脚)。按核对过的对照表改正,共 16 处、10 个文件:jinyin-baiguzhao→jiuyin-baiguzhao(4 处)、changquana→changquan(4 处)、tiaji-jian→taiji-jian(2 处)、shenhuo-shengong→shenghuo-shengong(2 处)、taiji-shenfong→taiji-shengong(1 处)、yan-fly→yanfly(1 处)、zhoangnan-zhi→zhongnan-zhi(1 处)、jinwu-goufan→jinwu-goufa(1 处)。(scripts/lpc_fix_skill_names.py)
同一个函数原样贴了两遍(2026-10-19,KB 06 §7.264)
同一个文件里同一个函数被原样贴了两遍(除空白外逐字相同),驱动报 Redeclaration of function,整个物件载入不了。删掉第二份及以后的副本,共 1 处:/d/beijing/npc/dan/danB_6.lpc 的 query_autoload()。(scripts/lpc_fix_dup_functions.py)
全局头文件丢了 2 个宏(2026-10-19,KB 04 §6.16)
/include/globals.h 里没有定义 TEXT2PIC_D、TYPE_CHARM,用到它们的物件(名单里 2 个)编译时报 Undefined variable/Undefined function,整个物件载入不了(编译器在第一个未定义的名字上停下,后面的错误和警告都看不到)。同系的库在各自的头文件里都有这几行:照其中和本库共有文件最多的那个库,原样补到 /include/globals.h 最后一个 #define 之后,宏体里出现的路径在本库里都存在。补完后名单里有 2 个载入,其余还差别的东西。(scripts/lpc_restore_defines.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 逐个物件对比载入,没有退步。
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 04 §6.15、§6.18)
宏有定义、基类文件却不在档案里:继承它的对象载入时报 Inherited file '…' does not exist!,编译扫描看不到这一类(scripts/lpc_missing_inherits.py 能列出)。同系的库里有同一个文件,原样拷来(scripts/lpc_restore_bases.py);基类和继承它的对象 include 而本库没有的头文件一起带来。每个基类补回后单独载入,再载入使用它的对象,载不进来、或一个用户也载不进来的撤掉了。
/inherit/medicine/pill←nte:1/1 个继承它的对象载入
逐个与 HEAD 对比载入,没有退步。
补回丢失的标点(2026-10-19,KB 03 §4.6)
转换时丢掉的分号、逗号、引号或文件末尾的 },共 2 个文件,修前 HEAD 载入失败。别的库里同路径的完好副本只比这里少几个标点,按它补回(括号里是那个库):/d/baituo/obj/bowl.lpc(cctx)、/kungfu/skill/kuihua-mogong/perform/wswd.lpc(yanhuangwuhun)。修后与 HEAD 逐个对比载入:这 2 个物件全部载入,没有退步(scripts/lpc_restore_from_twin.py、lpc_fix_eaten_quote.py --comma、lpc_fix_eof_braces.py)。
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)。具体是:cross pubu(穿瀑布)永远回答“你要往哪儿穿?”,瀑布后面的密室进不去。改动:/d/mingjiao/shanmen.lpc(1 处)、/d/tiezhang/hhyuan-3.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,共 1 处)。改动:/cmds/std/watch.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)。
目录读出后的后缀截取宽度(2026-10-20,KB 06 §7.296)
.c 改名成 .lpc 之后,get_dir("*.lpc") 读出的文件名还按两个字符截取($1[0..<3]):baguadao.lpc 变成 baguadao.l,用它拼出的路径加载不到对象(故事、战场、事件、帮助、自造物品数据、召唤列表等)。改成 [0..<5](scripts/lpc_fix_getdir_strip.py)。改动:/adm/daemons/storyd.lpc(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 个文件)。
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/arch/blockade.lpc、/cmds/arch/recovermud.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.,同一个动词的其他处理函数不再尝试(不是最新的一条就悄悄跳过)。删除了 7 条注册(6 个文件,scripts/lpc_fix_dead_add_action.py),动词留给别的处理函数:/adm/npc/referee.lpc(do_halt)、/cmds/usr/top.lpc(do_view)、/d/baituo/obj/shedan.lpc(do_pour)、/d/tianlongsi/munitang.lpc(do_exit)、/d/wudu/huxue2.lpc(do_train)、/inherit/misc/fboard.lpc(do_list)。最多的函数名:do_halt 2 处、do_view 1 处、do_pour 1 处、do_exit 1 处、do_train 1 处。
缺失物品的 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 都被跳过。1 个文件里 1 处(new)改成 { object new_ob = new(路径); if (new_ob) new_ob->move(...); }(scripts/lpc_guard_carry_object.py --new:路径按这个文件自己看到的宏解析,宏名冲突、虚拟对象路径一律跳过)。 对这 1 个改动文件做加载检查(HEAD 与工作区对比):HEAD 能加载 1 个,现在 1 个(新增可加载 0 个,回归 0 个)。
汉字按字节切片的老写法没有换成按字符:改法名 "澄" + 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] == "澄")永远不成立;NPC 的称呼和提示里取到两个字而不是一个字。
本库 17 处(12 个文件):拼名字的赋值 10 处、与汉字常量比较 6 处、to_chinese()[..] 1 处。例:name[2..3] → name[1..1](/kungfu/class/emei/fengling.lpc:128);name[0..1] → name[0..0](/kungfu/class/emei/tobebonze.h:40);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,不要重跑。
长度检查按字节写,旁边的提示按汉字写:2 处(2026-10-22,KB 06 §7.362)
老档的 strlen() 数字节(一个汉字 2 字节),转成 UTF-8 后它数字符:提示写「必须是 2 到 6 个中文字」的检查还是 strlen(name) < 4 || strlen(name) > 12,于是两三个字的房名、帮会名、群名、聊天室名、称号被提示自己说允许的那句话拒绝,上限却是提示的两倍;留言板的标题检查 i < 4 || i > 24 || i % 2 还会拒绝所有奇数个字的标题(post 你好吗)。本库 2 处(1 个文件):if ((strlen(name) < 4) || (strlen(name) > 12)) {(/adm/npc/luban.lpc:1773)。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 区间 2 个文件;channeld 同盟 / 门派标题 1 个文件。证明(scripts/lpcc_eval.py):sjplii 的 check_legal_name 在 HEAD 接受「张a」、改后拒绝,两边都接受「张三」;xkx100 的 clubpoem->mixup("离离原上草") 得到「离离原草上」(真交换汉字);nitan_san 两字同盟名得到 【 兄 弟 】。关键对象加载通过。
中文名 / 验证码仍按 GBK 取「两字节一字」(2026-10-23,KB 06 §7.373)
pname = pname[(random(sizeof(pname)) & 0xFFFE)..<1]; pname = pname[0..1]; 在按字符计下标时会取出两个汉字。scripts/lpc_fix_pname_slice.py 去掉掩码并把收尾改成 [0..0](pname/pname2/sec_name/str/str1)。本库 4 处。证明:nt1 生成名长度 2–4;HEAD 常见 3–5。
yuanwai 孤儿 call_out announce_success(2026-10-27,KB 06 §7.349 Also)
d/changan/npc/yuanwai.lpc(及 aoxiangtianji 的 d/city 副本)在 check_daughter 里 call_out("announce_success", …),但本文件从未定义该函数;同系也无实现。到点会 *Undefined function*。cry_daughter 已完成认亲与赠书,删除这对 remove_call_out/call_out。证明:扫描 HIT call_out→announce_success 且无定义;改后残渣 0。
深度功能测试(2026-10-27,§6.25 zhongling tell_object 引号错位)
d/wanjiegu/npc/zhongling(及同路径副本)的 tell_object("who, 钟灵脱下一双绣花鞋。\n") 把对象参数写进了字符串;改为 tell_object(who, "…")。证明:原文错位;改后加载,语料残渣 0。
深度功能测试(2026-10-27,§6.10 未知 pragma save_binary/optimize)
删除本库中 FluffOS 不认的 #pragma save_binary / #pragma optimize… 行。