Reborn in Blood

✅ 可玩

浴血重生

yxcs

🔑 fluffos / Mud@2026 更新 66a3bd8 2026-10-28 源码 下载 ZIP

▶ 开始游玩 · Play Now

浴血重生登录横幅自称 "1.YXCS"/"浴血重生",是一款围绕"浴血重生"这一江湖恩怨、洗心革面主题展开的传统武侠 MUD,新角色要经历标准的门派拜师与完整的功夫技能体系,创角时还能选择"国际挑战者"式的比武活动;血统比较特殊:既有 ES II 引擎系列的痕迹(`chinesed.lpc` 等文件署名可追溯到 "ES"→"XKX" 一支),又混入了"Lonely"("nitan/NT" 系列的作者)后期改写的部分模块,属于一个 ES 系底子上被二次深度魔改的分支,不是纯血统的任何一支;地图上"世界之巅"跳崖场景与"天涯"家族(`xysylmhb`/`xyzxiiylzymh`/`yzxiiizylfy`/`xyzx3`/`tianxiawuxue`)逐字节相同,"Lonely"这条线索也和 `tianxiawuxue` 鸣谢名单里的同一位作者相呼应;另有一处防盗号保护,已在 wizlist 中登记为高权限的 ID 无法在注册流程中直接设置密码,需先从名单移除、注册完成后再加回去。

English

A traditional wuxia revenge story built around its "Reborn in Blood" premise — the login banner self-identifies as "1.YXCS" / "Reborn in Blood." New characters go through standard sect apprenticeship and a full kungfu/skill system, plus an "international challenger"-style tournament option at character creation; a wizlist-based anti-account-theft protection strips password-setting rights from any ID already registered as a high-privilege wizard until it's temporarily removed from the list. Its lineage is unusual: it carries traces of the ES II engine series (files like chinesed.lpc trace authorship back through the "ES"-to-"XKX" branch) mixed with modules later rewritten by "Lonely," the author behind the Nitan/NT series — making it a deeply modified hybrid rather than a pure descendant of any single lineage. Its map can be pinned down more precisely: the "Peak of the World" cliff-jump scene is byte-identical to the unrelated "Tianya" family shared by several other archives in this collection (xysylmhb/xyzxiiylzymh/yzxiiizylfy/xyzx3/tianxiawuxue).

README

内容亮点

在线试玩

https://mudlibs.fluffos.info/yxcs/

管理员账号 / Admin account

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

本地运行

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

游戏端口:40056。

NOTES · 移植与修复记录

yxcs — 浴血重生 (archive #62)

Archive: archives/浴血重生MUD.rar. Port: 40056. Status: done (boots clean, full registration flow verified end-to-end with real Chinese names, reaching an actual game room; lpcc sweep at ~98%+ pass).

What this is

The mudlib's own config.cfg self-identifies name : 1.YXCS — "YXCS" is the pinyin initialism of 浴血重生 ("Bathed in Blood, Reborn"), matching the archive's own title exactly. The live in-game banner also prints "浴血重生(2.YXCS)". No slug discrepancy worth noting.

Archive layout: the actual mudlib root is nested one level down at raw/socket/yxcs/ — raw/socket/ also bundles several unrelated Windows binaries alongside it (MudOS.exe, serv-u/ — a cracked FTP server installer + keygen, superscan/ — a 2000s-era network port scanner). These are contemporary "toolbox" bundling from whoever originally distributed this archive, not part of the mudlib at all — ignored entirely, only raw/socket/yxcs/ was copied into work/.

13,452 raw files / 11,995 .lpc after conversion — a normal-to-large-sized lib, well below the "mega-lib" bracket (AGENTS.md §6b) that would call for skipping the full lpcc sweep.

Lineage

A genuine hybrid of two lineages already seen elsewhere in this project, not a clean match to either:

Fixes applied, and why

1. NEW bug class: #define nosave static / #define protected static

guarded by an LPC macro this driver never predefines — silently converts nearly every nosave function in the lib into static function (a hard parse error, AGENTS.md §3)

include/globals.h (and identical copies in adm/obj/master.lpc, adm/obj/simul_efun.lpc, and 4 files under a u/lonely/ backup tree) had:

#ifndef __SENSIBLE_MODIFIERS__
#define nosave static
#define protected static
#endif

__SENSIBLE_MODIFIERS__ (double-underscore, LPC-visible) is never predefined by this driver to LPC code (confirmed: only mentioned in ~/src/fluffos/src/local_options.README as a suggestion, never actually #define'd anywhere reachable from LPC) — so this #ifndef branch always fires. Since this driver DOES support nosave as a real (soft-warning-only) function modifier and rejects static on functions with a hard parse error (empirically verified: static int foo(){} → hard error, nosave void foo(){} → soft "Illegal to declare nosave function" warning only), this macro would have converted the vast majority of this lib's own nosave function declarations into an immediate, near-universal boot-blocking parse error.

Caught by luck, then fixed properly: convert_lib.sh's blanket \bstatic\b → nosave sed (§3's standard fix) also fired on the word "static" *inside this macro's own replacement text*, turning #define nosave static into #define nosave nosave — a self-referential macro that the C preprocessor's "blue paint" rule resolves as a no-op (leaves nosave as itself), which accidentally neutralized exactly half the problem. But it also turned #define protected static into #define protected nosave, silently changing protected's semantics (DECL_PROTECTED → DECL_NOSAVE) instead of leaving it alone. Verified protected is a fully legal, real modifier on this driver on its own (protected int foo(){} compiles clean, no warning) — so the correct fix is to let BOTH pass through completely unchanged, not alias one to the other. Rewrote all 7 files' macro block to:

#define nosave nosave
#define protected protected

Spot-checked afterward: grep -rn '\bstatic\b' across the whole work/ tree now only matches my own new comments, confirming no other lingering static-as-function-modifier collateral.

2. §15h (is_chinese / check_legal_name GBK byte-range bugs)

3. §14 (valid_override needs the 3-arg signature)

adm/obj/master.lpc's valid_override(file, name) upgraded to valid_override(file, name, main_file), checking both file and main_file against SIMUL_EFUN_OB/MASTER_OB.

4. §15w (log_error() conflates warnings with real errors)

adm/obj/master.lpc's log_error() unconditionally showed the scary "编译时段错误:..." message to whatever player happened to be connected for EVERY compile diagnostic reaching the apply, including harmless soft warnings (e.g. this driver's own nosave-function warning, #pragma warnings, unused-variable warnings — all very common in this lib). Gated the player-facing write on strsrch(message, "warning:") == -1, matching the wuhanzhan (#58) precedent. Everything still logged to the log file regardless.

Confirmed NOT needed: error_handler() already unconditionally does efun::write_file(LOG_DIR + "debug.log", standard_trace(...)) at the end of its own body (no "falls through automatically" assumption relying on a non-existent return-value path) — the §15w "add a permanent RUNTIME_ERRORS insurance write" follow-up wasn't needed here.

5. NEW: #8e (tail) — fatal here since it's inside the composed

simul_efun compilation unit

adm/simul_efun/file.lpc's tail(string file) called efun::tail(file) — never a real FluffOS efun. Reimplemented in plain LPC (read_file + explode on \n + slice last 20 lines + write), same pattern as every other lib. Also fixed an identical copy in u/lonely/sec/file.lpc (an unused wizard-homedir backup copy, not on the live compile path, fixed for consistency). Confirmed dead/rarely-used admin tooling — no live callers found anywhere in the tree.

6. §15s (tell_room()'s bare message() 4th-arg bug)

adm/simul_efun/message.lpc's varargs void tell_room(mixed ob, string str, object *exclude) { if(ob) message("tell_room", str, ob, exclude); } — when called in the common 2-arg form, exclude defaults to bare int 0, which this driver's message() (4th arg typed void | object | object *) can reject. Fixed to exclude || ({}).

7. §11-style copy-paste bug: clone/weapon/panguanbi.lpc

inherit PEN; / init_pen(25) — PEN was never a defined macro anywhere (PIN exists, a *different* weapon type meaning "针"/needle) and init_pen() was never a real function. The item's own content (id "panguanbi", long description "这是一柄普通的精钢剑" — "an ordinary fine steel sword") plus a working sibling copy at /d/obj/weapon/sword/panguanbi.lpc (correctly inherit SWORD; init_sword(20);) confirm this was a copy-paste-and-half-rename artifact. Fixed to inherit SWORD; ... init_sword(25); (kept the original numeric argument).

8. §8g-style missing #defines: SSERVER, F_NOCLONE

Two bare macros used by inherit SSERVER; (5 skill files) and inherit F_NOCLONE; (4 boss-NPC files under kungfu/class/ultra/ — 南海神尼/黄裳/ 独孤/葵花太监, all major named Jin Yong characters) were never #define'd anywhere, a hard parse error (inherit <undefined identifier> parses as "expecting L_STRING", not silently OK). Both had an obvious, already- existing target to alias to rather than fabricate:

Follow-on: the 4 F_NOCLONE boss files each call a bare check_clone() explicitly from their OWN create() (which fully overrides feature/unique.lpc's own automatic-on-create uniqueness check without ever calling ::create()), so the automatic check never actually ran for them. Added check_clone() to feature/unique.lpc itself (same body as its own create()), which — since it's inherited via the new F_NOCLONE→F_UNIQUE alias — became available to all 4 files at once.

9. §15b (never-defined-but-called globals): add_light, keep_heart_beat

10. NEW: whole "competitor" (international-challenger event) subsystem

silently dropped from feature/attack.lpc

feature/attack.lpc had a .bak sibling (feature/attack.bak, 555 lines vs the live file's 342) — diffing them showed the ENTIRE competitor variable + query_competitor()/set_competitor()/competition_with()/ win()/lost() subsystem existed in the backup but had been completely removed from the live file, while 9+ other files (kungfu/class/generate/ challenger|indian|european|japanese|japanese1.lpc + u/lonely/ copies, adm/daemons/story/challenge.lpc, inherit/char/challenger.lpc, u/lonely/obj/user/quit.lpc) still call it — a real, wide-reaching "only ever called, never defined" gap (§15b), not a typo. Restored verbatim from attack.bak (not a guess) into feature/attack.lpc: the competitor variable + query_competitor()/set_competitor() near the top (no forward-call issue), and competition_with()/win()/lost() moved to just AFTER fight_ob()'s own definition later in the file — per §8b, these three call fight_ob()/run_override() and calling a same-file function before its definition fails to resolve on this driver; the backup's original ordering (which put all 5 functions in one place, before fight_ob()) would have hit exactly that. This was the single highest-impact fix in this pass by file count (resolved compile errors across the whole challenger-NPC family in one shot).

Follow-on fix needed once query_competitor resolved: inherit/char/ challenger.lpc's own competition_with() override had killertemp=ob; with no local declaration anywhere in the function — a genuine pre-existing typo (not something the restore introduced). Every sibling file using the identical killertemp=ob; idiom elsewhere in this lib (japanese.lpc, questguai.lpc, chinese.lpc) declares it as a plain local object; matched here (object killertemp; added to the function).

11. Pre-existing content typos fixed via the lpcc sweep

Confirmed NOT needed (and how confirmed)

Known residual issues (documented, not fixed — non-critical content)

Registration flow

Read adm/daemons/logind.lpc's actual callback chain before testing (per AGENTS.md's standing warning about hidden pre-id prompts): logon() prints a "Select 国标码 GB or 繁体 BIG5 (gb/big5):" line, but this is a soft prompt, not a gate — input_to(get_id, ...) fires next regardless, and get_id() only special-cases the literal input "big5" (sets a flag and re-shows the whole banner+prompt); ANY other input (including a normal English id) falls straight through to the real id-validation logic. So the very first --send can just be the real login id directly, no separate blank/gb answer needed.

Full chain confirmed by reading the source: get_id → (existing user) get_passwd or (new user) confirm_id (y/n) → get_name (Chinese name, no separate y/n confirmation when a real name is typed — only random-name generation goes through get_resp) → new_password → confirm_password → gift-attribute selection (select_gift 0-4/set_gift/get_gift y/n) → get_email → get_gender (m/f) → make_body()/init_new_player()/enter_world().

Verified twice, in two separate continuous mudclient.py sessions (before AND after restarting the driver to pick up the feature/ attack.lpc competitor-subsystem restore, to make sure that change didn't regress the core player-body class every character depends on):

1. qinfeng → y → 秦风 → test12345 → test12345 → 0 → y → [email protected] → m → look → quit 2. linfeng → y → 林风 → test12345 → test12345 → 0 → y → [email protected] → f → look → quit

Both runs: Chinese name accepted with no rejection, no separate confirmation prompt (matches the source), gift/email/gender flow completed normally, and the character landed in an actual room ("世外桃源" / Peach Blossom Spring — the real starting room, not a void/error state), with a correct room description, exits, NPCs (水笙/狄云) listed, and the news system firing normally. A third quick test confirmed the *existing-user* path (re-entering linfeng) correctly routes to a password prompt instead of character creation, and 3 wrong-password attempts correctly disconnect with the expected message. debug.log was clean of any error/access-denied/crash lines across all three sessions (only the usual first-boot *Warning: unable to open stat file domain_stats/author_stats lines, and ordinary compile warnings — no 执行时段错误, no Segmentation, no Fail to load, no access denied).

lpcc sweep

Ran twice (once before the deeper §15b/copy-paste-content fixes, once after, to measure improvement): 11995 total files both times.

Memory stayed healthy throughout both sweeps on this 23GB host (never dropped below ~16GB available, well clear of the OOM risk threshold in AGENTS.md §6b) despite a concurrent agent running another lib's sweep at the same time.

Process notes

Re-verification pass: driver rebuild + formatter + WASM (2026-07)

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

Standard pass per AGENTS.md §1.3b/§1.3e/§1.5:

- logon(): ban_cnt > 12 per-IP pending-connection cap — loopback exempt. - get_id(): the netclub/public-ip per-IP multi-login caps (ip_cnt > 12 / > 4) — loopback exempt. - get_passwd(): 30-second "你刚退出游戏" relogin load throttle — loopback exempt (the 600s kickout penalty is punishment/game design, kept). Also removed a leftover debug printf("%O\n", ob) in get_name() that printed /clone/user/login#N at every new player.

WASM long-sit boot-watch pass (2026-07)

200s scripts/wasm_boot_watch.sh sit: completely clean, zero grep hits beyond the known-benign early Unable to open log file: "log/debug.log" line — no new findings, no fix needed. (This lib's own adm/simul_efun/object.lpc file_owner() uses a different, already- correct 2-arg sscanf(file, "/u/%s/%s", name, rest) shape that doesn't have the 3-arg misattribution bug found live on sibling zhonghua2 and ported to 7 other libs in this batch — checked and confirmed fine, nothing to port here.)

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

状态已从过时的 limited 修正——这份档案自己的 README 和 group_note 里从未记录过任何缺陷说明,本轮重新测试也没有发现:管理员登录(fluffos/Mud@2026)干净正常,权限已通过这份档案自己的最高阶层字符串确认('★ 您目前权限:〖 巫师协会懂事 〗(boss)'),quit 正常。

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

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

Read doc/help/newbie in full first (5-part in-game newbie guide, credited "By 黑客(lonely)"): covers stat-roll ranges, personality/character choice (光明磊落/狡黠多变/心狠手辣/阴险奸诈, each with a mechanical effect), sect recommendations by weapon type, and a Q&A section explicitly naming gc e n + learn zhu literate as the free literacy-training route (gc = 扬州中央广场).

NEW bug found and fixed: every single connection crashed inside logon(), before the id prompt, on a genuinely fresh checkout

First boot attempt (driver launched clean from libs/yxcs, port up in ~1s) produced, for every connection attempt: new_conn_handler: logon() on object clone/user/login#N has failed, the user is disconnected in the driver's own debug.log — a total, silent connection block with zero player-visible banner text (matches the exact symptom class in AGENTS.md §7.9/§7.11: the driver's own crash-summary line carries no LPC stack trace).

Root cause, found via the second, LPC-level debug.log (work/log/debug.log, written by error_handler()'s own write_file(LOG_DIR "debug.log", ...) — see the log_error() discussion above; check BOTH log locations per AGENTS.md's standing instruction, this bug was invisible in the first one):

执行时段错误:*Wrong permissions for opening file /log/file/cat_file for append.
"No such file or directory"
呼叫来自:/clone/user/login.lpc 的 logon() 第 7 行
呼叫来自:/adm/daemons/logind.lpc 的 logon() 第 115 行
呼叫来自:/adm/obj/simul_efun.lpc 的 cat() 第 291 行
呼叫来自:/adm/obj/simul_efun.lpc 的 log_file() 第 11 行

adm/daemons/logind.lpc's logon() — the very first thing every new connection's login.lpc calls — does cat(WELCOME) to print the login banner. adm/simul_efun/file.lpc's cat() unconditionally calls log_file("file/cat_file", ...) as its own audit-log side effect *before* actually printing anything, and log_file() itself was a bare write_file(LOG_DIR + file, text) with no directory guard at all — a fresh checkout never ships work/log/file/, so the write throws, the throw is never caught anywhere in the logon() call chain, and the entire apply aborts before the banner (or the id prompt after it) ever gets sent to the connecting socket. This is a new confirmed instance of AGENTS.md §7.11 ("missing runtime directories and the silent write_file abort") — same shape as the xajhxo precedent (log_login() → uncaught log_file() write into a never-shipped directory, killing registration one step earlier than the visible symptom), except here it fires on every connection, not just at one step of character creation, because cat(WELCOME) sits at the very top of logon() itself.

Fix: patched log_file() itself (adm/simul_efun/file.lpc), not just the one call site, since it's a shared simul_efun used by dozens of call sites across the whole tree — added the missing assure_file() guard (this file already has its own assure_file() helper, same pattern as the xajhxo fix; needed a one-line forward declaration since assure_file() is defined later in the same file and this compiler doesn't resolve same-file forward references without one):

void assure_file(string file);
void log_file(string file, string text) {
  assure_file(LOG_DIR + file);
  write_file(LOG_DIR + file, text);
}

Verified: killed the driver, restarted clean, reconnected — work/log/file/cat_file now gets created on first write, banner prints, id prompt reached, zero logon() ... has failed lines in either debug.log for the rest of the session.

Also required (pure operational setup, not a code bug, but a fresh-checkout prerequisite worth recording): the archive shipped with neither libs/yxcs/log/ (the driver's own real debug.log, §5.2 — CWD-relative, not mudlib-relative) nor work/log/ (the mudlib-virtual LOG_DIR target used by the LPC code above) on disk at all. mkdir -p log work/log/nosave work/log/wiz before boot; without it, debug.log itself never gets written (silent, not even the crash-summary line makes it to disk) and log_error()'s own write additionally throws during preload compile-warning logging (self-healing since it's already inside preload()'s outer catch(), but pollutes preload output).

Defensive fix applied alongside (not confirmed as a live crash this pass, but matches the exact AGENTS.md §7.9 shape and the underlying data files are explicitly gitignored — libs/*/work/adm/daemons/iduser / .../users, per this project's own .gitignore comment "user-id counters... not meaningful shipped content"): logind.lpc's logon() did i_user = atoi(read_file(__DIR__"users", 1)) (and the same shape for iduser and maxonline) with no stringp() guard — on a fresh checkout where those counter files don't exist yet, read_file() returns int 0, and atoi() on a non-string argument is exactly the §7.9 "fresh-checkout crash bomb" pattern. Guarded all three with stringp(...) ? atoi(...) : 0. (maxonline already existed on this checkout so this one wasn't empirically confirmed as live here, but users/iduser were both genuinely absent and this guard is cheap insurance regardless of which exact site would have thrown first.)

Registration — real Chinese name, full flow

Continuous session via a small custom Python telnet-IAC-stripping client in tmux (this environment has no telnet or nc-with-negotiation binary available, so scripts/tmux_mud.sh — which shells out to telnet — doesn't work here; wrote a ~90-line drop-in replacement using the same IAC-strip logic as scripts/mudclient.py, kept in the scratchpad, not committed).

qinfengb (rejected once first as qftest2 — digits not allowed, "你的 英文名字只能用英文字母") → y → 秦风波 (real Chinese name, accepted immediately, no separate confirmation prompt — matches the logind.lpc source read in the earlier pass) → test12345 ×2 → gift-attribute 0 (random) → y → [email protected] → m → landed in 世外桃源 (/d/register/entry), correct room description, water笙/狄云 present, news system fired. look/score/i all correct at this state.

Then the personality-choice sub-flow (not covered by the earlier registration-only pass): east → 陆天抒 (光明磊落 branch) → out → 「阎罗殿」(reincarnation hall, 地藏王) → born 扬州人氏 → landed in /d/city/kedian ("有间客栈"). score afterward correctly shows 性格:光明磊落, correct stats, food/water bars full (§8.9 pattern: confirmed NOT present here, bars start full).

Combat — safe sparring via the training-dummy stat-mirror pattern

cmds/std/fight.lpc's actual logic read first (per AGENTS.md's standing warning against assuming a "safe" NPC without checking the real accept_fight gate): a can_speak-having NPC's accept_fight(me) must return 1 for fight to proceed. d/shaolin/npc/mu-ren.lpc (and an apparently-orphaned identical copy at d/city/npc/mu-ren.lpc — see "observations" below) matches the exact §10.7-documented dummy shape: set("no_die", 1), and accept_fight() deletes its own skills/stats and copies the attacker's own skill map + str/int/con/dex/qi/jing/neili onto itself before the fight starts (a genuine mirror match, not a scripted-weak opponent). Admin-cloned one into the player's current room (clone /d/shaolin/npc/mu-ren) since none of this lib's dummy instances happen to be placed along the 世外桃源→扬州 walking path used above. fight mu ren in a no_fight-clear outdoor room ran a full multi-round exchange (both sides landing and missing hits, HP-state narration escalating normally) and resolved with the player conceding ("这场比试算我输了,佩服,佩服!") — no crash, no stuck state, score/look immediately afterward both correct.

Skill acquisition — organic path AND admin shortcut, both verified

Organic: per the newbie doc's own "gc e n" hint and the board item_desc text in d/city/shuyuan.lpc ("学文化的格式是 learn zhu literate!"), gave money to 朱丹臣 (d/city/npc/zhu.lpc, aliased zhu) via give 10 silver to zhu (money supplied by admin clone /clone/money/silver 20 + give, since a level-14 newbie starts with no cash) → NPC's own accept_object() credited a mark/朱 balance → learn zhu literate → "你听了朱丹臣的指导,似乎有些心得。你的「读书写字」 进步了!" — real accept-logic path, no shortcut, works end to end.

Admin shortcut: cmds/wiz/copyskill.lpc (copyskill <target>) — copies a target's entire skill map + skill_prepare + combat stats onto the caller. Ran copyskill qinfengb from the admin account: "你口中念 念有词,只见一道红光笼罩了你和秦风波。" — no dedicated single-skill grant command exists in cmds/wiz/ (checked the whole directory; the closest is this bulk stat/skill copy), documented honestly rather than assumed.

quit, debug.log, reconnect after a real gap

No new-account quit-deletes-account grace period found in this lineage (unlike the nitan family): logind.lpc's registration chain only calls ob->save()/user->save() once, inside enter_world(), at the very end of the full flow (after gender selection) — by the time a player can even type quit, the account is already durably saved, so there is no partial-registration window to worry about. cmds/usr/quit.lpc read in full: no lockout for wizardp(), and for non-wizards a pker_starttime window is punitive-PK-cooldown design, not a fresh-account grace period.

quit from 「东大街」 (outdoors, mid-conversation with 朱丹臣): dropped one worthless Cloth item as expected content-consistency (§7-adjacent but plainly intentional — "因为这样东西并不值钱,所以人们并不会注意到 它的存在" is a normal drop-message, not an error), printed "欢迎下次再 来!", connection closed cleanly. Both debug.log (driver-level) and work/log/debug.log (LPC-level) checked immediately after — zero new error/crash/access-denied lines beyond the already-documented, pre-existing d/city2/npc/wizer.lpc:22 exert_function() type-mismatch content bug (unrelated to this session, confirmed via grep this bug's own earlier pre-existing note in this same file).

Used the post-quit interval productively (reverted incidental resave noise on data/{login,user}/f/fluffos.o, spot-checked earlier prior-pass fixes — the nosave nosave/protected protected macro rewrite, F_NOCLONE→F_UNIQUE, SSERVER→F_SSERVER — all still intact, grepped 6 sibling same-lineage libs for the same log_file()-missing-assure_file() shape found above (see "cross-lib observation" below), and drafted this NOTES.md section) — then registered a second throwaway character, persisttest/李持久 (female, so the §8.9-adjacent gender-conditional init_new_player() money/combat_exp bonus path got exercised too), specifically to redo the persistence check cleanly (the first attempt, on qinfengb, was invalidated by deleting its own .o save files as part of the resave-noise cleanup *before* actually reconnecting to confirm — logged that mistake so a future pass doesn't repeat it: do the persistence reconnect BEFORE any save-file cleanup, not after).

persisttest quited from 世外桃源, then reconnected after a genuine ~1-2 minute additional wall-clock gap (on top of the several minutes already spent on the interval work above) via a fresh telnet session (real disconnect+reconnect, not a resumed connection): banner printed clean, persisttest + password → recognized as an existing account (no "creates a new person" prompt this time, confirming the id correctly round-tripped through save/reload) → "☆ 您现在是第 二 次光临浴血重生" / "☆ 您上次连线的地址是 127.0.0.1" / "☆ 您上次退出本游戏的时间是:[ 2026年8月7日21点36分 ]" (matches the exact prior quit time) → score showed the exact same character: 中文姓名 李持久, 性别 女性, stats 膂力25/悟性22/根骨18/身法15 (the exact roll accepted at registration), 钱庄存款 二十两白银 and 实战经验 50 (both from the female-branch init_new_player() bonus, confirming user->save()/reload round-trips that data correctly too). Full state persistence confirmed. quited again cleanly, debug.log/work/log/ debug.log both still clean (same pre-existing wizer.lpc content bug only, no new errors).

发现但判定为既有设计、未改动的现象

Cross-lib observation (not fixed this pass — out of scope, yxcs-only pass)

The log_file()-missing-assure_file() shape fixed above in adm/simul_efun/file.lpc is present, unfixed, in every other checked sibling of this lib's ES/XKX lineage (§11): xkx2001, rzrmud, bmxkx2001, kxkj, yueyingqiyuan, wuhanzhan all ship the identical unguarded void log_file(string file, string text) { write_file(LOG_DIR + file, text); }. Whether any of them actually hits the crash live depends on whether their own logon()/registration chain routes through an equivalent cat()-audit-log or other log_file() call before the id prompt (not checked here — that's each lib's own §10.7 pass to make). Flagging for whichever future dive picks one of these up: check work/log/debug.log (not just the driver's own debug.log) for a Wrong permissions ... for append trace through log_file() before assuming registration is clean.

§9 formatter

Ran format-corpus.mjs on both edited files (adm/daemons/logind.lpc, adm/simul_efun/file.lpc) — both reformatted clean, 0 errors. Checked all 3 documented blind spots: grep -rnE ':\s:\s*[a-zA-Z_]+\(' — zero hits in either file; no case-label lines touched by either diff (no manual diff-review needed); grep -rl '\\ n' — zero hits in either file. Re-booted and re-tested the full flow above against the reformatted files (this NOTES entry's own registration/combat/skill/quit walkthrough was run AFTER formatting, not before).

WASM 未验证说明

Per this project's build state this pass: WASM build permanently blocked (emsdk hardcodes storage.googleapis.com, denied by the proxy — confirmed via curl -sS $HTTPS_PROXY/__agentproxy/status). The fixes above (both the new log_file()/assure_file() fix and the logind.lpc counter-file guard) are pure LPC-level runtime-error guards with no WASM-specific code path — expected to apply identically under WASM once a build becomes available, but genuinely unverified under WASM this pass; the earlier WASM-enablement pass's own findings (loopback ban-bypass, admin seeding) are untouched and still apply.

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

针对驱动升级(quest_times/win_times %-operator 修复 + Warning/warning 大小写回退兼容)做的重测。核对上面记录的所有修复(新连线 logon() 崩溃、log_file()、counter-file 防护、宏重写等)逐项确认代码仍然 生效;win_times 的 %-operator 也已用 to_int(query("win_times")) % 5(d/city2/npc/refereew.lpc:146、 d/taoyuan/npc/{jinyong,gulong}.lpc)。

本轮新发现并修复的 PROGRAMMING bug(上一轮 §10.7 深挖未覆盖到)

1. feature/dbase.lpc 的 set() 密码写保护是 tybxjh/wlhd 那一类 已确认的 bug 形状:if (prop == "password") if (wizhood(this_object()->query("id")) == "(boss)") if (this_player()) if (geteuid(this_player()) != this_object()->query("id")) return;——注释明确写着"Add by Lonely to fix a steal-power bug",本意是防止别人冒充覆盖既有 (boss) 级账号的密码,但 wizhood() 纯粹读 wizlist 文件,不检 查 dbase 里是否真的已经存在密码。本轮实测 fluffos 的注册/重 连都正常(这份档案里 this_player() 在密码 set() 那一刻的 euid 恰好已经和目标 id 一致,所以没有触发拦截——和 tybxjh 的具 体触发时机不同,但代码形状完全一致,属于潜在缺陷,不是已经在 本档案上实测复现的活跃崩溃)。按已确立的标准修法加上 mapp(dbase) && dbase[prop],只在密码已经存在时才拦截,不影响 首次创建。 2. §8.9 食物/饮水初始化判断的对象错了——上一轮深挖遗漏: adm/daemons/logind.lpc 的 enter_world() 里 ob->query("age") == 14(应为 user)。已改成 user->query("age") == 14。 3. get_resp()(系统随机中文名接受分支)一处调试残留 printf("%O\n", ob)(AGENTS.md §7.34-class)——上一轮深挖用的是 手动输入中文名分支,没有触发这条泄漏:紧跟在中文名字确认之 后,把连线桩物件的原始引用直接回显给正在注册的新玩家。已删除; get_name()(手动输入分支)本来就没有这个残留,核对确认。

实测过程

管理员 fluffos/Mud@2026(此前深挖已注册并提交存档)用真实密码 重新连线两次(先重启驱动应用上面三处修复,再各做一次独立的登录+重 连验证),落地此前保存的地点,score 显示食物/饮水满格。两个 debug.log 位置(驱动级 log/debug.log 和 LPC 级 work/log/debug.log,本档案自己此前记录过必须都查)全程干净,无 运行时错误。驱动按精确 PID 结束;测试期间产生的存档时间戳增量已 git checkout -- 还原。启动前按此前记录的前置条件手动创建了 log/、work/log/{nosave,wiz} 目录(均已确认被 .gitignore 正确 忽略,非代码问题)。

§7.100 修复(ROOM 基类的同一"多余 replace_program()"形状,全档案扫描第 6 批)

``§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/bgargoyle.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.

§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.

深度功能测试补充 (2026-08-24): shop buy and 拜师 sect apprenticeship — the two flows every prior §10.7 pass on this lib had skipped

Audited the full history above and confirmed neither a shop purchase nor a completed sect apprenticeship had ever been exercised on this lib, despite the newbie doc's own §3 sect-recommendation text implying a real system existed. Closed both gaps this pass, via two concurrent scripts/tmux_mud.sh sessions (admin + a fresh throwaway player qinmaiwu/秦买物, registered end-to-end same as the original pass) so the admin could goto <player> + clone/give money without needing quit-and-restore round-trips.

Shop purchase — found and fixed a real crash bug (vendor.lpc §-class, list/buy at ANY shop with a stale vendor_goods entry)

d/city/zahuopu.lpc (扬州 杂货铺, reachable in 3 moves from the newbie start room: kedian → west → beidajie1 → south → guangchang → east → dongdajie1 → south → zahuopu), NPC 杨永福 (d/city/npc/yang.lpc, inherit F_VENDOR_SALE). First list command thrown by a real player crashed outright: 这里发现了BUG,请用SOS告诉巫师。

work/log/debug.log:

执行时段错误:*call_other() couldn't find object '/u/xiha/fd'.
程式:/feature/vendor_sale.lpc 第 149 行
物件: /d/city/npc/yang#294
呼叫来自:/feature/vendor_sale.lpc 的 do_vendor_list() 第 149 行

yang.lpc's vendor_goods array lists "/u/xiha/fd" as its first entry — confirmed via the raw archive (raw/socket/yxcs/u/xiha/ only ever shipped workroom.c, never an fd.c) that this file never existed at all, not a casing mismatch. feature/vendor_sale.lpc's is_vendor_good(), do_vendor_list(), and (transitively, via is_vendor_good()) do_vendor_buy() all called methods directly on vendor_goods string entries with no existence guard, so this one dead reference broke list (and would have broken buy too, for anyone who managed to name it) for every player at this shop, every time — the exact class already cataloged in AGENTS.md's mohuanshiji precedent ("worth checking as a standing step on any future lib's feature/vendor.lpc-style shop test").

Fix followed this codebase's own existing idiom for the identical problem in the sibling feature/dealer.lpc (file_size(ob[i] + ".lpc") > 1, log the stale entry, skip it rather than crash) — added the same guard to all three loops/lookups in feature/vendor_sale.lpc (is_vendor_good(), and both loops inside do_vendor_list()), logging a vendor_error line instead of throwing. This is a missing-defensive-check programming bug (no existence check before an unconditional -> call), not a content restoration — the dead /u/xiha/fd entry itself was left in yang.lpc's vendor_goods array untouched, matching the give.lpc/ask.lpc QUEST-daemon precedent's remedy of guarding the call site rather than fabricating the missing target.

Verified live after a driver restart: list now prints all 16 real items (skipping the dead entry silently), and buy budai (麻布袋,一 两白银) correctly deducted exactly 1 tael from the player's 20-tael starting balance (二十两银子 → 十九两银子) and added 布袋(Budai) to inventory — real purchase, correct change/inventory math confirmed end-to-end.

Sect apprenticeship (拜师) — clean pass, no bug found

Full recruit/apprentice two-command handshake (cmds/skill/ recruit.lpc + cmds/skill/apprentice.lpc + feature/apprentice.lpc's recruit_apprentice()) read in full first. Picked 丐帮 (newbie doc's own §3 recommendation for 拳脚/unarmed fighters) — specifically 左全 (kungfu/class/gaibang/zuo-qu.lpc, one of the 七袋弟子, reachable from guangchang via enter shudong → /d/gaibang/inhole) since his attempt_apprentice() only gates on gender == "男性" (the simplest of the gaibang roster's per-NPC stat/gender gates — siblings he-bj/ li-sh/ma-jw/yu-hx/liang each gate on a different stat threshold, jian/peng refuse everyone outright).

apprentice zuo (test char already male, 光明磊落 personality) → "你想要拜左全为师" → 左全 accepted immediately (no stat gate hit) → "你跪了下来向左全恭恭敬敬地磕了四个响头,叫道:「师父!」恭喜您成为 丐帮的第二十代弟子。" score before vs. after: 头衔 changed 【布衣平 民】→【叫 化 子】, 称谓 changed 普通百姓→丐帮第二十代弟子, 你的师傅 changed 目前还没有→左全. Full apprenticeship mechanism (recruit/ apprentice pending-state handshake, family mapping population, assign_apprentice() title generation) works correctly end-to-end — no bug found, clean pass.

Formatter note

Could not run the §9 LPC formatter (~/src/fluffos/tools/lpc-syntax/ bin/format-corpus.mjs) this pass — node is not installed/on PATH in this session's shell environment (checked which node, nvm, common install paths; none found). The feature/vendor_sale.lpc edit itself hand-matches the existing codebase's own indentation/brace style (copied directly from the sibling feature/dealer.lpc idiom, no ::, case, or CJK-string edits involved, so the formatter's three known blind spots don't apply here regardless). Flagging for whichever future pass has a working node available: re-run the formatter on this one file and re-verify.

Testing setup note

Two concurrent scripts/tmux_mud.sh sessions (admin fluffos, throwaway player qinmaiwu/秦买物) driven with only ASCII/pinyin commands past the initial Chinese-name registration step (done via a one-shot scripts/mudclient.py call first, per this project's standing tmux-mojibake caution) — no mojibake observed on the ASCII-only in-play commands, consistent with the false-alarm pattern being specific to multi-byte *input* during registration, not general gameplay. Test character's save file was never observed on disk under data/user/q//data/login/q/ despite score/reconnect showing correctly persisted state across the two tmux sessions — most likely a net-dead in-memory reattach rather than an actual disk restore (the first tmux session was never sent quit, just closed); nothing to clean up on disk either way since no qinmaiwu.o file exists. Driver killed by exact PID after testing; both tmux sessions stopped.

§7.19 enable_player() reentrancy fix (2026-09-01)

Corpus-wide mechanical fix (AGENTS.md §7.19, Batch F of 6). feature/command.lpc's enable_player() had no reentrancy guard: NPC init() (e.g. d/shushan/npc/zhangmen.lpc) -> setup()/reset_me() -> enable_player() -> enable_commands(), which can synchronously re-invoke the same object's init() (driver docs BUGS note; live-verified mhxy/wuhanzhan precedent), and revive()/wakeup()/wakeup2() re-invoke enable_player() while already living(), ruling out a bare living() guard. Fixed with the standard in_enable_player_now true reentrancy flag (mhxy's reference fix). Verified via single-file lpcc --batch PASS.

深度功能测试(§10.7,2026-10-05)— here-document terminators

scripts/lpc_fix_heredoc_terminator.py --all --apply: 4 here-document block(s) repaired (2 with the terminator glued to the last text line, 2 with it indented), so End of file in text block no longer hides the room or object behind them: d/heimuya/shenggu.lpc, d/heimuya/tang.lpc, u/ken/b1.lpc, u/ken/tobig5.lpc. The terminator must start its line (the lexer's own test, KB 04 §6.10); a glued one lost its newline in the GBK -> UTF-8 conversion together with a half character, which stays out.

深度功能测试(§10.7,2026-10-04)— paths named in another case

The archive comes from a case-insensitive host: files are stored as BAGUA0.lpc, longjing.C, d/SHAOLIN/, the code names them in lower case (__DIR__ "bagua0", "tea/longjing", "/d/shaolin/..."), so the rooms, NPCs and items behind them could not be loaded (a .C file is not an .lpc file; KB 03 §4.5). scripts/lpc_case_paths.py --convert --apply yxcs: 28 file(s) renamed to lower case (.C -> .lpc, .H -> .h) and 52 path reference(s) in 2 file(s) rewritten to the new spelling; 0 skipped, 0 ambiguous. Load check of the 32 objects that were renamed, edited or name a renamed path (HEAD against the working tree, an object is the same under any spelling of its path): 4 PASS -> 22 PASS, 0 that loaded before fail now, 18 more load.

28 files moved (18 .lpc, 10 .C); mostly under u/lonely/zhuanshi (18), kungfu/skill/kuihua-mogong (7), kungfu/skill/never-defeated (3). A rescan with scripts/lpc_warnings.py yxcs is still due: the renamed files are compiled for the first time.

深度功能测试(§10.7,2026-10-05)— room base survives a raising NPC

scripts/lpc_resilient_room.py --apply: make_inventory() of inherit/room/room.lpc loads each inventory object as if (catch(ob = new(file)) || !objectp(ob)) return 0;. new() of a file that is not there returns 0 (the room just lacks that NPC), but new() of a file whose create() raises (a skill file for set_skill() this archive never had, a carry_object() item that is not there, a header that never shipped) raised inside the room and the room did not load at all. The wrong-case renames of this lib (the section above) make the NPCs behind them reachable for the first time, so a room that holds one with such a content gap would have gone from "NPC missing" to "room missing"; now it loads without that NPC, as it did before. The room base compiles and loads with the change (HEAD against the working tree). KB 03 §4.5.

深度功能测试(§10.7,2026-10-05)— 任务表里的 .c 路径与任务守护进程的防护

scripts/lpc_dynamic_rows.py:d/obj/quest/dynamic_location、d/obj/quest/dynamic_quest 里 86 行写的是原档案的 .c 路径。转档时文件已改名 .lpc,而显式后缀按原样解析,load_object("/d/x.c")、new("/d/obj/quest/x.c") 返回 0 且不报错(KB 03 §4.2,KB 06 §7.220),所以 adm/daemons/questd.lpc 读到的每一行都加载不出来:随机任务和任务物品从未生成,在 create() 里直接对结果调用 tar->set() 的版本还会崩溃,连带加载它的 cron 守护进程和 give 的任务钩子。这些行已改为 .lpc;另有 1 行指向的文件两种后缀都不存在(档案缺内容),保持原样。 scripts/lpc_dynamic_quest_guard.py:3 处 spread_quest() 调用(init_dynamic_quest() 的循环里)包进 catch(),缺失的任务物品或编译不过的房间只跳过那一个任务,守护进程照常加载、其余任务照常生成。 验证:adm/daemons/questd.lpc和 cron 守护进程在新进程里加载(HEAD 一次,工作树三次,选房是随机的):HEAD 通过 2 个,工作树三次分别通过 2、2、2 个(共 2 个),无回退。

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

房间基类 inherit/room/room.lpc:reset() 的 case 1: 拿到 0 就跳过这一项(if (!objectp(ob[list[i]])) break;)。档案里没有的 NPC 或物品(或 create() 出错的物件)原先会让列出它的房间整个加载失败(Bad argument 1 to environment(),或对 0 的 call_other()),连带这个房间后面的区域;现在房间照常加载,只是少了那个物件,下次 reset() 再试(KB 05 §7.25;scripts/lpc_resilient_room.py、scripts/lpc_room_reset_guard.py)。 验证:探针(scripts/lpc_room_reset_probe.py:房间基类列出一个不存在的物件,再调用 reset())HEAD 单件 崩溃、多件 OK,工作树 单件 OK、多件 OK。

深度功能测试(§10.7,2026-10-06)— 与 zhonghua2 同源的三处编译警告

验证:改动的文件和包含 npc/indian 的守护进程在 HEAD 与工作树分别加载(scripts/lpc_listcheck.sh,新进程),无回退。

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

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

深度功能测试(§10.7,2026-10-07)— 被 ; 截断的消息

kungfu/skill/yizhi-chan/yizhi.lpc 第二式的 msg += "…护住身前。"; 后面单独一行"只听「嗤」的一声,掌影顿消,$p已经变得脸色惨白。"——多余的 ; 把消息截成两句,后半句从来没显示过;接回去。

验证:改动的文件在 HEAD 与工作树分别加载(新进程),无回退。

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

scripts/lpc_warnings.py yxcs --fix 加 scripts/lpc_fix_no_effect.py --apply,共改动 1173 个 .lpc 和 22 个 .h(多为删去未用的局部变量)。HEAD 与工作树分别加载(新进程):1125 -> 1125 通过,无回退;改过的头文件的 271 个包含者 267 -> 267 通过。启动时警告 30 -> 0;新进程登录(输入名字)正常。 整库对比的 1 个“回退” /obj/npc/marchial 是随机的:它在 create() 里随机八选一拿兵器,其中 obj/weapon/stick、obj/weapon/sixhammer 在存档里不存在,carry_object() 返回 0 后 ->wield() 出错,四分之一的江湖人载入失败(HEAD 那次碰巧没抽到;d/chaoting/npc/japanese.lpc 同样,这次反过来碰巧通过)。两个文件改用现有的 obj/weapon/club(木棍)与 obj/weapon/hammer(铁锤),此后两者连续 8 次载入都通过。

深度功能测试(§10.7,2026-10-10)— 编译警告整理的剩余部分;28 个“唯一”NPC 从不主动战斗

改动的 84 个文件 HEAD 与工作树各载入一次:84 -> 84 通过,无回退,警告 101 -> 0。

深度功能测试(§10.7,2026-10-11):“无副作用表达式”警告复查

内力/精力当作伤害种类(2026-10-15,KB 06 §7.241 第二类)

本库 feature/damage.lpc 的 receive_damage() 不接受 jingli/neili/force 等种类,me->receive_damage("jingli", 30) 之类在练功、绝招、吸取时报 F_DAMAGE: 伤害种类错误。33 处改为 add(type, -N)(scripts/lpc_fix_damage_calls.py 第二步)。

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

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

东方故事/西游记体系的技能文件(2026-10-15,KB 06 §7.241 第三类)

这些 kungfu/skill 文件来自 gin/kee/sen/force 体系,本库人物只有 jing/qi/neili:receive_damage("kee", 30) 报 伤害种类错误,query("force") 永远为 0,技能学不了也练不了。按 kee→qi、gin/sen→jing、force→neili、max_force→max_neili、force_factor→jiali 改了属性名(scripts/lpc_port_es_props.py),共 8 个文件。

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

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

治疗/疗伤的属性名(2026-10-15,KB 06 §7.241)

receive_heal()/receive_curing() 也只接受本库的种类。5 个文件(多为只调用 receive_heal/receive_curing 的药物、NPC)来自其他体系,按本库的属性名改名(scripts/lpc_port_es_props.py --any-file)。

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

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

技能按另一门武功的等级取招(2026-10-15,KB 06 §7.243)

这些技能文件是从别的武功复制改名来的,query_action() 仍用原武功的等级查招式表:只会本技能的人等级为 0,取不到招,每次出招都报错。改为读本技能自己的等级(scripts/lpc_fix_action_level.py):quanzhen-jian。

招式表最低等级之下没有招(2026-10-15,KB 06 §7.243)

招式表的最低 "lvl" 高于 0(如全部为 100),技能等级未到之前取不到招,每次出招都报错。循环后补 if (!a_action) a_action = action[0];(lpc_fix_action_level.py --fallback):dagou-bang、tiandao-blade。

->query_( 笔误(2026-10-15,KB 06 §7.245)

调用不存在的函数 query_,call_other 静默返回 0,相关判断永远按 0 计算。改为 ->query(:tiandao-blade。

妙手回春的银针检查(2026-10-15)

miaoshouhuichun 的 valid_learn() 用了未赋值的 object ob(ob->query_temp("weapon") 报错),还把兵器对象和字符串 "银针" 比较。改为 ob = me->query_temp("weapon"),再用 id("yin zhen")/id("yinzhen") 判断是否银针。

find_player() 只认在世界里的身体(2026-10-15,KB 07 §8.26)

simul_efun 的 filter_player() 加上 environment(ob):注册中途断线留下的、不在任何房间的身体不再被当成玩家,两个以上时 find_player() 不会再报 The player(<id>) has existed in the world.(wllz3 实测过的问题)。本库若注册流程不会留下带玩家 uid 的身体,这一改动不改变行为。

空手使用兵器绝招(2026-10-15,KB 06 §7.246)

perform 指令允许直接点名招式(如 perform stick.ban),这些绝招读了 me->query_temp("weapon") 却从不检查,空手时 weapon->name() 报错(有的已先扣了内力)。在赋值后补 if (!objectp(weapon)) return notify_fail("你必须手持兵器才能使用这一招。\n");(scripts/lpc_fix_perform_weapon.py):bahuang-qiangfa/throw、bingpo-blade/ningxie、huanhua-jian/snow、huanhua-jianfa/snow、liangyi-dao/sanshen、murong-jianfa/kuangjian、tianyu-qijian/kuangwu。

把经验、属性、内力当技能读(2026-10-15,KB 06 §7.247)

经验、属性、内力上限不是技能,xkx/ES 的 query_skill() 对它们只返回 0(风云的还会去载入同名技能文件而报错)。改为 query("...")(scripts/lpc_fix_pool_as_skill.py):/quest/wudang/song 生成的任务怪物照抄玩家福缘(set("kar", who->query_skill("kar")),怪物福缘一直为 0)。

当前内力、精这类名字有时指的是内功技能,逐处读过后手改:gouyee/heal、yuxuan-guizhen/heal 的疗伤量写成 query_skill("neili") / 5,本库其余疗伤 exert 都是 query_skill("force") / 5,照此改为内功等级(若读内力,疗伤量会大十倍);落英缤纷 luoying-shenjian/lybf:自己的注释说成功率由“精神高低”决定,两处 query_skill("jing") 改为 query("jing")。

碧海生潮曲空手报错(2026-10-15,KB 06 §7.246)

iceforce/roar(碧海生潮曲)先 ob = me->query_temp("weapon"),再直接拿 base_name(ob) 判断是不是玉箫;空手 exert roar 时 base_name(0) 报错,提示“你必须先找一只玉萧来才可以吹--曲”根本出不来。条件前补 !objectp(ob) ||。

iceforce「chillgaze」从未编译通过(2026-10-15)

iceforce/chillgaze 原档在第一个 return notify_fail(...) 后多了一个 },exert() 就此结束,后面的语句全落在函数外,skill、damage 也没有声明,文件编译失败,这个 exert 从来用不了。照 bixiecanyang、hc、xyzx3 已修好的版本删去多余的 }、补上 int skill, damage;,其余字句不变,只是缩进进函数体。

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

query_skill() 里的技能名拼错了,或用的是本库改名前的旧名;本库没有这个技能,调用永远得 0:门槛(< N 就拒绝)永远过不去,相关功夫或绝招学不了、用不了;内功互斥(> N 就拒绝)从不生效;公式里这一项一直是 0。经汉字名(提示文字或中文名词典)或纯拼写差异(_/-、少一个连字符、相邻字母颠倒)核对后,改为本库的技能名(scripts/lpc_fix_skill_typo.py):beimin-shengong→beiming-shengong(guiyuan-dafa、honghua-shengong、tiangang-zhengqi、wangran-xinfa、xiantian-gong);douzhuan-xignyi→douzhuan-xingyi(/d/mr/npc/obj/shu1、/d/mr/obj/shu1);mizongxinfa→mizong-xinfa(longxiang/fanchang);yihua-jimu→yihua-jiemu(yihua-jiemu);yiqi-guanriyue→yiqiguan-riyue(yiqi-guanriyue/heal);yunv-xinjing→yunu-xinjing(wangran-xinfa);zhenfen-xinfa→zhenfeng-xinfa(zfwy-bu);zhengqi-jue→zhengqijue(/d/bwdh/human)。

技能名拼错:技能文件里拼错自己的名字(2026-10-15,KB 06 §7.249)

技能自己的文件(或它的绝招目录)里,query_skill() 读的是差一个字母的自己的名字,永远得 0:“基本功夫要高过本技能”之类的限制从不生效,按等级取招、计算伤害的那一项一直是 0。改为本技能的名字(scripts/lpc_fix_skill_typo.py 的 self 判据):baitao-xuangong→bitao-xuangong(bitao-xuangong);jinggang-quan→jingang-quan(jingang-quan);xuantie-jiafa→xuantie-jianfa(xuantie-jianfa);xuanxie-jianfa→xuantie-jianfa(xuantie-jianfa)。

地图数据库 mapdb 读到只有文件头的 map.o(2026-10-15,KB 06 §7.250)

本库的 data/npc/map.o 只有一行文件头:genmap 第一次载入时 if (!restore()) save();,地图还没建就存了档,值为 0 的变量不写进去。mapdb 的 restore() 读它成功,map 却成了 0,query_room_info()、query_room_exits()、query_map() 都对 0 取下标或把 0 交出去:本库暂无调用者,问题潜伏。mapdb(/clone/npc/mapdb.lpc)加一个 restore():读档后 map 不是映射就重置为 ([]);地图为空时 query_random_room_path() 返回 0。地图本身仍需巫师用 genmap 生成。

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

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

用兵器的绝招空手施展时报错(内联写法)(2026-10-15,KB 06 §7.246)

绝招不存兵器变量,直接写 (me->query_temp("weapon"))->query("name")(或在拒绝判断里写 (weapon = me->query_temp("weapon"))->query("skill_type")),之前又没检查兵器:空手 perform 时报 Bad argument 1 to EFUN call_other(),内力等往往已经扣掉。在第一次用到它的那条语句前补上“你必须手持兵器才能使用这一招”的拒绝(scripts/lpc_fix_perform_weapon.py):yunu-jianfa/suxin。

移进不存在的巫师房间(2026-10-15,KB 06 §7.251)

用完的物品、要“离开”的 NPC、掷在空中的兵器被移进巫师的工作室(/u/llm/、/u/wind/),本库没有这些房间。本库的 move() 用 load_object() 找目的地,找不到就返回 0,不报错,东西留在原处:被雇来打晕或杀人的李凌(d/city2/npc/liling2)办完事后没有离开,留在原地(d/city2/npc/liling2 本身还载入不了:create() 里 carry_object() 的物品文件缺失或编译失败,见 KB 06 §7.73,另行处理);婚礼结束(d/nanyang/npc/meipo 的 last_marry)时月老没有离开喜堂,每办一次婚礼喜堂里就多一个月老;喜宴结束后喜来福(d/nanyang/npc/xi-laifu)没有退回内堂,每办一次婚礼迎宾楼就多一个喜来福。3 个文件改为移进本库的虚空房间 VOID_OB(/clone/misc/void),与原作把它们“停放”在巫师房间的用意相同(haiyang2 的维护者把月老送进 /d/city/empty,也是同样的做法)。

玉女剑法「合壁」用一次就永久改动经验和剑法(2026-10-15,KB 06 §7.253)

收尾的 hebi() 声明时没有参数(void hebi() { object me, target, env; int i, j, o, p, count; ...),call_out 传进去的人和数值全被同名的局部变量(0)挡住,开头的 if (!me && !target) return; 每次都返回:合壁的攻击、闪避加成和 hebi 标记要到重新登录才消失。更糟的是夫妻判断写成了 target->querry("id")(没有这个函数,得 0),没成亲的人 marry/id 也是 0,于是人人都被当成夫妻:自己的玉女剑法和经验乘以玉女素心功的级数/80(至少变成浮点数,160 级以上翻倍),随后给对方 set_skill("combat_exp", ...) 时报 No such skill,收尾的 call_out 也就没排上,乘过的等级和经验永远不还原。测试里用一次合壁,经验 100000 变成 200000.0、剑法 100 变成 200.0。改正:hebi() 按它自己再次 call_out 时传的八个参数声明,perform 的 call_out 去掉多余的 h, k,querry 改为 query,给对方的 set_skill("combat_exp") 改为与上一行一样的 set("combat_exp")。测试里加成照常生效,hebi() 结束时还原并清除标记,没成亲的人经验和剑法不变。

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

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

物品清单把名字的第一个字吃掉(2026-10-18,KB 07 §8.1)

inventory、房间的物品列表(feature/move)和部分 look 把同名物品合并计数,键是 query("unit") + short(),只有一件时按 key[2..] 去掉量词。量词是一个汉字,在原来的 GBK 里占 2 字节,[2..] 正好去掉量词;转成 UTF-8 以后一个汉字只占一个下标,这一刀把名字的第一个字也切掉了(「把长剑」只显示「剑」,带颜色的名字切掉的是转义序列开头)。改为 [1..](scripts/lpc_fix_unit_cut.py):cmds/usr/inventory.lpc、feature/move.lpc、quest/quest_jun/look.lpc。

水潭里 ging_cost 是 jing_cost 的笔误(2026-10-18)

shuitan 先算 jing_cost,倒水时却扣 receive_damage("jing", ging_cost),ging_cost 从没声明过:Undefined variable 'ging_cost',整个物件载入不了。改成 jing_cost:d/shaolin/npc/obj/shuitan.lpc。改后用 lpcc 逐个载入这些对象:1 个通过。

全真心法 valid_learn() 里没声明的 lvl(2026-10-18)

kungfu/skill/quanzhen-xinfa.lpc 的 valid_learn() 判断 me->query("gender") == "无性" && lvl > 49,可是函数里只有 nk、nf、nh、ns 四个变量,没有 lvl:Undefined variable 'lvl',这门心法的文件载入不了,学它、用它都失败。nh 正是全真心法的等级(nh = query_skill("quanzhen-xinfa", 1)),改成 nh > 49。改后用 lpcc 逐个载入这些对象:1 个通过。

补回丢掉的基类宏(2026-10-18,KB 04 §6.13)

inherit F_XXX; 里的宏本库任何头文件都没有定义,报 syntax error, unexpected L_IDENTIFIER, expecting L_STRING or '(',整个对象载入不了;宏指向的基类文件本库其实有,别的库都把这个宏定义成同一个路径。在全局头文件 include/globals.h 里补上:NPC_TRAINEE → /inherit/char/trainee(1 个文件)。(scripts/lpc_restore_macros.py)改后用 lpcc 逐个载入这些对象:1 个里 0 个通过,其余 1 个还有别的错误(d/xingxiu/npc/lingshe.lpc:Undefined function set_color)。

kungfu/skill/qingyi-jian 第一式的 skill_name 丢了收尾引号(2026-10-18,KB 03 §4.6)

"skill_name" : "大悲式, 的收尾引号没了(转码时跟半个汉字一起丢了),字符串连到下一行,damage_type 成了代码:Illegal character 0xe5,整个武功载入不了。补回 ",(同系的 bixiecanyang、syxjl 等库里有完好的同名文件)。载入:通过。

set_skill() 遇到本库没有文件的武功不再抛错(2026-10-18,KB 06 §7.256)

feature/skill.lpc 里的 set_skill()、map_skill()、prepare_skill() 碰到没有武功文件的名字就 error("F_SKILL: No such skill (…)"),调用它们的 NPC create() 整个中断:NPC 载入不了,刷出它的房间也少一个人。本库有 5 个对象设了本库没有文件的武功(10 个名字,最多的是 hunyuan-force、ruyi-blade、taxue-steps)。三处都改成 return:这一门武功不给、不映射,对象照常载入,只是少了它(缺的武功本身仍是内容缺口)。抽样载入这些对象:5 个里 5 个通过。(scripts/lpc_guard_set_skill.py)

补回本库没有的基类文件(2026-10-18,KB 04 §6.15)

下面这些基类本库没有,继承它们的对象(房间、NPC、物品)整批载入不了(inherit XXX; 的宏没定义,或者 inherit "/std/…"; 的文件不在)。同系的库里有同名文件,两库有大量逐字节相同的文件(亲缘关系),所以从那边原样拷来,缺的宏补进全局头文件 include/globals.h:/inherit/weapon/rake(宏 RAKE)←wxddym,4 个对象继承它,抽样 4/4 载入;/std/weapon/archery(宏 ARCHERY)←hxxtjqb,2 个对象继承它,抽样 2/2 载入;/d/xueshan/obj/anqi-jian←hxxtjqb,2 个对象继承它,抽样 2/2 载入;/inherit/room/city1←fqyy2,1 个对象继承它,抽样 1/1 载入。每个基类补回后单独载入、再抽样载入使用它的对象,基类载不进来或者一个用户也载不进来的就撤掉(本库撤掉了它们,不再补)。(scripts/lpc_restore_bases.py)

武功名拼错的 NPC(2026-10-19,KB 06 §7.258)

set_skill("kunlun-shnfa", …)、map_skill("dodge", "shaolin-shnfa") 这样的调用把武功名拼错了:本库没有这个武功文件,有的是拼对的那个。以前这种 NPC 在 create() 里报 No such skill 载入不了;武功缺失时跳过之后它们能载入,可是少了那门武功(set_skill 被跳过,map_skill 映射不到,门派弟子用普通轻功/拳脚)。按核对过的对照表改正,共 23 处、19 个文件:yujiashu→yujianshu(4 处)、yan-fly→yanfly(3 处)、xinxiu-duzhang→xingxiu-duzhang(2 处)、tiaji-jian→taiji-jian(2 处)、kongmingquan→kongming-quan(2 处)、taiji-shenfong→taiji-shengong(2 处)、lingbo-weibu→lingboweibu(2 处)、poyu-qua→poyu-quan(1 处)等共 13 个名字。(scripts/lpc_fix_skill_names.py)

调用了父类没有的函数的对象(2026-10-19,KB 06 §7.259)

::create();、::init();、return ::buy_object(who, item); 这类调用写的是父类里有这个函数的版本;本库的父类没有,旧驱动把它当空操作(返回 0),现在的驱动在编译时就报 Unable to find the inherited function,整个对象载入不了。单独成句的调用删掉,return ::f(...) 改成 return 0;(void 函数里是 return;),与旧驱动的行为一致。共 3 处、3 个文件:::scan()(2 处)、::do_discard()(1 处)。只改了出错原因全是这一类的文件;还带着别的错误(多半是父类本身没了)的文件没动,等父类补回后再看。(scripts/lpc_fix_dangling_super.py)

set_name 的 id 参数传成字符串(2026-10-19,KB 06 §7.260)

set_name("海口大碗", "bowl"); 把物品的 id 写成了字符串,本库的 set_name(string name, string *id) 要的是数组,驱动在编译时报 Bad type for argument 2 of set_name ( string * vs string ),整个物件载入不了;旧驱动不检查参数类型,字符串里照样找得到这个词,物品能用 id 称呼。改成 ({ "bowl" }),共 2 个文件:/d/baituo/npc/obj/bowl.lpc、/d/baituo/obj/bowl.lpc。(scripts/lpc_fix_set_name_id.py)

feature/damage.lpc 丢了 set_ghost()(2026-10-19,KB 06 §7.262)

feature/damage.lpc 里有 int ghost 和 is_ghost(),没有 set_ghost(int i);木人、狼等 NPC 在 create() 里调用它,整个 NPC 报 Undefined function set_ghost 载入不了。从 xkx100 补回这一行函数,受益 NPC 1 个:d/feitian/npc/wolf。(scripts/lpc_transplant_function.py)

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

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

删掉 exert_function(整数)(2026-10-19,KB 06 §7.266)

/d/city2/npc/wizer.lpc create() 里的 exert_function(10); 把整数传给了要字符串的直接调用(让 NPC 闲聊时自己运功),驱动报 Bad type for argument 1 of exert_function ( string vs int ),整个 NPC 载入不了。这是存档里的笔误,不知道作者想传哪个字符串,删掉这一句(只影响闲聊时的运功表现)。chidi 的同一个 NPC 早先就是这样处理的。

区域物件的零碎修正(2026-10-19,KB 06 §7.267–§7.271)

逐个物件与 HEAD 对比载入,没有退步。

RANK_D 对 0 的称呼(2026-10-19,KB 06 §7.273)

adm/daemons/rankd.lpc 的 query_respect()、query_rude()、query_self()、query_self_rude() 里 4 个函数开头补上 if (!objectp(ob)) ob = this_object();。NPC 在 create() 里写 "…" + RANK_D->query_respect(this_player()) + "…"(inquiry 对话、chat_msg),驱动自己跑 reset() 时没有人在场,this_player() 是 0。旧驱动里 0->query("age") 返回 0,称呼走默认分支;新驱动直接报 Bad argument 1 to EFUN call_other(),房间的 make_inventory() 吞掉错误,被打死的 NPC 再也刷新不回来。用 scripts/lpc_reach_census.py --walk 找到(xkx100 的武当弟子、一灯、汴梁书生…);修在守护程序里,不动 1,800 个 NPC 文件。

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

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

补回丢失的标点(2026-10-19,KB 03 §4.6)

转换时丢掉的分号、逗号、引号或文件末尾的 },共 2 个文件,修前 HEAD 载入失败。别的库里同路径的完好副本只比这里少几个标点,按它补回(括号里是那个库):/kungfu/condition/shenzhen_poison.lpc(longyunmeng)、/quest/murong/qlist3.lpc(bixiecanyang)。修后与 HEAD 逐个对比载入:这 2 个物件全部载入,没有退步(scripts/lpc_restore_from_twin.py、lpc_fix_eaten_quote.py --comma、lpc_fix_eof_braces.py)。

旧驱动的类型宽松:缺省参数、无类型形参、数组初始化、class 变量(2026-10-19,KB 04 §6.19、§6.20)

原来的 MudOS 把调用少传的参数补 0、把没写类型的形参当 mixed、不检查变量的声明类型与初始值,也允许变量叫 class;这个驱动在编译时全部拒绝,整个物件载入失败。修了 2 个文件:/u/ken/b1.lpc、/u/lonely/banghui/npc/shi1.lpc(scripts/lpc_round_files.py 的修复轮:调用处补写 0、无类型形参补 mixed、string X = ({...}) 补星号、void 函数的返回值,以及 class 变量改名 pick_class)。逐个文件在 HEAD 和改后载入对比:这些文件里 1 个原来载入失败、现在载入,没有退步。

== !"字符串" 多出来的 !(2026-10-19,KB 06 §7.280)

!"taoist" 是整数 0,x == !"taoist" 就是“x 等于 0”,作者为其余所有人写的那一支永远走不到。具体是:龙女对古墓弟子的机关暗门提示永远给不出来(5 处);孙婆婆的“你去吧”只对 class 没设置的人生效;性别检查(“你不是女的,无法领会其中至阴之理”)永远不拦人,男的照样能学玉女心法。全部改成 != "字符串"(scripts/lpc_fix_not_literal_cmp.py):/kungfu/class/gumu/long.lpc(5 处)、/kungfu/class/gumu/sunpopo.lpc(1 处)、/kungfu/skill/yunu-xinfa.lpc(1 处)。同样的行在 xkx 一系的 35 个库里都有。

x != "a" || x != "b" 和 x == "a" && x == "b":同一个值的比较链永远成立/永远不成立(2026-10-20,KB 06 §7.282)

if (arg != "wan" || arg != "丸") return notify_fail(...) 对任何 arg 都为真,dir == "south" && dir == "north" 永远为假:条件下面的守卫要么永远拦、要么永远不拦。作者要的是“既不是 A 也不是 B”(&&)或“是 A 或 B”(||)。!= 链的 || 改成 &&(仅当条件下面是 return 的拒绝/守卫),== 链的 && 改成 ||(scripts/lpc_fix_cmp_chain.py)。具体是:客栈小二从不拦住付了房钱又往南/往北走的客人;百日十龙丸怎么 eat 都只得到“你要吃什么?”。改动:/d/changan/ca2.lpc(1 处)、/d/longmen/xuehepai/obj/bairiwan.lpc(1 处)。

if (x = 常量):条件里写成赋值的比较(2026-10-20,KB 06 §7.290)

if (arg = "button" || arg = "按钮")、if (!arg || arg = "") return 0;、else if (check = 0 && tempB != ""):把 == 写成了 =,条件的值就是那个常量,分支对所有非零数和任何字符串(连 "" 都算)永远成立、对 0 永远不成立,变量还被覆盖;驱动对此没有任何警告。每一处 = 改成 ==(scripts/lpc_fix_cond_assign.py,共 8 处);其后 x == "a" && x == "b" / x == "a" || "b" 这类被 == 暴露出来的链也随之改成 || 或补全变量(/d/hainan/npc/xianhe.lpc、/d/hainan/npc/xiaohe.lpc、/d/shushan/shanjian.lpc)。改动:/d/hainan/npc/xianhe.lpc(3 处)、/d/hainan/npc/xiaohe.lpc(3 处)、/d/shushan/shanjian.lpc(2 处)。

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

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

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

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

get_config(__MUD_PORT__) 经旧版 runtime_config.h 得到字符串(2026-10-20,KB 06 §7.302)

本库的 include/runtime_config.h 是老 MudOS 的编号(整数设置从 15 起,本驱动从 256 起),get_config(__MUD_PORT__) 读到的是另一项设置(字符串),(int) 又只是编译期标注,于是 socket_bind(fd, LOCAL_PORT()) 报 Bad argument 2 to socket_bind(),版本守护进程 port = get_config(__MUD_PORT__) + VERSION_PORT 是字符串相加。头文件自己的注释写明 get_config(__MUD_PORT__) == __PORT__,所以代码里的这个调用(连同外面的 (int) / to_int())改成了驱动的预定义 __PORT__(scripts/lpc_fix_mud_port.py)。改动:/adm/daemons/versiond.lpc(1 处)、/include/getconfig.h(1 处)。

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

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

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

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

不带参数的指令对 0 调用 efun:不在 wiz / adm 目录里的指令(2026-10-21,KB 06 §7.336)

指令敲成不带参数时,驱动把 0 传给字符串参数;下面的指令第一句就把这个 0 交给 efun,运行时报 Bad argument 1 to ...。它们在 cmds/std、cmds/usr、cmds/bos、cmds/app 这类目录里,上一轮的扫描只看巫师目录。用 scripts/lpcc_bare.py 不登录、在一次 lpcc 求值里以 0 调用 main() 逐个确认后,由 scripts/lpc_fix_bare_arg.py --all-dirs 在第一处使用参数的语句前加守卫:没有 help() 的是 return notify_fail("…\n");。改动(1 个文件,括号里是接住 0 的 efun):/cmds/bos/hf.lpc(find_player)。加载检查 HEAD 与工作树对照,没有退步。

socket:dump_socket_status() 在本库没有(2026-10-21,KB 06 §7.291)

管理员扫描里 socket 指令(/cmds/bos/socket.lpc)编译不了:write(dump_socket_status()); 用的是 MudOS 有、本驱动没有的 efun。2026-10-20 的补丁只按名字找了巫师目录里的同名指令,这一条在 cmds/bos、cmds/hufa、cmds/island、cmds/ser 这类目录里;用 scripts/lpc_add_sefun.py dump_socket_status 在 /adm/obj/simul_efun.lpc 末尾补了一个由 socket_status() 构造表格的 simul_efun(没有 sockets 包的构建,比如 WASM,只打印表头)。指令 HEAD 编译失败,现在通过。

睡袋:/cmds/adm/bag 本库没有,使用者被留在聋哑状态(2026-10-21,KB 06 §7.344)

clone/misc/sleepbag.lpc、sleepbag2.lpc 的 do_sleep() 在设好 block_msg/all、no_get 和房间的 sleeping_person 之后调用 "/cmds/adm/bag"->main(me, "<休息中>")。这条巫师指令只有 hc、tianxiawuxue 带着,本库没有:call_other() couldn't find object '/cmds/adm/bag',玩家之后什么消息也收不到(look 一片空白),十秒后的 wakeup call_out 没有排上,房间一直 no_fight。城里的小贩 xiaofan 卖这个睡袋,没有人在扫描里买过它。bag 的全部内容就是 me->disable_player(msg)(feature/command.lpc 里的 nomask void disable_player(string type),没有权限检查),两个文件都改成直接 me->disable_player("<休息中>");。chidi 上实测:sleep 之后十秒 "你一觉醒来,只觉精力充沛",look 正常(HEAD 上玩家被留在空白屏里,log/debug.log 有 trace)。改动:/clone/misc/sleepbag.lpc、/clone/misc/sleepbag2.lpc。

mapp:全局变量不能写 varargs(2026-10-21,KB 04 §6.28)

varargs mixed m; 和 varargs string *rfile; 是 mapp 指令的两个全局变量,本驱动只允许函数用 varargs(Illegal to declare varargs variable.),指令编译不了。去掉两处 varargs。

香烟 smoke.lpc:do_smoking() 读没赋值的 me(2026-10-21,KB 06 §7.348)

smoke 指令的第一句是 jing = me->query("jing"),me 声明了没赋值,每次抽烟都抛 Bad argument 1 to call_other()。补 me = this_player();(后面的 this_player() 调用不变)。改动:/d/emei/user-room/melodies/smoke.lpc。

注册到不存在函数的 add_action(2026-10-21,KB 06 §7.349)

add_action("函数", "动词") 绑定的函数,在对象本身、它包含的头文件、它继承的父类和继承它的子类里都没有定义(scripts/lpc_scan_callout_targets.py 静态解析,子类用传递闭包复核,scripts/lpc_verify_handlers.py 运行时 function_exists() 复核)。驱动从玩家最新的一条动作往回找,遇到这样的句子就报 *Function for verb 'drop' not found.,同一个动词的其他处理函数不再尝试(不是最新的一条就悄悄跳过)。删除了 69 条注册(42 个文件,scripts/lpc_fix_dead_add_action.py),动词留给别的处理函数:/d/city/chatroom2.lpc(do_jump)、/d/city2/qishi.lpc(do_pass)、/d/city3/npc/sister.lpc(do_vendor_list)、/d/feitian/npc/biguqing.lpc(do_accept)、/d/gumu/duanchang.lpc(do_no、do_tiao、do_yes)、/d/quanzhen/npc/haodatong.lpc(do_decide)、/d/quanzhen/npc/mayu.lpc(do_decide)、/d/quanzhen/npc/qizhicheng.lpc(do_decide)、/d/quanzhen/npc/sunbuer.lpc(do_decide)、/d/quanzhen/npc/wangchuyi.lpc(do_decide) 等共 42 个文件。最多的函数名:do_send 15 处、do_quit 14 处、do_decide 7 处、do_ride 7 处、do_unride 7 处。

基类的 add_action 登记:处理函数只在后代里定义,基类自己被加载时报错(2026-10-21,KB 06 §7.349)

房间、NPC、公告板这类基类,init() 里登记的 add_action("函数", "动词") 的函数只由继承它的后代定义;基类对象自己被直接加载(房间可以走进去、NPC 可以克隆)时,访客输入这个动词,驱动报 *Function for verb 'x' not found.(第一轮扫描把这些当成“有后代定义,是活的”放过了,scripts/lpc_verify_handlers.py 在基类对象上跑 function_exists() 才看出来)。登记前加 if (function_exists("函数", this_object(), 1))(第三个参数 1:默认 function_exists() 把 protected / private 函数当作没有定义),后代照常登记。共 6 处、1 个文件(scripts/lpc_fix_dead_add_action.py --guard):/d/bwdh/kantai.lpc(do_abandon、do_practice、do_study)。

对象路径里的 ..:new(__DIR__ "../obj/x") 报 Read access denied(2026-10-22,KB 06 §7.351)

__DIR__ 是当前文件所在目录(带结尾斜杠),__DIR__ "../obj/x" 就是 /d/zhiye/npc/../obj/x;驱动的 legal_path() 不接受带 .. 的路径,new() / load_object() 直接抛 *Read access denied.(实测,find_object() 对它答 0)。走库自己的 carry_object() / 房间 objects 表的路径,库的基类会先规范化,能用;直接把路径交给 new() / clone_object() / load_object() / move() 的不行,调用到那一步才报错。改成规范化后的绝对路径(scripts/lpc_fix_dotdot_dir.py --direct):/d/wudang/npc/xiaocui.lpc(__DIR__ "../obj/nuerxiang" → "/d/wudang/obj/nuerxiang")。

缺失物品的 new() / carry_object() 调用链加了保护(2026-10-22,KB 06 §7.73 补充)

new(路径)->move(...); / carry_object(宏("x"))->wear(); 这类语句,路径指向的文件在这个压缩包里没有:new() 返回 0,->move() 在 0 上报 Bad argument 1 to EFUN call_other()。在 create() 里这个对象永远加载不了,在 reset() 里第一个缺失物品之后的刷新每次 reset 都被跳过。2 个文件里 4 处(new)改成 { object new_ob = new(路径); if (new_ob) new_ob->move(...); }(scripts/lpc_guard_carry_object.py --new:路径按这个文件自己看到的宏解析,宏名冲突、虚拟对象路径一律跳过)。 对这 2 个改动文件做加载检查(HEAD 与工作区对比):HEAD 能加载 2 个,现在 2 个(新增可加载 0 个,回归 0 个)。

调用了、但这个库自己的守护进程里没有的函数(2026-10-22,KB 06 §7.354)

MACRO->函数() 调用的函数在这个库的守护进程里不存在:call_other() 对不存在的函数不报错、只返回 0,所以这些功能(时间显示、昼夜事件、名字检查、价格文字……)一直没起作用。同一血统另一个库的同名守护进程里有这些函数,原文照抄到本库守护进程末尾(scripts/lpc_port_function.py;调用处传的参数个数、函数体用到的函数 / 全局变量 / 宏 / 字符串键都在本库里有,已核对;守护进程在 HEAD 和工作区都能加载,每个函数用固定参数各调用一次:HEAD 返回 0,现在返回正常的值):/adm/daemons/chinesed.lpc ← fengyun434:check_control()(1 处调用)、check_length()(5 处调用)、check_return()(1 处调用)、check_space()(1 处调用)、check_chinese()(1 处调用)。

(: 函数 :) 指针指向对象自己没有定义的函数(2026-10-22,KB 06 §7.355)

item_desc / inquiry / chat_msg_combat 里的 (: 函数名 :) 指向本对象(含包含文件、继承的父类)没有函数体的函数:编译不报错,用到时驱动报 *Undefined lfun pointer called: 函数名(look 某物、ask NPC about 话题 直接出错,战斗 / 闲聊里的指针在 NPC 的 chat() 里出错,这一拍心跳的后半段被跳过)。scripts/lpc_scan_callout_targets.py --kinds=lfun。 还剩 19 个函数没有补(inquiry 12, item_desc 5, chat_msg 1, other 1):原型还在函数体丢了、或者根本没写过,没有可以直接补回的捐赠(别的库同一路径的文件里没有这个函数,或者它还要用本库没有的辅助函数、签名不同),不编造:/d/chaoting/bingying/npc/zhiqin_bing.lpc:back_home、/d/city/npc/hua_girl.lpc:ask_me、/d/city/npc/zhuziliu.lpc:give_job、/d/city/npc/zhuziliu.lpc:task_ok、/d/feitian/npc/luo.lpc:kungfu_asked1、/d/feitian/npc/shiren.lpc:away、/d/goathill/npc/obj/dead_leech.lpc:eat_tonic、/d/npc/guojing.lpc:ask_job、/d/npc/guojing.lpc:ask_gonglao、/d/npc/guojing.lpc:ask_fangqi 等另外 9 个。

log/ 下的日志子目录没有人建:写日志的 write_file() / log_file() 报错(2026-10-22,KB 06 §7.358)

这个库的代码往 log/ 的 2 个子目录写日志:log/cmds(cmds/wiz/clone2.lpc)、log/doc/register(cmds/usr/helpbbs.lpc)。压缩包、git clone 和站点包里都没有这些目录(本地启动没有写过它们,gen_keep_dirs.py 没记),write_file() 对不存在的目录抛 *Wrong permissions for opening file /log/dlog/money for append. "No such file or directory",调用它的函数在写日志那一行中断,后面的奖励、标志、步骤都没有执行。本库的 log_file() 会自己建目录(实测,或读源码:nitan 系的 assure_file()),所以这里只记了直接用 write_file() / save_object() 写的目录。把 log/cmds、log/doc/register 记进 scripts/wasm_keep_dirs.txt(scripts/lpc_keep_log_dirs.py;站点和 pristine 树按它建空目录)。证明(scripts/lpcc_eval.py,在 /adm/daemons 这类目录下的求值对象里写 /log/zzdirprobe/...,新进程)见 KB 06 §7.358 的实测表。

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

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

写死的 "/路径"->函数() 指向库里没有的文件:改成现存的同名文件(2026-10-22,KB 06 §7.359)

1 处语句级的 call_other 字面量路径,库里没有这个文件(区域改了名 / 大小写不对 / 差一个字母 / 文件挪了地方):"/cmds/skill/skills"->skill_level()(/quest/quest_jun/look.lpc)→ "/cmds/usr/skills"。call_other() 对不存在的对象抛 couldn't find object,所在函数当场中断。改成库里现存、并且定义了被调用函数的文件(scripts/lpc_fix_call_path.py;巫师目录、备份目录、名字不同的兄弟文件都不算候选)。

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

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

本库 21 处(16 个文件):拼名字的赋值 13 处、与汉字常量比较 8 处。例:name[0..1] → name[0..0](/d/xuedao/npc/suixi.lpc:102);name[2..3] → name[1..1](/kungfu/class/emei/jingxin.lpc:101);name[0..1] == "慧" → name[0..0] == "慧"(/kungfu/class/shaolin/cheng.h:108)。scripts/lpc_fix_gbk_slice.py 把下标按字符重算(社区的 UTF-8 版 xkx100utf8 里就是同样的写法,作对照);没有改的:截断(name = name[0..7],现在最多 8 个字,只是放宽)、ASCII 的区间(fname[0..3] == "room"、ctime(time())[4..19])和上下文看不出是汉字的区间。证明(scripts/lpcc_eval.py,bixiecanyang;其余各库是同一份文本):让澄字辈掌门 attempt_apprentice() 一个名叫「张三」的访客,HEAD 的法名是 慧,改后是 慧三;抽样 28 个库的 HEAD / 工作树加载对比 0 退步。工具不幂等([0..3] 折半得 [0..1],又是对齐区间),改过的文件记在 scripts/gbk_slice_converted.txt,不要重跑。

长度检查按字节写,旁边的提示按汉字写:24 处(2026-10-22,KB 06 §7.362)

老档的 strlen() 数字节(一个汉字 2 字节),转成 UTF-8 后它数字符:提示写「必须是 2 到 6 个中文字」的检查还是 strlen(name) < 4 || strlen(name) > 12,于是两三个字的房名、帮会名、群名、聊天室名、称号被提示自己说允许的那句话拒绝,上限却是提示的两倍;留言板的标题检查 i < 4 || i > 24 || i % 2 还会拒绝所有奇数个字的标题(post 你好吗)。本库 24 处(12 个文件):if ((strlen(name) < 2) || (strlen(name) > 12)) {(/cmds/skill/meskills.lpc:588);if ((strlen(name) < 2) || (strlen(name) > 20)) {(/cmds/usr/buildjob.lpc:71)。scripts/lpc_fix_strlen_gate.py 以提示为准:条件里每个 strlen 门槛都恰是提示所说数字的两倍才折半,存长度的变量(i = strlen(arg);)的门槛和 || i % 2 奇偶项、其后循环的 i % 2 == 0 && 一并处理;提示里有英文 / 字母 / 字节的不动。证明(scripts/lpcc_eval.py,bxsj 的留言板,求值对象继承 NPC 并重写 edit() 记录调用,command("post 标题")):HEAD 拒绝「你好」和「你好吗」、放行 23 个字的标题;改后接受前两个、拒绝第三个;shenmo 的 named.lpc invalid_new_name("张三"):HEAD 回 名字只能是2-4个中文字。,改后回 0。抽样 24 + 15 个库的 HEAD / 工作树加载对比 0 退步。

按字节写的汉字循环、茶馆猜诗和同盟频道标题(2026-10-23,KB 06 §7.363)

老档按字节做「一个汉字」:while (i--) if (i % 2 == 0 && !is_chinese(name[i..<0])) 只检查偶数下标,奇数位上的拉丁字母(张a)会过;茶馆猜诗 mixup() 用 strlen(str)/2 再 j=j+j、str[k..k+1] 交换两字节;泥潭系 channeld 的 switch (strlen(fname)) case 4/6/8/10 和 strlen(family)==4/6 按字节长度给同盟 / 门派名加空格。本驱动的 strlen() 和区间都按字符算。scripts/lpc_fix_byte_char.py:去掉奇偶项、把区间改成 name[i..i],按字符重写 mixup() 并把 strlen(first)>=14 折成 7,频道标题的 case / 门派长度改成字符数(对照 aoxiangtianji)。本库 汉字循环 / is_chinese 区间 16 个文件。证明(scripts/lpcc_eval.py):sjplii 的 check_legal_name 在 HEAD 接受「张a」、改后拒绝,两边都接受「张三」;xkx100 的 clubpoem->mixup("离离原上草") 得到「离离原草上」(真交换汉字);nitan_san 两字同盟名得到 【 兄 弟 】。关键对象加载通过。

血条 / 表情标题按字节算显示宽度(2026-10-23,KB 06 §7.365)

老档把汉字当两字节:bar_string[0..(val * N / max) * 2 - 1] 把「格数」换成字节下标,半格血条在本驱动(按字符算区间)上会整条画满;巫师表情 edemote 的 repeat_string("─", 13 - (strlen(emotion) / 2)) 也会少减汉字宽度。scripts/lpc_fix_display_pad.py:去掉 CJK 血条 / 空白条上的 * 2(jings/qis 赋值和 blank_string3[0..(23-a)] 的 23→11 一并改),表情标题去掉 / 2;ASCII 空格的 none_string / empty_string 仍保留 * 2(一格两个空格)。本库 2 处(1 个文件)。证明(lpcc_eval.py hhsj):tribar_graph(6,9,12) 在 HEAD 画出整条 12 个■,改后为 6 个■+3 个□;麻将 strlen(tempB)/2 是两字符牌码,未改。

Beyond 出口仍指向 /u/beyond(2026-10-23,KB 06 §7.368)

宁波 / 苏州 / 慕容等区域已进 /d/ningbo、/d/suzhou、/d/mr、/d/hz,出口与任务物路径仍写 /u/beyond/…。scripts/lpc_fix_beyond_exits.py 在目标 .lpc 存在时改写(murong→mr)。本库 1 处。证明:sjplii xikou HEAD 西向 /u/beyond/ningbo/aywsi,改后 /d/ningbo/aywsi 可加载;bxsj hubian1 三向均可加载。

死巫师出口 gold/dock、sunrise、mei(2026-10-23,KB 06 §7.370)

/d/wanjiegu/road4 东向 /u/g/gold/dock、峨眉寿星居南向 /u/xinyue/sunrise_room、玩家卧室通往 /u/mei/… 均无对应房间。scripts/lpc_fix_drop_dead_u_exits.py 删除这些出口行,并去掉同方向的 create_door(否则 create_door 无出口会炸)。本库 1 处。证明:zxty08nxgbb 的 road4 HEAD 有东向,改后没有;mei_room1 可加载。

中文名 / 验证码仍按 GBK 取「两字节一字」(2026-10-23,KB 06 §7.373)

pname = pname[(random(sizeof(pname)) & 0xFFFE)..<1]; pname = pname[0..1]; 在按字符计下标时会取出两个汉字。scripts/lpc_fix_pname_slice.py 去掉掩码并把收尾改成 [0..0](pname/pname2/sec_name/str/str1)。本库 8 处。证明:nt1 生成名长度 2–4;HEAD 常见 3–5。

example/book 注释折行无法加载(2026-10-27,KB 04 §6.25 Also)

obj/example/book.lpc 的 // name of the skill 等注释被折行,下一行 the skill 成了裸标识符,驱动报 unexpected L_IDENTIFIER。用手足 sjsh 完好副本覆盖。证明:HEAD 加载失败;改后加载成功。

hanbing `random 反引号(2026-10-27,KB 04 §6.25 Also)

hanbing-mianzhang / hanbing-mianzhang2 在 random( 前多了一个反引号,驱动按模板字面量读到 EOF。删掉。证明:HEAD 失败;改后加载。

深度功能测试(2026-10-27,§6.25 ZHAOSHI 截断玩家技能)

玩家自创武功在 // ZHAOSHI : 0 处截断(EOF),无法加载。按同系完整 moming-blade 补一招 + valid_*/query_*/practice(4):kungfu/skill/liuyun-sword.lpc, kungfu/skill/mytest-unarmed.lpc, kungfu/skill/mtquan-unarmed.lpc, kungfu/skill/mytest-sword.lpc。

深度功能测试(2026-10-27,§6.25 d/city/sj 去引号)

d/city/sj 整文件去引号(add_action(do_out, out) 等);按 jhfy 完整副本替换。

深度功能测试(2026-10-27,§6.25 tell_object 缺 me(自动放弃/愿否))

一参 tell_object("…") 在已有 me 时改为 tell_object(me, "…")(city.lpc, city1.lpc)。证明:抽样 city / xiaolongnv 加载。

深度功能测试(2026-10-27,§6.25 bahuang throw 缺 me)

kungfu/skill/bahuang-qiangfa/throw 一参 tell_object 补 me。证明:改后加载。

深度功能测试(2026-10-27,§6.25 one-arg message_vision)

message_vision("…") 补第二参(me / TP / this_player())。

深度功能测试(2026-10-27,§6.10 未知 pragma save_binary/optimize)

删除本库中 FluffOS 不认的 #pragma save_binary / #pragma optimize… 行。