info.html · 介绍 · play.html · 游玩 · llms.txt · 下载与本地运行 · ZIP · GitHub
2015 年整理发布的版本,属于 ES II 引擎系列——master、security、 login 等底层代码与本项目中的"金庸群侠传2008加强版"几乎逐字节相同(匹配度甚至比 2008 版自己与"侠客行3"的引擎匹配度还高),但游戏内容是独立打磨了七年的真实内容分叉:净增 187 个文件、减少 67 个,新增红花会等区域,丐帮相关场景也大幅扩充。少林、武当、峨嵋、明教、丐帮等门派悉数登场,玩家从一间普通客栈起步练武、闯荡江湖。街头就能遇到乔峰这样武功盖世的成名人物,稍有不慎就会命丧刀下,经历停尸、鬼门关问话、转世重生的完整流程;追随风清扬习武途中也可能触发叛出师门的剧情分支。
English
The 2015 release of this project's 金庸群侠传/"Jin Yong Heroes Gathering" (ES II engine) family -- confirmed via md5sum an even closer engine match to sibling jqxz2008 than jqxz2008's own match to xiakexing3 (master, security, login, and Chinese-text daemon files are byte-identical or differ by a single blank line), but a genuine seven-years-later content fork: net +187/-67 files, including a new zone (honghua) and an expanded Beggars'-Sect obj set (city2's imperial-palace district itself is not actually new here -- file-count-verified present in all four 2008/2015 editions alike) and drift in both directions (a file corrupted in jqxz2008 is complete here; a different file is truncated here but fine in the 2008 builds).
README
内容亮点
- 对练功、内功、装备均有细致的数值设计,江湖气息浓厚。
在线试玩
https://mudlibs.fluffos.info/jqxz2015/
管理员账号 / Admin account
- id:
fluffos - 密码 / password:
Mud@2026 - 中文名 / display name: 浮浮
- 权限 / level:
(admin)— 本 lineage 的最高权限等级,可使用全部 巫师指令。 - 授权方式:在
work/adm/etc/wizlist中加入fluffos (admin)一行。
警告:正式对外开放前请务必修改此密码(这是本地游玩用的公开默认
密码)。
本地运行
cd libs/jqxz2015
~/src/fluffos/build-debug/src/driver config.fluffos游戏端口:40086。
NOTES · 移植与修复记录
jqxz2015 — 金庸群侠传 (Jin Yong Heroes Gathering, 2015 edition)
Archive: archives/金庸群侠传2015版.rar ("Jin Yong Heroes Gathering, 2015
edition"). Extracted mudlib root: raw/jy/ (a single top-level jy/
directory inside the archive, identical layout convention to archive #91).
Port: 40086. Status: done (boots clean, full registration flow
verified twice with real Chinese names, post-login look/score/quit
verified working both times).
Lineage confirmation (evidence, not assumption)
config.cfg's name field (GBK-decoded) is literally 金庸群侠传, and
Readme.txt carries the same "ES2 lib (Tian Cao Di Guo)... Wrote By
Phoebus.suny 1998" credit already seen on archive #91
(jqxz2008). Same jy/ top-level directory name, same
adm/obj/+adm/single/ dual master-file layout.
Confirmed via md5sum, not assumed, against #91's raw archive — this
is an even closer match than #91 vs xiakexing3(#44) was:
| file | match vs #91 raw |
|---|---|
| adm/obj/master.c | byte-identical |
| adm/single/master.c | byte-identical |
| adm/daemons/securityd.c | byte-identical |
| adm/daemons/chinesed.c | byte-identical |
| adm/obj/simul_efun.c | byte-identical |
| adm/simul_efun/chinese.c | byte-identical |
| include/globals.h | byte-identical |
| feature/command.c | byte-identical (incl. the private bug) |
| home/command.c | byte-identical |
| feature/name.c | byte-identical (incl. capitalize()-on-0 bug) |
| adm/daemons/commandd.c | byte-identical |
| d/city/npc/guidao.c | byte-identical (incl. is_killing() typo) |
| d/baituo/ouyangfeng.c | byte-identical (incl. both typos) |
| d/shaolin/obj/shuitan.c | byte-identical (incl. ging_cost typo) |
| adm/daemons/logind.c | differs by exactly one blank line (whitespace only, confirmed via diff of decoded content) |
So this 2015 release is the SAME underlying "ES II / 金庸群侠传" engine
core as #91's 2008 "加强版" (enhanced edition), 7 years later, with the
engine/daemon layer essentially frozen and only game content evolved:
3,893 raw files here vs 3,773 in #91 (net +187 new / -67 removed, mostly
new zones — city2, honghua, huanggon, gaibang obj expansions,
etc. — plus some cleanup of old scratch/orphan files). A few individual
content files (mostly under d/mingjiao/) were independently edited
between the two releases (see below) — direction is NOT "2015 always
newer/better", it's a genuine content fork with drift in both directions
(e.g. d/mingjiao/jmqshenmu.c, truncated in #91, is COMPLETE here; but
d/city2/npc/zhengmen.c is genuinely truncated here, matching, in shape,
#91's jmqshenmu.c finding).
Cross-check note for #92/#93 (concurrent, not yet landed): per the
task brief these could not be diffed against since they were being
processed concurrently in sibling sessions — a later pass should
md5sum-cross-check this lib's core files against whatever #92
(金庸群侠传2008版.rar) and #93 (金庸群侠传2008超豪华版.rar) turn out
to be, the same way this pass cross-checked against #91.
Fixes applied (ported directly from #91 where the source was
byte-identical; confirmed present via direct read before applying, not assumed)
1. AGENTS.md §15h (is_chinese/check_legal_name GBK byte-range
checks): adm/simul_efun/chinese.lpc's is_chinese() — GBK lead-byte
range (str[0] > 160 && str[0] < 255, strlen>=2) → CJK codepoint
range (str[0] >= 0x4e00 && str[0] <= 0x9fff, strlen>=1).
adm/daemons/logind.lpc's check_legal_name() — byte bound <2||>12
→ character bound <1||>6 (message already promised "1 到 6 个中文
字"); dropped the i%2==0 even-byte-offset gate. Byte-identical
source to #91's pre-fix files, so the fix is verbatim.
2. AGENTS.md §15ae (private nomask command-hook breaks every
post-login command): feature/command.lpc's command_hook(string
arg) was private nomask; home/command.lpc's copy was already
correct (no private) — exact same split as #91. Dropped private.
Verified working (see registration transcripts below — look/
score both function correctly post-login in both test runs).
3. AGENTS.md §15ar — checked, confirmed NOT independently needed:
adm/daemons/commandd.lpc's rehash() uses sscanf(cmds[i], "%s.c",
cmds[i]) (no $ anchor) to strip the .c extension. Because this is
a *plain quoted* "%s.c" literal (not the concatenated cmds[i]+"$",
"%s.c$" shape from the archives where §15ar was first cataloged),
convert_lib.sh's standard \.c"-reference fixer (§2) already caught
and rewrote it to "%s.lpc" automatically during the mechanical
conversion pass — confirmed by grepping the post-convert_lib.sh
work/ copy before making any manual edit. This clarifies why #91's
own NOTES.md never called out a separate §15ar fix: same shape, same
automatic resolution, on the identical source file.
4. feature/name.lpc's capitalize()-on-0 robustness bug (same
as #91 finding #5): short(int raw)'s fallback assumed query("id")
is always a string; guarded with stringp(id) so non-character items
(bulletin boards) don't crash look in their room. Byte-identical
source to #91.
5. d/city/npc/guidao.lpc's is_killing(who) direct-call type
mismatch (same as #91 finding #6): fixed to
is_killing(who->query("id")). Byte-identical source to #91.
6. d/baituo/ouyangfeng.lpc, two typos (same as #91 finding #13):
missing semicolon after a write(...) in a switch case 0: block;
object me=this-player(); → this_player(). Byte-identical source
to #91.
7. d/shaolin/obj/shuitan.lpc: ging_cost typo for jing_cost
(same as #91 finding #14). Byte-identical source to #91.
8. AGENTS.md §15ac (bare SAVE_EXTENSION): 6 files this pass —
include/net/ftpdsupp.h, d/quanzhou/npc/{tang,tang3}.lpc,
d/taishan/tang3.lpc, cmds/arch/purge.lpc,
adm/daemons/network/netmail.lpc — replaced with
__SAVE_EXTENSION__. Left alone: clone/npc/meng-zhu.lpc (#define
SAVE_EXTENSION ".o" locally, self-contained — verified, same as #91).
9. The "tang"-family new-as-bare-variable-name typo (same 7 files
as #91, same lines: d/quanzhou/npc/{tang,tang1,tang2,tang3}.lpc,
d/taishan/{tang2,tang3,xingtang}.lpc): object *inv, new; +
new = new("/clone/npc/...") + new->move(...). Renamed the local
variable to newob throughout (declaration + both usages) in all 7
files; the new(...) efun calls themselves untouched.
10. kungfu/class/mingjiao/mingjiao.h's string-literal-adjacent-to-
macro-expansion syntax error (same shape as #91 finding #10, but
the surrounding logic differs — this 2015 copy independently added an
else branch with reversed rank-comparison logic and its own second,
correctly-+-joined string, plus already carries #include <ansi.h>
unlike #91's original): ob->query("party")["party_name"] == HIG
"明教" NOR → HIG + "明教" + NOR (explicit +).
11. adm/daemons/combatd.lpc's #include </quest/quest.h> —
AGENTS.md §15t variant 1 (absolute path inside angle brackets, never
resolved by this driver's inc_open()) — this file's content
diverges substantially from #91's (2015's combatd.lpc has different
damage-formula code entirely, but kept the same broken quest.h
include and the same variant-3 ordering bug independently). Fixed to
#include "/quest/quest.h" (quoted absolute form) AND moved
inherit F_DBASE; above all #include lines (AGENTS.md §15t variant
3 — quest.h's file-scope mapping quest_name = ([...]) global would
otherwise land textually before the inherit, a fatal "Illegal to
inherit after defining global variables" here). Confirmed via a live
score test that score now works correctly (this is the same code
path #91 needed this exact pair of fixes for, but arrived at via a
fresh discovery here since combatd.lpc's content differs — the
quest.h include itself, previously assumed only relevant to #91,
turned out to be genuinely present and broken here too).
12. quest/quest.h's own string-literal-adjacent-to-macro syntax
errors (NEW finding this pass, not present in #91's combatd.lpc
since #91's copy never actually included quest.h at all — its
version of combatd.lpc had no quest.h reference to trip over this):
once fix #11 above made quest.h actually get included and parsed,
two more of the exact same "adjacent string literal + macro, no +"
bug (AGENTS.md §9/§10 family) surfaced inside it —
"你可以领取"HIG + values(quest_name)[i] + NOR"任务了!\n"NOR and
"你得先完成"HIY + quest_name[lock_quest] + NOR"任务才能继续这个任务。\n"
— both rewritten with explicit + throughout. quest.h is only
ever #included by combatd.lpc, which already has #include
<ansi.h> earlier in the same file, so HIG/HIY/NOR resolve
fine once the syntax itself compiles.
13. d/baituo/{obj,npc/obj}/bowl.lpc's set_name() wrong argument
type (NEW finding, genuinely pre-existing, not present in #91 —
#91's archive doesn't ship this file at all): set_name("海口大碗",
"bowl") passed a bare string where set_name(string name, string
*id) (per feature/name.lpc) requires an array — every other
set_name() call site in the whole lib correctly uses ({ "id" }).
Fixed both copies (d/baituo/obj/bowl.lpc and
d/baituo/npc/obj/bowl.lpc, identical content) to
set_name("海口大碗", ({ "bowl" }));.
14. d/city2/npc/zhengmen.lpc genuinely truncated in the raw archive
itself (NEW finding, same class as #91's jmqshenmu.c — confirmed
by diffing work/ against the pre-conversion raw .c, both exactly
77 lines, ending mid-valid_leave() with 2 unclosed braces, not
something our pipeline introduced): closed the truncated function
with the 2 missing closing braces (no fabricated logic added), purely
so the file is syntactically valid — the room's real, complete
create()/look_gaoshi() content above is untouched.
Confirmed NOT needed (checked by reading the actual source, not
assumed from #91's precedent alone — master.lpc/securityd.lpc are
byte-identical to #91's so these transfer directly, but each was
re-verified against this archive's actual work/ content)
- §4 (master's lazy security-daemon load recursing):
master.lpc'sconnect()/compile_object()/log_error()never do a lazyload_object(SECURITY_D)— confirmed by direct read of the whole file (byte-identical to #91, which already confirmed this clean). - §7 (
get_root_uid()/get_bb_uid()): both present inmaster.lpc(lines 177/182, matching #91 exactly). - §8c (
valid_read/valid_writeoverriding withthis_player()):securityd.lpchas onlyvalid_write, novalid_readat all, nothis_player()override logic — confirmed present (byte-identical to #91). - §15n/§15o (custom securityd ACL blocking driver compiles / missing
get_include_path()):securityd.lpcimplementsvalid_writeonly;master.lpc's file has no customvalid_readACL to gate compiles. - §15p (DNS/intermud daemon in preload):
adm/etc/preload(11 entries, read directly) never lists any network/dns daemon — nothing to exclude, same as #91. - §15l (
master.lpcdestructingSIMUL_EFUN_OBincreate()):master.lpc'screate()body (read directly) has nodestruct()call at all. - §15ag (
ed_start/ed_cmd/query_ed_mode): zero occurrences anywhere inwork/(grepped). - §15v (
LONELY_IMPROVED-style always-on efun-substitution flag): zero occurrences (grepped) — this is an ES II lineage lib, not the unrelated "nitan" lineage this pattern is specific to. - §8f (bare
array/TYPE * a, b;comma-list array-modifier bug): zero barearray name;declarations found (grepped); this is a Chinese ES II lineage lib, not the English Dead-Souls lineage this bug is specific to. - §15z (
#define nosave static/#define protected staticshim): none found in any.hfile (grepped). - Duplicate
inherit F_UNIQUE;(present in #91'sd/mingjiao/npc/{yinwushou,yinwulu,yinwufu}.lpc): already fixed in this 2015 archive independently — confirmed via diff, only ONEinherit F_UNIQUE;line in each of the 3 files here (2008's had two). Not a bug here, no action needed. kungfu/class/mingjiao/tanzhu.hwrong-path#include(#91 finding #11/#12): zero references totanzhu.hanywhere in this archive (grepped) — the NPC files that used it in #91 (fenggongying/baiguishou/changjinpeng) were independently rewritten in this 2015 release to either usemingjiao.hinstead (changjinpeng.lpc) or have their own inlineinit()with no header include at all (fenggongying/baiguishou) — confirmed via direct diff against #91.- Fixed-width
[0..<3]filename-extension-width slice bug (§2's variant): present (18kungfu/skill/*/*.lpcfiles, samepfname = explode(__FILE__,"/")[<1][0..<3]pattern as #91) but confirmed dead code —pfnameis assigned once and never read again anywhere in any of the 18 files (grepped each), same as #91's finding. Not fixed. d/huashan/map.lpc— a plain ASCII-art room-layout text file mistakenly caught by the blanket.c→.lpcrename (AGENTS.md §12), confirmed viagrep -rlreturning zero references anywhere else in the tree. Same precedent as #91/other libs' orphaned-map findings — left as a permanently-"failing" but harmless dead file, not renamed (matches established convention of not touching confirmed-dead content unless it actively breaks something live).doc/build/devil.lpc(missing semicolon afterinherit NPC) anddoc/efuns/shiwu.lpc(baredo_closeidentifier instead of a quoted string incall_out) — both are illustrative example/template files under thedoc/documentation tree, confirmed unreferenced anywhere in the real object tree (grepped). Left as-is, same "documentation, not live code" category as other libs'doc/-tree lpcc-sweep noise.cmds/usr/to.lpc/cmds/wiz/to.lpc("Illegal to use local variable in functional" —me/argreferenced inside an old-style(: ... :)functional closure): byte-identical to #91's copies, which hit the exact same failure and was not individually fixed there either (present in #91's ownlpcc_fail.log, part of its undifferentiated remaining-failures tail) — left unfixed here too for consistency; a rarely-used admin multi-line-input utility, not on the registration/gameplay-critical path.
Content gaps confirmed as real archive gaps, not bugs (AGENTS.md §13)
— same categories as #91, independently re-verified for this archive (not assumed transferred)
d/mingjiao/yuan/*(9 "yuan" NPCs, e.g. 郑七灭/郑十灭 family) reference two genuinely-missing kungfu skill files (xuanyuan-arrow,liangyi-jian) — confirmed absent anywhere underkungfu/skill/(same gap as #91).d/wudang/taoyuan/{tyroad4,5,6,7}.lpcare orphaned early drafts of the complete, workingd/wudang/tyroad{4,5,6,7}.lpcfiles one directory up — confirmed nothing in the tree references thetaoyuan/copies (grepped), same finding as #91.d/npc/m_weapon/weapon/{m_club,m_blade,m_whip,m_sword,m_staff, m_cloth}.lpc:create()callsthis_player()unconditionally, always null in an isolatedlpcccompile — the standard §6b "compiled divorced from runtime context" false positive, same shape as #91 (one extra file,m_cloth, vs #91's 5 — this 2015 release added a 6th weapon-template variant).adm/daemons/network/*(10 files: dns_master-family services, mudlist, mail_serv, netmail, telnetd, inetd, pingd, ...): confirmed not inadm/etc/preloadand not referenced from outside this subdirectory (grepped) — dead/inert intermud subsystem, never compiled during a real boot or registration/gameplay path.home/simul_efun.lpc: a stray sandbox copy of the real simul_efun, same §6bmain_file_name()sweep artifact as #91 — never loaded as the actual simul_efun (configured path is/adm/obj/simul_efun).clone/board/*corrupted save data (11 board.ofiles underdata/board/failrestore_object()with "Illegal file format") — same pre-existing corrupted-seed-data class as #91's board/chinesed findings; each board'ssetup()wraps the failure incatch()(visible indebug.logas "错误讯息被拦截"), fully non-fatal — directly confirmed live during both registration tests AND a subsequent WASM long-sit boot-watch (2026-07-24):/clone/board/ kedian_b, the starting-room board, IS one of the 11 corrupted files — its ownrestore()throws "Illegal file format" every time a fresh character'senter_world()creates it, caught harmlessly bylogind.lpc'sCATCH(), and it then displays correctly underlookas an empty board (no persisted notes). (An earlier pass of this note wrongly suggestedkedian_brestores cleanly and a separate board was the one throwing — direct inspection ofdata/board/kedian_b.o's raw bytes confirms it's random binary garbage like the other 10.)adm/daemons/chinesed.lpc'sdata/e2c_dict.o(English→Chinese translation dictionary save file) fails torestore()— same pre-existing corrupted-seed-data issue as #91, caught bymaster.lpc'spreload()catch wrapper, fully non-fatal (translation lookups just return input unchanged).u/liujun/quest/{leftkiller,rightkiller}.lpcreference a missing skill (six-chaos-sword);u/editer/tie-luohan.lpcis a broken wizard scratch-directory draft with garbled variable names (e.g.skill_statussname,snamei) from a botched find-replace — both under personal wizard directories, not core content, same finding as #91 (identical filenames too).d/taohua/taohua_b.lpc(a bulletin board) references a room/tmp/jungu/datingthat doesn't exist anywhere in this archive (only an unrelated NPC filed/npc/jungu.lpcexists, no/tmp/jungu/zone) — genuine content gap, board just never resolves its "home room", harmless since boards aren't preloaded.
Interactive test result — full registration + post-login flow
(verified TWICE, across a driver restart, with the complete final fix set applied both times)
Run 1 (before the bowl.lpc/zhengmen.lpc fixes, driver PID
1099537): id qinfengwu → y (confirm new character) → real Chinese
name 秦风 (accepted first try) → password test1234 (x2) → accept
gift stats (y) → email → gender m → enters 客店 (the tea-house
starting room). look re-renders the room correctly; score shows a
full real character sheet (title/age/gender/birthdate, 膂力/悟性/根骨/
身法 stats, 精/气 bars, 食物/饮水 bars, kill count, 潜能/实战经验) — this
is exactly the code path fix #11 (combatd.lpc's quest.h include) makes
work; quit saves and disconnects cleanly with the expected "你丢下一件
布衣" message.
Run 2 (after ALL fixes above, fresh driver restart, PID 1133574): id
qinfengliu → y → real Chinese name 秦岭 → password test5678
(x2) → y → email → gender f → enters 客店, with the correct
gender-specific NPC greeting ("这位小姑娘" instead of run 1's "这位小
兄弟"). look/score/quit all work identically to run 1, score
showing correct female-specific stat roll. Zero error: lines and zero
Segmentation/fatal lines in debug.log across the full run
(confirmed via python3 substring count, not just grep, to sidestep
any shell/locale quoting issues with the Chinese search strings).
您的英文名字:使用 qinfengliu 这个名字将会创造一个新的人物,您确定吗(y/n)?
您的中文名字:
请设定您的密码:
请再输入一次您的密码,以确认您没记错:
膂力[ 19] 悟性[ 21] 根骨[ 17] 身法[ 23]
您接受这一组天赋吗?
您的电子邮件地址:
您要扮演男性(m)的角色或女性(f)的角色?
目前权限:(player)
...
客店 -
这是一家价钱低廉的客栈,生意非常兴隆。...
/clone/board/kedian_b [ 没有任何留言 ]
店小二(Xiao er)
店小二笑咪咪地说道:这位小姑娘,进来喝杯茶,歇歇腿吧。
【 平 民 】普通百姓 秦岭(Qinfengliu)
你是一位十四岁的女性人类,...
膂力:[ 19] 悟性:[ 21] 根骨:[ 17] 身法:[ 23]
...
你丢下一件布衣。
当你下次连线进来时,会从这里开始。
欢迎下次再来!Testing-methodology note (matches #91's own pitfall exactly): the
first two names attempted in initial ad-hoc testing (qinfeng2015 —
contains digits) got rejected at the English-id prompt
("对不起,你的英文名字只能用英文字母"), which desynced the whole
scripted --send sequence (each subsequent line got consumed as a fresh
id-retry attempt instead of advancing through the intended flow) — not
a bug, just confirms the id-validation is working correctly (English
letters only) and a reminder to always use a letters-only id in
mudclient.py scripts for this lineage.
Both known non-fatal pre-existing corrupted-save-data hits (chinesed's
e2c_dict.o, one board's .o) appeared during both runs exactly as
expected, both caught gracefully with zero effect on registration,
look, or score.
lpcc sweep
Ran twice (before/after the bowl.lpc/zhengmen.lpc fixes found via the
first sweep's own output), each a fresh lpcc --batch sweep via
scripts/lpcc_check.sh against all 3,256 .lpc files:
- Before: 3194/3256 pass (98.09%).
- After (bowl.lpc x2 + zhengmen.lpc fixes): 3196/3256 pass (98.16%).
Remaining 60 failures triaged by category (AGENTS.md §6b), every single
one directly re-verified against this archive's own source (not assumed
from #91's precedent) — see "Confirmed NOT needed" and "Content gaps"
sections above for the full breakdown: 11 corrupted pre-existing board
save files, 2 chinesed/e2c-dict-adjacent restore failures, ~19 genuinely
missing zone/skill content (mingjiao/yuan x9, wudang/taoyuan x4,
u/liujun/u/editer wizard scratch x3, taohua_b's missing room x1,
m_weapon x6 this_player()-null sweep artifacts), 10 dead
network/intermud daemon files, 1 home/simul_efun.lpc sweep artifact, 2
doc/-tree illustrative example files, 1 orphaned ASCII-art map file, 2
cmds/{usr,wiz}/to.lpc admin-utility functional-closure errors (present
and left unfixed in #91 too, for consistency). None of these affect
registration, look, or score — all confirmed via direct source
reading and, for the network/preload-related ones, direct grep of
adm/etc/preload, not guessed from precedent alone.
Memory stayed healthy throughout both sweeps (~35s wall-clock each,
free -h showed only ~4.1GB used / 11GB free at peak — a small/medium
lib, nowhere near mega-lib territory; no throttling needed despite
concurrent sibling agents potentially sweeping #92/#93 at the same
time).
Process notes
- Driver launched via
setsid nohup ... & disown(per AGENTS.md's documented workaround for the plain-nohup-dying-mid-session issue),cd'd intolibs/jqxz2015/first solog/debug.logresolves correctly. Booted twice total (once before thebowl.lpc/zhengmen.lpcfixes to get an initial clean registration read, once after, to re-verify with the complete final fix set) — PID 1099537 (first boot) was killed by its own exact PID before the second boot (PID 1133574), and PID 1133574 was killed by its own exact PID after all testing completed, each confirmed viass -tlnpno longer showing port 40086. No broadpkill -fpattern used at any point (this session was warned about a prior incident where that killed sibling agents' concurrent driver processes on archives #92/#93 — avoided entirely here). trace_lpcc.json(auto-generated by the single-filelpccsanity check before the first boot) andlpcc_batch_raw.log(the sweep script's intermediate raw output) were both removed from the lib's top-level directory after use;lpcc_fail.logwas kept, matching every other already-shipped lib's convention (it's the sweep's designed, permanent-per-lib output artifact, not an ad hoc scratch file).
Re-verification pass: driver rebuild + LPC formatter + WASM build
- LPC formatter (AGENTS.md "Post-conversion tooling"): ran
format-corpus.mjsover all 3,256.lpcfiles — 3,227 reformatted in place, 29 refused (nonzeroerrorsis expected/fine on messy legacy code per the tool's own self-check contract, not chased down). - Native retest against rebuilt driver (
~/src/fluffos/build-debug/ src/driver, rebuilt fresh from upstream master): booted clean, zero fatal errors indebug.log(only pre-existing non-fatal warnings and the already-documentedchinesed/board corrupted-save-datacatch()hits). Full registration verified with a fresh real name (秦风八) — English id → confirm → Chinese name → password ×2 → accept stats → email → gender m → arrives in 客店;look/score/quitall produce correct real output. No regressions from either the rebuilt driver or the reformat; no fixes needed this pass. - WASM build test (
scripts/wasm_client.jsagainstbuild-wasm/src): boots cleanly in-process (only ordinary compile warnings, no fatal preload errors). Full registration/login flow completed successfully under WASM too (id → name 秦风瓦 → password → stats → email → gender → 客店 arrival),look/quitalso correct — this lib has no IP/site-gating daemon on its login path, so it is not affected by the documentedquery_ip_number()WASM limitation and reaches a full playable state under WASM.
WASM-enablement pass (loopback-allow / uptime / throttle / admin seed)
Standard WASM/local-play pass per AGENTS.md §1.3(b)/(e) and §1.5.
Gates patched (loopback always allowed):
adm/daemons/band.lpcis_banned()(~line 39): short-circuitreturn 0for loopback /localhost/127.*(strict match on a well-formed string only — a malformed/non-string host is NOT treated as loopback, per the fail-closed correction: the driver-sidequery_ip_number()/resolve()bugs are now fixed upstream, so this fallback is no longer needed and would otherwise be a fail-open bypass). This is the only address gate on the login path —logind.lpclogon()callsBAN_D->is_banned(query_ip_name(ob)).
Uptime startup gate: none. No uptime() < N connection-rejection gate
exists (only cosmetic UPTIME_CMD display + in-game rumor/content timers).
Anti-flood throttle: none. logind.lpc has a reconnect/replace flow
(有人从别处…) which is normal game behavior, not a per-IP rate limit.
Admin account: id fluffos, pw Mud@2026, name 浮浮, granted (admin)
via adm/etc/wizlist. Registered through the real flow; login verified as
目前权限:(admin), update /adm/daemons/band recompiled successfully.
Save files (must be committed — NOT gitignored, orchestrator: force-add if
git status hides them): work/data/user/f/fluffos.o,
work/data/login/f/fluffos.o.
WASM 修复摘要(迁移自 meta.json 的 group_note)
同一引擎核心,2015 年内容版本。
§7.86 跨库扫描修复(留言板 post 崩溃)
BULLETIN_BOARDinherit+ 多余replace_program()致命形状(AGENTS.md §7.86,post命令崩溃):全档案 19 处命中,已删除多余的replace_program(...)调用(保留inherit),逐文件保留原有行尾格式(CRLF/LF 按文件原样)。本次为跨库 §7.86 扫描修复(触发原因:该 bug 已在 6+ 个互不相关的血统家族独立确认,属于近乎普遍的拷贝粘贴模式),仅做编译检查(驱动干净启动、端口正常监听),未做完整 §10.7 深度游玩测试。
深度功能测试 / Deep functional test (2026-08-07)
按 AGENTS.md §10.7 流程做的第一轮真正意义上的深度游玩测试——此前几
轮都停留在注册/登录/编译层面。这份档案自己的 README 及既有 NOTES 已
确认它和"2008 加强版"(jqxz2008)、"2008 标准版"(jqxz2008std)、
"2008 豪华版"(jqxz2008dlx)、xiakexing3 共享同一套 ES II 引擎核
心,其中 jqxz2008/jqxz2008dlx/jqxz2008std/xiakexing3 都已经
各自做过一轮 §10.7 深挖并记录了具体 bug——开机前先把这几份记录读了
一遍当路线图,逐条对照本档案的实际源码,5 个全部确认存在(细节见下
"开机前主动移植"),比预期的还要更省事:不用重新从零排查,直接照着
清单核对再动手修。
WASM 本轮仍然跳过验证:emsdk 安装器把工具链下载硬编码到
storage.googleapis.com,本 session 的出站代理策略拒绝该域名
(curl -sS $HTTPS_PROXY/__agentproxy/status 确认为 403),未重试。
但这份档案自己 NOTES.md 里"WASM build test"一节记录过更早一轮会话
已经用 scripts/wasm_client.js 完整验证过注册/登录流程在 WASM 下能
跑通——本轮只是没有重新跑一遍确认这轮修的 bug 在 WASM 下同样生效,
不是"从未验证过"。
开机前主动移植(对照 jqxz2008 系家族已确认修好的 bug):
1. AGENTS.md §7.7(已确认第 N 例)——adm/daemons/chinesed.lpc
的 create() 原本是裸 restore(),本档案的 data/e2c_dict.o 是
损坏的二进制垃圾(不是合法 mapping 字面量),restore_object()
抛出的运行时错误没有被捕获,会让 create() 在那一行直接中止,
全局 mapping dict 被清零——第一次真正用到 chinese()/
to_chinese() 的地方(战斗/技能提示大量使用)就会崩溃。改成
catch(restore()); if (!mapp(dict)) dict = ([]);,和 jqxz2008
系已验证过的修复完全一致。开机日志里能直接看到这处 catch()
正确拦下了损坏存档的运行时错误(而不是让 create() 中止),
验证修复生效。
2. AGENTS.md §7.11(已确认第 N 例,且是本档案里最严重的一处)——
work/log/nosave/ 目录在这份 work/ 树里从未被创建(gitignore
忽略的运行期目录,与仓库无关),但至少 4 个 write_file()/
log_file() 调用点无保护地往里面写:adm/daemons/combatd.lpc
的 killer_reward()(每一次玩家死亡都会跑到,且这一处不像
kill.lpc 那样有 userp() 判断限定 PK 场景,任何死亡都会触发)、
cmds/std/kill.lpc(仅 userp() 场景)、cmds/skill/{bai,
apprentice}.lpc 的风清扬弟子计数器。killer_reward() 这一处一旦
目录缺失就会在 die() 中途未捕获地抛异常,让角色的死亡清理(尸
体、鬼魂状态、移到死亡场景)全部不会执行,角色变成"活着但气血
精气归零"的破损状态,而且会在之后每一次 heart_beat() 都
重新触发——jqxz2008/jqxz2008dlx 都通过实际杀死角色确认过这
个死循环崩溃。本轮用该家族已验证的 assure_file() 模式在 4 处
write_file() 调用前各加一行 assure_file(...)(combatd.lpc/
kill.lpc/bai.lpc/apprentice.lpc),并给 bai.lpc/
apprentice.lpc 里 read_file() 的结果加了 stringp() 判断
(避免 atoi(0))。本轮额外发现的第 6 个同类隐患:这份档案
自己的 adm/simul_efun/file.lpc 里 log_file()(全档案通用的日
志辅助函数,被 cmds/arch/call.lpc 等至少 5 个不同的
nosave/* 日志点调用)本身也只是裸 write_file(LOG_DIR + file,
text),没有调用同一个文件里现成的 assure_file() 辅助函数——
直接在 log_file() 内部加一行 assure_file(LOG_DIR + file),一
次性覆盖它所有的调用点,比逐个日志点手工加保护更彻底(assure_file
定义原本在 log_file 后面,这个驱动的编译器要求同文件内被调用
的函数需要先声明/定义,所以顺手把两个函数的顺序对调了)。
3. cmds/skill/bai.lpc/cmds/skill/apprentice.lpc(一处括号位置
错误)——if (((string)me->query("family/master_id" ==
"feng qingyang")) || ...),== 比较被夹在 query(...) 的参数
括号内,传给 query() 的实际是恒为假的布尔值,不是想要的属性名
字符串,导致"从风清扬门下叛出"检测分支永远不会触发。已改成先呼叫
query("family/master_id") 拿返回值再比较,两个完全相同的文件都
改了。
4. AGENTS.md §8.9(已确认第 N 例)——adm/daemons/logind.lpc
enter_world() 里 if (!user->query("food") && !user->query("water")
&& ob->query("age") == 14),age 取自登录阶段用完即弃的连线桩物
件 ob,不是真正的角色本体 user——桩物件永远没有 age 属性,
条件恒为假,导致每个新角色的食物/饮水从创建起就永远是空的。改成
user->query("age") == 14。Live 验证:注册后 score 食物/饮水两
栏均满格(■■■...),管理员账号 fluffos 重新登录后同样两栏被
补上(此前从未有 food/water 字段,见下方存档 diff)。
5. get_name() 遗留调试 printf("%O\n", ob)(新发现,jqxz2008
系没有,xiakexing3 有)——紧跟在玩家输入中文姓名之后,会把连
线桩物件的原始引用(/clone/user/login#0 这类内部标识)直接回显
给正在注册的新玩家,属于内部调试信息泄漏。已删除该行,Live 验证:
注册流程中输入中文名字后直接进入密码设置提示,没有任何对象引用
泄漏。
测试路径:读 doc/help/newbie 确认「较量」(fight) 是安全对练的
标准做法(气/精跌到 50% 或以下自动停止)后,在原生驱动下一次连续会
话里:注册(真实中文名 叶秋白,id jqxzdeep)→ 落地客店,look/
score/i 确认干净、食物/饮水满格(§8.9 修复验证)→ west→south
到中央广场,fight liu mang 对普通"流氓"安全对练,几回合后自动
"承让了"结束,score 确认气条降到约 50%、无死亡/无损失 → enter
shudong 进入丐帮地下通道,bai zuo 组织性拜入 丐帮 第二十代弟子
(师父左全),xue zuo begging 组织性学习技能,即时进步提示正常 →
另开管理员会话(fluffos/Mud@2026,账号已在 adm/etc/wizlist 中)
用 call jqxzdeep->set_skill(sword,50)(该引擎家族没有专门的
setskill/setparty 类快捷指令,cmds/arch/call.lpc 是通用的管理
员任意函数调用指令,充当本档案的技能赋予捷径路径)验证捷径路径——
nosave/CALL_PLAYER 操作日志正确写入(验证了上面第 2 点里 log_file()
的修复),角色 skills 指令确认组织性的 begging 与捷径赋予的
sword 同时存在 → quit(触发 save())→ debug.log 全程检查
(grep -v 排除编译期 warning 后)零 error:/crash/fatal 行 →
真实间隔重新连线(nc 断开重连,非同一 TCP 会话),score/skills
确认门派归属、师父、组织性/捷径两条技能、已花费潜能全部正确持久化。
一次会话内的持久化教训(记录,非 bug):本轮为了应用
log_file() 修复重启过一次驱动,但重启前忘了让测试角色先 quit
(只是杀掉了旧驱动进程)——重连后发现角色回到全新状态(无门派、无
技能、潜能满格),排查后确认这不是 mudlib 的持久化 bug:cmds/usr/
quit.lpc 的 main() 明确调用 me->save(),本档案没有自动周期性
存档,纯粹是测试流程上少做了一次 quit 才导致进度丢失。之后重新走
了一遍拜师/学艺流程并正确 quit,最终的持久化验证(见上)就完全
正常了。
测试角色:id jqxzdeep,中文名 叶秋白,密码 Jqxz2026Test,
丐帮第二十代弟子(师父左全),技能 begging(组织性)+ sword(捷径路
径,50 级),位于客店。存档:work/data/{login,user}/j/jqxzdeep.o。
管理员账号 fluffos 存档因本轮测试产生了正常的 food/water/mud_age
增量(§8.9 修复的直接体现,非损坏),按这份档案自己既有 NOTES 里
"必须提交,不受 gitignore"的约定一并提交。
验证通过:真实中文名注册;look/score/i 多次状态检查;食
物/饮水初始化(§8.9);安全对练 fight(自动停止机制);丐帮组织
性拜师+学艺;管理员捷径路径(call)技能赋予;chinesed.lpc
损坏存档的 catch() 防护;log_file()/assure_file() 缺失目录防
护(含新发现的 log_file() 自身漏洞);quit(save())后
debug.log 检查;真实断线重连后的完整状态持久化。
明确未验证(记录而非静默跳过):完整战斗到死亡的循环(fight
安全对练已覆盖核心战斗机制,真正杀死角色需要更多时间预算构造合适
对手,本轮未做);风清扬弟子叛出这个罕见分支(bai.lpc/
apprentice.lpc 的括号修复已通过代码比对验证,未构造这个特定场景
实机触发);商店购买(起始区域客店本身没有商店,真实商业区未探索);
WASM 下的重新验证(详见上方说明,proxy 阻断,且此前已有会话独立确
认过 WASM 可用)。
深度功能测试(2026-08-13,round two,新驱动重测)
Re-tested against the freshly-rebuilt build-debug/src/driver(post
全库 quest_times/win_times %-operator 修复 + Warning/warning
驱动文本回退)。本次复核确认这份档案已经是本轮 jqxz2008 家族里
最干净的一个:log_error()(已有 #15w 引用注释)、log_file()
(早前会话自己就发现并修复了同一个 assure_file() 缺失 bug,见
commit 4603617af84)、管理员账号(fluffos/Mud@2026,
wizlist 已有授权且存档已提交)全部依然正确生效,本轮没有发现
新 bug,未做任何改动。
win_times 修复确认存在且正确:d/city2/npc/refereew.lpc:176;
未发现 message() simul_efun 包装函数。用已提交的 fluffos/
Mud@2026 登录,update /adm/simul_efun/file 确认可正常重新编
译,零诊断刷屏(这次连线也没有再触发姊妹档案 jqxz2008std 那次遇
到的随机昏迷事件)。log/debug.log 时间戳全程未变化(Jul 23,
早于本次会话),确认无新增未捕获运行期错误。登录本身产生的存档时
间戳类微小 diff 已用 git checkout 撤销,不提交。驱动最终按精确
PID kill,ps -p 确认已退出。
§7.100 扫描修复(ROOM 基类多余 replace_program())
#define ROOM "/inherit/room/room":删除 818 处多余的、独立成行的
replace_program(ROOM);(保留 inherit ROOM;),与 jqxz2008
系列同一血统同一形状。clone/misc/roommaker.lpc 同样有两套模
板——"造一间空房间"的 heredoc 本来干净,"克隆我所在的房间"命令的
字符串拼接模板把同一枚多余的 replace_program(ROOM); 烤进了每一
个新克隆的房间,已同步修正。已用 build-debug 驱动干净启动验证
(0 个新增编译错误,端口正常监听);未做完整 §10.7 深度游玩测
试。
深度功能测试(2026-08-20,round three,补齐三处"明确未验证")
本轮专门针对上面 2026-08-07 记录的三处"明确未验证"项,预算充足, 逐一构造场景实机验证。开机前先做了一遍标准清单快速核对(全部确认 已经是干净状态,未发现新问题,细节见下)。
标准清单核对:§7.90(config.fluffos 第 40 行 maximum
evaluation cost : 5000000,确认——注意 work/config.cfg 里另有一份
maximum evaluation cost : 300000,但那不是驱动实际加载的配置文件,
config.fluffos 的 master file/mudlib directory 等字段才是真正
生效的一份,已核实);§7.100(全档案 replace_program(ROOM); 42 处
命中全部是注释行,零处存活,确认已是上一轮修复后的干净状态);
§7.111(adm/obj/master.lpc——config.fluffos 的 master file
字段指向的真正生效文件——第 200 行已经是
objectp(error["object"]) ? file_name(error["object"]) : "(driver)"
的空指针防护写法;adm/single/master.lpc 那份没有防护但从未被驱动
加载,非生效代码,确认无需处理);§7.79(全档案零 addn()/
addn_temp() 2 参数裸调用,本档案这套血统本来就不含这个 bug 形
状,确认不适用);§7.108(clone/user/user.lpc 第 110-116 行
reconnect() 明确调用了 enable_commands(),确认干净);§7.112
(death_stage() 家族 4 个实例——bgargoyle/wgargoyle/
newgargoyle/yu-zu2——逐一检查每一个真正终止流程的 exit 分支,
全部正确清除了 death_stage_active 重入锁,确认无残缺分支)。
1. 完整战斗到死亡的循环——已验证,真实死亡+复活全流程跑通:
新建测试角色 jqxzfour(中文名 秦四,密码 Jqxz2026Four,男性),
读 cmds/std/kill.lpc 确认(与本 session 其它库的规律一致)kill
指令对 NPC 目标确实没有任何安全阀(obj->kill_ob(me) 对方直接反
击)。找到 d/npc/xiaofeng.lpc(萧峰,北大街)——max_qi 4500/
max_jing 1500 级别的高战力 NPC,远超新手角色——在原生驱动下对他
下 kill xiao feng:几回合后被"雷霆一击"重创,"眼前一黑",真实死
亡(非 fight 安全对练)。死亡后走的是完全真实、未修改的代码路
径:feature/damage.lpc 的 die() → CHAR_D->make_corpse() 掉落
尸体 → 移动到 DEATH_ROOM(/d/death/gate.lpc,鬼门关)→ 房间内
white gargoyle(白无常)NPC 的 death_stage() 对话流程逐条播放
("你叫什么名字?"→…→"阳寿未尽?")→ 最终 reincarnate() 并移动到
复活点 /d/city/wumiao(武庙)。score 确认惩罚符合设计(潜能从
99 减半到 50,气/精降为约 75%,随心跳自然恢复中)、身上物品全部
随尸体掉落(i 显示"目前你身上没有任何东西",与登录时"你丢下一件
布衣"的既有设计一致)。整段过程 debug.log 零 error:/crash/
Segmentation。断线重连验证状态正确持久化。(注:feature/
damage.lpc 里 DEATH_ROOM->start_death(this_object())
这一行调用的函数在全档案任何地方都未定义——call_other 到不存在
的函数在这个驱动下是静默返回 0,不是运行时错误,debug.log 全程
确认没有相关报错;真正的死亡流程是靠玩家被移动进鬼门关房间后,房
间里 wgargoyle 的 init() 自己探测 previous_object() 触发的,
不依赖这个从未实现的 start_death(),纯粹是历史遗留的死代码,不
是本轮范围内的 bug)。
2. 风清扬弟子叛出——已验证,真实触发,且额外发现并修复一个真
实运行时崩溃 bug(详见下):读 cmds/skill/apprentice.lpc/
kungfu/class/huashan/feng.lpc 确认触发条件——先要成为风清扬的弟
子(family/master_id == "feng qingyang"),再拜一个不同门派的师
父,且对方已经对你 pending/recruit(即对方已经用 recruit 指
令点名收你为徒、只等你回拜)。feng.lpc 收徒门槛很高(剑法/紫霞
神功/身法/文学等技能全部 ≥130~160、shen ≥ 100000、int ≥ 41、
随机 kar 检定),管理员 call 赋予测试角色对应技能/属性后(符
合任务允许的"用管理员捷径进入场景,但让真正的触发指令走真实代码"
原则),先在 /d/huashan/buwei2 拜入门槛较低的入门弟子路线(岳不
群,仅需 shen≥1000+query_int()≥25),确认拿到 family_name ==
"华山派" 后,再到 /d/huashan/houshan 拜风清扬,成功——family/
master_id 确认变为 "feng qingyang"。随后用管理员 possess
指令附身到丐帮 左全(/d/gaibang/inhole)身上手动对 jqxzfour
下一次 recruit 指令(不经由 attempt_apprentice() 的自动即时收
徒分支,只是先挂起 pending/recruit),退出附身后,jqxzfour 玩
家自己下 bai zuo——这次真正命中 apprentice.lpc(原括号 bug
修复处)里 ob->query_temp("pending/recruit")==me 那个分支,输出
"你决定背叛师门,改投入左全门下!!",family_name 变为"丐帮",
family/master_id 变为左全,score 也确认师承信息正确更新;/
kungfu/class/huashan/FENG 计数文件从"0"变为"2"(两次拜风清扬产生
的正常计数递增,一次是最初的入门测试,一次是为复现这个分支而重
新拜的),确认原括号错误修复后这条分支的运行时行为完全符合预期。
(补充观察,非 bug,未修改):feng.lpc/kungfu/class/gaibang/
hong.lpc 的 attempt_apprentice() 用
(string)ob->query("family/family_name") != "" 判断"对方是否已
经有师父"——对一个从未加入任何门派的全新角色,query(...) 返回
的是裸 int 0,(string)0 在这个驱动下转成字符串 "0" 而非空
字符串 "",导致该判断对"完全没有门派"和"已有其它门派"两种情况
一视同仁地拒绝,实机复现确认(bai feng 对一个从未拜过师的全新
角色会被拒绝,提示"既然已有名师指点,何必又来拜老朽呢")。但这条
分支在正常玩法里几乎不可能被触发——华山派/丐帮的高阶传人一定是先
经过入门弟子(岳不群/宁中则/令狐冲,或丐帮的左全等)才可能有资格
再进阶拜访风清扬/洪七公,不会有全新角色跳过所有入门步骤直接来见
这两位——按本 session 的 scope 纪律(无编译错误/运行时崩溃/
debug.log 报错/驱动级拒绝,大概率是设计而非 bug)未作修改,只记
录在此供后续参考。
3. 商店购买——已验证,价格扣除+实物到手全部正确:d/city/
zahuopu.lpc(杂货铺,东大街南)用 list/buy 两个指令,NPC
杨永福(d/city/npc/yang.lpc)用 F_DEALER 混入。给测试角色
jqxzfour 用管理员 clone /clone/money/coin + call
coin->set_amount(500) + give coin to jqxzfour(任务允许的
"clone+give 该档案真实货币物件"标准手法,需要角色在线才能接收,
先重连再 give);list 确认价目表,buy budai(麻布袋,标价一
两白银=100)购买成功,i 确认物品到手且找零正确(四两白银,
500-100=400=4两,数学验证一致)。有一处值得记录但非 bug 的现象:
buy 命令刚执行完的一瞬间,i 仍然显示"五百文铜板"(旧的、本该
被清空的硬币堆)——根源是 inherit/item/combined.lpc 的
set_amount(0) 并不会立即把 amount 归零,只是 call_out
("destruct_me", 1) 延迟 1 秒后再摧毁物件,这 1 秒窗口内
query_amount()/short() 显示的是即将消失前的旧值;2 秒后再查
i,旧硬币堆已经正确消失,只剩找零后的银两,最终状态完全正确。
无编译错误/运行时崩溃/debug.log 报错,纯粹是这个 ES2 引擎家族的
货币物件通用的、无害的、会自我纠正的显示延迟,不是本档案独有,
不作修改。
新发现并修复的真实 bug(AGENTS.md §7.30 第二例):在"1.完整战
斗到死亡"测试过程中,debug.log 捕获到一条真实未拦截的运行时错
误——执行时段错误:*Bad argument 1 to keys() Expected: mapping
Got: 0,来自 /d/npc/xiaofeng.lpc 第 99 行 check_skills()。根
源:feature/skill.lpc 的 mapping query_skills() { return
skills; },skills 这个成员变量对一个从未学过任何技能的全新角色
从来没有被赋值过,LPC 对未初始化 mapping 变量的默认值是裸
int 0 而非 ([]),xiaofeng.lpc 的 init() 在任何玩家进入他
所在房间(北大街)2 秒后排程的 check_skills() 无防护地对这个
可能是 0 的返回值调用 keys(),直接崩溃——任何全新、从未学过
任何技能的角色路过北大街都会触发,属于高可及性的真实 bug,不是
本档案独有内容/平衡设计。全档案排查所有 keys(...->query_skills
())/sizeof(...) 调用点(多数早已用 mapp()/真值判断正确防
护),额外发现 4 处同款无防护实例并一并修复(均改为在调用 keys()
前加 if (!mapp(skl)) return; 或等价的提前返回防护):
d/npc/xiaofeng.lpc(萧峰,北大街,已确认可达且已实机复现崩溃 与修复后不再崩溃)d/npc/duanyanqing.lpc(段延庆,西大街2,与萧峰同款check_skills()call_out 形状,确认已放置可达)kungfu/class/mingjiao/yangxiao.lpc(杨逍,明教铁焰令对话,需 先加入明教才会走到这条分支,但明教新弟子零技能时仍会命中)kungfu/class/shaolin/qing-le.lpc(清乐,少林两处——藏经楼手谕 +达摩令——同理需先加入少林)d/city/npc/baibian.lpc(城内"百变",目前档案里未被任何房间引 用,是死代码,但为与已有防护的姊妹文件d/wudang/npc/baibian.lpc保持一致,顺手一并修复)
全部 5 处用 update 指令在活驱动上重新编译确认"成功",并用一个全
新注册、skills 指令确认"你目前并没有学会任何技能"的角色(秦五
/jqxztest)真实走进萧峰房间验证不再崩溃、debug.log 全程零
error:。已提交。
测试角色:jqxzfour(秦四,Jqxz2026Four,男性,历经商店购
买→真实死亡复活→华山派→风清扬弟子→丐帮叛徒的完整测试链)、
jqxztest(秦五,Jqxz2026Test5,男性,仅用于验证 §7.30 fix,
零技能状态)。存档:work/data/{login,user}/j/{jqxzfour,
jqxztest}.o。管理员账号 fluffos 存档因本轮测试(clone/
give/possess 等操作)产生正常增量,按既有约定一并提交。
测试过程中的插曲(记录,非 bug):possess(附身 NPC)后,
账号与"当前受控身体"的绑定关系(find_body(id))会保持指向被
附身的 NPC,若不先用某种方式正确退出附身就断线,下次用密码重新
连线会走 confirm_relogin 的"是否踢掉旧连线"流程而不是直接
reconnect,且如果同一批命令里把 y/n 确认和后续指令一起发送,
非 y/n 的后续指令会被当成 y/n 回答误吃掉(yn[0]!='y' 直接判定
为"否",destruct(ob) 断开这次新连线)——这不是 mudlib bug,是
测试脚本没有先手动处理这个确认提示;后续通过重启驱动清空所有连
线状态解决,之后的 update 验证等操作均在干净状态下完成。验证通过:真实商店购买(价格扣除+实物到手+找零正确);真实
kill战斗死亡到复活的完整流程(掉落尸体/鬼门关对话/复活点正
确/惩罚符合设计/断线重连持久化正确);风清扬弟子叛出的完整真实
触发(含用管理员 possess 精确构造出 apprentice.lpc 里那条此
前只做过代码比对、从未实机触发过的 pending/recruit==me 分支);
新发现并修复一处 §7.30 家族真实运行时崩溃 bug(5 处实例);标准
检查清单六项全部确认干净。
§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,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 jqxz2015 --fix 加 scripts/lpc_fix_no_effect.py --apply,共改动 266 个 .lpc 和 10 个 .h(多为删去未用的局部变量)。HEAD 与工作树分别加载(新进程):253 -> 253 通过,无回退;改过的头文件的 67 个包含者 67 -> 67 通过。启动时警告 17 -> 0;新进程登录(输入名字)正常。
- 2026-10-10:编译警告第二轮(按驱动报告逐条修):按位 & 改逻辑运算 0 处,返回类型/原型 6 处,NPC+F_UNIQUE 的 init() 0 个,带初始化的未用局部变量 1 个,只在 #if 分支用的声明移进分支 0 个文件;改动 6 个文件,HEAD 与工作树各载入一次无回退(6 objects; HEAD PASS 6, tree PASS 6; regress 0; newly loading 0),这些文件的警告 6 -> 0。
- 2026-10-10(续):第二轮编译警告整理(
lpc_fix_unused_init.py)删掉了只在不启用的#if分支里用到的局部变量声明(如include/net/ftpdsupp.h中#ifdef GUEST_WIZARD_FTP分支的file),启用该选项时会编译失败;声明已放回所用的分支里,工具已改为跳过这种情况(交给lpc_move_decl.py)。
编译警告收尾(2026-10-13)
scripts/toolkit_fix.sh 一轮去掉 16 处多余继承;include/net/ftpdconf.h 把 VALID_READ、VALID_WRITE 定为 1,覆盖 ftpd.h 的 0,先 #undef(同 xiakexing2017),行为不变。能编译的文件警告清零;改动的对象在 HEAD 与工作树各载入一次(16 objects; HEAD PASS 15, tree PASS 15; regress 0; newly loading 0)。
- 2026-10-14:2 个存档文件(留言板 2 个;
data/board/gaibang_b.o,data/board/tiandi_b.o)还是原档案的 GBK 编码,没有转成 UTF-8,restore_object()报Invalid utf8 string后对象以空数据启动(表情守护进程没有表情、留言板没有帖子、玩家无法载入)。scripts/lpc_save_encoding.py逐个按 GB18030 解码,结果按存档格式解析通过才写回(KB 03 §4)。
无门派玩家的 family 映射(2026-10-15,KB 05 §7.30 第三种)
mapping fam = ob->query("family"); 之后直接 fam["family_name"]:没有门派(新人或叛师后)的玩家在学习、练功、拜师、进入门派房间时报 Value being indexed is zero,而不是作者写好的提示。2 处在声明行加上 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):mizongxinfa→mizong-xinfa(longxiang/fanchang)。
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)
3 个文件、3 处在 create() 里 carry_object("<本库没有的文件>")->wear()(或 wield()、set_amount()):carry_object() 得 0,接着的调用报 Bad argument 1 to EFUN call_other(),NPC 根本载入不了,该有它的房间里就少了这个人。多是从别的系统搬来的 NPC 用了原系统的物品路径(最常见:/d/city/obj/tudao、/clone/cloth/female-cloth、/clone/cloth/cloth)。每处改为 { object carried_ob = carry_object(...); if (carried_ob) carried_ob->wear(); }(scripts/lpc_guard_carry_object.py):NPC 照常出现,只是不带这件东西;文件补回来(或是虚拟对象)照样会带上。载入检查:改动的文件改前能载入 0 个,改后 2 个(2 个原来载入不了),没有退步;其余 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 映射不到,门派弟子用普通轻功/拳脚)。按核对过的对照表改正,共 6 处、5 个文件:xinxiu-duzhang→xingxiu-duzhang(2 处)、tiaji-jian→taiji-jian(2 处)、jinyin-baiguzhao→jiuyin-baiguzhao(1 处)、qishang--quan→qishang-quan(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 逐个物件对比载入,没有退步。另有 13 处浮点数赋值要手工改(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/ 下 11 个技能的 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.,同一个动词的其他处理函数不再尝试(不是最新的一条就悄悄跳过)。删除了 15 条注册(15 个文件,scripts/lpc_fix_dead_add_action.py),动词留给别的处理函数:/d/mingjiao/npc/changjinpeng.lpc(do_join)、/d/mingjiao/npc/lengqian.lpc(do_join)、/d/mingjiao/npc/pengyingyu.lpc(do_join)、/d/mingjiao/npc/shuobude.lpc(do_join)、/d/mingjiao/npc/tangyang.lpc(do_join)、/d/mingjiao/npc/wensong.lpc(do_join)、/d/mingjiao/npc/yanyuan.lpc(do_join)、/d/mingjiao/npc/yinwufu.lpc(do_join)、/d/mingjiao/npc/yinwulu.lpc(do_join)、/d/mingjiao/npc/yinwushou.lpc(do_join) 等共 15 个文件。最多的函数名:do_join 13 处、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] == "澄" 等 21 处(2026-10-22,KB 06 §7.360)
原档按字节算字符串区间(一个汉字 2 字节):name[2..3] 是名字的第二个字,name[0..1] == "澄" 问名字是不是以「澄」开头。转成 UTF-8 之后,这个驱动的区间和 strlen() 都按字符算(strlen("澄观") 是 2,"澄观"[0..1] 是两个字),老算术原样留着、意思全变:拜入少林 / 武当 / 峨嵋等派的玩家被改成错误的法名(二字名 张三 变成一个字的 澄,更长的名字取到第三个字);各派掌门的辈分判断(name[0..1] == "澄")永远不成立。
本库 21 处(13 个文件):拼名字的赋值 13 处、与汉字常量比较 8 处。例:name[0..1] → name[0..0](/kungfu/class/emei/kong.lpc:134);name[2..3] → name[1..1](/kungfu/class/shaolin/cheng.h:157);name[0..1] == "慧" → name[0..0] == "慧"(/kungfu/class/shaolin/cheng.h:140)。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 加载失败;改后加载成功。