Light Rain Journey to the West II (Xiaoyu Xiyou II)

✅ 可玩

小雨西游Ⅱ (Xiaoyu Xiyou II)

xyxy2

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

▶ 开始游玩 · Play Now

原始压缩包名为"20150716未知lib.zip"(来源不明),实际是"小雨西游"(Xiaoyu Xiyou)引擎家族的第二份快照,和本项目里的 `xiaoyuxiyou`、`xyxyutf8` 同属一支——三者共享同一张"傲来国"地图(`chinese.c` 档案与世界地图数据一致),但内容哈希比对显示彼此并非字节级重复,各自是游戏开发不同阶段留下的独立快照。新角色其实是从傲来国的"翠香楼"起步——《西游记》原著里孙悟空的出生地——而不是长安酒楼;玩家先找陪练 NPC 安全练级,再拜入武馆师傅门下学艺,之后能乘筏渡江前往长安,加入百花谷门派;死亡后会被送往地府的一处驿站小镇,那里设有专属的生死公告栏,复活时还会有真实的属性惩罚。

English

Originally archived under the generic filename "20150716 unknown lib.zip," this is actually the second entry in the "Xiaoyu Xiyou" (Light Rain Journey to the West) engine family, sharing a lineage with this project's sibling snapshots xiaoyuxiyou and xyxyutf8 (confirmed via an identical chinese.c file and shared world data, though a content-hash comparison shows it's not byte-identical to either -- each is a snapshot from a different point in the game's development, not a re-encoding). New characters actually start at Cuixiang Tower in the Aolai Kingdom -- Sun Wukong's own birthplace in the original novel -- not at a Chang'an tavern as an earlier version of this description claimed. From there, players spar safely against a training NPC to gain early levels, apprentice under a martial-arts-hall instructor, and can eventually cross a raft to Chang'an to join the Hundred Flowers Valley sect. Death sends characters to the underworld, landing them in a waystation town with its own "Board Between Life and Death" bulletin board before reviving them with a stat penalty.

README

内容亮点

在线试玩

https://mudlibs.fluffos.info/xyxy2/

管理员账号 / Admin account

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

本地运行

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

游戏端口:40003。驱动内置 30 秒启动保护期,请稍候后再连接。

NOTES · 移植与修复记录

20150716未知lib.zip → xyxy2

Status: DONE — boots clean, playable over telnet

Full ASCII-art Monkey King banner, GB/BIG5 encoding-selection prompt (a legacy dual-encoding-era feature — answering either way is fine since everything here is UTF-8 now), then normal login flow, all confirmed working. Note: this lib enforces a 30-second startup grace period (adm/daemons/logind.lpc's logon(): if (uptime() < 30) { ...still starting up, try later... }) — intentional, not a bug; wait >30s after boot before testing a connection.

What was fixed

1. Encoding: 9208 converted, 320 already UTF-8/ASCII, 31 skipped binary, 76 lossy (-c fallback, pre-existing stray bytes). 2. .c → .lpc: 8467 files. 1914 literal .c" refs auto-fixed, 0 left over. 3. static → nosave: 203 files. 4. master.lpc has neither the §4 (load_object in valid_read) nor the §14 (2-arg valid_override) issues — checked, both already fine in this lib (it uses sscanf(file, "/adm/simul_efun/%s", file) to detect simul_efun fragments for the destruct override case, a different but equally valid solution to the same problem AGENTS.md §14 documents). 5. adm/etc/log/ directory was missing entirely from the archive (not just the driver's debug-log dir — the mudlib's OWN runtime log dir). Symptom: repeated *Wrong permissions for opening file /log/log for append errors at boot (misleading — it's a missing-directory issue, not an actual permission problem; SECURITY_D's write-permission check for a nonexistent path denies rather than erroring with ENOENT). Fixed: mkdir work/log. 6. Found and fixed a new general pattern (AGENTS.md §8d): ~200+ files #include <local.h>-style a per-file header living in their OWN directory (e.g. d/kaifeng/ground0.lpc's #include <ground.h>, with ground.h sitting right next to it) — <...> never searches the including file's own directory in this driver (only "..." does). Fixed with ONE addition to master.lpc: implemented get_include_path() to prepend the compiling file's own directory to the search path. This alone dropped the lpcc sweep's failure count from 289 to 64 (of 9017 checked).

Known remaining issues (documented, not fixed)

How to run

cd libs/xyxy2
~/src/fluffos/build-debug/src/driver config.fluffos
# wait >30s after boot before connecting (see startup grace period above)
python3 ../../scripts/mudclient.py 127.0.0.1 40003 --timeout 10 --send "gb" --send "" --send "look" --send "quit"

Post-hoc fix: UTF8-native is_chinese/registration (AGENTS.md §15h)

Applied in a later batch pass across the whole project: is_chinese/is_chinese2 in the shared chinese.lpc simul_efun fragment used GBK byte-range checks that silently never match real Chinese text once strings are UTF-8 (this driver's str[i] returns a Unicode codepoint, not a GBK byte). This broke character registration specifically -- any real Chinese name was rejected. Fixed the range check to test the CJK Unicode block instead, and halved the GBK-byte-calibrated length bounds in check_legal_name to match. See AGENTS.md §15h for the full writeup; confirmed via a real interactive registration test (Chinese surname + given name reaching the next prompt).

Re-verification pass (driver rebuild + LPC formatter + WASM build)

WASM-enablement pass (loopback-allow / uptime bypass / throttle exemption / admin seeding)

Gates found and patched (AGENTS.md §1.3b/§1.3e/§1.5):

Retrofitted fail-open → fail-closed (2026-07-24): all four spots above were originally written so that ANY malformed/non-string ip bypassed its gate, not just genuine loopback — defensive against the old WASM driver bug where query_ip_number() returned garbage for every WASM connection. That driver bug is now fixed (WASM reports a clean "127.0.0.1" same as native), so there is no remaining justification for "can't parse it" ⇒ "must be loopback". Changed: - obj/login.lpc's logon(): no longer coerces an unparseable ip into "127.0.0.1". It now stores whatever query_ip_number() actually returns, falling back only to "" (untrusted/non-local) when it isn't even a string — the sscanf(...)!=4 well-formedness check that used to gate the coercion is gone entirely. - adm/daemons/band.lpc's create_char_banned()/is_strict_banned(): changed from !stringp(site) || site=="127.0.0.1" || strsrch(site,"127.")==0 || sscanf(site,"%*d.%*d.%*d.%*d")!=4 (any unparseable site returns "not banned") to stringp(site) && (site=="127.0.0.1" || strsrch(site,"127.")==0) for the bypass, with an added if (!stringp(site)) return 1; immediately after so a non-string site is treated as banned (deny) rather than falling into the regexp match on a non-string value. Since last_from/band.lpc's callers all key off the corrected obj/login.lpc value now, logind.lpc's own lb_ip != "127.0.0.1" comparisons needed no further change — they were already exact-match fail-closed; they just used to receive an already-laundered value.

Admin account: id fluffos, login password Mud@2026, super (admin) password Adm@2026 (the lib's two-password registration requires a mixed-case ≥7-char super password distinct from the login password), Chinese name 浮浮. Granted (admin) by adding fluffos (admin) to adm/etc/notices — this lib's WIZLIST macro (include/login.h:14) points at /adm/etc/notices, NOT the adjacent adm/etc/wizlist file. Verified post-restart: fluffos login + talent-selection (9/y), lands in 翠香楼, update /adm/daemons/logind → 成功.

Save files the orchestrator must add (untracked; data/user + data/login trees are not in git for this lib, and none of these are gitignored):

Retest: fresh normal registration (id qintest / 秦风) end-to-end — NOTE the flow has a first-entry talent-selection step after gender: send 9 (accept) then y (confirm); look/score/quit all correct in 翠香楼. debug.log clean (warnings only, zero runtime errors). qintest saves removed after the test; fluffos kept.

Re-retest after the fail-closed retrofit (2026-07-24): fresh boot, fresh normal registration (gb → 1 → new → id qretest → real Chinese name 秦风八 → super-password Test123!×2 → login password test1234×2 → email → m → talent 9/y) all the way through look/score/quit — landed in 翠香楼, rich score output correct, clean farewell message on quit. No 30-second startup-grace delay needed connecting immediately after boot (loopback bypass still working). fluffos/Mud@2026 admin login re-verified: look then update /adm/daemons/logind → 重新编译 /adm/daemons/logind.lpc ...成功!. Zero 执行时段错误 lines in debug.log for the whole session. Test char qretest (including its data/zhaohuan/q/qretest summon-state dir) removed afterward; fluffos kept.

深度功能测试 / Deep functional test (2026-07-24, round two, AGENTS.md §10.7)

First genuine hands-on *playthrough* pass on this lib (every prior pass above verified registration + look/score/quit + admin login, never a real multi-system playthrough). Native driver (build-debug), one continuous session per test phase, driven via scripts/mudclient.py. Read work/doc/help/newbie/newbie first — it lays out the exact intended early-game path (傲来武馆 safe sparring → raft to Changan → pick a sect → learn skills → 10级突破 dungeon) and was followed closely below.

Test character: id linfeng, Chinese name 林风, login password test1234, super password Test123! — kept as a representative playthrough character. State left behind: level 5, joined 百花谷 (Baihuagu) as 第四代外门弟子 under 百草仙, skills unarmed 1/dodge 6/parry 1 (dodge/parry trained organically by the real dog fight below, unarmed taught explicitly by 东方聪), inventory 炸鸡腿 (chicken leg, bought from the shop) + 9两20文 remaining coin, located in 翠香楼 (start room). Save files: work/data/user/l/linfeng.o, work/data/login/l/linfeng.o, work/data/zhaohuan/l/linfeng.

Bugs found and fixed

1. (RETRACTED — content/design judgment call, not a programming bug; reverted on user review) d/changan/aolaiws.lpc's close_passage() deletes the raft's exit entirely if a player misses the ~20s boarding window, leaving them in a genuine zero-exit room for the rest of the live session (recoverable only by disconnecting). Originally "fixed" by restoring the exit instead of deleting it — since reverted. The accompanying flavor message ("一个浪头打来,木筏向海上漂去。" — a wave hits, the raft drifts out to sea) plausibly describes an INTENTIONAL "you missed the boat and are now stranded" consequence for a time-gated mechanic, not an oversight — deleting an exit as a deliberate timing-punishment is a design choice, not a proven programming defect (no crash, no wrong efun usage, nothing the code itself contradicts). Left as originally shipped, documented here rather than silently re-fixed. See AGENTS.md §7.27 for the retraction writeup and the general lesson (this exact shape is now a documented cautionary case study, not a bug class to fix on sight).

2. adm/obj/master.lpc — mudlib-root-absolute #include </path> inside <...> never resolves, get_include_path() can't fix it.

``lpc // ADDED: mixed include_file(string compiled, string from, string path) { if (path && strlen(path) && path[0] == '/') return "/" + path; return path; } ``

3. work/log/nosave/ — another missing runtime directory (same class as this lib's pre-existing adm/etc/log/ fix above, AGENTS.md §7.11).

What was tested and confirmed working

Explicitly NOT verified live (say so, don't silently skip)

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

小雨西游家族基础版。状态已从过时的 limited 修正——这份档案自己的 NOTES.md 记载着早前某次会话就已经完成的完整转换+修复过程(GBK→UTF8 编码转换、.c→.lpc 改名、static→nosave、补上缺失的 adm/etc/log/ 目录,以及一种通用的 #include <local.h> 式同目录头文件模式,靠 master.lpc 的 get_include_path() 修复),并确认"启动干净,可以通过 telnet 游玩",带有一次真正验证过的注册流程。uptime()<30 的启动宽限门槛已经正确地对本地回环放行了(adm/daemons/logind.lpc 的 logon():"if (lb_ip != "127.0.0.1" && uptime() < 30)")——本轮已通过一次立即(没有等 30 秒)的 WASM 连线干净到达注册 id 提示、零编译错误来现场确认。这份 meta.json/README 只是从未更新以反映已经完成的工作——除了这次冒烟级别的复核之外不需要新的测试。

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

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

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

1. config.fluffos:maximum evaluation cost 从 800000 提升 到 5000000(本项目标准安全值,预防性调整)。 2. cmds/arch/update.lpc(AGENTS.md §7.106):缺少 environment(me) && 前置防护,补上(cmds/wiz/update.lpc 已是正 确写法)。 3. adm/simul_efun/file.lpc:log_file() 没有 assure_file() 目录预建保护,补上调用及前向声明;cat() 补上 read_file() || "" 空值防护。 4. obj/user.lpc::reconnect()(AGENTS.md §7.108,第十九条独立确 认的血统——与同宗 xiaoyuxiyou 共享同一份 obj/user.lpc 架构、同 一处 bug):adm/daemons/logind.lpc 有同款 exec(old_link, user); 踢掉重复登录写法,reconnect() 缺少 enable_commands()。按 §7.108 记录的写法预防性修复,现场用两个 真实连线复现"保持第一个连线不断开→第二个连线登录→答 y 踢掉旧连 线"验证:score 修复后立即正常显示完整角色档案。

master.lpc::log_error() 已经是正确的 "arning:" 大小写无关写法, 无需改动;本档案无 adm/daemons/closed.lpc,不受 §7.107 影响。

现场验证摘要

驱动干净启动,管理员 fluffos/Mud@2026 登录(GB/BIG5 选择→ "进入游戏(Enter)"菜单需送出字元 1,纯空白 Enter 不推进→id+密码) 确认 目前权限:(admin),update /adm/daemons/logind 成功验证真 实写入权限。踢掉重复登录重连路径现场验证通过(见上)。debug.log 全程干净(744 行,无真实错误)。

本轮修改的文件

§7.100 sweep (2026-08-19)

Fixed the corpus-wide inherit ROOM; ... replace_program(ROOM); redundant-replace bug (AGENTS.md §7.100). 196 live occurrences deleted: 195 via scripted sweep (fix_710_room.py), plus 1 hand-fixed roommaker-tool template (obj/roommaker.lpc, simple string-builder variant, same lineage as xyxyutf8/xiaoyuxiyou). 8 already-commented-out instances left untouched. No real .lpc source found under work/data/. Verified via build-debug driver boot: clean compile, zero new "cannot replace"/"cannot bind" debug.log lines; confirmed serving via raw-socket connect on port 40003.

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

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

深度功能测试第四轮 / Round-four §10.7 test (2026-08-20): death/respawn gap resolved

Primary target: the one explicitly-flagged gap from the round-two deep test above ("Explicitly NOT verified live: Death/respawn — not reached"). Prior pass found real (non-scripted) combat against a weak level-2 wild NPC (d/city/npc/dog.lpc, 黑狗, in 西芫街) converged to a near-permanent stalemate with bare-fisted unarmed 1 — consistent with the newbie guide's own advice to buy a weapon first, not a bug, but left death/respawn genuinely unexercised.

Resolved: real death and full automatic reincarnation confirmed working end-to-end, twice independently, zero debug.log errors either time. Rather than fight logistics (weapon shopping), used the session's standard sanctioned shortcut — admin call-based stat grants on the existing linfeng character (id linfeng, already representative from the round-two pass) to push a real kill dog fight to a genuine conclusion, per this session's precedent that kill has no NPC-target danger gate (confirmed by reading cmds/std/kill.lpc: the 40-level PK gate only applies userp(me) && userp(obj); for an NPC target do_kill() unconditionally calls obj->kill_ob(me), i.e. the NPC always fights back for real once killed).

Mechanism (traced from feature/damage.lpc and adm/daemons/combatd.lpc): ordinary combat reduces both kee (health, regenerates via heal_up()) and eff_kee (a separate, non-regenerating wound/damage-cap stat, only reduced when the attacker is_killing(), i.e. via a real kill, and floored at 1 point of wound per landing hit). std/char.lpc::heart_beat() checks eff_kee < 0 FIRST on every tick → die() (unconditional, no unconsciousness stage); only if that's still non-negative does a separate kee < 0 check fire unconcious() (a temporary faint + auto-revive, t = random(100-con)+30 seconds later, with kee regenerating back up via heal_up() in the meantime — this is what the round-two pass's ~10-minute stalemate attempt was actually seeing, misread at the time as "no death path"). To force the real branch: admin call linfeng->set("eff_kee", <small positive number>) right before a real kill dog, so the next landed wounding hit (guaranteed floor of 1 per receive_wound()) pushes eff_kee negative and die() fires unconditionally on the next tick, bypassing the recoverable-unconsciousness branch entirely.

Verified twice, independently: 1. First pass (accidental/unattended): admin lowered eff_kee, a real kill dog fight produced one landed hit and the expected unconcious() faint message ("你的眼前一黑,接着什么也不知道了"); watching stopped there per the original plan, but real time continued to elapse in the background (heart_beat doesn't depend on an open connection) — a later reconnect found the character already fully cycled through: is_ghost() = 0, standing in d/ourhome/kedian.lpc (REVIVE_ROOM, 荒郊小店), inventory emptied (lose_inventory(), expected/documented design), money and base stats intact (matches this lib's own login banner promise: "本泥潭 内,人物的金钱、潜能不会因死亡而有任何损失的"). 2. Second pass (directly observed): admin powerup(1,1)-healed the character to full, teleported it directly to /d/aolai/west1 via call linfeng->move(...), set eff_kee critically low again, issued a fresh real kill dog, and reconnected partway through to catch the fight live: same "结果造成轻微的伤势" → "半昏迷状态" → "你的眼前一黑" sequence captured directly on-screen this time. Left the world running unattended for several more minutes (heart_beat keeps ticking headless) and reconnected again: character now standing in 荒郊小店, room description confirms this is the dedicated death/revival waystation (生死之间留言板 — "Board Between Life and Death" — is the room's actual board name), score shows 气血 status "充沛" (fully recovered, not the "伤残" seen mid-recovery in pass 1), eff_kee back to exactly query_maxkee() (1072, both reset by reincarnate()+powerup() inside the judge NPC's dialogue chain), is_ghost() = 0, and — the clinching evidence that the REAL die() path executed rather than merely another faint — remaining lifespan ticked down by exactly 1 (79/80 → 78/80), matching die()'s own life/life_time - 1 decrement, a field nothing else in this code path touches. debug.log stayed at zero 执行时段错误/Fatal/ Too deep recursion lines across the ENTIRE multi-stage test (boot through final quit), confirming no crash anywhere in the death → DEATH_ROOM(阴阳界) → judge NPC (d/death/npc/pang.lpc, 崔判官/崔珏) dialogue → reincarnate() → REVIVE_ROOM chain. Also directly re-confirmed clean netdead/reconnect handling through this: an abrupt disconnect mid-unconscious-state, and again mid-post-death, both resumed correctly with no stranding, no duplicate object, no error. 3. Proactively checked the combatd.lpc bounce-division-by-zero bug pattern flagged this session on sjpl2/sjplii/sjplgfjxb/fy2mg (while (... / bounce) with bounce /= 2 and no bounce > 0 guard): grep -n bounce adm/daemons/combatd.lpc — zero matches, this lib's combatd.lpc is a different (unrelated) lineage, not affected.

No code changes were needed — this is a genuinely working, unmodified system; the round-two "not reached" note was a coverage gap in testing budget, not a latent bug. linfeng's save state now reflects a completed death/reincarnation (empty inventory, position in 荒郊小店, 78/80 remaining lifespan) — kept as-is per the "representative playthrough character" precedent rather than reset, since this is now arguably a MORE informative saved state (proves the full lifecycle works) than the pre-death one.

Standard checklist pass (fast confirm, all already fixed/clean)

Secondary target (not attempted, budget spent on the primary gap)

20级突破 puzzle dungeon and the 10-25级 loot dungeon: still not attempted this round either — the death/respawn investigation (two full cycles, real-time-gated) consumed this pass's full budget. Left for a future round; see the round-two notes above for the newbie-guide entry points.

AGENTS.md §7.156 regression fix (2026-08-27, sibling-lineage sweep)

Found live on sibling lib xyxyutf8's round-two deep test, then confirmed by a corpus-wide grep sweep for the pattern across every lib that received the original §7.30 accessor fix: cmds/std/learn.lpc's if (!skills || !mapp(skills)) me->set_skill(skill, 1); else skills[skill] = my_skill; re-derives "never initialized" from query_skills()'s return shape, but feature/skill.lpc's own §7.30 fix (return mapp(skills) ? skills : ([]);) means that check is now always false for a brand-new character -- the else branch runs and mutates a fresh, disconnected empty mapping instead of the character's real internal state. The success message and potential-point deduction still fire, but the skill itself is silently discarded: every player's first-ever learned skill was affected. set_skill() in this lib already handles both the never-initialized and already-populated cases correctly (checks !mapp(skills) against the real instance variable), so the fix is to always call it with the final value instead of re-deriving the branch caller-side. Verified via lpcc --batch (single file compile, PASS) -- not re-tested with a full live playthrough this pass, since the fix is a mechanical port of the exact fix already verified live on xyxyutf8. See AGENTS.md §7.156.

Description-quality pass correction (2026-09-01, batch 26)

The pre-existing meta.json english_description claimed new characters "start out in worldly scenes like Chang'an's Yingxiong Restaurant" — this was a factual error. A grep for 英豪酒楼 across work/ returns zero hits (in this lib or in sibling xiaoyuxiyou), and the actual live-tested starting room, confirmed repeatedly in this file's own round-two/three/four deep-test sections above, is 翠香楼 (Cuixiang Tower) in 傲来国 (the Aolai Kingdom) — Chang'an only enters the map later, as the destination of the raft crossing on the way to the 百花谷 sect. Rewrote the description to name the correct starting location and dropped the invented tavern name.

AGENTS.md §7.19 sweep (2026-09-01): false positive, not fixed

Flagged by the corpus-wide scoping scan as sharing the mhxy/wuhanzhan enable_player()-reentrancy-from-init() shape, but on closer inspection this lib already carries its own, differently-shaped guard (byte-identical to sibling xyxyutf8's copy of feature/command.lpc): nosave int enabled = 0; at file scope, and enable_player() only calls the raw enable_commands() efun (plus add_action("command_hook", ...)) inside if (!enabled) { enabled = 1; ... }. Since enabled is set to 1 *before* enable_commands() runs, any reentrant call into enable_player() triggered as a side effect of that same enable_commands() call sees enabled == 1 and skips re-invoking the efun -- the recursion terminates at depth 2 instead of running away into "Too deep recursion." (Same pre-existing-guard pattern Batch C found on sibling lib xiaoyuxiyou.) No in_enable_player_now mechanical fix applied -- would be redundant with the existing enabled guard.

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

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

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

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

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

scripts/lpc_warnings.py xyxy2 --fix 加 scripts/lpc_fix_no_effect.py --apply(d/dntg/doushuai/bgl1.lpc 的 for (n == 0; ...) 改成 =),共改动 871 个 .lpc 和若干 .h。HEAD 与工作树分别加载(新进程):862 -> 862 通过,无回退;改过的头文件的 596 个包含者 590 -> 591 通过(quest/tianguan/npc/learn2 新能加载)。

启动时警告 78 -> 0;新进程登录(编码选择、进入游戏菜单、英文名提示)正常。

深度功能测试(§10.7,2026-10-08)— .lpc 后缀的定宽切片

.c 改名 .lpc 时只改了字符串没改切片宽度:f[<2..] == ".lpc" 拿两个字符比四个字符,永远不成立(!= 永远成立),按后缀筛文件、去后缀的代码因此从不运行或截成 x.l(KB 06 §7.238)。scripts/lpc_lpc_suffix_slice.py --apply 改了 1 处比较、1 处去后缀(如 cmds/adm/mem2.lpc);改动的文件 HEAD 与工作树分别加载(新进程),无回退。

编译警告收尾(2026-10-13)

scripts/lpc_twin_port.py adopt xiaoyuxiyou xyxy2 搬来 xiaoyuxiyou 同日整理(0347f6d042c)里与本库逐 token 相同的文件,scripts/toolkit_fix.sh 去掉多余继承,能编译的文件警告清零。改动的 30 个对象在 HEAD 与工作树各载入一次:HEAD PASS 28,tree PASS 29,regress 0(多出的同样是随机挑武功的 quest/tianguan/npc/other.lpc)。d/kaifeng/ground*.lpc 用 #include <ground.h>,守卫宏照样定义在包含之前;d/maze/qingling-2/enter.lpc 只有注释掉的代码用的 str 删去。

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

receive_heal()/receive_curing() 也只接受本库的种类。本库人物只有 kee/sen(连 gin 也没有):药物的 receive_heal("gin", 60)、NPC 的 receive_curing("gin", ...) 和来自侠客行体系的 qi/jing 调用都报 伤害种类错误。1 个文件按 gin→sen、qi→kee、jing→sen、neili→force 改名(scripts/lpc_port_es_props.py --any-file)。

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

1 个文件、1 处在 create() 里 carry_object("<本库没有的文件>")->wear()(或 wield()、set_amount()):carry_object() 得 0,接着的调用报 Bad argument 1 to EFUN call_other(),NPC 根本载入不了,该有它的房间里就少了这个人。多是从别的系统搬来的 NPC 用了原系统的物品路径(最常见:/d/sky/obj/zhanyaojian)。每处改为 { object carried_ob = carry_object(...); if (carried_ob) carried_ob->wear(); }(scripts/lpc_guard_carry_object.py):NPC 照常出现,只是不带这件东西;文件补回来(或是虚拟对象)照样会带上。载入检查:改动的文件改前能载入 0 个,改后 0 个(0 个原来载入不了),没有退步;其余 1 个另有原因(多为 set_skill() 了本库没有的武功)。

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 载入不了,刷出它的房间也少一个人。本库有 31 个对象设了本库没有文件的武功(29 个名字,最多的是 mindsword、sevensteps、taoism)。三处都改成 return:这一门武功不给、不映射,对象照常载入,只是少了它(缺的武功本身仍是内容缺口)。抽样载入这些对象:30 个里 29 个通过,其余 1 个停在别的错误上(quest/rzr/shushan1000:*Bad argument 1 to EFUN call_other())。(scripts/lpc_guard_set_skill.py)

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

set_skill("kunlun-shnfa", …)、map_skill("dodge", "shaolin-shnfa") 这样的调用把武功名拼错了:本库没有这个武功文件,有的是拼对的那个。以前这种 NPC 在 create() 里报 No such skill 载入不了;武功缺失时跳过之后它们能载入,可是少了那门武功(set_skill 被跳过,map_skill 映射不到,门派弟子用普通轻功/拳脚)。按核对过的对照表改正,共 17 处、13 个文件:hellfire_whip→hellfire-whip(9 处)、dagonforce→dragonforce(4 处)、dragon-step→dragonstep(2 处)、yange_blade→yange-blade(1 处)、lahua-shou→lanhua-shou(1 处)。(scripts/lpc_fix_skill_names.py)

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

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

改后房间照常载入(与 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。按 §7.19 加了标志变量(scripts/lpc_fix_enable_player_guard.py)。改后同样的测试(载入掌门房间,再克隆一个活物走进去)不再出错,没有退步。

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

adm/daemons/rankd.lpc 的 query_respect()、query_rude()、query_self()、query_self_rude() 里 6 个函数开头补上 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)

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

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/liandan/baihuagu.h(1 处)。

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

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

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

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

if (x = 常量):条件里写成赋值的比较(2026-10-20,KB 06 §7.290)

if (arg = "button" || arg = "按钮")、if (!arg || arg = "") return 0;、else if (check = 0 && tempB != ""):把 == 写成了 =,条件的值就是那个常量,分支对所有非零数和任何字符串(连 "" 都算)永远成立、对 0 永远不成立,变量还被覆盖;驱动对此没有任何警告。每一处 = 改成 ==(scripts/lpc_fix_cond_assign.py,共 2 处)。改动:/daemon/condition/xiangliu_hurt.lpc(2 处)。

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

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

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

登录计数文件 UserNumber 缺失(2026-10-20,KB 06 §7.298)

logind.lpc 的 do_counter() 读 /adm/daemons/UserNumber(访客计数,运行中的 mud 才会写);.gitignore 把它排除在仓库之外,所以新检出的树里没有,read_file() 回 0,sscanf(0, ...) 报错。这份副本登录时不调用它,但同样会在调用时出错。加了 if (stringp(file)) 的守卫(与 dtxywzxzb、rzrmud、xiyouji2006、zitengzhan 早先的做法相同)。

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)。改动:/cmds/adm/cfg.lpc(1 处)、/include/getconfig.h(1 处)。

NPC 的 chat() 在 chat_msg 为空数组时下标越界(2026-10-21,KB 06 §7.334)

NPC 基类的 chat() 是 if (arrayp(msg = query(...))) { if (random(100) < chance) { rnd = random(sizeof(msg)); if (stringp(msg[rnd])) ...,不检查列表是否为空。本库现有的 NPC 文件里没有字面写成空 chat_msg 的(扫描只认 set("chat_msg", ({ })));守卫挡的是运行时才为空的列表和以后新增的 NPC。在 random(100) < chance 前面加 sizeof(msg) &&(scripts/lpc_fix_chat_empty.py;if (random(100) > chance) return 0; 的写法是 !sizeof(msg) ||)。改动:/std/char/npc.lpc(共 1 个文件)。

存档里的 .c 文件名改成 .lpc(2026-10-21,KB 03 §4.2 第 9 项)

存档里写着 "/d/city/npc/wei.c" 这样的文件名;extract 时源文件已经全部改成 .lpc,而驱动对带扩展名的路径只认字面,new() / load_object() / move() 都找不到它,调用方多半把失败当成「没有这个东西」悄悄跳过。本库 1 个存档共 1 处按 scripts/lpc_fix_save_dotc.py 改成 .lpc(只改 .lpc 存在而 .c 不存在的字符串;玩家存档、备份、留言板、巫师目录和文件索引缓存不动)。改动:/d/dntg/hgs/inner_shuiliandong.o(1 处)(共 1 个存档)。

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

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

update 不带参数:valid_read(0) 先于 cwf 缺省(2026-10-21,KB 06 §7.342)

管理员扫描里 update 不带参数报 Bad argument 1 to sscanf() Expected: string Got: 0.(/adm/daemons/securityd.lpc 的 valid_read(),第一句 sscanf(file, "/c/%*s")):main(me, file) 先 SECURITY_D->valid_read(file, me, "read"),之后才 if (!file) file = me->query("cwf")。把“缺省取 cwf、仍为空就拒绝”这两句移到权限检查前面(是移动,不是复制)。改动:/cmds/arch/update.lpc、/cmds/wiz/update.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.,同一个动词的其他处理函数不再尝试(不是最新的一条就悄悄跳过)。删除了 10 条注册(6 个文件,scripts/lpc_fix_dead_add_action.py),动词留给别的处理函数:/d/changan/pinqiting.lpc(do_pass、do_resign)、/d/city/npc/duguoyin.lpc(do_vendor_list)、/d/city/npc/vikee.lpc(do_list)、/d/eastway/npc/petboss.lpc(do_cost、do_list、do_upgrade)、/d/qujing/village/npc/oldwoman.lpc(do_yes)、/d/qujing/wudidong/cave2.lpc(do_push)。最多的函数名:do_list 2 处、do_push 2 处、do_pass 1 处、do_resign 1 处、do_vendor_list 1 处。

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

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

(: 函数 :) 指针指向对象自己没有定义的函数(2026-10-22,KB 06 §7.355)

item_desc / inquiry / chat_msg_combat 里的 (: 函数名 :) 指向本对象(含包含文件、继承的父类)没有函数体的函数:编译不报错,用到时驱动报 *Undefined lfun pointer called: 函数名(look 某物、ask NPC about 话题 直接出错,战斗 / 闲聊里的指针在 NPC 的 chat() 里出错,这一拍心跳的后半段被跳过)。scripts/lpc_scan_callout_targets.py --kinds=lfun。 还剩 1 个函数没有补(chat_msg_combat 1):原型还在函数体丢了、或者根本没写过,没有可以直接补回的捐赠(别的库同一路径的文件里没有这个函数,或者它还要用本库没有的辅助函数、签名不同),不编造:/d/dntg/lijing/lijing.lpc:do_jifabao。

(: 函数名 :) 指针指向本库没有的函数:只含这个指针的行加了注释(2026-10-22,KB 06 §7.355 补充)

inquiry / item_desc / chat_msg* 里的 (: 函数名 :) 指向本对象(含包含文件、继承的父类)没有函数体的函数:用到时(ask、look、NPC 闲聊)驱动抛 *Undefined lfun pointer called: 函数名,这一拍心跳的后半段被跳过。这些函数没有可以补回的来源(别的库同一路径的文件里没有,或者它还要用本库没有的东西),所以 1 个文件里 1 行只含这个指针的行((: do_jifabao :),)加了注释,原文保留并写明原因,这一项当作没有这个话题 / 物品 / 闲聊条目(scripts/lpc_fix_dangling_lfun.py;#include 的文件在库里缺失的对象、指针不在整行上的写法没动)。 前提(function_exists())和加载检查(HEAD 与工作区对比,本库改动的 .lpc 文件)的结果见 KB 06 §7.355:没有一个回归。

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

原档按字节算字符串区间(一个汉字 2 字节):name[2..3] 是名字的第二个字,name[0..1] == "澄" 问名字是不是以「澄」开头。转成 UTF-8 之后,这个驱动的区间和 strlen() 都按字符算(strlen("澄观") 是 2,"澄观"[0..1] 是两个字),老算术原样留着、意思全变:NPC 的称呼和提示里取到两个字而不是一个字。

本库 10 处(10 个文件):query("name")[..] 10 处。例:->query("name")[0..1] → ->query("name")[0..0](/d/dntg/hgs/jiaojunchang.lpc:217);->name(1)[0..1] → ->name(1)[0..0](/quest/tianguan/npc/baihua2.lpc:245)。scripts/lpc_fix_gbk_slice.py 把下标按字符重算(社区的 UTF-8 版 xkx100utf8 里就是同样的写法,作对照);没有改的:截断(name = name[0..7],现在最多 8 个字,只是放宽)、ASCII 的区间(fname[0..3] == "room"、ctime(time())[4..19])和上下文看不出是汉字的区间。证明(scripts/lpcc_eval.py,bixiecanyang;其余各库是同一份文本):让澄字辈掌门 attempt_apprentice() 一个名叫「张三」的访客,HEAD 的法名是 慧,改后是 慧三;抽样 28 个库的 HEAD / 工作树加载对比 0 退步。工具不幂等([0..3] 折半得 [0..1],又是对齐区间),改过的文件记在 scripts/gbk_slice_converted.txt,不要重跑。

长度检查按字节写,旁边的提示按汉字写:2 处(2026-10-22,KB 06 §7.362)

老档的 strlen() 数字节(一个汉字 2 字节),转成 UTF-8 后它数字符:提示写「必须是 2 到 6 个中文字」的检查还是 strlen(name) < 4 || strlen(name) > 12,于是两三个字的房名、帮会名、群名、聊天室名、称号被提示自己说允许的那句话拒绝,上限却是提示的两倍;留言板的标题检查 i < 4 || i > 24 || i % 2 还会拒绝所有奇数个字的标题(post 你好吗)。本库 2 处(1 个文件):if ((strlen(name) < 2) || (strlen(name) > 12)) {(/d/city/npc/zhangsunwuji.lpc:167)。scripts/lpc_fix_strlen_gate.py 以提示为准:条件里每个 strlen 门槛都恰是提示所说数字的两倍才折半,存长度的变量(i = strlen(arg);)的门槛和 || i % 2 奇偶项、其后循环的 i % 2 == 0 && 一并处理;提示里有英文 / 字母 / 字节的不动。证明(scripts/lpcc_eval.py,bxsj 的留言板,求值对象继承 NPC 并重写 edit() 记录调用,command("post 标题")):HEAD 拒绝「你好」和「你好吗」、放行 23 个字的标题;改后接受前两个、拒绝第三个;shenmo 的 named.lpc invalid_new_name("张三"):HEAD 回 名字只能是2-4个中文字。,改后回 0。抽样 24 + 15 个库的 HEAD / 工作树加载对比 0 退步。

按字节写的汉字循环、茶馆猜诗和同盟频道标题(2026-10-23,KB 06 §7.363)

老档按字节做「一个汉字」:while (i--) if (i % 2 == 0 && !is_chinese(name[i..<0])) 只检查偶数下标,奇数位上的拉丁字母(张a)会过;茶馆猜诗 mixup() 用 strlen(str)/2 再 j=j+j、str[k..k+1] 交换两字节;泥潭系 channeld 的 switch (strlen(fname)) case 4/6/8/10 和 strlen(family)==4/6 按字节长度给同盟 / 门派名加空格。本驱动的 strlen() 和区间都按字符算。scripts/lpc_fix_byte_char.py:去掉奇偶项、把区间改成 name[i..i],按字符重写 mixup() 并把 strlen(first)>=14 折成 7,频道标题的 case / 门派长度改成字符数(对照 aoxiangtianji)。本库 汉字循环 / is_chinese 区间 6 个文件;茶馆猜诗 mixup 1 个文件。证明(scripts/lpcc_eval.py):sjplii 的 check_legal_name 在 HEAD 接受「张a」、改后拒绝,两边都接受「张三」;xkx100 的 clubpoem->mixup("离离原上草") 得到「离离原草上」(真交换汉字);nitan_san 两字同盟名得到 【 兄 弟 】。关键对象加载通过。

中文名 / 验证码仍按 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。

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

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

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

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

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

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

深度功能测试(2026-10-27,§6.25 tell_object 缺 me(自动放弃/愿否))

一参 tell_object("…") 在已有 me 时改为 tell_object(me, "…")(city.lpc)。证明:抽样 city / xiaolongnv 加载。

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

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

深度功能测试(2026-10-27,§6.25 one-arg message_vision)

message_vision("…") 补第二参(me / TP / this_player())。

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

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