Tales of Wulin Heroes: Soul of Yan-Huang (Public Final, 2016-12-08 Build)

✅ 可玩

炎黄武魂public-final-2016-12-08

yhwhpublicfi

🔑 wlqxztest(密码见 README) 更新 66a3bd8 2026-10-28 源码 下载 ZIP

▶ 开始游玩 · Play Now

游戏内标题为《武林群侠传》之炎黄武魂,`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

内容亮点

本次修复的关键 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 → 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 崩溃)

深度功能测试(§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

转档遗漏:三个从未转码的 GBK 遗留文本档案(AGENTS.md §4.1)

用整棵 work/ 树的 Python UTF-8 解码扫描(排除 backup/、字体、 二进制存档等已知非文本内容)找到 3 个仍是原始 GB18030 字节、从未 被转档管线处理过的无后缀纯文本档案,和 §4.1 记录的 yhyxs/ yanhuangwuhun(同为 yh2003 血统的手足档案)一字不差是同一批档 案:

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 类别

实机游玩记录

用新注册的测试角色「秦风」(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) 权限真实生效,不只是登录横幅显示。

一处走查但判定为内容问题、未改动

§7.100 修复(ROOM 基类多余 replace_program(),2026-08-19)

``§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.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 同源的三处编译警告

验证:改动的文件和包含 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-13)

scripts/lpc_twin_port.py adopt yanhuangwuhun yhwhpublicfi 搬来 yanhuangwuhun 整理(89552da089f)里与本库逐 token 相同的 12 个文件,能编译的文件警告清零;改动的 13 个对象在 HEAD 与工作树各载入一次:HEAD PASS 12,tree PASS 12,regress 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)

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 而本库没有的头文件一起带来。每个基类补回后单独载入,再载入使用它的对象,载不进来、或一个用户也载不进来的撤掉了。

逐个与 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… 行。