info.html · 介绍 · play.html · 游玩 · llms.txt · 下载与本地运行 · ZIP · GitHub
自称 天下无雪("A World Without Snow"),作者署名"Dream",鸣谢名单包括 Poor、Sinb、Lonely、Zjb 等多位巫师,是一个运营较久、拥有独立世界观的中文武侠 MUD。地图其实和"天涯"家族同源——`d/city/sj.lpc`("世界之巅"跳崖场景)与 `xysylmhb`/`xyzxiiylzymh`/`yzxiiizylfy` 等同样打着 "夕阳再现"或其它品牌、实际却是"天涯"血统的档案逐字节相同(本档案新角色随机落在的"北疆小镇""铁枪庙"等起点也和那几份档案完全对应),此前没有任何一份档案互相记录过这层关系;鸣谢名单里的"Lonely"正是 NT/nitan 系的作者,说明这个更大的生态圈之间本来就存在人员/代码交流。
English
Self-titled "A World Without Snow," credited to an author known as "Dream" with an acknowledgments list naming several fellow wizards (Poor, Sinb, Lonely, Zjb, among others) — a long-running Chinese wuxia MUD with its own distinct setting. Its map, however, turns out to share deep roots with this archive's "Tianya" (Horizon) lineage: several scenes, including its "Peak of the World" cliff-jump location, are byte-for-byte identical to areas in other differently-branded games in that lineage — a connection no prior entry in this archive had documented before. One of its credited wizards, "Lonely," is also the author of the Nitan series, hinting at genuine code and personnel exchange across this wider MUD community.
README
内容亮点
- 新角色会被随机安排到北疆小镇、铁枪庙、武庙或客店四处起始场景之一, 体验属性天赋分配、门派拜师、江湖历练等经典玩法。
- 游戏本身明确表态"严禁 PK",更偏重交友与探索,而非对抗竞技。
- 多个城市、门派(如丐帮、少林)都设有各自的木人陪练——攻击时会 原样镜像挑战者自身属性进行安全对练,如同真人一般。
在线试玩
https://mudlibs.fluffos.info/tianxiawuxue/
管理员账号 / Admin account
- ID:
fluffos - 密码:
Mud@2026 - 中文名: 浮浮
- 权限:
(admin)(本 mudlib 巫师等级表的最高级别) - 权限授予方式:
/adm/etc/wizlist数据文件追加fluffos (admin)。 - 小提示:本 lib 有一个"退出后需等待一段时间才能再次登录相同账号" 的防护(任何账号退出后都要等约 30 秒才能重新登录),这是原始代码 的正常游戏设计。
警告:对外公开架设前请务必修改此密码。
本地运行
cd libs/tianxiawuxue
~/src/fluffos/build-debug/src/driver config.fluffos游戏端口:40045。
NOTES · 移植与修复记录
tianxiawuxue — 天下无雪
Archive: 天下无雪.rar (#51). Port: 40045. Status: done (boots
clean, full registration flow verified end-to-end including a real
Chinese name entering the game world).
What this is
"天下无雪" ("A World Without Snow"), credit line "by Dream" (see the
in-game news banner and 2006.6.24 yc credit), thanks a wizard-team
roster (Poor/Sinb/Lonely/Zjb/Xxxqi/Yuchang/Lywin/Kool/Weal/Han) in its
welcome/news text. adm/obj/{master,simul_efun} layout (not
adm/single/), inherits per-object storage via feature/dbase.c
(inherit F_DBASE; in logind.c and elsewhere) rather than the
nitan-family shared-simul_efun dbase pattern — no AGENTS.md §15
architecture fix needed here (confirmed via source reading before
boot, same as rzrmud). ~15,737 raw files, 12,168 .lpc files after
rename — one of the larger libs in this batch.
Observation on lineage: this lib's adm/simul_efun/chinese.c is
byte-identical to xyzx3's (archive #48), processed in
parallel by another agent in this same project run — same standard
single-first-character is_chinese shape
(strlen>=2 && str[0]>160 && str[0]<255). Worth noting as a possible
shared "夕阳再现"/风云-family upstream common ancestor, though this
lib's own master.c/securityd.c/logind.c were read and fixed
independently rather than assumed identical beyond that one file.
Fixes applied
1. AGENTS.md §15h, standard shape, in
adm/simul_efun/chinese.lpc: is_chinese()'s GBK lead-byte check
(strlen(str)>=2 && str[0]>160 && str[0]<255) rewritten to a CJK
Unicode codepoint check (strlen(str)>=1 && str[0]>=0x4e00 &&
str[0]<=0x9fff).
2. AGENTS.md §15h, check_legal_name() in adm/daemons/logind.lpc:
byte-count bound < 2 || > 10 → character-count bound < 1 || > 5;
removed the i%2==0 && even-byte-offset gate so every character
position is checked. The message text ("必须是 1 到 5 个中文字")
already stated the correct intended character count, confirming the
halved bound is right, not a guess. The file has CRCRLF line
endings throughout (confirmed via cat -A) — used line-numbered
sed rather than a text-match Edit, since the literal \r\r
bytes don't match a plain-text search string.
The second loop (strsrch(name, banned_name[i]) substring check)
was left untouched per the task brief — strsrch works fine on
UTF-8 strings as-is, no fix needed there.
3. AGENTS.md §15p: /adm/daemons/network/dns_master was in
adm/etc/preload — removed proactively before the first boot
attempt. Confirmed via source read that its create() really does
call startup_udp() synchronously (not deferred via call_out()),
which calls socket_create()/socket_bind() directly at load
time — exactly the hang-risk pattern §15p warns about. Checked
every other preload entry (dynamicd, channeld, monitord,
storyd, toptend, fingerd, aliasd, commandd, autosaved,
rankd, virtuald) for socket_create/socket_bind/socket_listen
— none of them use any socket efuns, so no other exclusions needed.
4. AGENTS.md §14 (free, low-risk, applied on sight):
master.lpc's valid_override(file, name) was 2-arg only — added
the 3rd main_file parameter and OR'd it into the
SIMUL_EFUN_OB/MASTER_OB allow-check, matching the documented
3-arg apply signature for #included simul_efun fragments.
5. Confirmed NOT needed, via source reading, before the first boot
attempt:
- §4 (lazy security-daemon load_object recursion) — master.c's
valid_write/valid_read already gate via find_object(SECURITY_D)
only. valid_read has an unusual extra early branch
(if (!undefinedp(user)) if (!objectp(user=previous_object())) return 1;)
— left as-is per the task brief, not touched.
- §7 (missing get_root_uid/get_bb_uid) — both already present in
master.c, returning ROOT_UID/BACKBONE_UID.
- §15l (destruct-SIMUL_EFUN_OB-in-create() driver crash) —
master.c has no create() logic beyond a write() banner line;
no destruct call at all.
- §8c (this_player()-override footgun in a custom securityd) —
adm/daemons/securityd.c's valid_read is an unconditional
return 1; (no ACL at all), and valid_write never overrides
user with this_player(). No §15n/§15o custom-ACL gap either,
for the same reason — there's effectively no read-side ACL to
misfire against driver-internal compiles.
- Deep named.lpc fix — no named.c/named.lpc file exists
anywhere in this lib (only a stale data/named.o save file).
- No hidden pre-id prompt (no BIG5/GB font question, no student
age-gate) — logon() goes straight from the welcome banner to
the English-id prompt.
Interactive test result — full registration flow
Read logind.lpc's actual get_id/confirm_id/get_name chain before
testing (not assumed from another lib). Shape: welcome banner → English
id (get_id) → y/n confirm_id → Chinese name (get_name, accepted
directly on a valid name, no extra y/n confirmation step) → password
(new_password/confirm_password) → gift/attribute selection
(select_gift/get_gift) → email (get_email) → gender (get_gender)
→ enter_world.
banned_name contains the mud's own name ("天下无雪"/"天下有雪"),
pronouns, and a few political figures (毛泽东/邓小平/江泽民) — no Jin
Yong novel-character names in the list, so no swap was needed from the
default test name.
Verified the complete registration path in one continuous
mudclient.py connection: id qinfeng → confirm y → real Chinese
name 秦风 → accepted (no rejection) → password test1234 (set +
confirmed) → gift selection 0 (random) → confirm gift y → email
[email protected] → gender m → character created, entered the game world
at 铁枪庙 (Iron Spear Temple), the news system announced "又有一个新玩
家:秦风[qinfeng]" and "听说又来了一位叫做秦风的少年侠士", look
rendered the room correctly, quit produced the game's own ASCII-art
farewell banner. debug.log for the whole session has zero
error/denied/Undefined function/Bad argument/recursion/segfault
lines — only benign "Unknown #pragma, ignored" and "Unused local
variable" compiler warnings (both non-fatal, both extremely common
across this whole codebase family).
Re-verification pass (2026-07-23) — found and fixed a §15w bug; noted a rare, non-reproducible void-room anomaly
The original pass tested look but not score. Re-testing surfaced two
things:
1. AGENTS.md §15w, fixed: adm/obj/master.lpc's log_error()
unconditionally broadcast every compile *warning* to the connected
player as 编译时段错误:...warning:... — this lib's boot log shows
plenty of ordinary "Unknown #pragma" warnings, so any lazily-compiled
file would have spammed this. Fixed with the same strsrch(message,
"warning:") == -1 guard already applied to tianxia/shiji/
shujian2008 this pass. Still always logged to file.
2. A rare, one-off "new character lands with no environment" anomaly —
observed once, NOT reproduced despite 13 further attempts, not fixed:
on the very first registration test after the §15w fix (id qftxwx,
real Chinese name 秦风茜, female), look immediately after entering
the world printed the void-room fallback text
(你的四周灰蒙蒙地一片,什么也没有。, from cmds/look.lpc's
!env branch) instead of a real room — enter_world()'s
user->move(startroom) (picking randomly among 4 known-good, existing
start rooms via random(4)) apparently silently failed to place the
character anywhere. score still worked (showed a normal, correctly-
populated character sheet), and debug.log for that session shows
zero errors of any kind. Re-ran 13 more full registrations
afterward (across a driver restart, both genders, deliberately
targeting a fresh "first connection of the session" scenario a second
time to test for a boot-order race) and every single one landed
correctly in one of the 4 real start rooms (北疆小镇/铁枪庙/武庙/客店)
— the anomaly did not recur. Given it's not reproducible, produces no
error signal to chase, and 13/14 real registrations this pass (plus the
original pass's own successful run) landed correctly, this is
documented as an observed rarity rather than fixed blind — flagging
here in case a future pass sees it recur and can capture a live
repro/debug.log snapshot at the moment it happens.
lpcc sweep
Right after the driver was killed post-registration-test, free -h
showed only ~1.7GB free with 2.4GB already swapped — two *other* libs
being processed concurrently by other agents on this same host
(xyzxfy2's lpcc --batch alone at ~6.1GB RSS,
dtsl2's at ~1.1GB RSS and rising) had consumed most of
the 23GB host's headroom. Waited rather than starting a third
concurrent sweep on top of an already-below-threshold state; memory
recovered to ~8.7GB free a couple minutes later once those other
sweeps finished, at which point the sweep here ran cleanly (peaked at
~2.1GB RSS on the lpcc process, host stayed at 6.7-8.7GB free
throughout — no pressure requiring an early kill).
Result: 12,167 files, 11,873 pass / 294 fail (97.6%). Found and fixed one genuine, reasonably-cheap bug via the sweep:
d/kaifeng/ground0.lpc'sannouncing()had a stray extra}closing the function body right after theif (wizardp(snowcat)) tell_object(...)single-statement branch, leaving a danglingelsewith no matchingifand an extra unmatched}at the end of the function — a genuine pre-existing typo, not an encoding or rename artifact. This one shared base file is inherited by 4 zone room files (ground0/ground1/ground2/ground3, an arena/ tournament zone in 开封/Kaifeng), matching the "one shared dependency, not N separate bugs" pattern (AGENTS.md §8g). Fixed by removing the stray brace. Note: fixing this surfaced a second, unrelated, genuinely pre-existing gap in the same file —do_report()referencesSTEP_PREPARE/STEP_FIGHT/STEP_FINISHconstants that are defined ind/kaifeng/guanli.h/ground.hbut never#included byground0.lpcitself — left unfixed as a known content-completeness issue in this one non-critical arena zone file, not chased further (not on the registration/boot path).
The remaining ~293 failures were triaged by category, not fixed individually (consistent with AGENTS.md §6b/§13 — long-tail zone/ skill content, not registration-blocking):
Cannot #include <header>cluster, mostly under/u/lonely/and other wizards' personal home directories (u/lonely/obj/user/even contains what looks like a whole alternate personal master.lpc/simul_efun.lpc/quit.lpc sandbox) — genuinely missing headers in personal wizard-sandbox content, a real archive content gap (§13-style), not something to fabricate.Invalid simulated efunction overridecluster, entirely in/u/lonely/file.lpcand/u/lonely/obj/user/simul_efun.lpc— a wizard's personal simul_efun clone attemptingefun::ed/efun::cpoverrides thatmaster.lpc'svalid_overridecorrectly denies (onlySIMUL_EFUN_OB/MASTER_OBmay use those) — working as designed, not a bug.Undefined function message_combatdcluster (~26 files, all underkungfu/skill/) — same "only ever called, never defined" shape as AGENTS.md §15b'smessage_vision-family gap on a different lib, but never actually implemented anywhere reachable in *this* lib either as a real function or a simul_efun. Affects combat-message flavor text in specific skill special-attacks only; not fixed (would require guessing the intended signature/semantics from scratch — out of scope for a registration-flow verification pass, logged here as a known gameplay gap).syntax errorcluster (90) andIllegal charactercluster (58) — mostly individual pre-existing typos scattered acrosskungfu/class/*NPC files (undefined macros used as bare identifiers whereinheritexpects a string literal — e.g.inherit F_QUESTER;whereF_QUESTERis never#defined anywhere in this lib at all, andinherit SSERVER;where onlyF_SSERVERis defined — likely renamed/removed features from whatever this content was cloned from) plus a fullwidth-punctuation-in-code- position typo pattern (§9-style, e.g. a fullwidth;instead of;right after aninheritstatement) confirmed present in at least one file. None of this is on the registration/boot path (kungfu/class/*are individual boss/NPC "class" instances, not preloaded or reachable from character creation) — logged as a known long-tail content gap per AGENTS.md §6b, not fixed file-by-file.
Rebuilt-driver / formatter / WASM re-verification pass (2026-07-23)
1. LPC formatter applied across all 12,168 .lpc files in work/:
{"total":12168,"written":12007,"wouldChange":0,"unchanged":28,
"errors":133}. Checked for the ::fn()-after-( formatter bug
found elsewhere this pass (see tianxia/NOTES.md) — zero hits of the
(: : corruption signature anywhere in this lib. Verified
adm/obj/master.lpc's §14 3-arg valid_override and §15w
strsrch(message, "warning:") == -1 guard both survived reformatting
intact.
2. Native re-test against the rebuilt build-debug/src/driver:
booted clean (zero fatal/error in error handler/denied lines).
Full registration verified end-to-end via mudclient.py: id
txwxfmta → confirm → real Chinese name 秦风庚 → password ×2
→ gift/attribute selection (0/random, confirm y) → email
[email protected] → gender m → entered the game world at 武庙 (one of
the 4 known-good start rooms from the original pass), look/score/
quit all producing correct real output. debug.log for the
verified session: zero denied/undefined function/bad
argument/error in error handler lines. (One transient,
non-reproduced observation, noted in the same spirit as this lib's
own already-documented void-room anomaly above: an early boot-time
check briefly showed a Bad argument 4 to EFUN message() runtime
error attributed to adm/daemons/dynamicd.lpc's regenerate_map() →
tell_room(), a call_out-scheduled map-regen daemon unrelated to
registration; it was not present in the debug.log by the time the
full session above ran clean, and repeated checks afterward found no
trace of it — logged here per this lib's own convention of flagging
non-reproducible oddities rather than silently dropping them, not
chased further since it never affected any interactive test.) No new
fixes needed.
3. WASM test: boots cleanly through Initializations complete.
Login blocked by the documented query_ip_number() limitation,
in its most direct form yet seen this pass: adm/daemons/band.lpc's
is_banned(site) explicitly does if (!site) return 1; and
if (sscanf(site, "%s.%s.%s.%s", ...) != 4) return 1; — i.e. treats
any string that fails to parse as a 4-part dotted-quad as banned BY
DEFAULT (fail-closed), and logind.lpc's get_id() calls
BAN_D->is_banned(query_ip_number(ob)) before accepting any ID.
Since query_ip_number() doesn't return a well-formed address under
wasm, every connection is rejected with "你的地址在本 MUD 不受欢迎。"
(your address is not welcome on this MUD) regardless of the id typed.
Known driver-side wasm limitation, not a mudlib bug — not
patched (native login verified working cleanly above, same session).
WASM-enablement pass (2026-07-24)
Standard four-change pass (AGENTS.md §1.3b/§1.3e/§1.5), using the
CORRECTED (fail-closed) loopback pattern — loopback is strictly
== "127.0.0.1", == "::1", or a leading "127." prefix; a
non-string/empty/malformed IP is NOT treated as loopback (the
query_ip_number() WASM garbage-IP bug this defensive fallback existed
for is fixed upstream now).
1. Loopback-allow: adm/daemons/band.lpc is_banned(site) — this
was the documented WASM login blocker (if (!site) return 1; /
if (sscanf(site, "%s.%s.%s.%s", ...) != 4) return 1;, i.e.
fail-closed/banned-by-default on anything that doesn't parse as a
dotted quad). Added a loopback short-circuit to return 0 BEFORE
that fail-closed format check.
2. Uptime gate: none present — no connection-time uptime() startup
gate found anywhere in logind.lpc (searched the whole adm/
tree; the only uptime() uses are unrelated day/night-cycle and
channel-throttle bookkeeping).
3. Anti-flood throttles exempt loopback:
- adm/daemons/logind.lpc logon() (~line 127) — ban_cnt > 6
same-IP concurrent-connection cap now exempts loopback.
- adm/daemons/logind.lpc get_id() (~line 200) — ip_cnt > 18
same-IP registration-count cap (only applies to non-(welcome),
sub-wizard accounts) now exempts loopback.
- Left alone (in-game content, not hosting protection, per
AGENTS.md's KEEP list): the per-ACCOUNT (not per-IP) "距离上次
退出时间太短" quit-retention gates in get_id() (30s) and
get_passwd() (3s, non-wizards only) — these fire for ANY
reconnect regardless of address, loopback included, and are
clearly game/account design (preventing rapid relogin), not a
hosting-era IP throttle. Documented here since it repeatedly
affected this pass's own re-testing — fluffos/any account must
wait ~30s after a quit before its next login attempt.
- vaild_allow_address() in band.lpc (opt-in per-account
allowip-style address restriction, defaults to allow when unset)
— not touched; not a blanket gate, doesn't affect fluffos since
the account never sets allow_ip.
4. Admin account seeded: fluffos / Mud@2026 / 浮浮, registered
through the real flow (id → confirm y → Chinese name → password ×2
→ gift/attribute 0/random → confirm y → email → gender f →
enter_world). Granted (admin) (top rank) via /adm/etc/wizlist
(securityd.lpc only loads this file once in create() — restarted
the driver for it to take effect). Save files:
data/login/f/fluffos.o, data/user/f/fluffos.o — neither
gitignored (a plain git add picks them up, no force-add needed).
Verified: update /cmds/usr/score.lpc → 重新编译 /cmds/usr/score.lpc
:成功! with (admin) shown at login banner.
5. Real bug found and fixed: maximum evaluation cost : 400000 in
config.fluffos was far too low for this lib (10-100x smaller
than every comparable lib in this project, which all sit in the
5,000,000-50,000,000+ range — the original archive's own
config.cfg never set this value at all, so 400000 was an
under-provisioned guess made when config.fluffos was first
written). Symptom: *Too long evaluation. Execution aborted.
fired routinely and reproducibly in ordinary gameplay code —
feature/move.lpc move(), feature/command.lpc
command_hook(), adm/daemons/natured.lpc's day/night cycle,
cmds/std/look.lpc — 43 occurrences accumulated over this pass's
testing alone, caught by master.lpc's error handler (non-fatal)
but silently truncating whatever the current top-level call was
mid-execution. This is almost certainly the root cause of this
lib's own previously-documented "rare, non-reproducible void-room
anomaly" (a brand-new character occasionally landing with no
environment()) and the "Bad argument 4 to EFUN message() /
one-off Too long evaluation" oddity flagged in the prior
rebuilt-driver pass — both were enter_world()'s user->move(startroom)
(or an adjacent step in the same call chain) getting aborted
mid-way by this same eval-cost ceiling, most likely to bite right
at boot (dynamicd.lpc's regenerate_map() call_out fires 1 second
after create() and does a synchronous, tell_room()-heavy
room-regeneration loop) but reproduced here in ordinary gameplay
commands too, unrelated to boot timing. Fixed by raising it to
5000000 (matching the common convention across sibling libs in
this project). Reproduced the void-room-style registration TWICE at
the old value (once with fluffos itself, once with a throwaway
qftxwuxueb-class test id is not accurate — see below) and PASSED
CLEANLY with zero new Too long evaluation lines after the config
change, across both a fresh registration run immediately after boot
(the exact regenerate_map()-collision window) and a normal
fluffos login. This is a config fix, not a mudlib/gate fix, but
documented here since it was found and fixed as part of this pass
and materially improves WASM/local-play stability (a WASM tab
registering immediately after boot is exactly the scenario this bug
hit hardest).
6. Retest: fresh registration (qftxwuxue/秦风, then a second
qftxwuxueb/秦风 run immediately post-restart to confirm the eval-cost
fix — both deleted after test, including their data/user/data/login
save files) end-to-end into 武庙/other real start rooms with
look/score/quit all producing correct output. fluffos login +
update wizard command verified in a separate session, both
before and after the config change. debug.log: no denied/
undefined function/error in error handler/bad argument lines
from any of these sessions; the pre-existing, unrelated
dynamicd.lpc tell_room()-on-a-missing-room Bad argument 4 to
EFUN message() cosmetic bug still fires on its own 30-minute
schedule (not on the registration/login path) — not fixed, out of
scope for this pass.
深度功能测试 / Deep functional test (2026-07-24, round two)
First real *playthrough* pass on this lib per AGENTS.md §10.7. Read
doc/help/newbie{,1,2,3,4} and doc/help/combat in full first — note
that this content is recycled from a DIFFERENT, unrelated upstream game
(it repeatedly names itself "晚霞"/"红尘", uses "hc" as its own
abbreviation, and describes a Yangzhou-centric map with a gc central
square and sects/mechanics that don't match this installation at all)
and does not reflect this lib's actual starting rooms or geography —
harmless (nothing crashes because of it) but a documentation-quality
observation, not fixed, out of scope. README.md's own description
(four random start rooms, sect/拜师/江湖历练) is accurate and was used
instead. Native driver (build-debug), one continuous character
(shenmubai/沈慕白) across many scripts/mudclient.py sessions, each
session's own close (no quit) itself exercising an unclean/net-dead
disconnect.
Task directive: check for the tianxia-sibling changed_match_path
bug first. This lib does NOT share it. tianxia's bug was a
never-defined changed_match_path(mapping, string) simul_efun restored
as a bare passthrough to the real match_path() efun. tianxiawuxue
has no such function anywhere (confirmed via grep -rn
changed_match_path — zero hits) and uses a completely different,
architecturally-correct storage mechanism: feature/dbase.lpc (inherit
F_TREEMAP;, not a simul_efun-based property store) delegates
multi-segment "a/b"-style property paths to feature/treemap.lpc's
own _query()/_set()/_delete() — genuine hand-written recursive
nested-mapping descent (explode(prop, "/"), walk one segment per
level), never touching the real match_path() efun at all (confirmed
grep -rn '\bmatch_path\b' outside doc/ has zero hits in work/).
Traced feature/command.lpc's bare-directional-movement fast path
(environment()->query("exits/" + verb)) by hand against
treemap.lpc's _query() and confirmed it correctly returns the
nested exits["west"] value. Live-verified this explicitly, per the
task's own instruction to test BOTH forms: registered 沈慕白, and
both bare west/east/north/south/northwest/out etc. AND go
<direction> correctly moved the character through 20+ distinct rooms
across several zones (长安/北京城2/华山派练武场/丐帮地下暗道) with no
asymmetry between the two forms. No fix needed here — noted for the
record since the task specifically asked.
Test character (kept, not cleaned up, as playthrough evidence): id
shenmubai, Chinese name 沈慕白 (male), password TxTest2026#.
Random gift roll: 膂力23/悟性20/根骨22/身法15. Final state: at a
valid_startroom (location re-randomizes on every fresh login — see
bug/observation below, so "current" location is not meaningful state);
no sect/skill acquired (see below); inventory Cloth/Trans site
(魔法传送帖); credits/deaths reset to 0 after an unavoidable mid-session
driver restart (§10.5-consistent — only save/quit persist state, an
in-memory-only death from before a restart does not survive it, which
is expected, not a bug). Saves: work/data/user/s/shenmubai.o,
work/data/login/s/shenmubai.o.
Bug found and fixed (NEW class): safe-sparring training dummies (mu-ren/muren, 9 files) never set can_speak, so fight/hit route every spar attempt through the REAL lethal kill_ob() path instead of the dummy's own carefully-written safe accept_fight() — live-reproduced player death on the very first hit
Files: d/city/npc/mu-ren.lpc, d/shaolin/npc/mu-ren.lpc,
d/shaolin/obj/mu-ren.lpc, d/shaolin/npc/obj/mu-ren.lpc,
d/quanzhen/npc/muren.lpc, d/mingjiao/obj/mu-ren.lpc,
d/mingjiao/npc/obj/mu-ren.lpc, d/shushan/obj/muren.lpc,
d/working/obj/mu-ren.lpc.
- How this was found: per AGENTS.md §10.7 item 3 and this task's explicit instruction, went looking for the lib's own safe-sparring mechanism before risking a real fight. Found
d/shaolin/npc/mu-ren(a training-dummy NPC placed ind/city2/wuchang.lpc's 练武场, reached viatrans tam+ 6 hops) with an elaborate, obviously intentionalaccept_fight(object ob)override: it copies the attacker's own skills/skill-maps/stats onto itself (ob->query_entire_dbase()→me->set(...)for str/int/con/dex/ qi/jing/neili/jiali), sets"no_die": 1on itself, and tracksfight_times/last_fighterso it "breaks" after repeated use rather than ever dying — unambiguously a purpose-built, always-safe practice partner, matchinghelp combat's own promise thatfight/hitnever cause real death ("不会真的受伤"). Usedfight mu renagainst a fresh, unequipped, level-0 character expecting a guaranteed-safe bout — and the training dummy killed the character outright on its second real exchange (你口中喷出几口鲜血,倒在地上,死了!, death counter went from 0 to 2 across two separate spar attempts before a later driver restart reset the unsaved counter back to 0). - Root cause:
cmds/std/fight.lpc'smain()only callsobj->accept_fight(me)inside anif (obj->query("can_speak")) { ... }branch; theelsebranch (taken whenevercan_speakis unset/falsy) skipsaccept_fight()entirely and instead runsme->fight_ob(obj); obj->kill_ob(me);— REAL, lethal combat, the exact same callkill.lpcwould make.cmds/std/hit.lpchas the identical shape. None of the 9mu-ren/murendummy files everset("can_speak", 1)(confirmed:can_speakappears nowhere in any of them before this fix), soquery("can_speak")returns0/undefined for all of them, and EVERYfight/hitagainst a training dummy — lib-wide, in every zone that has one — silently took the lethal branch instead of the safety-net branch its own code was clearly written for. Confirmedaccept_fight()is called from NOWHERE else in the entire codebase (grep -rn 'accept_fight(' work/cmds work/feature work/inherit, only hit:fight.lpc's one call site plus the base definition ininherit/char/npc.lpc) — sofightreally is the sole intended entry point, and thisno_die-flagged, stat-mirroring dummy'saccept_fight()was provably 100% dead code before this fix, for every single instance in the archive. - Why this isn't the "a safe spar that isn't perfectly safe" design choice AGENTS.md §10.7's scope note warns against fixing: that caution is about
help combat's own documented risk when the skill gap between two REAL opponents is too large (an intentional balance mechanic). This is categorically different — a single-purpose,no_die-flagged practice-dummy NPC whose entire elaborate stat-mirroring safety mechanism is architecturally unreachable via the only command that could ever invoke it, contradicting both its own code's obvious purpose and the command's own player-facing help text. Confirmed byte-identical in the pristine raw archive (raw/mud/world/kungfu/…n/a — dummy files are underd/, checkedraw/mud/world/d/city/npc/mu-ren.cetc.; thecan_speak-less shape matcheswork/exactly) — an original-game bug, not introduced by conversion, but squarely "making its own already-intended logic actually work" per the scope note's own test, not a balance judgment call. - Fix: added
set("can_speak", 1);right afterset_name(...)in all 9 files (the dummy's ownlongdescription already says "如同 真人一般" — "as lifelike as a real person" — so this is consistent with its own flavor text, not an invented property). This is a narrow, local, zero-blast-radius fix: it does NOT touch the sharedfight.lpc/hit.lpccommand files (which route hundreds of other, genuinely-hostile silent NPCs system-wide and were deliberately left alone, since auditing whether ALL of those should also gain a safe-negotiation path is a design question outside this task's scope), and does not affect any other NPC in the lib. - Verified live, before/after: before the fix,
fight mu ren(matchable id is the two-word"mu ren", not"muren") against thed/city2/wuchangdummy killed the fresh test character on the second exchange. After the fix (recompiled via thefluffosadmin'supdate /d/shaolin/npc/mu-renetc., all 9 files individually confirmed "重新编译 ... :成功!", then a full driver restart to be certain), the identicalfight mu rensequence against the same dummy correctly ran several rounds of real-looking combat log text, then the dummy conceded (木人胜了这招,向后跃开三尺,笑道:承让!) — matching the siblingtianxialib's own documented safe-spar-concedes shape — the character survived with<气>(stamina) depleted but no injury, gained+1 实战经验/+1 潜能, and你共死亡stayed at0.debug.logshowed zero new lines from either the pre-fix death or the post-fix safe spar. - This is a NEW bug class for AGENTS.md's catalog — see draft below (not added to AGENTS.md directly per this task's instructions).
Bug found and fixed: kungfu/class/gaibang/hong.lpc's attempt_apprentice() wraps two rejection conditions in mapp(), which is always false for a boolean/int comparison result, permanently bypassing both intended sect-entry gates
File:line: kungfu/class/gaibang/hong.lpc:75 and :79.
- How this was found: while looking for an accessible sect to exercise the organic
apprenticepath withshenmubai's randomly rolled (and comparatively weak) stats, read everyattempt_apprentice()override inkungfu/class/*/*.lpclooking for one without a hard-to-satisfy stat gate. 洪七公 (hong.lpc, 丐帮/Beggars' Sect's 17th leader) has:
``lpc
if (mapp(ob->query("shen") < 100000)) {
command("say " + RANK_D->query_respect(ob) + "的侠义不够啊,怎么能成为我老叫花的徒弟呢");
return;
}
if (mapp(ob->query_skill("huntian-qigong") < 600)) {
command("say " + RANK_D->query_respect(ob) + "的本派内功不够啊,怎么能成为我老叫花的徒弟呢");
return;
}
`
ob->query("shen") < 100000 and ob->query_skill(...) < 600 are
both relational-comparison expressions that evaluate to plain int
0/1 — mapp() is the driver's mapping-type predicate and returns
0 (false) for ANY non-mapping argument, including these ints. So
mapp(<anything> < <anything>) is unconditionally 0, the if
body (the rejection) can NEVER execute, and both gates are dead code:
every character, regardless of actual shen/skill level, sails past
these two checks. This sits directly between a correctly-formed
guard two lines above it (if ((int)ob->query_str() < 30 || (int)
ob->query_con() < 25) { ...; return; }, no mapp()) and another
correctly-formed guard four lines below it (if (mapp(ob->query
("family")) && ...), where mapp() is used CORRECTLY because
ob->query("family") really is expected to be a mapping) — the
mapp() wrapper on the two broken lines is an obvious copy/paste
artifact from the third guard's *correct* usage of mapp()`, applied
to the wrong kind of expression on the two lines above it.
- Confirmed present byte-identical in the pristine raw archive (
raw/mud/world/kungfu/class/gaibang/hong.clines 78/82) — an original-game bug, not introduced by conversion. - Fix: removed the erroneous
mapp()wrapper, restoring plain boolean guards matching the surrounding code's own established pattern:
``lpc
// BEFORE:
if (mapp(ob->query("shen") < 100000)) { ...; return; }
if (mapp(ob->query_skill("huntian-qigong") < 600)) { ...; return; }
// AFTER:
if (ob->query("shen") < 100000) { ...; return; }
if (ob->query_skill("huntian-qigong") < 600) { ...; return; }
``
- NOT fully live-verified end-to-end — recompiled cleanly via the
fluffosadmin'supdate /kungfu/class/gaibang/hong(confirmed "重新编译 ... :成功!", no compile errors), but reaching 洪七公 himself (d/city/gbxiaowu.lpc, "林间小屋") turned out to be gated behind a SEPARATE, legitimate design mechanism: the only mapped entrance (d/city/gbandao.lpc, "暗道") has its ownvalid_leave()override that blocks any non-丐帮 character from proceeding further via an NPC (简长老) that physically attacks and repels outsiders — i.e., you must already be in the sect to reach the sect leader who recruits you, an unrelated chicken-and-egg gate this task's time budget didn't allow fully tracing (possibly a different, unmapped entrance exists; not investigated further). Themapp()logic error itself is unambiguous from static reading and the clean recompile confirms no syntax regression, but the actual in-game consequence (does a low-shencharacter now get recruited, live) is explicitly unverified, flagged honestly rather than claimed.
Observation (NOT fixed — genuinely ambiguous, documented per the task's own instruction rather than guessed): fresh characters' spawn location is re-randomized on literally EVERY future login, not just the first, because enter_world()'s success branch never persists "startroom"
File: adm/daemons/logind.lpc, enter_world(), contrast the success
branch (~line 690) against the fallback branch (~line 693-695).
if (file_size(startroom + ".lpc") > 0 && !catch(load_object(startroom)))
user->move(startroom); // <-- no user->set("startroom", ...) here
else {
user->move(start_room[i]);
startroom = start_room[i];
user->set("startroom", start_room[i]); // <-- only the fallback persists it
}- How this was found: registered
shenmubai, landed at 客店 (/d/city2/kedian). Later, after an unavoidable driver restart mid- session (destroying the live in-memory object, forcing a realrestore()+enter_world()fresh-login path rather than areconnect()), the SAME character landed at a completely different room (北疆小镇, one of the other 3start_room[]entries) despite never having died or explicitly relocated. Traced this toenter_world():startroom = user->query("startroom")is read on every login, but the only two places that ever WRITE it are (a) this function's own fallback branch (only reached if the previousstartroomfailed to load — not the normal case), and (b)cmds/usr/save.lpc'ssavecommand, and ONLY when the player is standing in a room withset("valid_startroom", 1)at the moment they typesave. Confirmed no other write site exists (grep -rn 'set("startroom"' work/→ exactly these two). The periodicadm/daemons/autosaved.lpcdaemon (runs every ~600s on every connected player) calls the bare->save()method, NOT thesavecommand's logic, so it does not setstartroomeither. Net effect: unless a player deliberately typessavewhile standing in one of the four starter rooms, EVERY subsequent full login (not just the first) re-rolls a fresh random start room fromstart_room[random(4)]. - Why this is genuinely ambiguous, not a clear-cut bug: (1) Confirmed byte-identical in the pristine raw archive (
raw/mud/world/adm/daemons/logind.clines 704-717) — an original, never-since-fixed shape, not introduced by this project's conversion. (2) Thesavecommand's own player-facing text — "当你下次连线进来时,会从这里开始" ("next time you connect, you'll start from here") — explicitly frames binding a spawn point as an opt-in player action, which reads as consistent with "random until you bind" being the intended default, not an oversight. (3) However, the sibling libtianxia's equivalententer_world()(libs/tianxia /work/adm/daemons/logind.lpc~line 1049) DOES calluser->set ("startroom", startroom)in BOTH branches, making a first-time-random spawn point sticky from then on automatically — a meaningfully different (and arguably more standard) design for the same lineage family, which raises real doubt about whether the missing call here was actually intentional or itself an unnoticed upstream bug thattianxiasimply doesn't share. - Per AGENTS.md §10.7's explicit scope note (which uses almost this exact shape — "a 'safe' spar that isn't perfectly safe" — as a worked example of a design choice NOT to fix) and the task's own "when genuinely unsure, document, don't guess" instruction: left UNTOUCHED. Documented here for a human maintainer's judgment call, not silently ignored.
Sixth independent occurrence of the known driver-fatal crash class (AGENTS.md §10.8) — corroborating, not a new mudlib bug
During this pass's net-dead soak window (character disconnected uncleanly, driver left running idle ~12 minutes with no player commands), the driver process itself aborted:
md: debugmalloc: attempted to free non-malloc'd pointer <addr>
Aborted (Signal sent by tkill() <pid> 1000)with a full C++ backtrace through reclaim_objects() →
gc_mapping() → check_svalue() → free_svalue() →
dealloc_object() → debugfree() → MDfree()'s own internal
consistency check aborting — i.e., triggered by the driver's own
periodic ~5-minute remove_destructed_objects()/reclaim_objects()
GC sweep, the exact same trigger path §10.8 already documents for
shenzhou. This is corroborating evidence for the existing §10.8
entry (now six independent occurrences across six unrelated
libs/lineages), not a new finding — flagged here per §10.8's own
"treat 'the process was still alive at the end' as worth checking"
guidance, not silently omitted. One small refinement to the existing
note: unlike every prior occurrence (which left debug.log
completely untouched), THIS occurrence's debugmalloc warning line
was captured in debug.log (one line, no further detail) —
apparently that specific abort path routes through debug_message()
before abort(), unlike the plain ref-count-consistency-check crashes
in the other five occurrences. Not mudlib-fixable; not root-caused
further here, consistent with the existing entry's own conclusion.
What was tested and confirmed working
- Registration: real Chinese name (沈慕白) through the full gift- selection/email/gender flow into a real random
valid_startroom(varied across sessions: 客店, 武庙, 北疆小镇 all observed — see thestartroomobservation above for why). - Movement/exploration: both bare directional commands AND
go <direction>(see thechanged_match_path-check section above), 20+ rooms across 长安/北京城2 (王府井/地安门/天安门/太庙-adjacent streets)/华山派/丐帮暗道/一片"青竹林" random-move maze zone (a legitimate lost-in-the-woods mechanic, not a bug — eventually exits via any repeated direction). - Long-distance travel:
trans <code>(Trans site/魔法传送帖, a starting-inventory item) correctly teleported the character tohs/华山,gc/扬州广场,tam/天安门 instantly, each with the correct "身影突然出现在一阵烟雾之中" flavor text and a real 10-jingcost — confirmed reaching the intended LIVE zone each time (not a stale/backup path, no §7.18-shaped bug here). - Safe sparring:
fight mu renagainst thed/city2/wuchangtraining dummy — see the bug writeup above (confirmed genuinely unsafe before the fix, confirmed genuinely safe, auto-concede, reward-granting after it). - Sect join (organic NPC path), mechanism confirmed working even though not completed:
apprentice yue/apprentice buqunagainst 岳不群 (华山派 sect head, reached viatrans hs) correctly triggered hisattempt_apprentice()dialogue and correctly rejected the character on legitimate content grounds (shen<10000,dex<25— both real, intentional stat gates, confirmed via source reading, not a bug); same against 令狐冲's lower-but-still-unmetint<25gate (read only, not reached live — see travel notes in the earlier "Interactive test result" section of this lib's own history for why 舍身崖 wasn't attempted this pass, prioritizing the more reachable target instead). Theapprentice/command()-self-call chain itself (message_vision,set_temp("pending/apprentice", ...)) ran correctly with no crash or error in every attempt — the MECHANISM works; this character's own randomly-rolled stats simply never qualified for either master tried, which is content, not a bug, per AGENTS.md §10.7's scope note. learn: readcmds/skill/learn.lpcin full (requiresis_apprentice_of()orrecognize_apprentice(), neither ever true forshenmubaigiven the above) — mechanism understood but NOT exercised live, since no sect join ever succeeded this pass. Honestly unverified, not claimed as tested.- Clean
quit: correct ASCII-art farewell banner (/adm/etc/welcome1) +me->save(); destruct(me);, zero newdebug.loglines immediately after, confirmed multiple times across the session. - Unclean (net-dead) disconnect + PROMPT reconnect (within the 600s
NET_DEAD_TIMEOUT,include/user.h): everymudclient.pysession in this pass that didn't end inquit(i.e., almost all of them) was itself a real unclean disconnect; reconnecting shortly after consistently printed重新连线完毕。and resumed the exact same live object/room, confirmed repeatedly (e.g. mid-navigation rooms with no other way to be standing in them). - Admin account (
fluffos/Mud@2026): confirmed working,(admin)status,update <path>successfully hot-recompiled all 10 edited files with "成功!" and no errors — used deliberately as afind_body()+move()teleport shortcut viaeval(per AGENTS.md §10.3's instrumentation guidance) after this lib's dynamically- changing/maze-like room graph made hand-navigated pathing to a specific distant NPC unreliable;work/tmp/had to be created first (missing directory,eval's scratch-file write otherwise fails — a minor pre-existing admin-tooling gap, not fixed, out of scope, removed again before finishing).
What was NOT verified live, and why
- Full 600-second
NET_DEAD_TIMEOUTforce-quit reconnect path: attempted via a real wall-clock wait, but the driver process itself crashed during that same idle window from the independent, known §10.8 driver-fatal class documented above (a sixth corroborating occurrence, itself a legitimate finding), before the timeout could fire and be observed. Given the time already spent this pass, this check was not re-attempted after restarting the driver. Explicitly unverified — not claimed as tested. (The PROMPT-reconnect path, the mechanically-adjacent code, was verified repeatedly, above.) - State persistence across a clean
quit+ real wait + reconnect: a cleanquitwas run and confirmed error-free, but the driver crashed (same §10.8 event) before a deliberate post-quit wait + reconnect could be re-run in this final pass. Money/inventory/skill state WAS repeatedly confirmed correctly round-tripping across the many earlier prompt-reconnects earlier in the session (strong circumstantial evidence the same save/restore path is sound), but this specific checklist item was not independently re-verified after the crash. Explicitly flagged, not silently assumed. hong.lpc's fix, live end-to-end (recruitment actually succeeding with a low-shencharacter) — blocked by a separate, legitimate access-gate mechanism reaching 洪七公 himself; see the bug writeup above.- A real shop purchase (
buy/list): identified a reachable vendor (d/city2/npc/xiaofan.lpc,list/buyviainherit F_VENDOR,feature/dealer.lpc) very close to the starting客店zone and read its fulldo_list()/do_buy()implementation, but ran out of session time (driver crash, then the coordinator's explicit time-box) before actually executing a live purchase. Explicitly unverified, not claimed as tested. - Real combat to death / respawn: not attempted (per the task's own guidance to use the safe-sparring mechanism first, which consumed most of this pass's combat-testing time investigating and then fixing the mu-ren bug above). Death/reincarnation code was not read this pass.
- WASM interactive playthrough: this pass was native-driver only, per the task's own instructions.
深度功能测试(2026-08-14,round three,新驱动重测)
针对驱动升级(quest_times/win_times %-operator 修复 + Warning/warning
大小写回退兼容)做的重测,逐项独立核对了本轮新确立的检查项(不只
是信任 NOTES.md 已有记录):log_error() 确认已经有严重度判断;
安全陪练木人 can_speak 修复仍然生效——现场用 fluffos 管理员对
d/city2/wuchang 的木人打了完整一轮 fight mu ren(受伤但非致
命,score 确认"你共死亡:0 次"),修复稳定持续生效;
feature/dbase.lpc 未发现密码写保护;win_times 的
%-operator 也已用 to_int(query("win_times")) % 5。§10.8 已归
档的驱动级致命崩溃类问题不属于本轮 mudlib 检查范围。
本轮新发现并修复的 PROGRAMMING bug
1. §8.9 食物/饮水初始化判断的对象错了:adm/daemons/
logind.lpc 的 enter_world() 里 ob->query("age") == 14(应为
user)。已改成 user->query("age") == 14。
2. get_resp()/get_name()(adm/daemons/logind.lpc)各有一处
调试残留 printf("%O\n", ob)(AGENTS.md §7.34-class):紧跟
在中文名字确认之后,把连线桩物件的原始引用直接回显给正在注册
的新玩家。已删除两处。
3. log_file()(adm/simul_efun/file.lpc)本身缺少
assure_file() 保护:已加上前向声明 +
assure_file(LOG_DIR + file);。
4. cat()(同一文件)对不存在文件的空指针式崩溃,主动加固:
未在本档案现场触发,属主动加固,改成 write(read_file(file) ||
"");。
实测过程
管理员 fluffos/Mud@2026(此前已确认可用)真实重连两次(先用
update /adm/simul_efun/file 触发了这个档案已知的 §include 型
simul_efun 限制——/adm/simul_efun/file.lpc 被 #include 进
adm/obj/simul_efun.lpc,不是独立编译单元,update 直接指向它会
报"No program in object",改用一个真正独立的物件
/adm/daemons/logind 验证写权限:"重新编译
/adm/daemons/logind.lpc:成功!")。第二次单独验证密码重连本身。
均成功登录,存档数据一致。全程 debug.log 无运行时错误(除了我自
己误触发的 §include 限制产生的编译期错误,与 mudlib 本身无关)。
驱动按精确 PID 结束;测试期间产生的帮会背景数据/存档时间戳增量已
git checkout -- 还原。
WASM 修复摘要(迁移自 meta.json 的 group_note)
状态已从过时的 limited 修正——这份档案自己的 README 里从未记录过任何缺陷说明,本轮重新测试也没有发现:管理员登录(fluffos/Mud@2026)干净正常,"★ 您目前权限:(admin)"。
§7.86 跨库扫描修复(留言板 post 崩溃)
BULLETIN_BOARDinherit+ 多余replace_program()致命形状(AGENTS.md §7.86,post命令崩溃):全档案 94 处命中,已删除多余的replace_program(...)调用(保留inherit),逐文件保留原有行尾格式(CRLF/LF 按文件原样)。本次为跨库 §7.86 扫描修复(触发原因:该 bug 已在 6+ 个互不相关的血统家族独立确认,属于近乎普遍的拷贝粘贴模式),仅做编译检查(驱动干净启动、端口正常监听),未做完整 §10.7 深度游玩测试。
AGENTS.md §7.100 修复(2026-08-19,批次五)
ROOM 基类冗余 replace_program(ROOM); 自崩溃地雷(详见 AGENTS.md
§7.100):3004 个房间文件的 create() 里紧跟 inherit ROOM; 之后
都有这一行多余调用,永久设下"待替换"标记,第一次对该房间对象绑
定闭包就会崩溃。自带建房工具有 8 份拷贝(clone/misc/roommaker.lpc
及 7 个巫师目录下的副本),其中 u/lonely/obj/roommaker.lpc/
roommk.lpc 各自有 3 处独立的字符串拼接地雷(缩进/后缀写法略有不
同),全部逐一手动摘除。
修复:脚本化删除所有房间文件里独立成行的 replace_program(ROOM);,
加上 8 处模板手动摘除字符串拼接片段。git diff --stat:3004 files
changed,与预期精确吻合(0 处遗留匹配,全部干净)。
验证:build-debug 驱动真实冷启动,端口 40045 正常监听,
debug.log 全程干净。既有管理员账号 fluffos/Mud@2026 登录正常
(落地武庙,look/quit),全程无新增
"cannot replace"/"cannot bind" 日志行。
Round-four §10.7 deep test: closing the 2 flagged gaps (2026-08-20)
Targeted the exact 2 items the prior round-two pass explicitly left
unverified (shop purchase, real combat to death/respawn), plus a fast
checklist sanity pass. Native build-debug driver, two concurrent
live telnet sessions (custom incrementally-flushing Python client,
since the standard mudclient.py buffers its whole transcript until
the connection closes and can't be watched mid-session or interleaved
with a second connection) — one as the existing admin fluffos, one
as a brand-new throwaway test character qindtest/秦斗 (per this
session's "separate throwaway character, not a 'clean' representative
one" precedent), used together so the admin could teleport the
throwaway character via eval + users()/file_name() (goto only
repositions the admin's own body, not another player's).
Gap 1 — real shop purchase: COMPLETED, works correctly, no bug
Read feature/dealer.lpc's do_list()/do_buy() (as the prior pass
already had) and completed a live purchase this pass. Cloned
/clone/money/coin onto fluffos via eval (had to split into two
eval calls — new(...)->move(this_player()) then a second
present("coin", this_player())->set_amount(500), since set_amount()
is void and chaining it directly after new() in one expression
made the following ->move() call on eval's own return value fail
with *Bad argument 1 to EFUN call_other(); this is a limitation of
eval's single-expression wrapper, not a mudlib bug), then goto
/d/city2/xidan (one of the two rooms carrying the xiaofan vendor
identified last pass) and buy bingtang hulu. Result: exactly
correct. Before: 500 coin. Item price per list: 五十文钱 (50
coin). After purchase: 50 coin + 4 silver (= 450 coin equivalent,
500-50=450 ✓) in inventory, plus the purchased 糖葫芦(Bingtang hulu)
item physically present. debug.log for the whole sequence: zero
error/denied/undefined-function/bad-argument lines (only the
pre-existing benign compiler warnings already documented above).
Gap 2 — real combat to death/respawn: COMPLETED, real death_stage() reincarnation chain exercised end-to-end, no bug
Read feature/damage.lpc's die()/unconcious()/reincarnate() and
cmds/std/kill.lpc before attempting anything (per this session's
established "the real kill command has no safety gate for NPC
targets" precedent — confirmed true here too: kill.lpc's main()
has no no_die/attitude check at all before me->kill_ob(obj);
obj->kill_ob(me);). Registered a fresh throwaway character
(qindtest/秦斗, password TxTest2026#, unequipped, no skills,
default rolled stats), then used the concurrent fluffos admin
session's eval filter(users(), (: $1->query("id")=="qindtest"
:))[0]->move(load_object("/d/city2/aobai6")) to teleport it directly
into 鳌拜's (Aobai, a "满洲第一勇士" boss NPC, attitude: aggressive,
combat_exp: 4280000 — deliberately picked as a massive stat mismatch
against a level-0 character to guarantee a real, fast death rather
than an uncertain multi-round fight) bedroom, then sent kill ao bai
from the qindtest session.
Real lethal combat, real death, and real reincarnation all ran
correctly, unmodified, start to finish:
1. kill ao bai → immediately hit "这里不准战斗" (no_fight in the
room briefly) then real combat resolved — one exchange
(鳌拜's「天目昭辉」strike), "你受伤过重,已经有如风中残烛..." →
"你口中喷出几口鲜血,倒在地上,死了!" — a real death via
feature/damage.lpc's die().
2. die()'s userp branch correctly fired: ghost=1,
this_object()->move(DEATH_ROOM),
DEATH_ROOM->start_death(this_object()) — landed at 鬼门关 (Ghost
Gate), the death-room, next to 白无常 (d/death/npc/wgargoyle.lpc
— one of the exact 3 files checked clean for the §7.112
death_stage_active reentrancy guard in this pass's checklist
section below, now exercised LIVE, not just statically).
3. The full 5-stage death_stage() narration chain played out
correctly over ~25s real time (5s per call_out), each stage's
dialogue line printing once per tick, no duplication, no stall.
4. Final stage correctly called ob->reincarnate() (clearing ghost,
restoring eff_jing/eff_qi to max) and ob->move(REVIVE_ROOM) —
landed at 武庙, one of the lib's own 4 known-good start rooms.
5. score immediately after: "你共死亡:1 次" (death counter correctly
incremented from 0→1), <精>/<气> bars showing partial (not
full/not zero — correctly reduced post-revival, not a stale/broken
value), character fully interactive afterward (look rendered the
real 武庙 room correctly).
debug.log across the entire kill → death → 5-stage narration →
reincarnate → score sequence: zero new
error/denied/undefined-function/bad-argument/recursion/segfault lines
— only the same pre-existing benign compiler warnings already logged
in this file. No bug found or fixed — the death/reincarnation
pipeline works correctly end-to-end on real, unmodified game logic.
Cleanup: both sessions quit cleanly (server-side ASCII farewell
banner, clean disconnect). fluffos's incidental inventory/location
drift from this pass's eval/goto use reverted via git checkout
--; the throwaway qindtest character's save files
(data/{login,user}/q/qindtest.o) deleted (never meant to be kept);
the eval command's scratch tmp/ directory (recreated for this
pass, same pre-existing gap the round-two pass already flagged as
out-of-scope) removed again afterward. git status for this lib
confirmed clean (no unintended save-file drift) before finishing.
Standard checklist sanity pass (confirm-only, no fixes needed)
- §7.90 (
config.fluffoseval-cost): confirmed5000000(the already-fixed value from the WASM-enablement pass above). - §7.100 (
replace_program(ROOM);):grep -rnacross all.lpcinwork/found 79 hits, all 79 confirmed commented out (// replace_program(ROOM);style) — zero live occurrences, matching the batch-five fix already recorded above. - §7.111 (
file_name(error["object"])null-guard): confirmed present in the realadm/obj/master.lpc(line 228):objectp(error["object"]) ? file_name(error["object"]) : "<none>". - §7.79 (bare 2-arg
addn()): zero hits anywhere inwork/— not applicable to this lib. - §7.108 (
reconnect()callsenable_commands()): confirmed in the REAL player class (USER_OB=/clone/user/user, perinclude/globals.h) —clone/user/user.lpc'sreconnect()callsenable_commands(); set_heart_beat(1); ...unconditionally, first line. (Three otherreconnect()-named functions exist elsewhere —clone/user/user_bak.lpc,clone/npc/user.lpc,u/lonely/obj/user/user.lpc— none of them is the liveUSER_OB.) - §7.112 (
death_stage()reentrancy): this lib's only 3 files withcall_out("death_stage"(d/shaolin/npc/yu-zu2.lpc,d/death/npc/bgargoyle.lpc,d/death/npc/wgargoyle.lpc) all already carry thedeath_stage_activetemp-flag guard, and EVERY exit branch of each file'sdeath_stage()clears it (the!ob||!present(ob)early-return branch, the!is_ghost()hostile-revert branch, and the finalreincarnate()branch all calldelete_temp("death_stage_active"); only the still-in-progresscall_out("death_stage", 5, ob, stage)recursion branch correctly does NOT clear it).wgargoyle.lpcwas additionally exercised LIVE in Gap 2 above, not just read statically — confirmed no duplicate/stuck narration in practice. - §7.30 (uninitialized-mapping accessors):
feature/skill.lpc's 4 accessors (query_skills-family) all already have themapp(x) ? x : ([])guard, matching the corpus-wide sweep already recorded above.
All 7 checklist items: already fixed / already clean, zero new fixes needed this pass.
§7.30 uninitialized-mapping accessor sweep (2026-08-20)
Corpus-wide mechanical sweep of the feature/skill.lpc shared-lineage
bug (confirmed independently on xiakexing2017/jqxz2015/haiyang2
via round-four testing): 4 accessor(s) in this file returned a raw
never-initialized mapping instance variable (defaults to int 0,
not ([]), until first assigned), crashing any unguarded
keys()/sizeof()/indexing caller for a fresh/untrained character.
Fixed at the accessor level (mapp(x) ? x : ([])) per the documented
remedy. Verified via lpcc --batch static compile check only (not a
live boot) as part of a large mechanical sweep; not individually
functionally re-tested live on this lib.
深度功能测试(§10.7,2026-10-04)— negative range ends
scripts/lpc_fix_negative_ranges.py: 5 line(s) in 2 file(s) count a range from the end with < (x[a..-1] -> x[a..<1], x[-2..] -> x[<2..]; KB 06 §7.209). In this driver a negative constant end gave "" / ({ }) and a negative start the whole value, so each of these returned the wrong slice; the compile warning A negative constant as the second element of arr[x..y] is gone from the files that compile. Range lvalues (s[0..-1] = text, the prepend idiom) are left alone. A paired compile of the changed files at HEAD and in the working tree showed no new error.
深度功能测试(§10.7,2026-10-05)— here-document terminators
scripts/lpc_fix_heredoc_terminator.py --all --apply: 2 here-document block(s) repaired (2 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/quanzhen/manglin1.lpc, d/quanzhen/manglin2.lpc. The terminator must start its line (the lexer's own test, KB 04 §6.10); a glued one lost its newline in the GBK -> UTF-8 conversion together with a half character, which stays out.
深度功能测试(§10.7,2026-10-04)— paths named in another case
The archive comes from a case-insensitive host: files are stored as BAGUA0.lpc, longjing.C, d/SHAOLIN/, the code names them in lower
case (__DIR__ "bagua0", "tea/longjing", "/d/shaolin/..."), so the rooms, NPCs and items behind them could not be loaded (a .C file is
not an .lpc file; KB 03 §4.5). scripts/lpc_case_paths.py --convert --apply tianxiawuxue: 18 file(s) renamed to lower case (.C -> .lpc,
.H -> .h) and 52 path reference(s) in 2 file(s) rewritten to the new spelling; 0 skipped, 0 ambiguous. Load check of the 20 objects that were renamed, edited or name a renamed path (HEAD against the working tree, an object is the same under any spelling of its path): 2 PASS -> 20 PASS, 0 that loaded before fail now, 18 more load.
18 files moved (18 .lpc); mostly under u/lonely/zhuanshi (18). A rescan with scripts/lpc_warnings.py tianxiawuxue is still due: the renamed files are compiled for the first time.
深度功能测试(§10.7,2026-10-05)— room base survives a raising NPC
scripts/lpc_resilient_room.py --apply: make_inventory() of inherit/room/room.lpc loads each inventory object as if (catch(ob = new(file)) || !objectp(ob)) return 0;. new() of a file that is not there returns 0 (the room just lacks that NPC), but new() of a file whose create() raises (a skill file for set_skill() this archive never had, a carry_object() item that is not there, a header that never shipped) raised inside the room and the room did not load at all. The wrong-case renames of this lib (the section above) make the NPCs behind them reachable for the first time, so a room that holds one with such a content gap would have gone from "NPC missing" to "room missing"; now it loads without that NPC, as it did before. The room base compiles and loads with the change (HEAD against the working tree). KB 03 §4.5.
深度功能测试(§10.7,2026-10-05)— 任务表里的 .c 路径与任务守护进程的防护
scripts/lpc_dynamic_rows.py:d/obj/quest/dynamic_location、d/obj/quest/dynamic_quest、quest/dynamic_location 里 151 行写的是原档案的 .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、adm/daemons/taskd.lpc 读到的每一行都加载不出来:随机任务和任务物品从未生成,在 create() 里直接对结果调用 tar->set() 的版本还会崩溃,连带加载它的 cron 守护进程和 give 的任务钩子。这些行已改为 .lpc;另有 36 行指向的文件两种后缀都不存在(档案缺内容),保持原样。
scripts/lpc_dynamic_quest_guard.py:2 处 spread_quest() 调用(init_dynamic_quest() 的循环里)包进 catch(),缺失的任务物品或编译不过的房间只跳过那一个任务,守护进程照常加载、其余任务照常生成;cmds/std/look.lpc 夜间检查的 !present("fire", this_player()) 前加 objectp(this_player()) &&(房间 reset() 销毁物品时 /feature/move.lpc 的 remove() 会调用 look_room(),此时没有 this_player(),present(…, 0) 报 Bad argument 2 to present())。
验证:adm/daemons/questd.lpc、adm/daemons/taskd.lpc和 cron 守护进程在新进程里加载(HEAD 一次,工作树三次,选房是随机的):HEAD 通过 2 个,工作树三次分别通过 2、2、2 个(共 3 个),无回退;adm/daemons/taskd.lpc 在 HEAD 与工作树都加载失败,另有原因,与本次无关。
验证:改动过的 adm/daemons/questd.lpc、adm/daemons/taskd.lpc、cmds/look.lpc、cmds/std/look.lpc、u/knightly/cmds/std/look.lpc 在新进程里加载,HEAD 通过 4 个、工作树通过 4 个(共 5 个),无回退。
深度功能测试(§10.7,2026-10-05)— 房间列出的物件缺档时房间照常加载
房间基类 inherit/room/room.lpc:reset() 的 case 1: 拿到 0 就跳过这一项(if (!objectp(ob[list[i]])) break;);reset() 的 default: 拿到 0 就跳过这一项(if (!objectp(ob[list[i]][j])) continue;)。档案里没有的 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-07)— 空的 if (current_water == 0) {}
5 个房间的 valid_leave() 里有一行什么也不做的 if (current_water == 0) {}(编译警告 Expression has no side effects),删去,行为不变:d/gaochang/room11.lpc、d/gaochang/room12.lpc、d/gaochang/room13.lpc、d/gaochang/room14.lpc、d/xingxiu/shanjiao.lpc。
深度功能测试(§10.7,2026-10-07)— 编译警告整理
scripts/lpc_warnings.py tianxiawuxue --fix 加 scripts/lpc_fix_no_effect.py --apply,共改动 826 个 .lpc 和 8 个 .h(多为删去未用的局部变量)。HEAD 与工作树分别加载(新进程):762 -> 762 通过,无回退;改过的头文件的 49 个包含者 44 -> 44 通过。
手改一处:d/liwu/obj/ling3.lpc 的 if ("mark_place", base_name(environment(me)) == "llzhuang"),逗号表达式左边的字符串什么也不做(编译警告 Expression has no side effects),去掉,行为不变。
记录、未改:任务基类 inherit/misc/quest.lpc 在第 74 行报 syntax error, unexpected '}',HEAD 起就编译不过;quest/quest_sc/guo.lpc 调用本库没有的 message_sort(),HEAD 起也编译不过。
启动时警告 26 -> 0;新进程登录(新人物确认)正常。
深度功能测试(§10.7,2026-10-08)— 追杀杀手 killer.lpc
quest/chousha/killer.lpc 的门派表里有本库没有的武功(feihua-wuping、guiyuan-dafa、tiexian-quan),set_skill() 遇到会 error,选到那一派时杀手加载失败;加一个 set_skill() 跳过本库没有的武功(同 wxddym,map_skill 随之跳过)。这个文件只由 haojie.h 生成,haojie.h 只有没放置的 yelao1 在用,属休眠内容;实际放在 d/city/shijian 的 yelao 生成 killer1/killer2,单独加载 12 次全过,未改。
- 2026-10-10:编译警告第二轮(按驱动报告逐条修):按位 & 改逻辑运算 11 处,返回类型/原型 25 处,NPC+F_UNIQUE 的 init() 0 个,带初始化的未用局部变量 3 个,只在 #if 分支用的声明移进分支 1 个文件;改动 39 个文件,HEAD 与工作树各载入一次无回退(39 objects; HEAD PASS 38, tree PASS 38; regress 0; newly loading 0),这些文件的警告 40 -> 1。
深度功能测试(§10.7,2026-10-11):“无副作用表达式”警告复查
kungfu/skill/liangyi-jian.bak.lpc:int i; level;去掉无用的level;。载入无回退。
编译警告收尾(2026-10-12)
scripts/toolkit_fix.sh 一轮(冗余继承 31 处)加手工收尾,能编译的文件警告清零。改动的 42 个对象 HEAD 与工作树各载入一次:HEAD PASS 39,tree PASS 39,regress 0。
d/obj/xiang.lpc(存盘的箱子):varargs int remove() { save(); }盖掉了feature/move.lpc的remove(),箱子被销毁时不从携带者身上减负重、不清 handing(nitan_ceshi 的 unique.lpc 同类,KB 06 §7.239 变体)。改成varargs void remove(string euid) { save(); ::remove(euid); },与 nitan170911 同修。questobj/guojob/guo.lpc(郭靖)同时 includezzzjob.lpc和teamjob.lpc,两者各声明一份names表,内容差两个地名(北疆小镇/伊犁、悬空寺/玄妙观);每份表只被紧跟其后的代码读到,各用各的。teamjob.lpc这份改名team_names,行为不变。u/lonely/obj/roommaker.lpc、roommk.lpc:special_props声明两次,后一次(多"file_name")本来就生效,删去前一次。d/city/library.lpc、d/city2/library.lpc、d/emei/user-room/host/home.lpc有意改STORY_DIR,前加#undef;kungfu/skill/huashan-jian.lpc招式表后多余的;;quest/quest_jun/song/obj/bingfu.lpc、lingjian.lpc用lpc_name_winner.py写明clean_up()。- 2026-10-14:1 个存档文件(玩家/登录存档 1 个;
data/user/m/mydjh.o)还是原档案的 GBK 编码,没有转成 UTF-8,restore_object()报Invalid utf8 string后对象以空数据启动(表情守护进程没有表情、留言板没有帖子、玩家无法载入)。scripts/lpc_save_encoding.py逐个按 GB18030 解码,结果按存档格式解析通过才写回(KB 03 §4)。
- 2026-10-14:新驱动(FluffOS 970d9f09)报
Float value truncated to int(#1426)。6 个文件 9 处:赋值、初始化、return 改写成to_int(...)(值不变,只是写明截断);x op= 浮点先把浮点转成整数再运算(系数小于 1 时 x 直接变 0),改为x = to_int(x op ...):/kungfu/skill/taiji-quan/zhenup.lpc(damage *=)。改动的对象新进程各载入一次,无回退(scripts/lpc_fix_float_trunc.py,KB 04 §6.10)。
- 2026-10-14:1 个文件因
Type of returned value doesn't match function return type ( int vs void )整份不编译:声明为void(或没写类型)的函数却返回值,旧驱动照样把值交给调用者。调用者要用返回值的(add_action 处理函数、命令、辅助函数)改为它实际返回的类型:check()。新进程比对 HEAD 与工作树:1 个对象,新增载入 1,回退 0(scripts/lpc_fix_void_return.py,KB 04 §6.3)。
- 2026-10-14:
kungfu/skill/liu-unarmed.lpc的query_action()里取等级与for循环两行被注释掉,剩下if (level > action[i - 1]["lvl"]),i 为 0,每次出招都报Array index must be positive or zero;恢复这两行(与其他武功相同的写法)。逐个武功调用 query_action/valid_learn/practice_skill 的运行期探针发现。
- 2026-10-15:
kungfu/skill/guangming-blade.lpc(光明刀法)是从五虎断门刀抄来的,query_action()里仍按wuhu-duanmendao的等级挑招式:没练五虎断门刀的人出招时一招都匹配不上,a_action为 0,接着赋值报错。改为按guangming-blade自己的等级。(武功运行期探针发现。)
负数伤害当作消耗(2026-10-15,KB 06 §7.241)
receive_damage("neili", -52)、receive_damage("qi", -12) 之类把 add() 的负数写进了 receive_damage():本库 feature/damage.lpc 对负数伤害报错(或归零),练功/运功时报 F_DAMAGE: 伤害值为负值 或消耗失效。已改为正数伤害,内力/精力类改为 add(type, -N)(scripts/lpc_fix_damage_calls.py):/kungfu/skill/shaolin-tantui。
内力/精力当作伤害种类(2026-10-15,KB 06 §7.241 第二类)
本库 feature/damage.lpc 的 receive_damage() 不接受 jingli/neili/force 等种类,me->receive_damage("jingli", 30) 之类在练功、绝招、吸取时报 F_DAMAGE: 伤害种类错误。18 处改为 add(type, -N)(scripts/lpc_fix_damage_calls.py 第二步)。
无门派玩家的 family 映射(2026-10-15,KB 05 §7.30 第三种)
mapping fam = ob->query("family"); 之后直接 fam["family_name"]:没有门派(新人或叛师后)的玩家在学习、练功、拜师、进入门派房间时报 Value being indexed is zero,而不是作者写好的提示。3 处在声明行加上 if (!mapp(fam)) fam = ([ ]);(scripts/lpc_fix_family_guard.py)。
东方故事/西游记体系的技能文件(2026-10-15,KB 06 §7.241 第三类)
这些 kungfu/skill 文件来自 gin/kee/sen/force 体系,本库人物只有 jing/qi/neili:receive_damage("kee", 30) 报 伤害种类错误,query("force") 永远为 0,技能学不了也练不了。按 kee→qi、gin/sen→jing、force→neili、max_force→max_neili、force_factor→jiali 改了属性名(scripts/lpc_port_es_props.py),共 12 个文件。
其他体系的属性名(2026-10-15,KB 06 §7.241 第三类,--any-file)
另有 12 个文件(绝招、状态、物品、NPC 等,不限于 kungfu/skill)来自 gin/kee/sen/force 体系,同样按 kee→qi、gin/sen→jing、force→neili 改名(scripts/lpc_port_es_props.py --any-file)。
family 映射(补)(2026-10-15)
mapping fam = (mapping)me->query("family");(带类型转换的写法)同样直接取下标,2 处补上 if (!mapp(fam)) fam = ([ ]);。
治疗/疗伤的属性名(2026-10-15,KB 06 §7.241)
receive_heal()/receive_curing() 也只接受本库的种类。5 个文件(多为只调用 receive_heal/receive_curing 的药物、NPC)来自其他体系,按本库的属性名改名(scripts/lpc_port_es_props.py --any-file)。
family 映射(再补)(2026-10-15,KB 05 §7.30)
mapping fam; fam = (mapping)ob->query("family");(先声明后赋值)和泥潭式的 query("family", me) 同样直接取下标:无门派的新人拜师(attempt_apprentice/recognize_apprentice)、NPC 的 greeting、房间的 valid_leave、ask_me 等报 Value being indexed is zero。11 处补上 if (!mapp(fam)) fam = ([ ]);(刚 recruit_apprentice() 之后的除外)。
技能按另一门武功的等级取招(2026-10-15,KB 06 §7.243)
这些技能文件是从别的武功复制改名来的,query_action() 仍用原武功的等级查招式表:只会本技能的人等级为 0,取不到招,每次出招都报错。改为读本技能自己的等级(scripts/lpc_fix_action_level.py):xiaoyao-jian。
招式表最低等级之下没有招(2026-10-15,KB 06 §7.243)
招式表的最低 "lvl" 高于 0(如全部为 100),技能等级未到之前取不到招,每次出招都报错。循环后补 if (!a_action) a_action = action[0];(lpc_fix_action_level.py --fallback):kuaidao-daofa、tiezhang-zhangfa、xiongba-tianxia。
补(同日):dugu-jiujian。招式表前 15 招(lvl 0–98)被 /* ... */ 注释掉了,生效的最低一招是 105,真正的 query_action() 上方也还有一份注释掉的旧定义。第一遍扫描把注释里的招和那份旧定义都算了进去,所以漏掉:105 级以下(包括刚学会的人)每次出招都报 Illegal type of index。补上回退后技能探针 0 错误。
空手使用兵器绝招(2026-10-15,KB 06 §7.246)
perform 指令允许直接点名招式(如 perform stick.ban),这些绝招读了 me->query_temp("weapon") 却从不检查,空手时 weapon->name() 报错(有的已先扣了内力)。在赋值后补 if (!objectp(weapon)) return notify_fail("你必须手持兵器才能使用这一招。\n");(scripts/lpc_fix_perform_weapon.py):dagou-bang/ban、daya-jian/badao、tianyu-qijian/kuangwu、yujianshu/fumo、yujianshu/jinsheng。
把经验、属性、内力当技能读(2026-10-15,KB 06 §7.247)
经验、属性、内力上限不是技能,xkx/ES 的 query_skill() 对它们只返回 0(风云的还会去载入同名技能文件而报错)。改为 query("...")(scripts/lpc_fix_pool_as_skill.py):/quest/wudang/song 生成的任务怪物照抄玩家福缘(set("kar", who->query_skill("kar")),怪物福缘一直为 0)。
当前内力、精这类名字有时指的是内功技能,逐处读过后手改:落英缤纷 luoying-shenjian/lybf:自己的注释说成功率由“精神高低”决定,两处 query_skill("jing") 改为 query("jing")。
妙手回春的银针检查(2026-10-15)
miaoshouhuichun 的 valid_learn() 用了未赋值的 object ob,ob->query_temp("weapon") 每次都报错,谁也学不了;还把兵器对象和字符串 "银针" 比较。照 chidi 的修法改为 ob = me->query_temp("weapon"),再用 id("yin zhen")/id("yinzhen") 判断是否银针。本库没有银针这件兵器,这门功夫仍学不了,但不再报错,而是提示要先拿起银针。
碧海生潮曲空手报错(2026-10-15,KB 06 §7.246)
iceforce/roar(碧海生潮曲)先 ob = me->query_temp("weapon"),再直接拿 base_name(ob) 判断是不是玉箫;空手 exert roar 时 base_name(0) 报错,提示“你必须先找一只玉萧来才可以吹--曲”根本出不来。条件前补 !objectp(ob) ||。
iceforce「chillgaze」从未编译通过(2026-10-15)
iceforce/chillgaze 原档在第一个 return notify_fail(...) 后多了一个 },exert() 就此结束,后面的语句全落在函数外,skill、damage 也没有声明,文件编译失败,这个 exert 从来用不了。照 bixiecanyang、hc、xyzx3 已修好的版本删去多余的 }、补上 int skill, damage;,其余字句不变,只是缩进进函数体。
技能名拼错(2026-10-15,KB 06 §7.249)
query_skill() 里的技能名拼错了,或用的是本库改名前的旧名;本库没有这个技能,调用永远得 0:门槛(< N 就拒绝)永远过不去,相关功夫或绝招学不了、用不了;内功互斥(> N 就拒绝)从不生效;公式里这一项一直是 0。经汉字名(提示文字或中文名词典)或纯拼写差异(_/-、少一个连字符、相邻字母颠倒)核对后,改为本库的技能名(scripts/lpc_fix_skill_typo.py):beimin-shengong→beiming-shengong(honghua-shengong、tiangang-zhengqi、xiantian-gong);baihua-cuoquan→baihuacuo-quan(bagua-zhang);buddhsim→buddhism(qianye-shou);douzhuan-xignyi→douzhuan-xingyi(/d/mr/obj/shu1);jinwu-dao→jinwu-daofa(jinwu-daofa);sanyang-unarmed→sanyin-unarmed(sanyang-unarmed/fuxue);xuantie-jian→xuantie-jianfa(/clone/lonely/xuantiejian);yihua-jimu→yihua-jiemu(yihua-jiemu);zhenfen-xinfa→zhenfeng-xinfa(zfwy-bu)。
技能名拼错:技能文件里拼错自己的名字(2026-10-15,KB 06 §7.249)
技能自己的文件(或它的绝招目录)里,query_skill() 读的是差一个字母的自己的名字,永远得 0:“基本功夫要高过本技能”之类的限制从不生效,按等级取招、计算伤害的那一项一直是 0。改为本技能的名字(scripts/lpc_fix_skill_typo.py 的 self 判据):xuantie-jiafa→xuantie-jianfa(xuantie-jianfa);xuanxie-jianfa→xuantie-jianfa(xuantie-jianfa)。
family 映射内联取下标(2026-10-15,KB 05 §7.30)
ob->query("family")["master_name"]、me->query("family")["family_name"](泥潭式为 query("family", ob)[...])直接对门派映射取下标:没有门派的人(新玩家、叛师者、大多数 NPC)在 NPC 的打招呼和问话、绝招的门派判断、房间的 valid_leave 里报 Value being indexed is zero,而不是得到拒绝。6 处(5 个文件)改为 dbase 路径查询 query("family/master_name"):有门派时值相同,没有时得 0;原有的判断照常生效(scripts/lpc_fix_family_index.py)。给映射赋值的写法未动。
message_combatd 没有定义(2026-10-15,KB 04 §6.2)
26 个绝招调用原 xkx 服务器的 simul_efun message_combatd(),本库只在巫师目录 u/lonely/sec/message.lpc 里有一份,正式的 simul_efun 没有,这些文件编译失败。adm/simul_efun/message.lpc 里补上与 message_vision() 等价的定义:10 个绝招现在能载入。八卦系 6 个绝招另外用了泥潭的 COMBAT_D->do_damage(),本库的 combatd 没有,仍无法载入(内容缺口)。
移进不存在的巫师房间(2026-10-15,KB 06 §7.251)
用完的物品、要“离开”的 NPC、掷在空中的兵器被移进巫师的工作室(/u/llm/、/u/wind/),本库没有这些房间。本库的 move() 用 load_object() 找目的地,找不到就返回 0,不报错,东西留在原处:被雇来打晕或杀人的李凌(d/city2/npc/liling2)办完事后没有离开,留在原地(d/city2/npc/liling2 本身还载入不了:create() 里 carry_object() 的物品文件缺失或编译失败,见 KB 06 §7.73,另行处理);婚礼结束(d/nanyang/npc/meipo 的 last_marry)时月老没有离开喜堂,每办一次婚礼喜堂里就多一个月老;喜宴结束后喜来福(d/nanyang/npc/xi-laifu)没有退回内堂,每办一次婚礼迎宾楼就多一个喜来福。3 个文件改为移进本库的虚空房间 VOID_OB(/clone/misc/void),与原作把它们“停放”在巫师房间的用意相同(haiyang2 的维护者把月老送进 /d/city/empty,也是同样的做法)。
玉女剑法「合壁」用一次就永久改动经验和剑法(2026-10-15,KB 06 §7.253)
收尾的 hebi() 声明时没有参数(void hebi() { object me, target, env; int i, j, o, p, count; ...),call_out 传进去的人和数值全被同名的局部变量(0)挡住,开头的 if (!me && !target) return; 每次都返回:合壁的攻击、闪避加成和 hebi 标记要到重新登录才消失。改正:hebi() 按它自己再次 call_out 时传的八个参数声明,perform 的 call_out 去掉多余的 h, k。测试里加成照常生效,hebi() 结束时还原并清除标记,没成亲的人经验和剑法不变。
NPC 带着本库没有的物品,载入失败(2026-10-15,KB 06 §7.73)
21 个文件、25 处在 create() 里 carry_object("<本库没有的文件>")->wear()(或 wield()、set_amount()):carry_object() 得 0,接着的调用报 Bad argument 1 to EFUN call_other(),NPC 根本载入不了,该有它的房间里就少了这个人。多是从别的系统搬来的 NPC 用了原系统的物品路径(最常见:/d/wudang/obj/bluecloth、/d/city2/obj/killerbian、/obj/cloth/cloth)。每处改为 { object carried_ob = carry_object(...); if (carried_ob) carried_ob->wear(); }(scripts/lpc_guard_carry_object.py):NPC 照常出现,只是不带这件东西;文件补回来(或是虚拟对象)照样会带上。载入检查:改动的文件改前能载入 0 个,改后 20 个(20 个原来载入不了),没有退步;其余 1 个另有原因(多为 set_skill() 了本库没有的武功)。
物品清单把名字的第一个字吃掉(2026-10-18,KB 07 §8.1)
inventory、房间的物品列表(feature/move)和部分 look 把同名物品合并计数,键是 query("unit") + short(),只有一件时按 key[2..] 去掉量词。量词是一个汉字,在原来的 GBK 里占 2 字节,[2..] 正好去掉量词;转成 UTF-8 以后一个汉字只占一个下标,这一刀把名字的第一个字也切掉了(「把长剑」只显示「剑」,带颜色的名字切掉的是转义序列开头)。改为 [1..](scripts/lpc_fix_unit_cut.py):cmds/std/look_test.lpc、cmds/usr/ii.lpc、cmds/usr/inventory.lpc、feature/move.lpc、quest/quest_jun/look.lpc。
水潭里 ging_cost 是 jing_cost 的笔误(2026-10-18)
shuitan 先算 jing_cost,倒水时却扣 receive_damage("jing", ging_cost),ging_cost 从没声明过:Undefined variable 'ging_cost',整个物件载入不了。改成 jing_cost:d/shaolin/npc/obj/shuitan.lpc。改后用 lpcc 逐个载入这些对象:1 个通过。
全真心法 valid_learn() 里没声明的 lvl(2026-10-18)
kungfu/skill/quanzhen-xinfa.lpc 的 valid_learn() 判断 me->query("gender") == "无性" && lvl > 49,可是函数里只有 nk、nf、nh、ns 四个变量,没有 lvl:Undefined variable 'lvl',这门心法的文件载入不了,学它、用它都失败。nh 正是全真心法的等级(nh = query_skill("quanzhen-xinfa", 1)),改成 nh > 49。改后用 lpcc 逐个载入这些对象:1 个通过。
武林盟主类 NPC 的存档里 weapon/armor 是个 mapping(2026-10-18)
盟主、fa-e、shang-shan、tang3/tang2/xingtang 这几个 NPC 在 create() 里 restore() 之后直接 carry_object(query("weapon"))。换盟主时 do_recopy() 把玩家整个 dbase 抄进来,玩家的 weapon 若是自制兵器的 mapping,存进 data/npc/*.o 以后下次载入就是 new(mapping):Bad argument 1 to EFUN new(),NPC 载入失败。本库的存档里确实有这种 mapping。两行都加 stringp() 判断,mapping 时不拿武器(NPC 空手):clone/npc/fa-e.lpc、clone/npc/meng-zhu.lpc、clone/npc/shang-shan.lpc。改后用 lpcc 逐个载入这些对象:3 个通过。
补回丢掉的基类宏(2026-10-18,KB 04 §6.13)
inherit F_XXX; 里的宏本库任何头文件都没有定义,报 syntax error, unexpected L_IDENTIFIER, expecting L_STRING or '(',整个对象载入不了;宏指向的基类文件本库其实有,别的库都把这个宏定义成同一个路径。在全局头文件 include/globals.h 里补上:SSERVER → /inherit/sserver(6 个文件)、F_COAGENT → /feature/coagent(2 个文件)。(scripts/lpc_restore_macros.py)改后用 lpcc 逐个载入这些对象:8 个里 6 个通过,其余 2 个还有别的错误(kungfu/class/meizhuang/heibai.lpc:syntax error, unexpected L_IDENTIFIER, expecting L_STRING or '(';kungfu/class/meizhuang/huang.lpc:/kungfu/class/meizhuang/huang.lpc:170:1: warning: Unused local variable 'purename')。
kungfu/skill/qingyi-jian 第一式的 skill_name 丢了收尾引号(2026-10-18,KB 03 §4.6)
"skill_name" : "大悲式, 的收尾引号没了(转码时跟半个汉字一起丢了),字符串连到下一行,damage_type 成了代码:Illegal character 0xe5,整个武功载入不了。补回 ",(同系的 bixiecanyang、syxjl 等库里有完好的同名文件)。载入:通过。
set_skill() 遇到本库没有文件的武功不再抛错(2026-10-18,KB 06 §7.256)
feature/skill.lpc 里的 set_skill()、map_skill()、prepare_skill() 碰到没有武功文件的名字就 error("F_SKILL: No such skill (…)"),调用它们的 NPC create() 整个中断:NPC 载入不了,刷出它的房间也少一个人。本库有 18 个对象设了本库没有文件的武功(22 个名字,最多的是 yiyang、xuantian-wujigong、xuantian-wuji)。三处都改成 return:这一门武功不给、不映射,对象照常载入,只是少了它(缺的武功本身仍是内容缺口)。抽样载入这些对象:18 个里 14 个通过,其余 4 个停在别的错误上(kungfu/class/meizhuang/heibai:*No program in object '/kungfu/class/meizhuang/heibai'!;quest/quest_sc/guo:*No program in object '/quest/quest_sc/guo'!……)。(scripts/lpc_guard_set_skill.py)
补回本库没有的基类文件(2026-10-18,KB 04 §6.15)
下面这些基类本库没有,继承它们的对象(房间、NPC、物品)整批载入不了(inherit XXX; 的宏没定义,或者 inherit "/std/…"; 的文件不在)。同系的库里有同名文件,两库有大量逐字节相同的文件(亲缘关系),所以从那边原样拷来,缺的宏补进全局头文件 include/globals.h:/inherit/weapon/xsword(宏 XSWORD)←wxddym,2 个对象继承它,抽样 2/2 载入;/feature/noclone(宏 F_NOCLONE)←zxty08nxgbb,1 个对象继承它,抽样 1/1 载入;/inherit/weapon/pin(宏 PIN)←yxcs,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 映射不到,门派弟子用普通轻功/拳脚)。按核对过的对照表改正,共 27 处、23 个文件:jinyin-baiguzhao→jiuyin-baiguzhao(4 处)、kunlun-shnfa→kunlun-shenfa(4 处)、lingbo-weibu→lingboweibu(3 处)、yan-fly→yanfly(3 处)、xinxiu-duzhang→xingxiu-duzhang(2 处)、tiaji-jian→taiji-jian(2 处)、kongmingquan→kongming-quan(2 处)、taiji-shenfong→taiji-shengong(2 处)等共 13 个名字。(scripts/lpc_fix_skill_names.py)
set_name 的 id 参数传成字符串(2026-10-19,KB 06 §7.260)
set_name("海口大碗", "bowl"); 把物品的 id 写成了字符串,本库的 set_name(string name, string *id) 要的是数组,驱动在编译时报 Bad type for argument 2 of set_name ( string * vs string ),整个物件载入不了;旧驱动不检查参数类型,字符串里照样找得到这个词,物品能用 id 称呼。改成 ({ "bowl" }),共 2 个文件:/d/baituo/npc/obj/bowl.lpc、/d/baituo/obj/bowl.lpc。(scripts/lpc_fix_set_name_id.py)
全局头文件丢了 3 个宏(2026-10-19,KB 04 §6.16)
/include/globals.h 里没有定义 UNARMED_ATTACK、WEAPON_ATTACK、QUEST_CREATE,用到它们的物件(名单里 8 个)编译时报 Undefined variable/Undefined function,整个物件载入不了(编译器在第一个未定义的名字上停下,后面的错误和警告都看不到)。同系的库在各自的头文件里都有这几行:照其中和本库共有文件最多的那个库,原样补到 /include/globals.h 最后一个 #define 之后,宏体里出现的路径在本库里都存在。补完后名单里有 7 个载入,其余还差别的东西。(scripts/lpc_restore_defines.py)
区域物件的零碎修正(2026-10-19,KB 06 §7.267–§7.271)
/d/board/mingjiao_b.lpc的location从不存在的/d/mj/guangming-ding改成/d/mingjiao/guangming-ding(载入明教留言板失败会让光明顶房间载入不了)- 2 个 NPC 文件、2 处
create()里的this_player()->carry_object(改成carry_object((没人在场时this_player()是 0,NPC 载入不了;有玩家在场时衣服武器落到玩家手里)
逐个物件与 HEAD 对比载入,没有退步。
enable_player() 重入保护(2026-10-19,KB 05 §7.19)
feature/command.lpc 的 enable_player() 没有重入保护:门派掌门大弟子 zhangmen.lpc 的 init() 以 me->setup(); 收尾,setup() 调 enable_player(),enable_commands() 又重跑 init(),第一个进房间的活物就触发 Too deep recursion(d/shushan/tianshi 等)。按 §7.19 加了标志变量(scripts/lpc_fix_enable_player_guard.py)。改后同样的测试(载入掌门房间,再克隆一个活物走进去)不再出错,没有退步。
开封擂台头文件的重复全局变量(2026-10-19,KB 04 §6.10)
d/kaifeng/ground.h 里的 modes、mode_hints、families 三张表被 ground0.lpc 和继承它的 ground1/2/3.lpc、ground.lpc 各包含一次,每次 inherit 都报 Redeclaration of global variable。表只放在 ground0.lpc 里:头文件用 #ifndef GROUND_TABLES_INHERITED 包住表,继承的几个程序在 #include "ground.h" 前 #define GROUND_TABLES_INHERITED(与 xiyouji 系其余库同一改法)。改后警告消失,与 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 文件。
玩家打造兵器模板被 NPC 带上(2026-10-19,KB 06 §7.275)
/d/npc/m_weapon/weapon/m_club.lpc、/d/npc/m_weapon/weapon/m_sword.lpc(共 2 个)的 create() 用 this_player() 读打造数据(me->query("weapon/lv") 等)。NPC 的 weapon 属性是兵器文件名(字符串),NPC 在别的 NPC 的命令环境里 carry_object() 这个模板时,set_desc() 里 switch (w_lv) 拿到的是那个字符串,驱动报 Bad argument 1 to switch,房间和 NPC 都载入不了(旧驱动里 switch 落到 default)。把 if (me) { 改成 if (me && mapp(me->query("weapon"))) {,玩家打造的流程不变。
两个斜杠开头的物件路径(2026-10-19,KB 06 §7.276)
1 个文件、1 处物件路径写成 //…(如 carry_object("//clone/cloth/hic_cloth")):/d/city3/shanlu3.lpc。当年的驱动不介意(路径先被规范化);新驱动把原样的字符串交给 master 的 valid_read(),securityd 按 //clone 查目录,NPC 的 euid 没有权限,报 Read access denied.,NPC 载入不了。改成一个斜杠。
玩家打造兵器模板没有打造者时(2026-10-19,KB 06 §7.275)
/d/npc/m_weapon/weapon/m_bian.lpc、/d/npc/m_weapon/weapon/m_staff.lpc、/d/npc/m_weapon/weapon/m_whip.lpc、/d/quanzhen/npc/obj/m_sword.lpc、/d/quanzhen/obj/m_sword.lpc(共 5 个)的 create() 开头 me = this_player(); 之后无条件读 me->query("weapon/name") 等打造数据。房间刷新时没有人在场(me 为 0),或者 NPC 在别的 NPC 的命令环境里 carry_object() 这个模板(NPC 的 weapon 属性是文件名字符串),旧驱动里读出来是 0 或字符串,switch 照样落到 default;新驱动报 Bad argument 1 to EFUN call_other() / Bad argument 1 to switch,NPC 和它所在的房间载入不了(--walk 普查里一个玩家走进房间就触发)。在 //读入数据 之后加 if (!me || !mapp(me->query("weapon"))) { setup(); return; }:没有打造者就留一个没有名字的空模板,玩家打造的流程不变。
补回丢失的标点(2026-10-19,KB 03 §4.6)
转换时丢掉的分号、逗号、引号或文件末尾的 },共 6 个文件,修前 HEAD 载入失败。别的库里同路径的完好副本只比这里少几个标点,按它补回(括号里是那个库):/d/city2/npc/zhengmen.lpc(jqxz2008)、/d/quanzhen/hudi6.lpc(bixiecanyang)、/kungfu/skill/guxing-sword.lpc(xyzx3)、/kungfu/skill/huang.lpc(bixiecanyang)。一行文字在逗号前丢了结尾的引号(下一行是同一个表的下一项),补上:/kungfu/skill/emperor-unarmed.lpc、/kungfu/skill/kunlun-zhang.lpc。修后与 HEAD 逐个对比载入:这 6 个物件全部载入,没有退步(scripts/lpc_restore_from_twin.py、lpc_fix_eaten_quote.py --comma、lpc_fix_eof_braces.py)。
旧驱动的类型宽松:缺省参数、无类型形参、数组初始化、class 变量(2026-10-19,KB 04 §6.19、§6.20)
原来的 MudOS 把调用少传的参数补 0、把没写类型的形参当 mixed、不检查变量的声明类型与初始值,也允许变量叫 class;这个驱动在编译时全部拒绝,整个物件载入失败。修了 1 个文件:/u/lonely/banghui/npc/shi1.lpc(scripts/lpc_round_files.py 的修复轮:调用处补写 0、无类型形参补 mixed、string X = ({...}) 补星号、void 函数的返回值,以及 class 变量改名 pick_class)。逐个文件在 HEAD 和改后载入对比:这些文件里 0 个原来载入失败、现在载入,没有退步。
== !"字符串" 多出来的 !(2026-10-19,KB 06 §7.280)
!"taoist" 是整数 0,x == !"taoist" 就是“x 等于 0”,作者为其余所有人写的那一支永远走不到。具体是:龙女对古墓弟子的机关暗门提示永远给不出来(5 处);孙婆婆的“你去吧”只对 class 没设置的人生效;性别检查(“你不是女的,无法领会其中至阴之理”)永远不拦人,男的照样能学玉女心法。全部改成 != "字符串"(scripts/lpc_fix_not_literal_cmp.py):/kungfu/class/gumu/long.lpc(5 处)、/kungfu/class/gumu/sunpopo.lpc(1 处)、/kungfu/skill/yunu-xinfa.lpc(1 处)。同样的行在 xkx 一系的 35 个库里都有。
x != "a" || x != "b" 和 x == "a" && x == "b":同一个值的比较链永远成立/永远不成立(2026-10-20,KB 06 §7.282)
if (arg != "wan" || arg != "丸") return notify_fail(...) 对任何 arg 都为真,dir == "south" && dir == "north" 永远为假:条件下面的守卫要么永远拦、要么永远不拦。作者要的是“既不是 A 也不是 B”(&&)或“是 A 或 B”(||)。!= 链的 || 改成 &&(仅当条件下面是 return 的拒绝/守卫),== 链的 && 改成 ||(scripts/lpc_fix_cmp_chain.py)。具体是:客栈小二从不拦住付了房钱又往南/往北走的客人。改动:/d/changan/ca2.lpc(1 处)、/d/haojie/npc/tianshaxing.lpc(1 处)。
浩劫系统 verdict_time():领头玩家已经离线时 lead->name() 报错,戒严不解除(2026-10-20)
三十分钟后收场时 lead(接战书的玩家)若已退出游戏就是 0,lead->name() 在宣布战果的 message() 里报错,后面的 LOGIN_D->set_madlock(0) 不再执行,戒严一直保持,quit 指令因此对所有人关闭。改为 (lead ? lead->name() : "各派豪杰")。改动:/feature/disaster.lpc(2 处)。
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,共 3 处)。改动:/d/hangzhou/npc/meipo.lpc(1 处)、/d/quanzhou/zhongxin.lpc(1 处)、/kungfu/skill/meinv-quan.lpc(1 处)。
登录密码超过 255 字节:crypt() 抛错(2026-10-20,KB 06 §7.294)
驱动的 crypt() 对超过 255 字节的密钥直接报错(Error in crypt(), check your salt),老驱动则按任意长度散列。在登录提示符下输入 256 字节以上的密码,密码检查那一行就抛错,连线停在一个裸的 > 提示符上,登录走不完(password 指令的旧密码检查同样);用 300 个 x 当参数的扫描发现的。/adm/obj/simul_efun.lpc 里补了一个同名的 simul_efun crypt(key, salt):只有超长的密钥才被截短(先截到 255 个字符,再逐字符截到 sizeof(to_buffer(key)) <= 255,限制按字节算,一个汉字占三个字节),再交给 efun::crypt();普通密码原样散列,已存的密码散列不受影响(scripts/lpc_add_sefun.py crypt)。
翻页器 start_more(read_file(...)):文件缺失时 explode(0)(2026-10-20,KB 06 §7.300)
东方故事系的翻页器 void start_more(string msg) { ... explode(msg, "\n") ... } 被这样调用:start_more(read_file(HELP_DIR + "help/topics"))、start_more(read_file(NEWS))。压缩包没带的文件使 read_file() 回 0,explode(0, ...) 在本驱动里报 Bad argument 1 to explode()(不带参数的 help 指令就是这样出错的),老驱动把 0 当空文本。在 start_more 开头加了 if (!stringp(msg)) return;(scripts/lpc_fix_start_more.py)。改动:/feature/more.lpc。
wabaod 的藏宝线索按双字节算(2026-10-20,KB 06 §7.307)
天书的线索由 adm/daemons/wabaod.lpc 在房间描述里挖空若干个字:desc = long[begin..begin + 60](按 GB 的 61 字节)、desc[b..b + 1] = "■"(两个字节换两个字节)。驱动的字符串是 UTF-8,区间按字符数:窗口成了 61 个字符,每次替换把两个字符换成一个,字符串越换越短,后面的偏移越界,启动时 push_lvalue_range: invalid ind2(随机出现,init_xunbao 的每次 call_out 也会)。改成按字符算:30 个字符的窗口,每处挖一个字(scripts/lpc_fix_wabaod.py)。
NPC 的 chat() 在 chat_msg 为空数组时下标越界(2026-10-21,KB 06 §7.334)
NPC 基类的 chat() 是 if (arrayp(msg = query(...))) { if (random(100) < chance) { rnd = random(sizeof(msg)); if (stringp(msg[rnd])) ...,不检查列表是否为空。本库现有的 NPC 文件里没有字面写成空 chat_msg 的(扫描只认 set("chat_msg", ({ })));守卫挡的是运行时才为空的列表和以后新增的 NPC。在 random(100) < chance 前面加 sizeof(msg) &&(scripts/lpc_fix_chat_empty.py;if (random(100) > chance) return 0; 的写法是 !sizeof(msg) ||)。改动:/inherit/char/npc.lpc、/u/lonely/banghui/npc.lpc(共 2 个文件)。
存档里的 .c 文件名改成 .lpc(2026-10-21,KB 03 §4.2 第 9 项)
存档里写着 "/d/city/npc/wei.c" 这样的文件名;extract 时源文件已经全部改成 .lpc,而驱动对带扩展名的路径只认字面,new() / load_object() / move() 都找不到它,调用方多半把失败当成「没有这个东西」悄悄跳过。本库 10 个存档共 10 处按 scripts/lpc_fix_save_dotc.py 改成 .lpc(只改 .lpc 存在而 .c 不存在的字符串;玩家存档、备份、留言板、巫师目录和文件索引缓存不动)。改动:/p/residence/dream1117419419.o(1 处)、/p/residence/dream1117420108.o(1 处)、/p/residence/dream1117420148.o(1 处)、/p/residence/lwt1128000462.o(1 处)(等共 10 个存档)。
quest/dynamic_room 的 .c 行:任务守护进程加载不了(2026-10-21,KB 06 §7.341)
任务守护进程(adm/daemons/taskd.lpc)的 create() 读 /quest/dynamic_room(琉璃庄的 19 个房间,/d/llzhuang/lou0.c ……),clear_room() 对每一行 load_object() 再 room->reset():显式的 .c 按原样解析(KB 03 §4.2),档案里的房间是 .lpc,load_object() 答 0,0->reset() 让 create() 中止,守护进程没有加载(HEAD 加载失败,改后通过)。2026-10-05 的 .c 行扫描只认 dynamic_location* 和 dynamic_quest* 两种表,dynamic_room 和 dynamic_npc_quest 没有扫到;scripts/lpc_dynamic_rows.py 现在认四种,这 19 行改成 .lpc(本库档案里没有的行照旧不动)。
findob:不带参数(2026-10-21,KB 06 §7.336)
ob = find_object(arg); 在第一句:不带参数时 Bad argument 1 to find_object() Expected: string Got: 0.。加了 if (!arg) return notify_fail("指令格式 : findob <物件路径>\n");。
cof:info[count][2] 越界(2026-10-21,KB 06 §7.347)
call_out_info() 之后的循环 for (i = 0; i < count; i++) if (max_eval < info[count][2]) 下标写成 count(比最后一个元素大一):每次都越界。改成 info[i][2],没有延迟函数时先答一句(info[0][2] 也会越界)。
蜀山厨子 chuzi:给食物的两行 new() 被注释掉了(2026-10-21,KB 06 §7.346)
do_yao() 里 m = new("d/obj/food/dishes/dish10"); / mm = ... 两行是注释,后面的 m->move(this_player()); mm->move(this_player()); 还在:向厨子要东西一律抛错。本库没有 dish10,按 chidi 的同一份文件改成 clone/food/baozi 和 clone/food/jiudai(本库都有)。
谷物加工厂 goldwork2/3/4:工作太久被赶出去时 ob->move(..)(2026-10-21,KB 06 §7.348)
working() 在连续工作次数超过 60+random(100) 时,运气低于 25 的人被送回广场:if ((int)me->query("kar") < 25) ob->move("/d/city/guangchang");,ob 声明了没赋值(同一目录的 goldwork.lpc、goldwork5.lpc 写的是 me->move)。抛错在 me->set_temp("working", 0) 和 cot-- 之前,房间里的工人计数漏掉一个,三次之后“人手已经够了”永远不再收人。改成 me->move(..),去掉 object ob;。改动:/d/city/goldwork2.lpc、/d/city/goldwork3.lpc、/d/city/goldwork4.lpc。
香烟 smoke.lpc:do_smoking() 读没赋值的 me(2026-10-21,KB 06 §7.348)
smoke 指令的第一句是 jing = me->query("jing"),me 声明了没赋值,每次抽烟都抛 Bad argument 1 to call_other()。补 me = this_player();(后面的 this_player() 调用不变)。改动:/d/emei/user-room/melodies/smoke.lpc。
妙手回春 valid_learn():先读 ob->query_temp("weapon") 再给 ob 赋值(2026-10-21,KB 06 §7.348)
学这门暗器技能时 valid_learn() 第一个武器检查读的是没赋值的 ob,xue / learn 在这里抛错;后面 ob = me->query_temp("weapon") 的检查才是对的。有两种写法:if (!ob->query_temp("weapon")) 改成 me->query_temp("weapon");if ((string)ob->query_temp("weapon") != "银针")(拿一个对象和字符串比较,永远不等,补上 ob 之后这门技能也学不成)改成后一种写法里的 !objectp(ob = me->query_temp("weapon")) || !(ob->id("yin zhen") || ob->id("yinzhen"))。改动:/kungfu/skill/miaoshouhuichun.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.,同一个动词的其他处理函数不再尝试(不是最新的一条就悄悄跳过)。删除了 43 条注册(38 个文件,scripts/lpc_fix_dead_add_action.py),动词留给别的处理函数:/d/biwu/chen.lpc(do_join)、/d/city/chatroom2.lpc(do_jump)、/d/city/giftroom.lpc(do_jump)、/d/city/mingren/giftroom.lpc(do_jump)、/d/city/npc/wei.lpc(do_sell)、/d/city2/qishi.lpc(do_pass)、/d/city3/npc/sister.lpc(do_vendor_list)、/d/fengxue/shandong1.lpc(do_swim)、/d/player/yysz/hupan.lpc(do_han)、/d/quanzhen/npc/haodatong.lpc(do_decide) 等共 38 个文件。最多的函数名:do_send 15 处、do_decide 7 处、do_faint 5 处、do_vendor_list 4 处、do_jump 3 处。
对象路径里的 ..:new(__DIR__ "../obj/x") 报 Read access denied(2026-10-22,KB 06 §7.351)
__DIR__ 是当前文件所在目录(带结尾斜杠),__DIR__ "../obj/x" 就是 /d/zhiye/npc/../obj/x;驱动的 legal_path() 不接受带 .. 的路径,new() / load_object() 直接抛 *Read access denied.(实测,find_object() 对它答 0)。走库自己的 carry_object() / 房间 objects 表的路径,库的基类会先规范化,能用;直接把路径交给 new() / clone_object() / load_object() / move() 的不行,调用到那一步才报错。改成规范化后的绝对路径(scripts/lpc_fix_dotdot_dir.py --direct):/d/wudang/npc/xiaocui.lpc(__DIR__ "../obj/nuerxiang" → "/d/wudang/obj/nuerxiang")。
缺失物品的 new() / carry_object() 调用链加了保护(2026-10-22,KB 06 §7.73 补充)
new(路径)->move(...); / carry_object(宏("x"))->wear(); 这类语句,路径指向的文件在这个压缩包里没有:new() 返回 0,->move() 在 0 上报 Bad argument 1 to EFUN call_other()。在 create() 里这个对象永远加载不了,在 reset() 里第一个缺失物品之后的刷新每次 reset 都被跳过。1 个文件里 1 处(new)改成 { object new_ob = new(路径); if (new_ob) new_ob->move(...); }(scripts/lpc_guard_carry_object.py --new:路径按这个文件自己看到的宏解析,宏名冲突、虚拟对象路径一律跳过)。 对这 1 个改动文件做加载检查(HEAD 与工作区对比):HEAD 能加载 1 个,现在 1 个(新增可加载 0 个,回归 0 个)。
调用了、但这个库自己的守护进程里没有的函数(2026-10-22,KB 06 §7.354)
MACRO->函数() 调用的函数在这个库的守护进程里不存在:call_other() 对不存在的函数不报错、只返回 0,所以这些功能(时间显示、昼夜事件、名字检查、价格文字……)一直没起作用。同一血统另一个库的同名守护进程里有这些函数,原文照抄到本库守护进程末尾(scripts/lpc_port_function.py;调用处传的参数个数、函数体用到的函数 / 全局变量 / 宏 / 字符串键都在本库里有,已核对;守护进程在 HEAD 和工作区都能加载,每个函数用固定参数各调用一次:HEAD 返回 0,现在返回正常的值):/adm/daemons/chinesed.lpc ← aoxiangtianji:chinese_month()(6 处调用)。
(: 函数 :) 指针指向对象自己没有定义的函数(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。 还剩 4 个函数没有补(inquiry 2, item_desc 2):原型还在函数体丢了、或者根本没写过,没有可以直接补回的捐赠(别的库同一路径的文件里没有这个函数,或者它还要用本库没有的辅助函数、签名不同),不编造:/d/city/npc/zhuziliu.lpc:give_job、/d/city/npc/zhuziliu.lpc:task_ok、/d/yihua/lianhuachi.lpc:look_CAI、/d/yuhua/lianhuachi.lpc:look_CAI。
读不到的留言板:"/clone/board/x"->foo(); 在 create() 里报错(2026-10-22,KB 06 §7.357)
xkx 系的房间在 setup() 之后写 "/clone/board/gaibang_r"->foo(); 来加载留言板(foo() 本来就没有定义,只为了触发加载)。这个库没有这个文件,call_other() 报 *call_other() couldn't find object '/clone/board/gaibang_r',对象留在内存里、load_object() 却抛错:玩家第一次走进房间就看到错误,写在 create() 中间的还会切掉后半段。scripts/lpc_fix_missing_foo.py 把 2 条单独成行的语句(/clone/board/meizhuang_b、/clone/board/tangmen_b;/d/meizhuang/houting.lpc、/d/tangmen/liujiantang.lpc)注释掉并写明原因(别的房间里同样的语句本来就是作者自己注释掉的)。证明和 45 个库的整体加载检查见 KB 06 §7.357。
不带前导斜杠的物品路径:缺失物品的 new() / carry_object() 调用链加了保护(2026-10-22,KB 06 §7.73 补充)
carry_object("d/city/obj/jiasha")->wear(); 这类路径不带前导斜杠的写法在这个驱动里按根目录解析(new("d/city/obj/changjian") 能加载 /d/city/obj/changjian),所以和带斜杠的一样:文件不在压缩包里时 new() 返回 0,->wear() 在 0 上报 Bad argument 1 to EFUN call_other(),整个 NPC 加载不了。此前的保护工具把这种写法当作「相对当前目录,没法判断」跳过了。1 个文件里 4 处(clone/cloth/fengting、clone/cloth/lingyun、clone/cloth/zixuan等)改成带保护的块(scripts/lpc_guard_carry_object.py)。 对这 1 个改动文件做加载检查(HEAD 与工作区对比):HEAD 能加载 0 个,现在 1 个(新增可加载 1 个,回归 0 个)。
(: 函数名 :) 指针指向本库没有的函数:只含这个指针的行加了注释(2026-10-22,KB 06 §7.355 补充)
inquiry / item_desc / chat_msg* 里的 (: 函数名 :) 指向本对象(含包含文件、继承的父类)没有函数体的函数:用到时(ask、look、NPC 闲聊)驱动抛 *Undefined lfun pointer called: 函数名,这一拍心跳的后半段被跳过。这些函数没有可以补回的来源(别的库同一路径的文件里没有,或者它还要用本库没有的东西),所以 2 个文件里 2 行只含这个指针的行("CAI": (: look_CAI :),)加了注释,原文保留并写明原因,这一项当作没有这个话题 / 物品 / 闲聊条目(scripts/lpc_fix_dangling_lfun.py;#include 的文件在库里缺失的对象、指针不在整行上的写法没动)。 前提(function_exists())和加载检查(HEAD 与工作区对比,本库改动的 .lpc 文件)的结果见 KB 06 §7.355:没有一个回归。
写死的 "/路径"->函数() 指向库里没有的文件:改成现存的同名文件(2026-10-22,KB 06 §7.359)
1 处语句级的 call_other 字面量路径,库里没有这个文件(区域改了名 / 大小写不对 / 差一个字母 / 文件挪了地方):"/d/mj/obj/baihong-jian"->move()(/d/mingjiao/npc/yingwang.lpc)→ "/d/mingjiao/obj/baihong-jian"。call_other() 对不存在的对象抛 couldn't find object,所在函数当场中断。改成库里现存、并且定义了被调用函数的文件(scripts/lpc_fix_call_path.py;巫师目录、备份目录、名字不同的兄弟文件都不算候选)。 其中殷天正(白眉鹰王)的 do_answer():玩家念对暗语(answer 怜我世人,忧患实多;保护教主,同抗外敌)时把白虹剑 move 给玩家,区域目录改名 mingjiao 之后这个路径没跟着改,回答暗语只得到 couldn't find object,剑永远发不出来。
汉字按字节切片的老写法没有换成按字符:改法名 "澄" + name[2..3]、辈分判断 name[0..1] == "澄" 等 23 处(2026-10-22,KB 06 §7.360)
原档按字节算字符串区间(一个汉字 2 字节):name[2..3] 是名字的第二个字,name[0..1] == "澄" 问名字是不是以「澄」开头。转成 UTF-8 之后,这个驱动的区间和 strlen() 都按字符算(strlen("澄观") 是 2,"澄观"[0..1] 是两个字),老算术原样留着、意思全变:拜入少林 / 武当 / 峨嵋等派的玩家被改成错误的法名(二字名 张三 变成一个字的 澄,更长的名字取到第三个字);各派掌门的辈分判断(name[0..1] == "澄")永远不成立。
本库 23 处(18 个文件):拼名字的赋值 15 处、与汉字常量比较 8 处。例:name[2..3] → name[1..1](/d/biwu/da-mo.lpc:155);name[0..1] → name[0..0](/d/xuedao/npc/suixi.lpc:102);name[0..1] == "慧" → name[0..0] == "慧"(/kungfu/class/shaolin/cheng.h:108)。scripts/lpc_fix_gbk_slice.py 把下标按字符重算(社区的 UTF-8 版 xkx100utf8 里就是同样的写法,作对照);没有改的:截断(name = name[0..7],现在最多 8 个字,只是放宽)、ASCII 的区间(fname[0..3] == "room"、ctime(time())[4..19])和上下文看不出是汉字的区间。证明(scripts/lpcc_eval.py,bixiecanyang;其余各库是同一份文本):让澄字辈掌门 attempt_apprentice() 一个名叫「张三」的访客,HEAD 的法名是 慧,改后是 慧三;抽样 28 个库的 HEAD / 工作树加载对比 0 退步。工具不幂等([0..3] 折半得 [0..1],又是对齐区间),改过的文件记在 scripts/gbk_slice_converted.txt,不要重跑。
长度检查按字节写,旁边的提示按汉字写:26 处(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 你好吗)。本库 26 处(13 个文件):if ((strlen(name) < 2) || (strlen(name) > 20)) {(/cmds/usr/buildlian.lpc:72);if ((strlen(name) < 2) || (strlen(name) > 40)) {(/cmds/usr/buildmen.lpc:77)。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 区间 15 个文件。证明(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(一格两个空格)。本库 8 处(4 个文件)。证明(lpcc_eval.py hhsj):tribar_graph(6,9,12) 在 HEAD 画出整条 12 个■,改后为 6 个■+3 个□;麻将 strlen(tempB)/2 是两字符牌码,未改。
Beyond 出口仍指向 /u/beyond(2026-10-23,KB 06 §7.368)
宁波 / 苏州 / 慕容等区域已进 /d/ningbo、/d/suzhou、/d/mr、/d/hz,出口与任务物路径仍写 /u/beyond/…。scripts/lpc_fix_beyond_exits.py 在目标 .lpc 存在时改写(murong→mr)。本库 1 处。证明:sjplii xikou HEAD 西向 /u/beyond/ningbo/aywsi,改后 /d/ningbo/aywsi 可加载;bxsj hubian1 三向均可加载。
死巫师出口 gold/dock、sunrise、mei(2026-10-23,KB 06 §7.370)
/d/wanjiegu/road4 东向 /u/g/gold/dock、峨眉寿星居南向 /u/xinyue/sunrise_room、玩家卧室通往 /u/mei/… 均无对应房间。scripts/lpc_fix_drop_dead_u_exits.py 删除这些出口行,并去掉同方向的 create_door(否则 create_door 无出口会炸)。本库 5 处。证明:zxty08nxgbb 的 road4 HEAD 有东向,改后没有;mei_room1 可加载。
中文名 / 验证码仍按 GBK 取「两字节一字」(2026-10-23,KB 06 §7.373)
pname = pname[(random(sizeof(pname)) & 0xFFFE)..<1]; pname = pname[0..1]; 在按字符计下标时会取出两个汉字。scripts/lpc_fix_pname_slice.py 去掉掩码并把收尾改成 [0..0](pname/pname2/sec_name/str/str1)。本库 4 处。证明:nt1 生成名长度 2–4;HEAD 常见 3–5。
hanbing `random 反引号(2026-10-27,KB 04 §6.25 Also)
hanbing-mianzhang / hanbing-mianzhang2 在 random( 前多了一个反引号,驱动按模板字面量读到 EOF。删掉。证明:HEAD 失败;改后加载。
set("long" 丢引号(2026-10-27,KB 04 §6.25 Also)
set("long", 后直接跟汉字(无 " / @LONG),驱动报 Illegal character。用同路径完好手足覆盖(fyue_room←jhfy;hudi5/6←zxty08nxgbb;quanzhen_old/hudi*←xyzxfy2)。证明:HEAD 失败;改后加载。
深度功能测试(2026-10-27,§6.25 ZHAOSHI 截断玩家技能)
玩家自创武功在 // ZHAOSHI : 0 处截断(EOF),无法加载。按同系完整 moming-blade 补一招 + valid_*/query_*/practice(6):kungfu/skill/killkillkill-sword.lpc, kungfu/skill/love-sword.lpc, kungfu/skill/papaquan-unarmed.lpc, kungfu/skill/shangxin-sword.lpc, kungfu/skill/hahasword-sword.lpc, kungfu/skill/tianxiawuxue-sword.lpc。
深度功能测试(2026-10-27,§6.25 d/city/sj 去引号)
d/city/sj 整文件去引号(add_action(do_out, out) 等);按 jhfy 完整副本替换。
深度功能测试(2026-10-27,§6.25 zhongling tell_object 引号错位)
d/wanjiegu/npc/zhongling(及同路径副本)的 tell_object("who, 钟灵脱下一双绣花鞋。\n") 把对象参数写进了字符串;改为 tell_object(who, "…")。证明:原文错位;改后加载,语料残渣 0。
深度功能测试(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… 行。