Ultimate Hell 2008: Complete Edition

✅ 可玩

终极地狱2008完整版

zjdy2008wzb

🔑 fluffos / Mud@2026 更新 66a3bd8 2026-10-28 源码 下载 ZIP

▶ 开始游玩 · Play Now

《终极地狱2008完整版》(REVIVE OF ULTRA HELL(BLOOD & MAGIC) FROM 1999.11.13,CDS 出品)是本项目"地狱"/Doing 血统六件套之一——与 `hell`、`zjdyaryl`、`zjdywzb`、`zjdyzj`、`zjmudhell` 共享同一个门派江湖世界,逐字节地图比对显示彼此高度重合(与 `hell` 约 88% 一致,与 `zjdyaryl` 高达 95%、与 `zjdyzj` 约 90%,与 `zjdywzb`、`zjmudhell` 则更疏远、约 76%),是同一份原作世界的六个快照/变体而非各自独立设计;本版特色是注册时姓氏、名字分开输入并附 1-5 号角色类型菜单,新角色从"世外桃源"而非常见的南城客栈开局,门派地图除少林、武当、峨嵋、丐帮、明教外,还有呼应金庸原著兵器/门派的"屠龙"、"血刀"场景。

English

Ultimate Hell 2008: Complete Edition ('Revive of Ultra Hell (Blood & Magic)', originally from 1999.11.13, produced by CDS). Part of this collection's wider 'Doing'/Hell-lineage family rooted in the hell archive — its master.lpc, logind.lpc, named.lpc, and versiond.lpc are structured almost line-for-line the same. A byte-level, line-ending-normalized comparison of the /d room tree confirms the shared world runs deeper than the engine files: this build is 88% identical to hell's own map, and even closer to its own zjdy-branded siblings — 95% to zjdyaryl, 90% to zjdyzj, and 76% to both zjdywzb and zjmudhell — so all six archives (hell, zjdy2008wzb, zjdyaryl, zjdywzb, zjdyzj, zjmudhell) are snapshots/variants of one authored wuxia world rather than independently-designed games. This edition's own distinguishing touches: registration splits surname and given name into separate prompts and adds an explicit 1-5 character-type menu, new characters start from 'Peach Blossom Spring' (世外桃源) rather than the more common south-city inn, and the sect map includes 'Dragon Slaying' (屠龙) and 'Blood Blade' (血刀) rooms nodding to specific Jin Yong weapons/factions alongside the standard Shaolin/Wudang/Emei/Beggars'-Sect/Mingjiao roster.

README

内容亮点

本次修复的关键 bug

1. 经典 §8.1 GBK 字节区间 is_chinese()(str[i..i+1] 字节 对判断,176-247/161-254 区间)——改成逐码点的 0x4e00-0x9fff;check_legal_name() 对应的 maxlen 没有减半的上限也一并改成 maxlen/2,下限从 2 改成 1。 2. master.lpc(adm/single/master.lpc)的 valid_read()/valid_write() 都缺少标准的 user == this_object() 短路判断——都补上了。 3. §7.50 is_killing(object) 与 is_killing(string id) 类型 不匹配,修好了 12 处呼叫点(几个门派 suck/tan/zhua/ hua 档案、clone/user/user.lpc、d/city/npc/guidao.lpc、 cmds/std/ansuan.lpc、cmds/std/surrender.lpc)。 4. 档案里没有 log/nosave/ 目录,导致 logon() 一开始的 log_file() 呼叫就报"Wrong permissions for opening file /log/nosave/logon",直接把每一个连线的玩家断线("logon() ... has failed")——建好了这个目录。这和 yxxcii 那份档案的同 类问题相比,这里是会挡住整个连线的严重 bug,不只是巫师丢东西 时的日志噪音。 5. 姓名组合最短长度检查(get_name() 里的 strlen(fname)<4,字节数没减半)和 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),都按 hell 家族已经确认的减半模式修 了——修好前,单字姓氏和任何两字全名都会被误判"太短"。 6. versiond.lpc 的 in_server()(通过 logind.lpc logon() 里直接、没有保护的 VERSION_D->is_version_ok()/ query_temp() 呼叫触发,所以即使不在 adm/etc/preload 里, 第一次连线时也会被编译)和 hell 那份 versiond.lpc 一样, 有真正没被掏空的 socket_create()/socket_bind() 呼叫——按 AGENTS.md §7.52 掏空了全部 13 个碰 socket 的函式(做法和 hell 的修复几乎一样)。

adm/daemons/ftpd.lpc、adm/daemons/network/dns_master.lpc 都已 经在 adm/etc/preload 里被注释掉,剩下的呼叫者也都是受保护的巫师 指令,属于完全休眠,本次没有改动。

深度功能测试(§10.7,2026-08-08)修复的 bug

手足档案 zjdywzb 的 §10.7 深挖发现的 §7.88/§7.89 逐条重新核实 ("移植的修复仍需逐库验证"),另外发现两处已知 bug 类别(§7.80、 §7.81)在这份档案里的独立命中。详见 NOTES.md;摘要:

管理员账号 / Admin account

警告:对外公开架设前请务必修改此密码。

本地运行

cd libs/zjdy2008wzb
~/src/fluffos/build-debug/src/driver config.fluffos

游戏端口:40110。

NOTES · 移植与修复记录

WASM 修复摘要(迁移自 meta.json 的 group_note)

终极地狱2008完整版(REVIVE OF ULTRA HELL(BLOOD & MAGIC) FROM 1999.11.13,CDS 出品),和本次会话已经处理过的 'hell' 档案同属一个 Doing 血统家族——master.lpc/logind.lpc/named.lpc/versiond.lpc 结构几乎逐行一致。WASM 修复了:(1)经典的 §8.1 GBK 字节区间 is_chinese()(用 176-247/161-254 区间做 str[i..i+1] 字节对检查)重写成逐码点 0x4e00-0x9fff 检查;check_legal_name() 对应的、没有减半的 maxlen 界限修复成 maxlen/2,最小值从 2 改成 1。(2)master.lpc(adm/single/master.lpc)的 valid_read()/valid_write() 缺少标准的 'user == this_object()' 保护——两处都已加上。(3)§7.50 类的 is_killing(object) 对 is_killing(string id) 修复了 12 处呼叫点(kungfu/skill/*.lpc 的 suck/tan/zhua/hua 档案、clone/user/user.lpc、d/city/npc/guidao.lpc、cmds/std/ansuan.lpc、cmds/std/surrender.lpc)。(4)缺失的 log/nosave/ 目录导致 logon() 的第一次 log_file() 呼叫抛出'Wrong permissions for opening file /log/nosave/logon',直接把每一个连线用户断线('new_conn_handler: logon() ... has failed')——已创建该目录,和 yxxcii 上见过的同一类 bug 一样,但这里是阻断启动的,不只是外观问题。(5)get_name() 里姓+名合并的最小长度检查(strlen(fname)<4,字节数翻倍)和 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)都修复成减半后的逐码点界限,和 hell 家族的先例完全一致——不修的话,单字姓氏和任何两字全名都会被拒绝为'太短'。(6)versiond.lpc 的 in_server()(通过 logind.lpc 在 logon() 里直接、未加保护的 VERSION_D->is_version_ok()/query_temp() 呼叫触达,所以即使它不在 adm/etc/preload 里,第一次连线时也会被编译)带有和 hell 的 versiond.lpc 一样真实、未掏空的 socket_create()/socket_bind() 呼叫——按照 AGENTS.md §7.52,把全部 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,和 hell 的修复方式几乎一致。adm/daemons/ftpd.lpc 和 adm/daemons/network/dns_master.lpc 都处于休眠状态(在 adm/etc/preload 里被注释掉,只有带保护的巫师指令呼叫者)——保持原样。管理员账号播种:fluffos (admin) 加入 adm/etc/wizlist。注册流程在格式化前后都完整验证过(英文 id→y 确认→中文姓→中文名→管理员密码+确认→登录密码+确认→角色类型菜单(1-5,用的 5)→性别→进入世外桃源),管理员权限已通过'目前权限:(admin)'确认。这份档案的提示符会显示实时时钟(符合 AGENTS.md §8.3 第 1 条)——注册测试时用的是 --idle 0.3。LPC 格式化工具对全部 7287 个档案运行(写入 7258 个,1 个转档之前就存在的错误,28 个未改动)。没有 :: 父类呼叫拆分命中,没有 case 标签带尾随注释的候选,没有 CJK 重新加空格/转义损坏命中。

§7.86 跨库扫描修复(留言板 post 崩溃)

深度功能测试(§10.7,2026-08-08)

手足档案 zjdywzb(同一个 Doing/"hell" 血统家族)已经做过 §10.7 深挖, 发现并修复了 §7.88(message() 包装函数漏标 varargs)、§7.89(自带 runtime_config.h 索引错位)、§7.86(留言板 post 崩溃)。本次按照 "移植的修复仍需逐库验证"的项目惯例,逐条重新核实这三处在 zjdy2008wzb 自己代码里的实际形状,而不是直接照搬。

深度功能测试第四轮(§10.7 round-four,2026-08-19)

本轮任务:补测第三轮明确标记为"未测试"的三个系统——门派拜师、商 店购物、邮件系统;并对已经全库扫描完毕的几条 checklist(§7.90、 §7.111-§7.115)做一次本档案专属的抽查。没有发现任何新的编程 bug,三个系统里两个(拜师、购物)完整验证正常工作,第三个(邮 件)确认是这个"hell"血统家族项目本身就蓄意关闭的功能,不是本档 案独有的坏损。

测试前置状况:管理员账号 fluffos 的存档处于损坏的中间状 态——data/login/f/fluffos.o 存在(purename 是"浮浮",明显是 一次未走完的注册残留),但 data/user/f/fluffos.o 完全不存在, 导致用 fluffos 连线会在 logind.lpc 的 user->restore() 失败 分支直接断线("无法读取你的数据档案,您需要和巫师联系。"),且 这个档案的 CONFIG_D->query_int("ask_recreate") 返回假,连"是否 重新创造玩家"的补救提示都不会出现。判断是第三轮会话在" look/ goto/update 三重验证"之后没有让角色真正存过档(obj/user.lpc 的 存档很可能只在正常 quit/心跳周期性存档时触发,而不是巫师权限检 查本身需要的),随后如果那次会话是直接杀掉驱动进程结束的,新建的 角色存档就会跟着丢失——这本身可能是个值得未来注意的"角色数据只 在正常退出/心跳时落盘,异常关闭会丢刚创建的角色"式的存档可靠性 问题,但和本档案玩家实际测试无关,未展开处理。本轮临时在 adm/etc/wizlist 加了 wztestfour (admin),通过正常注册流程重 新播种了一个可用的管理员测试角色,验证完毕后已经把 wizlist 恢复 原状、删除了 wztestfour/fluffos 的残留存档档案(fluffos 的 损坏 login 存档也一并清掉了,避免下一轮踩同一个坑)。

- §7.111(master.lpc 的 standard_trace() file_name (error["object"]) 崩溃):adm/single/master.lpc 第 230 行已经是 error["object"] ? file_name(error["object"]) : "0" 的三元保护写法,安全。 - §7.112(init() 重连叠加 call_out 链): d/death/npc/{wgargoyle,bgargoyle}.lpc 都已经用 query_temp("death_stage_active")/set_temp(...)/ delete_temp(...) 做了防重入闸门,和第三轮"死亡复活流程完 整走通、无卡死"的实测结果一致。 - §7.113(netdead 重连不恢复 heart_beat):adm/daemons/ logind.lpc 的 reconnect() 无条件呼叫 user->reconnect(), clone/user/user.lpc 的 reconnect() 里无条件 set_heart_beat(1)——属于 AGENTS.md §7.113 记录的"批次二" 45 库之一,本档案当时就已确认干净,本轮静态复查结论一致。 - §7.114(private 修饰的 input_to 回调经 mixin 失效): feature/edit.lpc 的 input_line() 没有 private 修饰符, 不受影响——而且这次实测走过的"多行输入"路径(bai/buy/ sell 都不需要多行编辑,但拜师确认、购物问答等交互全程响应 正常,没有出现"第一行有效、后续行被吞"的症状),间接佐证这 个档案确实不在 §7.114 名单里。 - §7.115(QUEST 宏指向不存在的档案):本档案的 include/quest.h/include/globals.h 里 QUEST_OB(/inherit/ misc/quest)、QUEST_D(/adm/daemons/questd)两个真正会被 call_other 呼叫的宏对应的档案都真实存在(work/inherit/ misc/quest.lpc、work/adm/daemons/questd.lpc),没有"单纯 叫 QUEST 且指向缺失档案"的那种宏,不适用本条。 - §7.90(eval-cost 配置):config.fluffos 的 maximum evaluation cost 已经是 5000000(第三轮已修),本轮驱动干 净启动 + 完整拜师/购物/多次巫师 call/goto 操作,全程 debug.log 没有出现任何 cost limit reached/Too long evaluation,佐证了第三轮"那两次 eval-cost 报错是当时会话自 己连续 8 条 update 造成的高强度负载,不是常规游玩会触发的 一般性配置问题"的判断是站得住的,本轮没有推翻这个结论。

清理:临时的 wztestfour 管理员测试账号(存档 + wizlist 条 目)已经清理干净,损坏的 fluffos 残留登录存档也已删除;驱动测 试进程按 PID 正常 kill,未使用 pkill -f。

§7.100 房间基类 replace_program() 扫尾修复(2026-08-19)

ROOM 宏(/inherit/room/room)在本档案 2,306 处房间文件的 create() 里紧跟 inherit ROOM; 之后又多余调用了一次 replace_program(ROOM);——和姊妹档案 zjdywzb/zjdyzj/zjmudhell 同一个 AGENTS.md §7.100 记录的休眠 bug(多余调用给对象打上永久 "pending replace"标记,对象一旦绑定任何闭包就会崩溃)。用 fix_710_room.py(二进制模式,只删除内容严格等于 replace_program(ROOM); 的独立行)扫过 work/,删除 2,305 处;剩 余 1 处是房间生成工具 clone/misc/roommaker.lpc 里 str += "...replace_program(ROOM);..." 的字符串拼接变体,手工改成 str += "\n\tsetup();\n}\n";。另有 17 处是转档之前已注释掉的 // 行,原样保留;work/version/(一份独立的 46 文件版本同步子树)和 work/data/ 下都没有真实 .lpc 源码命中。git diff --stat 确认 2305 个文件各删 1 行 + roommaker.lpc 1 处字符串编辑,与脚本自报数 字吻合。修复后真实驱动干净启动(零新增编译错误、端口正常监听、 debug.log 无任何"cannot replace"/"cannot bind"行);由于这份档案 先前的 fluffos 存档已被上一轮测试清理删除,重新走了一次完整注 册流程(fluffos/浮浮云/管理密码Mud@2026Adm/登录密码 Mud@2026/均衡型/男),确认"目前权限:(admin)"后 look/goto 两个曾经命中过这个 bug 的房间 (d/mingjiao/shanlu3.lpc、d/guanwai/shanhaiguan.lpc)/quit 全部正常,无回归。

§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-10-04)— negative range ends

scripts/lpc_fix_negative_ranges.py: 8 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)— 房间列出的物件缺档时房间照常加载

房间基类 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 同源的三处编译警告

验证:改动的文件和包含 npc/indian 的守护进程在 HEAD 与工作树分别加载(scripts/lpc_listcheck.sh,新进程),无回退。

深度功能测试(§10.7,2026-10-07)— 编译警告整理

scripts/lpc_warnings.py zjdy2008wzb --fix 加 scripts/lpc_fix_no_effect.py --apply,共改动 534 个 .lpc 和若干 .h。HEAD 与工作树分别加载(新进程):532 -> 532 通过,无回退;改过的头文件的 128 个包含者 127 -> 127 通过。 手工(与 zjmudhell、zjdyzj 相同):28 处 Illegal to declare nosave function——include/globals.h 的 #define nosave nosave 让扫描工具认不出这个关键字,手工改成 protected;adm/daemons/natured.lpc 的空语句 lt[LT_MON];、adm/daemons/combatd.lpc 和 test.lpc 的空语句 your_temp["guarding"]; 删去。都不改变行为。

启动时警告 52 -> 0;新进程登录(新人物确认)正常。

深度功能测试(§10.7,2026-10-11):“无副作用表达式”警告复查(同码收尾)

深度功能测试(§10.7,2026-10-12):编译警告收尾

能编译的文件里的警告 3 -> 0(lpc_warnings.py zjdy2008wzb 重扫:7267 个文件可编译,剩下的诊断都在本来就编译不过的文件里)。与 zjdyzj 同码:zjdyzj 当天的修复(提交 15d40f6ba6a)改的 3 个文件在这里都是 token 级孪生,用 lpc_twin_port.py adopt 搬过来;ZJ 登录协议代码没有动。

真问题: clone/misc/swmuding.lpc 神木王鼎自己声明了一张 13 种毒虫的 mapping insects,可读表的是基类 clone/misc/muding.lpc 的函数,它们读的是基类那份普通木鼎表,叶子的表从来没用上。改名 sw_insects,在 create() 里赋给基类的 insects。

其余: feature/food.lpc、feature/liquid.lpc 的 do_effect() 改为 varargs int do_effect(object me) 并 return 1;,与 eat/drink 读取返回值的重载(d/guanwai/obj/wan.lpc、d/xiakedao/obj/pigpart.h)同型。

验证:改动文件、所有继承 F_FOOD/F_LIQUID 的物品、包含 pigpart.h 的文件、eat/drink 命令共 209 个对象,HEAD 与工作树各用新进程载入:206 -> 206 通过,regress 0;删除声明审计 0 项待看。209 个对象载入无回退。

负数伤害当作消耗(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。

转码吃掉的引号(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_*(达摩)中毒状态都载入失败。

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);lenyue-shengong→lengyue-shengong(lengyue-shengong);matrial-cognize→martial-cognize(qiankun-danuoyi/nuoyi);taiji-shengon→taiji-shengong(taiji-shengong)。

技能名拼错:技能文件里拼错自己的名字(2026-10-15,KB 06 §7.249)

技能自己的文件(或它的绝招目录)里,query_skill() 读的是差一个字母的自己的名字,永远得 0:“基本功夫要高过本技能”之类的限制从不生效,按等级取招、计算伤害的那一项一直是 0。改为本技能的名字(scripts/lpc_fix_skill_typo.py 的 self 判据):shicheng-liulang→shicheng-liulong(shicheng-liulong);xuanyuan-arror→xuanyuan-arrow(xuanyuan-arrow)。

柔云步法「柔云纵」有时报错(2026-10-15,KB 06 §7.251)

rouyun-steps/zong 随机把人送到三个房间之一:精、精力已经扣了,“乘云而去了”也说了,送不过去时人留在战斗里并报错。第三个是巫师的测试房 /u/deaner/test1,库里没有;改为 /d/city/guangchang(hy、jym 等库原本就用这个)。

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)。给映射赋值的写法未动。

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 映射不到,门派弟子用普通轻功/拳脚)。按核对过的对照表改正,共 12 处、9 个文件:changquana→changquan(4 处)、tiaji-jian→taiji-jian(2 处)、taiji-shenfong→taiji-shengong(1 处)、yan-fly→yanfly(1 处)、lingboweibu→lingbo-weibu(1 处)、jiahua-neigong→jiaohua-neigong(1 处)、zhoangnan-zhi→zhongnan-zhi(1 处)、jinggang-zhi→jingang-zhi(1 处)。(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)

die_reason 的参数个数(2026-10-19,KB 04 §6.10)

/kungfu/condition/damo_luanqi.lpc、/kungfu/condition/damo_shangshen.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 文件。

从 work/ 里删掉 tar 的 PaxHeader/ 记录(2026-10-19,KB 02 §2.2)

压缩包的制作者把 tar 的 pax 扩展头记录(49 path = ...、20 ctime = ...,每个不超过 262 字节)当成文件打进了包里,放在 PaxHeader/ 目录(有的嵌套两层)。转换时 .c 结尾的被改名成 .lpc,在扫描里成了编译不过的“物件”。这些是元数据,不是 mudlib 内容:80 个文件从 work/ 删除(raw/ 里仍然有)。

x != "a" || x != "b" 和 x == "a" && x == "b":同一个值的比较链永远成立/永远不成立(2026-10-20,KB 06 §7.282)

if (arg != "wan" || arg != "丸") return notify_fail(...) 对任何 arg 都为真,dir == "south" && dir == "north" 永远为假:条件下面的守卫要么永远拦、要么永远不拦。作者要的是“既不是 A 也不是 B”(&&)或“是 A 或 B”(||)。!= 链的 || 改成 &&(仅当条件下面是 return 的拒绝/守卫),== 链的 && 改成 ||(scripts/lpc_fix_cmp_chain.py)。改动:/d/mingjiao/shanmen.lpc(1 处)。

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 编码器等少数几处手改)。改动:/cmds/arch/sameip.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 处)、/adm/single/importer.lpc(1 处)。

get_config(__MUD_PORT__) 经旧版 runtime_config.h 得到字符串(2026-10-20,KB 06 §7.302)

本库的 include/runtime_config.h 是老 MudOS 的编号(整数设置从 15 起,本驱动从 256 起),get_config(__MUD_PORT__) 读到的是另一项设置(字符串),(int) 又只是编译期标注,于是 socket_bind(fd, LOCAL_PORT()) 报 Bad argument 2 to socket_bind(),版本守护进程 port = get_config(__MUD_PORT__) + VERSION_PORT 是字符串相加。头文件自己的注释写明 get_config(__MUD_PORT__) == __PORT__,所以代码里的这个调用(连同外面的 (int) / to_int())改成了驱动的预定义 __PORT__(scripts/lpc_fix_mud_port.py)。改动:/include/getconfig.h(1 处)、/version/include/getconfig.h(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 个文件)。

注册到不存在函数的 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.,同一个动词的其他处理函数不再尝试(不是最新的一条就悄悄跳过)。删除了 5 条注册(4 个文件,scripts/lpc_fix_dead_add_action.py),动词留给别的处理函数:/adm/npc/referee.lpc(do_halt)、/d/beijing/hg_w.lpc(do_body)、/d/tulong/yitian/npc/obj/ling2.lpc(do_du)、/inherit/misc/fboard.lpc(do_list)。最多的函数名:do_halt 2 处、do_body 1 处、do_du 1 处、do_list 1 处。

对象路径里的 ..:new(__DIR__ "../obj/x") 报 Read access denied(2026-10-22,KB 06 §7.351)

__DIR__ 是当前文件所在目录(带结尾斜杠),__DIR__ "../obj/x" 就是 /d/zhiye/npc/../obj/x;驱动的 legal_path() 不接受带 .. 的路径,new() / load_object() 直接抛 *Read access denied.(实测,find_object() 对它答 0)。走库自己的 carry_object() / 房间 objects 表的路径,库的基类会先规范化,能用;直接把路径交给 new() / clone_object() / load_object() / move() 的不行,调用到那一步才报错。改成规范化后的绝对路径(scripts/lpc_fix_dotdot_dir.py --direct):/d/wudang/npc/xiaocui.lpc(__DIR__ "../obj/nuerxiang" → "/d/wudang/obj/nuerxiang")。

调用了、但这个库自己的守护进程里没有的函数(2026-10-22,KB 06 §7.354)

MACRO->函数() 调用的函数在这个库的守护进程里不存在:call_other() 对不存在的函数不报错、只返回 0,所以这些功能(时间显示、昼夜事件、名字检查、价格文字……)一直没起作用。同一血统另一个库的同名守护进程里有这些函数,原文照抄到本库守护进程末尾(scripts/lpc_port_function.py;调用处传的参数个数、函数体用到的函数 / 全局变量 / 宏 / 字符串键都在本库里有,已核对;守护进程在 HEAD 和工作区都能加载,每个函数用固定参数各调用一次:HEAD 返回 0,现在返回正常的值):/adm/daemons/chinesed.lpc ← hhsj:find_skill()(1 处调用)。

汉字按字节切片的老写法没有换成按字符:改法名 "澄" + name[2..3]、辈分判断 name[0..1] == "澄" 等 24 处(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 的称呼和提示里取到两个字而不是一个字。

本库 24 处(16 个文件):拼名字的赋值 14 处、与汉字常量比较 9 处、to_chinese()[..] 1 处。例:name[0..1] → name[0..0](/kungfu/class/emei/tobebonze.h:40);name[2..3] → name[1..1](/kungfu/class/shaolin/cheng.h:164);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:1771)。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)。本库 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(一格两个空格)。本库 2 处(1 个文件)。证明(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)。本库 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… 行。