Tie Xue Jiang Hu (Blood and Iron Jianghu)

✅ 可玩

铁血江湖 (Tie Xue Jiang Hu)

tiexuejianghu

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

▶ 开始游玩 · Play Now

属于 ES II(Eastern Stories II)引擎系列武侠 mudlib,与本项目中的 wuhanzhan《大话西游》、wmkj《未明空间》等同属一个大家族,但代码库本身是独立分支,由作者 "hxsd" 开发,以帮派经营和 NPC 招募为核心特色,还内置了一套相当完整的商人/贸易子系统(作者自称"和大航海时代差不多")。游戏世界以中州、少林、全真等门派/城镇为骨架展开,新玩家从"英豪酒楼"起步,可以习武、闯荡江湖、加入帮派赚取产业收入;原始服务器因人气不足与内部巫师团队矛盾而停运,此后作者公开发布了源码,这份归档正是那次公开发布的产物。

English

A wuxia mudlib built on the ES II (Eastern Stories II) engine, part of the same family as this archive's Wuhanzhan (A Chinese Odyssey) and Weiming Kongjian, though it is an independently developed branch. Created by the author "hxsd," it centers on sect management and NPC recruitment, backed by an unusually complete merchant/trading subsystem the author likened to Uncharted Waters. New players start at the Hero's Tavern and can train in martial arts, roam the jianghu, and join a sect to earn income from its holdings. The original server closed after its popularity waned and its wizard staff fell into internal conflict, after which the author released the source code — this archive preserves that release.

README

在线试玩

https://mudlibs.fluffos.info/tiexuejianghu/

管理员账号 / Admin account

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

本地运行

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

游戏端口:40087

NOTES · 移植与修复记录

tiexuejianghu — 铁血江湖 (Tie Xue Jiang Hu / "Bloody Jianghu")

Archive: archives/铁血江湖.rar (archive #95). Extracted mudlib root: raw/txjh/export/mudlib/ (the archive nests txjh/export/mudlib/ — a config.cfg sits at raw/txjh/, one level above the export/ dir it points into). Port: 40087. Status: done (boots clean, full registration flow verified three times with real Chinese names, post-login look/score verified working every time, zero runtime errors in debug.log across all sessions).

What this is / lineage

The raw config.cfg's own name field (GBK-decoded) is 风云三(本地) ("Fengyun III (local)") — a stale copy-paste leftover unrelated to this game, the same pattern already seen on dtsl2 (archive #71-ish). raw/txjh/readme.txt (by the original author, "hxsd") and raw/txjh/小熊泥苑.txt (the "小熊泥苑"/Xiongxiong-Niyuan mud-resource site's own re-packaging note) both independently confirm the real game is 铁血江湖 ("Tie Xue Jiang Hu"): a guild-focused wuxia mud with an unusually developed NPC-recruitment/guild-income system and a full merchant/trade subsystem ("和大航海时代差不多" — "similar to Uncharted Waters/Age of Discovery"). The readme states the original server shut down due to low player counts and internal wiz-team conflict, and the archive was released publicly afterward. config.fluffos's name field here is set to 铁血江湖, not the stale 风云三(本地) value.

adm/obj/master.lpc's own header comment says "for ES II mudlib, original from Lil, rewritten by Annihilator (11/07/94)" — this is the same "ES II" (Eastern Stories II) lineage shared by the large majority of already-processed archives (shzs, wuhanzhan, huoying, yueyingqiyuan, haiyang2, yanhuangwuhun, etc.) — directory layout (adm/, feature/, std/, obj/, cmds/, d/, u/), securityd.lpc's ACL shape, and feature/dbase.lpc's real (non-simul_efun) set/query implementation all match that family, NOT the "nitan"/Lonely lineage (§15's dbase architecture bug doesn't apply here) and NOT the TMI-2/ES2/Falcon "XO" lineage. Did not force a match to any specific already-shipped sibling archive — no byte-identical core files were found against the handful of siblings spot-checked (master.lpc, chinese.lpc) — this looks like a genuinely distinct ES II-derived codebase, not a rebrand of one already in the project.

Fixes applied (with why)

§15h — is_chinese() GBK byte-range check (adm/simul_efun/chinese.lpc)

Was strlen(str)>=2 && str[0] > 160 && str[0] < 255 (a GBK lead-byte range check assuming byte-indexed strings). On this driver str[i] is a Unicode codepoint and strlen() counts characters. Fixed to strlen(str)>=1 && str[0] >= 0x4e00 && str[0] <= 0x9fff (CJK Unified Ideographs range, >=1 since one character is now one index). Without this, no real Chinese name could ever pass registration.

§15h — check_legal_name() bound + sliding-window (adm/daemons/logind.lpc)

Same file also implements the name-length/window checks directly (no separate named.lpc in this lib). Byte-length bound `strlen(name) < 4 ||

8 (2–4 GBK chars) halved to < 2 || > 4` (character count). The

i%2==0 && !is_chinese(name[i..<0]) sliding-window guard (was landing on alternating *byte* offsets to catch each GBK character's lead byte) had the i%2==0 && dropped entirely, since every index is already one character now.

§15ae — private nomask command-hook (feature/command.lpc)

command_hook(string arg) was declared private nomask and dispatched via add_action("command_hook", "", 1) in enable_player(). This driver treats private as hidden from add_action's external dispatch (unlike the original target driver), so every post-login command would have silently done nothing with zero error anywhere. Dropped private, kept nomask. Checked and confirmed present exactly as documented in the catalog — this lib would have failed the exact same silent-command symptom as xuanjianlu/bmxkx2001/bxsj/bxsj1/xiakexing3 had this not been caught proactively before first boot.

§15ar-adjacent — checked, NOT needed (worth documenting explicitly)

There is no separate commandd.lpc-style command-directory indexer in this lib matching the catalog's exact sscanf(name+"$", "%s.c$", name) shape — adm/daemons/cmd_d.lpc's rehash() uses sscanf(cmds[i], "%s.c", cmds[i]) (a quoted string ending in .c", not .c$"), so convert_lib.sh's standard quoted-".c"-reference fixer (§2) already turned it into "%s.lpc" automatically during the mechanical conversion pass — confirmed by reading cmd_d.lpc post-convert and re-testing look/score end-to-end. Documenting this because it's the same *category* of bug as §15ar but this lib's specific text shape happened to be inside the standard fixer's blast radius, unlike jinyongwenzi's %s.c$ shape which needed a manual fix. Worth double-checking on every future lib: same underlying pattern, but only sometimes auto-fixed depending on the exact quoting.

§15p — excluded dns_master from preload (adm/etc/preload)

Standing policy, applied proactively before first boot.

Non-standard: excluded ftpd from preload too (adm/etc/preload)

adm/daemons/ftpd.lpc (preloaded in the raw archive) #include <flock.h>, which does not exist anywhere in this archive (only <net/ftpd.h>, <net/ftpdconf.h>, <net/ftpdsupp.h> exist) — FLOCK_D isn't even #defined anywhere either, confirming the whole file-locking subsystem this daemon depends on was never actually wired up in this specific archive (present as real files in es1_win/esI, absent here). Since ftpd would be a fatal preload-time compile error and nothing in the core registration/gameplay path (master/securityd/logind/ simul_efun/command/chinesed) references FTPD_D, excluded it from preload — the same "trim non-essential network daemon" treatment §15p already applies to dns_master. Confirmed via lpcc that adm/obj/master (which pulls in the whole real preload chain) compiles clean with ftpd excluded.

§14 — valid_override() 3-arg upgrade (adm/obj/master.lpc)

Added the main_file 3rd parameter and check, cheap/free fix per the catalog, applied proactively. As documented, never actually observed to matter on a real boot here either (only would affect an lpcc-standalone compile of an #included simul_efun fragment).

§8g — one shared root cause spanning many "Undefined variable"/syntax errors (include/armor.h, include/globals.h)

§12-style orphaned non-LPC content (d/sandboy/map.lpc)

A pure box-drawing ASCII-art room map, not a single line of LPC, caught by the blanket .c.lpc rename. Confirmed nothing else references it (grep -rl for the basename comes up empty besides itself). Renamed to .txt.

Missing-quote typo (d/obj/books-nonskill/hmeng014.lpc)

string name = "《红楼梦》第十四回; — missing closing " before the ;, confirmed present in the raw pre-conversion GBK bytes too (not a conversion artifact). This desynced the parser for the rest of the file, producing a cascading "unexpected L_NUMBER" + three "Illegal character" errors on later, perfectly valid UTF-8 bytes. Added the missing quote.

Malformed array literal, genuine pre-existing GB18030 corruption (3 copies of gengfu.lpc: d/jinling/npc/, d/suzhou/npc/, d/suzhou/qinyun/npc/)

nosave string *sym_dee = ({ ...,"酉","","亥" }); (or "酉",","亥" depending on which lossy-conversion pass) — the raw archive's GB18030 bytes for "戌" (5th of the 10 Earthly Branches, between 酉 and 亥) contain a genuinely invalid byte sequence (confirmed: primary iconv -f GB18030 fails outright with "illegal input sequence" at that exact position on all 3 raw copies), so convert_lib.sh's -c-fallback lossy conversion dropped it, per the Encoding section's documented "iconv -c can eat an adjacent real byte too" gotcha. Restored the correct sequence "酉","戌","亥" (the 10 Earthly Branches in their canonical order) by inference from the surrounding array, not fabricated from nothing.

§15t variant 3 — inherit after global-variable declarations (8 files)

obj/mknpc.lpc, d/suzhou/obj/shoulei.lpc, d/suzhou/npc/guan_jia.lpc, d/suzhou/npc/test.lpc, d/suzhou/npc/wutiande.lpc, u/oldsix/mknpc.lpc, u/oldsix/hammer.lpc, u/oldsix/cloth.lpc — all had a mapping/string * global variable declared textually before their inherit statement, fatal here ("Illegal to inherit after defining global variables") even though the original target driver tolerated it. Reordered inherit to precede the global declarations in every file (content unchanged otherwise).

Duplicate inherit ROOM from two rooms merged into one file (u/xxy/shaolin/matou1.lpc)

The file's own header comments read // Room: /d/shaolin/matou1.c AND // Room: /u/nangong/matou.c — two genuinely different rooms (侠客岛码头 and 南码头) concatenated into one file, each with its own inherit ROOM;/create(). Since only one object can ever be "live" at this one path, and the file's own name matches the FIRST room (matou1), removed the second, dead block (lines 151–178: the 南码头 definition) rather than guess how to merge them. No /u/nangong/matou file exists anywhere else in the archive, so this content was already unreachable dead weight (the duplicate inherit was a hard compile error, meaning this second room was never actually loadable even in a hypothetical original-driver boot of this exact archive) — nothing playable was lost.

void functions returning a value (3 files + 1 wrong-type return)

std/weapon/gun.lpc — bad inherit target + reused BLADE helper

inherit GUN;GUN was never a #defined macro anywhere in this archive (no sibling weapon-type path entry for it in weapon.h either), and this is the only file in the whole lib referencing it. create() calls init_blade(25) (a real function only BLADE provides) confirming this "手提机枪" (submachine gun — an anachronistic one-off item) was actually meant to inherit BLADE, reusing its damage helper, not some fabricated GUN base. Fixed to inherit BLADE;.

#include wrong absolute path, one wizard homedir cluster (8 files, u/xxy/shaolin/bagua*.lpc)

All 8 hardcoded #include "/d/shaolin/bagua.h", but the file actually lives at /u/xxy/shaolin/bagua.h (the header, and the function check_dirs() it defines, were both effectively unreachable). Fixed the absolute path in all 8 files — this single header also defines check_dirs(), so it cleared that "Undefined function" category too in the same pass.

§8e — tail() is not a real efun (cmds/app/tail.lpc)

Same pattern as the catalog's own first documented case. Reimplemented do_tail_lpc() in plain LPC (read_file + explode + slice + write), defined before main() per §8b (a same-file forward call to a not-yet-defined function fails "Undefined function" here, unlike some looser old-driver targets).

Confirmed NOT needed (checked proactively, found clean)

- F_UNIQUE (51 files inherit it) — no /feature/unique.lpc exists anywhere in this archive at all (present in nearly every sibling ES II lib in this project, genuinely absent here). Left undefined/ unfixed; these files won't compile, none are on any preload path. - STICK/MACE/RAKE/BOW/ARCHERY (weapon-type path macros, 17+11+4+1+1 files) and F_FIGHTER/F_CLOTH/DAEMON (2+2+4 files) — none defined anywhere in include/, and (unlike the armor.h/F_SSERVER cases above) not simply commented out either — genuinely absent content, not a mechanical omission to restore. - prepare_skill() (33 files), get_npc_data()/set_npc_data() (12 files) — called everywhere, defined nowhere in the whole archive (not even a stub). No sibling ES II lib in this project defines these either (checked), so nothing to port from. NPC-combat-setup and NPC-stat-persistence features this specific archive never shipped a working implementation for. - daemon/skill/old/jiuyin-shengong.lpc's ::hit_ob(...) (1 file) — FORCE (std/force.lpc) never defines a base hit_ob, so the :: parent-call has nothing to reach. Isolated, single file. - u/xxy/city2/npc/shenzhao.lpc's #include "/kungfu/class/shaolin/hui.h" (2 files) and u/aug_old/{yapu1,thd/zhou_botong}.lpc's #include "thd.h"/"npc.h" — target files genuinely don't exist anywhere in the archive (unlike the bagua.h case, this isn't a wrong-path typo with the real file sitting elsewhere). - A long tail of smaller isolated one-off/few-file categories in the remaining lpcc_fail.log entries (mud_name, set_encumbrance, member_group — mostly unreachable adm/daemons/network/* files, set_max_items, data_netmail_file, a handful of "Bad assignment (mapping vs unknown)"/"syntax error" entries scattered across personal wizard homedirs u/aug_old, u/xxy, u/panguan, u/temp) — each affects 1-2 files, none on the boot/registration/gameplay path exercised by this pass's testing. Not investigated further per the project's stated "breadth over exhaustive depth" priority.

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

Applied the four standard WASM-first changes (AGENTS.md §1.3b/§1.3e/§1.5):

1. Loopback always allowed — ban gate (adm/daemons/logind.lpc:48-64)

logon() unconditionally ran BAN_D->is_banned(query_ip_name(ob)) / BAN_D->is_banned(query_ip_number(ob)) and destructed on a hit. Wrapped the ban block so it only runs for a non-loopback remote address.

Retrofitted fail-open → fail-closed (2026-07-24): the gate as originally patched here ran the ban check only when stringp(ip) && ip != "127.0.0.1" && strsrch(ip, "127.") != 0 && sscanf(ip, "%*d.%*d.%*d.%*d") == 4 — i.e. it required the ip to successfully parse as a well-formed dotted-quad before the ban check would even run, so ANY malformed/unparseable ip silently skipped the ban gate entirely (fail-open), not just genuine loopback. This was written defensively against the old WASM driver bug where query_ip_number() returned garbage for every WASM connection; that driver bug is now fixed (WASM reports a clean "127.0.0.1" same as native), so there is no remaining justification for treating "can't parse it" as "must be loopback". Changed to fail-closed: if (!(stringp(ip) && (ip == "127.0.0.1" || strsrch(ip, "127.") == 0))) — only a real loopback-shaped string skips the ban check; anything else, including an unparseable/non-string ip, now goes through the normal ban logic same as any other remote connection.

2. Uptime startup gates — none present

No uptime() < N connection-rejection gate exists in this lib. The uptime() hits are all in-game gambling rooms (d/*/duchang*.lpc, npc/douji, npc/saigui) and the cosmetic cmds/usr/uptime.lpc / adm/daemons/network/cmwhod.lpc uptime display — game content, left alone.

3. Anti-flood throttles — none present

No per-IP connection-rate / multi-login-per-IP / registration throttle in logind.lpc (only a MAX_USERS cap and a wiz_lock_level gate, neither IP-based). Nothing to exempt.

4. Admin account seeded — fluffos / Mud@2026 / 浮浮

Registered through the real flow (id fluffosy → 浮浮 → Mud@2026 ×2 → email → m), landed in 英豪酒楼. Granted (admin) by appending fluffos (admin) to adm/etc/wizlist (the file securityd.lpc:82 reads into wiz_status; get_status/wizhood return (admin), which feature/command.lpc:90 maps to ADM_PATH + enable_wizard()). Verified after reboot: login as fluffos, update /adm/daemons/logind重新编译 ... 成功, who4 wizard listing works.

Save files for the orchestrator to force-add (currently untracked, NOT gitignored — a plain add works, listed for completeness):

Retest: fresh normal registration (秦十/qinshi) still reaches 英豪酒楼; debug.log had 0 runtime errors across the session; test char qinshi removed afterward (fluffos kept).

Re-retest after the fail-closed retrofit (2026-07-24): fresh boot, fresh normal registration (id qinretes, real Chinese name 秦风七) all the way through look/score/quit — landed in 英豪酒楼, correct output throughout, normal 30-second delayed-quit message. fluffos/ Mud@2026 admin login verified again: look then update /adm/daemons/logind重新编译 /adm/daemons/logind.lpc:成功!. Zero 执行时段错误 lines in debug.log for the whole session. Test char qinretes removed afterward (fluffos kept).

Registration-flow + post-login-command transcripts

Three full end-to-end runs, each in ONE continuous mudclient.py connection (--idle 0.6), across three different driver boots (to also re-verify the emoted.o fix and the full set of source fixes together):

Run 1 (after emoted.o fix, before the lpcc-sweep-driven content fixes): qinfgy秦风二test123 (×2) → [email protected]mlookscorequit. Landed in 英豪酒楼; look printed the real room description twice (before/after an NPC "耳光" interaction event); score printed 普通百姓 秦风二(Qinfg), correct stats/HP bars/food/water gauges; quit gave the normal 档案正在存取中,三十秒后方能下线! delayed- quit message. Zero 执行时段错误 (runtime error) lines in debug.log for this session.

Run 2 (after ALL fixes above, fresh boot): tiexuey秦风三test123 (×2) → [email protected]mlookscorequit. Landed in 英豪酒楼; look ×2 correct; score printed 普通百姓 秦风三(Tiexue), correct stats; NPC "武大郎" random_chat fired (previously the emoted-restore bug made this crash with Bad argument 1 to keys() every ~heartbeat — now silent/clean); quit gave the normal delayed-quit message. Zero runtime errors in debug.log.

Run 3 (final re-verification after the very last two fixes — gun.lpc/tail.lpc — neither on the registration path, run anyway for completeness): muyuany秦风四test123 (×2) → [email protected]f (female, to also exercise the alternate gender/clothing branch in enter_world()) → lookscorequit. Landed in 英豪酒楼; look ×2 correct; score printed 普通百姓 秦风四(Muyuan), 女性 (female), correct stats/gauges; quit gave the normal delayed-quit message. Zero 执行时段错误 lines in debug.log for the entire session (grep -c confirmed 0).

All three runs used a real Chinese given name (2–3 characters), confirming the §15h is_chinese/check_legal_name fix works correctly end-to-end, not just in isolation.

lpcc_check.sh sweep results

Ran the full sweep three times as fixes progressed (9190-9191 .lpc files, not a mega-lib, full sweep is the required gate per AGENTS.md):

Remaining ~740 failures are dominated by the documented content gaps above (F_UNIQUE alone accounts for ~51 files, prepare_skill/ get_npc_data/set_npc_data another ~56, the weapon-type/feature macros another ~35), the known #include-fragment sweep-artifact category (_axe.lpc/_blade.lpc/_sword.lpc/_dagger.lpc-style #define AS_FEATURE; #include "X.lpc" files failing standalone with Unable to find the inherited function 'setup' — confirmed via grep that this exact error string never appears in the real boot's debug.log, matching §6b's documented false-positive pattern exactly), and a long tail of 1-2-file isolated content issues in personal wizard homedirs, none on the registration/gameplay path this pass tested.

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

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

Round-two deep playthrough pass (AGENTS.md §10.7), following the bxsj/xiyouji worked examples. Played as an ordinary new player through registration, exploration, organic skill-learning, sect-joining, safe and lethal combat, a real quit, a real-wall-clock-gap reconnect, and (unusually for this project's round-two passes so far) a full death/reincarnation cycle, native driver (build-debug). Read doc/help/newbie in full first — it named the intended test path (中州城's 英豪酒楼 start, hp/cha/score/look, the menpai/帮会 sect list, xue <skill> from <teacher> syntax) but, notably, said nothing about a safe-sparring mechanism — that had to be found by grepping accept_fight/room source, and turned out to be gated behind an in-game cost a fresh character can't pay (see below).

Test characters (both kept, not cleaned up, as representative playthrough evidence):

Bug found and fixed #1: already-cataloged §7.12 class, live-reproduced here for the first time

adm/simul_efun/message.lpc:61-62's tell_room(mixed ob, string str, object *exclude) wrapper passes the (omitted-when-not-given) exclude varargs parameter straight through to the message() efun, which on this driver resolves an unsupplied array-typed varargs argument to raw int 0, not ({}). message() requires its exclude argument to be an object or array — this is exactly AGENTS.md §7.12 ("Shared message/wrapper argument bugs"), already documented as affecting "most of the ES II family," which tiexuejianghu is (per this file's own lineage section) — but this lib's original conversion pass never checked for it, and it shipped live.

``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 || ({})); } ``

Bug found and fixed #2: NEW bug class — a hardcoded respawn-room path stale from an old, since-replaced zone rewrite

include/login.h:14's REVIVE_ROOM constant ("/d/yangzhou/temple") does not point at a loadable object. d/death/npc/{wgargoyle, bgargoyle}.lpc (白无常/黑无常, the two death-realm psychopomp NPCs) both run a 5-stage, 5-second-interval dialogue (death_stage()) after a player dies, then call ob->reincarnate(); ob->move(REVIVE_ROOM); to send the player back to the living world.

``lpc // before #define REVIVE_ROOM "/d/yangzhou/temple" // after (see the file for the full comment explaining why) #define REVIVE_ROOM START_ROOM ``

Minor logic bug found and fixed (not crash-class, but confirmed via live incorrect behavior): 徐霞客's answer-window timer had its subtraction backwards

d/zhongzhou/npc/xuxiake.lpc:99's do_answer() — part of this NPC's "answer my trivia question before I'll teach you 读书写字" apprenticeship gate (the organic-skill-learning path this session used) — computed now_time = (int)ob->query_temp("徐/time") - time(); (stored-question- time minus now), which is always negative or zero and can never exceed the intended 10-second answer window (if (now_time > 10)), rather than time() - stored_time (elapsed, positive, correctly comparable to the window). Discovered live: an unanswered question never expired even across brute-force wrong guesses tried well outside any reasonable 10-second window, and (worse for a tester relying on the intended "say the question again if you got it wrong" UX) the question is only generated once per xue attempt (guarded by if (ob->query_temp("徐/answer")) return notify_fail(...) at the top of recognize_apprentice()), so a player who doesn't see the question text in time (this project's own mudclient.py --idle pacing raced the question's own 1-second call_out delay on the first attempt) is stuck re-guessing the SAME never-re-rolled question indefinitely rather than getting a fresh one after 10 seconds as designed. Not a crash — the broken timer makes the puzzle strictly easier (never expires) rather than broken/unplayable, so it's a genuine but low-severity bug. Fixed the subtraction order:

// before
now_time = (int)ob->query_temp("徐/time") - time();
// after
now_time = time() - (int)ob->query_temp("徐/time");

Verified: update /d/zhongzhou/npc/xuxiake recompiled clean as admin; re-tested the full organic-learning flow end-to-end post-fix (xue literate from xu xiake → question → answer 22 → learned) — unaffected for the correct-answer-in-time case, which is all that was re-verified live; the now-correctly-enforced 10-second expiry itself wasn't separately re-timed live (low value given the trivial, mechanical nature of the fix).

What was tested and confirmed working

Process/testing note for future agents on this lib

Room navigation via a static regex-based BFS over set("exits", ([... ])) literals (as used successfully on other libs in this project) is not fully reliable here for two lib-specific reasons hit live during this pass: (1) some rooms (e.g. d/yeyangzai/caocong, "草丛") implement a randomized "you can't tell which direction" maze where the SAME direction command must be retried a variable number of times before it actually succeeds — a static shortest-path graph can't capture this; (2) mudclient.py sessions are not persistent connections across separate invocations in this project's usual workflow, so a character's *actual* position when a new session logs in is wherever the PREVIOUS session left it (via silent reconnect), not the game's own START_ROOM — sending a route computed from START_ROOM after actually reconnecting mid-route produces a string of 什么? ("what?") rejections that are easy to misdiagnose as a game bug rather than a test-script coordinate error. Verify current position with look before sending a long movement queue, especially after any prior session that didn't end in a full room-resetting quit.

§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,CRLF 行尾档 案)已经在更早一轮(引用注释里的"AGENTS.md #15w")正确修复过,管 理员账号(fluffos/Mud@2026adm/etc/wizlist 已有 fluffos (admin) 且存档已提交)也已经全部正确,本轮只发现并修复 了 log_file() 一处。

发现并修复的 PROGRAMMING bug

1. log_file()adm/simul_efun/file.lpc,CRLF 行尾档案)完全没 有 assure_file() 保护(AGENTS.md §7.11-class 的又一确认实 例)cmds/app/{clone,rm,update}.lpc/cmds/wiz(/arch)/ summon.lpc 等文件多处 log_file("wiz/<子目录>/<id>.log", ...) 调用依赖对应子目录存在,其中 wiz/update/<id>.log 每次巫师执 行 update 指令都会触发,本轮的 update 验证步骤本身就顺带验 证了这个修复。注册/登录本身只写 log_file("USAGE", ...)(无子 目录,本来就存在),不受影响。已补上 assure_file(LOG_DIR + file);(含前向声明,用 Python 字节级替 换保留原 CRLF 行尾格式)。

Proactive checks(无需改动)

实测过程

用已提交的 fluffos/Mud@2026 登录,update /adm/simul_efun/file (就是本轮改过的文件)确认可正常重新编译,零诊断刷屏。全程未生成 log/debug.log(说明真的零运行期错误,不是文件被清空)。登录本 身产生的存档时间戳类微小 diff 已用 git checkout 撤销,不提交。 驱动最终按精确 PID kill,ps -p 确认已退出。

AGENTS.md §7.100 修复(2026-08-19,批次五)

ROOM 基类冗余 replace_program(ROOM); 自崩溃地雷(详见 AGENTS.md §7.100):3010 个房间文件的 create() 里紧跟 inherit ROOM; 之后 都有这一行多余调用,永久设下"待替换"标记,第一次对该房间对象绑 定闭包就会崩溃。有 5 处代码生成模板烤了同一个地雷(obj/roommaker.lpcd/obj/clone/misc/roommaker.lpcobj/rmmaker.lpcu/panguan/rmmaker.lpcu/panguan/room.lpc——和手足档案 fys 同一 套模板家族)。

本档案独有的新变体(fys 没有):u/heart/xuedao/ 下 143 个文件的 冗余调用和一行 UTF-8 尾随注释共享同一行 (replace_program(ROOM); //如果没有init函数请不要删除这句话), 严格的独立成行脚本正确地跳过了它——另写了一个针对这个精确行形状 的脚本手动摘除。累计 3012 处 live 调用删除,和 survey 记录的数字精 确吻合,修复后 0 处遗留。

验证:build-debug 驱动真实冷启动,端口 40087 正常监听, debug.log 全程干净。既有管理员账号 fluffos/Mud@2026 登录正常 (落地英豪酒楼,look/quit),全程无新增 "cannot replace"/"cannot bind" 日志行。

§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): 3 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.

AGENTS.md §7.19: enable_player() reentrancy guard (2026-09-01)

Same corpus-wide bug class as mhxy/wuhanzhan: feature/command.lpc's enable_player() wraps enable_commands() and is unconditionally reachable from an NPC's init() via setup()/reset_me() (confirmed on this lib's own d/*/npc/zhangmen*.lpc-family NPCs, matching mhxy's originally-documented d/xueshan/npc/zhangmen.lpc pattern). Calling enable_commands() on an object that's already living() makes the driver re-invoke that object's init() as a side effect; since init() calls back into enable_player(), that is genuine same-call-stack reentrancy that repeats until "Too deep recursion" aborts a room's first-ever visit.

Fixed with a true reentrancy flag (nosave private int in_enable_player_now;), NOT a bare if (living(this_object())) return; guard — this lib's feature/damage.lpc revive() and cmds/std/sleep.lpc wakeup()/wakeup2() all legitimately re-invoke enable_player() while the object is still living() (that's how a fainted/asleep character gets commands back), so a living()-gated guard would silently break every one of those real re-enables. enable_player()'s single body has no early return statements, so the flag is set at entry and cleared once, before the function's fall-through end. Verified with a single-file lpcc compile check (exit 0, no errors) against feature/command.lpc.

深度功能测试(2026-09-04,shop)

Live pass, port 40087. 2026-07-24 already apprenticed qinlangf to 谷虚道长 (武当派); this round is shop only. First send is the English id (no GB/BIG5 menu). Admin fluffos / Mud@2026 lands at 英豪酒楼 (/d/zhongzhou/yinghao) with 武大郎 present.

Shop: list on 武大郎 (d/zhongzhou/npc/wudalang.lpc, F_VENDOR) shows 烤鸡腿 三十文铜板 (key jitui). clone /obj/money/gold then buy jitui from wu dalang succeeded: “你向武大郎买下一根烤鸡腿”, inventory 烤鸡腿 + 九十九两银子 + 七十文钱. can_afford()'s 零钱 checks are already commented out here (Huang 1996 auto-convert), so gold-only is fine. 武大郎 random_chat emotes — idle 0.45.

No code change. 拜师 not re-done.