info.html · 介绍 · play.html · 游玩 · llms.txt · 下载与本地运行 · ZIP · GitHub
笑傲江湖(迷你版)是以金庸小说《笑傲江湖》为背景的武侠 MUD,属于 TMI-2/ES2(Falcon 系)引擎家族,是"笑傲江湖"系列里体积最小、内容最精简的一个版本(作者称之为"mini xo"):地图刻意做得极简,只有扬州城和一座码头小镇两座城市,可加入的门派也只有无量派一家,很适合用来体验这套引擎最原始、最基础的玩法框架;同批的"笑傲江湖最终版"(xo_final)与本档几乎逐文件沿用同一张地图、同一个无量派设定(差异只在少量文件的细节修改),再在此基础上大幅扩充出 10 座城市、16 大门派的更大世界。
English
A wuxia MUD set in Jin Yong's "The Smiling, Proud Wanderer," the smallest, most minimal build in this collection's xo series — the author's own "mini xo." The map is deliberately bare-bones: two cities (Yangzhou and a wharf town) and a single playable sect, the Wuliang (Boundless) Sect, making it a good look at this ES2/"Falcon"-family engine's basic framework stripped of content. Its sibling archive, the Final Edition (xo_final), reuses this same map and sect almost line-for-line (only minor per-file edits differ) while expanding it into a much larger world with 10 cities and 16 sects.
README
内容亮点
- 详见上方简介:极简的双城单派地图与 xo_final 的扩充关系。
在线试玩
https://mudlibs.fluffos.info/xo/
管理员账号 / Admin account
- id:
fluffos - 密码 / password:
Mud@2026 - 中文名 / display name: 浮浮(Fluffos)
- 权限 / level:
(admin)—— 本 lib 的最高巫师权限(通过/secure/etc/wizlist授予,SECURITY_D->get_status()据此判定)。
警告:这是一个公开的默认密码,仅供本地/浏览器试玩。正式对外开服前
请务必修改此密码。
本地运行
cd libs/xo
~/src/fluffos/build-debug/src/driver config.fluffos游戏端口:40023。
NOTES · 移植与修复记录
xo — 笑傲江湖迷你版 (The Smiling, Proud Wanderer — Mini Edition)
Archive: xo.zip. Port: 40023. Status: done (boots clean, connects,
plays through login into "create new character?" confirmation with zero
crashes).
What this is
A different, smaller lineage from everything else processed so far in
this batch: secure/daemon/master.c header says "Original from TMI-2 and
ES2, Rewritten by Falcon 96-10-02" — TMI-2 ("The Mud International 2") is
another classic MudOS-era mudlib base, distinct from the "ES II"/nitan
families seen in archives #21-#26. Uses the secure/daemon/{master,
sefun} path convention (not adm/obj/ or adm/single/). Small lib —
1395 .c files, "mini edition" as the name says. No set/query/
delete global simul_efun defined (like rzrmud/xkx2001) — every
object provides its own via inheritance, the architecturally correct
pattern (see AGENTS.md §15).
Fixes applied
1. AGENTS.md §4 (lazy security-daemon load): secure/daemon/
master.lpc's valid_write/valid_read called load_object(SECURITY_D)
unconditionally on every single call (not gated behind find_object()
first), wrapped in catch() but with no re-entrancy guard. Added the
full guard (nosave flag + find_object() check before attempting
load_object()) per the established §4 fix shape, applied proactively
before the first boot attempt given the exact matching pattern.
2. New bug (case-sensitivity, Windows-origin archive on a
case-sensitive Linux filesystem): 3 files (system/feature/char/
command.lpc, cmds/arch/ll.lpc, cmds/arch/localcmds.lpc)
#include <Action.h> (capital A), but the actual file on disk is
include/action.h (lowercase) — silently resolves on Windows'
case-insensitive filesystem, hard-fails here. This was responsible for
the overwhelming majority of the initial lpcc sweep's failures (762
"Undefined class 'Action'" + 155 "Cannot #include Action.h" out of
1395 files, cascading from just those 3 root includes via inheritance)
— fixing the 3 #include lines dropped the failure count from 209 to
72 in one shot (85.0% → 94.8% pass). Checked the whole tree for any
other same-shape case-only filename mismatches (find -iname +
case-insensitive dedup) — none found, this was the only instance.
Interactive test result
Boots clean, connects; welcome message + "last modified 1999.11" credit
line render correctly, empty input at the username prompt correctly
triggers a polite disconnect ("欢迎下次再来" — not a bug), new +
a valid English name reaches the "create new character?" (y/n)
confirmation with zero crashes. Did not create a full character or play
further (out of scope).
lpcc sweep
1395 files, 1323 pass / 72 fail (94.8%, after the Action.h fix). Remaining
72 failures are the usual long tail (a handful of syntax typos in
individual files, a few missing daemons like TASK_D/SendToUser/
SendToMud referenced but not present in this "mini" trimmed-down
archive) — not triaged individually, consistent with AGENTS.md §6b/§13.
Post-hoc fix: UTF8-native is_chinese/registration (AGENTS.md §15h)
Applied in a later batch pass across the whole project: is_chinese/is_chinese2
in the shared chinese.lpc simul_efun fragment used GBK byte-range checks that
silently never match real Chinese text once strings are UTF-8 (this driver's
str[i] returns a Unicode codepoint, not a GBK byte). This broke character
registration specifically -- any real Chinese name was rejected. Fixed the
range check to test the CJK Unicode block instead, and halved the
GBK-byte-calibrated length bounds in check_legal_name to match. See
AGENTS.md §15h for the full writeup; confirmed via a real interactive
registration test (Chinese surname + given name reaching the next prompt).
2026-07-23: driver rebuild retest + LPC formatter + WASM check
- Formatter: ran
tools/lpc-syntax'sformat-corpus.mjsover all 1395.lpcfiles inwork/; 1363 written, 7 already-conformant, 25 errors (files it refused to touch, expected/fine on legacy code). Spot-checked that this didn't disturb the §4/case-sensitivity fixes above, plus the pre-existing#define private protected/#define nosave nosavecompatibility shim ininclude/globals.h— all intact post-format. - Native retest: rebuilt
~/src/fluffos/build-debug/src/driverbooted clean (zero fatal errors inlog/debug.log— the two "mudlib error handler"/#define __DEFAULT_PRAGMAS__lines are the driver's own startup config dump, not errors). Went further than the previous pass (which had stopped at the "create new character?" confirmation) into a full end-to-end registration + play session: real Chinese name 秦风丁/秦风戊, English id/confirm/Chinese name/password/email/gender all completed, dropped into 小秦淮客寓;lookshowed the correct room+NPCs,scoreproduced a correct full character sheet,quitcorrectly enforced the "must play 30 real minutes before saving" gate and disconnected cleanly on confirmingy. Zero realdebug.logerrors. - WASM: booted cleanly (only the expected non-fatal
socket_create/socket_bind/socket_connect"Undefined function" compile errors fromsystem/std/net/client.lpc, since thesocketspackage isn't built into this WASM binary — matches the documented non-fatal WASM restriction). Registration itself proceeds correctly all the way through the gender prompt (m/f) — but reproducibly, across several--idle/--timeoutvalues (1.0/2.0/3.0/6.0s), the transition into the live game world (enter_world()) never completes: no banner/room text appears after answering the gender prompt, and subsequentlook/quitinput gets the driver's generic "什么? 你想干嘛?" (unrecognized command) fallback instead of real output. This is not the documentedquery_ip_number()limitation (this lib never gates login on IP format). It also does not reproduce on the native rebuilt driver (full playthrough above was clean), and notably does not reproduce onxo_final— a very close sibling with near-identicallogind.lpcregistration/enter_world()code — under the exact same WASM harness (seexo_final's own NOTES.md entry, verified working end-to-end). Root cause not identified (the WASM harness's debug-log-open failure at boot, a separate pre-existing cosmetic warning, means any real runtime error thrown duringenter_world()here would be silently discarded rather than surfaced anywhere inspectable). Verdict: flagged as a possible WASM-specific gap isolated to this lib's own code path, not patched — native play is completely unaffected, and chasing it further didn't seem proportionate to the smoke-test scope of this pass. Worth a closer look in a future WASM-focused pass.
2026-07-23 (integrity review): WASM world-entry hang RESOLVED — was the harness, not the mudlib
Re-ran the full WASM registration flow (new → id → confirm → Chinese name
→ password ×2 → email → gender) against the same build-wasm binary but
with the FIXED scripts/wasm_client.js (the copyDir() log-directory
recursion fix landed in the final commit of the previous pass, AFTER this
lib's WASM test had been run). Result: enter_world() now completes
normally under WASM — MOTD banner, 小秦淮客寓 start room, look, and
the quit save-gate prompt all appear exactly as in the native run. No
mudlib race exists in xo's enter_world path; the earlier "reproducible
world-entry hang" was the old harness failing to recreate the lib's
nested log/ subdirectory shape in the WASM in-memory FS (this lib's
log/ has 6 nested subdirs — acct/catch/log/room_log/runtime/static),
so an early uncaught write_file()/log_file() during enter_world threw
ENOENT and silently aborted the flow — precisely the harness gap class
described in that commit's message. Verdict: fully playable under
WASM; the previous NOTES entry's "possible WASM-specific gap isolated
to this lib" flag is closed.
Also noted (pre-existing, original-author code, left as-is): system/
daemon/logind.lpc's enter_world() contains two leftover debug
printf("beforee exec...") / printf("before setup...after exec..")
lines that print to every player at world entry — present since the raw
archive (verified in the initial conversion commit), cosmetic only.
WASM-enablement pass (loopback-allow / gate bypass / admin seed)
Standard WASM-first pass per AGENTS.md §1.3b/e and §1.5. Gates patched:
system/daemon/band.lpcis_banned()(~line 39) — loopback / empty / malformed-IP short-circuitreturn 0;at the top (inline test, no helper needed — only one gate function in this daemon).system/daemon/logind.lpcCheckDupIp()(~line 148) — multi-login deny list now exempts loopback/malformed-IP connections (return 0;before the multi_deny regexp loop).logon()'sLOGIN_DELAYstartup-grace gate (~line 102) is compiled out (LOGIN_DELAY not defined anywhere) — left as-is, noted only.uptime() < 10inlogon()(~line 125) is cosmetic (banner text choice), not a gate — left intact.
Admin account seeded: id fluffos, pw Mud@2026, name 浮浮, granted
(admin) via fluffos (admin) appended to secure/etc/wizlist.
Verified: real registration (ENTER/new/fluffos/y/浮浮/pw×2/email/m →
landed in 小秦淮客寓), then relogin as fluffos →
update /system/daemon/logind → 成功, score correct. Retest: fresh
normal registration (秦风, f) end-to-end with look/score correct (quit
shows the original 30-min new-account retention prompt — content timer,
kept per policy); test char save removed; zero new debug.log errors.
Save file: work/data/user/f/fluffos.o (NOT gitignored — normal add,
no force-add needed).
Fail-closed retrofit for the loopback-allow gate (2026-07-24)
The loopback helper above was originally written matching the
project-wide convention at patch time (AGENTS.md §1.3b), which also
treated an empty/non-string/malformed query_ip_number() result as
loopback, defensively, because the WASM driver used to return garbage
there. That underlying driver bug is now fixed (fluffos commits
e33bb5da "fix: query_ip_number() returned uninitialized garbage under
WASM" and 007bb863 "feat: synthetic resolve() on WASM instead of
raising an LPC error", both 2026-07-23; the locally-built
build-debug/build-wasm binaries already postdate both commits), so
treating unparseable IPs as trusted is a fail-open gap with no remaining
justification. Retrofitted to fail-closed: loopback is now strictly
ip == "127.0.0.1" || ip == "::1" || ip[0..3] == "127." (with a
stringp() guard before the slice) — a malformed/empty IP now falls
through to the NORMAL gate instead of being treated as local. Retested
after tightening: fresh driver boot clean, fluffos loopback login and
its wizard update command both still work; zero new debug.log errors.
深度功能测试 / Deep functional test (2026-07-24)
First real *playthrough* pass on this lib (all prior passes verified
only registration + look/score/quit + admin login). This "mini"
archive has no help newbie/help intro file at all (help/user/
contains only a single sect help page and no topics index — a genuine
content gap in this trimmed archive, not a conversion bug; help with
no argument literally prints 0 to the player, see Bug 8 below), so the
test path was derived entirely from reading room/NPC source: register →
小秦淮客寓 (start room, Yangzhou) → walk to 崇雅书院/至止堂 and learn
literate from the teacher NPC 增城湛 via qingjiao → (admin-assisted,
see below) reach 无量剑派东宗's hall and join via apprentice/kneel
→ a real fight → a real death → the death-realm/reincarnation flow → a
shop purchase → quit/reconnect testing. Found and fixed eight
distinct programming bugs (compile errors, a driver-API-misuse crash, and
a silent-stranding move() bug), one of which is a well-established
project bug class (§7.25) and most of the rest are one-off typos of a
kind AGENTS.md already tracks (§6.6/§8.5-adjacent); also captured a
driver-level SEGFAULT, corroborating the §10.8 "ambient background
processing can crash the whole process, invisible to debug.log" class
with a genuinely different C++-level mechanism (a dangling shadowed
object pointer walked during the periodic reset() sweep) than either
of the two prior occurrences.
Note on this pass's scope: partway through this session the orchestrating session clarified that only genuine *programming* bugs are in scope for live fixes (compile errors, driver-API misuse, missing null/objectp checks around calls that can crash, obviously-wrong references) — game-balance/content/design questions are explicitly OUT of scope, even when they look surprising. One thing found live (a "safe" sect mirror-spar that turned out to deal lethal, real damage — see "Observed, not fixed" below) falls squarely in that excluded bucket and was deliberately left untouched, documented only.
Wuliang sect is not reachable by ordinary walking in this archive:
d/menpai/wuliang's only outbound connection to the rest of the map
(shanjiao.lpc's northwest exit) points at /d/map/xinan/jiangbian,
and /d/map/ doesn't exist anywhere in this "mini" archive (confirmed:
d/map is entirely absent). No city room links into
d/menpai/wuliang either. This means the sect content described in the
lib's own README ("目前只有扬州城和无量派两大门派") is real and
functional but currently has no in-game path to it at all — every
sect-related test below (apprentice/kneel, the mirror-spar,
qingjiao) was reached via admin goto/summon, not by walking. This
looks like a genuine map-connectivity gap from the archive trim (not
something we fixed — no defensible "correct" reconnection point exists,
and fabricating one would be a content decision) but is worth flagging
prominently since it's a bigger blocker to real play than any single bug
below.
Test characters (kept as evidence, not cleaned up):
qinfengding/ 秦风丁 (male, pwAa123456) — first registration, used for the teacher-NPCqingjiaotest and a full cleanquit(both the "too new to save" no-save-confirm path AND, much later in the same real session once 30 real minutes had elapsed, a REAL save-and-quit, reconnect-verified). Currently in小秦淮客寓wearing 青布衣衫, literate skill improved once via 增城湛.qinfengwu/ 秦风戊 (female, pwAa123456) — used for the prompt net-dead/reconnect test and the shop-purchase test (bought 白缎衫 from 沈万福 inbaiyi_dianfor 800 铜钱, funded via an admin-dropped/ player-picked-up 银子 since fresh characters start with no money). Currently in沈家白衣铺, holds 白缎衫 + 200 铜钱 + starting gear.qinfenglong/ 秦风龙 (male, pwAa123456) — used for the sect-join (apprentice zuo/kneel), the mirror-spar-that-wasn't-safe (see below, died to 老高), and the death/reincarnation flow. Deliberately has no save file — during testing this character hitquit+ywhile still under the lib's real 30-real-minute-before-first-save gate (cmds/comm/quit.lpc'sconfirm_quit_with_nosave()), which correctly and intentionallyrm()s both thelogin/anduser/save files — confirmed this is the INTENDED behavior (matches the on-screen warning verbatim), not a bug; documented here only so a future pass isn't confused by the missing.ofile for an id that clearly saw a lot of activity indebug.log-adjacent logs (data/log/q/qinfenglongstill exists and shows the session).- Admin:
fluffos(pre-existing, pwMud@2026) — used throughout forgoto/summon/force/update/callto reach the disconnected sect zone and to recompile fixes live.
Verified working
- Registration end-to-end with real Chinese names (秦风丁/秦风戊/秦风龙), landing in
小秦淮客寓with correctlook/score/i. - Organic teacher-NPC skill learning:
qingjiao zeng literateagainst 增城湛 (崇雅书院/至止堂) — first attempt succeeds ("你听了增城湛关于 读书识字的讲解阐释..."), immediate repeat correctly refused ("贪多不化 ..."). - Sect join (
apprentice <NPC>→ NPC leads you to a side hall →kneelonce the NPC's own delayed dialogue sets the flag) against 左子穆, leader of 无量剑派东宗 — full flow completed, disciple rank/family granted, sword received, persisted correctly across an unrelated driver restart (see Bug 3's segfault below — after the driver came back up,qinfenglong's family/rank data was intact even though their physical location reset to the last realstartroom, which is correct/expected since location is separate save state from family). - A real fight to the death (see "Observed, not fixed" — the sect's mirror-spar
accept_fightbranch actually killed a fresh, unarmed disciple in one hit), the full death → 黄泉路 → 鬼门关 → 酆都地府 → 阎罗大殿 flow, and (after Bug 7's fix) the reincarnation NPC 判官 (chacha.lpc) correctly walking through its dialogue and moving a ghost with an empty inventory back to a real, live room. - A real shop purchase:
list shen(vendor goods listing) thenbuy baiduan shan from shen— correct price/change arithmetic, item added to inventory, auto-save fired, zero crashes. quit: both the "too new, confirm without saving" path (explicitly wipes save files — confirmed intentional, seeqinfenglongabove) and, later in the same real session once past the 30-real-minute mark, a genuine save-and-quit → reconnect round trip with correct location/inventory/score restored.- A prompt (well within any timeout) unclean net-dead disconnect + reconnect (
qinfengwu, and incidentallyqinfengding/qinfenglongacross nearly every test in this pass, sincemudclient.pyclosing its socket without sendingquitIS an unclean disconnect) — this lib's ownnet_dead()/reconnect()(clone/user/user.lpc) never relocates the player at all (noVOID_OBpark, no location temp var), so there is no §7.20-style stale-location-on-reconnect risk to find here; reconnecting mid-session always resumed exactly in place, every time. debug.loggrepped after everyquit/crash/compile-fix in this session, per the AGENTS.md §10.7 mandate — see the segfault entry below for why this matters: at NO point diddebug.loggrow by even one line beyond its pre-session baseline (219 lines, unchanged for the entire ~30-minute session), despite multiple live compile errors, one live driver-API-misuse crash, and one full driver segfault all happening during that same window. Every one of those was caught purely by watching the client transcript / driver stdout / the in-liblog/runtimefile, neverdebug.logitself.
Not verified live (explicitly)
- The full 900-second (
NET_DEAD_TIMEOUT) unclean-disconnect wait: not performed, for time-budget reasons. Mitigating factor found by code reading instead: this lib'snet_dead()(clone/user/user.lpc) never moves the player toVOID_OBor any holding room at all — it just stops the heartbeat and schedulesuser_dump(DUMP_NET_DEAD)after the timeout, which (per the same file) simply calls the ordinarycommand("quit")at the player's CURRENT, never-changed location. Both of the two independent root causes AGENTS.md §7.20 documents (void-parking without restore, and areconnect()that never gets called) require the net-dead path to relocate the player in the first place — this lib's simpler design structurally can't hit either. Lower-priority to chase further given that structural argument, but flagged honestly as code-review-only, not live-tested. - A wizard
check_rein/death_stagerace was observed where re-entering阎罗大殿multiple times (to re-trigger 判官's dialogue during iterative testing) stacks multiple concurrentcall_outchains with no dedup guard (init()callscall_out("check_rein", 2, ob)unconditionally on every room entry) — plausible under real multi- minute AFK/re-entry play, not just repeated admin testing, but was not cleanly isolated/reproduced as a standalone bug this pass (my own repeatedgoto/summonre-entries are a confound); flagged as worth a closer look in a future pass rather than fixed blind.
Bugs found and fixed
1. Unterminated string literal (×3, same shape, different files) —
AGENTS.md §6.6-adjacent (pre-existing authors' typo, not a new bug
class): a Chinese-text string literal missing its closing "
before the trailing comma, causing the driver to keep consuming
subsequent lines as string content until it hits the next "
(usually inside a //-commented line, since the comment marker means
nothing once already inside an unterminated string) and then throwing
a cascade of "Illegal character" / UTF-8-mid-codepoint errors once the
accidental early-close lands mid-multibyte-character.
- d/menpai/wuliang/npc/zuo.lpc:69 — this one is the single most
impactful fix in this pass: 左子穆, the sect's own leader/master,
failed to compile entirely, so d/menpai/wuliang/dating.lpc's room
population silently dropped him (caught by std/room.lpc's already-
catch()-guarded make_inventory() — this lib is NOT vulnerable
to the unguarded §7.25 crash shape, just the graceful-degradation
side of it) — meaning the ENTIRE sect-join mechanism was inert
(no master NPC to apprentice) until this fix.
``lpc
// BEFORE:
"姓名" : "嗯,你既知我姓左,怎会不知在下便是无量东宗掌门人左子穆?,
// AFTER:
"姓名" : "嗯,你既知我姓左,怎会不知在下便是无量东宗掌门人左子穆?",
`
- system/skill/misc/yuanyang-dao.lpc:33 (the "鸳鸯刀法" weapon
skill's 4th combat move) — same shape, fixed identically.
- system/skill/misc/taizu-quan.lpc:181` (the "太祖长拳" unarmed skill's
"英雄独立" move) — same shape, fixed identically.
2. Undefined-macro inherit (×2 files): d/city/yangzhou/waifang.lpc
and d/city/yangzhou/woshi.lpc (both real, reachable rooms — a
courtesan-house's outer/inner room, linked from meixiang_yuan.lpc)
did inherit DOOR_ROOM; — DOOR_ROOM is never #defined anywhere in
this archive (no door_room.lpc base class exists at all), a hard
compile error (expecting L_STRING or '('). Every other room in this
lib that needs a door (e.g. d/menpai/wuliang/damen.lpc) just
inherits plain ROOM and calls create_door(), which std/room.lpc
already provides directly — DOOR_ROOM was never real content, just
a stale reference. Fix: inherit ROOM; in both files.
3. Malformed function declaration swallowed into a comment:
system/skill/basic/kongshou.lpc:37-38 — the base "unarmed combat"
skill, needed on literally every unarmed combat round for every
character. The Chinese explanatory comment and the following
function signature were on the same physical line with no separating
newline, so the ENTIRE function header got absorbed into the //
comment, leaving a bare orphaned { on the next line
(syntax error, unexpected '{'). Reproduced live: fighting as an
unarmed disciple spammed a "Compiling error .../kongshou.lpc ... *No
program in object" message to the player on every single combat
round (both attack and parry attempts), since skill.lpc's combat
dispatch tries to load this file fresh every time it's referenced and
it never successfully compiles.
``lpc
// BEFORE:
// 这个函数用来区别这种天生的技能与其他后天学习的技能int is_native_skill()
{
return 1;
}
// AFTER:
// 这个函数用来区别这种天生的技能与其他后天学习的技能
int is_native_skill()
{
return 1;
}
`
Checked the other 4 sibling files in system/skill/basic/ with the
same is_native_skill() pattern (wuqi.lpc, horsedodge.lpc,
dodge.lpc, yeshou.lpc`) — all correctly formatted, this was an
isolated one-off typo, not a copy-pasted class.
4. Missing #include <armor.h> (×2 files) — AGENTS.md §6.1:
d/city/yangzhou/npc/cloth/cloth.lpc (the base clothing template) and
d/menpai/wuliang/npc/obj/choushan.lpc (a sect disciple's robe, worn
by the live npc/qyz.lpc... which itself turns out to be dead/
commented-out content, see below — fixed anyway since it's a one-line,
zero-risk fix and the exact §6.1 shape) both did inherit CLOTH;
without #include <armor.h> (where CLOTH is #defined). Every
sibling cloth file in the same directory has the include; these two
were just missing it. Fix: add #include <armor.h> above the
inherit.
- cloth.lpc also had a second, independent bug on the same pass:
set("value",); — a call with a dangling comma and no second
argument (Wrong number of arguments to 'set', expected: 2, got:
1). Every sibling cloth file's equivalent line reads
set("value", 800)-shaped; fixed to set("value", 0) (a sensible
zero default for what is explicitly a base/template object, per its
own empty set_name("", ...) treatment elsewhere in the same
create()).
5. Driver-API misuse: missing objectp() guard after a move() call
that can legitimately self-destruct its argument — matches AGENTS.md
§7's "missing objectp()/stringp() checks" class, closest existing
relative is §7.25's shape (a call that can legitimately fail/vanish,
with no guard on the caller side). cmds/verb/drop.lpc:57's
do_drop() calls obj->move(environment(me)), checks only the
integer return value, then unconditionally calls further methods
(obj->is_character(), obj->query("unit"), obj->value()) on the
same obj reference. d/menpai/wuliang/npc/obj/sword.lpc's own
move() override (a soulbound-weapon "剑在人在,剑亡人亡" mechanic)
legitimately destruct(this_object())s itself and returns 1
(success) when dropped outside a valid ownership context — a fully
intentional, working design (see sword.lpc:33-52), but do_drop()
has no way to know that and dereferences the now-destructed obj
immediately after. Reproduced live: drop sword (as a disciple
standing in the death realm, where the sword's ownership check fails)
printed the correct in-fiction "剑转眼间断成了数块,不见了。" message,
immediately followed by an uncaught *Bad argument 1 to EFUN
call_other() Expected: object, string, array, Got: int(0) runtime
error (visible in log/runtime), aborting the rest of do_drop()
mid-function.
``lpc
// BEFORE:
if (obj->move(environment(me))) {
if (obj->is_character())
// AFTER:
if (obj->move(environment(me))) {
// obj->move() can legitimately destruct obj as a side effect (e.g.
// a bound/soulbound weapon shattering when dropped outside its
// valid owner context -- see d/menpai/wuliang/npc/obj/sword.lpc's
// own move() override) -- guard before touching it further.
if (!objectp(obj)) return 1;
if (obj->is_character())
`
This is a general, call-site-independent fix (guards the ONE shared
do_drop() used by every drop invocation, including the amount-
split and drop all` paths), not specific to the sword.
6. Silent-stranding move() to nonexistent content in the death/
reincarnation flow — same shape as AGENTS.md §7.18 (hardcoded path
into content missing from THIS archive), new file/lineage instance:
d/place/death/npc/chacha.lpc's death_stage() — the 判官 NPC that
finalizes reincarnation — picks a random(3) destination for a newly
-reincarnated ghost. Only branch case 0
(/d/city/yangzhou/kuixing_ge) resolves to real content in this
trimmed archive; case 1 (/d/map/zhongyuan/nanmen — /d/map/
doesn't exist anywhere in this archive) and case 2
(/d/city/lanzhou/guangchang — lanzhou doesn't exist either) both
silently fail. Confirmed the failure mode live (via goto on the
admin account, which has its own explicit existence check and
reported "没有这个玩家、生物、或地方" without moving): move()'s own
implementation (system/feature/base/move.lpc:74-80) already
gracefully notify_fail()s rather than crashing for a target that
doesn't exist at all (as opposed to one that exists but fails to
compile, which throws) — but chacha.lpc never checks move()'s
return value, and notify_fail() from a call_out-driven context
with no active command dispatch never surfaces to anyone. Net effect:
2 out of 3 times, a reincarnating ghost's ghost flag gets cleared
(reincarnate() already ran) but they're never actually relocated —
permanently stuck in 阎罗大殿, a death-realm-only room with (per
鬼门关's own room text) no way back to the living world through
ordinary movement. Also checked the "西域"/gaochang special-case
branch one line above — /d/city/gaochang/center doesn't exist
either, but confirmed (via logind.lpc's own start_rooms array,
where the gaochang entry is commented out) that no character in
this archive can ever actually be tagged hydra/desert/from=="西域"
in the first place, so that branch is already-dead and left alone.
``lpc
// BEFORE:
switch (random(3)) {
case 0: ob->move("/d/city/yangzhou/kuixing_ge"); break;
case 1: ob->move("/d/map/zhongyuan/nanmen"); break;
case 2: ob->move("/d/city/lanzhou/guangchang"); break;
}
// AFTER: (both dead branches repointed to the one confirmed-live
// destination already used by case 0, matching AGENTS.md #7.18's
// fix pattern -- see the file for the explanatory comments kept in
// place)
switch (random(3)) {
case 0: ob->move("/d/city/yangzhou/kuixing_ge"); break;
case 1: ob->move("/d/city/yangzhou/kuixing_ge"); break; // was the dead /d/map/ path
case 2: ob->move("/d/city/yangzhou/kuixing_ge"); break; // was the dead lanzhou path
}
`
Verified live end-to-end after the fix: dropped all items (a
prerequisite the same NPC enforces earlier in its dialogue), re-
entered 阎罗大殿, sat through 判官's full multi-stage dialogue, and
was moved to 小秦淮酒楼` (a real, live room) successfully.
7. Operator-precedence + typo bug, NOT observed live (dead code given
current data, fixed proactively since it's a trivial and clearly
unintentional pair of mistakes): cmds/skill/study.lpc:127-128 —
if (bonus = book["bonus_jibie"] > 0) me->improvve_jibie(...). Two
independent bugs stacked: = binds looser than > in this grammar,
so bonus was being assigned the BOOLEAN result of the comparison
(0 or 1) rather than the actual configured bonus amount (contrast
with the parallel bonus_jilei branch a few lines up, which correctly
does bonus = book["bonus_jilei"] then checks it); and
improvve_jibie (double-v) is a typo for the real function
improve_jibie (defined in system/feature/char/skill.lpc:351, used
correctly by name everywhere else including 3 lines below in the same
function's else branch) — an Undefined function error waiting to
happen the moment it's ever reached via ->. Not reachable with
current data: grepped every book/skill data file in this archive
and none of them ever set "bonus_jibie" to a positive value, so
book["bonus_jibie"] > 0 is always false and this exact branch never
executes today — but the fix is one-line-obvious and harmless, so
applied proactively rather than left as a landmine for the first book
that ever sets that key.
``lpc
// BEFORE:
if (bonus = book["bonus_jibie"] > 0)
me->improvve_jibie(book["name"], bonus);
// AFTER:
if ((bonus = book["bonus_jibie"]) > 0)
me->improve_jibie(book["name"], bonus);
``
8. Cosmetic, not fixed (too minor/ambiguous to count as a real
programming bug, documented only): cmds/comm/help.lpc's main()
does cat(HELP_DIR + "topics") when called with no argument;
help/user/topics doesn't exist anywhere in this trimmed archive
(genuine content gap, not a conversion bug). secure/sefun/file.lpc's
cat() is write(read_file(file)); read_file() of a missing file
returns int 0, and write() coerces that to the literal string
"0" — so a bare help with no topic just prints 0 to the player
instead of a message like "没有说明文件". Left as-is per the "don't
fabricate missing content" policy (the fix would require deciding
what a proper topics index should say, a content question) — but
flagged here in case a future content pass wants to add a real
topics file, at which point this stops mattering entirely.
Observed, not fixed (design/content, out of scope per this pass's corrected instructions)
- The sect's "mirror match" isn't actually safe:
d/menpai/wuliang/ npc/laogao.lpc'saccept_fight()has a friendly-dialogue branch for attackers whosefamily/family_namematches the sect ("好吧,我就陪你 练几招吧,看好了哦。") that reads exactly like the "safe sparring mechanism" AGENTS.md §10.7's checklist asks testers to find and use before risking a real fight — but the branch doesn't cap damage, disable death, or use any different combat resolution than a genuine fight; it's real combat with friendlier flavor text only. Used it as directed by the checklist (attacker was a same-sect disciple,qinfenglong) and it killed a fresh, unarmed, zero-combat_expcharacter in a single hit (老高 immediately wielded his real sword and landed a killing blow: "你没能躲开,只听见你一声惨嚎,悬泉剑已在你右肩 划出一道深可及骨的可怕伤口!!" → death). This is internally consistent (the code does exactly what it's written to do, consistently) and matches the exact "a 'safe' fight sparring mechanic that isn't perfectly safe" example the orchestrating session explicitly called out as NOT in scope — documented, not touched. - A ghost can leave the death realm without ever reincarnating: while chasing Bug 6 above,
qinfenglong(still flaggedghost, in阎罗大殿) got picked up by an unrelated, already-existing safety net —system/feature/user/alias.lpc'sprocess_input()checks!environment(this_object())on every keystroke and teleports a player with no environment intoVOID_OB(clone/misc/void.lpc, "天涯海角,梦的尽头", with a workingoutexit to a real room). The room the character had been standing in was most likely reaped by this archive's ordinary idle-object cleanup during an unrelated multi- minute admin digression, not anything wrong with the death-realm code itself — the safety net caught it and worked exactly as designed (a live, escapable room, not a dead end). Net observable effect: the character ended up back in the living city, walking around, while still internally flagged as aghost(never went throughchacha.lpcat all this time) — an odd-looking but non-crashing state that self- resolved the next time阎罗大殿was re-visited and the reincarnation dialogue actually completed. Not chased further (unclear whether this is "a bug" or just an unusual but harmless interaction between two independently-correct systems); documented for anyone who sees a【 鬼 魂 】player wandering a normal city room and wonders why.
Driver segfault (corroborates AGENTS.md §10.8, new immediate mechanism)
~26 minutes into this session, during ordinary ambient play (not
triggered by a specific command — the crashing call stack is entirely
inside the driver's own periodic reset() sweep, backend.cc's
look_for_objects_to_swap()), the native driver process died outright
with a SIGSEGV. debug.log showed absolutely nothing — identical to
both prior §10.8 occurrences (xjcq2000, shiji), reinforcing
that this class of failure is genuinely undetectable by log-watching
alone; only the redirected driver stdout (captured per the standing
recommendation from that section) had anything.
Captured backtrace (driver build fluffos-20260721-25c87bbc):
backend_run_one_gametick -> look_for_objects_to_swap -> reset_object
-> safe_apply(APPLY_RESET) -> apply -> apply_low -> eval_instruction
-> f__call_other -> apply -> apply_low [SIGSEGV]
src/vm/internal/apply.cc:201, in apply_low:
while (ob->shadowed && ob->shadowed != current_object &&
(!(ob->shadowed->flags & O_DESTRUCTED))) { // <- crash hereThis is a different immediate C++-level mechanism than either prior
occurrence (both of those were FATAL: Object ... ref count 0, but not
destructed internal-consistency aborts from free_svalue(); this one
is a raw segfault dereferencing ob->shadowed, apparently a dangling
pointer, while a reset()-triggered call_other() walks the shadow
chain) — but the same broad category (driver-level object-lifecycle
memory corruption surfacing later, during unrelated background
activity, as a process-ending crash). Not mudlib-fixable; not root-
caused to a specific LPC source pattern (the corruption, whatever it
was, had already happened before this crash — the reset cycle just
happened to be the next code to touch the bad pointer). Driver was
restarted (fresh PID, confirmed via readlink -f /proc/<pid>/cwd
before doing anything with it) and testing continued; no second
occurrence in the remaining ~30 minutes of this session. This is now
the third independent occurrence of "background driver processing
crashes the whole process, invisible to debug.log" across three
unrelated libs/lineages — per §10.8's own escalation note, worth
promoting to a driver-level (~/src/fluffos) investigation rather than
continuing to treat each new occurrence as a per-lib mudlib finding, if
this keeps recurring.
lpcc sweep
Baseline (start of this pass) 1323/1395 pass (94.8%). After this pass's
fixes: 1331/1395 pass (95.4%). Remaining 64 failures are the
already-documented long tail: genuinely corrupted/non-LPC content under
d/menpai/wuliang/east/ (plain-text poem fragments, garbled binary, a
"By XO team... since 1997 April." credits blob — not LPC source at all,
pre-existing archive corruption, not a conversion bug, and this whole
subtree turns out to be unreachable anyway per the map-connectivity gap
noted above), missing daemons (TASK_D, BET_D, SendToUser, NBUG)
consistent with this "mini" archive's documented trimming, and a handful
of dead/superseded duplicate files (system/menpai/wuliang/zuo_zimu.lpc
etc. — confirmed via grep to be shadowed by a live npc/-subdirectory
version and never referenced by any room's objects mapping, left
alone per the project's "leave dead code alone" convention) — not
triaged further as none are live/reachable.
WASM 修复摘要(迁移自 meta.json 的 group_note)
笑傲江湖 XO/TMI-2/ES2/Falcon 基础版(迷你版)。状态已从过时的 limited 修正——这份档案自己的 README 和 group_note 里从未记录过任何缺陷说明,本轮重新测试也没有发现:这份压缩包没有随附管理员存档(只有一条 wizlist 阶层授权)——已改为用一次全新的 'new' 注册(fluffos/Mud@2026)来验证,干净地进入起始区域(小秦淮客寓),并以正常的告别信息 quit。
§7.86 跨库扫描修复(留言板 post 崩溃)
BULLETIN_BOARDinherit+ 多余replace_program()致命形状(AGENTS.md §7.86,post命令崩溃):全档案 4 处命中,已删除多余的replace_program(...)调用(保留inherit),逐文件保留原有行尾格式(CRLF/LF 按文件原样)。本次为跨库 §7.86 扫描修复(触发原因:该 bug 已在 6+ 个互不相关的血统家族独立确认,属于近乎普遍的拷贝粘贴模式),仅做编译检查(驱动干净启动、端口正常监听),未做完整 §10.7 深度游玩测试。
深度功能测试第二轮 / Deep functional test round two (2026-08-15, post driver-upgrade re-test)
驱动于 2026-08-12 升级后的重测。标准检查清单发现并修复四处问题:
1. cmds/app/update.lpc(AGENTS.md §7.106):完全没有
environment(me) 空值防护(if (obj = present(file,
environment(me)))),补上
if (environment(me) && (obj = present(file, environment(me))))。
2. secure/sefun/file.lpc:log_file() 没有 assure_file()
目录预建保护,补上调用及前向声明;cat() 补上
read_file() || "" 空值防护。
3. secure/daemon/master.lpc::log_error()(AGENTS.md §7.10 大小写
坑的又一实例,与本轮在 xlqy_new2007 上发现的一样):
strsrch(message, "warning: ")(小写、带尾随空格)逐字节对不上
本驱动实际吐出的大写 Warning: ,等于完全没有过滤——本档案这处
还额外没有 wizardp() 分流(对所有连线玩家一视同仁广播),改成
不含开头 w/W 的 "arning:" 子串匹配(§7.10 标准写法)后即可正常
过滤警告,未额外新增巫师分流(不在本轮范围内,且原代码本就没
有这层区分)。
4. clone/user/user.lpc、clone/user/wizard.lpc 的 reconnect()
(AGENTS.md §7.108,第十六条独立确认的血统):两个档案各自独
立定义 reconnect()(wizard.lpc 覆写而非继承 user.lpc),均
缺少 enable_commands()。system/daemon/logind.lpc 有同款
exec(old_link, user); 踢掉重复登录写法。按 §7.108 记录的写法
预防性修复两处,现场用两个真实连线复现"保持第一个连线不断开→
第二个连线登录→答 y 踢掉旧连线"验证:score 修复后立即正常显
示完整角色档案。
现场验证摘要
驱动干净启动,管理员 fluffos/Mud@2026 登录(回车进入→id+密码)
成功进入游戏世界,update /system/daemon/logind 成功验证真实写入
权限,现场未观察到编译警告泄漏(确认 log_error 修复生效)。踢掉重
复登录重连路径现场验证通过(见上)。debug.log 全程干净(216 行,
无真实错误)。
本轮修改的文件
work/cmds/app/update.lpcwork/secure/sefun/file.lpcwork/secure/daemon/master.lpcwork/clone/user/user.lpcwork/clone/user/wizard.lpc
§7.100 sub-threshold instance (2026-08-20)
Found during the §7.100 tail-sweep (below the original 166-lib survey's
=100-occurrence threshold, never checked). 73 live
replace_program(ROOM); occurrences across 73 room files — mostly a
large d/menpai/wuliang/*.lpc sect-zone cluster (68 rooms including a
west/ subdirectory), plus d/city/matou/mache.lpc/kechuan.lpc and
a d/place/death/*.lpc cluster of 8 rooms. No room-building tool
exists in this lib. 4 pre-existing already-//-commented instances
left untouched. Fixed by deleting the redundant lines. Verified via a
clean native driver boot (zero new debug.log errors, port listening,
killed by exact PID after ~8s).
深度功能测试第三轮 / Deep functional test round three (2026-09-03)
新角度:巡捕游荡触发的城门 reset/make_inventory 路径(log/catch
里成串的 *Bad argument 1 to EFUN call_other() ... Got: int(0))、
留言板 post/read、酒楼 list/buy、真实死亡进入地府。
Bug(AGENTS.md §7.73 新实例):迷你版把装备挪到 npc/obj/,
NPC 仍按全局 HEAD_DIR/BLADE_DIR 取值 → 每次城门 reset 都
call_other(0)
xunbu 的 random_move() 懒加载城门房间时,make_inventory 克隆
士兵/卖花姑娘,其 create() 里无防护的 carry_object(...)->wear()/
wield() 对缺失路径返回 0,立刻炸:
| NPC | 坏路径 | 本档案实际位置 |
|---|---|---|
| liu_yan / run_yu | HEAD_DIR "huang_m" / "yu_jin" 等花 | d/city/yangzhou/npc/obj/*.lpc |
| shibing1 / shibing2 / xiaowei | BLADE_DIR + "changdao" | 同上 obj/changdao.lpc |
xo_final/xajh2 在全局 clone/wear/head/、clone/weapon/blade/
里有这些文件,所以同名代码在兄弟档不炸——这是迷你版裁剪后的路径
错位,不是内容彻底丢失。vendor_goods 也指向同样的坏 HEAD_DIR
路径,卖花 list/buy 同样会失败。
修复:花与长刀改为 __DIR__ "obj/...",并对所有
carry_object→wear/wield 链加上 §7.73 标准守卫(先赋值再
if (ob))。现场验证:goto 通泗门/安定门/镇淮门/草河小街/
禾嘉街,士兵与柳烟均正常出现;list liu yan 列出六种花;
buy 干菜包子 from xiao er(酒楼)成交;游荡约 20s 后
log/catch 中 0 条 call_other 错误(仅剩启动时已知的
emoted 损坏存档 restore_object 警告,CATCH 住、与本轮无关)。
本轮其它现场验证(无新 bug)
- 注册(字母-only id,3–12)→ 小秦淮客寓;管理员
fluffos/Mud@2026 - 留言板:
post <标题>→ 正文 →.→read N正常(§7.114 形状的edit/input_to通路干净) - §7.111
trace_line已有obj ? file_name : "<none>"守卫 - §7.112
chacha/mengpo的death_stage_active守卫在位; §7.113reconnect()含enable_commands()+set_heart_beat(1) - 死亡:
call <mortal>->die()进入黄泉路,北行经孟婆至鬼门关; 判官转世目标此前已按 §7.18 修过(三支均指向现存的kuixing_ge) give对 NPC 的obj->value()→destruct分支与兄弟档同形,是 给 NPC 钱的惯用写法,不是 §7.201(那是给玩家也 destruct)
本轮修改的文件
work/d/city/yangzhou/npc/liu_yan.lpcwork/d/city/yangzhou/npc/run_yu.lpcwork/d/city/yangzhou/npc/shibing1.lpcwork/d/city/yangzhou/npc/shibing2.lpcwork/d/city/yangzhou/npc/xiaowei.lpc
深度功能测试(§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-07)— 兵器的 actions 函数指针
set("actions", (: WEAPON_D, "query_action" :));:旧 MudOS 把 (: 字符串, "函数" :) 当作 call_other 函数指针,本驱动把它当作表达式函数指针,求值只得到字符串 "query_action"。没有对应兵器技能时 feature/attack.lpc 直接用兵器的 actions,COMBAT_D 拿到的不是 mapping,reset_action() 后仍不是,记一条 bad action 就不出招——拿着这些兵器打不出攻击。改成别的兵器早已用的 (: call_other, WEAPON_D, "query_action" :)(KB 04 §6.10):d/menpai/wuliang/west/npc/obj/flower.h。改动的文件在 HEAD 与工作树分别加载(新进程),无回退。
深度功能测试(§10.7,2026-10-08)— 编译警告整理
scripts/lpc_warnings.py xo --fix 加 scripts/lpc_fix_no_effect.py --apply,共改动 29 个 .lpc 和 3 个 .h(多为删去未用的局部变量)。HEAD 与工作树分别加载(新进程):23 -> 23 通过,无回退;改过的头文件的 4 个包含者 1 -> 1 通过。启动时警告 1 -> 0;新进程登录(输入名字)正常。
深度功能测试(§10.7,2026-10-08)— .lpc 后缀的定宽切片
.c 改名 .lpc 时只改了字符串没改切片宽度:f[<2..] == ".lpc" 拿两个字符比四个字符,永远不成立(!= 永远成立),按后缀筛文件、去后缀的代码因此从不运行或截成 x.l(KB 06 §7.238)。scripts/lpc_lpc_suffix_slice.py --apply 改了 2 处比较、0 处去后缀(如 secure/daemon/httpd.lpc);改动的文件 HEAD 与工作树分别加载(新进程),无回退。
编译警告收尾(2026-10-13)
手工清零(改动及相关对象在 HEAD 与工作树各载入一次,regress 0)。
clone/user/templet.lpc(存档autoload转换器)继承F_DBASE后又自己声明一个dbase:restore_object()填前一个、清空后一个,再存盘写出两条dbase,玩家下次载入可能读到空的那条(KB 06 §7.233)。删去自己的那个。system/std/char/npc.lpc私有的默认拒绝语refuse_msg与d/menpai/wuliang/npc/zuo.lpc等任务 NPC 自己的同名,私有的那份改名npc_refuse_msg。- 草稿
system/feature/todo/poison.lpc自己的毒药列表poison与它包含的旧include/poison.h的poison同名,改名poisons(文件里 9 处)。
- 2026-10-14:新驱动(FluffOS 970d9f09)报
Float value truncated to int(#1426)。4 个文件 6 处:赋值、初始化、return 改写成to_int(...)(值不变,只是写明截断);x op= 浮点先把浮点转成整数再运算(系数小于 1 时 x 直接变 0),改为x = to_int(x op ...):/cmds/app/explore.lpc(power +=)、/cmds/app/xplor.lpc(points +=)、/cmds/skill/xiulian.lpc(jilei_gain +=)、/secure/daemon/userd.lpc(x +=)。改动的对象新进程各载入一次,无回退(scripts/lpc_fix_float_trunc.py,KB 04 §6.10)。
- 2026-10-14:1 个文件因
Illegal to inherit after defining global variables整份不编译:FluffOS 要求所有inherit写在第一个全局变量之前,MudOS 不管。scripts/lpc_fix_inherit_order.py把写在inherit之前的全局变量(以及声明全局变量的头文件的#include)挪到最后一个inherit之后(KB 04 §6.3)。
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。3 处补上 if (!mapp(fam)) fam = ([ ]);(刚 recruit_apprentice() 之后的除外)。
NPC 带着本库没有的物品,载入失败(2026-10-15,KB 06 §7.73)
2 个文件、4 处在 create() 里 carry_object("<本库没有的文件>")->wear()(或 wield()、set_amount()):carry_object() 得 0,接着的调用报 Bad argument 1 to EFUN call_other(),NPC 根本载入不了,该有它的房间里就少了这个人。多是从别的系统搬来的 NPC 用了原系统的物品路径(最常见:/d/menpai/wuliang/obj/cloth、/d/menpai/wuliang/obj/changjian、/d/menpai/wuliang/obj/jian3)。每处改为 { object carried_ob = carry_object(...); if (carried_ob) carried_ob->wear(); }(scripts/lpc_guard_carry_object.py):NPC 照常出现,只是不带这件东西;文件补回来(或是虚拟对象)照样会带上。载入检查:改动的文件改前能载入 0 个,改后 0 个(0 个原来载入不了),没有退步;其余 2 个另有原因(多为 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):include/net/ftpdsupp.h。
全局头文件丢了 2 个宏(2026-10-19,KB 04 §6.16)
/include/globals.h 里没有定义 TASK_D、BET_D,用到它们的物件(名单里 3 个)编译时报 Undefined variable/Undefined function,整个物件载入不了(编译器在第一个未定义的名字上停下,后面的错误和警告都看不到)。同系的库在各自的头文件里都有这几行:照其中和本库共有文件最多的那个库,原样补到 /include/globals.h 最后一个 #define 之后,宏体里出现的路径在本库里都存在。补完后名单里有 2 个载入,其余还差别的东西。(scripts/lpc_restore_defines.py)
被注释吞掉的 inherit / include(2026-10-19,KB 06 §7.274)
/d/city/yangzhou/npc/obj/guo.lpc:#include <ansi.h>。这些指令接在上一行 // 注释的末尾(档案里丢了换行),成了注释的一部分,驱动看不到:缺 inherit 的技能报 Undefined function offensive_target,缺 #include <weapon.h> 的兵器报语法错误。scripts/lpc_fix_swallowed_directive.py 把换行放回去。载入检查 1 个文件,1 个原来编译不过、现在载入,没有退步。
补回本库没有的基类文件,第二轮(2026-10-19,KB 04 §6.15、§6.18)
宏有定义、基类文件却不在档案里:继承它的对象载入时报 Inherited file '…' does not exist!,编译扫描看不到这一类(scripts/lpc_missing_inherits.py 能列出)。同系的库里有同一个文件,原样拷来(scripts/lpc_restore_bases.py);基类和继承它的对象 include 而本库没有的头文件一起带来。每个基类补回后单独载入,再载入使用它的对象,载不进来、或一个用户也载不进来的撤掉了。
/system/std/task(宏TASK)←xajhxo:1/1 个继承它的对象载入
逐个与 HEAD 对比载入,没有退步。
标准整理轮,第二轮(2026-10-19,scripts/toolkit_fix.sh)
本库在新驱动下重扫,机械修复:1 个带初始化的未使用声明。修后与 HEAD 逐个物件对比载入,没有退步。
补回丢失的标点(2026-10-19,KB 03 §4.6)
转换时丢掉的分号、逗号、引号或文件末尾的 },共 1 个文件,修前 HEAD 载入失败。一行文字在逗号前丢了结尾的引号(下一行是同一个表的下一项),补上:/d/menpai/wuliang/west/npc/xin_shuangqing.lpc。修后与 HEAD 逐个对比载入:这 1 个物件全部载入,没有退步(scripts/lpc_restore_from_twin.py、lpc_fix_eaten_quote.py --comma、lpc_fix_eof_braces.py)。
set_name 的 id 参数(2026-10-19,KB 06 §7.260)和没有修的 delete()
/clone/wizard/edit.lpc(TMI-2 的行编辑器)里 set_name("编辑器", "editor") 改成 ({ "editor" })。文件仍然载入失败:它用 TMI-2 的 simul_efun delete(数组或字符串, 位置, 个数)(8 处),本库没有这个函数,调用落到物件自己的 delete(string)(属性删除)上,类型不符。这是巫师工具,没有重写。
补回丢失的标点,另一个版本的完好副本(2026-10-19,KB 03 §4.6 第四轮)
/system/menpai/wuliang/zuo_zimu.lpc:"姓名" : "嗯,你既知我姓左,……左子穆?, 丢了收尾的引号,补回;多出来没用到的局部变量声明(master_id、bonus、test)删掉。文件仍然载入失败:refuse_msg 只在 system/std/char/questnpc.lpc 里声明,这个物件没有继承它,是另一处改名遗留,没有改。
无量剑派掌门:补回 refuse_msg、wl-shenfa 改成 wuliang-shenfa、太祖长拳丢掉的引号(2026-10-19,KB 06 §7.258)
同 xajh2 的同名一节:system/menpai/wuliang/zuo_zimu.lpc 丢了 string *refuse_msg 的声明(取自 xajh2 的 d/menpai/wuliang/npc/zuo_bak_xli.lpc,补在 #include "east_master.h" 之后);zuo_zimu.lpc、qu_lianxing.lpc、rong_ziju.lpc 授的 wl-shenfa 是不存在的技能名,改成 wuliang-shenfa;system/skill/misc/taizu-quan.lpc 719 行 ......, 丢了结尾的引号(补成 ......",,文本取自 xo_final/system/skill/unarmed/level2/taizu-quan.lpc)。system/menpai/wuliang/obj/choushan.lpc 还写着 inherit EQUIP;,EQUIP 在 globals.h 里已经注释掉(xajh2 的同一个文件早已改成 #include <armor.h> + inherit CLOTH;,这里照改,两份现在逐字节相同)。qu_lianxing.lpc、rong_ziju.lpc、shang_yuqing.lpc 授的 parry 本库没有技能文件,system/feature/char/skill.lpc 的 set_wugong() 对没有文件的技能 error(),物件在 create() 里中止;set_wugong() 开头加 if (!valid_skill(skill)) return 0;(同文件的 set_xiuwei() 早已这样处理),物件照常载入,只缺这一项技能(KB 06 §7.256)。授了缺失技能的物件(活目录里)共 7 个。修后在 system/menpai/ 和这些物件上对比 HEAD 与工作树:载入 9 → 15(zuo_zimu、qu_lianxing、rong_ziju、shang_yuqing、choushan 和 pangzi),没有回归,没有警告。
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,共 4 处)。改动:/d/city/yangzhou/shufeng_guan.lpc(1 处)、/include/poison.h(3 处)。
tail 指令:tail(file) 驱动里没有(2026-10-20,KB 06 §7.291)
cmds/*/tail.lpc 调用 MudOS 的 tail() efun,FluffOS 没有,指令编译不过。模拟 efun 文件里补了 tail(file)(Discworld 家族的兼容版:文件最后约 20 行,从完整的一行开始,存在返回 1;scripts/lpc_add_sefun.py tail)。
登录密码超过 255 字节:crypt() 抛错(2026-10-20,KB 06 §7.294)
驱动的 crypt() 对超过 255 字节的密钥直接报错(Error in crypt(), check your salt),老驱动则按任意长度散列。在登录提示符下输入 256 字节以上的密码,密码检查那一行就抛错,连线停在一个裸的 > 提示符上,登录走不完(password 指令的旧密码检查同样);用 300 个 x 当参数的扫描发现的。/secure/daemon/sefun.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)。改动:/system/feature/user/more.lpc。
巫师命令不带参数时对 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() 之后的 2 个文件补了原型 int help(object me);,否则编译报 Undefined function help);没有 help() 的是 return notify_fail("…\n");。改动(3 个文件,括号里是接住 0 的 efun):/cmds/admin/changebody.lpc(present)、/cmds/admin/replace.lpc(get_dir)、/cmds/arch/ll.lpc(present)。加载检查 HEAD 与工作树对照,没有退步。
注册到不存在函数的 add_action,第二轮:宏路径父类和静态解析不了的对象(2026-10-21,KB 06 §7.349)
第一轮的静态解析读不了经宏路径继承父类的对象(#define ROOM STD_DIR "room/room" 这类定义的正文以另一个宏开头)和它解析不了的继承,这些对象当作 UNSURE 没有扫;第二轮修了解析器,重扫并对这些对象在运行时问 function_exists()。add_action("函数", "动词") 绑定的函数,在对象本身、它包含的头文件、它继承的父类和继承它的子类里都没有定义(scripts/lpc_scan_callout_targets.py 静态解析,子类用传递闭包复核,scripts/lpc_verify_handlers.py 运行时 function_exists() 复核)。驱动从玩家最新的一条动作往回找,遇到这样的句子就报 *Function for verb 'drop' not found.,同一个动词的其他处理函数不再尝试(不是最新的一条就悄悄跳过)。删除了 4 条注册(3 个文件,scripts/lpc_fix_dead_add_action.py),动词留给别的处理函数:/clone/misc/bandage.lpc(do_remove)、/d/city/yangzhou/yuelao_ci.lpc(do_divorce)、/system/std/room/kezhan.lpc(DoCheck、DoLoad)。最多的函数名:do_remove 1 处、do_divorce 1 处、DoCheck 1 处、DoLoad 1 处。
写死的 "/路径"->函数() 指向库里没有的文件:改成现存的同名文件(2026-10-22,KB 06 §7.359)
2 处语句级的 call_other 字面量路径,库里没有这个文件(区域改了名 / 大小写不对 / 差一个字母 / 文件挪了地方):"/cmds/arch/xplor"->QueryLevel()(/system/daemon/biwud.lpc)→ "/cmds/app/xplor"。call_other() 对不存在的对象抛 couldn't find object,所在函数当场中断。改成库里现存、并且定义了被调用函数的文件(scripts/lpc_fix_call_path.py;巫师目录、备份目录、名字不同的兄弟文件都不算候选)。
长度检查按字节写,旁边的提示按汉字写: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 处(3 个文件):if (strlen(msg) > 20)(/clone/misc/chatroom.lpc:69);if (strlen(msg) > 30)(/clone/misc/chatroom.lpc:75)。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 区间 3 个文件。证明(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 是两字符牌码,未改。
estate ROOM_HEAD 宏引号 / #inherit / dir / retrun(2026-10-27,KB 04 §6.25 Also)
system/daemon/estate 的 ROOM_HEAD/EXIT_STRING 宏里裸双引号打断 #define,模板写成 #inherit AREA,CreateRoom 用未定义的 dir,AddItem 写 retrun 且参数 class Location 本库无此类型。改为转义引号、inherit AREA、out_dir、return、mixed location。证明:HEAD 失败;改后加载。
深度功能测试(2026-10-27,§6.25 mooncake2 do_write 截断)
u/xli/mooncake2 的 do_write 在 tell_object(me,"你将祝福写在 处截断,且 if 缺 )。用同目录完好的 mooncake 的 do_write 覆盖。证明:HEAD 失败;改后加载。
深度功能测试(2026-10-27,§6.25 tell_object 字符串目标)
xinfang/chatroom/pplroomd:tell_object("ob", …)→tell_object(ob, …)。
深度功能测试(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… 行。