The Smiling, Proud Wanderer (Final Edition)

✅ 可玩

笑傲江湖(最终版)

xo_final

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

▶ 开始游玩 · Play Now

笑傲江湖(最终版)是以金庸小说《笑傲江湖》为背景的武侠 MUD,属于 TMI-2/ES2(Falcon 系)引擎家族,在"笑傲江湖迷你版"(xo)几乎逐文件沿用的地图和无量派设定基础上大幅扩充而成,作者自称"自玩测试站",扩出了 10 座城市、16 大门派(少林、武当、峨嵋、昆仑、丐帮,以及慕容世家等跨作品客串门派)的完整世界;新玩家从"新手培训站"开始,逐步学习基本指令、领取新手礼包,再踏入江湖闯荡,比迷你版更照顾新手的引导设计;新角色开局 10 分钟内还不能存档退出,此时执行 `quit` 并二次确认不会保存进度,而是直接销毁角色——一个刻意防止刷号的设计。

English

A wuxia MUD set in Jin Yong's "The Smiling, Proud Wanderer," greatly expanded from this collection's Mini Edition (xo) into a much larger world of 10 cities and 16 sects (Shaolin, Wudang, Emei, Kunlun, the Beggars' Sect, and more, alongside crossover sects like the Murong clan). The author describes it as their own private test server. New players start at a dedicated newbie training station that walks them through basic commands and hands out a starter kit before they head out into the jianghu, and characters can't save-and-quit during their first 10 minutes of play -- quitting early destroys the character on confirmation rather than saving it, a deliberate anti-account-farming design.

README

内容亮点

在线试玩

https://mudlibs.fluffos.info/xo_final/

管理员账号 / Admin account

警告:这是一个公开的默认密码,仅供本地/浏览器试玩。正式对外开服前
请务必修改此密码。

本地运行

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

游戏端口:40024。

NOTES · 移植与修复记录

xo_final — 笑傲江湖最终版1.2 (The Smiling, Proud Wanderer — "Final" Edition)

Archive: xo最终版1.2.rar. Port: 40024. Status: done (boots clean, full registration flow verified end-to-end including a real Chinese name).

What this is

Same TMI-2/ES2 (Falcon) lineage as xo (#28), but the full, un-trimmed "final" build — ~7,174 .c files vs xo's 1395 "mini edition". Same secure/daemon/{master,sefun} layout. A homebrew test-station banner ("自玩测试站... 本lib是在mini xo基础之上,全新设计开发而成") confirms this is a fork built on top of the mini edition.

Fixes applied

1. AGENTS.md §4 (lazy security-daemon load): applied proactively to secure/daemon/master.lpc's valid_write/valid_read, same shape as xo. 2. AGENTS.md §15h (GBK byte-range Chinese detection): secure/sefun/ chinese.lpc's is_chinese, system/daemon/band.lpc's IsLegalName, and system/daemon/logind.lpc's length checks all fixed to the CJK codepoint range / halved character-count bounds, applied proactively from the catalog before first boot. 3. New: "comment eats next line" typo, found twice — a Chinese-text comment line with no leading whitespace runs // right into the start of the *next* physical line's code, silently deleting a function declaration and leaving a dangling {: - system/skill/basic/kongshou.lpc: // ...int is_native_skill()\n{ - d/menpai/shaolin/npc3/hui_quest.lpc: // ...if ( random(...) < 100 ) Both fixed by moving the comment to its own line above the code. 4. Lossy GBK→UTF8 conversion corruption: convert_lib.sh's iconv -c pass silently drops genuinely-invalid byte sequences in some raw .c files, occasionally eating a string literal's closing quote (breaking syntax) and sometimes leaving behind invisible Unicode Private-Use-Area characters (, ) that defeat exact-string Edit calls. Surveyed the whole tree with iconv -f GBK -t UTF-8 against the RAW pre-conversion files to find every instance (33 total flagged, most cosmetic/non-fatal); confirmed and fixed the ~8 in system/skill that actually broke compilation, reconstructing each closing quote from context (sibling "action"/"lian"/"zhaoshi" fields' patterns): mohe-zhi.lpc, yuanyang-dao.lpc, taizu-quan.lpc (two spots), dagou-bangfa.lpc, dugu-jiujian.lpc, baye-zhui.lpc. The two with hidden PUA characters needed Python line-index read/write instead of the Edit tool's exact-substring match.

Interactive test result — full registration flow

Verified the complete registration path in one continuous connection (critical per the user's explicit instruction not to stop at "reaches a prompt"):

1. new → 欢迎光临笑傲江湖3 / English-name prompt. 2. English id (myxoidfull) → passes IsLegalID, reaches the "确定吗(y/n)?" confirmation. 3. y → reaches the Chinese-name prompt. 4. Real Chinese name 赵云 → accepted (no rejection message), proceeds straight to "请设定您的密码:" — this is the actual proof the §15h fix works, not just that the prompt renders.

Also confirmed (as expected, not a bug): empty input at the English-name prompt triggers a polite disconnect; BAN_D->IsTimeAllowed's anti-flood throttle (3 real minutes between new registrations from the same IP, enforced via an in-memory NewIps mapping in band.lpc, cleared by restarting the driver) rejects a second new attempt from the same source within the window with no output at all (die()'s error message is commented out at logind.lpc — this is intentional silence, not a swallowed error; don't mistake it for a bug when retesting).

lpcc sweep

Memory warning (new data point for AGENTS.md §6b): this ~7,174-file lib drove the host to ~214MB free / 18.8GB RSS on the lpcc process after ~12 minutes despite being far smaller than the previously-documented "tens of thousands of files" nitan-family threshold — file count alone does not predict memory blowup risk. Monitor free -h/process RSS on *any* sweep, not just presumed-large ones, and kill proactively if pressure gets severe. Reached a clean boot (zero compile errors in the boot log) after the fixes above.

2026-07-23: driver rebuild retest + LPC formatter + WASM check

WASM-enablement pass (loopback-allow / gate bypass / admin seed)

Standard WASM-first pass per AGENTS.md §1.3b/e and §1.5. Gates patched (all in system/daemon/band.lpc, the live BAN_D — xoban.lpc is orphaned/unreferenced, left untouched):

Admin account seeded: id fluffos, pw Mud@2026, name 浮浮, granted (admin) via fluffos (admin) appended to secure/etc/wizlist. Verified: real registration (new/fluffos/y/浮浮/pw×2/email/m → landed in 新手培训站, auto-save fired), relogin as fluffos → update /system/daemon/band → 成功, score correct. Retest: two fresh normal registrations (秦风 m, 秦岚 f) end-to-end; test char saves removed; zero new debug.log errors. Note: this lib's email prompt actually validates format — [email protected] is rejected, use a normal-looking address. Save file: work/data/user/f/fluffos.o (NOT gitignored — normal add, no force-add needed).

Fail-closed retrofit for the loopback-allow gate (2026-07-24)

The loopback helper above was originally written matching the project-wide convention at patch time (AGENTS.md §1.3b), which also treated an empty/non-string/malformed query_ip_number() result as loopback, defensively, because the WASM driver used to return garbage there. That underlying driver bug is now fixed (fluffos commits e33bb5da "fix: query_ip_number() returned uninitialized garbage under WASM" and 007bb863 "feat: synthetic resolve() on WASM instead of raising an LPC error", both 2026-07-23; the locally-built build-debug/build-wasm binaries already postdate both commits), so treating unparseable IPs as trusted is a fail-open gap with no remaining justification. Retrofitted to fail-closed: loopback is now strictly ip == "127.0.0.1" || ip == "::1" || ip[0..3] == "127." (with a stringp() guard before the slice) — a malformed/empty IP now falls through to the NORMAL gate instead of being treated as local. Retested after tightening: fresh driver boot clean, fluffos loopback login and its wizard update command both still work; zero new debug.log errors.

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

同一血统,完整的'final'构建版本。

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

深度功能测试 / Deep functional test (2026-08-07)

第一次真正的完整游玩测试(此前几轮都只验证了注册/look/score/quit 和管理员登录,没有实战、门派、持久化)。测试角色 id xofdeep,中文名 云梦仙,拜入峨嵋派后法号"静仙"。本轮 WASM 未重新验证:emsdk 工具链下 载硬编码指向 storage.googleapis.com,本次会话的出口代理策略性拒绝该 域名(403,已用 curl $HTTPS_PROXY/__agentproxy/status 确认是策略拒 绝而非临时故障),本地无法构建 WASM 驱动。

本档案体量巨大(~7,174 个 .lpc 文件),原生 debug(ASAN/UBSAN)驱动 下几乎每条指令第一次触发某个尚未编译过的文件时都会有数秒到十几秒的 延迟(不是死锁,只是懒编译开销大),测试过程中多次原样等待而非误判 为卡死。

发现并修复:toptend.lpc 的排行榜数据文件缺失时,每一次玩家登录都会崩溃(AGENTS.md §7.54 已知模式的又一实例,触发原因是错误的 file_size() 判断值而非完全没有判断)

`` *Bad argument 1 to explode() Expected: string Got: 0. 函数调用堆栈: get_passwd() /system/daemon/logind.lpc:235 enter_world() /system/daemon/logind.lpc:607 topten_checkplayer() /system/daemon/toptend.lpc:40 topten_add() /system/daemon/toptend.lpc:354 ` logind.lpc 的 enter_world()——每一次玩家真正进入游戏世界都会调用 ——无条件调用 toptend_checkplayer(),后者又为年龄/杀人数/内功/拳 法/轻功/剑法/刀法/短兵刃/长兵刃/经验/钱财/总纲这 12 项排行榜各调用 一次 topten_add()`。

``lpc if (file_size(f_name) == 0) { ... // 写一份全新的排行榜文件 } //主要程序! ... str = read_file(f_name); astr = explode(str, "\n"); ` 只处理了"文件存在但大小为 0"的情况,没有覆盖file_size()返回 -1 (文件根本不存在)的情况——而 libs/*/work/data/topten/ 这整个目 录在项目的 .gitignore 里被标记为"可重新生成,不纳入版本控制" (# Lib similarity/lineage analysis data -- regenerable via ... 一节)。也就是说这不是这份归档特有的缺陷,而是任何一次真正的全 新 git clone 都会必然触发:file_size()==-1(不等于 0)→ 落 入下面的"主要程序"分支 → read_file() 对不存在的文件返回整数 0(不是空字符串)→ explode(0, "\n") 抛出上面的错误。同一文件 里另外两处功能类似的读取(topten_query() 第 125 行、topten_del() 第 243 行)都正确地写的是 file_size(f_name) == -1`,证明这是那一 处判断值写错了,不是设计上刻意如此。

观察但未修改:库存列表中某个物品的 ANSI 颜色码首字节(ESC,0x1B)在发送给玩家的字节流里神秘缺失,怀疑是驱动层问题,未能定位根因

测试内容与结果

§7.100 扫描修复(ROOM 基类多余 replace_program())

#define ROOM STD_DIR "room/room"(STD_DIR = /system/std/,宏 名本身仍是字面量 ROOM,源码里的调用不受拼接影响):删除 615 处 多余的、独立成行的 replace_program(ROOM);(保留 inherit ROOM;),全部由脚本自动删除。本库没有任何在游戏内建造房间的工具 (roommaker/rmmaker 等名称均未找到),因此没有"工厂"侧需要修 复。修复后全库仅剩 11 处历史遗留的 //-注释掉实例,均确认无害、 未改动。已用 build-debug 驱动干净启动验证(0 个新增编译错误,端 口 40024 正常监听,debug.log 无新增 "cannot replace"/"cannot bind" 行);未做完整 §10.7 深度游玩测试。

深度功能测试第二轮 / round-four §10.7 (2026-08-20):真实战斗致死与重生

补全上一轮(2026-08-07)明确标注为"未测试"的缺口——真实战斗导致死 亡、进入地府、转世重生的完整闭环。角色 id xodeath,中文名死测生。

测试方法

system/std/char/character.lpc 的 heart_beat()(第 106 行)确认 了本库的死亡触发模型与本 session 已测过的 xyxy2/xajhxo 同宗: eff_kee/eff_sen/eff_gin(不可自然恢复的"内伤"值,只被 receive_wound() 扣减)任意一项 < 0 时直接 die();kee/sen/ gin(可恢复的"体力"值)< 0 则只是 unconcious()(安全,30+ 秒后 revive())——这正是 duilian 陪练"不会造成伤害"的设计基础 (duilian.lpc 帮助文本明确写"对练不会造成伤害",它走的是完全独 立的 duilian_ob() 逻辑,根本不调用 receive_wound())。

用管理员账号 fluffos(本库已有的 (admin) 账号)通过 call xodeath->set("eff_kee",3) 把测试角色的"内伤"值预先调到接近 归零(正常新手默认 max_kee=165),再 call xodeath->move("/d/place/newbie/lianwu_chang") 把角色传送到新手练 武场——这里除了安全的 duilian 指令外,也有可以真实 kill 的普通 NPC「陪练」(d/place/newbie/npc/pei_lian.lpc,非"陪练"专属安全对 象,未设 no_die/no_fight)。对 kill peilian 发起真实战斗(kill. lpc 会调用双方 kill_ob(),NPC 真实反击),几回合后一次「陪练」 的真实命中(receive_wound)让 eff_kee 转负,下一次 heart_beat 触发真死:「你满身血迹,再也支持不住,一头撞倒在地上,腿蹬了几 下,眼见是活不成了。」——移动到 DEATH_ROOM (/d/place/death/yellow1,黄泉路)。

之后角色(无携带物品,i 显示"你身上没有任何东西")按黄泉路系列 房间一路 north 走完全程:黄泉路→黄泉路(2)→鬼门关→酆都地府(1)→ 酆都地府(2)→阎罗大殿,在阎罗大殿遇到"查察司判官"(即 d/place/death/npc/chacha.lpc)。该 NPC 的 init()→check_rein() (新角色 age<=15 自动满足条件)→death_stage() 五段式对话状态 机在几次移动的间隔时间里自动跑完,最终 reincarnate() 清空 ghost 标记、把角色传送到三个随机复活城市之一(本次是魁星阁/扬州), score 确认状态从"孤魂"变回"平民",且"你经历过一次死亡"的死亡计 数正确写入存档;quit/重新登录后死亡计数、门派/属性状态在真实的 保存-加载周期后依然一致。全程 debug.log 保持完全空白,零错误。

§7.112 死亡状态机重入守卫——现场验证,确认干净

按本 session 在 xajh2/xajhxo 上两次发现并修复的模式( death_stage() 某个出口分支没清 death_stage_active 重入守卫, 把幽灵永久卡住),逐分支核对了本库仅有的两个同类状态机:

两个文件都是干净的,不是本库的实例——这次实测(含真实经过两个状 态机)也没有触发任何卡死。

标准检查清单快速过一遍(均确认已修好/本来就干净,不再重新推导)

结论

本轮唯一明确指派的缺口(真实战斗→死亡→地府→转世重生的完整闭环) 已完整走通,全程零 debug.log 错误,未发现新 bug;标准检查清单 七项全部确认干净/已修复。测试角色存档(xodeath)事后已清理,管 理员 fluffos 及背景 NPC 存档因驱动运行产生的正常增量已随本次提 交一并保存。

深度功能测试(§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)— here-document terminators

scripts/lpc_fix_heredoc_terminator.py --all --apply: 1 here-document block(s) repaired (1 with the terminator glued to the last text line, 0 with it indented), so End of file in text block no longer hides the room or object behind them: d/city/dali/huating.lpc. The terminator must start its line (the lexer's own test, KB 04 §6.10); a glued one lost its newline in the GBK -> UTF-8 conversion together with a half character, which stays out.

深度功能测试(§10.7,2026-10-07)— 兵器的 actions 函数指针

set("actions", (: WEAPON_D, "query_action" :));:旧 MudOS 把 (: 字符串, "函数" :) 当作 call_other 函数指针,本驱动把它当作表达式函数指针,求值只得到字符串 "query_action"。没有对应兵器技能时 feature/attack.lpc 直接用兵器的 actions,COMBAT_D 拿到的不是 mapping,reset_action() 后仍不是,记一条 bad action 就不出招——拿着这些兵器打不出攻击。改成别的兵器早已用的 (: call_other, WEAPON_D, "query_action" :)(KB 04 §6.10):d/menpai/wuliang/west/npc/obj/flower.h。改动的文件在 HEAD 与工作树分别加载(新进程),无回退。

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

scripts/lpc_warnings.py xo_final --fix 加 scripts/lpc_fix_no_effect.py --apply,共改动 178 个 .lpc 和 10 个 .h(多为删去未用的局部变量)。HEAD 与工作树分别加载(新进程):172 -> 172 通过,无回退;改过的头文件的 296 个包含者 295 -> 295 通过。

启动时警告 25 -> 0;新进程登录(输入名字)正常。

深度功能测试(§10.7,2026-10-08)— .lpc 后缀的定宽切片

.c 改名 .lpc 时只改了字符串没改切片宽度:f[<2..] == ".lpc" 拿两个字符比四个字符,永远不成立(!= 永远成立),按后缀筛文件、去后缀的代码因此从不运行或截成 x.l(KB 06 §7.238)。scripts/lpc_lpc_suffix_slice.py --apply 改了 2 处比较、0 处去后缀(如 secure/daemon/httpd.lpc);改动的文件 HEAD 与工作树分别加载(新进程),无回退。

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

scripts/lpc_warnings.py xo_final --fix 加 scripts/lpc_fix_no_effect.py --apply,共改动 3 个 .lpc(多为删去未用的局部变量)。HEAD 与工作树分别加载(新进程):3 -> 3 通过,无回退。启动时警告 0 -> 0;新进程登录(输入名字)正常。

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

编译警告收尾(2026-10-13)

scripts/toolkit_fix.sh 一轮去掉 2 处多余继承(d/pig/pigroom.lpc 等),模板与迷宫两类照 nt6 的改法搬来,其余手工,能编译的文件警告清零。改动的 23 个对象在 HEAD 与工作树各载入一次:HEAD PASS 23,tree PASS 23,regress 0。

family 映射(再补)(2026-10-15,KB 05 §7.30)

mapping fam; fam = (mapping)ob->query("family");(先声明后赋值)和泥潭式的 query("family", me) 同样直接取下标:无门派的新人拜师(attempt_apprentice/recognize_apprentice)、NPC 的 greeting、房间的 valid_leave、ask_me 等报 Value being indexed is zero。5 处补上 if (!mapp(fam)) fam = ([ ]);(刚 recruit_apprentice() 之后的除外)。

NPC 带着本库没有的物品,载入失败(2026-10-15,KB 06 §7.73)

12 个文件、15 处在 create() 里 carry_object("<本库没有的文件>")->wear()(或 wield()、set_amount()):carry_object() 得 0,接着的调用报 Bad argument 1 to EFUN call_other(),NPC 根本载入不了,该有它的房间里就少了这个人。多是从别的系统搬来的 NPC 用了原系统的物品路径(最常见:/kungfu/class/gaibang/obj/blackcloth、/d/city/lanzhou/clone/obj/cloth1、/d/city/dali/npc/obj/yifu3)。每处改为 { object carried_ob = carry_object(...); if (carried_ob) carried_ob->wear(); }(scripts/lpc_guard_carry_object.py):NPC 照常出现,只是不带这件东西;文件补回来(或是虚拟对象)照样会带上。载入检查:改动的文件改前能载入 12 个,改后 12 个(0 个原来载入不了),没有退步。

tuzhong1 里的全角逗号(2026-10-18,KB 03 §4.6)

d/zuzhi/yipin_tang/peacock/xuanwu_tang/npc/tuzhong1.lpc 的 set_name("徒众", ({ "tu zhong" , "tuzhong" })) 里一个逗号是全角的 ,(Illegal character 0xef),NPC 载入不了。换成半角 ,。载入:通过。

通向不存在房间的出口,按对面房间的回头出口改正(2026-10-18,KB 06 §7.257)

房间出口 "west": __DIR__"xxx" 指向的文件本库没有,玩家走过去就被卡住(笔误、改过名的房间,或者没带进档案的编号房间)。对面的房间存在、并且它相反方向的出口正好指回这个房间,说明出口原本就是通向它:/d/zuzhi/yipin_tang/peacock/xuanwu_tang/midao 的 down:yandong1.lpc → yandong。改动后每个出口都能解析到本库的文件(scripts/lpc_fix_dead_exits.py;目标在运行时本来就能载入的库——虚拟房间——不动)。

被注释吞掉的 inherit / include(2026-10-19,KB 06 §7.274)

/d/city/yangzhou/npc/obj/guo.lpc:#include <ansi.h>。这些指令接在上一行 // 注释的末尾(档案里丢了换行),成了注释的一部分,驱动看不到:缺 inherit 的技能报 Undefined function offensive_target,缺 #include <weapon.h> 的兵器报语法错误。scripts/lpc_fix_swallowed_directive.py 把换行放回去。载入检查 1 个文件,1 个原来编译不过、现在载入,没有退步。

补回丢失的标点(2026-10-19,KB 03 §4.6)

转换时丢掉的分号、逗号、引号或文件末尾的 },共 4 个文件,修前 HEAD 载入失败。别的库里同路径的完好副本只比这里少几个标点,按它补回(括号里是那个库):/d/zuzhi/yipin_tang/dixia/shuangqi.lpc(xajhxo)、/d/zuzhi/yipin_tang/dixia/suni.lpc(xajhxo)。一行文字在逗号前丢了结尾的引号(下一行是同一个表的下一项),补上:/d/menpai/wuliang/npc/zuo.lpc、/d/menpai/wuliang/west/npc/xin_shuangqing.lpc。修后与 HEAD 逐个对比载入:这 4 个物件全部载入,没有退步(scripts/lpc_restore_from_twin.py、lpc_fix_eaten_quote.py --comma、lpc_fix_eof_braces.py)。

补回标点后新载入的物件里的未使用局部变量(2026-10-19,KB 04 §6.10)

之前载入失败、补回丢失的标点后才载入的物件里还有未使用的局部变量警告,共 1 个文件:/d/menpai/wuliang/west/npc/xin_shuangqing.lpc。删掉没有用到的声明;用 scripts/lpc_listcheck.sh 对比 HEAD 和改后,物件仍然载入,没有警告。

旧驱动的类型宽松:缺省参数、无类型形参、数组初始化、class 变量(2026-10-19,KB 04 §6.19、§6.20)

原来的 MudOS 把调用少传的参数补 0、把没写类型的形参当 mixed、不检查变量的声明类型与初始值,也允许变量叫 class;这个驱动在编译时全部拒绝,整个物件载入失败。修了 2 个文件:/d/zuzhi/yipin_tang/peacock/xuanwu_tang/develope/boat.lpc、/d/zuzhi/yipin_tang/xuanwu_tang/develope/boat.lpc(scripts/lpc_round_files.py 的修复轮:调用处补写 0、无类型形参补 mixed、string X = ({...}) 补星号、void 函数的返回值,以及 class 变量改名 pick_class)。逐个文件在 HEAD 和改后载入对比:这些文件里 0 个原来载入失败、现在载入,没有退步。

set_wugong() 对没有文件的技能不再中止物件(2026-10-19,KB 06 §7.256)

system/feature/char/skill.lpc 的 set_wugong() 经 set_jibie() → check_skill() 对没有技能文件的名字 error(),授了这种技能的 NPC 在 create() 里中止(本库缺 baidu-dao、lingshe-shenfa、pikong-zhang、panshe-dao、jumang-shenfa、qinglong-zhua、ny-bufa 等,共 11 个物件授了它们)。同文件的 set_xiuwei() 早就用 if (!valid_skill(skill)) 绕开这一情形,set_wugong() 开头加同样一行:if (!valid_skill(skill)) return 0;,物件照常载入,只缺这一项技能(缺的技能仍是内容缺口)。修后在这 11 个物件和 system/menpai/ 的 9 个物件上对比 HEAD 与工作树:载入 18 → 19(weishi2),没有回归,没有警告;system/menpai/autoresetd.lpc 仍失败(读 /etc/roomreset,存档里没有这个文件)。

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/verb/mazemap.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 处)。改动:/d/city/yangzhou/shufeng_guan.lpc(1 处)。

登录密码超过 255 字节:crypt() 抛错(2026-10-20,KB 06 §7.294)

驱动的 crypt() 对超过 255 字节的密钥直接报错(Error in crypt(), check your salt),老驱动则按任意长度散列。在登录提示符下输入 256 字节以上的密码,密码检查那一行就抛错,连线停在一个裸的 > 提示符上,登录走不完(password 指令的旧密码检查同样);用 300 个 x 当参数的扫描发现的。/secure/daemon/sefun.lpc 里补了一个同名的 simul_efun crypt(key, salt):只有超长的密钥才被截短(先截到 255 个字符,再逐字符截到 sizeof(to_buffer(key)) <= 255,限制按字节算,一个汉字占三个字节),再交给 efun::crypt();普通密码原样散列,已存的密码散列不受影响(scripts/lpc_add_sefun.py crypt)。

join、accept 对档案里没有的擂台房间调用函数(2026-10-20,KB 06 §7.270 / §7.288)

cmds/verb/join.lpc 和 accept.lpc 开头是 object tai = load_object("/d/place/biwu/biwutai"); if (!tai->query_temp(...))。比武大会的擂台房间 /d/place/biwu/biwutai 不在档案里(d/place/biwu/ 下的报名处、大厅、等候室和各门派擂台房都在,唯独缺它),load_object() 答 0,于是直接敲 join 或 accept 就是 Bad argument 1 to call_other()(本库的错误处理把它写进 /log/runtime/cmds,并对玩家说“运行时发生错误”)。两个命令现在先测 objectp(tai),房间不存在就按原来的话回答“现在不是报名/比武时间”。比武大会本身(vote ... start、巫师命令 biwu、reward_d 的 record())依赖同一个房间,仍然不工作,那是档案缺的内容,没有碰。实测(xo_final):join 答“现在不是报名时间,你不能去报名。”,accept 答“现在不是比武时间,你不能接收邀请。”,控制台没有错误;加载检查 2/2,回归 0。

closed 守护的心跳每秒调一次不存在的 versiond(2026-10-20,KB 01 §1.3(c))

closed.lpc 的 heart_beat() 以 if (! VERSION_D->is_version_ok()) return; 开头,本库没有 /adm/daemons/versiond:有人在闭关时,控制台每秒一条 call_other() couldn't find object '/adm/daemons/versiond',闭关的后续处理(load_all_users())也永远走不到。改成 if (find_object(VERSION_D) && !VERSION_D->is_version_ok())(KB 01 的写法:没有版本守护就当版本正常)。加载检查 OK。

巫师命令不带参数时对 0 调用 efun(2026-10-21,KB 06 §7.336)

巫师(管理员)把命令敲成不带参数时,驱动把 0 传给字符串参数;下面的命令第一句就把这个 0 交给 efun,运行时报 Bad argument 1 to ...,这条指令从来没有用过。用 scripts/lpcc_bare.py 不登录、在一次 lpcc 求值里以 0 调用 main() 逐个确认后,由 scripts/lpc_fix_bare_arg.py 在第一处使用参数的语句前加守卫:文件自带 int help(object me) 的,守卫是 if (!arg) return help(me);(help() 定义在 main() 之后的 1 个文件补了原型 int help(object me);,否则编译报 Undefined function help);没有 help() 的是 return notify_fail("…\n");。改动(3 个文件,括号里是接住 0 的 efun):/cmds/admin/empty.lpc(find_player)、/cmds/admin/testnpc.lpc(sscanf)、/cmds/imm/hbless.lpc(find_player)。加载检查 HEAD 与工作树对照,没有退步。

注册到不存在函数的 add_action,第二轮:宏路径父类和静态解析不了的对象(2026-10-21,KB 06 §7.349)

第一轮的静态解析读不了经宏路径继承父类的对象(#define ROOM STD_DIR "room/room" 这类定义的正文以另一个宏开头)和它解析不了的继承,这些对象当作 UNSURE 没有扫;第二轮修了解析器,重扫并对这些对象在运行时问 function_exists()。add_action("函数", "动词") 绑定的函数,在对象本身、它包含的头文件、它继承的父类和继承它的子类里都没有定义(scripts/lpc_scan_callout_targets.py 静态解析,子类用传递闭包复核,scripts/lpc_verify_handlers.py 运行时 function_exists() 复核)。驱动从玩家最新的一条动作往回找,遇到这样的句子就报 *Function for verb 'drop' not found.,同一个动词的其他处理函数不再尝试(不是最新的一条就悄悄跳过)。删除了 17 条注册(11 个文件,scripts/lpc_fix_dead_add_action.py),动词留给别的处理函数:/d/city/yangzhou/yuelao_ci.lpc(do_divorce)、/d/city/yangzhou/yuelao_ci_bak.lpc(do_divorce)、/d/city/yangzhou/yuelao_ci_bak_xli.lpc(do_divorce)、/d/menpai/huashan/npc/xiaoer.lpc(do_buy、do_list)、/d/menpai/quanzhen/npc/seller.lpc(do_buy、do_list)、/d/menpai/wudang/npc/xiaoer.lpc(do_buy、do_list)、/d/menpai/xuedao/npc/xiaoer2.lpc(do_buy)、/d/place/newbie/npc/lao_tou.lpc(do_vendor_list)、/d/zuzhi/yipin_tang/peacock/xuanwu_tang/xuanya1.lpc(do_droop、do_pull)、/d/zuzhi/yipin_tang/xuanwu_tang/xuanya1.lpc(do_droop、do_pull) 等共 11 个文件。最多的函数名:do_buy 4 处、do_divorce 3 处、do_list 3 处、do_droop 2 处、do_pull 2 处。

(: 函数 :) 指针指向对象自己没有定义的函数(2026-10-22,KB 06 §7.355)

item_desc / inquiry / chat_msg_combat 里的 (: 函数名 :) 指向本对象(含包含文件、继承的父类)没有函数体的函数:编译不报错,用到时驱动报 *Undefined lfun pointer called: 函数名(look 某物、ask NPC about 话题 直接出错,战斗 / 闲聊里的指针在 NPC 的 chat() 里出错,这一拍心跳的后半段被跳过)。scripts/lpc_scan_callout_targets.py --kinds=lfun。 还剩 2 个函数没有补(inquiry 2):原型还在函数体丢了、或者根本没写过,没有可以直接补回的捐赠(别的库同一路径的文件里没有这个函数,或者它还要用本库没有的辅助函数、签名不同),不编造:/d/menpai/shaolin/npc/xuwen.lpc:ask_armor2、/d/menpai/shaolin/npc/xuwen.lpc:ask_armor3。

(: 函数名 :) 指针指向本库没有的函数:只含这个指针的行加了注释(2026-10-22,KB 06 §7.355 补充)

inquiry / item_desc / chat_msg* 里的 (: 函数名 :) 指向本对象(含包含文件、继承的父类)没有函数体的函数:用到时(ask、look、NPC 闲聊)驱动抛 *Undefined lfun pointer called: 函数名,这一拍心跳的后半段被跳过。这些函数没有可以补回的来源(别的库同一路径的文件里没有,或者它还要用本库没有的东西),所以 1 个文件里 2 行只含这个指针的行("僧鞋": (: ask_armor2 :), "绑腿": (: ask_armor3 :),)加了注释,原文保留并写明原因,这一项当作没有这个话题 / 物品 / 闲聊条目(scripts/lpc_fix_dangling_lfun.py;#include 的文件在库里缺失的对象、指针不在整行上的写法没动)。 前提(function_exists())和加载检查(HEAD 与工作区对比,本库改动的 .lpc 文件)的结果见 KB 06 §7.355:没有一个回归。

写死的 "/路径"->函数() 指向库里没有的文件:改成现存的同名文件(2026-10-22,KB 06 §7.359)

2 处语句级的 call_other 字面量路径,库里没有这个文件(区域改了名 / 大小写不对 / 差一个字母 / 文件挪了地方):"/cmds/arch/xplor"->QueryLevel()(/system/daemon/biwud.lpc)→ "/cmds/app/xplor"。call_other() 对不存在的对象抛 couldn't find object,所在函数当场中断。改成库里现存、并且定义了被调用函数的文件(scripts/lpc_fix_call_path.py;巫师目录、备份目录、名字不同的兄弟文件都不算候选)。

汉字按字节切片的老写法没有换成按字符:改法名 "澄" + name[2..3]、辈分判断 name[0..1] == "澄" 等 8 处(2026-10-22,KB 06 §7.360)

原档按字节算字符串区间(一个汉字 2 字节):name[2..3] 是名字的第二个字,name[0..1] == "澄" 问名字是不是以「澄」开头。转成 UTF-8 之后,这个驱动的区间和 strlen() 都按字符算(strlen("澄观") 是 2,"澄观"[0..1] 是两个字),老算术原样留着、意思全变:拜入少林 / 武当 / 峨嵋等派的玩家被改成错误的法名(二字名 张三 变成一个字的 澄,更长的名字取到第三个字)。

本库 8 处(5 个文件):拼名字的赋值 8 处。例:name[0..1] → name[0..0](/d/menpai/emei/npc/tobebonze.h:41);name[4..5] → name[2..2](/d/menpai/quanzhen/npc/chu.h:80);name[2..3] → name[1..1](/d/menpai/quanzhen/npc/qing.h:119)。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 处(2 个文件):} else if (strlen(msg) > 16) {(/d/city/yangzhou/pplroomd.lpc:89);} else if (strlen(msg) > 40) //若长度在八个汉字以外,重新输入。(/d/place/player/newroom.lpc:86)。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 个文件。证明(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 是两字符牌码,未改。

estate ROOM_HEAD 宏引号 / #inherit / dir / retrun(2026-10-27,KB 04 §6.25 Also)

system/daemon/estate 的 ROOM_HEAD/EXIT_STRING 宏里裸双引号打断 #define,模板写成 #inherit AREA,CreateRoom 用未定义的 dir,AddItem 写 retrun 且参数 class Location 本库无此类型。改为转义引号、inherit AREA、out_dir、return、mixed location。证明:HEAD 失败;改后加载。

深度功能测试(2026-10-27,§6.25 tell_object 字符串目标)

pplroomd:tell_object("ob", …)→tell_object(ob, …)。

深度功能测试(2026-10-27,§6.25 one-arg message_vision)

message_vision("…") 补第二参(me / TP / this_player())。

深度功能测试(2026-10-27,§6.10 未知 pragma save_binary/optimize)

删除本库中 FluffOS 不认的 #pragma save_binary / #pragma optimize… 行。