info.html · 介绍 · play.html · 游玩 · llms.txt · 下载与本地运行 · ZIP · GitHub
取材自金庸小说《侠客行》,作者 "Coollizard" 与 "xkx100" 团队自 2001 年起维护,属于本项目"Century 家族"(`adm/single/` 目录结构)武侠 mudlib 分支之一,是这批游戏中文件数量最多的一个(转换后约 1.2 万个 LPC 文件),经比对代码库与本项目另两款同名"侠客行"游戏 xiakexing2017、xiakexing3(二者彼此是关系密切的近亲)截然独立;游戏世界以北京、长安、洛阳、扬州等真实历史地名为骨架,覆盖全国多个"出生地",新角色从随机分配的出生城市客栈起步,创建时可选择冒险、谨慎、可人、睿智、坚韧五种性格类型,影响初期属性倾向;可通过寺前武僧一类 NPC 拜入少林门下,在木人桩前安全习武过招;此外还有一套与现实时间并行显示的独立"侠客行历法"。
English
Based on Jin Yong's novel Ode to Gallantry (Xia Ke Xing), developed since 2001 by author Coollizard and the xkx100 team. It belongs to this collection's "Century" mudlib family (built around an adm/single/ directory layout) and is the largest of that group by file count — roughly 12,000 LPC files after conversion, and confirmed to have a distinct codebase from this collection's other two Xia-Ke-Xing-titled libs (xiakexing2017, xiakexing3), which are themselves close siblings of each other. Its map is built around real historical Chinese cities, including Beijing, Chang'an, Luoyang, and Yangzhou, with new characters starting at a randomly assigned home-city inn (e.g. Jiaxing's "Misty Rain Tower"); at creation, players also pick one of five personality types (Adventurous, Cautious, Likable, Wise, Resilient) that nudges their starting stat spread. New characters can apprentice into the Shaolin sect through the monk Qingwei at the temple square, becoming a lay disciple of Shaolin's 41st generation, and spar safely against the temple's wooden training dummy while learning kung fu. An independent "Xia Ke Xing calendar" clock runs alongside real time.
README
内容亮点
- 游戏世界以北京、长安、洛阳、扬州等真实历史地名为骨架,覆盖全国多个 "出生地"供玩家选择。
- 少林寺设有木人陪练(
d/shaolin/obj/mu-ren.lpc)。
在线试玩
https://mudlibs.fluffos.info/xiakexing100/
管理员账号 / Admin account
- ID:
fluffos - 密码 / Password:
Mud@2026 - 中文名 / Display name: 浮浮
- 权限 / Level:
(admin)—— 本 lib 的最高等级,通过adm/etc/wizlist授予。
警告:这是一个公开的默认密码,仅供本地/浏览器试玩。正式对外开服前
请务必修改此密码。
本地运行
cd libs/xiakexing100
~/src/fluffos/build-debug/src/driver config.fluffos游戏端口:40037。这是本批游戏中体积最大的一个,启动后请稍等片刻 再连接。
NOTES · 移植与修复记录
xiakexing100 — 侠客行一百
Archive: 侠客行100.rar. Port: 40037. Status: done (boots clean and
quick, full registration flow verified end-to-end including a real
Chinese name).
What this is
"侠客行一百", credited to "Coollizard & xkx100 2003-2004",
http://yoyo.xm.fj.cn/xkx100, up since 2001-01-14 per its own connection
banner. Same "Century-family" adm/single/{master,simul_efun} layout
as shiji/zhonghua2/shujian2008/etc. ~14,227 raw files, 12,209
after .c→.lpc rename — the largest lib processed in this session
run.
Fixes applied
1. AGENTS.md §15h, standard shape: is_chinese()'s GBK lead-byte
check → CJK codepoint check; check_legal_name()'s byte-count bound
< 4 || > 10 → character-count bound < 2 || > 5, removed the
i%2==0 even-byte-offset gate.
2. Confirmed NOT needed, via source reading: no §4 fix
(master.c's valid_write gates via find_object only,
valid_read is a bare return 1;); no deep named.lpc fix
(named.c exists but lacks the PATH()/sliding-window pattern seen
in the nitan-family shape — a simpler, different implementation
here).
3. AGENTS.md §15p: /adm/daemons/network/dns_master was in
adm/etc/preload — removed proactively before the first boot
attempt. Booted clean in under 20 seconds, zero compile errors, no
hang.
Interactive test result — full registration flow
No hidden pre-id prompts. Verified the complete registration path in
one continuous connection: id xkxbtest → confirm y → real Chinese
name 秦风 (avoiding "韦小宝"/Wei Xiaobao — a famous Jin Yong
character found in this lib's banned_name list) → accepted, proceeds
straight to "请设定您的密码:".
lpcc sweep
12,209 files, 12,118 pass / 91 fail (99.3%). Failure tail dominated by
an accept_hit type-mismatch cluster (120 of the reported instances
across files, string vs object argument), plus the usual handful of
missing globals/syntax typos — not triaged individually per AGENTS.md
§6b/§13. Memory stayed comfortably healthy throughout the sweep despite
this being the largest lib in the current session run (~13GB free
consistently, lpcc RSS peaked well within normal range, no pressure
requiring an early kill).
Re-verification pass (driver rebuild + LPC formatter + WASM build)
- Reformatted all 12209
.lpcfiles underwork/withtools/lpc-syntax/format-corpus.mjs: 10795 written, 1414 already idempotent-clean, 0 refused. Verified the earlier §15ae fix (feature/command.lpc'scommand_hookstayingnomaskwithprivatestill commented out) survived unchanged. - Native retest against the freshly-rebuilt driver (
~/src/fluffos/build-debug/src/driver, rebuilt from latest upstream master): clean boot, zero fatal errors inlog/debug.log. Full registration flow re-verified with a fresh real Chinese name (秦墨/idxkxbrew, then秦徽/idxkxbrev), reaching an actual starting room,look/score/quitall producing correct output — also separately re-confirmed post-login command dispatch (the §15ae fix) via a reconnect +lookon the saved character. No regressions from either the driver rebuild or the reformat. - WASM build test found and fixed a real, pre-existing mudlib bug (
scripts/wasm_client.jsagainst~/src/fluffos/build-wasm/src): boot itself was clean, but every connection attempt silently stalled right after the login banner, never reaching the id prompt at all — no fatal error printed anywhere. Root-caused by reproducing the exact same stall natively (temporarily moving asidework/log/MUDVISITOR, the untracked runtime-state visitor-counter fileadm/daemons/logind.lpc'showmany_visitor()reads on every connection):read_file(VISITORS)returns a non-string (0) when the file doesn't exist, and the un-guardedsscanf(content, "%s %d", ...)that follows throwsBad argument 1 to sscanf— uncaught, this aborts the rest oflogon()silently (confirmed viadebug.log's执行时段错误:*Bad argument 1 to sscanf), before the player ever sees an id prompt. This is a genuine pre-existing mudlib bug, not a WASM-specific driver gap — it just never manifested in earlier native testing passes becauseMUDVISITORalready existed on disk from prior test runs (it's untracked/gitignored runtime state, not shipped in the original archive's git history), whereasscripts/wasm_client.js's in-memory filesystem deliberately never copieslog/'s *contents* (only creates the empty directory, by design, to keep the harness fast), so a WASM run is effectively always a "genuinely fresh archive, first boot ever" scenario for this file — the exact condition that triggers the bug. Fixed: added astringp(content)guard (return0/treat as "no visitors yet" if the file doesn't exist) to bothhowmany_visitor()and the identically-shapedhowmany_card()(GIFTCARDfile, same pattern, fixed proactively). Re-verified: (a) natively, withMUDVISITORmoved aside, connection now proceeds straight to the id prompt showing "第一位访问者" and a full registration completes cleanly, zerodebug.logerrors; (b) under WASM, full registration now also completes end-to-end (idxkxwasmz→ real Chinese name秦岫→ stat roll → gift/email/gender → landed in an actual starting room,look/score/quitall producing correct output). This lib has no IP-format-dependent login gate, so once this fix was in place it was fully playable under WASM too.
WASM-enablement pass (loopback-allow / admin seeding)
Applied the four standard WASM-first changes (AGENTS.md §1.3b/§1.3e/§1.5).
1. Loopback always allowed — ban list + per-IP throttles (adm/daemons/logind.lpc:73-124)
logon() ran BAN_D->is_banned(), an in_login > 10 per-IP
in-progress-login throttle, and BAN_D->is_multi() (per-IP character
cap) unconditionally. Added an is_local local computed once and
gated all three on !is_local.
Written fail-closed from the start (2026-07-24): is_local =
(stringp(lip) && (lip == "127.0.0.1" || strsrch(lip, "127.") == 0)) —
only a genuine loopback-shaped string is treated as local; an
unparseable/non-string ip is NOT local and still goes through the ban
list and both throttles. (An earlier partial pass on this file had used
the fail-open shape seen on this batch's other four libs — !stringp(lip)
|| lip == "127.0.0.1" || strsrch(lip, "127.") == 0 || sscanf(lip,
"%*d.%*d.%*d.%*d") != 4, which let ANY malformed ip bypass every gate —
but that was corrected to the fail-closed form above before this pass
was considered complete; see the sibling libs' NOTES.md entries for the
full rationale: the old WASM driver bug that produced garbage
query_ip_number() output is now fixed, so there is no reason left to
treat "can't parse it" as "must be loopback".)
2. Uptime startup gates — none present
No uptime() < N connection-rejection gate exists in this lib. All
uptime() hits are in-game content: gambling rooms (d/*/duchang*.lpc,
npc/douji, npc/saigui), NPC/room respawn timers, cooldowns, and
adm/daemons/autosaved.lpc's once-per-boot data-file initialization
(if (uptime() < 400) { ...write_file... } — first-boot bootstrap of
some /data/* flags, not a connection gate). Nothing to bypass.
3. Anti-flood throttles — covered by item 1
No separate registration-throttle daemon exists; the per-IP protection
in this lib IS the in_login/BAN_D->is_multi() checks patched above,
already loopback-exempt.
4. Admin account seeded — fluffos / Mud@2026 / 浮浮
Registered through the real flow (id fluffos → y → 浮浮 →
test1234/confirm → talent 1/20/20/20/y → personality 0 →
email → m), landed in a random starting room. Granted (admin) by
appending fluffos (admin) to adm/etc/wizlist (securityd.lpc's
get_status() reads this file into wiz_status). Verified: login as
fluffos shows 目前权限:(admin), update /adm/daemons/logind →
重新编译 /adm/daemons/logind.lpc:成功!.
Save files for the orchestrator to force-add (untracked, not gitignored):
libs/xiakexing100/work/data/user/f/fluffos.olibs/xiakexing100/work/data/login/f/fluffos.o
Bonus fix: quit/exit was silently broken for EVERY player (pre-existing, not WASM-related)
While verifying the admin account's quit, discovered cmds/usr/exit.lpc's
savequit() never actually let anyone quit: int a = 1; is reassigned
inside the if (link_ob) {...} branch to a = (link_ob->save()), and
link_ob (me->query_temp("link_ob")) is the /clone/user/login
connection object set by enter_world()/reconnect() on every
login, not just a rare possession/reconnect edge case. FluffOS's
save_object() efun returns the byte-size of the text written on
success (confirmed by reading ~/src/fluffos/src/vm/internal/base/object.cc's
save_object_recurse(), which accumulates and returns textsize), not
a 0/1 boolean — so a ends up as some multi-hundred-byte count, and the
final check if (a == 1 && me->save()) was false for virtually every
quit, for every character, admin or not. The player saw all the normal
quit text ("你共停留了...欢迎下次再来!") followed immediately by a scary
"警告:档案保存失败,无法退出游戏,请马上联系巫师解决。" and was never
actually disconnected (destruct(me) never reached). Confirmed present
verbatim in the original raw archive (raw/xkx100/cmds/usr/exit.c), so
this is a decades-old author typo/driver-assumption mismatch, not
something introduced by this project's conversion or by the WASM pass.
Fixed: if (a == 1 && me->save()) → if (a && me->save()) (test
truthiness, matching the efun's actual 0=fail/nonzero=success
contract). Verified with a fresh registration and with the fluffos
admin account: quit now completes cleanly with no warning and no
lingering interactive body.
Retest (2026-07-24)
Fresh boot, fresh registration (id qinlanx/qintestb, real Chinese
names 秦岚新/秦测三) through look/score/quit — landed in a
starting room, correct score output, clean quit with no warning.
fluffos/Mud@2026 admin login verified: look then update
/adm/daemons/logind → 重新编译 ... 成功!, then clean quit (the
bonus fix above). Zero 执行时段错误 lines in debug.log across the
whole session (the one hit from an unrelated missing-log/nosave/
directory surfaced only while probing the quit bug with the call
wizard command directly on a userp target — log/ is fully
gitignored/regenerated at boot, not a real defect worth chasing
further here). Test characters removed afterward; fluffos kept.
Reverted an incidental data/topten.o leaderboard diff caused by the
test registrations (pre-existing tracked file, not meant to churn from
QA runs).
深度功能测试 / Deep functional test (AGENTS.md §10.7, 2026-07-24)
One continuous native session (~/src/fluffos/build-debug/src/driver,
port 40037), following the §10.7 checklist end to end: read help
intro/help newbie/help newbie-basic/help newbie-shaolin1 first,
registered a real Chinese name (qftester / 秦风, password test1234,
born 嘉兴/group 3, talents 20/20/20/20, personality 0), landed at
/d/jiaxing/yanyu ("烟雨楼"), look/score/i/hp all correct.
Explored on foot toward 牛家村 reading room .lpc source
(d/jiaxing/*.lpc) to navigate since exit lists intermittently hide
under the lib's night-time darkness gate. Used the wizard spgo/
summon commands (via the seeded fluffos admin) purely to fast-travel
the SAME test character to distant content (少林寺 练武场/广场) rather
than trekking the whole map by foot — the actual sect-join, skill-learn,
combat, and shop interactions below were all performed by the ordinary
player character, not the admin.
Safe sparring: the newbie guide's suggested targets (a village
小孩/女孩) both declined fight — traced this to their attitude
being genuinely "friendly" in their own create() (/d/village/npc/
kid.lpc, /d/village/npc/girl.lpc), which inherit/char/npc.lpc's
accept_fight() is coded to always decline (case "friendly": ...
return 0;) — working as designed, not a bug (a different, unrelated
/d/jiaxing/npc/boy.lpc//d/village/npc/boy.lpc with attitude:
"peaceful" momentarily looked like a mismatch until the actual live
object path was confirmed via call obj->query(...) — red herring, not
reused). Used the lib's own documented, code-confirmed-safe wooden-dummy
mechanic instead (d/shaolin/obj/mu-ren.lpc, accept_fight() checks
me->query("damaged")/a random(fight_times)>=10 break-chance, exactly
the §10.7-item-3 shape): fight mu at /d/shaolin/wuchang1 exchanged
several rounds of blows with correct combat text, halt ended it
cleanly, hp/i afterward correct, zero debug.log errors.
Skill/sect join: followed help newbie-shaolin1's documented path —
apprentice biqiu (清为比丘 at /d/shaolin/guangchang1w) immediately
accepted as a 俗家弟子/少林派第四十一代弟子 (no manual ask ... about
出家/kneel needed for this particular monk); score showed 师父/称谓
updated correctly; skills biqiu listed the master's own skill roster;
xue biqiu dodge 1 (organic NPC-teacher path) advanced 基本躲闪 from
unlearned to 1/0, cha confirmed it. Both the sect-join and
skill-learn steps worked correctly, no separate admin-command shortcut
was tested (none is needed/expected in this lib — apprentice IS the
join mechanism).
quit → debug.log → reconnect (§10.7 items 5, 8, 9): clean quit
produced no warning (confirms the pre-existing savequit() fix from the
"Bonus fix" section above still holds) and left zero new debug.log
lines. Net-dead (dropped the connection without quit) and reconnected
PROMPTLY (a few seconds later): worked correctly, position/state intact.
Net-dead and NOT reconnecting until the real timeout elapsed found a
new, live-reproduced bug — see below. Separately, clean quit
followed by a genuine ~75-real-second wall-clock gap, then a FULL fresh
login (not a net-dead reconnect) via qftester/test1234: correctly
restored sect membership, skill, and all score fields from the
on-disk save file (data/user/q/qftester.o — family mapping,
skills/learned mappings, dbase.qi/jing etc. all intact).
Shop purchase (§10.7 item 6): character had no starting funds
("你没有存款"), so used the admin account to clone /clone/money/coin,
call coin->set_amount(500), spgive qftester coin (funding only —
the purchase itself was performed by the ordinary player character).
list at 烟雨楼's 店小二 showed the menu correctly; buy jitui (30
文) succeeded, correctly made change into higher denominations (500
铜钱 → 1 烤鸡腿 + 4 两白银 + 70 文铜钱); eat jitui consumed it. No
errors.
Not verified live: progression to a real death/respawn cycle — the
session budget went to the net-dead bug investigation below instead;
code review only (d/city/ghost*.lpc/鬼门关 revival flow referenced by
help newbie-basic's〖死亡〗section was read but not exercised). A
sect promotion (拜达摩/升辈) is a multi-hour undertaking per the
newbie guide's own admission and was not attempted.
Bug found and fixed: tell_room() 2-arg wrapper crashes the net-dead force-quit handler — matches AGENTS.md §7.12 exactly (severity-escalated instance)
adm/simul_efun/message.lpc's tell_room() wrapper:
varargs void tell_room(mixed ob, string str, object *exclude) {
if (ob) message("tell_room", str, ob, exclude); // BEFORE
}Every 2-argument call site leaves exclude as LPC's default int 0
(not an empty array), and the real message() efun's 4th argument
rejects a bare 0. clone/user/user.lpc's user_dump() — the
NET_DEAD_TIMEOUT-driven (900s / 15 real minutes, include/user.h)
force-quit handler that runs when a net-dead player never reconnects —
calls tell_room(environment(), ..., "\n") with only 2 args at its very
first line (the DUMP_NET_DEAD case). This is byte-for-byte the same
lib/function/case/timeout shape AGENTS.md §7.12 documents as
"severity-escalated" from dtsl's deep functional test: the crash
aborts user_dump() at that exact statement, so the two lines after it
("/cmds/usr/exit"->savequit(this_object())) never run — silently
disabling the entire net-dead force-quit safety net: a player who
net-deads and never manually reconnects would stay alive in server
memory forever (never actually saved-and-removed via this path) until a
driver restart.
Live-reproduced (not just pattern-matched): temporarily lowered
NET_DEAD_TIMEOUT from 900 to 12 (include/user.h), ran the wizard
update /clone/user/user command to recompile it, connected as
qftester, dropped the connection without quit, waited past the
shortened timeout:
执行时段错误:*Bad argument 4 to EFUN message()
Expected: object, array, Got: int(0).
程式:/adm/single/simul_efun.lpc 第 77 行
呼叫来自:/clone/user/user.lpc 的 user_dump() 第 75 行,物件: /clone/user/user#105 ("秦风")
呼叫来自:/adm/single/simul_efun.lpc 的 tell_room() 第 77 行Fixed (the standard AGENTS.md §7.12 wrapper fix, protects every 2-arg call site in the lib at once, not just this one):
varargs void tell_room(mixed ob, string str, object *exclude) {
if (ob) message("tell_room", str, ob, exclude || ({})); // AFTER
}Re-verified with the same shortened-timeout methodology: no crash,
debug.log clean, and who afterward showed only the admin online —
qftester was correctly force-quit-and-saved this time (confirms the
two previously-dead lines, including savequit(), now execute).
Restored NET_DEAD_TIMEOUT to 900 and did a full clean driver restart
before finishing (the test-only timeout value was never left in place).
Note for the project: two other confirmed "Century/adm-single"
lineage siblings (AGENTS.md §11) — shiji and xjcq2000 — still
carry the exact same unfixed 2-arg tell_room() wrapper in their own
adm/simul_efun/message.lpc (checked via grep during this pass, not
fixed — out of scope for this task, which is xiakexing100-only).
shujian2008, xkxz2, and zhonghua2 (same family) already
carry the fix from earlier passes. Worth a follow-up pass on shiji/
xjcq2000 specifically for this bug given xjcq2000 is
also the lib AGENTS.md §10.8 documents hitting an unrelated driver-fatal
crash ~25 minutes into its own net-dead soak — the two are different
bugs but both live in the same net-dead code path family.
Observation, not fixed (design ambiguity, see §10.7's scope note): two independent day/night clocks can visibly contradict each other
cmds/std/look.lpc's exit-listing darkness gate
(天色太黑了,你看不清明显的出路) keys off NATURE_D->game_time(),
which derives an in-game shichen (時辰) hour from a heavily-compressed
calendar clock (adm/daemons/natured.lpc: #define TIME_TICK
((time()%(60*24*3600))*365) — 60 mud-years pass every 60 real days,
i.e. roughly 6 mud-hours per real minute, confirmed live: the session's
in-game date advanced across several 时辰 within a couple of real
minutes). The SEPARATE sun-position flavor line
(NATURE_D->outdoor_room_description()) keys off current_day_phase,
a nosave variable advanced by its own independent real-time
call_out("update_day_phase", ...) cycle. These two clocks are not
synchronized and were observed live disagreeing outright in the same
room printout — "一轮火红的夕阳正徘徊在西方的地平线上"(sunset flavor
text) immediately followed by "天色太黑了,你看不清明显的出路"
(darkness gate, only fires for 亥/子/丑/寅时) moments apart, and at one
point "太阳正高挂在西方的天空中"(afternoon flavor text) paired with the
SAME darkness message. Purely cosmetic/exit-listing (movement in a
known direction still works even when the list is hidden — confirmed by
navigating through several "dark" rooms via directions read from
source), and both clocks' formulas are pure LPC business logic with no
encoding/efun/grammar involvement, so this is very plausibly authentic
original-game behavior rather than anything this project's conversion
introduced. Documented per §10.7's scope note rather than "fixed" by
guessing which clock should govern the gate.
§7.86 跨库扫描修复(留言板 post 崩溃)
BULLETIN_BOARDinherit+ 多余replace_program()致命形状(AGENTS.md §7.86,post命令崩溃):全档案 70 处命中,已删除多余的replace_program(...)调用(保留inherit),逐文件保留原有行尾格式(CRLF/LF 按文件原样)。本次为跨库 §7.86 扫描修复(触发原因:该 bug 已在 6+ 个互不相关的血统家族独立确认,属于近乎普遍的拷贝粘贴模式),仅做编译检查(驱动干净启动、端口正常监听),未做完整 §10.7 深度游玩测试。
深度功能测试(2026-08-13,round two,新驱动重测)
针对驱动升级(quest_times/win_times %-operator 修复 + Warning/warning
大小写回退兼容)做的重测。
发现并修复的 PROGRAMMING bug
1. log_file()(adm/simul_efun/file.lpc)完全没有
assure_file() 保护(AGENTS.md §7.11-class):已加上前向声明
+ assure_file(LOG_DIR + file);。
Proactive checks(无需改动)
- 实际生效的 master file 是
adm/single/master.lpc(config.fluffos指定),其log_error()已经在更早一轮修复过(strsrch(message, "arning:") == -1判断)。仓库里还有一份未使用的adm/obj/master.lpc(没有任何档案#include/引用它,也不是config.fluffos指定的 master file),其中的log_error()仍是 未修复的旧形状——确认它是死代码后未改动。 win_times的%-operator 修复确认存在且正确:d/city/npc/jinyong.lpc:197、d/beijing/npc/refereew.lpc:177、d/city/npc/gulong.lpc:246均已用to_int(query("win_times")) % 5。feature/dbase.lpc未发现 tybxjh/wlhd 那种密码写保护,不适用。
实测过程
管理员 fluffos/Mud@2026(此前 WASM 阶段已注册并提交存档)用真
实密码重新连线,落地在此前保存的地点(车马店),score 正常显示
天赋/属性,quit 前的游戏内状态与存档一致。全程 debug.log 只有
正常的编译期提示(Unknown #pragma 等价的 In file included
from 追踪行、未使用局部变量),无运行时错误。驱动按精确 PID 结
束;测试期间产生的存档时间戳增量已 git checkout -- 还原,未提
交无关变化。
AGENTS.md §7.100 修复(2026-08-19,批次三)
ROOM 基类冗余 replace_program(ROOM); 自崩溃地雷(详见 AGENTS.md
§7.100):4430 处命中,其中 d/huangshan/banshan.lpc 是本项目已见
过多次的"同一个 create() 里两处独立冗余调用"形状(setup() 前
后各一次),两处均删除。自带建房工具 clone/misc/roommaker.lpc 的
字符串拼接模板同样修复。
git diff --stat:4428 files changed, 1 insertion(+), 4430 deletions(-),
与预期精确吻合。
验证:build-debug 驱动真实冷启动,端口 40037 正常监听。既有管理
员账号 fluffos(登录密码为 Mud@2026,与原始注册记录的
test1234 不同,二者都在 NOTES 中留档过)登录,目前权限:(admin)
确认,车马店→南大街→车马店多房间走访无误,quit 干净退出,全程
无新增 "cannot replace"/"cannot bind" 日志行。
§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: 4 line(s) in 1 file(s) count a range from the end with < (x[a..-1] -> x[a..<1], x[-2..] -> x[<2..]; KB 06 §7.209). In this driver a negative constant end gave "" / ({ }) and a negative start the whole value, so each of these returned the wrong slice; the compile warning A negative constant as the second element of arr[x..y] is gone from the files that compile. Range lvalues (s[0..-1] = text, the prepend idiom) are left alone. A paired compile of the changed files at HEAD and in the working tree showed no new error.
深度功能测试(§10.7,2026-10-05)— here-document terminators (opener line, case)
scripts/lpc_fix_heredoc_terminator.py --all --apply: 2 more block(s) repaired: 2 where the text sits on the opener's line (@LONG text...LONG, the newlines were lost): open/task1/huodu.lpc, d/city/task1/huodu.lpc.
深度功能测试(§10.7,2026-10-05)— 任务表里的 .c 路径与任务守护进程的防护
scripts/lpc_dynamic_rows.py:quest/dynamic_location 里 4141 行写的是原档案的 .c 路径。转档时文件已改名 .lpc,而显式后缀按原样解析,load_object("/d/x.c")、new("/d/obj/quest/x.c") 返回 0 且不报错(KB 03 §4.2,KB 06 §7.220),所以 adm/daemons/questd.lpc 读到的每一行都加载不出来:随机任务和任务物品从未生成,在 create() 里直接对结果调用 tar->set() 的版本还会崩溃,连带加载它的 cron 守护进程和 give 的任务钩子。这些行已改为 .lpc。
scripts/lpc_dynamic_quest_guard.py:1 处 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和 cron 守护进程在新进程里加载(HEAD 一次,工作树三次,选房是随机的):HEAD 通过 2 个,工作树三次分别通过 2、2、2 个(共 2 个),无回退。
验证:改动过的 adm/daemons/questd.lpc、cmds/std/look.lpc 在新进程里加载,HEAD 通过 2 个、工作树通过 2 个(共 2 个),无回退。
深度功能测试(§10.7,2026-10-05)— 房间列出的物件缺档时房间照常加载
房间基类 inherit/room/room.lpc:make_inventory() 用 catch() 包住 new(file),做不出来就返回 0;reset() 的 case 1: 拿到 0 就跳过这一项(if (!objectp(ob[list[i]])) break;)。档案里没有的 NPC 或物品(或 create() 出错的物件)原先会让列出它的房间整个加载失败(Bad argument 1 to environment(),或对 0 的 call_other()),连带这个房间后面的区域;现在房间照常加载,只是少了那个物件,下次 reset() 再试(KB 05 §7.25;scripts/lpc_resilient_room.py、scripts/lpc_room_reset_guard.py)。
验证:探针(scripts/lpc_room_reset_probe.py:房间基类列出一个不存在的物件,再调用 reset())HEAD 单件 崩溃、多件 崩溃,工作树 单件 OK、多件 OK。
深度功能测试(§10.7,2026-10-06)— 编译警告整理
scripts/lpc_warnings.py xiakexing100 --fix:无用局部变量 1847 个、varargs 7 处、转义 34 处、nosave 函数 30 个改 protected,共改动 879 个 .lpc。这些文件在 HEAD 与工作树分别加载(新进程):867 -> 867 通过,无回退;scripts/lpc_audit_removed_locals.py HEAD 的 16 条候选都是声明被重建(仍在用的名字保留)或同名的 efun 调用(time())。启动时警告 505 -> 0;新进程启动后登录界面(侠客行时间与农历日期、名字校验、新人物确认)正常。
深度功能测试(§10.7,2026-10-07)— 空的 if (current_water == 0) {}
3 个房间的 valid_leave() 里有一行什么也不做的 if (current_water == 0) {}(编译警告 Expression has no side effects),删去,行为不变:d/xingxiu/nanjiang2.lpc、d/xingxiu/nanjiang3.lpc、d/xingxiu/shanjiao.lpc。
深度功能测试(§10.7,2026-10-08)— .lpc 后缀的定宽切片
.c 改名 .lpc 时只改了字符串没改切片宽度:f[<2..] == ".lpc" 拿两个字符比四个字符,永远不成立(!= 永远成立),按后缀筛文件、去后缀的代码因此从不运行或截成 x.l(KB 06 §7.238)。scripts/lpc_lpc_suffix_slice.py --apply 改了 5 处比较、2 处去后缀(如 clone/npc/qingyun.lpc);改动的文件 HEAD 与工作树分别加载(新进程),无回退。
- 2026-10-10:
/d/wudujiao/mishi.lpc的技能判断用按位&连接两个比较(如tjss > 10000 & taoism > 10000),改为逻辑&&。两边都是 0/1 比较结果,行为不变,只是写法纠正。
- 2026-10-10:编译警告第二轮(按驱动报告逐条修):按位 & 改逻辑运算 12 处,返回类型/原型 34 处,NPC+F_UNIQUE 的 init() 0 个,带初始化的未用局部变量 0 个,只在 #if 分支用的声明移进分支 0 个文件;改动 36 个文件,HEAD 与工作树各载入一次无回退(36 objects; HEAD PASS 36, tree PASS 36; regress 0; newly loading 0),这些文件的警告 47 -> 0。
深度功能测试(§10.7,2026-10-11):钱塘潮颜色
adm/daemons/event/qiantang.lpc:"…十分壮观。\n"; NOR;分号把NOR隔成独立语句,颜色不复位;改为"…" NOR;。载入无回退。
深度功能测试(§10.7,2026-10-11):“无副作用表达式”警告复查(批 3)
daemon/skill/*-archery.lpcpractice_skill():(: throw_weapon :);只造函数指针不调用(练习本就不该射箭),删去。- 改动的对象 HEAD 与工作区都能载入,无回退。
深度功能测试(§10.7,2026-10-11):dns_master 空 if
adm/daemons/network/dns_master.lpcquery_services():if (! (mud_svc[mud]["tell"/"finger"] & SVC_KNOWN)) {里只有#if PREF_X & SVC_TCP … #endif,选项关闭时 if 体为空(“无副作用”警告);把#if/#endif挪到 if 外面(KB 04 §6.10,2026-10-07 那次扫描漏掉了! (带空格、大括号另起一行的写法)。载入无回退。
深度功能测试(§10.7,2026-10-11):dns_master 空 if
adm/daemons/network/dns_master.lpcquery_services():if (! (mud_svc[mud]["finger"/"tell"] & SVC_KNOWN))块里只有#if PREF_X & SVC_TCP … #endif,选项关闭时 if 为空(“无副作用”警告报在下一句);把#if/#endif挪到 if 外面(KB 04,2026-10-07 那次扫描漏了! (加括号换行这种写法)。载入无回退。
深度功能测试(§10.7,2026-10-11):铁掌山房间描述
d/tiezhang/pingtai.lpc、wmfeng.lpc、wztang.lpc:完整描述后孤立的"\n";删去(无可见变化)。载入无回退。
深度功能测试(§10.7,2026-10-12):黑木崖老者
d/heimuya/npc/laozhe.lpcinit():残留调试行sprintf("%s \n", what);,what是对象,本驱动sprintf的%s遇对象报错,进房间时init()每次中断、招呼从不执行;删去(与 fys 同)。
编译警告收尾(2026-10-12)
scripts/toolkit_fix.sh 一轮加手工收尾,能编译的文件警告清零。改动的 34 个对象 HEAD 与工作树各载入一次:HEAD PASS 32,tree PASS 33,regress 0,新载入 1(laozhe)。
- 冗余继承 15 处(
lpc_diamonds.py:open/task1/*、open/xiangyang/npc/*的 NPC 又直接继承一遍基类已有的 mixin;shenzhao-jing、taixuan-gong、douzhuan-xingyi/xingyi)。d/city/pai9room.lpc在inherit ROOM前多写了inherit F_CLEAN_UP,删去(§7.240)。 clean_up()两条路进来(F_SSERVER与 NPC/SKILL/ROOM 基类都继承F_CLEAN_UP):d/death/god1、d/yixing/npc/bangzhong、kungfu/skill/{bixie-jian,love-sword,taiji-jian}用lpc_name_winner.py写出驱动本来就选的那一个。d/heimuya/npc/laozhe.lpc:command("give yancao to", me)给单参数 efun 传了两个参数,是编译错误,这个老者从来载不进来;同族其它库都已注释掉这一行和白克隆一个yancao的那行,这里照删。open/xiangyang/task/guo.lpc同时 includezzzjob.lpc和teamjob.lpc,两者各声明一份逐字相同的names表;两处都加#ifndef XIANGYANG_TASK_NAMES防重。d/yixing/doc/info_{store,biao,guest}.h经bangzhu_duty.h/guanjia.h被同一文件 include 两次,加 include guard。- 宏重定义:
shuyuan2/3的STORY_DIR(globals.h里是故事守护的目录)、clxiaoting/bangling的BANGZHU、biaotou的BIAOHUO(changle.h已定义),本地#define前加#undef。d/city/daxiaoroom.lpc注释块里的嵌套/*。 - 未改:
d/yixing/npc/bangzhu.lpcHEAD 就编不过(doc/set_bang.h:83语法错误),与本轮无关。
- 2026-10-12:
open/xiangyang/task/teamjob.lpc的组队任务用names[0][random(40)]选地点,而这张表只有 34 个地名,random()落到表外时数组越界报错、任务中断。改成random(sizeof(names[0]))(shenmou/stey/newjob/teamjob.lpc同类)。HEAD 与工作树各载入一次,regress 0。
- 2026-10-14:新驱动(FluffOS 970d9f09)报
Float value truncated to int(#1426)。9 个文件 12 处:赋值、初始化、return 改写成to_int(...)(值不变,只是写明截断);x op= 浮点先把浮点转成整数再运算(系数小于 1 时 x 直接变 0),改为x = to_int(x op ...):/kungfu/skill/bahuang-gong/powerup.lpc(skill *=)。改动的对象新进程各载入一次,无回退(scripts/lpc_fix_float_trunc.py,KB 04 §6.10)。 - 2026-10-14(同一次重扫,手工部分):
- 36 个技能文件的 int power_point() 返回 1.1–1.5 的浮点(含按内功等级分支的写法),经 int 返回一律被截成 1,改为 float。
- adm/daemons/combatd.lpc 用到这个值:
- 防守时读进 float dpower,限定在 1–1.5,乘到防御等级上,这里原本就是浮点写法。
- 进攻时原写 damage *= (int)SKILL_D(...)->power_point(me)。(int) 对浮点只是编译期标注,不做转换,damage 会在运行时变成浮点。现改为 damage = to_int(damage * ...)。
- 玩家可见:带威力系数的武功和轻功按原设计的 1.1–1.5 倍计算伤害和防御。原先在本驱动下系数一直被截成 1。
- d/city/daxiaoroom.lpc 去掉注释里嵌套的 /*;mudlib/testsuite/tmp_eval_file.lpc 补 return。
- 2026-10-14:1 个文件因
Illegal to inherit after defining global variables整份不编译:FluffOS 要求所有inherit写在第一个全局变量之前,MudOS 不管。scripts/lpc_fix_inherit_order.py把写在inherit之前的全局变量(以及声明全局变量的头文件的#include)挪到最后一个inherit之后(KB 04 §6.3)。
内力/精力当作伤害种类(2026-10-15,KB 06 §7.241 第二类)
本库 feature/damage.lpc 的 receive_damage() 不接受 jingli/neili/force 等种类,me->receive_damage("jingli", 30) 之类在练功、绝招、吸取时报 F_DAMAGE: 伤害种类错误。5 处改为 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,而不是作者写好的提示。2 处在声明行加上 if (!mapp(fam)) fam = ([ ]);(scripts/lpc_fix_family_guard.py)。
其他体系的属性名(2026-10-15,KB 06 §7.241 第三类,--any-file)
另有 1 个文件(绝招、状态、物品、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,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。18 处补上 if (!mapp(fam)) fam = ([ ]);(刚 recruit_apprentice() 之后的除外)。
技能按另一门武功的等级取招(2026-10-15,KB 06 §7.243)
这些技能文件是从别的武功复制改名来的,query_action() 仍用原武功的等级查招式表:只会本技能的人等级为 0,取不到招,每次出招都报错。改为读本技能自己的等级(scripts/lpc_fix_action_level.py):boruo-strike、cibei-blade、huashan-jianfa、huashan-zhangfa。
空手使用兵器绝招(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):taiji-jian/raozhi。
技能名拼错(2026-10-15,KB 06 §7.249)
query_skill() 里的技能名拼错了,或用的是本库改名前的旧名;本库没有这个技能,调用永远得 0:门槛(< N 就拒绝)永远过不去,相关功夫或绝招学不了、用不了;内功互斥(> N 就拒绝)从不生效;公式里这一项一直是 0。经汉字名(提示文字或中文名词典)或纯拼写差异(_/-、少一个连字符、相邻字母颠倒)核对后,改为本库的技能名(scripts/lpc_fix_skill_typo.py):five_poison→five-poison(/clone/medicine/poison/redyao、/clone/medicine/poison/shenxiandao、/clone/medicine/poison/whiteyao、/clone/medicine/poison/wuxing、/clone/medicine/poison/yellowyao);jinwu-dao→jinwu-daofa(jinwu-daofa)。
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,而不是得到拒绝。3 处(3 个文件)改为 dbase 路径查询 query("family/master_name"):有门派时值相同,没有时得 0;原有的判断照常生效(scripts/lpc_fix_family_index.py)。给映射赋值的写法未动。
达摩剑「达摩三绝剑」、反两仪刀「华岳三神峰」每次报错(2026-10-15,KB 06 §7.246)
两个绝招都声明了 object weapon, ob; 却从不给 ob 赋值:结尾 if (!ob->is_fighting(me)) 在内力扣完后报错,sanshen 的三刀甚至都砍向 ob(0)。改为 target,并先判断 objectp(target)(循环里可能取不到对手)。
去掉的预定义宏 SAVE_EXTENSION(2026-10-18,KB 04 §6.11)
老版 MudOS 给每个 LPC 对象预先定义了 SAVE_EXTENSION(".o");FluffOS 的 ChangeLog(COMPAT_BUSTER 一条)把它删了,改用 __SAVE_EXTENSION__。本库没有自己 #define 这个宏,用到它的文件一律 Undefined variable 'SAVE_EXTENSION',整个对象载入不了。改成 __SAVE_EXTENSION__(scripts/lpc_fix_predefined_macro.py):d/jiaxing/npc/tang.lpc、d/jiaxing/npc/tang3.lpc、d/quanzhou/npc/tang.lpc、d/quanzhou/npc/tang3.lpc、include/net/ftpdsupp.h。tang3/tang/meng-zhu 是武林盟主一类的 NPC,原来一个都载入不了。改后用 lpcc 逐个载入这些对象:4 个通过。
set_skill() 遇到本库没有文件的武功不再抛错(2026-10-18,KB 06 §7.256)
feature/skill.lpc 里的 set_skill()、map_skill()、prepare_skill() 碰到没有武功文件的名字就 error("F_SKILL: No such skill (…)"),调用它们的 NPC create() 整个中断:NPC 载入不了,刷出它的房间也少一个人。本库目前没有对象设了缺失的武功;三处都改成 return:这一门武功不给、不映射,对象照常载入,只是少了它(缺的武功本身仍是内容缺口)。(scripts/lpc_guard_set_skill.py)
宠物商人 d/city/npc/oldman 的变量叫 class(2026-10-18,KB 04 §6.14)
string *class = ({ ... }) 的 class 在 FluffOS 里是保留字(结构体),syntax error, unexpected L_CLASS,老头载入不了。变量改叫 pet_class(7 处)。载入:通过。
武功名拼错的 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 映射不到,门派弟子用普通轻功/拳脚)。按核对过的对照表改正,共 26 处、18 个文件:shaolin-shnfa→shaolin-shenfa(5 处)、pixie-jian→bixie-jian(4 处)、choushui-zhang→chousui-zhang(4 处)、pixie-sword→bixie-sword(3 处)、tiaji-jian→taiji-jian(2 处)、lingbo-weibu→lingboweibu(2 处)、shenxingbaibian→shenxing-baibian(1 处)、jingding-zhang→jinding-zhang(1 处)等共 12 个名字。(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)
RANK_D 对 0 的称呼(2026-10-19,KB 06 §7.273)
adm/daemons/rankd.lpc 的 query_respect()、query_rude()、query_self()、query_self_rude() 里 4 个函数开头补上 if (!objectp(ob)) ob = this_object();。NPC 在 create() 里写 "…" + RANK_D->query_respect(this_player()) + "…"(inquiry 对话、chat_msg),驱动自己跑 reset() 时没有人在场,this_player() 是 0。旧驱动里 0->query("age") 返回 0,称呼走默认分支;新驱动直接报 Bad argument 1 to EFUN call_other(),房间的 make_inventory() 吞掉错误,被打死的 NPC 再也刷新不回来。用 scripts/lpc_reach_census.py --walk 找到(xkx100 的武当弟子、一灯、汴梁书生…);修在守护程序里,不动 1,800 个 NPC 文件。
被注释吞掉的 inherit / include(2026-10-19,KB 06 §7.274)
/d/shaolin/npc/obj/heisuo.lpc:#include <weapon.h>;/d/shaolin/obj/heisuo.lpc:#include <weapon.h>。这些指令接在上一行 // 注释的末尾(档案里丢了换行),成了注释的一部分,驱动看不到:缺 inherit 的技能报 Undefined function offensive_target,缺 #include <weapon.h> 的兵器报语法错误。scripts/lpc_fix_swallowed_directive.py 把换行放回去。载入检查 2 个文件,2 个原来编译不过、现在载入,没有退步。
标准整理轮(2026-10-19,scripts/toolkit_fix.sh)
本库在新驱动下重扫,机械修复:2 个未使用的局部变量。修后与 HEAD 逐个物件对比载入,没有退步。
载入不了的零碎文件(2026-10-19,KB 03 §4.7、KB 04 §6.10)
d/shenlong/jushi.lpc、sea.lpc、sea2.lpc里me->name() + "\241\243\n"的\241\243(GBK 的「。」写成八进制转义,旧驱动把这两个字节原样发给 GBK 客户端)改成「。」;新驱动报Invalid UTF8 codepoint in string literal,三个房间(共 4 处)载入不了。
逐个载入与 HEAD 对比,没有退步。
标准整理轮,第二轮(2026-10-19,scripts/toolkit_fix.sh)
本库在新驱动下重扫,机械修复:1 个未使用的局部变量。修后与 HEAD 逐个物件对比载入,没有退步。
手工收尾(2026-10-19,KB 04 §6.10)
d/city/npc/oldman.lpc:宠物店老人的int *weight = ({ … })(宠物重量表)和 NPC 基类feature/move.lpc的nosave int weight(物件自己的重量)同名(Redeclaration of global variable 'weight'),驱动给了它第二个变量;改名pet_weight(nosave,3 处,scripts/lpc_rename_ident.py),行为不变。
逐个与 HEAD 对比载入,没有退步。
帮派文件里丢掉的引号(2026-10-19,KB 03 §4.6)
d/yixing/doc/set_bang.h第 82、84 行:两句帮主的话,最后半个字连同结尾的引号一起丢了(…景仰之情<乱码>);),下一行的开头引号把它闭合,后面的汉字被当成代码(Illegal character 0xe8),宜兴帮主d/yixing/npc/bangzhu.lpc从来载入不了。字串照 nt7 里完好的拷贝补回(犹如滔滔江水连绵不绝。、帮主的敬仰犹如黄河泛滥一发不可收拾。),引号补上。- 同一文件第 45 行
level = ceil( pow( … ) ) * 4 / 5;把浮点数存进 int,补to_int()。 d/yixing/doc/info_store.h、info_biao.h、info_guest.h没有重复包含的保护(本库其他拷贝有):bangzhu.lpc自己 include 一遍,bangzhu_duty.h→guanjia.h又 include 一遍,四张表被声明两次;加上#ifndef __YIXING_INFO_*_H__。bangzhu.lpc同时继承NPC和F_SSERVER,两条路都带来clean_up()(clean_up() inherited from both …),写出int clean_up() { return sserver::clean_up(); },行为不变。
载入 d/yixing/npc/ 的 bangzhu、biaotou、bangzhu2、cl_bei:HEAD 通过 3 个,现在通过 4 个(bangzhu.lpc 现在载入),没有退步。
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/baihuagu/yangfeng.h(1 处)、/d/gumu/liangong1.lpc(1 处)、/d/mingjiao/shanmen.lpc(1 处)。另有 /d/city/npc/majiang.lpc(2 处) 的条件下面做的是别的事(== 和 || 也可能是本意),保持原样。
深度功能测试(§10.7,2026-10-20):实机指令扫描后同步 xkx100 的发现(KB 08 §10.16)
xkx100 的实机指令扫描(见 libs/xkx100/NOTES.md)里和本库代码相同的几处,同样修复:cmds/usr/boss.lpc(/open/shit.txt 不存在,write(0))、cmds/usr/news.lpc 和 inherit/misc/bboard.lpc(公告板房间 /u/qingyun/workroom 不存在)、cmds/wiz/clone.lpc(if (msg = "none"))、cmds/wiz/cip.lpc(无参数)、cmds/wiz/w_lian.lpc(__DIR__ "enable" 指向不存在的 /cmds/wiz/enable)、clone/quest/* 与 clone/haojie/shashou.lpc 的 random_move()(find_object(dest)->query("no_fight"),目的地没载入时对 0 调用)、adm/daemons/disaster.lpc(lead->name(),领头玩家离线时报错、戒严不解除)、cmds/wiz/callouts.lpc(call_out_info() 只有 3 项)。exit.lpc 的 a == 1 和 npcd.lpc 的 string dest 本库 7 月就是对的。
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,共 16 处)。改动:/d/changan/npc/majiang.lpc(3 处)、/d/changan/npc/matong.lpc(3 处)、/d/changan/puke-room.lpc(4 处)、/d/city/npc/matong.lpc(3 处)、/d/city/shufengguan.lpc(1 处)、/d/hangzhou/npc/meipo.lpc(1 处)、/quest/weixiaobao.lpc(1 处)。
callouts:sizeof(info[i]) == 4 把每一行都挡掉了(2026-10-20,KB 06 §7.287)
驱动的 call_out_info() 每项只有 3 个元素,输出行前的守卫 if (sizeof(info[i]) == 4) 永远不成立,指令只打印表头。改为 >= 3。改动:/cmds/adm/callouts.lpc(1 处)。
登录密码超过 255 字节:crypt() 抛错(2026-10-20,KB 06 §7.294)
驱动的 crypt() 对超过 255 字节的密钥直接报错(Error in crypt(), check your salt),老驱动则按任意长度散列。在登录提示符下输入 256 字节以上的密码,密码检查那一行就抛错,连线停在一个裸的 > 提示符上,登录走不完(password 指令的旧密码检查同样);用 300 个 x 当参数的扫描发现的。/adm/single/simul_efun.lpc 里补了一个同名的 simul_efun crypt(key, salt):只有超长的密钥才被截短(先截到 255 个字符,再逐字符截到 sizeof(to_buffer(key)) <= 255,限制按字节算,一个汉字占三个字节),再交给 efun::crypt();普通密码原样散列,已存的密码散列不受影响(scripts/lpc_add_sefun.py crypt)。
sefun cat():缺文件时 write(0) 报错(2026-10-20,KB 06 §7.297)
void cat(string file) { write(read_file(file)); }:文件不存在(压缩包没带的欢迎/公告文件,或只有运行中的 mud 才会写的日志)时 read_file() 回 0,write(0) 在本驱动里报 Bad argument 1 to receive(),调用者(登录对话、cat 指令)被中断;老驱动什么也不打印。改成 write(read_file(file) || "");(scripts/lpc_fix_cat_unchecked.py)。改动:/adm/simul_efun/file.lpc。
翻页器 start_more(read_file(...)):文件缺失时 explode(0)(2026-10-20,KB 06 §7.300)
东方故事系的翻页器 void start_more(string msg) { ... explode(msg, "\n") ... } 被这样调用:start_more(read_file(HELP_DIR + "help/topics"))、start_more(read_file(NEWS))。压缩包没带的文件使 read_file() 回 0,explode(0, ...) 在本驱动里报 Bad argument 1 to explode()(不带参数的 help 指令就是这样出错的),老驱动把 0 当空文本。在 start_more 开头加了 if (!stringp(msg)) return;(scripts/lpc_fix_start_more.py)。改动:/feature/more.lpc。
get_config(__MUD_PORT__) 经旧版 runtime_config.h 得到字符串(2026-10-20,KB 06 §7.302)
本库的 include/runtime_config.h 是老 MudOS 的编号(整数设置从 15 起,本驱动从 256 起),get_config(__MUD_PORT__) 读到的是另一项设置(字符串),(int) 又只是编译期标注,于是 socket_bind(fd, LOCAL_PORT()) 报 Bad argument 2 to socket_bind(),版本守护进程 port = get_config(__MUD_PORT__) + VERSION_PORT 是字符串相加。头文件自己的注释写明 get_config(__MUD_PORT__) == __PORT__,所以代码里的这个调用(连同外面的 (int) / to_int())改成了驱动的预定义 __PORT__(scripts/lpc_fix_mud_port.py)。改动:/include/getconfig.h(1 处)。
d/luoyang/obj/xiang.lpc:chuangli 先 explode(read_file("/log/PARTY"))(2026-10-20,KB 06 §7.326)
关帝像的 chuangli(kaibang)指令在检查年龄和经验之前就读 /log/PARTY,那是运行中的 mud 记录已创立帮派的文件,全新的树里没有,explode(0) 报 Bad argument 1 to explode():任何人敲 chuangli 什么 都是系统错误,而不是“你还嫩着呢”。改成 file = read_file("/log/PARTY") || "";(空串的 explode 是空数组)。xkx100utf8 和 nt7 是 gitlink 库(fluffos-org 上游),同一行在那里没有改。加载检查各 1/1。
NPC 的 chat() 在 chat_msg 为空数组时下标越界(2026-10-21,KB 06 §7.334)
NPC 基类的 chat() 是 if (arrayp(msg = query(...))) { if (random(100) < chance) { rnd = random(sizeof(msg)); if (stringp(msg[rnd])) ...,不检查列表是否为空。本库有 1 个 NPC 文件写成 set("chat_msg", ({ }))(或 chat_msg_combat)并带正的 chat_chance(例如 /d/city/npc/lulixian.lpc),每次心跳有 chat_chance% 的概率 random(0) 为 0、msg[0] 报 Array index out of bounds(驱动捕获,心跳继续,但每次一条运行时错误),这个 NPC 在内存里就一直发生。在 random(100) < chance 前面加 sizeof(msg) &&(scripts/lpc_fix_chat_empty.py;if (random(100) > chance) return 0; 的写法是 !sizeof(msg) ||)。改动:/inherit/char/npc.lpc(共 1 个文件)。
巫师命令不带参数时对 0 调用 efun(2026-10-21,KB 06 §7.336)
巫师(管理员)把命令敲成不带参数时,驱动把 0 传给字符串参数;下面的命令第一句就把这个 0 交给 efun,运行时报 Bad argument 1 to ...,这条指令从来没有用过。用 scripts/lpcc_bare.py 不登录、在一次 lpcc 求值里以 0 调用 main() 逐个确认后,由 scripts/lpc_fix_bare_arg.py 在第一处使用参数的语句前加守卫:没有 help() 的是 return notify_fail("…\n");。改动(1 个文件,括号里是接住 0 的 efun):/cmds/wiz/inittask.lpc(sscanf)。加载检查 HEAD 与工作树对照,没有退步。
blockade / recover:data/keep 不存在,解封之后世界仍然锁着(2026-10-21,KB 06 §7.340)
管理员扫描里 blockade 报 Error copying file from /data/user/f/fluffos.o to /data/keep/fluffos, Error: No such file or directory,随后的 recover 在第一个 cp() 上死于 */data/keep/fluffos: lstat failed,来不及执行最后的 LOGIN_D->set_madlock(0):封锁解不开。data/keep/ 是运行时目录,git 克隆里没有空目录。blockade 在第一次写之前 if (file_size("/data/keep") != -2) mkdir("/data/keep");(mkdir() 失败答 0,不抛错),recover 对没有保存档的玩家 if (file_size(src) < 0) continue;,其余照常恢复、照常解锁(scripts/lpc_fix_keep_dir.py,hy5 上实测:没有保存档时 recover 答“时空解封完毕”,blockade 建出 data/keep 并保存,recover 取回并删除)。改动(2 个文件):/cmds/arch/blockade.lpc、/cmds/arch/recover.lpc。
任务分配 quest:按顺序找目标的备用循环用了 living[j](2026-10-21,KB 06 §7.347)
/feature/quest.lpc:先随机挑目标(j = random(sizeof(living))),挑不中再“按顺序找”:for (i = 0; i < sizeof(living); i++) if (check(living[j], ...)) { target = living[j]; break; }。下标写成了 j(上一个循环最后一次的随机下标),备用循环把同一个 NPC 检查 sizeof(living) 遍,世界小的时候任务就分不出去。xkx100 的原文就是这样,派生库照抄。改成 living[i]。
追杀任务 killer1.lpc:奖励循环里的 me 从没赋值(2026-10-21,KB 06 §7.348)
黑衣人 die() 对每个在场的追杀者发经验和潜能,循环里写的是 me->add("combat_exp", exp)(nitan 系是 addn("combat_exp", exp, me)),me 要到循环之后才被 find_player(owner) 赋值:xkx100 系抛 Bad argument 1 to call_other(),nitan 系把奖励悄悄记到 0 上,追杀者什么也拿不到。循环里先 me = obs[i];。改动:/clone/quest/killer1.lpc。
马钰 waiting():等了 300 秒没等到的惩罚落在没赋值的 ob 上(2026-10-21,KB 06 §7.348)
七星阵的等待超时分支写的是 ob->add("score", -5000)(nitan6 系 addn("score", -5000, ob)),ob 在这个分支里还是 0:超时那一刻抛错,之后的 do_back 已经排好了所以只是少了惩罚。hhsj、nitan170911、xfbhh 里同一处写的是 me(带着任务的玩家),照改。改动:/kungfu/class/quanzhen/ma.lpc。
注册到不存在函数的 add_action(2026-10-21,KB 06 §7.349)
add_action("函数", "动词") 绑定的函数,在对象本身、它包含的头文件、它继承的父类和继承它的子类里都没有定义(scripts/lpc_scan_callout_targets.py 静态解析,子类用传递闭包复核,scripts/lpc_verify_handlers.py 运行时 function_exists() 复核)。驱动从玩家最新的一条动作往回找,遇到这样的句子就报 *Function for verb 'drop' not found.,同一个动词的其他处理函数不再尝试(不是最新的一条就悄悄跳过)。删除了 11 条注册(8 个文件,scripts/lpc_fix_dead_add_action.py),动词留给别的处理函数:/clone/medicine/nostrum/gaoyao.lpc(do_eat)、/clone/misc/city/city.lpc(do_chakan)、/d/changan/qishi.lpc(do_pass、do_resign)、/d/city/weiqishi.lpc(do_pass、do_resign)、/d/shenlong/obj/sg_mianzhao.lpc(do_open)、/d/wudujiao/huxue2.lpc(do_train)、/inherit/misc/fboard.lpc(do_list)、/kungfu/class/yunlong/xutianchuan.lpc(do_skills)。最多的函数名:do_pass 2 处、do_resign 2 处、do_skills 2 处、do_eat 1 处、do_chakan 1 处。
基类的 add_action 登记:处理函数只在后代里定义,基类自己被加载时报错(2026-10-21,KB 06 §7.349)
房间、NPC、公告板这类基类,init() 里登记的 add_action("函数", "动词") 的函数只由继承它的后代定义;基类对象自己被直接加载(房间可以走进去、NPC 可以克隆)时,访客输入这个动词,驱动报 *Function for verb 'x' not found.(第一轮扫描把这些当成“有后代定义,是活的”放过了,scripts/lpc_verify_handlers.py 在基类对象上跑 function_exists() 才看出来)。登记前加 if (function_exists("函数", this_object(), 1))(第三个参数 1:默认 function_exists() 把 protected / private 函数当作没有定义),后代照常登记。共 1 处、1 个文件(scripts/lpc_fix_dead_add_action.py --guard):/d/yixing/npc/bangzhu.lpc(do_xue)。
对象路径里的 ..:new(__DIR__ "../obj/x") 报 Read access denied(2026-10-22,KB 06 §7.351)
__DIR__ 是当前文件所在目录(带结尾斜杠),__DIR__ "../obj/x" 就是 /d/zhiye/npc/../obj/x;驱动的 legal_path() 不接受带 .. 的路径,new() / load_object() 直接抛 *Read access denied.(实测,find_object() 对它答 0)。走库自己的 carry_object() / 房间 objects 表的路径,库的基类会先规范化,能用;直接把路径交给 new() / clone_object() / load_object() / move() 的不行,调用到那一步才报错。改成规范化后的绝对路径(scripts/lpc_fix_dotdot_dir.py --direct):/d/wudang/npc/xiaocui.lpc(__DIR__ "../obj/nuerxiang" → "/d/wudang/obj/nuerxiang")。
缺失物品的 new() / carry_object() 调用链加了保护(2026-10-22,KB 06 §7.73 补充)
new(路径)->move(...); / carry_object(宏("x"))->wear(); 这类语句,路径指向的文件在这个压缩包里没有:new() 返回 0,->move() 在 0 上报 Bad argument 1 to EFUN call_other()。在 create() 里这个对象永远加载不了,在 reset() 里第一个缺失物品之后的刷新每次 reset 都被跳过。2 个文件里 3 处(new)改成 { object new_ob = new(路径); if (new_ob) new_ob->move(...); }(scripts/lpc_guard_carry_object.py --new:路径按这个文件自己看到的宏解析,宏名冲突、虚拟对象路径一律跳过)。 对这 2 个改动文件做加载检查(HEAD 与工作区对比):HEAD 能加载 2 个,现在 2 个(新增可加载 0 个,回归 0 个)。
(: 函数 :) 指针指向对象自己没有定义的函数(2026-10-22,KB 06 §7.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 个函数没有补(other 2, inquiry 2):原型还在函数体丢了、或者根本没写过,没有可以直接补回的捐赠(别的库同一路径的文件里没有这个函数,或者它还要用本库没有的辅助函数、签名不同),不编造:/adm/daemons/npcd.lpc:exert_function、/adm/daemons/npcd.lpc:perform_action、/d/yixing/npc/bangzhu.lpc:ask_skills、/d/yubifeng/npc/huyidao.lpc:ask_book。
(: 函数名 :) 指针指向本库没有的函数:只含这个指针的行加了注释(2026-10-22,KB 06 §7.355 补充)
inquiry / item_desc / chat_msg* 里的 (: 函数名 :) 指向本对象(含包含文件、继承的父类)没有函数体的函数:用到时(ask、look、NPC 闲聊)驱动抛 *Undefined lfun pointer called: 函数名,这一拍心跳的后半段被跳过。这些函数没有可以补回的来源(别的库同一路径的文件里没有,或者它还要用本库没有的东西),所以 2 个文件里 4 行只含这个指针的行("武功": (: ask_skills :), "skills": (: ask_skills :), "刀谱": (: ask_book :),)加了注释,原文保留并写明原因,这一项当作没有这个话题 / 物品 / 闲聊条目(scripts/lpc_fix_dangling_lfun.py;#include 的文件在库里缺失的对象、指针不在整行上的写法没动)。 前提(function_exists())和加载检查(HEAD 与工作区对比,本库改动的 .lpc 文件)的结果见 KB 06 §7.355:没有一个回归。
汉字按字节切片的老写法没有换成按字符:改法名 "澄" + name[2..3]、辈分判断 name[0..1] == "澄" 等 41 处(2026-10-22,KB 06 §7.360)
原档按字节算字符串区间(一个汉字 2 字节):name[2..3] 是名字的第二个字,name[0..1] == "澄" 问名字是不是以「澄」开头。转成 UTF-8 之后,这个驱动的区间和 strlen() 都按字符算(strlen("澄观") 是 2,"澄观"[0..1] 是两个字),老算术原样留着、意思全变:拜入少林 / 武当 / 峨嵋等派的玩家被改成错误的法名(二字名 张三 变成一个字的 澄,更长的名字取到第三个字);各派掌门的辈分判断(name[0..1] == "澄")永远不成立。
本库 41 处(30 个文件):拼名字的赋值 29 处、与汉字常量比较 9 处、与汉字常量比较 1 处、对切片赋值 2 处。例:name[0..1] → name[0..0](/d/tianlongsi/npc/kurong.lpc:374);name[2..3] → name[1..1](/kungfu/class/emei/fengling.lpc:117);name[4..5] → name[2..2](/kungfu/class/quanzhen/chu.h:80)。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,不要重跑。
长度检查按字节写,旁边的提示按汉字写:6 处(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 你好吗)。本库 6 处(3 个文件):if ((strlen(name) < 2) || (strlen(name) > 12)) {(/cmds/skill/editskill.lpc:451);if ((strlen(arg) < 2) || (strlen(arg) > 10)) {(/d/hangzhou/npc/huqingyu.lpc:84)。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 区间 7 个文件;茶馆猜诗 mixup 1 个文件。证明(scripts/lpcc_eval.py):sjplii 的 check_legal_name 在 HEAD 接受「张a」、改后拒绝,两边都接受「张三」;xkx100 的 clubpoem->mixup("离离原上草") 得到「离离原草上」(真交换汉字);nitan_san 两字同盟名得到 【 兄 弟 】。关键对象加载通过。
血条 / 表情标题按字节算显示宽度(2026-10-23,KB 06 §7.365)
老档把汉字当两字节:bar_string[0..(val * N / max) * 2 - 1] 把「格数」换成字节下标,半格血条在本驱动(按字符算区间)上会整条画满;巫师表情 edemote 的 repeat_string("─", 13 - (strlen(emotion) / 2)) 也会少减汉字宽度。scripts/lpc_fix_display_pad.py:去掉 CJK 血条 / 空白条上的 * 2(jings/qis 赋值和 blank_string3[0..(23-a)] 的 23→11 一并改),表情标题去掉 / 2;ASCII 空格的 none_string / empty_string 仍保留 * 2(一格两个空格)。本库 6 处(3 个文件)。证明(lpcc_eval.py hhsj):tribar_graph(6,9,12) 在 HEAD 画出整条 12 个■,改后为 6 个■+3 个□;麻将 strlen(tempB)/2 是两字符牌码,未改。
死巫师出口 gold/dock、sunrise、mei(2026-10-23,KB 06 §7.370)
/d/wanjiegu/road4 东向 /u/g/gold/dock、峨眉寿星居南向 /u/xinyue/sunrise_room、玩家卧室通往 /u/mei/… 均无对应房间。scripts/lpc_fix_drop_dead_u_exits.py 删除这些出口行,并去掉同方向的 create_door(否则 create_door 无出口会炸)。本库 1 处。证明:zxty08nxgbb 的 road4 HEAD 有东向,改后没有;mei_room1 可加载。
中文名 / 验证码仍按 GBK 取「两字节一字」(2026-10-23,KB 06 §7.373)
pname = pname[(random(sizeof(pname)) & 0xFFFE)..<1]; pname = pname[0..1]; 在按字符计下标时会取出两个汉字。scripts/lpc_fix_pname_slice.py 去掉掩码并把收尾改成 [0..0](pname/pname2/sec_name/str/str1)。本库 4 处。证明:nt1 生成名长度 2–4;HEAD 常见 3–5。
/open/ 上残留的 family 映射门(2026-10-24,KB 05 §7.30 Also)
与 xkx100 同源:open/xiangyang/task/pi1..pi4.lpc(§7.30 Also)。
/open/ 上残留的武功授予拼写(2026-10-27,KB 06 §7.258 Also)
lpc_fix_skill_names.py 曾把 /open/ 当巫师家跳过。open/task1/ 的 cao/caokou/eseng/meng/zhu 已 set_skill("shaolin-shenfa", …),却 map_skill("dodge", "shaolin-shnfa");quan 同理 kunlun-shnfa。映射失败,轻功仍是普通 dodge。改为正确名。证明:lpcc_eval HEAD 上 query_skill_mapped("dodge") 为 0,改后为 "shaolin-shenfa";quan 为 "kunlun-shenfa"。
深度功能测试(2026-10-27,§6.25 ZHAOSHI 截断玩家技能)
玩家自创武功在 // ZHAOSHI : 0 处截断(EOF),无法加载。按同系完整 moming-blade 补一招 + valid_*/query_*/practice(1):kungfu/skill/dragonfly-sword.lpc。
深度功能测试(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… 行。