Ultimate Hell: Ai Ruo You Lan

✅ 可玩

终极地狱之爱若幽兰

zjdyaryl

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

▶ 开始游玩 · Play Now

游戏登录后自报家门为"地狱泥潭---爱若幽兰"(压缩包标题为"终极地狱之爱若幽兰"),属于 ES II → XKX → "地狱"(Hell/Doing 血统)引擎家族,与 `hell`、`zjdy2008wzb`、`zjdywzb`、`zjdyzj`、`zjmudhell` 共六个档案共享同一个门派江湖世界(逐字节地图比对显示与 `zjdy2008wzb` 高达 95% 一致,与最近的姊妹版 `zjdyzj`(指间MUD版)也有 94% 一致——两者 master 文件内容几乎完全相同,与 `zjdywzb`、`zjmudhell` 则更疏远、约 73-79%),是同一份原作世界反复重制的六个版本之一而非各自独立的游戏;与 `zjdyzj` 不同,本作保留了普通 telnet 注册流程而没有接入手机客户端专属协议层,也和名字同样带"终极地狱"字样、但内容完全不同的 `zhongjidiyu` 没有任何关系,只是名字碰巧相似。

English

Introduces itself in-game as 'Hell's Quagmire — Ai Ruo You Lan' (the archive's own title is 'Ultimate Hell: Ai Ruo You Lan'). Part of the ES II to XKX to 'Hell' branch of the engine family, and part of a six-way 'Hell'/Doing-lineage map family with this collection's hell, zjdy2008wzb, zjdywzb, zjdyzj, and zjmudhell — a byte-level, line-ending-normalized room-tree comparison found it 95% identical to zjdy2008wzb and 94% identical to its closest sister zjdyzj ('Fingertip MUD' edition, sharing the same 'Hell' engine core down to near-identical master-file content), with that same map only ~73-79% identical to zjdywzb/zjmudhell — one shared authored wuxia world reused across all six builds, not a handful of coincidentally similar titles. Unlike zjdyzj, this build keeps a plain telnet registration flow rather than a mobile-client protocol layer. Not the same game as zhongjidiyu, another archive in this collection that also happens to carry 'Ultimate Hell' in its name.

README

内容亮点

在线试玩

https://mudlibs.fluffos.info/zjdyaryl/

管理员账号 / Admin account

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

本地运行

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

游戏端口:40073。

NOTES · 移植与修复记录

终极地狱之爱若幽兰 (Ultimate Hell: Love Like Orchid) — archive #79

Source archive: archives/终极地狱之爱若幽兰1.166正式版.rar Slug: zjdyaryl (matches the archive title; no discrepancy — the config's own name field is №㊣地狱泥潭---爱若幽兰㊣№......, i.e. "地狱泥潭" (Hell Nitan/Swamp) + "爱若幽兰" (Love Like Orchid), matching the archive title exactly). Port: 40073.

Real mudlib root: the archive's top level is 终极地狱之爱若幽兰1.166正式版/, containing:

Lineage: confirmed ES II → XKX → "hell" fork via adm/single/master.lpc's own header credit chain: "for ES II mudlib / original from Lil / rewritten by Annihilator (11/07/94) / modified by Xiang for XKX (12/15/95) / updated by Doing Lu for hell (2K)", and adm/daemons/securityd.lpc's matching "Modified by Xiang for XKX / Updated by DOing Lu for ULTRA HELL". Same adm/single/{master,simul_efun}.lpc + adm/daemons/* "Century"-style layout as es1_win/esI/xkx2001/rzrmud/bmxkx2001/ kxkj/yueyingqiyuan/wuhanzhan/yanhuangwuhun/haiyang2/ kxkj1/xuanjianlu/shenzhou/shenmo. NOT related to the nitan/NT/Lonely lineage despite "泥潭" appearing in the display name — that word is just part of this fork's own branding ("Hell Swamp"), not a signal of the NT/nitan/Lonely engine family; confirmed via feature/ dbase.lpc (real local set/query/delete methods, not the bare simul_efun dbase-sharing architecture bug of §15).

CROSS-CHECK FLAG for the main session: archives #78 (终极地狱.rar) and #80 (终极地狱-指间mud版服务端.rar) share the "终极地狱" name and were being processed by sibling agents concurrently with this one — could NOT cross-check lineage/duplication against them here. Per this project's repeated experience (documented many times in TODO.md — sjpl2 vs shujian2008, xianlvqiyuan vs xlqy_new2007, kxkj1 vs kxkj, etc.), similar/identical Chinese titles are NOT a reliable lineage signal — verify via diff/md5sum on core files (master.c, chinese.c, securityd.c, logind.c) once all three archives are done, rather than assuming they're the same game or unrelated just from the shared name.

Fixes applied

Proactive (applied before first boot, from the AGENTS.md catalog)

1. §15h is_chinese() (adm/simul_efun/chinese.lpc) — GBK byte-range check (str[i] < 176 || str[i] >= 248, paired-byte loop) replaced with a CJK Unified Ideographs codepoint range check (0x4e00..0x9fff), one character per index. Standard fix; this WAS the blocker for real registration in every earlier-processed lib until §15h was discovered. 2. §15h deep named.lpc fix (adm/daemons/named.lpc) — this lib has the full "nitan-family-shaped" deep pattern despite not being nitan lineage: - PATH(name) macro: name[0..1] (first GBK byte-pair) → name[0..0] (first character). - strlen(name) < 2 (×3 call sites: remove_name, who_is, invalid_new_name's initial null-check) → strlen(name) < 1. - invalid_new_name's combined-length gate strlen(name) < 4 → < 2. - Sliding-window substring checks: name[i..i+3] (4-byte/2-char window) → name[i..i+1]; name[i..i+5] (6-byte/3-char window) → name[i..i+2]; loop bound i <= l - 4 → i <= l - 2; inner guard i + 6 <= l → i + 3 <= l. 3. §15h logind.lpc check_legal_name — byte-width bound maxlen halved (strlen(name) > maxlen → > maxlen / 2; lower bound < 2 → < 1), plus the separate combined surname+given-name length check (strlen(fname) < 4 → < 2) in get_name(). Both match the in-game prompt text exactly ("不要超过两个汉字" = max 2 characters; "姓和名的组合至少要有两个汉字" = combined min 2 characters). 4. §14 valid_override 3-arg upgrade (master.lpc) — added the main_file parameter and an main_file == SIMUL_EFUN_OB/MASTER_OB check, insurance for any efun::-override fragment #included into simul_efun.lpc/master.lpc rather than being that file itself. 5. §8d/§15o get_include_path() (master.lpc) — was completely absent; added the standard "prepend the compiling file's own directory" implementation so mid-connection lazy compiles of any same-directory #include resolve correctly (compile-time-only/preload compiles already work via the config's include directories, but a live compile triggered from inside a connection needs this apply). 6. §15n securityd.lpc custom-ACL allowlist — this lib has a genuinely custom exclude_read/trusted_read ACL (not the simpler find_object(SECURITY_D)-only master.lpc pattern), so added the standard switch(func) { case "load_object": case "recompile_object": case "include": return 1; } early-allow to valid_read() before any euid/status logic — compiling/including code should never be gated by a fresh, not-yet-authenticated connection's (player) ACL status. 7. §15p dns_master preload exclusion — /adm/daemons/network/ dns_master was present in adm/etc/preload; commented out (the master.lpc's own update_file() already strips #-prefixed lines, confirmed by reading it before relying on the comment-out). 8. §15ae command_hook private bug — feature/command.lpc declared its central add_action dispatch hook as private nomask int command_hook(string arg). This driver treats private as hidden from add_action's external dispatch once inherited into another object (the player body class here) — would have silently broken every post-login command (including look) with zero visible error anywhere. Dropped private, kept nomask. Confirmed via testing this was the single most important fix — verified look/score/i all actually dispatch and produce real output, not silence. 9. §15w log_error() warning-spam gate (master.lpc) — applied proactively as insurance: gated the player-facing broadcast (efun::write/tell_object) on the message NOT containing "warning:", so ordinary compile warnings (e.g. the nosave-function warnings from fix #10 below) don't spam a connected wizard-level player during any lazy compile. Everything still gets logged to /log/log unconditionally.

Found reactively (boot + lpcc sweep)

10. §3 static→nosave blanket sed, and its counterexample — convert_lib.sh's automated pass touched 128 files. As expected from the moniHuafu precedent, this lib ALSO uses a "static/xxx" naming convention extensively — both as log_file("static/XXX", ...) paths (a REAL /log/static/ directory ships in the raw archive) and as dbase property-key namespacing (->query("static/marry"), ->query("static/sadly"), etc — internally self-consistent either way, but reverted anyway for clarity/no-surprises). Found 51 files with "nosave/... string-literal corruption after the sed; reverted all of them back to "static/... with a scoped quote-anchored sed ("nosave/ → "static/), verified zero remaining "nosave/ hits afterward. feature/treemap.lpc's nosave nomask (originally static nomask) function declarations compile fine — no ordering/collision issue there. 11. §15s message()-wrapper crash (adm/simul_efun/message.lpc) — the local message(mixed arg, string message, mixed target, mixed exclude) override forwarded straight to efun::message(...), but tell_room()'s common 2-arg form (tell_room(room, msg), no exclude) leaves exclude at its varargs default of raw int 0, which this driver's real message() efun rejects (Expected: object, array, Got: int(0)). This crashed every do_channel() broadcast at preload time (channeld.lpc → message() → simul_efun's message()) — 8+ daemons hit it during preload alone (natured, punishd, storyd, eventd, memoryd, backupd, ftpd, cpud, questd). Fixed once at the shared root: normalize exclude to ({}) when it's neither an object nor an array before delegating to the real efun. Confirmed fully resolved — zero Bad argument 4 to EFUN message() errors in a fresh boot after the fix (down from ~10 per boot before it). 12. §2 .c→.lpc rename-width bug ([0..<3] → [0..<5]) — found 5 genuine sites (all listing/stripping a *.lpc-glob'd filename's extension): adm/daemons/storyd.lpc, adm/daemons/eventd.lpc, adm/single/importer.lpc (one of its two [0..<3] sites — the sprintf("...item/%c/%s", ..., item_name[0..<3]) one, explicitly commented "去掉后面的 .c 字样" / "strip the trailing .c"), and adm/npc/luban.lpc (2 sites, both stripping a player-built room's .lpc filename before a DBASE_D->clear_object() call). Left alone: importer.lpc's OTHER [0..<3] site inside get_user_list() — that one strips a DIFFERENT, unrelated (2-char, .o-shaped) save-data filename extension, not something our .c→.lpc rename touched; it's part of a legacy migration tool not on the registration/gameplay path, so left as pre-existing (possibly already buggy, out of scope). 13. §15b is_killing() type mismatches (direct calls passing an object where the function declares string id, only caught by this driver's static type checker on DIRECT calls, not ->-based call_other): - clone/user/user.lpc's accept_kill(object ob) — is_killing(ob) → is_killing(ob->query("id")). This is the player body class — broke make_body() silently, exactly matching this bug's documented signature (registration completes through gender selection, then the character never actually lands, with zero visible error). Confirmed by testing: after the fix, both test runs reached the actual starting room. - d/city/npc/guidao.lpc's ask_me() — is_killing(who) → is_killing(who->query("id")) (a quest/story NPC, not on the critical registration path, but fixed anyway since it was found via the sweep). 14. New §8g-shaped shared-root bug: inherit/misc/quest.lpc's set_information() parameter too narrowly typed — declared void set_information(string key, string info), but QUEST_D's own real set_information(object qob, string key, mixed info) already accepts (and many quest files pass) a function pointer (e.g. set_information(NPC_NAME, (: ask_npc :))) as the "info" — this thin wrapper's own narrower string info parameter rejected every such call with Bad type for argument 2 ( string vs function ). Fixed at the single shared root (info retyped mixed), resolving 7 quest clone files at once: supply, explore, capture, deliver, judge, shen, search. 15. Genuine pre-existing typos found via the lpcc sweep (none related to encoding/rename — confirmed by checking the raw archive): - inherit/condition/damo.lpc had two independent bugs in one file, both cascading into confusing-looking downstream noise: (a) line 215, return name + HIM "发作身亡了; — missing closing " before the semicolon. This single dropped quote swallowed ~13 lines of subsequent code as string-literal content, surfacing as a "syntax error, unexpected L_IDENTIFIER" at a COMPLETELY different line (228) and "Illegal character 0xe9/0x95/0xbf" errors at yet another line (281) that are actually perfectly valid UTF-8 bytes for 长/长/的/吁 — pure lexer-desync fallout from the one missing quote, not real illegal-character bugs (matches §9/§10's documented cascading-noise pattern exactly). (b) line 228 itself, independently: intp(cnd["remain"] || ! stringp(cnd["id"])) was missing a ] — intp() was being called with a whole boolean OR-expression as its argument instead of just cnd["remain"]; fixed to intp(cnd["remain"]) || ! stringp(cnd["id"]). Fixing both resolved this file plus its 3 sibling clones (kungfu/condition/ damo_luanqi, damo_shangshen, damo_zheyuan, all of which inherit it) — 4 files from 2 bugs in 1 shared file. - kungfu/class/generate/girl.lpc:579 — query_per() called with 0 args where feature/attribute.lpc's int query_per(string arg) requires 1 (the parameter is never actually used in the function body, and every OTHER of the 5 real call sites elsewhere goes through ->query_per()/call_other, which this driver's strict arg-count check doesn't enforce the same way as a direct call). Fixed by passing 0 explicitly. - d/village/npc/obj/shoes.lpc — a set("icon","05047"); statement got accidentally interleaved mid-argument into a set("long", ...) call (set("long", \n set("icon","05047"); \n"这是...");), splitting one statement into a syntax error. Reordered so each set() call is complete on its own. - d/baituo/obj/bowl.lpc + d/baituo/npc/obj/bowl.lpc (identical duplicate content shipped in two different zone directories) — set_name("海口大碗", "bowl") passed a bare string where set_name(string name, string *id) requires an array; fixed both to set_name("海口大碗", ({ "bowl" })).

Confirmed NOT needed (checked, absent)

Confirmed harmless, left unfixed (documented, not chased further)

Verification

Boot: ~/src/fluffos/build-debug/src/driver config.fluffos from libs/zjdyaryl/, port 40073. Clean boot, Accepting telnet connections on 0.0.0.0:40073. Initializations complete. — zero fatal errors, only the one known-harmless versiond.lpc socket_bind() line in debug.log (present on every boot, before and after all fixes).

Full registration + post-login flow, verified in two separate driver sessions, each a SINGLE continuous mudclient.py connection:

lpcc_check.sh sweep: 7303 total .lpc files. First pass (before sweep-driven fixes): 7272 pass / 31 fail (99.6%). After fixing the genuine bugs found (damo.lpc ×2, quest.lpc shared-root, girl.lpc, guidao.lpc, shoes.lpc, bowl.lpc ×2): 7289 pass / 14 fail (99.81%) — the remaining 14 are all confirmed-expected noise (11 story-daemon self-destruct-when-no-players files + 2 DNS/intermud config-ID-mismatch daemons + 1 legacy importer with no diagnostic), documented above, none of them real bugs worth fixing.

Driver was launched via Bash's run_in_background-equivalent (setsid nohup ... & disown) each time and killed by exact PID after each test — no pkill -f pattern used.

Status for TODO.md

playable / done — full registration + post-login command flow verified end-to-end twice, 99.81% lpcc pass rate, zero unexplained debug.log errors. Cross-check against archives #78/#80 flagged above for the main session once all three are complete.

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.3c/§1.3e/§1.5:

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

200s scripts/wasm_boot_watch.sh sit: ftpd.lpc/versiond.lpc sockets-absent preload errors match the already-documented §1.3c class (caught by master.lpc's preload catch(), cosmetic); versiond compile-and-fail recurs twice in one boot (two separate unguarded callers reach load_object), same known class, harmless. Proactively ported two fixes found live on sibling zhonghua2 (shares the identical inherit/item/combined.lpc and adm/simul_efun/object.lpc byte-for-byte): dropped private on combined.lpc's destruct_me() (call_out-self-invocation denied under private→DECL_HIDDEN inheritance, so spent-down money stacks never self-destruct), and fixed object.lpc's file_owner() (return name → return dir, misattributes 3-level-deep /u/<wiz>/<subdir>/<file> log_error writes). Neither fired visibly in this lib's own sit. Retest: fresh registration (id arysanb) into 世外桃源, look/quit clean, no regressions.

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

'hell'/Doing-Lu 引擎基础版。状态已从过时的 limited 修正——本轮修复了一个真实的 bug:clone/user/login.lpc 的 query_save_file() 只防范了 id 不是字符串的情况(!stringp(id)),没有防范空字符串的情况——对 "" 取 id[0] 会回传整数 0,而 sprintf 的 %c 格式会拒绝这个值('Incorrect argument to type %c, must be valid UTF8 char'),在任何 id 被输入之前,第一次自动呼叫 query_save_file() 就会崩溃(每一次连线尝试都会现场触发,把 id 提示搞坏)。已通过额外检查 id == "" 修复(手足档案 zhongjidiyu(052)和 zjdyzj(054)上也应用了同样的修复)。修复后重新验证管理员登录(fluffos/Mud@2026)干净正常,'目前权限:(admin)',quit 正常。

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

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

Native driver only (~/src/fluffos/build/src/driver, -DPACKAGE_DB=OFF ASAN/UBSAN preset), booted from the lib root (libs/zjdyaryl/, port 40073) per §5.2. Client: scripts/mudclient.py (raw-socket, single continuous connection per invocation) — scripts/tmux_mud.sh was tried first but this container has no telnet binary at all, so every session below is a mudclient.py invocation carrying the full send-sequence in one shot (one TCP connection = one continuous session).

Pre-boot environment gotcha (not a code bug)

First boot in this container hit *Wrong permissions for opening file /log/log for append. "No such file or directory" (spammed once per preloaded daemon, caught by master.lpc's own catch(), non-fatal) — neither libs/zjdyaryl/log/ (lib-root, for debug.log itself, driver CWD-relative per §5.2) nor libs/zjdyaryl/work/log/{static,user}/ (mudlib-virtual-root, for log_file()/assure_file() targets like clone/user/login.lpc's log_file("static/logon", ...)) existed yet in this fresh container — both are gitignored runtime directories that a prior pass's WASM-enablement notes assumed were already present. Created both (mkdir -p log log/static log/user, lib-root and work/ respectively) before the real test boot; zero Wrong permissions lines in every subsequent boot. Not committed (gitignored), noted here so a future dive in a fresh container doesn't misread the same symptom as a regression in the already-fixed log_file()/assure_file() pair (adm/simul_efun/file.lpc's log_file() genuinely still lacks its own assure_file() guard, matching this lineage's known §7.11 shape, but every actual call site either goes through an already-assure_file()d caller — e.g. channeld.lpc — or targets a directory that exists once the above mkdir -p is done; no live crash reproduced from it this pass).

Newbie material

clone/misc/newbie.lpc("新手必读") is a read book → HELP_CMD->main(me, "feature") pointer, but the real onboarding path is entirely NPC-driven: land in 世外桃源 (d/register/entry.lpc) → 水笙(shuisheng)'s greeting()/do_register() prompts register <email> → decide → walk to one of 4 personality-NPC rooms (east = 陆天抒/"光明磊落") → out → 阎罗殿(yanluodian.lpc) → wash (roll the 4 stats per chosen 猛士/智慧/耐力/敏捷/均衡 type) → born <地名> (e.g. born 扬州人氏) lands in a real starting city (/d/city/kedian).

Registration + state verification (two independent continuous sessions)

Combat mechanism

Read cmds/std/fight.lpc before testing, per this session's standing lead: confirmed the exact can_speak-gated split it was looking for — obj->query("can_speak") true → routes through obj->accept_fight(me) (decline-or-spar, "点到为止...不会真的受伤" per fight's own help text); false → unconditionally obj->kill_ob(me), a real fight. Default accept_fight() (inherit/char/npc.lpc) itself calls kill_ob() directly when !can_speak, so the split is enforced at both call sites, consistently — existing, intentional design, not a bug (matches the pattern already documented project-wide; did not test the non-can_speak branch against a live creature, by design, since that branch is genuinely lethal).

Live test: fight ouyang ke (欧阳克, a human/can_speak story NPC at 北大街) correctly invoked accept_fight() — declined in-character ("在下怎么可能是小兄弟的对手?" / "看起来欧阳克并不想跟你较量。") because its attitude is "friendly" and its qi/jing were both at 100% (inherit/char/npc.lpc's default accept_fight(): "friendly" + ≥75% qi/jing → decline). A real, clean exercise of the safe branch with a negative outcome — no damage, no crash, no error. (This same fight attempt is also what first reproduced the eval_function bug below, via combatd.lpc's post-fight-request start_call_out().)

Skill/sect acquisition — both paths

quit / reconnect / persistence

cmds/usr/quit.lpc has no new-account grace-period or delete-on-quit logic (checked before testing) — ordinary quit is always safe here, no need to simulate a raw disconnect instead. Existing design, not a bug: non-wizards get all non-equipped, non-autoload inventory dropped on quit (anti-hoarding-while-offline mechanic).

Bugs found and fixed

1. §8.3a addendum, 3rd confirmed instance: feature/action.lpc's eval_function() declared private. private→DECL_HIDDEN demotion-on-inheritance (this file is inherited into every character via inherit/char/char.lpc) silently blocks the call_out("eval_function", ...) dispatch that start_call_out() (this file's own general-purpose "run this function after a delay" primitive) relies on — 91 files across the tree call start_call_out(), including adm/daemons/combatd.lpc and 80+ kungfu/skill//kungfu/special/ buff/poison/powerup files. Reproduced live: debug.log showed apply() with insufficient permission: ... ob: clone/user/user#N, function: eval_function, origin: internal, needs: private, has: hidden immediately after an ordinary declined fight command (which schedules a combatd.lpc recovery callback via start_call_out()). Fix: dropped private (void eval_function(function fun) { evaluate(fun); }). Re-tested the identical fight decline post-fix, fresh boot: zero further eval_function/insufficient permission lines. Also fixed the identically-shaped clone/questob/letter.lpc:private void eval_function(...) for consistency — not confirmed live-triggered (nothing in that file actually schedules a call_out("eval_function" itself, so it may be dead code), but same bug shape, same trivial fix, zero risk. 2. §7.90, 5th confirmed instance (new lineage): maximum evaluation cost : 2000000 (config.fluffos) was too tight — not tripped by registration or movement, but by ordinary background daemon activity: adm/daemons/quest/capture.lpc's periodic heart_beat() spawning a kungfu/class/generate/capturenpc3 NPC whose randomly-chosen setup_family() branch (from_xueshan()) hit Eval interrupted: ... cost limit reached, limit: 2000000 usec mid-set_skill()/ACL-check, roughly 20 minutes into an otherwise-idle boot with no player nearby. Fix: raised to 5000000 (established §7.90 remedy value, already used by 30+ other libs). Verified: fresh boot + full replay of both registration sessions + the fight/apprentice/setsk tests above, zero further cost limit reached lines in debug.log.

发现但判定为既有设计、未改动的现象 (observations, not bugs)

WASM 未验证说明

Not re-verified under WASM this pass (native-only, per this project's current WASM build blocker). Confirm via: curl -sS "$HTTPS_PROXY/__agentproxy/status" — emsdk's storage.googleapis.com dependency is denied by the proxy, unchanged from every other lib checked this session. This lib's own prior WASM-enablement pass (2026-07, above) already covers WASM-specific gates (VERSION_D, messaged.lpc socket_bind, loopback allow); the two fixes in this pass (eval_function visibility, eval-cost ceiling) are driver-behavior-general and apply identically under WASM once it's buildable again in this environment.

深度功能测试第二轮 / Deep functional test round 2 (2026-08-15, post driver-upgrade re-test)

Round-two re-verification against the current native build-debug driver (post-upgrade — pulls in PRs #1343/#1344 and the corpus-wide %-operator float-crash fix). Standard checklist + live playthrough-style verification. The prior pass's own reconnect test only covered the link-dead/wall-clock- gap path, not the kick-duplicate-login confirmation path — this round adds that.

Findings:

1. AGENTS.md §7.107 (adm/daemons/closed.lpc's load_all_users() calling login_ob->restore()/user_ob->restore() with no catch() guard): a corrupted closed-cultivation account's save data would throw uncaught, aborting the whole heart_beat() tick before the cleanup (destruct()+map_delete()) runs, and retrying forever. Fixed by wrapping both restore() calls in catch() with an ok flag, same pattern as the other confirmed instances of this class this window. 2. AGENTS.md §7.108 (clone/user/user.lpc's reconnect() missing enable_commands()): confirmed active LOGIN_D (adm/daemons/logind.lpc) calls user->reconnect() on the character body after exec(old_link, user). Fixed by adding enable_commands(); as the first statement. Live-verified with two concurrent telnet sessions: session 2 logged in as fluffos (this lib's regular login password Mud@2026), confirmed the "赶出去,取而代之吗?(y/n)" prompt with y, and the resulting session correctly dispatched look (real room description). score returned "还没有出生呐" — expected content-gated response for this still-unregistered admin account (not a bug; same pattern as previously confirmed on sibling lib xkxz2), confirmed harmless by cross-checking with look. 3. adm/simul_efun/file.lpc: log_file() never called assure_file() before write_file(); added the call (plus a forward declaration). cat()'s write(read_file(file)) had no null-guard; changed to write(read_file(file) || ""). 4. Already correct, no change needed: cmds/wiz/update.lpc already guards with environment(me) &&. adm/single/master.lpc's log_error() already uses the case-agnostic "arning:" filter (AGENTS.md §7.10). maximum evaluation cost was already 5000000 (raised in an earlier pass per this NOTES.md's own §8.3a section).

Live verification summary: booted the native driver on port 40073 (the known-harmless, previously-documented versiond.lpc socket_bind() argument-type error fired again at boot as expected, non-fatal; Initializations complete / Accepting telnet connections both printed). Logged in as the seeded fluffos admin (Mud@2026), confirmed real write access via update /adm/simul_efun/file (recompiled successfully). Ran the two-session kick-duplicate-login reconnect test described above and confirmed the §7.108 fix live — this specific path (distinct from the link-dead reconnect this lib's earlier passes already covered) had not been exercised before. No new error classes in log/debug.log beyond the known versiond/boot-time line. Killed the driver by exact PID when done.

本轮修改的文件 / Files modified this round:

AGENTS.md §7.100 fix (2026-08-19): redundant replace_program(ROOM) landmine

Same corpus-wide bug as the batch-1-6 sweep (ROOM macro "/inherit/room/room" from include/globals.h). Deleted 2,315 live standalone replace_program(ROOM); lines under work/ via fix_710_room.py, plus hand-fixed the room-building tool's string-builder template (work/clone/misc/roommaker.lpc). No .lpc files under work/data/, so no false-negative risk. Remaining matches after the fix are all pre-existing //-commented.

Verified: clean build-debug boot (zero new compile errors, zero "cannot replace"/"cannot bind" in debug.log), live admin login (fluffos/Mud@2026) into the game world, look/quit worked cleanly (score's "还没有出生呐" is pre-existing admin-account behavior). Incidental data/{login,user}/f/fluffos.o save drift from the login test was reverted via git checkout HEAD before committing.

§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): 5 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-09-04,round three,shop + 拜师)

新角度:扬州醉仙楼购物 + 丐帮李斧头拜师。round one 只测了 apprentice ouyang ke 的 born_family 拒收(「你不是我们欧阳家的人」),没有真实 收徒,也没有商店购买。round two(2026-08-15)只补了 kick-duplicate 重连。 sibling zjdy2008wzb 2026-08-19 已经走过华山店 buy jitui + bai li futou。

本轮没有新的 programming bug。enter_world() 已经是 ob->set("registered", user->query("registered"))(从 user 抄到 login, 和 xkxz2 Bug 2 方向相反)。log_file() 已有 assure_file()。 log_error() 已有 arning: 闸门。env/prompt 是 "null",不是每秒时钟。

实测过程

管理员 fluffos / Mud@2026 / 浮云。第一输入是「您的英文名字」,没有 BIG5 提示。端口 40073。连线有大量 Tomud 控制码(licon/lbadd),不影响 指令派发。is_admin() 是 VERSION_D->is_release_server() || admin_flag == 1222,本环境 is_release_server() 为真,clone /clone/money/gold 一次成功。

原先 registered:0、score「还没有出生呐」。走完 register [email protected] → decide → west/out(阴险奸诈)→ wash → born 扬州人氏,落地扬州客店。born 后弹出游戏规则 pager(ENTER/q), 下一条指令被 pager 吃掉,不影响后续 clone。

goto /d/city/zuixianlou,list 包子五十文 / 烤鸡腿八十文 / 烤鸭一两 白银又五十文 / 牛皮酒袋一两白银。扬州店小二没有丐帮穷叫化踢人。 buy jitui 成功。i 剩九十九两白银 + 二十文铜钱(10000−80 = 9920)。

goto /d/gaibang/underhs(舍身崖下),李斧头 id li / kungfu/class/gaibang/li-futou.lpc,只收男性。apprentice li 一次成功: 「恭喜您成为丐帮的第二十代弟子。」score「丐帮第二十代传人」、师父李斧头。 save.lpc 真正双存。

save 后不 quit 丢 socket(此时 user.o registered:1、login.o 仍是 0),重启驱动强迫走 enter_world()。重连落地客店而不是世外桃源, 注意事项是普通欢迎而不是「您还没有注册」,score 仍是丐帮二十代 / 李斧头 / 扬州人氏,银子铜钱还在。烤鸡腿是 F_FOOD,不进 autoload,重启后不在 身上——不是存档 bug。

live debug.log 是 libs/zjdyaryl/log/debug.log(Boot Time Fri Sep 4 03:32:59 2026),无 error: / Too deep recursion。mudlib work/log/log 只有开机编译警告。管理员存档未提交。

深度功能测试(§10.7,2026-10-04)— negative range ends

scripts/lpc_fix_negative_ranges.py: 4 line(s) in 1 file(s) count a range from the end with < (x[a..-1] -> x[a..<1], x[-2..] -> x[<2..]; KB 06 §7.209). In this driver a negative constant end gave "" / ({ }) and a negative start the whole value, so each of these returned the wrong slice; the compile warning A negative constant as the second element of arr[x..y] is gone from the files that compile. Range lvalues (s[0..-1] = text, the prepend idiom) are left alone. A paired compile of the changed files at HEAD and in the working tree showed no new error.

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

cmds/std/look.lpc 夜间检查的 !present("fire", this_player()) 前加 objectp(this_player()) &&(房间 reset() 销毁物品时 /feature/move.lpc 的 remove() 会调用 look_room(),此时没有 this_player(),present(…, 0) 报 Bad argument 2 to present())。 验证:改动过的 cmds/std/look.lpc 在新进程里加载,HEAD 通过 1 个、工作树通过 1 个(共 1 个),无回退。

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

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

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

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

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

scripts/lpc_warnings.py zjdyaryl --fix 加 scripts/lpc_fix_no_effect.py --apply,共改动 543 个 .lpc 和 14 个 .h(多为删去未用的局部变量)。HEAD 与工作树分别加载(新进程):536 -> 536 通过,无回退;改过的头文件的 128 个包含者 127 -> 127 通过。 本库与其他指间 MUD 一样在 globals.h 里 #define nosave nosave,扫描器看不出旧 static 函数改成的 nosave 函数(Illegal to declare nosave function),按扫描诊断把 10 个文件的 28 处改成 protected(master、treemap、questd、dbased、cmwhod 等),这 10 个文件和 adm/daemons/natured.lpc(删去空语句 lt[LT_MON];)在 HEAD 与工作树分别加载 11 -> 11 通过。启动时警告 52 -> 0;新进程登录(新人物确认)正常。

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

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

深度功能测试(§10.7,2026-10-12):编译警告收尾

能编译的文件里的警告 3 -> 0(lpc_warnings.py zjdyaryl 重扫:7290 个文件可编译,剩下的诊断都在本来就编译不过的文件里)。与 zjdyzj 同码:zjdyzj 当天的修复(提交 15d40f6ba6a)改的 3 个文件在这里都是 token 级孪生,用 lpc_twin_port.py adopt 搬过来;ZJ 登录协议代码没有动。

真问题: clone/misc/swmuding.lpc 神木王鼎自己声明了一张 13 种毒虫的 mapping insects,可读表的是基类 clone/misc/muding.lpc 的函数,它们读的是基类那份普通木鼎表,叶子的表从来没用上。改名 sw_insects,在 create() 里赋给基类的 insects。

其余: feature/food.lpc、feature/liquid.lpc 的 do_effect() 改为 varargs int do_effect(object me) 并 return 1;,与 eat/drink 读取返回值的重载(d/guanwai/obj/wan.lpc、d/xiakedao/obj/pigpart.h)同型。

验证:改动文件、所有继承 F_FOOD/F_LIQUID 的物品、包含 pigpart.h 的文件、eat/drink 命令共 206 个对象,HEAD 与工作树各用新进程载入:205 -> 205 通过,regress 0;删除声明审计 0 项待看。206 个对象载入无回退。

负数伤害当作消耗(2026-10-15,KB 06 §7.241)

receive_damage("neili", -52)、receive_damage("qi", -12) 之类把 add() 的负数写进了 receive_damage():本库 feature/damage.lpc 对负数伤害报错(或归零),练功/运功时报 F_DAMAGE: 伤害值为负值 或消耗失效。已改为正数伤害,内力/精力类改为 add(type, -N)(scripts/lpc_fix_damage_calls.py):/kungfu/skill/duanyun-fu、/kungfu/skill/feifeng-whip。

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。2 处补上 if (!mapp(fam)) fam = ([ ]);(刚 recruit_apprentice() 之后的除外)。

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.249)

query_skill() 里的技能名拼错了,或用的是本库改名前的旧名;本库没有这个技能,调用永远得 0:门槛(< N 就拒绝)永远过不去,相关功夫或绝招学不了、用不了;内功互斥(> N 就拒绝)从不生效;公式里这一项一直是 0。经汉字名(提示文字或中文名词典)或纯拼写差异(_/-、少一个连字符、相邻字母颠倒)核对后,改为本库的技能名(scripts/lpc_fix_skill_typo.py):choushui-zhang→chousui-zhang(chousui-zhang);cuhixiao-jifa→chuixiao-jifa(xiaoao-jianghu);lenyue-shengong→lengyue-shengong(lengyue-shengong);matrial-cognize→martial-cognize(qiankun-danuoyi/nuoyi);taiji-shengon→taiji-shengong(taiji-shengong)。

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

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

柔云步法「柔云纵」有时报错(2026-10-15,KB 06 §7.251)

rouyun-steps/zong 随机把人送到三个房间之一:精、精力已经扣了,“乘云而去了”也说了,送不过去时人留在战斗里并报错。第三个是巫师的测试房 /u/deaner/test1,库里没有;改为 /d/city/guangchang(hy、jym 等库原本就用这个)。

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,而不是得到拒绝。1 处(1 个文件)改为 dbase 路径查询 query("family/master_name"):有门派时值相同,没有时得 0;原有的判断照常生效(scripts/lpc_fix_family_index.py)。给映射赋值的写法未动。

没有对手的绝招全部报错:message_combatd()(2026-10-15)

指间版 message_combatd(msg, me, you, ...) 为客户端加了图标和伤害行,直接读 you->query_temp("armor/armor")、you->query("qi")。不对别人出手的招(混天气功、龙象功等的 roar,先天功 shield,金刚不坏体 jingang ……)只传 msg, me,you 是 0,每次使用都报错,绝招探测里本库有 28 个这样的招。照同系 zjmudhell、wxddym、wdxtym 的写法,伤害行包进 if (you),取护甲图标前也先判断 you;28 个招全部能用了。

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 载入不了,刷出它的房间也少一个人。本库目前没有对象设了缺失的武功;三处都改成 return:这一门武功不给、不映射,对象照常载入,只是少了它(缺的武功本身仍是内容缺口)。(scripts/lpc_guard_set_skill.py)

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

set_skill("kunlun-shnfa", …)、map_skill("dodge", "shaolin-shnfa") 这样的调用把武功名拼错了:本库没有这个武功文件,有的是拼对的那个。以前这种 NPC 在 create() 里报 No such skill 载入不了;武功缺失时跳过之后它们能载入,可是少了那门武功(set_skill 被跳过,map_skill 映射不到,门派弟子用普通轻功/拳脚)。按核对过的对照表改正,共 12 处、9 个文件:changquana→changquan(4 处)、tiaji-jian→taiji-jian(2 处)、taiji-shenfong→taiji-shengong(1 处)、yan-fly→yanfly(1 处)、lingboweibu→lingbo-weibu(1 处)、jiahua-neigong→jiaohua-neigong(1 处)、zhoangnan-zhi→zhongnan-zhi(1 处)、jinggang-zhi→jingang-zhi(1 处)。(scripts/lpc_fix_skill_names.py)

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

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

从 work/ 里删掉 tar 的 PaxHeader/ 记录(2026-10-19,KB 02 §2.2)

压缩包的制作者把 tar 的 pax 扩展头记录(49 path = ...、20 ctime = ...,每个不超过 262 字节)当成文件打进了包里,放在 PaxHeader/ 目录(有的嵌套两层)。转换时 .c 结尾的被改名成 .lpc,在扫描里成了编译不过的“物件”。这些是元数据,不是 mudlib 内容:2 个文件从 work/ 删除(raw/ 里仍然有)。

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

if (arg != "wan" || arg != "丸") return notify_fail(...) 对任何 arg 都为真,dir == "south" && dir == "north" 永远为假:条件下面的守卫要么永远拦、要么永远不拦。作者要的是“既不是 A 也不是 B”(&&)或“是 A 或 B”(||)。!= 链的 || 改成 &&(仅当条件下面是 return 的拒绝/守卫),== 链的 && 改成 ||(scripts/lpc_fix_cmp_chain.py)。改动:/d/mingjiao/shanmen.lpc(1 处)。

member_array('/', str) 改为 strsrch(str, "/"):字符字面量的 member_array 按字节搜索(2026-10-20,KB 06 §7.283)

member_array('/', str) 里的 '/' 是整数,驱动按 UTF-8 字节搜索,返回字节偏移(带第三个参数时起点也是字节);最新的 FluffOS(923cdbc0)在字符串里有非 ASCII 文字时,对每个调用点警告一次(Warning: member_array(int, string) searches BYTES)。而 str[0..idx-1] 按字符切,中文字符串会在错误的位置截断。改为 strsrch(str, "/")(找不到同样返回 -1,按字符计数;scripts/lpc_fix_member_array_char.py,JSON 编码器等少数几处手改)。改动:/cmds/arch/sameip.lpc(1 处)。

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

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

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)。改动:/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(共 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/std/actionavailable.lpc(sscanf)。加载检查 HEAD 与工作树对照,没有退步。

注册到不存在函数的 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.,同一个动词的其他处理函数不再尝试(不是最新的一条就悄悄跳过)。删除了 5 条注册(4 个文件,scripts/lpc_fix_dead_add_action.py),动词留给别的处理函数:/adm/npc/referee.lpc(do_halt)、/d/beijing/hg_w.lpc(do_body)、/d/tulong/yitian/npc/obj/ling2.lpc(do_du)、/inherit/misc/fboard.lpc(do_list)。最多的函数名:do_halt 2 处、do_body 1 处、do_du 1 处、do_list 1 处。

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

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

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

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

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

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

本库 15 处(10 个文件):拼名字的赋值 8 处、与汉字常量比较 6 处、to_chinese()[..] 1 处。例:name[0..1] → name[0..0](/kungfu/class/emei/tobebonze.h:40);name[2..3] → name[1..1](/kungfu/class/shaolin/cheng.h:164);chk[0..1] == "你" → chk[0..0] == "你"(/adm/npc/ganjiang.lpc:532)。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,不要重跑。

长度检查按字节写,旁边的提示按汉字写:2 处(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 你好吗)。本库 2 处(1 个文件):if ((strlen(name) < 4) || (strlen(name) > 12)) {(/adm/npc/luban.lpc:1735)。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)。本库 channeld 同盟 / 门派标题 1 个文件。证明(scripts/lpcc_eval.py):sjplii 的 check_legal_name 在 HEAD 接受「张a」、改后拒绝,两边都接受「张三」;xkx100 的 clubpoem->mixup("离离原上草") 得到「离离原草上」(真交换汉字);nitan_san 两字同盟名得到 【 兄 弟 】。关键对象加载通过。

中文名 / 验证码仍按 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)。本库 4 处。证明:nt1 生成名长度 2–4;HEAD 常见 3–5。

yuanwai 孤儿 call_out announce_success(2026-10-27,KB 06 §7.349 Also)

d/changan/npc/yuanwai.lpc(及 aoxiangtianji 的 d/city 副本)在 check_daughter 里 call_out("announce_success", …),但本文件从未定义该函数;同系也无实现。到点会 *Undefined function*。cry_daughter 已完成认亲与赠书,删除这对 remove_call_out/call_out。证明:扫描 HIT call_out→announce_success 且无定义;改后残渣 0。

深度功能测试(2026-10-27,§6.25 zhongling tell_object 引号错位)

d/wanjiegu/npc/zhongling(及同路径副本)的 tell_object("who, 钟灵脱下一双绣花鞋。\n") 把对象参数写进了字符串;改为 tell_object(who, "…")。证明:原文错位;改后加载,语料残渣 0。

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

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