Legend of Jin Yong's Heroes (2008 Deluxe Edition)

✅ 可玩

金庸群侠传(2008 超豪华版)

jqxz2008dlx

🔑 fluffos / Mud@2026 更新 6e86eb7 2026-10-27 源码 下载 ZIP

▶ 开始游玩 · Play Now

本压缩包对应"金庸群侠传"(ES II 引擎)家族的"2008超豪华版"这一内容版本,md5sum 确认与本项目中的"2008加强版"(`jqxz2008`)、"2008标准版"(`jqxz2008std`)核心引擎(master、安全、登录等关键文件)逐字节相同,这支血脉还延伸到 `xiakexing3`/`xiakexing2017` 两个更远的快照;本作在门派 NPC、战斗数值配置、部分地图场景上有独立的内容调整,文件规模也是四个 2008 系版本中最大的一个。与兄弟版本一样,新角色从店小二看店的路边茶馆起步,可经中央广场的树洞暗语加入丐帮拜入左全门下,也可走白驼山使者按资质招人的另一条路线;深度测试里走通了完整的拜师→改投另一位师父的真实"叛门"流程,验证了一次真实商店交易(扣款并拿到实物),以及一次完整的战斗死亡→黑无常鬼门关→转生复活。

English

The "Deluxe" build of this project's 金庸群侠传/"Jin Yong Heroes Gathering" (ES II engine) family -- md5sum-confirmed byte-identical core engine (master, security, login, Chinese-text daemons) to sibling jqxz2008 and jqxz2008std, but the largest actual content build of the three (3,811 raw files vs. jqxz2008's 3,773), with its own sect-NPC roster and combat-number tuning (the city2 imperial-palace-gate district some earlier notes flagged as Deluxe-only is actually present in all four editions, file-count-verified -- not a genuine difference). Shares the same tea-house starting point, Beggars'-Sect passphrase-hideout join, and White Camel Mount recruiter path as its siblings.

README

内容亮点

在线试玩

https://mudlibs.fluffos.info/jqxz2008dlx/

管理员账号 / Admin account

警告:Mud@2026 是本地游玩用的公开默认密码。若要正式对外开放主机,
请先修改此密码(或从 wizlist 中删除该账号)。

本地运行

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

游戏端口:40085。

NOTES · 移植与修复记录

jqxz2008dlx — 金庸群侠传 (Jin Yong Heroes Gathering, deluxe)

Archive: archives/金庸群侠传2008超豪华版.rar ("Jin Yong Heroes Gathering 2008, super deluxe edition"). Extracted mudlib root: raw/jy/ (a single top-level jy/ directory inside the archive, same layout as archive #91). Port: 40085. Status: done (boots clean, full registration flow verified 3 times with real Chinese names, post-login look/score/quit verified working each time).

What this is / lineage (confirmed via md5sum BEFORE doing anything else)

config.cfg's name field (GB18030-decoded: bd f0 d3 b9 c8 ba cf c0 b4 ab -> 金庸群侠传) matches the archive title exactly.

Confirmed byte-identical core engine to jqxz2008 (archive #91, libs/jqxz2008/), checked via md5sum on the raw archives before any conversion, per the task brief's lineage-check instruction:

| file | md5 vs #91 | md5 vs xiakexing3(#44) | |---|---|---| | adm/obj/master.c | identical | identical (matches #91's own prior finding) | | adm/single/master.c | identical | identical | | adm/daemons/logind.c | identical | identical | | adm/daemons/securityd.c | identical | differs (matches #91's prior finding that only securityd/config differ vs xiakexing3) | | adm/simul_efun/chinese.c | identical | identical | | adm/daemons/chinesed.c | identical | identical |

So this archive is confirmed to be the same underlying engine core as #91, exactly as the task brief predicted (title-family: xiakexing3(#44), #91, #92, #93, #94 all share the 金庸群侠传/侠客行 lineage). Per the task's explicit instruction, all of #91's proven fixes to these byte-identical files were ported directly rather than rediscovered from scratch (see below) — verified line-by-line via diff against #91's already-fixed work/ copies before applying each one, not assumed.

However, this is NOT a duplicate/near-duplicate of #91's overall content — it's a genuinely different content snapshot on the same engine (the same relationship as "different game version, same server software"). diff -rq of the two raw archives shows: file count differs (3773 raw files in #91 vs 3811 here), and dozens of zone/NPC/room files differ byte-for-byte between the two (combatd.c has different combat-formula tuning, chard.c/updated.c/several d/ zone files differ, several files exist only in one archive or the other e.g. clone/board/ mingjiao_b.c only here, d/mingjiao/guangmingding.c only in #91, etc). This matches the established shujian2008/sjtx2 and zhongjidiyu-family precedent: same engine, different content build.

Cross-check note for later archives (per task brief): archive #92 (金庸群侠传2008版.rar, being processed concurrently by a sibling agent into libs/jqxz2008std/ at the time of this writing) and archive #94 (金庸群侠传2015版.rar, not yet started) were NOT cross-checked against this lib (concurrent/not-yet-processed, per the task brief's own caveat) — whoever processes or reviews #94 next should md5sum its adm/obj/master.c/adm/daemons/logind.c/adm/simul_efun/ chinese.c/adm/daemons/chinesed.c against both #91's and this lib's raw copies; given the pattern held for #91 vs xiakexing3 vs this lib, there's a real chance #94 is yet another same-engine snapshot.

Small-to-medium lib: 3,811 raw files, 3,171 .lpc/.c files sweepable by lpcc_check.sh.

Fixes applied (with why) — ported from #91 after confirming applicability

For every fix below, the underlying file was diffed against #91's pre-fix/post-fix state first; only fixes confirmed applicable (identical buggy pattern actually present in this archive's copy) were applied. Nothing was applied blindly on lineage-assumption alone.

1. AGENTS.md §15h (is_chinese / check_legal_name — GBK byte-range checks silently wrong under UTF-8 strings). Confirmed via diff that adm/simul_efun/chinese.lpc and adm/daemons/logind.lpc were BYTE-FOR- BYTE identical to #91's own pre-fix originals (not just "similar") — ported #91's exact fix verbatim: - chinese.lpc's is_chinese(): GBK lead-byte range (str[0] > 160 && str[0] < 255, strlen>=2) → CJK Unified Ideographs codepoint range (str[0] >= 0x4e00 && str[0] <= 0x9fff, strlen>=1). - logind.lpc's check_legal_name(): byte-count bound strlen(name) < 2 || > 12 → character-count bound < 1 || > 6; dropped the i%2==0 && even-byte-offset gate. - Verified working: real Chinese names "秦风", "秦风二", "秦风三" all accepted on the first try across 3 separate registration runs.

2. AGENTS.md §15ae (private nomask command-hook breaks every post-login command silently): feature/command.lpc's command_hook was private nomask (same as #91); home/command.lpc's copy was already correct (nomask only, no private) — same split as #91. Dropped private from the feature/ copy. Verified: look and score both work correctly post-login in all 3 test runs.

3. AGENTS.md §15t (variant 1 + variant 3, combined): combatd.lpc DIFFERS from #91's copy in its combat-formula numbers (this is the deluxe edition's own balance tuning), but the include/inherit-ordering bug was present in BOTH: #include </quest/quest.h> (absolute path inside angle brackets, never resolved by this driver's inc_open()) placed AFTER inherit F_DBASE; in source order but the file-scope global quest_name it defines textually preceded the inherit once included — a fatal "Illegal to inherit after defining global variables". Fixed identically to #91: moved inherit F_DBASE; above all #includes, and changed #include </quest/quest.h> to the quoted absolute form #include "/quest/quest.h". Verified: score (which needs combatd) works cleanly post-fix; before the fix this would have thrown *No program in object '/adm/daemons/combatd'! exactly as it did in #91.

4. The same capitalize()-on-0 robustness bug in feature/name.lpc: byte-identical to #91's pre-fix short(int raw) fallback (capitalize (query("id")) with no guard). Applied the identical stringp(id) guard fix. Not independently re-triggered via a live crash this time (the tea-house board /clone/board/kedian_b in this archive also has no "short" set, same as #91, so this WOULD have crashed look there without the fix — pre-emptively fixed before first boot per the task's explicit "apply proactively before first boot" instruction, then confirmed look works cleanly with the fix in place).

5. d/city/npc/guidao.lpc's is_killing(who) direct-call type mismatch: byte-identical bug to #91 (is_killing(who) instead of is_killing(who->query("id"))). Fixed identically.

6. The "tang"-family NPC template's new used as a bare variable name: present identically in the same 7 files as #91 (d/quanzhou/npc/{tang, tang1,tang2,tang3}.lpc, d/taishan/{tang2,tang3,xingtang}.lpc). Renamed the local variable new → newob throughout (declaration + both usages) in all 7 files, exactly as in #91 — the actual new(...) efun calls are untouched.

7. AGENTS.md §15ac (bare SAVE_EXTENSION instead of __SAVE_EXTENSION__): found in the SAME 6 files as #91 — include/net/ftpdsupp.h, adm/daemons/network/netmail.lpc, cmds/arch/purge.lpc, d/quanzhou/npc/tang.lpc, d/quanzhou/npc/ tang3.lpc, d/taishan/tang3.lpc. Fixed identically. Left alone (same as #91): clone/npc/meng-zhu.lpc and u/jackyboy/TOKEN.C, which both #define SAVE_EXTENSION ".o" locally.

8. kungfu/class/mingjiao/mingjiao.h's string-literal-adjacent-to- macro-expansion syntax error (== HIG "明教" NOR with no + operators): present identically. Fixed to HIG + "明教" + NOR. A genuine divergence from #91 found here: this archive's raw copy of kungfu/class/mingjiao/mingjiao.h ALREADY had #include <ansi.h> at the top (confirmed via the raw, pre-conversion .c file, not just the converted copy) — #91's raw copy was missing it and needed it added. So only the syntax-error half of #91's two-part fix applied here; the <ansi.h>-add half was already unnecessary. Also found and fixed the SAME syntax bug in a SECOND, separate d/mingjiao/npc/mingjiao.h file (different file, same bug, not mentioned in #91's notes — possibly #91 didn't have this second copy hit by its lpcc sweep, or this is new deluxe-only content; either way it's the identical fix).

9. d/mingjiao/npc/changjinpeng.lpc's wrong absolute #include path (#include "/kungfu/class/mingjiao/tanzhu.h" — doesn't exist; real file is d/mingjiao/npc/tanzhu.h): present identically, fixed identically (#include "tanzhu.h").

10. d/mingjiao/npc/{fenggongying,baiguishou}.lpc's #include __DIR__"tanzhu.h": present identically in both files, fixed identically to plain quoted #include "tanzhu.h".

11. d/baituo/ouyangfeng.lpc, the same two independent pre-existing typos as #91: (a) missing semicolon after write("...") inside a switch case 0: block; (b) object me=this-player(); (subtraction typo for this_player()) in the LIVE inquiry_map() function. Fixed both. Note: this file also has a second, commented-out (/* ... */) copy of inquiry_map() containing the SAME this-player() typo at line 95 — left untouched since it's dead code inside a comment block, confirmed by reading the full comment span before deciding.

12. d/shaolin/obj/shuitan.lpc: ging_cost typo for the declared variable jing_cost: present identically at the same call site (me->receive_damage("jing", ging_cost)). Fixed identically. Note: this archive ALSO has a second, different shuitan.lpc at d/shaolin/shuitan.lpc (not present in #91) — checked it separately and confirmed it does NOT have this typo (already uses jing_cost correctly throughout) — left untouched, no fix needed there.

13. d/mingjiao/jmqshenmu.lpc genuinely truncated in the raw archive itself: confirmed via diff that this archive's raw .c file is byte-identical to #91's raw .c file (both 26 lines, ending mid- void init() { with no closing braces) — the exact same pre-existing truncation, not a conversion artifact, not something specific to this archive. Closed with an empty body exactly as in #91.

New fixes found in THIS archive (not part of #91's list — genuinely new

content/bugs specific to the deluxe edition's differing files)

14. d/baituo/obj/bowl.lpc and d/baituo/npc/obj/bowl.lpc (2 files, both named bowl.lpc in different directories, same content bug): set_name("海口大碗", "bowl") — second argument to set_name() must be an array of id strings (every sibling file in the same archive, e.g. d/baituo/npc/xiaoqing.lpc, correctly uses ({ "id1", "id2" })), but these two pass a bare string, which this driver's static type checker rejects (Bad type for argument 2 of set_name (string * vs string)) — the whole file failed to compile. Fixed to set_name("海口大碗", ({ "bowl" }) ) in both files. Neither file exists in #91's archive (deluxe-only content).

15. d/city2/npc/zhengmen.lpc genuinely truncated in the raw archive itself, in a DIFFERENT way than jmqshenmu.lpc (missing closing braces mid-function rather than mid-statement): confirmed via diff that this archive's raw .c is byte-identical to #91's raw copy of the SAME file (both 77 lines, valid_leave()'s nested if(dir== "north"){ ... } else { ... } block and the function itself are never closed) — this exact same truncation also exists, unfixed, in #91's shipped work/ copy (confirmed via diff against #91's raw and work directories — #91's own conversion never caught this one; it's not in #91's NOTES.md's fix list at all). Fixed here by adding the 3 missing closing braces (traced brace depth line-by-line with a small Python script to get the count right — first attempt under-added by one brace, caught by a second lpcc compile and corrected). This file is in a side zone (d/city2, the imperial-palace-gate NPC/room), not on the tested registration/look/score path, so it wasn't a registration blocker either way — found via the lpcc_check.sh sweep, not a live-boot crash. Cross-check flag: since #91 has this exact same latent bug still unfixed in its shipped work/ copy, this is worth a follow-up patch to libs/jqxz2008/work/d/city2/ npc/zhengmen.lpc too, though that's out of scope for this archive's own task. - After the brace fix, the file compiles but its create() still hits a runtime *Bad argument 1 to EFUN call_other() ... Got: int(0) while trying to populate its "objects" mapping (/d/city/npc/wujiang, /d/city/npc/bing — both files genuinely exist on disk) — same shape/category as the m_weapon/luguanji.lpc "call_other on 0" cases below (§6b-style isolated-compile artifact, not chased further); the syntax fix alone is the meaningful improvement (file went from "doesn't compile at all" to "compiles, loads, one populate-step artifact identical to an established benign category").

Confirmed NOT needed (byte-identical core files inherited the "not

needed" verdict from #91's own reading of the same file; independently re-verified via diff that the file text is unchanged, not just assumed)

Content gaps confirmed as real archive gaps, not bugs (AGENTS.md §13)

- d/city2/obj/luguanji.lpc's carry_object(__DIR__"obj/diaopi")-> wield() fails with the same "call_other on 0" shape even though diaopi.lpc itself compiles cleanly standalone (confirmed via a direct isolated lpcc run) — same §6b isolated-compile-context artifact class as the m_weapon files, just via carry_object() instead of a direct this_player() call. - d/city2/lilishi.lpc references /d/city/obj/tudao, which genuinely does not exist anywhere in this archive — a real missing-content gap (§13), not an isolated-compile artifact. - d/xingxiu/npc/btshan.lpc references d/xingxiu/npc/ke.lpc, which doesn't exist (§13 content gap); its sibling snake.lpc DOES exist. - d/shaolin/cangku.lpc references d/shaolin/obj/{jitui,jiudai}.lpc, neither of which exists (§13 content gap). - d/shaolin/obj/{houdian,bailongdong}.lpc reference NPCs via __DIR__"npc/..." (i.e. d/shaolin/obj/npc/...), but the actual NPC files live one level up at d/shaolin/npc/{seng-bing3,xiang-ke}.lpc — a genuine relative-path mismatch (the NPCs exist, just not where these two rooms look for them). Left as a documented content/path bug rather than fixed, since the "right" fix (change __DIR__ to __DIR__+".." or similar) needs a judgement call about original intent and this is a single side-zone, not on the registration path. - d/wudang/fuzhen5.lpc references /u/fcxy/songqing.lpc, which doesn't exist (§13 content gap; there's even a commented-out alternate reference in the same line via CLASS_D("wudang"), suggesting the original author knew this NPC's location was in flux). - d/mingjiao/npc/yinsusu.lpc, d/taohua/npc/shoumu.lpc, d/xingxiu/npc/btshan.lpc (room-self, separately from its ke.lpc NPC-population issue above) each hit a "call_other on 0" during their own create() — not individually root-caused further (side-zone NPCs, not on the registration/look/score path); documented as the same general content-gap/§6b-adjacent category. - d/taohua/taohua_b.lpc (a bulletin board) tries to move() itself into /tmp/jungu/dating, which doesn't exist — a genuine missing room/zone reference (§13). - d/huashan/map.lpc: NOT real LPC code at all — it's a plain-text ASCII map (confirmed via file: "Unicode text... with CRLF, LF line terminators", and its content is garbled box-drawing/tile characters, not a program) that happens to carry a .c→.lpc extension from the original archive; confirmed via grep that nothing in the tree ever references d/huashan/map as an object path — dead/inert data file, not a bug, not fixed. - doc/build/devil.lpc, doc/efuns/shiwu.lpc: unreferenced anywhere (grepped), genuinely-broken example/tutorial scripts under doc/ (missing semicolons, a bare do_close where a string "do_close" was clearly intended for call_out) — never loaded in real gameplay, left as-is per the same judgement as other wizard-scratch content. - cmds/usr/to.lpc / cmds/wiz/to.lpc (2 files, identical bug): a real driver-compat compile error, NOT a content gap — me->edit( (: this_object(), ({ "do_to", me, arg }) :) ) fails with "Illegal to use local variable in functional" (this driver forbids capturing a local variable inside an unbound (: ... :) closure literal the way old-style MudOS code here does it). Other ->edit() call sites in this same lib (bboard.lpc, mailbox.lpc) pass a plain function-name symbol and this_player()/parameter-only args and compile fine, so this is specific to to.lpc's particular this_object(), array calling convention. This is a real, understood bug — but it's a non-critical wizard/player utility command (composes a multi-line message via the line editor), not on the registration/look/score path, and fixing it correctly would require restructuring the closure (e.g. to a bound lambda) rather than a one-line patch, so per AGENTS.md's "prioritize breadth over depth" policy it's documented here as a known, real, unfixed compile bug rather than patched.

Interactive test result — full registration + post-login flow

Driver booted clean (setsid nohup ... & disown, PID 922298, launched from libs/jqxz2008dlx/ so log/debug.log resolves correctly per AGENTS.md §6). Zero fatal errors in log/debug.log across the whole session — only the 2 expected non-fatal caught corrupted- save-data errors (chinesed's e2c_dict.o, kedian_b's board data, both documented above) and ordinary compile *warnings* ("Unused local variable", "Illegal to declare nosave function").

Ran the full registration flow 3 separate times in 3 separate continuous mudclient.py connections, with 3 different real Chinese names, confirming the fix is robust and not a one-off:

1. qinfengjy (English id) → y (confirm new character) → "秦风" → password → confirm → accept gift stats (y) → email → gender (m) → enters game world at 客店 → look → score → quit. All steps succeeded; look re-rendered the room cleanly; score showed the full character sheet (title 平民, age/gender/birthdate, 膂力/悟性/ 根骨/身法 stats, 精/气 bars, 食物/饮水 bars, kill count, 潜能/实战经验); quit saved and discononected cleanly with the "丢下一件布衣" message (unequipped default item on quit, expected). 2. qinfengjyer → "秦风二" → same full flow, same success. 3. qinfengsan → "秦风三" → same full flow, same success (this was the FINAL post-all-fixes confirmation run, done after the bowl.lpc/ zhengmen.lpc lpcc-sweep fixes, to make sure nothing in the late round of fixes destabilized the core path).

Sample transcript (run 1, abbreviated to the state-changing prompts):

您的英文名字:使用 qinfengjy 这个名字将会创造一个新的人物,您确定吗(y/n)?
请输入您的高姓大名,...
您的中文名字:(accepted 秦风 first try — before §15h fix this would loop-reject forever)
请设定您的密码:
请再输入一次您的密码,以确认您没记错:
...膂力[23], 悟性[19], 根骨[19], 身法[19]
您接受这一组天赋吗?
您的电子邮件地址:
您要扮演男性(m)的角色或女性(f)的角色?

目前权限:(player)
[1;36m客店[2;37;0m -
    这是一家价钱低廉的客栈,生意非常兴隆。...
    这里明显的出口是 west 和 up。
  /clone/board/kedian_b [ 没有任何留言 ]
  店小二(Xiao er)
你上次连线是从0 on Wed Dec 31 16:00:00 1969

> 店小二用脖子上的毛巾抹了抹手,说道:这位小兄弟,请进请进。
[1;36m客店[2;37;0m - (look re-rendered cleanly)
> [1m【 平  民 】[2;37;0m普通百姓 秦风(Qinfengjy)
 你是一位十四岁的男性人类,...
 膂力:[ 23]  悟性:[ 19]  根骨:[ 19]  身法:[ 19]
 <精> ■■■■...  <气> ■■■■...
 战斗攻击力 1 (+0)    战斗防御力 1 (+1)
 食物:□□□...  饮水:□□□...
 你到目前为止总共杀了 0 个人,其中有 0 个是其他玩家。
 神: 0  潜能: 99 (1%)  实战经验: 0
> 你丢下一件布衣。
因为这样东西并不值钱,所以人们并不会注意到它的存在。
当你下次连线进来时,会从这里开始。
欢迎下次再来!

Note (same test-script gotcha as #91): the English id must be fresh letters-only each retry — a digit anywhere in the id (e.g. qinfengjy2) gets rejected by the English-name-must-be-letters check and, since mudclient.py sends its whole --send list regardless of prompt state, the rejection loop consumes all the scripted follow-up sends as more id attempts. Not a bug, just something to remember when re-testing.

lpcc sweep

Ran 3 times across the fix-iteration cycle via scripts/lpcc_check.sh:

Remaining 65 failures were triaged by category (AGENTS.md §6b), all confirmed via direct source reading (not guessed): 11 corrupted pre-existing board saves, 11 dead network/intermud daemon files (not preloaded, not referenced), ~13 genuinely missing zone/skill/race/NPC content (mingjiao/yuan x9, monkey/gudi3/gudi4 undefined-race, wudang/taoyuan x4 orphaned drafts, lilishi→tudao, btshan→ke, cangku→jitui/jiudai, fuzhen5→songqing, taohua_b→missing /tmp/jungu/dating), 3 wizard-scratch quest/tool files (u/liujun/ quest/{left,right}killer, u/editer/tie-luohan), 1 dead-code-only reserved-word bug (network/services/mudlist_a.lpc, unreachable), 1 sweep artifact (home/simul_efun.lpc), 1 known-unfixed-efun hit (cmds/wiz/tail.lpc, §8e), 2 non-content-gap real driver-compat bugs left unfixed as non-critical (cmds/usr/to.lpc/cmds/wiz/to.lpc's closure-capture error), 2 non-LPC/dead data files (d/huashan/map.lpc, plus the 2 doc/ example scripts), 6 §6b isolated-compile-context artifacts (5 m_weapon files + luguanji.lpc's carry_object()-> wield()), a path-mismatch pair (houdian/bailongdong → their own npc/ subdir that doesn't exist), and zhengmen.lpc's now-syntax-clean but still content-gap-flavored remainder. None of these affect registration, look, or score — all confirmed via direct source reading, not guessed.

Memory stayed healthy throughout all 3 sweeps (free -h showed ~11-19GB available before/after each run, well clear of pressure; no other lpcc/driver sweeps were running concurrently at sweep time).

Process notes

2026-07-23 re-verification pass (driver rebuild + formatter + WASM)

WASM-enablement pass (2026-07: loopback-allow + admin seeding)

Standard pass per AGENTS.md §1.3b/e + §1.5 (applied identically across the three jqxz2008 builds — engine files are byte-identical in this group):

Admin account: fluffos / Mud@2026 / 浮浮, registered through the real native flow (id → y → Chinese name → password ×2 → gift y → email → gender m). Granted (admin) via adm/etc/wizlist (file was shipped empty; now contains fluffos (admin)), which securityd.lpc reads at create(). Verified after restart: login shows 目前权限:(admin), update /cmds/usr/score prints 重新编译成功. Save files (must be committed): work/data/user/f/fluffos.o, work/data/login/f/fluffos.o.

Retest: fresh registration (秦风/ceshizhe) end-to-end + look/score/quit clean; fluffos login + wizard update clean; debug.log shows only the known pre-existing corrupted-save restore errors (chinesed e2c dict / kedian board) documented above — zero new errors; test character saves removed.

Dual-mode verification pass (2026-07-24)

深度功能测试(§10.7,本轮):移植同引擎兄弟档案 jqxz2008 已确认的 4 个 bug

这份档案自己的 README 已经说明和"2008 加强版"(jqxz2008)、"2008 标 准版"(jqxz2008std)是完全相同的服务端引擎核心,只在门派 NPC、战斗 数值、部分地图内容上有独立调整。jqxz2008 自己已经做过一轮扎实的 §10.7 深度测试并记录了 4 个真实 bug——既然引擎核心相同,这轮直接逐一 核对这些 bug 是否也存在于 jqxz2008dlx(而不是重新从零排查),四个 全部确认存在且未修复:

1. adm/daemons/chinesed.lpc(§7.7:损坏存档数据把全局 mapping 清 零)。 data/e2c_dict.o 是损坏的二进制垃圾数据(不是合法的 mapping 字面量),create() 原本是 seteuid(getuid()); restore();—— restore() 抛出的运行时错误没有在 create() 内被捕获,会让 create() 在那一行直接中止,mapping dict 被清零。第一次真正用到 chinese()/to_chinese() 的地方(战斗/技能提示大量使用)就会崩溃。 修法和 jqxz2008 完全一致:catch(restore()); if (!mapp(dict)) dict = ([]);——单独加 mapp() 判断而不加 catch() 是不够的,因为不加 catch() 那一行代码根本不会被执行到。

2. adm/daemons/combatd.lpc/cmds/std/kill.lpc/cmds/skill/{bai, apprentice}.lpc(§7.11:缺失的 /log/nosave/ 目录让 write_file() 静默中止一个多步骤清理函数)。 work/log/nosave/ 目录在这份档案里 同样不存在。最严重的是 combatd.lpc 的 killer_reward()——这个函数 在每一次死亡时都会跑到,中间不加保护地 write_file("/log/nosave/ KILLRECORD", ...),一旦目录不存在就会抛出未捕获异常,让 die() 在 那一行永久中止:角色的死亡清理(尸体、鬼魂状态、移动到死亡场景)全部 不会执行,角色变成"活着但气血精气归零"的破损状态,而且这个崩溃会在 之后的每一次 heart_beat() 都重新触发一次,变成死循环。用真实驱动 让测试角色(沈十)被"欧阳克"这个 NPC 杀死做了实测验证:你死了 → 干净地进入"鬼门关"死亡场景,NPC"白无常"正常打招呼,全程 debug.log 保持空白(十秒以上的心跳观察也没有延迟复现)。修法沿用 jqxz2008 已 验证过的 assure_file()(这份档案自己的 adm/simul_efun/file.lpc 里 已经有这个函数),在全部四处 write_file("/log/nosave/...", ...) 调 用前各加一行 assure_file(...);顺手也给 bai.lpc/apprentice.lpc 里的 read_file() 结果加了 stringp() 判断(避免 atoi(0))。

3. cmds/skill/bai.lpc/cmds/skill/apprentice.lpc(一处括号位置 错误,把 == 比较写进了 query() 的参数列表内)。 这两个完全相同 的档案里都有:

if (((string)me->query("family/master_id" == "feng qingyang")) || ...)

== 比较被夹在 query(...) 的参数括号内,所以传给 query() 的实际 是一个布尔/整数值(永远是 0),不是想要的属性名字符串——这个用来检 测"是否从风清扬门下叛出"的分支永远不可能触发。已改成先呼叫 query("family/master_id"),再拿它的返回值和字符串比较(和同一档案 里其它所有正确写法一致)。触发条件很窄(角色确实拜风清扬为师后又叛 出),本轮没有专门构造这个场景做实测,但代码结构本身已经明确证明这 是笔误而非设计判断。

以上四个 bug 全部对应到既有的 AGENTS.md §7.7/§7.11/§7.9 类别,不是新 分类,只是在同一引擎的另一个具体档案上再确认一次——这也进一步印证了 "共享同一底层引擎的多个档案(内容版本不同)值得直接核对已知 bug 列 表,而不是每份都从零排查"这条经验(和这个会话里 NT/nitan 家族的 §7.78 系列发现是同一个模式)。

未继续测试的部分

时间关系,除了已经验证的注册、战斗、死亡流程外,没有测试拜师 (bai/apprentice)本身、购物、以及触发风清扬叛出这个罕见分支—— bai/apprentice 的两处修复已经通过代码对照(逐字节对比两个档案确 认改动一致)验证,未做额外的实机拜师测试。

补充发现(来自对同引擎兄弟档案 jqxz2008std 的深度测试):第 5 个 bug,§8.9 食物/饮水初始化检查错了对象

adm/daemons/logind.lpc 的 enter_world() 里:

if (!user->query("food") && !user->query("water") && ob->query("age") == 14) {

age 是角色本身(user)的属性,不是登录物件(ob)的属性—— ob->query("age") 永远是 0,这个分支从来没有真正执行过,每个新 角色的食物/饮水从创建起就永远是空的(score 显示空白状态条),静 默、无报错。已改成 user->query("age") == 14,用真实驱动重新注册 验证过(沈叁),score 正确显示食物/饮水两条状态全满。这个 bug 在 标准版(jqxz2008std)先发现,确认加强版/超豪华版/标准版三份档案 里 logind.lpc 这一行逐字节相同,一并同步修复。

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

同一引擎,不同内容构建版本。

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

深度功能测试(2026-08-13,round two,新驱动重测)

Re-tested against the freshly-rebuilt build-debug/src/driver(post 全库 quest_times/win_times %-operator 修复 + Warning/warning 驱动文本回退)。log_error()(adm/obj/master.lpc)已经在更早一 轮(引用注释里的"AGENTS.md #15w")正确修复过,管理员账号 (fluffos/Mud@2026,adm/etc/wizlist 已有 fluffos (admin)) 也已经用真实注册流程创建并提交过,本轮只发现并修复了 log_file() 一处(和同引擎兄弟档案 jqxz2008 同一形状)。

发现并修复的 PROGRAMMING bug

1. log_file()(adm/simul_efun/file.lpc)完全没有 assure_file() 保护(AGENTS.md §7.11-class 的又一确认实例):注册/登录本身只 写 log_file("USAGE", ...)(无子目录,本来就存在),不受影响, 但 nosave/CRASHES/nosave/PURGE/nosave/CALL_PLAYER 等管理指 令路径会在首次使用时未捕获抛出。已补上 assure_file(LOG_DIR + file);(含前向声明)。

Proactive checks(无需改动)

实测过程

用已提交的 fluffos/Mud@2026 登录,score 确认"目前权限: (admin)",update /adm/simul_efun/file(就是本轮改过的文件)确认 可正常重新编译。log/debug.log 时间戳全程未变化(Aug 5,早于本 次会话,且文件本身为空),确认无新增未捕获运行期错误。登录本身产 生的存档时间戳类微小 diff(data/{login,user}/f/fluffos.o 的 last_on 字段)已用 git checkout 撤销,不提交。驱动最终按精确 PID kill,ps -p 确认已退出。

(data/{login,user}/s/shenten.o 是此前会话遗留的未提交测试存档 ——Aug 5 mtime,早于本次会话,未受本轮任何操作影响,未触碰。)

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

#define ROOM "/inherit/room/room":删除 826 处多余的、独立成行的 replace_program(ROOM);(保留 inherit ROOM;)。本库自带的房间 建造工具 clone/misc/roommaker.lpc(与 jqxz2008/jqxz2008std 同一血统的"寒山寺"结构)"造一间空房间"的 heredoc 模板本来就干净, 但"克隆我所在的房间"命令的字符串拼接模板把同一枚多余的 replace_program(ROOM); 烤进了每一个新克隆的房间,已同步修正。已 用 build-debug 驱动干净启动验证(0 个新增编译错误,端口正常监 听);未做完整 §10.7 深度游玩测试。

§7.30 uninitialized-mapping accessor sweep (2026-08-20)

Corpus-wide mechanical sweep of the feature/skill.lpc shared-lineage bug (confirmed independently on xiakexing2017/jqxz2015/haiyang2 via round-four testing): 4 accessor(s) in this file returned a raw never-initialized mapping instance variable (defaults to int 0, not ([]), until first assigned), crashing any unguarded keys()/sizeof()/indexing caller for a fresh/untrained character. Fixed at the accessor level (mapp(x) ? x : ([])) per the documented remedy. Verified via lpcc --batch static compile check only (not a live boot) as part of a large mechanical sweep; not individually functionally re-tested live on this lib.

深度功能测试(§10.7,round four):三个此前未实机测试的分支全部实测

补齐本档案自己 NOTES.md 之前标记的"未继续测试的部分"——拜师 (bai/apprentice)本身、商店购买、风清扬弟子叛出——三项全部用真 实驱动、真实指令实机验证,全程 debug.log 保持空白(无新增 error:/crash)。测试角色:shensi(沈肆,男,登记密码已略去不 记录)。

标准检查清单快速确认(应已修复,仅确认不重新排查):

1. 拜师(bai/apprentice)——已实机验证,多次成功,无崩溃, 师承/头衔正确更新:测试角色先在 /d/huashan/buwei2 对入门弟子路 线的岳不群 bai yue(门槛低:shen≥1000+query_int()≥25),成功 ——score 确认"华山派第十四代弟子",师父岳不群;随后移动到 /d/ huashan/houshan 对风清扬 bai feng(门槛高:剑法/紫霞神功/身法/ 文学等技能≥130~150、shen≥100000、query_int()≥41、随机 kar 检定),管理员用 call shensi->set(...)/set_skill(...) 赋予测试 角色对应属性/技能后(任务允许的"管理员捷径进场景,真实指令走真实 代码"手法),成功——score 确认"华山派第十三代弟子",师父风清 扬。全程无崩溃,family_name/master_id/头衔(第N代弟子)均正确 更新,验证了本档案自己 NOTES.md 里之前只做过代码对照、从未实机触 发过的 bai.lpc/apprentice.lpc 两处修复(§7.11 assure_file() + stringp() 判断、§7.9 类的括号错位修复)在真实驱动下运行正确。

2. 商店购买——已实机验证,价格扣除+实物到手全部正确:d/city/ zahuopu.lpc(杂货铺)用 list/buy 两个指令,NPC 杨永福 (d/city/npc/yang.lpc)用 F_DEALER 混入。管理员 clone /clone/ money/coin + call coin->set_amount(500) + give coin to shensi (任务允许的"clone+give 该档案真实货币物件"标准手法,give 需要 admin 和目标角色在同一房间才能成功,一开始漏了 goto 导致"这里没 有这个活人",补上 goto /d/city/zahuopu 后成功)给测试角色 500 文 铜板;list 确认价目表,buy budai(麻布袋,标价一两白银=100文, 注意商品的 buy 用的是 set_name() 里的别名"budai",不是档案名 "mabudai",用错名字会被 do_buy() 正确拒绝为"你想买什么?"而非崩 溃)购买成功,i 确认物品到手(麻布袋)且找零正确(四两白银, 500-100=400=4两,数学验证一致)。无编译错误/运行时崩溃/debug.log 报错。

(过程中发现一个值得记录、但确认是设计而非 bug 的机制:feature/ dealer.lpc 的 do_buy() 第一行就有 if ((fam = this_player()->query("family")) && fam["family_name"] == "丐帮") return notify_fail("你是个穷叫化,买什麽东西!\n");——丐帮弟子被 硬性禁止在普通商店购物,这正是任务说明里"non-beggar test character"这条要求的真正来源。测试角色因为先做风清扬叛出测试而暂 时加入了丐帮,商店测试前特意再实机 bai yue 一次把门派切回华山 派,才能通过这道设计关卡;notify_fail 走的是正常拒绝路径,没有 任何错误信号,按本 session 的 scope 纪律不作修改。)

3. 风清扬弟子叛出——已验证,真实触发,命中此前只做过代码对照的 apprentice.lpc 修复分支:读 cmds/skill/apprentice.lpc(第 55 行 if ((object)ob->query_temp("pending/recruit") == me),本档案 自己 NOTES.md 记录的括号错位修复处)确认触发条件——目标已经对我方 pending/recruit(即目标已经用 recruit 指令点名收我为徒、只等 我回拜),且我方当前 family/family_name 与目标不同才会触发"背叛 师门"文案;若我方当前 family/master_id == "feng qingyang",还会 额外命中一段读写 /log/nosave/FENG 计数文件的分支(本档案自己 NOTES.md 记录的另一处 §7.11 assure_file() 修复,此前也只做过代 码对照,从未实机跑过)。

实测路径:先用管理员 possess feng+recruit shensi(这一步之所 以能立即完成拜师而不是仅仅"挂起",是因为测试角色此前有一次被风清 扬本人 attempt_apprentice() 正常拒绝的 bai feng 尝试——即使被 拒绝,apprentice.lpc 也已经在拒绝之前无条件地把 pending/apprentice 挂在了测试角色身上,recruit 指令检测到这个 挂起状态会直接完成拜师,不需要再走 attempt_apprentice() 的门槛 检查),确认测试角色 family/master_id 变为 "feng qingyang" (score 显示"华山派第十三代弟子",师父风清扬)。随后管理员移动测 试角色到 /d/gaibang/inhole,possess zuo(左全,丐帮),执行 recruit shensi——这次确认真正挂起(左全对测试角色还没有 pending/apprentice)——输出"你想要收沈肆为弟子",正确进入 recruit.lpc 的"挂起"分支而非"立即完成"分支。退出附身后,测试角色 真实执行 bai zuo:命中目标分支,输出"风清扬现在共有0个徒弟。" (确认 /log/nosave/FENG 被 assure_file() 正确建立且未崩溃,文 件确认内容为"0")、"你决定背叛师门,改投入左全门下!!"、"恭喜您成 为丐帮的第二十代弟子。"——family_name 从"华山派"变为"丐帮", master_id 从风清扬变为左全,score 确认师承信息正确更新。全程 debug.log 保持空白。这是本档案自己 NOTES.md 明确记录"逐字节代码 对照验证、未做实机测试"的两处修复(括号错位分支本身 + 嵌套的 FENG 计数器写入)第一次真正被驱动执行到,确认运行时行为完全符合预期, 没有发现新 bug。

测试方法论备注(供后续同引擎档案参考):recruit 指令的 "挂起 pending/recruit" 分支只有在目标此前没有已经对我方挂起 pending/apprentice 时才会触发;如果顺序反过来(我方已经因为一次 被拒绝的 bai 挂起了 pending/apprentice),管理员 possess 目 标后执行 recruit 会直接完成拜师(走 recruit.lpc 自己的分支), 不会经过 apprentice.lpc 里那处待验证的 pending/recruit 分支 ——本轮测试头几次尝试就踩到了这个顺序问题(用 call feng->recruit_apprentice(shensi) 直接注入也不可行,call 指令的 参数解析器只认字面量/带引号字符串,裸标识符 "shensi" 会被当成字符 串传入触发 call_other() couldn't find object 'shensi' 运行时报 错——这是 call 这个管理指令自身已知的语法限制,不是 mudlib bug),最终靠"先用一次会被拒绝的真实 bai(这一步真实无害地挂起 了 pending/apprentice),再用管理员 recruit 补上"的顺序绕开, 才干净地复现了目标分支。

驱动进程按精确 PID 结束(kill -TERM,确认 cwd 匹配后操作),测试 角色 shensi/管理员 fluffos 的存档增量(师承变化、FENG 计数器 从 0 到 1、fluffos.o 的正常时间戳类增量)按既有约定一并提交,未 触碰此前会话遗留、未提交的 shenten.o。

深度功能测试(§10.7,2026-10-04)— negative range ends

scripts/lpc_fix_negative_ranges.py: 5 line(s) in 2 file(s) count a range from the end with < (x[a..-1] -> x[a..<1], x[-2..] -> x[<2..]; KB 06 §7.209). In this driver a negative constant end gave "" / ({ }) and a negative start the whole value, so each of these returned the wrong slice; the compile warning A negative constant as the second element of arr[x..y] is gone from the files that compile. Range lvalues (s[0..-1] = text, the prepend idiom) are left alone. A paired compile of the changed files at HEAD and in the working tree showed no new error.

深度功能测试(§10.7,2026-10-05)— tail() simul_efun

scripts/lpc_add_tail.py --apply: cmds/wiz/tail.lpc calls tail(file), an efun of the MudOS this archive ran on that FluffOS does not have (Undefined function tail: the command did not compile). adm/simul_efun/file.lpc now defines void tail(string file): the last 10 lines of the file, written to the player. Load check (HEAD against the working tree): 1 of the 1 tail command file(s) failed to load at HEAD, all load now, and the simul_efun file loads. KB 04 §6.2.

深度功能测试(§10.7,2026-10-05)— 房间列出的物件缺档时房间照常加载

房间基类 inherit/room/room.lpc: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-05)— 巫师留言板存档 data/board/*.o.gz

巫师留言板 wiz_b / towiz_b 以 .o.gz 存档(1996 年的帖子)。本机驱动 restore_object() 优先读 .o.gz,而留言板用 save_object(file) 写明文 .o,所以本机上新帖每次重启都退回旧快照;网页版驱动没有 zlib,只读 .o,而归档自带的 .o 是读不出的二进制。.gz 内容为 GB18030(转码时没被处理),转成 UTF-8 写成 .o,替换归档里那个读不出的二进制 .o;towiz_b 原文有 4 个残字节,转为替换符。删除 .o.gz(KB 01)。用 lpcc 载入留言板核对条数(jqxz2008:wiz_b 47 条、towiz_b 115 条)。

深度功能测试(§10.7,2026-10-07)— 空的 if (current_water == 0) {}

3 个房间的 valid_leave() 里有一行什么也不做的 if (current_water == 0) {}(编译警告 Expression has no side effects),删去,行为不变:d/xingxiu/nanjiang2.lpc、d/xingxiu/nanjiang3.lpc、d/xingxiu/shanjiao.lpc。

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

scripts/lpc_warnings.py jqxz2008dlx --fix 加 scripts/lpc_fix_no_effect.py --apply,共改动 257 个 .lpc 和 10 个 .h(多为删去未用的局部变量)。HEAD 与工作树分别加载(新进程):245 -> 245 通过,无回退;改过的头文件的 60 个包含者 60 -> 60 通过。启动时警告 17 -> 0;新进程登录(输入名字)正常。

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

scripts/toolkit_fix.sh 一轮去掉 18 处多余继承;include/net/ftpdconf.h 把 VALID_READ、VALID_WRITE 定为 1,覆盖 ftpd.h 的 0,先 #undef(同 xiakexing2017),行为不变。能编译的文件警告清零;改动的 18 个对象在 HEAD 与工作树各载入一次:HEAD PASS 17,tree PASS 17,regress 0。

无门派玩家的 family 映射(2026-10-15,KB 05 §7.30 第三种)

mapping fam = ob->query("family"); 之后直接 fam["family_name"]:没有门派(新人或叛师后)的玩家在学习、练功、拜师、进入门派房间时报 Value being indexed is zero,而不是作者写好的提示。5 处在声明行加上 if (!mapp(fam)) fam = ([ ]);(scripts/lpc_fix_family_guard.py)。

其他体系的属性名(2026-10-15,KB 06 §7.241 第三类,--any-file)

另有 3 个文件(绝招、状态、物品、NPC 等,不限于 kungfu/skill)来自 gin/kee/sen/force 体系,同样按 kee→qi、gin/sen→jing、force→neili 改名(scripts/lpc_port_es_props.py --any-file)。

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

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

技能名拼错(2026-10-15,KB 06 §7.249)

query_skill() 里的技能名拼错了,或用的是本库改名前的旧名;本库没有这个技能,调用永远得 0:门槛(< N 就拒绝)永远过不去,相关功夫或绝招学不了、用不了;内功互斥(> N 就拒绝)从不生效;公式里这一项一直是 0。经汉字名(提示文字或中文名词典)或纯拼写差异(_/-、少一个连字符、相邻字母颠倒)核对后,改为本库的技能名(scripts/lpc_fix_skill_typo.py):beimin-shengong→beiming-shengong(hamagong、honghua-shengong、huagong-dafa、huntian-qigong、hunyuan-yiqi、kuihua-xinfa 等 16 个文件);mizongxinfa→mizong-xinfa(longxiang/fanchang);qiankundanuoyi→qiankun-danuoyi(/cmds/std/nuoyi)。

family 映射内联取下标(2026-10-15,KB 05 §7.30)

ob->query("family")["master_name"]、me->query("family")["family_name"](泥潭式为 query("family", ob)[...])直接对门派映射取下标:没有门派的人(新玩家、叛师者、大多数 NPC)在 NPC 的打招呼和问话、绝招的门派判断、房间的 valid_leave 里报 Value being indexed is zero,而不是得到拒绝。7 处(6 个文件)改为 dbase 路径查询 query("family/master_name"):有门派时值相同,没有时得 0;原有的判断照常生效(scripts/lpc_fix_family_index.py)。给映射赋值的写法未动。

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

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

留言板存档损坏时 setup() 不再抛错(2026-10-18)

data/board/*.o 里有几个是外来的二进制数据(以 ?inh 开头,restore_object() 报 Illegal file format - 1)。inherit/misc/bboard.lpc 的 setup() 里 restore() 直接抛,留言板对象(连带创建它的客店房间,比如 d/city/kedian)载入失败。改成 catch(restore());,留言板以空板启动(xkx2017 的同一个文件早就是这样写的)。上面「存档损坏」那一条里说的“setup() 已经包住了”并不准确。

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 载入不了,刷出它的房间也少一个人。本库有 9 个对象设了本库没有文件的武功(2 个名字,最多的是 xuanyuan-arrow、liangyi-jian)。三处都改成 return:这一门武功不给、不映射,对象照常载入,只是少了它(缺的武功本身仍是内容缺口)。抽样载入这些对象:9 个里 9 个通过。(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 映射不到,门派弟子用普通轻功/拳脚)。按核对过的对照表改正,共 5 处、4 个文件:xinxiu-duzhang→xingxiu-duzhang(2 处)、tiaji-jian→taiji-jian(2 处)、jinyin-baiguzhao→jiuyin-baiguzhao(1 处)。(scripts/lpc_fix_skill_names.py)

全局头文件丢了 1 个宏(2026-10-19,KB 04 §6.16)

/include/globals.h 里没有定义 MAILDIR,用到它们的物件(名单里 1 个)编译时报 Undefined variable/Undefined function,整个物件载入不了(编译器在第一个未定义的名字上停下,后面的错误和警告都看不到)。同系的库在各自的头文件里都有这几行:照其中和本库共有文件最多的那个库,原样补到 /include/globals.h 最后一个 #define 之后,宏体里出现的路径在本库里都存在。名单里的物件除了这几个宏之外还有别的错误,暂时仍载入不了。(scripts/lpc_restore_defines.py)

标准整理轮(2026-10-19,scripts/toolkit_fix.sh)

本库在新驱动下重扫,机械修复:9 处浮点数赋给 int 的地方改成 to_int()。修后与 HEAD 逐个物件对比载入,没有退步。另有 7 处浮点数赋值要手工改(lpc_fix_float_hooks.py 列出)。

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 文件。

技能的 power_point() 返回类型(2026-10-19,KB 04 §6.10)

kungfu/skill/ 下 6 个技能的 int power_point(object me) { return 1.5; } 返回的是浮点数,新驱动按 int 声明截成 1。声明改成 float,值回到设计的 1.1、1.5…。这个库里读 power_point() 的只有遗留的 combatd.b(二进制,不加载),combatd.lpc 不调用,所以对运行没有别的影响。

玩家打造兵器模板没有打造者时(2026-10-19,KB 06 §7.275)

/d/npc/m_weapon/weapon/m_blade.lpc、/d/npc/m_weapon/weapon/m_club.lpc、/d/npc/m_weapon/weapon/m_staff.lpc、/d/npc/m_weapon/weapon/m_sword.lpc、/d/npc/m_weapon/weapon/m_whip.lpc(共 5 个)的 create() 开头 me = this_player(); 之后无条件读 me->query("weapon/name") 等打造数据。房间刷新时没有人在场(me 为 0),或者 NPC 在别的 NPC 的命令环境里 carry_object() 这个模板(NPC 的 weapon 属性是文件名字符串),旧驱动里读出来是 0 或字符串,switch 照样落到 default;新驱动报 Bad argument 1 to EFUN call_other() / Bad argument 1 to switch,NPC 和它所在的房间载入不了(--walk 普查里一个玩家走进房间就触发)。在 //读入数据 之后加 if (!me || !mapp(me->query("weapon"))) { setup(); return; }:没有打造者就留一个没有名字的空模板,玩家打造的流程不变。

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 处)。

行编辑器指令编译失败:(: this_object(), ({ "do_to", me, arg }) :)(2026-10-20,KB 06 §7.284)

Illegal to use local variable in functional.:call_other 形式的函数指针 (: ob, ({ "函数", 参数 }) :) 的数组里只能是常量,写了局部变量 me / arg 整个指令就编译不过,to 这类先开编辑器、再回调自己的指令因此从未能用。改成 (: call_other, this_object(), "do_to", me, arg :)(参数在建立指针时绑定,编辑器再把输入的文字接在最后,do_to(me, arg, text) 收到全文;scripts/lpc_fix_functional_locals.py)。改动:/cmds/usr/to.lpc(1 处)、/cmds/wiz/to.lpc(1 处)。

call_out_info() 的每一项只有 3 个元素(2026-10-20,KB 06 §7.287)

驱动返回的是 ({ 物件, 函数, 延迟 }),不带 call_out 的参数,旧代码读第 4 项 info[i][3](callouts 指令、calloutd、cod 工具)一读就报 Array index out of bounds,指令从第一行起什么也打印不出来。改为 (sizeof(info[i]) > 3 ? info[i][3] : 0)(scripts/lpc_fix_callout_info.py)。改动:/cmds/arch/callouts.lpc(1 处)。

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

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

sefun cat():缺文件时 write(0) 报错(2026-10-20,KB 06 §7.297)

void cat(string file) { write(read_file(file)); }:文件不存在(压缩包没带的欢迎/公告文件,或只有运行中的 mud 才会写的日志)时 read_file() 回 0,write(0) 在本驱动里报 Bad argument 1 to receive(),调用者(登录对话、cat 指令)被中断;老驱动什么也不打印。改成 write(read_file(file) || "");(scripts/lpc_fix_cat_unchecked.py)。改动:/adm/simul_efun/file.lpc。

翻页器 start_more(read_file(...)):文件缺失时 explode(0)(2026-10-20,KB 06 §7.300)

东方故事系的翻页器 void start_more(string msg) { ... explode(msg, "\n") ... } 被这样调用:start_more(read_file(HELP_DIR + "help/topics"))、start_more(read_file(NEWS))。压缩包没带的文件使 read_file() 回 0,explode(0, ...) 在本驱动里报 Bad argument 1 to explode()(不带参数的 help 指令就是这样出错的),老驱动把 0 当空文本。在 start_more 开头加了 if (!stringp(msg)) return;(scripts/lpc_fix_start_more.py)。改动:/feature/more.lpc。

存档里的乱码文件:restore_object() 报 Illegal file format(2026-10-20,KB 06 §7.316)

存档里有一批数据文件是乱码:开头是 ?adm、?inh、?clo、?obj(#/adm/… 的第一个字节被换成了 ?),后面是随机字节,没有任何驱动读得了。adm/daemons/chinesed 在预载时 restore() 读 data/e2c_dict.o,首次登录时起始房间的留言板 /clone/board/kedian_b 读 data/board/*_b.o;restore_object() 对不是文本的文件抛 Illegal file format,调用处的 catch()(KB 06 §7.255)保住了房间和精灵,但本库 master 的 error_handler() 把调用栈返回给驱动,每次启动和首次登录都在控制台打印一次或两次 错误讯息被拦截。现在共用的 feature/save.lpc 的 restore() 先读文件第一个字节,不是 # 就返回 0(读被 master 拒绝时 read_bytes() 返回 0,仍由 restore_object() 决定,和以前一样);留言板和字典从空开始,第一次 save() 写出合法文件,乱码文件原样留在树里。实测:启动和登录都没有报错,已保存的角色重新连线照常加载。

NPC 的 chat() 在 chat_msg 为空数组时下标越界(2026-10-21,KB 06 §7.334)

NPC 基类的 chat() 是 if (arrayp(msg = query(...))) { if (random(100) < chance) { rnd = random(sizeof(msg)); if (stringp(msg[rnd])) ...,不检查列表是否为空。本库现有的 NPC 文件里没有字面写成空 chat_msg 的(扫描只认 set("chat_msg", ({ })));守卫挡的是运行时才为空的列表和以后新增的 NPC。在 random(100) < chance 前面加 sizeof(msg) &&(scripts/lpc_fix_chat_empty.py;if (random(100) > chance) return 0; 的写法是 !sizeof(msg) ||)。改动:/inherit/char/npc.lpc(共 1 个文件)。

存档里的 .c 文件名改成 .lpc(2026-10-21,KB 03 §4.2 第 9 项)

存档里写着 "/d/city/npc/wei.c" 这样的文件名;extract 时源文件已经全部改成 .lpc,而驱动对带扩展名的路径只认字面,new() / load_object() / move() 都找不到它,调用方多半把失败当成「没有这个东西」悄悄跳过。本库 3 个存档共 6 处按 scripts/lpc_fix_save_dotc.py 改成 .lpc(只改 .lpc 存在而 .c 不存在的字符串;玩家存档、备份、留言板、巫师目录和文件索引缓存不动)。改动:/d/shaolin/npc/obj/kat.o(1 处)、/d/shaolin/obj/kat.o(1 处)、/d/shenlong/obj/lxlx.o(4 处)(共 3 个存档)。

巫师命令不带参数时对 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)。改动(1 个文件,括号里是接住 0 的 efun):/cmds/wiz/test.lpc(present)。加载检查 HEAD 与工作树对照,没有退步。

blockade / recover:data/keep 不存在,解封之后世界仍然锁着(2026-10-21,KB 06 §7.340)

管理员扫描里 blockade 报 Error copying file from /data/user/f/fluffos.o to /data/keep/fluffos, Error: No such file or directory,随后的 recover 在第一个 cp() 上死于 */data/keep/fluffos: lstat failed,来不及执行最后的 LOGIN_D->set_madlock(0):封锁解不开。data/keep/ 是运行时目录,git 克隆里没有空目录。blockade 在第一次写之前 if (file_size("/data/keep") != -2) mkdir("/data/keep");(mkdir() 失败答 0,不抛错),recover 对没有保存档的玩家 if (file_size(src) < 0) continue;,其余照常恢复、照常解锁(scripts/lpc_fix_keep_dir.py,hy5 上实测:没有保存档时 recover 答“时空解封完毕”,blockade 建出 data/keep 并保存,recover 取回并删除)。改动(2 个文件):/cmds/adm/recover.lpc、/cmds/arch/blockade.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.,同一个动词的其他处理函数不再尝试(不是最新的一条就悄悄跳过)。删除了 2 条注册(2 个文件,scripts/lpc_fix_dead_add_action.py),动词留给别的处理函数:/inherit/misc/fboard.lpc(do_list)、/kungfu/class/gumu/yangguo.lpc(do_qiecuo)。最多的函数名:do_list 1 处、do_qiecuo 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.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。 还剩 1 个函数没有补(inquiry 1):原型还在函数体丢了、或者根本没写过,没有可以直接补回的捐赠(别的库同一路径的文件里没有这个函数,或者它还要用本库没有的辅助函数、签名不同),不编造:/d/huashan/npc/teller.lpc:tell_fortune。

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

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

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

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

本库 18 处(13 个文件):拼名字的赋值 10 处、与汉字常量比较 8 处。例:name[0..1] → name[0..0](/kungfu/class/emei/kong.lpc:134);name[2..3] → name[1..1](/kungfu/class/shaolin/cheng.h:155);name[0..1] == "慧" → name[0..0] == "慧"(/kungfu/class/shaolin/cheng.h:139)。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,不要重跑。

黑木崖脚下的老者:init() 里留着调试语句,每个走进 /d/heimuya/road1 的人都触发运行时错误(2026-10-22,KB 06 §7.361)

d/heimuya/npc/laozhe.lpc 的 init() 在 ::init() 之后有 what = new(__DIR__ "obj/yancao"); sprintf("%s aaa\n", what);:调试遗留,%s 收字符串或数字、不收对象,于是 (s)printf(): Incorrect argument to type %s. (arg: 0) 每次有人进入乱石坡都抛一次,后面的 call_out("greeting", ...) 永远不执行,老者不再搭话(还每次白克隆一个烟草)。两行都注释掉(同系的 haiyang2 / hy / hy5 / cctx / fqyy2 早就注释了)。证明:scripts/lpc_reach_census.py xiakexing2017 --load --walk(一个普通 NPC 访客走进每个加载成功的房间):HEAD 336/337,改后 337/337。

按字节写的汉字循环、茶馆猜诗和同盟频道标题(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 区间 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(一格两个空格)。本库 4 处(2 个文件)。证明(lpcc_eval.py hhsj):tribar_graph(6,9,12) 在 HEAD 画出整条 12 个■,改后为 6 个■+3 个□;麻将 strlen(tempB)/2 是两字符牌码,未改。

doc/build devil 丢分号/粘连 inherit(2026-10-27,KB 04 §6.25 Also)

doc/build/devil.lpc(建档示例倭寇)被格式化弄坏:inherit NPC void create() 粘在一起,语句之间的 ; 全丢,还有嵌套坏掉的 set("con", set("con", 10)。按原意重写成带 setup() 的完好 NPC(原 /obj/blade、/obj/cloth 在多数库不存在,示例里去掉携带以免 create 炸)。证明:HEAD 加载失败;改后加载成功。