Xia Ke Xing — 2017 Complete Edition (Ode to Gallantry)

✅ 可玩

侠客行 (MUD侠客行2017完整版)

xiakexing2017

🔑 fluffos / Mud@2026 更新 34c14f9 2026-09-04 源码 下载 ZIP

▶ 开始游玩 · Play Now

取材自金庸小说《侠客行》,压缩包标注为"2017完整版";与本项目中同名"侠客行"游戏 xiakexing100 代码库彼此独立(内容匹配度仅约 2%-4%),但经过逐档比对,它其实与本项目另一款"侠客行三"xiakexing3、以及以"金庸群侠传"为名的 jqxz2008 系列是关系密切的近亲——共有路径下约 80%-84% 的文件逐字节相同,是同一套 adm/single/master.lpc 服务端核心与同一个基础游戏世界(茶馆/客栈起步、丐帮枯树洞收徒、明教弟子按"缘"字辈份编号取名等)在不同站点换皮后产生的多个内容快照,而非各自独立开发的游戏。

English

Based on Jin Yong's novel Ode to Gallantry (Xia Ke Xing) in its own login banner, this archive is labeled the "2017 Complete Edition." Despite the shared name, its codebase is genuinely independent of this collection's xiakexing100 (only ~2-4% of files match by content). It is, however, a much closer relative of xiakexing3 and of this collection's jqxz2008/jqxz2008dlx/jqxz2008std/jqxz2015 "Legend of Jin Yong's Heroes" (Jin Yong Qunxiazhuan) family than either side's own description previously acknowledged: a direct file comparison found roughly 80-84% of the files it shares a path with are byte-identical to both xiakexing3 and to jqxz2008 — one server program and one base game world (adm/single/master.lpc core, tea-house/inn start, Beggars'-Sect-via-hollow-tree recruitment, Mingjiao's numeric-curse-named NPCs) produced across several separately-branded content builds, not independent games. New characters start at an inn, can apprentice into named sect teachers (e.g. the Beggars' Sect's 余洪兴/Yu Hongxing), and the game clock displays "Xia Ke Xing time," real Beijing time, and the lunar calendar side by side.

README

内容亮点

在线试玩

https://mudlibs.fluffos.info/xiakexing2017/

管理员账号 / Admin account

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

本地运行

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

游戏端口:40017

NOTES · 移植与修复记录

MUD侠客行2017完整版.zip → xiakexing2017

Status: DONE — boots clean, playable over telnet

Zero fixes needed — clean boot and full login flow on the first attempt.

What was fixed

Nothing needed for boot. Routine conversion: encoding (3330 converted, 521 already UTF-8/ASCII, 59 skipped binary, 15 lossy), .c.lpc (3266 files, 146 refs auto-fixed), 8 local angle-bracket includes converted to quotes automatically, staticnosave (42 files).

Known remaining issues

How to run

cd libs/xiakexing2017
~/src/fluffos/build-debug/src/driver config.fluffos
python3 ../../scripts/mudclient.py 127.0.0.1 40017 --timeout 10 --send "" --send "look" --send "quit"

Post-hoc fix: UTF8-native is_chinese/registration (AGENTS.md §15h)

Applied in a later batch pass across the whole project: is_chinese/is_chinese2 in the shared chinese.lpc simul_efun fragment used GBK byte-range checks that silently never match real Chinese text once strings are UTF-8 (this driver's str[i] returns a Unicode codepoint, not a GBK byte). This broke character registration specifically -- any real Chinese name was rejected. Fixed the range check to test the CJK Unicode block instead, and halved the GBK-byte-calibrated length bounds in check_legal_name to match. See AGENTS.md §15h for the full writeup; confirmed via a real interactive registration test (Chinese surname + given name reaching the next prompt).

Re-verification pass (driver rebuild + LPC formatter + WASM build)

WASM-enablement pass (loopback-allow / admin seeding)

This lib's adm/daemons/band.lpc/logind.lpc are byte-identical (per §2.1 lineage check) to the xiakexing3/jqxz2008 engine files, whose WASM pass was already done and verified with the correct fail-closed convention — ported that fix here and re-verified independently rather than assuming it.

Admin account: fluffos / Mud@2026 / 浮浮, registered through the real flow (id → y → 浮浮 → password ×2 → talent accept y → email → m). Granted (admin) by appending fluffos (admin) to adm/etc/wizlist (shipped with rwz (admin) already present, no trailing newline — added one; securityd.lpc reads this file at create(), so a driver restart was needed to pick up the new line). Verified after restart: 目前权限:(admin), title 【天神】, update /adm/daemons/band重新编译 /adm/daemons/band.lpc:成功!.

Save files for the orchestrator to force-add (untracked, not gitignored):

Two pre-existing caught (non-fatal) restore_object(): Illegal file format errors were observed in debug.log during this pass — /adm/daemons/chinesed's save data at boot preload, and /clone/board/kedian_b's board save data at enter_world() (matches the raw-path /clone/board/kedian_b display already visible in the game, instead of a proper board name — its corrupted save data is why). Both are wrapped in catch() by master.lpc's preload()/ logind.lpc's own catch respectively, non-fatal, and confirmed via git log/git status to be genuinely corrupted data already committed as part of the original archive conversion (archive #20, "booted clean with zero fixes") — not introduced by this session. Left as-is per the project's established emoted.o/similar precedent; not a new regression.

Retest: fresh boot, fresh registration (id qretest, real Chinese name 秦风十一) through look/score/quit — landed in 客店, correct output, clean quit. fluffos/Mud@2026 admin login verified via score (confirms (admin)/天神) and update. debug.log had exactly the two pre-existing corrupted-save errors above and zero NEW runtime errors. Test character qretest removed afterward; fluffos kept.

深度功能测试 / Deep functional test (2026-07-24, round two)

First real *playthrough* pass on this lib (all prior passes verified only registration + look/score/quit, or watched boot output). Read doc/help/newbie and doc/help/intro in full first — this is the "东方故事2" (ES II) -derived 金庸-themed game: newbie names the fight (safe, to-half-health sparring) vs kill (real) distinction up front, the bai/xue teacher-apprentice loop, the 扬州 (Yangzhou) starting-city layout with turn-by-turn routes to every sect, and dozens of shortcuts. Played one continuous native-driver (build-debug) session as an ordinary new player: registration with a real Chinese name, exploring Yangzhou (客店→北大街→中央广场→东大街→东门, then the deterministic ml1ml7 "青竹林" maze into d/city/pomiao and the 丐帮 hideout gbandao), the organic bai/apprentice sect-join path against four different 丐帮 teacher NPCs (all correctly rejected per their own, met-or-not stat/alignment gates — not a bug, see below), the fight safe-sparring command against a 流氓 (real multi-round combat output, no crash), a list/buy shop-purchase attempt (correctly rejected for insufficient funds), a real clean quit→relogin round trip (state preserved), a real prompt net-dead reconnect (uncleanly closing the socket, reconnecting ~25s later — resumed in the exact same room, confirming this lib's net_dead() never void-parks the player at all, see "§7.20 checked" below), and — critically — a real full- duration (600s = NET_DEAD_TIMEOUT) unclean-disconnect wait, which crashed the native driver process outright. Found and fixed four separate bugs: one already-cataloged class (§7.12, promoted to CRITICAL severity by this pass — the driver crash above), one recurrence of an existing class applied at a more general choke point (§7.25- shaped), and one genuinely new class (drafted below) that hit in three independent files.

Primary test character (kept, state left as evidence): id qinfengxia, Chinese name 沈秋白 (male), password Xia@2026. Rolled stats 膂力19/悟性26/根骨21/身法14 (all four teacher-rejection messages below are a direct, verifiable consequence of this exact roll, not a bug). State: explored Yangzhou + the 丐帮 hideout, sparred a 流氓 via fight (both survived, health text on both sides — matches the "点到 为止" safe-sparring description in help combat/help intro), no sect/skill acquired live (see honesty note below), survived a clean quit→relogin, a prompt net-dead reconnect, and — after the fix below — a real full-duration net-dead force-quit + fresh-login verification. Currently sitting at 客店 (start room) after a final clean quit. Saves: work/data/user/q/qinfengxia.o, work/data/login/q/qinfengxia.o.

Secondary throwaway character: id goumaice, Chinese name 顾买测 (female), password Gm@2026. Used to exercise the shop list/buy flow (correctly rejected, no money) and — deliberately left net-dead at the same real moment as qinfengxia — as the second of the two simultaneously-net-dead characters needed to reproduce the §7.12 driver crash (see Bug 1). Saves: work/data/user/g/goumaice.o, work/data/login/g/goumaice.o.

§7.20 (void-parking) explicitly checked and does NOT apply to this lib: read clone/user/user.lpc's net_dead()/reconnect() in full — this lineage never moves a disconnected player to a VOID_OB/holding room at all; the player object simply stays in its current room with a netdead temp flag while call_out("user_dump", NET_DEAD_TIMEOUT, DUMP_NET_DEAD) waits, and reconnect() (confirmed actually invoked, adm/daemons/logind.lpc:481) just clears the flag in place. No location to lose, no restore path needed. Confirmed live with both a prompt (~25s) and a full 600s-plus net-dead reconnect: character stayed in the same room both times.

Bug 1 (CRITICAL — already-cataloged class, AGENTS.md §7.12, severity re-confirmed): the shared tell_room() simul_efun wrapper forwards an unset exclude varargs as a raw int 0, crashing message() — reached from the NET_DEAD_TIMEOUT force-quit path, and reproduced as an actual native driver process crash

File:line: adm/simul_efun/message.lpc:36-38.

This is the identical bug AGENTS.md §7.12 already documents (first found on yueyingqiyuan, severity-escalated on dtsl's own §10.7 pass) — citing the existing class, not redrafting it. Filed here because this lib turns out to carry a byte-identical copy of the vulnerable adm/simul_efun/message.lpc (not currently listed as a sibling of dtsl/yueyingqiyuan in AGENTS.md §11's lineage map — worth a lineage note) and because this pass independently reproduced §7.12's full "severity escalation" scenario live, including the driver crash, on a *third* lib:

`` md: debugmalloc: attempted to free non-malloc'd pointer ... #3 MDfree ... #4 debugfree ... #5 dealloc_object ... #6 int_free_svalue #7 assign_svalue ... #8 assign_value_to_lvalue ... #9 eval_instruction (F_ASSIGN) ... #12 f__call_other ... #17 call_function_interactive (processing the reconnect command) ... Aborted (Signal sent by tkill()) ` Confirmed via ps/ss that the driver was genuinely gone (not just the connection dropping) and via the stdout backtrace, not inferred. The exact C-level mechanism (a destructed-object reference whose refcount reached 0 without a proper free_object`) wasn't rigorously proven with ASan/valgrind (out of scope), matching AGENTS.md §7.12's own caveat, but the correlation is strong: the crash did not recur after the fix, reproducing an equivalent two-character scenario.

``lpc // BEFORE: varargs void tell_room(mixed ob, string str, object *exclude) { if (ob) message("tell_room", str, ob, exclude); } // AFTER: varargs void tell_room(mixed ob, string str, object *exclude) { if (ob) message("tell_room", str, ob, exclude || ({})); } ``

Lineage note for AGENTS.md §11: xiakexing2017's adm/simul_efun/message.lpc carries this exact vulnerable tell_room() shape, matching dtsl's. Currently listed as "Standalone/distinct" in §11 — worth flagging as sharing at least this one shared-infrastructure file with the broader ES II family (§11's "ES II / 东方故事 mega-family" already carries the §7.12 warning), even though this project's own newbie/intro docs describe it as "东方故事2" (ES II) -derived already, so this is consistent, not a surprise.

Bug 2 (new bug class, draft below): mapping-typed properties/accessors default to a raw int 0 when never set, and several call sites index into them without checking — "value being indexed is zero" / "bad argument 1 to keys()"

Two independent instances, one in shared engine code (reachable from nearly every room in the game) and one in specific zone content — same underlying shape, draft text below covers both.

Instance A — feature/skill.lpc's query_skills()/query_learned()/ query_skill_map()/query_skill_prepare() (lines 13-14, 103-109): each is declared mapping query_X() { return X; } where the module variable X (skills/learned/skill_map/skill_prepare) is declared mapping X; but never initialized — LPC's default value for an unset mapping global is int 0, not ([]). Every setter in the same file (set_skill(), map_skill(), etc.) correctly guards with if (!mapp(skills)) skills = (...), but the four query accessors return the raw variable unconditionally. Reached live: d/npc/xiaofeng.lpc's check_skills() (fired via a 2-second call_out from init(), i.e. on ordinary room entry) does skl = ob->query_skills(); sname = sort_array(keys(skl), ...) — for our fresh test character (0 skills learned, completely ordinary, expected state for a brand-new player), query_skills() returned raw 0, and keys(0) crashed:

执行时段错误:*Bad argument 1 to keys()
Expected: mapping Got: 0.
程式:/d/npc/xiaofeng.lpc 第 99 行

84 call sites across 42 files call ->query_skills()/->query_learned() — most already defensively re-guard with their own if (!mapp(...)) before use (e.g. cmds/std/check.lpc, cmds/skill/skills.lpc, which is exactly why this didn't surface everywhere), but at least this one did not.

Instance B — a mapping-typed per-object query() property indexed directly, same shape, different mechanism: query("party") (an object's faction-membership record, unset for anyone not in that faction) and query("family") (sect-membership record, unset for anyone sect-less) both legitimately return 0 for the common case of "hasn't joined". Three files indexed one of these directly with no guard: d/mingjiao/npc/mingjiao.h:6 and its byte-identical duplicate kungfu/class/mingjiao/mingjiao.h:6 (ob->query("party")["party_name"] in a shared greeting() used by ~20+ 明教 NPC files, fired via a 1- second post-init() call_out — i.e. crashes for any non-明教 player standing near ANY of them, confirmed live for d/mingjiao/npc/ changyuchun.lpc's 常遇春, who sits in the starting city's central square that every fresh login passes through), and d/xiaoyao/obj/ bojuan.lpc:43 (me->query("family")["family_name"], a readable skill scroll — crashes for any non-逍遥派 player who tries read/study/du on it, which is the obvious, intended first thing to try). All three crash with the same signature:

执行时段错误:*Value being indexed is zero.

This shape is NOT universal in this lib — most other query("family")[/ query("party")[ call sites (checked: kungfu/class/mingjiao/ zhangwuji.lpc, d/xiaoyao/xiaodao1.lpc, shishi4.lpc, npc/qingyun.lpc, npc/xuemuh.lpc, fangjian2.lpc) already correctly guard with `!ob-

query("family") ||/ob->query("party") &&` — confirming this is an

easy-to-miss oversight recurring independently, not evidence the whole convention is broken, and that the correct local idiom was already established and just not applied consistently.

Detection: grep ->query_skills(\|->query_learned(\|->query_skill_map( \|->query_skill_prepare( (or a lib's own equivalent mapping-returning accessor) for definitions that return <bare variable>; without a mapp() guard, matching the setter functions' own established discipline in the same file. Separately grep ->query("<mapping-shaped- property>")\[ (family/party/couple/skill-map-shaped properties) for direct indexing with no adjacent mapp()/truthiness check — cross-check against sibling call sites in the SAME file/directory first, since (as here) the correct guarded idiom is very often already established nearby and the unguarded instance is the outlier, not the norm.

Fix: at the accessor/property level, not every call site — same "shared choke point" principle as §7.25/§7.26. For an engine accessor like Instance A: mapping query_skills() { return mapp(skills) ? skills : ([]); } (applied to all four accessors in feature/skill.lpc). For a one-off unguarded index like Instance B: capture the property into a local first and guard it (party = ob->query("party"); if (mapp(party) && party["party_name"] == ...)), matching the idiom already used correctly elsewhere in the same codebase.

Verified: restarted the driver after each fix; re-walked qinfengxia past 萧峰/xiaofeng (北大街) and 常遇春/changyuchun (中央 广场) — both previously-crashing check_skills()/greeting() calls fired cleanly with zero debug.log errors afterward, confirmed across two independent fresh-boot sessions. bojuan.lpc's fix was verified by code-inspection parity with the other five already-correct sibling call sites in the same directory (not re-walked live to the 逍遥派 zone specifically — a multi-minute maze/gate trek for a one-line, pattern- identical fix already proven safe by the two live-verified sibling instances; noted honestly rather than silently claimed as live-tested).

Bug 3 (recurrence of AGENTS.md §7.25, fixed at a more general choke point): cmds/std/go.lpc's destination-room force-load silently swallows the player's move command on that room's first-ever visit when the room's own tail-of-create() companion-object load throws

File:line: cmds/std/go.lpc:70-73 (plus two smaller sibling instances at d/wizard/guest_room.lpc:24 and d/wizard/wizard_room.lpc: 21, same shape, fixed the same way).

Matches AGENTS.md §7.25's "closely related shape" almost exactly ("rooms that force-load a companion object ... via call_other('<path>', '???') in their own create()") — citing the existing class. The difference from a textbook §7.25 instance: the vulnerable call_other(dest, "???") isn't inside each room's own create(), it's in the single SHARED movement command (go.lpc) that force-compiles *any* destination room on its first-ever visit — so this fix was applied at that one shared choke point instead of repeating catch() across this lib's 17 separate rooms that end their own create() with an identical "/clone/board/xxx_b"->foo(); companion-board force-load (confirmed all 17 have the load as the LAST statement of create(), i.e. after exits/objects/setup() are already set — spot-checked 5 of the 17 directly, matching the one instance actually reproduced live).

``lpc // BEFORE: if (!(obj = find_object(dest))) call_other(dest, "???"); // AFTER: if (!(obj = find_object(dest))) catch(call_other(dest, "???")); ` Safe specifically because every instance checked (17/17 by grep, 5/17 spot-checked directly) puts the risky companion-object load as the LAST statement of the destination room's create() — so even when the catch() swallows a throw, the room object is already fully populated (exits/objects/setup() all ran) by the time go.lpc's retry find_object(dest) check runs immediately after, and the move proceeds normally into a correctly-initialized room. Also applied the same catch() to the two structurally-identical but currently- unexercised direct call_other(".../board", "???") force-loads in d/wizard/guest_room.lpc and d/wizard/wizard_room.lpc (their own create(), not reached via go.lpc` — the same §7.25 shape, proactive fix by code-shape match, not yet live-triggered since their board data isn't known to be corrupted).

Honesty notes — not verified live, explicitly

Files modified this pass

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

深度功能测试第三轮 / Deep functional test round three (2026-08-14)

Independently re-verified every §10.7 checklist item against current code rather than trusting the round-two writeup above; found and fixed one new bug (update.lpc), plus a 100%-reproducible recurrence of the already-cataloged AGENTS.md §7.90 eval-cost class.

New fix: cmds/wiz/update.lpcpresent(file, environment(me)) crashes when the caller has no environment

File:line: cmds/wiz/update.lpc:20.

main()'s first check calls present(file, environment(me)) unconditionally. When environment(me) is 0 — reachable any time update is typed by an object that isn't currently placed in a room — this throws *Bad argument 2 to present() Expected: object Got: 0., aborting the whole command with no useful message.

``lpc // BEFORE: if ((obj = present(file, environment(me))) && interactive(obj)) // AFTER: if (environment(me) && (obj = present(file, environment(me))) && interactive(obj)) ``

Fix: cold-start eval-cost exhaustion during make_body() — recurrence of AGENTS.md §7.90 ("xyj2000f" variant), 100% reproducible, not intermittent

Initially misdiagnosed this as a debug-build-speed test artifact to note and leave alone. Checking AGENTS.md before drafting a new entry caught the mistake: §7.90 already documents this exact class, including a variant ("harsher variant on xyj2000f") that matches this lib symptom-for-symptom — eval-cost abort inside make_body() itself, 100% reproducible on every attempt (not the more common "only some never-visited rooms" flavor), no player-facing error, and §7.90's own prescribed and verified fix is to raise the committed maximum evaluation cost, not leave it alone. Applying that established fix here instead of inventing a new rationalization.

It reproduced on every single fresh-boot first login attempt, every time, across multiple independent boots, and did not cleanly self-heal the way this session's other libs' cold-start eval-cost hits did: the character that "succeeds" after the aborted make_body() lands in a session where every command (look, who, update) returns the generic "什么?" fallback — command dispatch never finished wiring up. Reconnecting doesn't help; the very next login attempt hits the identical abort, every time.

Re-verified still holding (code-inspection, not full live re-repro — see rationale)

All three round-two fixes remain present and unmodified in the current code (adm/simul_efun/message.lpc's exclude || ({}), feature/skill.lpc's four mapp()-guarded accessors plus the mingjiao.h/bojuan.lpc guards, and cmds/std/go.lpc's catch(call_other(dest, "???")) plus its two guest_room.lpc/wizard_room.lpc siblings) — confirmed by direct grep against each fix's exact diff, not merely assumed. Bug 2 Instance A was additionally re-verified live: walked to 北大街 where 萧峰/xiaofeng sits, waited past his check_skills() call_out, debug.log showed zero errors afterward (previously crashed with "Bad argument 1 to keys()" pre-fix). Bug 1's full NET_DEAD_TIMEOUT reproduction and Bug 3's maze route were not re-walked live this pass — both require multi-minute real-time or multi-step scripted routes already thoroughly live-verified twice in the round-two writeup above, and this pass's time budget went to the new update.lpc bug investigation instead; noted honestly rather than silently re-claimed as freshly live-tested.

Verification method

Two rapid consecutive reconnects as fluffos (both clean, both showing "目前权限:(admin)"), update /adm/daemons/logind used as the real privileged-action admin-rights check (not the login banner), driver killed by exact PID after testing, incidental fluffos.o save-timestamp churn reverted before commit.

Files modified this pass

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

#define ROOM "/inherit/room/room":删除 818 处多余的、独立成行的 replace_program(ROOM);(保留 inherit ROOM;),与 xkx2017/ jqxz2008 系列同一血统同一形状(本档案不是逐字节相同的手足档案, 独立验证)。clone/misc/roommaker.lpc 同样有两套模板——"造一间空 房间"的 heredoc 本来干净,"克隆我所在的房间"命令的字符串拼接模板 把同一枚多余的 replace_program(ROOM); 烤进了每一个新克隆的房间, 已同步修正。已用 build-debug 驱动干净启动验证(0 个新增编译错 误,端口正常监听);未做完整 §10.7 深度游玩测试。

``§7.112`` residual-gap closure (2026-08-20)

Corpus re-scan (grep -rl 'call_out("death_stage"' ... | filter for missing guard) found unguarded init()-scheduled death_stage() call_out chain(s) in d/death/npc/newgargoyle.lpc that the original two-wave sweep (see AGENTS.md §7.112) missed -- same reconnect-triggered duplicate-chain bug, different filename/lineage. Added the standard query_temp("death_stage_active")/set_temp/delete_temp re-entry guard, adapted per file's own exit points. Compile-verified via lpcc --batch.

深度功能测试第四轮 / Deep functional test round four (2026-08-20)

Resolved this lib's two remaining round-two/round-three "honesty notes — not verified live" gaps (sect apprenticeship completion and death/respawn) explicitly. Found and fixed one new, genuinely crash-causing bug in the process; the standard checklist re-confirm otherwise came back 100% clean (all prior fixes still present, matching the current code).

Item 1 — sect membership / xue skill learning: COMPLETED LIVE. New bug found and fixed: adm/daemons/chinesed.lpc's bare restore() (no local catch()) let a pre-existing corrupted save silently abort create() before its own mapping dict variable could ever be (re-)guarded, crashing every real xue/skills command

File:line: adm/daemons/chinesed.lpc:25-28 (pre-fix).

Re-examined the four 丐帮 teachers previously confirmed reachable without prior sect membership (鲁有脚/彭有敬 at d/city/pomiao, 简长老 at d/city/gbandao, 苏国盛 — actually 洪七公's man hong — at d/city/gbxiaowu/d/city/mishi, though the latter two turn out to be gated behind d/city/gbandao's own valid_leave() for non-members, so not actually reachable pre-membership either) and confirmed none of the pomiao/gbandao-reachable teachers can currently accept qinfengxia's actual roll (int 26): kungfu/class/gaibang/lu.lpc rejects if int>=25 (inverted from what a skim of the file names suggests — Lu wants *low*-int students), peng.lpc and jian.lpc are unconditional non-recruiters. This matches the round-two writeup's own conclusion, not a contradiction of it.

Read the full kungfu/class/gaibang/*.lpc roster instead of stopping at the four already-tried teachers: yu-hx.lpc (余洪兴, 丐帮八袋弟子) accepts if int>=25 — the *actual* NPC the original task brief's "int>=25 threshold" was describing, not lu.lpc. qinfengxia's existing int 26 already satisfies it — no stat grant was needed at all, only physical access. yu-hx.lpc sits in d/gaibang/underxx, reachable in real play only via d/city/pomiao's dong (树洞) passage, itself gated by (fam=me->query("family")) && fam["family_name"]=="丐帮" — i.e. the whole underground-tunnel teacher roster (li-sh, liang, yu-hx, zuo-quan, ma-jw, he-bj) is circularly locked behind already having a sect, so reaching it the "long way" isn't actually possible pre-membership either. Used the sanctioned admin-shortcut path instead: admin goto /d/gaibang/underxx (teleport the admin only, bypassing the tedious/circular travel gate, not any stat/security check) then admin summon qinfengxia (pulls the real character object to the admin's room via the ordinary move() mechanism — the same summon any admin could use in a real support situation) to physically place qinfengxia in the room without touching any stat. bai yu/apprentice yu then ran yu-hx.lpc's real, unmodified attempt_apprentice() check against the character's real, roll-derived int, exactly like the four previously-tested teachers.

`` 执行时段错误:*Value being indexed is zero. 程式:/adm/daemons/chinesed.lpc 第 94 行 呼叫来自:/feature/command.lpc 的 command_hook() 第 55 行,物件: /clone/user/user#12 ("沈秋白") 呼叫来自:/cmds/skill/xue.lpc 的 main() 第 71 行,物件: /cmds/skill/xue 呼叫来自:/adm/obj/simul_efun.lpc 的 to_chinese() 第 6 行,物件: /adm/obj/simul_efun 呼叫来自:/adm/daemons/chinesed.lpc 的 chinese() 第 94 行,物件: /adm/daemons/chinesed ``

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

Item 2 — death/respawn: COMPLETED LIVE, fully clean, no new bug found

Real kill liu (matched 流氓头/Liumang-tou, the stronger of the two 流氓 NPCs at d/city/guangchang — the sect leader from item 1 helpfully teleported next to admin via goto+summon first, same sanctioned admin-positioning shortcut, no stat/skill grant needed since qinfengxia's own base combat stats were already sufficient to lose realistically) against qinfengxia (freshly resurrected from the very apprenticeship test above, i.e. not a throwaway) ran a genuine, unmodified multi-round kill-command fight — confirmed no safe-sparring floor applies (kill.lpc has no analogous "stop at half health" logic, matching this session's 10+ other confirmations that kill vs. an NPC is unprotected) — and the character actually died for real, no smash shortcut needed:

你的眼前一黑,接著什么也不知道了....
你死了。
【谣言】某人:我看到沈秋白被流氓头杀死了。真是好惨。
鬼门关 - ...
  白无常(White gargoyle)

Confirms inherit/char/char.lpc's two-stat wound model precisely matches this session's precedent on other libs: eff_qi/eff_jing < 0 (mortal wound) → real die(); qi/jing < 0 alone → unconcious() (non-lethal, revive()s later) — real kill combat clearly reached the former, not just the latter.

Walked the full post-death cycle for real, no NET_DEAD_TIMEOUT-style acceleration needed (the whole sequence is only 5 real-time call_out stages × 5s ≈ 25s):

Standard checklist re-confirm (fast pass, all previously-fixed — no re-derivation needed)

All came back clean, matching the code exactly (not merely assumed from the NOTES history):

Verification method

Native build-debug driver, two concurrent telnet sessions (admin fluffos + test character qinfengxia), debug.log watched continuously via direct file reads after every command batch, not merely spot-checked at the end. Driver killed by exact PID after each restart (two restarts this pass: once to load the chinesed.lpc fix, once implicitly via the initial boot); readlink -f /proc/<pid>/cwd confirmed against this lib's own work/ directory before every kill. qinfengxia's and fluffos's save-file timestamp churn is the only diff left in work/data/ — both ended the session with a clean, in-game quit.

Files modified this pass

深度功能测试(2026-09-04,round three,shop + 拜师)

新角度:扬州醉仙楼购物 + 丐帮左全拜师。2026-07-24 round two 的 list/buy 因没钱被拒,诚实记录「成功购物未现场完成」;2026-08-20 round four 用 qinfengxia 走完余洪兴拜师和 xue,仍没补上一次真正付钱的购买。

实测过程

管理员 fluffos / Mud@2026 / 浮浮。第一输入是「您的英文名字:」(欢迎 画面之后,没有 BIG5 选择)。落地扬州客店 /d/city/kedianscore 「【天神】普通百姓」。log_error() 已有 arning: 闸门,本轮屏幕上没有 编译警告倾泻。

goto /d/city/zuixianloulist 烤鸡腿八十文铜板 / 牛皮酒袋一两白银 / 包子五十文铜板 / 鲸鱼十两黄金。F_DEALER 里丐帮穷叫化拒绝购买整段是 注释掉的,仍按家族惯例先买再拜。clone /clone/money/goldbuy jitui 成功(「你从店小二那里买下了一根烤鸡腿」)。当场 i 还挂着「一两黄金」 + 九十九两白银 + 二十文铜板,跟 xkx2017 一样是 MONEY_D->player_pay() 把金锭 set_amount(0) 后物件还没析构的显示;断线重连后黄金条目消失, 只剩烤鸡腿 + 九十九两白银 + 二十文铜板(10000−80 = 9920),找零数学 正确。

goto /d/gaibang/inhole,左全在树洞里(kungfu/class/gaibang/zuo-quan.lpc, 只检查男性),apprentice zuo 一次成功:左全收徒,score 「丐帮第二十 代弟子」、师父左全。cmds/usr/save.lpc 真正调用两个 save()user.o 立刻带上 family_name":"丐帮" / master_name":"左全" / generation":20 / class":"beggar"。断线后再连(「重新连线完毕」),称谓/师傅/银子/鸡 腿还在。

本轮没有新的 programming bug。live debug.loglibs/xiakexing2017/log/debug.log(Boot Time Fri Sep 4 02:15:41 2026), 无 error: / Too deep recursion。管理员存档未提交。