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

✅ 可玩

金庸群侠传(2008 加强版)

jqxz2008

🔑 fluffos / Mud@2026 更新 51c42c7 2026-09-01 源码 下载 ZIP

▶ 开始游玩 · Play Now

本游戏自称 金庸群侠传,本压缩包对应"2008加强版"这一内容版本。属于"ES II"引擎家族(源自作者 Phoebus.suny 1998 年的 ES2"天曹地国"版本),与本项目中的标准版(`jqxz2008std`)、超豪华版(`jqxz2008dlx`)、2015版(`jqxz2015`)核心引擎逐字节相同,是同一套服务端程序的四种不同内容版本;这支血脉还延伸得更远——`xiakexing3`(游戏内同样自称"金庸群侠传")与本作 91% 的文件逐字节相同,`xiakexing2017` 又与两者各有 80%-84% 重合,可以说是同一款底层游戏保留下来的六个快照。新角色从店小二看店的路边茶馆起步,可在中央广场通过一处树洞暗语机制加入丐帮、拜入左全门下习武,也可走白驼山使者按资质招人的另一条入门路线;向风清扬拜师会触发"风清扬现在共有 N 个徒弟"的实时播报彩蛋。明教九名"缘"字辈弟子的名字里藏着一个数字诅咒梗——一伤、二败、三毁……直到八衰。深度体验里角色真的死于黑无常之手,完整走过了尸体、化鬼、转生的死亡仪式。

English

In-game titled 金庸群侠传 ("Jin Yong Heroes Gathering"), running on the "ES II" engine (credited in its own Readme.txt to author Phoebus.suny's 1998 Tiancao-Diguo release) — the same core confirmed byte-for-byte, via direct md5sum comparison of the raw archives, as this project's jqxz2008std (a leaner, earlier '2008 Standard' content cut with fewer quests and shorter room text), jqxz2008dlx ('2008 Deluxe,' its own sect-NPC/combat-tuning/map additions), and jqxz2015 (seven more years of added zones) -- one server program, four separate content builds, not independent games. A later file comparison found the lineage extends beyond that four-way family too: this collection's xiakexing3 (in-game self-titled the same "Jin Yong Heroes Gathering" despite its archive name) shares 91% of its files byte-for-byte with this build, and xiakexing2017 shares 80-84% with both xiakexing3 and this build -- two more content snapshots of the same base game (not separately re-checked against jqxz2008dlx/std/2015). New characters land at a roadside tea house run by 店小二 (Xiao-er) and can join the Beggars' Sect through an organic passphrase-gated tree-hole hideout at the Central Square, training under 左全/Zuo Quan, or the White Camel Mount sect via a separate stat-gated recruiter NPC; real combat death against a 黑无常 (Black Gargoyle) NPC leads into the full corpse/ghost/reincarnation ritual at the death-gate inn. The Mingjiao zone's nine "yuan" NPCs carry a running numeric-curse naming gag (一伤/二败/三毁.../八衰 -- "one-hurt," "two-defeat"..."eight-decline").

README

内容亮点

在线试玩

https://mudlibs.fluffos.info/jqxz2008/

管理员账号 / Admin account

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

本地运行

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

游戏端口:40082

NOTES · 移植与修复记录

jqxz2008 — 金庸群侠传 (Jin Yong Heroes Gathering)

Archive: archives/金庸群侠传2008加强版.rar ("Jin Yong Heroes Gathering 2008, enhanced edition"). Extracted mudlib root: raw/jy/ (a single top-level jy/ directory inside the archive). Port: 40082. Status: done (boots clean, full registration flow verified with a real Chinese name, post-login look/score verified working).

What this is / lineage

config.cfg's name field (GBK-decoded) is literally 金庸群侠传, matching the archive title exactly — this is NOT a mislabeled archive. adm/obj/{master,simul_efun} layout, "ES II" lineage (its own Readme.txt says "ES2 lib (Tian Cao Di Guo) Version... Wrote By Phoebus.suny 1998").

Confirmed near-identical sibling of xiakexing3 (archive #44, libs/xiakexing3/): md5sum diff shows adm/obj/master.c, adm/daemons/logind.c, adm/daemons/chinesed.c, adm/obj/simul_efun.c, adm/simul_efun/chinese.c, include/globals.h, and adm/simul_efun/message.c/feature/message.c are all byte-identical between the two archives. Only adm/daemons/securityd.c and config.cfg differ. This fully explains xiakexing3's own NOTES.md oddity ("config MUD_NAME is 侠客行三 but the live banner reads 金庸群侠传") — xiakexing3 is a rebranded fork/snapshot of (or a common ancestor with) this exact "金庸群侠传" codebase; whoever forked it changed the config's name/MUD_NAME field but never touched the deeper, shared engine files, so the in-game banner text baked into those shared files still says "金庸群侠传". Cross-check note for later archives: per the task brief, archives #92 (金庸群侠传2008版.rar), #93 (金庸群侠传2008超豪华版.rar), and #94 (金庸群侠传2015版.rar) are still queued and share this title family — worth an md5sum cross-check against this lib's core files (adm/obj/master.lpc, adm/daemons/logind.lpc, adm/daemons/chinesed.lpc, adm/simul_efun/chinese.lpc) once processed, the same way this pass cross-checked against xiakexing3(#44). Given xiakexing3, #92, #93, #94 all share "金庸群侠传"/"侠客行" branding, there is a real chance several of them turn out to be near-identical snapshots of the same underlying engine with only site branding + a handful of content files differing (same pattern as the shujian2008/sjtx2 and zhongjidiyu-family precedents already in AGENTS.md) — check this lib's fixes (§15h chinese.lpc shape, §15ae command.lpc shape, combatd.lpc's quest.h include, the "tang"-family new-as-variable-name typo, etc.) against them directly before re-diagnosing from scratch.

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

Fixes applied (with why)

1. AGENTS.md §15h (is_chinese / check_legal_name — GBK byte-range checks silently wrong under UTF-8 strings): - adm/simul_efun/chinese.lpc's is_chinese(): GBK lead-byte range check (str[0] > 160 && str[0] < 255, strlen>=2) → CJK Unified Ideographs codepoint range check (str[0] >= 0x4e00 && str[0] <= 0x9fff, strlen>=1). - adm/daemons/logind.lpc's check_legal_name() (inline in logind.lpc — this lib has no separate named.lpc): byte-count bound strlen(name) < 2 || > 12 → character-count bound < 1 || > 6 (halved, matching what the user-facing message already promises: "1 到 6 个中文字"); dropped the i%2==0 && even-byte-offset gate in the per-character is_chinese(name[i..<0]) sliding-window loop (every index is already one full character now). - Verified working: real Chinese name "秦风" now passes on the first attempt (confirmed via the registration transcript — see below); before this fix every valid Chinese name would have been silently rejected.

2. AGENTS.md §15ae (private nomask command-hook breaks every post-login command silently): feature/command.lpc's command_hook(string arg) was declared private nomask and is dispatched via add_action("command_hook", "", 1) from F_COMMAND, inherited transitively into the player body (clone/user/user.lpcinherit/char/char.lpcinherit F_COMMAND). Dropped private (kept nomask). Verified: look and score both work correctly post-login (see transcript below) — without this fix every typed command, including look, would silently do nothing.

3. AGENTS.md §15t (variant 1): adm/daemons/combatd.lpc had #include </quest/quest.h> — an ABSOLUTE path inside angle brackets, which this driver's inc_open() never resolves (angle brackets only search the configured include path, never an already-absolute name). /quest/quest.h genuinely exists on disk. Fixed to #include "/quest/quest.h" (quoted absolute form, which this driver's resolver does handle). Without this, combatd.lpc (needed by the score command and all combat) never compiled at all — confirmed via a live score attempt throwing *No program in object '/adm/daemons/combatd'! before the fix.

4. AGENTS.md §15t (variant 3, NEW manifestation): fixing #3 above then surfaced a SECOND bug in the same file: once /quest/quest.h actually got included, its file-scope global mapping quest_name = ([...]); landed textually BEFORE combatd.lpc's own inherit F_DBASE; line (the #include was listed after some other #includes but before the inherit), which is a fatal "Illegal to inherit after defining global variables" on this driver. Fixed by moving inherit F_DBASE; above ALL of combatd.lpc's #include lines. quest.h's own quest_finished()/quest_failed()/lock_quest()/islocked() function bodies are real (not just prototypes) — the earlier "Undefined function quest_finished" sweep error was purely a downstream symptom of the broken #include, not a missing function; it resolved automatically once the include worked.

5. A capitalize()-on-0 robustness bug in feature/name.lpc (same family as AGENTS.md §15e's "guard every unchecked chained call" principle, new concrete instance): short(int raw)'s fallback (str = name(raw) + "(" + capitalize(query("id")) + ")", used whenever query("short") isn't set) assumes this_object() always has an "id" property — true for characters, but this same function is inherited by ALL items via ITEM -> F_NAME (inherit/ item/item.lpc), including bulletin boards (inherit/misc/bboard.lpc). Any board/item without an explicit "short" property crashes every look in its room with *Bad argument 1 to capitalize() Expected: string Got: 0. Found via the very first look in the tea-house starting room (/clone/board/kedian_b has no "short" set). Fixed with a stringp(id) guard: only append the "(id)" suffix when there really is a string id; otherwise return the bare name. Verified: re-ran the full test after the fix — look in the same room no longer throws, board is now displayed cleanly as /clone/board/kedian_b [ 没有任何留言 ].

6. d/city/npc/guidao.lpc's is_killing(who) direct-call type mismatch (same shape as AGENTS.md §15b's nitan_ceshi finding): is_killing(string id) is declared in feature/attack.lpc (inherited transitively into every NPC/character); every other 20+ call site in this lib correctly calls is_killing(ob->query("id")), but guidao.lpc's ask_me(object who) called is_killing(who) directly with the raw object. Since this is a same-object DIRECT call (not ->), the static type checker enforced the declared string parameter strictly and refused to compile the whole file. Fixed to is_killing(who->query("id")), matching every sibling call site.

7. Duplicate inherit F_UNIQUE; (copy-paste typo, pre-existing, not a conversion artifact): d/mingjiao/npc/{yinwushou,yinwulu, yinwufu}.lpc each had inherit F_UNIQUE; listed TWICE. Harmless under whatever driver these were authored against, but this driver fatally rejects re-declaring the same nomask function (violate_unique) from a duplicate inherit ("Illegal to redefine 'nomask' function"). Removed the duplicate line in all 3 files.

8. The "tang"-family NPC template's new used as a bare variable name (pre-existing authoring bug, not a conversion artifact): 7 files — d/quanzhou/npc/{tang,tang1,tang2,tang3}.lpc, d/taishan/{tang2,tang3,xingtang}.lpc — all share one copy-pasted do_clone() function declaring object *inv, new; and later doing new = new("/clone/npc/..."). new is a reserved efun/keyword on this driver, so declaring/assigning a variable literally named new is a hard syntax error (unexpected L_NEW, unexpected L_ASSIGN, Illegal LHS) — the whole file failed to compile. Renamed the local variable to newob throughout (declaration + both usages) in all 7 files; the actual new(...) efun calls are untouched (they're function-call syntax, not the bare identifier).

9. AGENTS.md §15ac (bare SAVE_EXTENSION instead of __SAVE_EXTENSION__): found in include/net/ftpdsupp.h, adm/daemons/network/netmail.lpc, cmds/arch/purge.lpc, and 2 of the "tang"-family files above (d/quanzhou/npc/tang.lpc, d/quanzhou/npc/tang3.lpc, d/taishan/tang3.lpc — 3 files actually). Replaced the bare SAVE_EXTENSION with __SAVE_EXTENSION__ in all of them. Left alone: clone/npc/meng-zhu.lpc and u/jackyboy/TOKEN.lpc, which both #define SAVE_EXTENSION ".o" locally themselves — self-contained, not part of the bug.

10. kungfu/class/mingjiao/mingjiao.h's string-literal-adjacent-to- macro-expansion syntax error: ob->query("party")["party_name"] == HIG "明教" NOR (a colored-string equality check) failed to parse (unexpected L_STRING) because after macro expansion (HIGESC+"[1;32m", NORESC+"[2;37;0m") two string- literal tokens end up textually adjacent with no operator between them, which this driver's grammar doesn't auto-concatenate. Rewrote as HIG + "明教" + NOR with explicit +. Also added #include <ansi.h> to this same header, since two of its includers (d/mingjiao/npc/{litianyuan,yinyewang}.lpc, reached transitively via tangzhu.h) never include <ansi.h> themselves, so HIG/NOR were genuinely undefined identifiers in that compilation context once the syntax error above stopped masking it.

11. d/mingjiao/npc/changjinpeng.lpc's wrong absolute #include path: #include "/kungfu/class/mingjiao/tanzhu.h" — that path doesn't exist (an early-draft location; the real tanzhu.h lives at d/mingjiao/npc/tanzhu.h, right next to this file, exactly where its sibling NPC files chengchaofeng.lpc/gaoshanwang.lpc correctly reference it via a bare "tanzhu.h"). Fixed to #include "tanzhu.h".

12. d/mingjiao/npc/{fenggongying,baiguishou}.lpc's #include __DIR__"tanzhu.h" (no +, no quotes around the whole directive) failed with "Cannot read #include file" (a different, more specific driver error than the "Cannot #include" bad-path case — the path resolves/opens but reading its content fails, consistent with __DIR__'s macro-expansion inside #include's unquoted form doing something unexpected here). Rather than forensically chase the exact interaction (low value for 2 files), rewrote both to the already-proven-working plain quoted form #include "tanzhu.h", matching every other sibling NPC file in the same directory that already resolves this exact same file successfully.

13. d/baituo/ouyangfeng.lpc, two independent pre-existing typos: (a) a missing semicolon after write("...") inside a switch case 0: block, causing the parser to read the next line's break; as part of an unterminated expression (unexpected L_BREAK); (b) object me=this-player();this- player() (a subtraction of this and player()) instead of this_player() (missing underscore). Fixed both.

14. d/shaolin/obj/shuitan.lpc: ging_cost typo for the declared variable jing_cost (transposed letters) in me->receive_damage("jing", ging_cost). Fixed to jing_cost.

15. d/mingjiao/jmqshenmu.lpc was genuinely truncated in the raw archive itself (confirmed by diffing against the pre-conversion .c — both are exactly 26 lines, ending mid-void init() { with no closing braces at all — not something our pipeline introduced). Closed the truncated function with an empty body (a single }) rather than fabricating any actual init() content, purely so the file is syntactically valid instead of a permanent parse-error landmine; the room's real, complete create() content is untouched.

Confirmed NOT needed (checked by reading the actual source)

Interactive test result — full registration + post-login flow

Registration flow (all in one continuous mudclient.py session, verified 3 times across the fix-iteration cycle, final clean run shown): 英文名字(id)y (confirm new character) → real Chinese name "秦风" (accepted on the first try, no rejection loop) → password → confirm password → accept random gift stats (y) → email → gender (m) → enters the game world at 客店 (the tea-house starting room).

您的英文名字:使用 qinfengwu 这个名字将会创造一个新的人物,您确定吗(y/n)?
请输入您的高姓大名,...
您的中文名字:/clone/user/login#0        <- (author's own printf("%O\n",ob) debug leftover; harmless)
请设定您的密码:
请再输入一次您的密码,以确认您没记错:
...膂力[20], 悟性[18], 根骨[20], 身法[22]
您接受这一组天赋吗?
您的电子邮件地址:
您要扮演男性(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

Post-login commands, in the SAME connection:

Zero fatal/runtime errors anywhere in log/debug.log across this final run (only expected compile *warnings* — "Unused local variable", "Illegal to declare nosave function" — and the one known, non-fatal, pre-existing corrupted-save-data error described below).

Known non-fatal pre-existing issue (not fixed)

adm/daemons/chinesed.lpc's create() calls restore() unconditionally on its English→Chinese translation dictionary save file (data/e2c_dict.o). That file's raw bytes (confirmed identical, md5sum, between raw/ and work/ — genuinely never touched by our encoding pass, since file classifies it as data and .o is deliberately excluded from the forced-text extension list) do not decode as a valid LPC mapping (restore_object(): Illegal file format) — this looks like pre-existing corrupted seed data in the original archive itself (same class of bug as zhonghua2's stale versiond.o, AGENTS.md §15m), NOT a driver-compat or encoding-conversion bug. It's fully caught by master.lpc's own preload() catch wrapper (visible in debug.log as "错误讯息被拦截"/"error message intercepted"), entirely non-fatal, and chinesed.lpc's dict mapping simply stays at its default empty value — English/Chinese name translation lookups just return the input unchanged instead of a real translation. Does not affect registration, look, or score.

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

lpcc sweep

Ran 3 times across the fix-iteration cycle (baseline → after the combatd/command_hook/name.lpc/guidao/tang-family/mingjiao fixes → final confirmation), each a fresh lpcc --batch sweep via scripts/lpcc_check.sh:

Remaining 71 failures were triaged by category (AGENTS.md §6b) and are all one of: corrupted pre-existing save data (11, boards), genuinely missing zone/skill/race content (§13, ~20 files across mingjiao/yuan, yanziwu-zone NPCs, wizard scratch quests), the dead DNS/intermud subsystem (~16, never preloaded/never referenced), a handful of wizard personal-sandbox scratch files (u/liujun/, u/editer/, home/simul_efun.lpc), 2 harmless tail()-missing-efun hits in an unused admin command (§8e, matching established precedent), and the this_player()-is-null-during- isolated-compile sweep artifact on 5 weapon template files (§6b). None of these affect registration, look, or score — all confirmed via direct source reading, not guessed.

Memory stayed healthy throughout all 3 sweeps (well under 1 minute each, free -h never dropped meaningfully — this is a small/medium lib, nowhere near mega-lib territory).

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)

2026-07-24 深度功能测试 / Deep functional test (AGENTS.md §10.7)

One continuous native mudclient.py session (plus a second fluffos admin session used specifically to reach death/combat, since the main character never accumulated the money or combat skill to risk real kill safely in the time budget). §8.3a's private nomask command_hook fix was already applied in this lib (feature/ command.lpc:29 reads nomask int command_hook(string arg), no private — confirmed by direct read before touching anything else) — not re-diagnosed.

Test character: id shenshaofeng, password xia2026wu, Chinese name 沈少峰 (male). Left in a clean, alive, fully-saved state at /d/city/zuixianlou (醉仙楼), title 叫化子/丐帮第二十代弟子 (member of the Beggars' Sect, 20th generation, master 左全/Zuo Quan), begging skill improved once via the organic teacher path, 潜能 98/99. Save files left in place per the task instructions (work/data/user/s/ shenshaofeng.o, work/data/login/s/shenshaofeng.o) as evidence. Admin account fluffos/Mud@2026 (pre-existing, from the WASM- enablement pass) reused for the death/reincarnation leg; left alive, saved, at /d/city/wumiao (its own now-legitimate chosen home, set via an explicit quit there — see bug #2 below for why that's legitimate and the room's own automatic version isn't).

What was verified working, live

Not verified live (honest gaps)

Bugs found and fixed

1. adm/daemons/chinesed.lpc — corrupted save data leaves a global mapping as raw 0, crashing the FIRST real use of cha/chinese() (AGENTS.md §7.7, third bullet: "restore_object() ... ZEROES ... a crash surfaces far away")

This lib's own NOTES.md already documented chinesed's data/e2c_dict.o as pre-existing corrupted seed data whose restore() fails at boot, and called it "fully non-fatal" because the failure is caught by master.lpc's preload() wrapper. That part is true for *boot* — but nothing downstream was actually safe: create() was

void create() {
  seteuid(getuid());
  restore();
}

restore()restore_object() throws a real runtime error on the malformed file; since that error is never caught INSIDE chinesed.lpc itself, it aborts create() immediately at the restore() line — the global mapping dict = ([]); initializer had already run at object creation, but restore_object()'s failure zeroes it back out per §7.7's exact mechanism, and because create() never reaches any statement after the throwing call, no local recovery code could run either. The very first real player use of any command that calls chinese() (confirmed live via cha zuo, but to_chinese() used throughout combat/skill messages could hit the same path) crashed with *Value being indexed is zero. at chinesed.lpc:94.

Fix — wrap the throwing call in catch() (so create() can actually continue past it) AND add the standard §7.7 post-restore guard:

// BEFORE:
void create() {
  seteuid(getuid());
  restore();
}
// AFTER:
void create() {
  seteuid(getuid());
  catch(restore());
  if (!mapp(dict)) dict = ([]);
}

A mapp() guard alone (tried first) was NOT sufficient — confirmed live that it still crashed identically, because the guard line is never reached without the catch() (the runtime error unwinds straight past it to the nearest existing catch, in master.lpc's preload()). Verified: rebooted, repeated the exact bai zuocha zuo sequence — full skill list printed, zero runtime error, zero new debug.log lines.

2. (RETRACTED — content/design judgment call, not a programming bug; reverted on user review) d/death/gate.lpc and d/city/wumiao.lpc's init() unconditionally wrote the player's permanent startroom on mere room entry. Originally flagged as an AGENTS.md §7.24 match and fixed by deleting both init() bodies — since reverted. The key fact that distinguishes this from the earlier zzfy §7.24 case: both rooms already flag themselves valid_startroom via their own create() — unlike zzfy's revive-limbo rooms, which did NOT carry that flag and so directly contradicted the lib's own gating convention. Here, writing startroom on entry doesn't violate this lib's own architecture at all; it's plausibly a deliberate "these are checkpoint locations, entering one silently updates your home" design (the death gate and a city temple both read as thematically plausible checkpoint spots), even though it bypasses the normal player-initiated save/quit-while-standing-here convention and gives no on-screen confirmation. That's surprising UX, not a proven programming defect. Left as originally shipped (both init()s restored), documented here rather than silently re-fixed. d/city/cangku.lpc/d/shaolin/cangku.lpc and the d/shaolin/ jail-cluster rooms (also touch startroom on capture/release) were separately confirmed to have genuine, matched restore paths and were correctly never touched.

3. Missing /log/nosave/ runtime directory crashes combatd.lpc's killer_reward() on EVERY death, kill.lpc's PK-attempt logger on every player-vs-player kill, and bai.lpc/apprentice.lpc's Feng-Qingyang student counter (AGENTS.md §7.11, exact match — same example directory the catalog entry already names)

work/log/nosave/ does not exist in this archive. Four call sites write into it with a bare write_file()/no assure_file()/no catch():

This is not a one-time cosmetic error — it's a live, reproduced, severe softlock. Confirmed by actually killing the fluffos admin character in real combat (a 黑无常 NPC): killer_reward()'s write_file() threw *Wrong permissions for opening file /log/nosave/KILLRECORD for append. "No such file or directory", UNCAUGHT, which aborts die() at exactly that call — every statement AFTER it (corpse creation, remove_all_killer(), moving the player to DEATH_ROOM, setting the ghost flag) never ran. The character was left standing in the combat room with 0 qi/jing, still "alive" by the engine's bookkeeping, and the SAME crash then re-fired on every single subsequent heart_beat() tick — an infinite crash loop, confirmed live by watching it repeat identically 3+ times across one score check before the fix.

Fix — the mudlib already has its own idiom for exactly this (assure_file(), adm/simul_efun/file.lpc:11, already used by feature/save.lpc) — used it at all four write sites instead of introducing an out-of-band mkdir:

// combatd.lpc, kill.lpc, bai.lpc, apprentice.lpc — pattern applied at
// each write_file("/log/nosave/...", ...) call:
assure_file("/log/nosave/KILLRECORD");   // (or ATTEMP_KILL / FENG)
write_file("/log/nosave/KILLRECORD", ...);

Also added a stringp() guard on the FENG counter's read_file() result in both bai.lpc/apprentice.lpc (same file, same class of risk as AGENTS.md §7.9 — read_file() on a not-yet-created file returns 0, which would otherwise flow into atoi(0)). Verified live: rebooted, repeated the exact same admin-vs-gargoyle fight to death — this time die() ran to completion cleanly (single 你死了, ghost title, corpse present, no repeated crash spam), and work/log/debug.log stayed at its pre-fight line count throughout.

4. cmds/skill/bai.lpc / cmds/skill/apprentice.lpc (identical duplicate files) — misplaced parenthesis passes the WRONG ARGUMENT TYPE to query(), so the Feng-Qingyang defection-counter check never actually ran

// BEFORE (both files, same line):
if (((string)me->query("family/master_id" == "feng qingyang")) || ((string)me->query("family/master_name" == "风清扬"))) {

The == comparison is INSIDE the query(...) call's argument list, so query() is actually invoked with a boolean/int (0, always false for any real property name) instead of the intended string key — query("family/master_id" == "feng qingyang") evaluates the comparison first and passes its result, not the string, meaning the branch could never fire regardless of the player's actual master. Fixed to compare the RETURN VALUE of query() against the string, as every other call site in the file already does correctly:

// AFTER:
if (((string)me->query("family/master_id") == "feng qingyang") || ((string)me->query("family/master_name") == "风清扬")) {

Low real-world impact (only reachable for a player defecting FROM the specific named master 风清扬/Feng Qingyang, a rare special case) but a genuine, unambiguous programming bug — not a design question — since the code's own structure makes its intent (compare a queried value to a literal) unambiguous. Not separately live-exercised (would need a character to actually be Feng Qingyang's disciple first, out of scope for this pass) but confirmed by direct read that it now matches every other correctly-written call site in the same file.

Bug-class mapping (all four matched EXISTING AGENTS.md entries — no new class)

Process notes

Driver run from libs/jqxz2008/ via nohup ... & disown, restarted 4 times across the fix-iteration cycle (chinesed fix alone → +bai.lpc paren fix → +gate.lpc/wumiao.lpc/§7.11 fixes → final confirmation), each old PID killed only after confirming readlink -f /proc/<pid>/cwd matched this lib's work/ directory (other agents' driver processes for xiakexing2017, xlqy_new2007, xo, shujian2008, xkxz2, zhonghua2 were running concurrently throughout and were never touched). RSS stayed at 30-44MB across the whole ~10-minute final session, no unbounded growth (§10.8 checked, nothing concerning). Final driver (PID 1718534) killed by exact PID after all testing completed, confirmed via ps/ss no longer showing port 40082.

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

adm/daemons/logind.lpcenter_world() 里:

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

age 是角色本身(user)的属性,不是登录物件(ob)的属性—— ob->query("age") 永远是 0,这个分支从来没有真正执行过,每个新 角色的食物/饮水从创建起就永远是空的,静默、无报错。这轮上面记录的 深度测试用的是 shenshaofeng/沈少峰这个角色,一路走到拜入丐帮、学 begging——没有专门核对过食物/饮水初始状态是否为满,所以当时漏掉 了这个 bug。已改成 user->query("age") == 14,用真实驱动重新注册 验证过(沈叁),score 正确显示食物/饮水两条状态全满。这个 bug 在 同引擎的"标准版"(jqxz2008std)先发现,确认三个版本档案里 logind.lpc 这一行逐字节相同,一并同步修复。

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

金庸群侠传引擎基础版(2008 加强版)。

§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@2026adm/etc/wizlist 已有 fluffos (admin))也 已经用真实注册流程创建并提交过,本轮只发现并修复了 log_file() 一处。

发现并修复的 PROGRAMMING bug

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

更正(2026-08-13):e2c_dict.o 已删除

上面记录的"未修复"已过时。用户指示清理这类噪音后,重新确认 chinesed.lpccreate()catch(restore()); if (!mapp(dict)) dict = ([]);——即使 restore() 失败,dict 也会正确回退成空映 射,删除这个永远无法被正确解析的损坏文件不会改变任何行为(有它在 的时候和没有它的时候,chinesed 的实际运行状态完全一样,区别只是 每次开机是否会在驱动 stdout 上多打印一条被 CATCH() 吞掉的错误 噪音)。已删除 data/e2c_dict.o,重新走一遍完整注册/登录流程复 测,chinesed 干净加载、无任何报错,功能无回归。

Proactive checks(无需改动)

实测过程

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

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

#define ROOM "/inherit/room/room":删除 824 处多余的、独立成行的 replace_program(ROOM);(保留 inherit ROOM;),与手足档案 jqxz2008dlx/jqxz2008std 同一血统同一形状。clone/misc/ roommaker.lpc 同样有两套模板——"造一间空房间"的 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.

深度功能测试 round four(2026-08-20/21):shop-purchase 缺口关闭 + 标准清单复核

Closed this lib's own explicitly-flagged §10.7 gap ("Not verified live (honest gaps)": a completed, successful shop purchase). Booted build-debug/src/driver clean on port 40082 (PID 976088, killed by exact PID when done, verified gone via ps/ss). Used a raw Python socket script (two concurrent connections, each response read/printed and validated before the next command was sent).

Test character: fresh id qintestg, Chinese name 秦八 (password redacted, not recorded in plaintext), registered end-to-end through the normal wizard, landing at 客店 with title 平民/普通百姓 — deliberately NOT a member of 丐帮 (confirmed via score: 【 平 民 】, not the 【 叫化子 】 beggar title), so the existing beggar-forbidden-from-buying design gate does not apply to this character. Save files (work/data/user/q/qintestg.o, work/data/login/q/qintestg.o) left in place as evidence, matching this file's own established precedent for this test class.

Funding (sanctioned admin clone+give pattern): logged in separately as the pre-existing fluffos/(admin) account (already committed from an earlier pass), goto'd to the same room as qintestg (/d/city/zuixianlou2, the tea-house-district shop's upper floor), clone /clone/money/coin (this lib's actual copper-coin money object, /clone/money/coin.lpc, id coin/coin_money), call coin->set_amount(500) to bump it from its clone-default of 1 up to 500, then give qintestg coinqintestg received "五百文铜板" (500 coins) live, confirmed via i.

The purchase itself: qintestg walked to 醉仙楼二楼 (kedian → w → n → e → up), where the 冼老板/Xian laoban F_DEALER NPC (d/city/npc/xian.lpc) sells kaoya (烤鸭/roast duck, value 150) via its vendor_goods list. buy kaoya succeeded on the first try: "你从冼老板那里买下了一只烤鸭。" Post-purchase i showed the received 烤鸭(Kaoya) item AND the correct change, auto-converted to higher denominations by moneyd.lpc's player_pay(): 三两白银(Silver) (300) + 五十文铜板(Coin) (50) = 350 = 500 − 150. Price deduction and item receipt both verified correct, live, not just by code review. Verdict: this gap is now CLOSED — no bug found, buy's code path (money check, move(), call_out("enough_rest", 1)) works exactly as the prior code-review pass predicted. Zero new lines in debug.log across the whole session (confirmed by line-count before/after).

Fast standard-checklist confirmation pass (per NOTES.md task brief — confirm, don't re-derive)

All of the following were already fixed/clean per this lib's own prior NOTES.md entries; this pass re-confirmed each by direct source read (and, where a fresh boot was already running, live behavior) rather than re-deriving from scratch:

Death/respawn live-verification status (per task's optional follow-up)

Not a new gap: this lib's own 2026-07-24 §10.7 pass already verified a REAL combat death + corpse + ghost + reincarnation cycle live end-to-end (the fluffos admin character vs. a 黑无常/bgargoyle.lpc NPC at /d/death/gateway), documented above — no further action needed here.

Process notes

Driver run from libs/jqxz2008/ via nohup ... & disown, single boot for this whole pass (PID 976088), killed by exact PID after confirming readlink -f /proc/976088/cwd matched this lib's work/ directory (no other libs' drivers were running concurrently this time). fluffos's save picked up minor real-gameplay-state churn from this session (food/ water values, startroom updated to /d/city/wumiao by that room's own documented — see bug #2 above — checkpoint-on-entry design, since the admin character was deliberately routed back there before quit to match its previously-documented resting spot) — left as-is, not reverted, since it reflects genuine state from real commands run, not timestamp-only churn.