info.html · 介绍 · play.html · 游玩 · llms.txt · 下载与本地运行 · ZIP · GitHub
不要被"山海战神"这个名字骗了——这并不是传统武侠/仙侠泥巴,而是史巴克(Spock)开发的英文科幻引擎"Final Frontier v0.6e"(`simple`/ES II 引擎系列)二次改造而成的中文版硬科幻"战斗模拟"游戏:人物属性叫力量/敏捷/智力/注意/体质/技术,护甲分传统、动能、光学、粒子、爆破五种类型,攻击方式带着浓厚的机甲/激光对抗色彩,是这批归档里题材最"硬科幻"的一个。整体规模不大,更像是一个演示引擎战斗系统的小型试验场,而非内容丰富的大型世界。
English
A Chinese-language adaptation of Spock's English-language science-fiction engine "Final Frontier v0.6e," part of the simple/ES II engine family. Despite the wuxia-sounding name, it's not a martial-arts MUD but a hard-sci-fi combat simulator, with stats like Strength, Agility, and Technique and mecha- and laser-flavored battles.
README
在线试玩
https://mudlibs.fluffos.info/shzs/
管理员账号 / Admin account
- ID:
fluffos - 密码 / Password:
Mud@2026 - 中文名 / Display name: 浮浮
- 权限 / Level:
(admin)(最高级别),通过/adm/etc/wizlist授予。 - 本库没有基于连线地址的封禁/限流机制,WASM 化改造中仅需管理员账号 播种即可。
警告:对外公开架设前请务必修改此密码。
本地运行
cd libs/shzs
~/src/fluffos/build-debug/src/driver config.fluffos游戏端口:40001。
NOTES · 移植与修复记录
山海战神.rar → shzs
- Archive:
archives/山海战神.rar(1.4MB, smallsimple/ES-II-derived MudOS 0.9.20 lib — "Final Frontier" themed base, reskinned). - Mudlib root in archive:
simple/(extracted directly at archive top level, no extra nesting). - Port: 40001.
Status: DONE — boots clean, playable over telnet
Login banner, Chinese prompts, and character-creation flow all render
correctly. This lib was the pilot used to build scripts/convert_lib.sh
and the fix catalog in AGENTS.md — see that file's "Common
driver-compatibility issues" catalog (§1-§14) for the general write-up of
every issue found here. Lib-specific specifics only, below.
What was fixed
1. Encoding: all .c/.h files GB18030→UTF-8 (774 converted, 124 already
ASCII/UTF-8, 0 hard failures). Also converted data/*.o save files
(dict/emote/daemon/ballot_box/stars — these are plain-text
save_object() format, not binary) — data/emoted.o needed the lossy
-c fallback (one stray invalid byte at position 25324, pre-existing
data corruption in the original archive, unrelated to us). Also
adm/etc/welcome (login banner) and config.fluffos itself (see
AGENTS.md §5 for the double-corruption trap hit here on first attempt —
fixed by re-copying fresh from raw/ and converting before any edits).
2. .c → .lpc rename: 855 files. Fixed 117 literal ".c" string
references across .lpc files, plus 36 in include/globals.h (the
F_DBASE macro — AGENTS.md §2, this is the one that cost the most time
to find since it surfaced as a runtime "Inherited file does not exist"
rather than a compile error). One orphaned non-LPC file caught by the
blind rename (d/shenmin/shenminmap.c, ASCII-art map, unreferenced
anywhere) — renamed to .txt instead (AGENTS.md §12).
3. static → nosave: 89 occurrences across the lib (AGENTS.md §3).
4. master.lpc's valid_read()/valid_write() had the lazy
load_object(SECURITY_D) recursion bug (AGENTS.md §4) — added the
re-entrancy-guard + catch() fix.
5. master.lpc's valid_override() was the old 2-arg signature, which
wrongly rejects efun:: overrides written in #included simul_efun
fragments (AGENTS.md §14) — added the 3rd main_file parameter. (Never
actually manifested in a real boot, only in the lpcc sweep testing a
fragment file as a standalone object — fixed anyway since it's free and
more correct.)
6. master.lpc does NOT have get_root_uid() (driver printed a non-fatal
warning and continued — did not need the AGENTS.md §7 stub fix here;
this lib's exit(-1) path apparently doesn't fire the way lib #2's did.
Left as-is since the lib boots and plays fine regardless).
7. Config: removed 5 obsolete keys (address server ip/port, binary
directory, swap file, reserved size), set port number : 40001,
mudlib directory to the absolute work/ path.
8. Full lpcc_check.sh sweep run (854 files after the shenminmap.txt
rename; 832 pass / 22 fail). Fixed 6 pre-existing typo
bugs found this way (all unrelated to our conversion — verified against
raw archive bytes):
- d/zuichen/{cdkedian3,cdkedian4,cdyaopu,chengzhong}.lpc: fullwidth
comma , used as an argument separator (AGENTS.md §9).
- d/shiwang/qianqingon.lpc: fullwidth period in #include <ansi。h>
(AGENTS.md §9).
- std/room/shop.lpc, cmds/std/put.lpc: missing closing " before
string concatenation (AGENTS.md §10).
- adm/daemons/rankd.lpc: 8× switch(x) { default: ... } with no real
case label (modern grammar requires at least one) — removed the
pointless switch wrapper, kept the body (indentation not perfectly
preserved, cosmetic only).
- cmds/wiz/invis.lpc: declared void main(...) but returned 1/0
(command-dispatch status codes) — changed to int main(...).
- obj/weapon/axe.lpc: copy-paste bug, inherit AXE/init_axe(...)
but /std/weapon/axe.lpc was never implemented in this lib and the
file's own header comment/id/name all say "dagger" — redirected to
inherit DAGGER/init_dagger(...) (AGENTS.md §11).
- obj/cloth.lpc: same pattern, inherit CLOTH with no
/std/armor/cloth.lpc to back it — redirected to inherit U_ARMOR
(matches its setup() call and "basic starting equipment" role).
Known remaining issues (not fixed — documented, low priority)
/adm/daemons/network/{ms,userid,pingtcp,mail_serv,netmail,pingd,inetd}.lpc— a cluster of optional network-service daemons (internal mail server, ping, telnet redirect, inetd) failing to compile due to missing headers (config.h,mailer.h,daemons.h,uid.h,priv.h,post.h— not present anywhere ininclude/) and a few undefined functions/variables cascading from that. None of these are on the preload list or required for normal play (login/rooms/combat/items all work); left broken.adm/simul_efun/object.lpc: harmless lpcc-sweep-only false positive (AGENTS.md §6b/§14) — real boot never hits it.- A number of
call_other()/Bad argument 1 to EFUN call_other()sweep failures are the same false-positive category as lib #2 (AGENTS.md §6b) — not individually triaged since the pattern is now understood; spot-checked 2, both were "target genuinely not compiled yet in this isolated single-file run", not real bugs.
How to run
cd libs/shzs
~/src/fluffos/build-debug/src/driver config.fluffos
# separately:
python3 ../../scripts/mudclient.py 127.0.0.1 40001 --timeout 10 --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 + formatter + WASM (2026-07-23)
- LPC formatter: ran
format-corpus.mjsacross all 854.lpcfiles underwork/— all reformatted cleanly except 2 refused on the token-mismatch safety gate (adm/obj/simul_efun.lpc,adm/simul_efun/system.lpc), expected/fine per the formatter's own self-check contract, not investigated further. - Native retest against the freshly-rebuilt driver: booted clean, zero fatal errors. Ran a full interactive registration with a real English id (
qflibtest, this lib's login uses an English id + a separate Chinese display name秦风) through name/password/email/ attribute-allocation/gender, reached the actual game world (梦旅馆大厅), and confirmedlook/score/quitall produced correct, real output (score sheet shows the chosen 10/10/10/10/10/10 attribute split; quit exits cleanly). No regressions from the reformat or the driver rebuild. - WASM build test (
scripts/wasm_client.js): fully playable. Boots cleanly under WASM, and the complete registration flow (id → confirm → Chinese name → password ×2 → email → attributes → gender) works end-to-end exactly like native, reaching the same starting room withlookproducing correct output andquitexiting cleanly. This lib does not gate login onquery_ip_number()or on any other WASM-restricted efun (its tworesolve()call sites are inftpd.lpc/dns_master.lpc, both optional network daemons never invoked during normal login) — no WASM-specific limitation applies here. Status: fully playable under WASM.
WASM-enablement pass (2026-07-24): admin seeding only (no gates found)
Checked for all four standard gate classes (AGENTS.md §1.3b/e): no
band.lpc/BAN_D-style ban daemon, no site-restriction daemon, no
uptime() check anywhere in the login path, and no per-IP anti-flood/
multi-login throttle (logind.lpc/logind2.lpc only use
query_ip_number/query_ip_name cosmetically, in log lines and "who
connected from where" messages — confirmed by grep, not just absence of
symptoms). So items 1-3 of the standard pass (loopback-allow,
uptime-bypass, throttle-exemption) are not applicable to this lib —
nothing to patch.
Admin account: registered fluffos / Mud@2026 through the real
registration flow (id fluffos accepted directly — no length/reserved-
word conflict), Chinese name 浮浮, gender m, attributes 10/10/10/10/10/10.
Granted (admin) via /adm/etc/wizlist (this file already had a
fluffos (admin) line staged from an earlier interrupted pass; verified
/adm/daemons/securityd.lpc reads this file for wizard-level decisions).
Verified in ONE continuous session: login as fluffos, look, then
update /adm/daemons/securityd.lpc recompiled successfully (ACL grants
write/compile access), then clean quit. Re-verified a fresh normal
registration end-to-end afterwards (id qinfeng, name 秦风, same
attribute split) reaching 梦旅馆大厅 with working look/score/quit; its
test save (data/login/q/qinfeng.o, data/user/q/qinfeng.o) was removed
afterwards. debug.log clean (compiler warnings only, no errors) across
both sessions. Save files for the orchestrator to force-add:
data/login/f/fluffos.o, data/user/f/fluffos.o (untracked, not
gitignored).
Note: an earlier same-batch agent's driver process for this lib (PID 4045698, started 00:37, before this session began) was found still bound to port 40001 with no admin work done yet; it was killed (exact PID) and the driver relaunched fresh before doing the registration above.
深度功能测试 / Deep functional test (2026-07-24, round two)
First genuine hands-on *playthrough* pass on this lib (all prior passes
verified registration + look/score/quit/update, never a real
walk through content). Native driver (build-debug), one continuous
session per check, scripts/mudclient.py. Test character: id
linfeng, Chinese name 林风, password Abc12345, attributes 15 力量/
10 敏捷/10 智力/6 注意/17 体质/2 技术 (the game's own example split from
help's attribute-allocation screen) — kept as a representative
playthrough character, currently standing on a d/lwe/jie* street
(state below). Save files: work/data/user/l/linfeng.o,
work/data/login/l/linfeng.o.
This lib's help newbie/help intro don't exist as such; its actual
newbie doc is help (topics: story, cmds) — read first, per the
checklist, and immediately found broken (see bug 1).
Bug 1 — help/help cmds/help story and the day/night broadcast
text were still raw GBK bytes, never converted (AGENTS.md §4.1 class, just missed on this lib's original pass)
- Symptom: the *very first thing* a new player is told to try (
help, andhelp motd— quoted verbatim in the MOTD bulletin as "本公告可以用 help motd 再次查看") rendered as mojibake, and every outdoor day/night phase transition (adm/daemons/natured.lpc, preloaded, cycles on acall_outthe whole time the driver is up) broadcast mojibake to every player standing outdoors. - Root cause:
doc/help/topics,doc/help/cmds,doc/help/story,adm/etc/nature/day_phase,adm/etc/motdwere never put through the GBK→UTF-8 conversion in any prior pass on this lib — confirmed byfile/byte-decode check (still literal GBK bytes, not even mis-decoded, genuinely untouched) and by diffing againstraw/simple/. This is exactly the AGENTS.md §4.1 "convert EVERY text file, not just source" rule; this lib's original conversion pass (documented above as "774 converted, 124 already ASCII/UTF-8, 0 hard failures") simply never walkeddoc/help/oradm/etc/nature/. - Fix:
iconv -f GB18030 -t UTF-8on all five files, byte-for-byte (verified: same line count, same non-Chinese content, only the Chinese text changed from garbage to real sentences — e.g.day_phase's dawn/noon/dusk broadcast lines, previously unreadable, now read correctly, e.g. "已经是中午了,太阳从你的上方照耀着大地。").adm/etc/motdlikewise (its "help motd" bulletin, previously garbage, now renders and was independently re-confirmed live at every login in this session). - Verified live:
help(topics listing),help story(the intro backstory, "山海战神之简单武力的故事背景..."),help cmds(the full command chart with Chinese glosses) and the MOTD bulletin at login all render correct Chinese now; re-tested after the driver restart that picked up the fix.
Bug 2 — per-command 指令格式: (syntax) help lines mis-decoded as
GBK when the source byte run was actually BIG5 (same §4.1 class, a narrower/more surgical instance)
- Found while checking
help study,help load, etc. (the individual command help topicshelp.lpcfalls through to in its default search path): the "指令格式:" prefix decoded correctly (it's genuinely GBK, shared boilerplate the Chinese-reskin author typed) but the bracketed argument placeholder immediately after it was garbage incmds/std/{pilot,steal,load,study,wear,vl,sl}.lpcandcmds/wiz/edstar.lpc— a single source line mixing two different encodings, GBK boilerplate concatenated with the ORIGINAL Final-Frontier-base BIG5 English-to-Chinese translation of the argument name (this codebase's ES2/FF heritage — seestudy.lpc's own header comment "Original ES II command" / "Last modified by Spock @ FF" — was shipped in Traditional/BIG5, and the reskin author added Simplified/GBK text around it without re-encoding the file). Confirmed by decoding the exact raw byte ranges: the "指令格式:" bytes are valid GBK, the following<...>bytes are valid BIG5 and garbage under GBK (e.g.study.lpc's raw bytes for<物品名稱>decode to<珇嘿>under GB18030 — silently wrong, not an error, so the original conversion's lossy-conversion log never flagged it). - Fix: byte-precise per-line re-decode against
raw/simple/(GBK prefix up to and including the fullwidth ":", BIG5 for the rest), applied as a single-line patch preserving the file's original CRLF line endings and every other line untouched. Examples:study.lpc"指令格式: study <珇嘿>" → "指令格式: study <物品名稱>";edstar.lpc"...edstar -a <琍╰畒夹 x,y,z> <琍╰郎>" → "...edstar -a <星系座標 x,y,z> <星系檔案>". - Caught and reverted a self-inflicted mistake while building this fix, worth recording: my first attempt regenerated whole files fresh from
raw/bytes (auto-picking GBK vs. BIG5 per line by scanning for stray bopomofo/hiragana/katakana characters — a decent first-pass heuristic, it correctly re-decoded 65 files' worth of lines) — but that wholesale regeneration silently reverted earlier, unrelated fixes already baked into the committed source (static→nosavein 5 files, i.e. AGENTS.md §4.3) and, separately, flattened CRLF to LF across every touched file (Python's default text-mode write), producing a 90+-line diff for what should have been a 1-line change. Caught both viagit diff --statbefore committing anything (staticreappearing was caught by re-grepping for it post-fix; the CRLF flattening by the diff being suspiciously large for a single-line semantic change). Reverted withgit checkout --, redid the fix as a precise byte-level single-line patch per file instead. Lesson for future encoding-repair work on already-converted files: never regenerate a whole file fromraw/once other fixes have landed on top of the conversion — patch only the specific corrupted byte range, and read/write in binary mode (or explicitnewline='') to preserve the original line endings. - The bopomofo/kana-based automated detector this project has used elsewhere (e.g. AGENTS.md §4.1's "human skim" heuristic) has a real false-negative gap: when BIG5 bytes get mis-decoded as GBK and land on *other valid-looking (but wrong) CJK ideographs* rather than bopomofo/kana, it produces no signal at all — confirmed directly: after fixing the 9 command-syntax lines above, the *body* text of those same help blocks (e.g.
study.lpc's "丁: ︓ぶ 100 虫︗, 珇のㄤず甧肂." /load.lpc's "丁: 10 虫︗.") is still mis-decoded BIG5-as-GBK and the automated scan (re-run clean afterward) does not flag it, because the wrong decode happens to land on ordinary CJK characters. Manually spot-checking ~15 more指令格式lines across the corpus (d/lwe/npc/zhahuo.lpc's dialogue, several others) turned up the same shape repeatedly. This is scoped far beyond what's reasonable to hand-fix in one pass — the automated detector alone already found 65 files with at least one bopomofo/kana artifact, and that's a lower bound, not the true count. Fixed only the 9 highest-confidence, most player-visible lines (thehelp <cmd>syntax headers, since those are what a genuinely new player types first) and stopped there rather than risk more half-finished wholesale edits under time pressure; the wider cleanup is flagged below as explicitly NOT done. This is the existing AGENTS.md §4.1 "mixed encodings within one file" class, just present at a much larger scale in this lib'scmds//feature//adm/daemons//d/trees than the single cataloged example (huoying'sconfig.cfg) suggested — worth a dedicated future pass, not a quick fix.
Bug 3 — a player who disconnects uncleanly is stranded in the void,
via TWO independent code paths (new bug class — see report for the AGENTS.md draft)
Found by literally doing what §10.7 step 5 asks: quit, grep
debug.log, reconnect after a real gap, confirm state — except the
very first "reconnect after real gap" (a session that ended by the
mudclient.py connection simply going away, i.e. exactly what a real
player's dropped wifi/closed laptop lid looks like, not a clean quit)
landed linfeng in "影子世界" (obj/void.lpc, the VOID_OB net-dead
holding room — zero exits) instead of back where they'd been.
- Path A — force-quit-from-void persists
/obj/voidasstartroomforever.obj/user.lpc'snet_dead()(driver-invoked automatically on a dropped connection) immediately parks the disconnected player inVOID_OB(remembering the real room in anosave/temp"last_location"var) and schedulesuser_dump(DUMP_NET_DEAD)forNET_DEAD_TIMEOUT(900s) later, which force-runscommand("quit")on the still-netdead, still-in-void object if they never reconnect.cmds/usr/quit.lpc:47-59(pre-fix) unconditionally persistedbase_name(environment(me))as"startroom"— with no special case forVOID_OB— so this force-quit-from-the-void wrote"startroom":"/obj/void"straight into the save file. Every future login (any number of days later, driver restarts, doesn't matter) then callsenter_world()→user->move("/obj/void")→ succeeds (void is a perfectly valid loadable room) → player is now permanently starting every session in a room with no exits. Reproduced live: an early test session in this pass ended withoutquit(idle-timeout close), and by the time I came back the disk save already read"startroom":"/obj/void"— confirmed withgrep -o '"startroom":"[^"]*"' data/user/l/linfeng.o. - **Path B —
LOGIN_D's ownreconnect()never restores the void-parked location, andobj/user.lpc'sreconnect()apply that *would* is dead code.obj/user.lpcdefines areconnect()apply, doc-commented "called by the LOGIN_D when a netdead player reconnects", whose whole job ismove(query_temp("last_location"))— exactly the fix Path A needed. Nothing calls it.**grep -rn "->reconnect(" work/across the whole lib returns zero hits.adm/daemons/logind.lpchas its *own*, differently-scopedreconnect(object ob, object user, int silent)function (re-links the connection, sends a "reconnected" room message, clears the netdead flag) thatget_passwd()actually calls on a netdead reconnect — and it never moves the player out ofVOID_OBat all. So even a player who reconnects promptly, well inside the 900s window, stays stuck in the void;obj/user.lpc's ownreconnect()was seemingly meant to be the fix but was simply never wired up. Reproduced live with debugwrite()/tell_object()instrumentation (removed before the final fix): a fresh login after an unclean disconnect showedfind_body=found netdead=1 last_location=/d/lwe/jie11 env=/obj/void, entered thereconnect(ob, user)branch, and the room remained/obj/voidthe entire time —last_locationwas captured correctly bynet_dead()but never consumed by anything in the live call path. - Fix (both paths, independent, both needed — matching the two distinct trigger conditions): 1.
cmds/usr/quit.lpc: rewrote the duplicate/overlapping startroom-setting logic into one clean if/else chain; whenenvironment(me)isVOID_OBat quit time, pull the real room fromme->query_temp("last_location")instead of persisting the void itself (falls back to leavingstartroomuntouched if even that's unavailable, rather than ever writing/obj/void). 2.adm/daemons/logind.lpc'sreconnect(): before re-linking, ifenvironment(user)isVOID_OBanduser->query_temp("last_location")is set,user->move()there first — doing, in the code path that's actually invoked, whatobj/user.lpc's dead-codereconnect()apply was clearly meant to provide. - Verified live, both paths, after rebuilding nothing (LPC-only change) and restarting the native driver: (a) logged in fresh, moved to
/d/lwe/jie2, let the connection drop uncleanly (noquit), reconnected within seconds — landed correctly back in街道(jie2), not the void, and a subsequent cleanquitpersisted"startroom":"/d/lwe/jie2"(not void) to disk; (b) separately confirmed the disk-corruption half by hand-editing"startroom":"/obj/void"into the save file (simulating what an UN-reconnected, timed-out net-dead session would have written pre-fix) and logging in fresh —enter_world()'s ownstartroompath is unaffected by this fix (by design — the fix stops void from ever being *written* again; recovering a save that's already been corrupted by the old bug needs a one-time manualstartroomreset, which is what was done forlinfeng's own save after the pre-fix reproduction above). debug.log stayed empty (noerror:/fatal lines) across every session in this entire pass, fix included. - This is a new bug class, not a rediscovery of an AGENTS.md §7.16/§7.17-style crash — nothing aborts or errors,
debug.logis and stays completely clean, which is exactly why boot-log watching and registration smoke tests can never catch it. Full draft writeup for AGENTS.md is in the task's final report (not added here — the orchestrating session owns AGENTS.md edits).
What else was tested and confirmed working
- Registration: real Chinese name (林风), full flow (English id → confirm y/n → Chinese name → password → confirm → email → attribute allocation with the in-game example split 15/10/10/6/17/2 → gender) — reached 梦旅馆大厅 (the Dream Inn hall) correctly.
look/score/iall correct at every stage (fresh, post-move, post-shop-visit, post-reconnect). - Exploration: walked the
d/lwetown zone (夜/清晨/正午/傍晚/入夜 time-of-day description variants all render correctly and change live as in-game time passes — confirmed by re-looking the same room at different points in the session), reached both the general store (d/lwe/shop.lpc, NPC 杂货老板/zhahuo) and the weapon store (d/lwe/shop1.lpc, NPC 段楚沛/duan chu pei, id list includeswuqi's directory-name aliaslwe wuqibut *not* barewuqi— the in-room[duan chu pei]bracket is the actual matchable id, a minor navigation trap for a human player but not a bug). - Shop
list:listat the weapon store correctly printed real priced stock (锯齿屠刀 24 银币, 长剑 18 银币, 短棍 1银20铜, 匕首 7银20铜) — confirmsfeature/dealer.lpc'sdo_list()and the underlyingMONEY_D->price_str()formatting work correctly.listat the general store correctly printed the "nothing for sale" path (zhahuoonly carries worn/wielded equipment, whichdo_list()correctly excludes — a content-completeness gap in the shipped NPC, not a bug: it has zero unequipped stock and novendor_goodsarray). kill/combat command surface:kill <target not present>correctly returned "这里没有这个人。" (no crash, no silent failure).- Session persistence: confirmed across three separate reconnect/relogin cycles in this pass (once accidentally exercising the net-dead path pre-fix, twice deliberately post-fix) that attributes, inventory, and (after the Bug 3 fix) location all persist correctly across a clean
quit+relogin. debug.log: grepped after every singlequitin this entire pass (a dozen-plus sessions) — stayed completely empty (no file even gets created) throughout, both before and after every fix.
Explicitly NOT verified live (with reason)
- Safe-sparring / training-dummy mechanism: none exists in this lib. Grepped
accept_fightacross the whole tree — zero hits. No木人/训练/陪练/dummy-pattern NPC is reachable from the starting zone (d/mochen/dongwuchang.lpc's "东练武场" training ground, with wooden dummies and sandbags in its room description, is real content but lives in a completely disconnected zone —d/mochen/d/mohao/d/shiwang/d/zuichen/d/tian/d/shenminhave zero cross-links to or fromd/lwe, confirmed by grepping everyd/lwe/*.lpcfor those path prefixes and vice versa). This lib genuinely ships without a reachable safe-combat mechanism. - Organic skill-teacher path: only one NPC in the entire lib implements the teacher/apprentice pattern (
d/mohao/ouyangxiu.lpc,inherit F_MASTER,attempt_apprentice()/recruit_apprentice()) and it's in the same disconnectedd/mohaozone above — unreachable from the actual starting area. Also checked thestudycommand's item-based path (cmds/std/study.lpc, reads a"skill"property off a carried book/item):grep -rn 'set("skill"'across the wholework/tree returns zero hits — no such item exists anywhere in the shipped content, reachable or not. This lib ships with no functional organic skill-acquisition path at all; not a conversion bug (nothing here is broken code, there's just no content wired up to use it), documented here rather than silently skipped. - Sect/faction-join mechanism: same finding —
feature/apprentice.lpc(thefamily/create_family/recruit_apprenticesect-equivalent infrastructure) is only ever invoked by the same single unreachableouyangxiu.lpcNPC. No join command, newbie-gift shortcut, or other faction-entry path exists in the reachable zone. - Live combat exchange, death/respawn: not reached. No safe sparring target exists (above) and deliberately picking a real fight with an unknown wild NPC's stats, without a safe first data point, was judged not worth the risk this late in an already long session; the
killcommand's basic dispatch (invalid-target case) was confirmed clean, but a full turn-by-turn combat log, a kill, and the death/respawn cycle were not exercised live. Reason: time budget — most of this pass's time went to the Bug 3 investigation (instrumented debugging across ~15 test sessions to isolate a two-path bug that only reproduces via specific disconnect timing), which was judged the higher-value use of the remaining budget over finishing the shop-purchase/combat checklist items. - A completed shop purchase (
buy):listwas verified live (above) and the underlyingfeature/dealer.lpc:do_buy()code path was read and looks correct (affordability check,MONEY_D->player_pay,ob->move(this_player())), but a livebuy <item>transaction wasn't completed in this pass — repeated navigation attempts to reach the weapon-shop NPC in the same room as abuycommand kept landing one room off (this lib's street grid has more live exits than itsset("exits", ...)blocks show via static grep, e.g.jie2live-shows asouthexit no.lpcsource search found — not investigated further, out of scope for this pass) — code-reviewed, not live-verified; flagging explicitly rather than silently presenting it as tested.
深度功能测试第二轮 / Deep functional test round two (2026-08-15, post driver-upgrade re-test)
驱动于 2026-08-12 升级后的重测。标准检查清单发现并修复三处问题:
1. config.fluffos:maximum evaluation cost 从 700000(已知
风险区间)提升到 5000000。
2. adm/simul_efun/file.lpc:log_file() 没有 assure_file()
目录预建保护,补上调用及前向声明;cat() 补上
read_file() || "" 空值防护。
3. obj/user.lpc::reconnect()(AGENTS.md §7.108,第五条独立确认
的血统——本档案与此前命中过的 shenzhou/shiji/shujian2008/shujian3
均无关联,是完全不同的 obj/user.lpc 架构,同一 bug 在这条独立
血统上再次出现):adm/daemons/logind.lpc 有同款 exec(old_link,
user); 踢掉重复登录写法,reconnect() 缺少 enable_commands()。
按 §7.108 记录的写法预防性修复,现场用两个真实连线复现"保持第一
个连线不断开→第二个连线登录→答 y 踢掉旧连线"验证:score 修复
后立即正常显示完整角色档案。
cmds/wiz/update.lpc(§7.106)与 master.lpc::log_error()(§7.10
的 "arning:" 大小写无关写法)均已是正确写法,无需改动;本档案无
adm/daemons/closed.lpc,不受 §7.107 影响。
现场验证摘要
驱动干净启动,管理员 fluffos/Mud@2026 登录确认
目前权限: (admin),update /adm/daemons/logind 成功验证真实写入权
限。踢掉重复登录重连路径现场验证通过(见上)。debug.log 全程干净
(448 行,无真实错误)。
本轮修改的文件
config.fluffoswork/adm/simul_efun/file.lpcwork/obj/user.lpc
深度功能测试第三轮 / Deep functional test round three (2026-08-18)
Standard §7.111/§7.112/logind-save/case-mismatch checklist (all clean, no action needed):
- §7.111 (
master.lpc::standard_trace()unguardedfile_name(error["object"])): already fixed here —objectp(error["object"]) ? file_name(...) : "(driver)"atadm/obj/master.lpc:200. - §7.112 (
init()unconditionally scheduling acall_out()chain): grepped everyinit()with acall_out(in it (~47 hits, all NPCs). All of them either fire a single one-shotcall_out("welcome", 0, ...)from the sharedfeature/attack.lpc(no chain, harmless if duplicated), or already guard their"greeting"call_out withremove_call_out("greeting"); call_out("greeting", 1, ob);— the correct anti-duplication idiom. No plain ROOM objects schedule call_outs frominit()at all. Nothing to fix. logind.lpc::enter_world()missingob->save(): present and correct (user->save(); ob->save();right aftersetup(), before the MOTD).u/<wizid>case-mismatch: not applicable — this lib has nou/wizard-home tree at all.
Bug found and fixed — adm/simul_efun/gender.lpc was BIG5 bytes
mis-decoded as GBK during the original conversion pass (same class as round two's Bug 2, much wider blast radius)
- Symptom: found while doing a from-scratch PK-combat playthrough (round one/two never exercised PK). Every first-person combat/action message that should read "你" (you) — e.g. "你对着测试四号喝道...", "忽然,狂声大笑,纵身跃起,向...发动攻击" — instead showed a blank where "你" belongs (leading space, no pronoun). Also affected
score's "你是一...的男性人类" line,tell/reply,emote, and any other message usinggender_self()/gender_pronoun(). - Root cause:
adm/simul_efun/gender.lpc(the sharedgender_self()/gender_pronoun()simul_efuns) was raw BIG5 bytes in the archive (raw/simple/adm/simul_efun/gender.c) but got run through the project's GB18030 conversion pass like everything else. Because these particular BIG5 byte sequences (case "女性"/"男性"/"雄性"/"雌性"etc., and their return values"你"/"妳"/"他"/"她"/"牠"/"它"/"祂") happen to be *unmappable* under GB18030, iconv's lossy fallback silently remapped them into Unicode Private-Use-Area codepoints instead of erroring — so the file "converted" cleanly with no warning, but everycaselabel became garbage that could never match a real"男性"/"女性"gender string, andgender_self()always fell through to its own corrupteddefault:value (also garbage, effectively empty when rendered). Confirmed byte-for-byte: decodingraw/simple/adm/simul_efun/gender.cas BIG5 recovers perfectly formed, grammatical Chinese matching this exact function's known contract. - Fix: precise byte-level patch (Python binary mode, no whole-file regeneration) replacing only the 8 corrupted string literals with their correctly-BIG5-decoded UTF-8 equivalents.
git diff --statconfirmed exactly 8 lines changed, CRLF preserved. - Verified live: rebuilt driver, ran the same PK-combat scenario — first-person messages now correctly show "你" throughout (e.g. "你对 着测试四号喝道小王八蛋!你死定了!"), third-person pronoun refs also correct.
debug.logstayed empty across the whole session. - This mis-decode class (§4.1/round-two's Bug 2) is proven to recur independently at least twice in this one lib now (help-topic syntax lines in round two, this shared simul_efun in round three) — flagging for the orchestrator: any lib sharing this "Final Frontier"/ES2 ancestry (BIG5-authored base + GBK-authored Chinese reskin layered on top) should have
adm/simul_efun/gender.lpc(or equivalent) spot checked, since a silently-emptygender_self()has no crash signature and is very easy to miss without an actual PK/combat playthrough.
Bug found and fixed — netdead reconnect never restores heart_beat,
permanently soft-locking anyone who dies and ever has one dropped connection (new bug class, not previously in AGENTS.md)
- Found while trying to complete the death → reincarnation loop (
kill→ die →/d/death/gate→/d/death/hall→say returnto 史巴克).d/death/npc/toilet.lpc'srelay_say()requires every limb'slimbs_eff_hitto be at least 50% oflimbs_max_hitbeforereturnis allowed ("您目前的状况还无法回到人世,请多休息一下吧" otherwise) — reasonable design, not a bug. But after admin-forced death (call hbtestb->die(), matching real PK-death numerically) the character's limbs sat frozen at1/1/max(重伤) for over a minute of real wall time with zero movement, never healing even while standing — the one path (feature/damage.lpc::heal_up()'s standing branch) that's supposed to add +1/tick to a ghost'slimbs_eff_hit. - Root cause, confirmed live via the
info <target>wizard command's "心跳:N" field (the reliable way to read real heart-beat state — thecall obj->query_heart_beat()idiom used earlier in this pass is *not* reliable for this efun, sincequery_heart_beathas no user-defined LPC wrapper andcall_otherto a nonexistent function silently returns 0 rather than erroring, which cost real time here chasing a false "always 0" signal before switching toinfo):obj/user.lpc::net_dead()correctly callsset_heart_beat(0)on an unclean disconnect (self-context, correct). But the *actually invoked* reconnect path,adm/daemons/logind.lpc::reconnect(object ob, object user, int silent)(called fromget_passwd()whenuser->query_temp("netdead"), and fromconfirm_relogin()'s duplicate-login-kick path), never re-enabled it — soheal_up()(and aging, idle-timeout, hunger/thirst decay — everything gated on heart-beat) silently stopped running for the rest of that session, any time a player's connection ever dropped and they reconnected. Combined with the death mechanism's healing requirement, this means: any player who dies and has ever had even one dropped connection can never heal enough limb health to reincarnate again, with zero error/crash signature (debug.logstays completely clean the whole time).obj/user.lpcalready has its ownreconnect()*apply* with the correct shape (enable_commands(); set_heart_beat(1); ...), doc- commented "called by the LOGIN_D when a netdead player reconnects" — but nothing calls it (same "intended but never wired up" dead-code pattern round one's Bug 3 found in this same function name). - Fix:
set_heart_beat()/enable_commands()are efuns with no cross-object form (bare calls always targetthis_object(), which insidelogind.lpc::reconnect()is the daemon itself, not the player — this is exactly why a first attempt at this fix, calling the efuns directly fromlogind.lpc, silently did nothing). Added a thinresume_heart_beat()wrapper toobj/user.lpc(right after the existing dead-codereconnect()apply) that doesenable_commands(); set_heart_beat(1);in the user object's own context, and call it asuser->resume_heart_beat();fromlogind.lpc's actually-invokedreconnect(). - Verified live with an A/B test (git-stashed the fix, rebuilt, re-ran the same scenario, then restored and rebuilt again): pre-fix,
info <player>showed心跳:1on fresh login but the "心跳:" field disappeared entirely after a real drop-and-reconnect cycle (heart_beat = 0, confirmed reproducible). Post-fix,心跳:1is present both before and after the same reconnect. Further verified the actual downstream effect: killed a test character, dropped+reconnected them, then sampledbodyevery 20s — limb values climbed steadily (1→3→5→8 over 60s, previously frozen forever at 1) confirmingheal_up()is running again and the reincarnation path is no longer permanently soft-locked.debug.logstayed empty throughout. - Flagging for the orchestrator: this is a new, previously uncataloged bug class — likely recurs in any lib whose
net_dead()/reconnect()split mirrors this shape (aset_heart_beatcall in the disconnect handler with no corresponding restore in the actually-invoked reconnect path). Worth a grep sweep across the corpus forset_heart_beat(0)innet_dead()-style applies paired with areconnect()that doesn't callset_heart_beat(1)(directly or via a wrapper) — not fixed elsewhere in this pass, this lib only.
What else was tested this round
- PK combat (two live characters,
cetestavscetestb): full exchange of blows, damage accumulation, skill-up messages, auto-flee trigger at low spirit/stamina, and the loser fleeing to an adjacent room — all worked correctly end-to-end (this is what surfaced thegender.lpcbug above). - Attacking an essential shop NPC (
kill li meng zhe): confirmed this is *intentional* content, not a bug —d/lwe/npc/bartender.lpcand every other vendor NPC ind/lweoverridekill_ob()to show a dramatic "transforms into a beast" flavor message and immediatelyremove_killer()both ways, cancelling the fight before any damage lands. Confirmed via code (identical pattern acrosszhahuo/zhanggui/xiaoer2/jiubao/wuqi/faju), not a gap. Matches this lib's existing documented finding that no reachable wild monster exists in the connectedd/lwezone. - Death → hell zone:
/d/death/gateand/d/death/hall(with NPC 史巴克/toilet.lpc) *are* reachable (unlike the disconnectedd/mochen/d/mohao/etc. zones noted in round one) — death correctly routes here viafeature/damage.lpc::die(). TheDEATH_ROOM-> start_death(this_object())call indie()targets a function that doesn't exist anywhere in the codebase (gate.lpcis a plainROOM) — confirmed this is harmless, not a bug:call_otherto an undefined function silently returns 0 in this driver config, no error, nodebug.logentry, and death still proceeds correctly. - A completed shop purchase (
buy): still not completed live this round either (admin-cloned gold onto a test character, but navigating on-foot to the weapon shop repeatedly landed one room off from wherever the lastlist/buyattempt needed — same live-exit- vs-static-grep mismatch round one already flagged for this lib's street grid). Not investigated further;list's working output anddo_buy()'s code path were already reviewed as correct in round one. - Registration flow,
look/score/i/body, and the netdead/void reconnect fix from round two all re-confirmed still working correctly throughout this pass's ~15 test sessions.
Files modified this round
work/adm/simul_efun/gender.lpc(BIG5-as-GBK mis-decode fix)work/adm/daemons/logind.lpc(calluser->resume_heart_beat()in the real reconnect path)work/obj/user.lpc(newresume_heart_beat()wrapper)
§7.114 fix: private input_line() broke multi-line to/board/mail input (2026-08-19)
Same ES2/FF-ancestry bug as zzhj/dfgs2 (see AGENTS.md §7.114):
work/feature/edit.lpc (this lib's F_EDIT mixin, inherited by
std/char.lpc) declared its input_to() re-arm target private:
private void input_line(string line, string text, function callback).
The recursive re-arm from inside input_line() silently failed to
register once reached through the inherited mixin, so any multi-line
.-terminated input session (board post, to, mail) dropped everything
after the first line. Fix: dropped private.
Live-verified on a fresh driver boot (port 40001), fresh character
(秦捌捌/qinbaba): to say → two lines of text → . → resulting
say output showed both lines (你 说道: hello line one\nhello line
two), not truncated after line 1. This lib has no chfn.lpc and its
board object isn't placed in any reachable room in this archive, so
cmds/usr/to.lpc (which drives the identical edit()/input_line()
flow) was used as the representative live test instead of post.
Killed the driver by exact PID when done.
Files modified this pass:
libs/shzs/work/feature/edit.lpc— droppedprivatefrominput_line().
§7.100 sub-threshold instance (2026-08-20)
Found during the §7.100 tail-sweep (below the original 166-lib survey's
=100-occurrence threshold, never checked). 10 live
replace_program(ROOM); occurrences across 10 room files
(obj/void.lpc, d/zuichen/jinshedong.lpc,
d/shiwang/yongdingmen.lpc, d/mohao/*.lpc x4, d/death/*.lpc x3) —
same fatal redundant-replace-after-inherit shape as the rest of the
§7.100 family. No room-building tool exists in this lib. Fixed by
deleting the redundant lines. Verified via a clean native driver boot
(zero new debug.log errors, port listening, killed by exact PID after
~8s).
§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.
深度功能测试(§10.7,2026-10-04)— negative range ends
scripts/lpc_fix_negative_ranges.py: 1 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)— tail() simul_efun
scripts/lpc_add_tail.py --apply: cmds/wiz/tail.lpc calls tail(file), an efun of the MudOS this archive ran on that FluffOS does not have (Undefined function tail: the command did not compile). adm/simul_efun/file.lpc now defines void tail(string file): the last 10 lines of the file, written to the player. Load check (HEAD against the working tree): 1 of the 1 tail command file(s) failed to load at HEAD, all load now, and the simul_efun file loads. KB 04 §6.2.
深度功能测试(§10.7,2026-10-05)— 房间列出的物件缺档时房间照常加载
房间基类 std/room.lpc:make_inventory() 用 catch() 包住 new(file),做不出来就返回 0;reset() 的 case 1: 拿到 0 就跳过这一项(if (!objectp(ob[list[i]])) break;)。档案里没有的 NPC 或物品(或 create() 出错的物件)原先会让列出它的房间整个加载失败(Bad argument 1 to environment(),或对 0 的 call_other()),连带这个房间后面的区域;现在房间照常加载,只是少了那个物件,下次 reset() 再试(KB 05 §7.25;scripts/lpc_resilient_room.py、scripts/lpc_room_reset_guard.py)。
验证:探针(scripts/lpc_room_reset_probe.py:房间基类列出一个不存在的物件,再调用 reset())HEAD 单件 崩溃、多件 崩溃,工作树 单件 OK、多件 OK。
深度功能测试(§10.7,2026-10-07)— 空的 if (current_water == 0) {}
2 个房间的 valid_leave() 里有一行什么也不做的 if (current_water == 0) {}(编译警告 Expression has no side effects),删去,行为不变:d/yishi/samo2.lpc、d/yishi/samo3.lpc。
深度功能测试(§10.7,2026-10-07)— 编译警告整理
scripts/lpc_warnings.py shzs --fix 加 scripts/lpc_fix_no_effect.py --apply,共改动 496 个 .lpc 和 1 个 .h(多为删去未用的局部变量)。HEAD 与工作树分别加载(新进程):490 -> 490 通过,无回退;改过的头文件的 1 个包含者 1 -> 1 通过。启动时警告 17 -> 0;新进程登录(输入名字)正常。
编译警告收尾(2026-10-13)
scripts/toolkit_fix.sh 一轮把 feature/container.lpc、std/equip.lpc、std/money.lpc 的 query_autoload() 改成与 F_AUTOLOAD 一致的 mixed;其余手工,能编译的文件警告清零;改动的 6 个对象在 HEAD 与工作树各载入一次,regress 0。
- 知府欧阳修
d/mohao/ouyangxiu.lpc把在大堂上chat的人打昏,处理函数叫do_chat,正好盖住std/char/npc.lpc设定 NPC 下一句闲聊的do_chat(mixed);目前没有别处对他调用do_chat,但名字冲突留着就是隐患。处理函数改名do_noisy(两条add_action一起改),行为不变。 obj/user.lpc没用的last_cmd(与feature/alias.lpc的同名)、std/space_ship/space_ship_room.lpc没用的doors(与F_DOOR的同名)删去。
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。2 处补上 if (!mapp(fam)) fam = ([ ]);(刚 recruit_apprentice() 之后的除外)。
去掉的预定义宏 SAVE_EXTENSION(2026-10-18,KB 04 §6.11)
老版 MudOS 给每个 LPC 对象预先定义了 SAVE_EXTENSION(".o");FluffOS 的 ChangeLog(COMPAT_BUSTER 一条)把它删了,改用 __SAVE_EXTENSION__。本库没有自己 #define 这个宏,用到它的文件一律 Undefined variable 'SAVE_EXTENSION',整个对象载入不了。改成 __SAVE_EXTENSION__(scripts/lpc_fix_predefined_macro.py):adm/daemons/network/netmail.lpc。netmail 是网络邮件守护进程(本库缺 mailer.h 等头文件,改后仍载入不了)。改后用 lpcc 逐个载入这些对象:0 个通过,1 个还有别的错误(adm/daemons/network/netmail:/adm/daemons/network/netmail.lpc:17: error: Cannot #include mailer.h)。
for (int i ...) 的循环变量在循环外还在用(2026-10-18,KB 04 §6.12)
当铺/商店的 do_buy() 写成 for (int i = 0; ...) if (...) break;,循环一结束又读 if (i == sizeof(inv))。FluffOS 里 for 头里声明的变量只在循环内有效,所以 Undefined variable 'i',整个房间(NPC)载入不了,当铺根本进不去。把 i 声明挪到函数开头(int i, index;),循环改成 for (i = 0; ...):std/room/shop.lpc。改后用 lpcc 逐个载入这些对象:1 个通过。
同一个 init() 写了两遍、内容不同(2026-10-19,KB 06 §7.265)
d/zuichen/huli 里 init() 定义了两次(一个加 buy/work 之类的指令,另一个再加 list/block_cmd),驱动报 Redeclaration of function 'init',整个物件载入不了。两处作者本来都要:把第二个 init() 里的 add_action(...) 并到第一个 init() 末尾,删掉第二个。(scripts/lpc_merge_dup_init.py)
出口指向不存在的房间(2026-10-19,KB 06 §7.257)
下列房间的出口写的文件不存在,而对面恰好只有一个房间的出口指回本房间,所以按对面的房间改正(笔误、大小写、路径少了一级):
/d/shenmin/wroad2.lpc的eastup出口:jiaolou→jiaojou/d/shenmin/zhuque.lpc的westup出口:jiaolou→jiaojou
改后房间照常载入(与 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 文件。
socket / dumpsocket 指令:dump_socket_status() 驱动里没有(2026-10-20,KB 06 §7.291)
这些巫师指令 write(dump_socket_status());,MudOS 的 efun 在 FluffOS 里不存在,指令编译不过。在模拟 efun 文件里补了 dump_socket_status():用 socket_status() 排出同样的表(没有 sockets 包的构建,比如 WASM,只有表头;scripts/lpc_add_sefun.py dump_socket_status)。
登录密码超过 255 字节:crypt() 抛错(2026-10-20,KB 06 §7.294)
驱动的 crypt() 对超过 255 字节的密钥直接报错(Error in crypt(), check your salt),老驱动则按任意长度散列。在登录提示符下输入 256 字节以上的密码,密码检查那一行就抛错,连线停在一个裸的 > 提示符上,登录走不完(password 指令的旧密码检查同样);用 300 个 x 当参数的扫描发现的。/adm/obj/simul_efun.lpc 里补了一个同名的 simul_efun crypt(key, salt):只有超长的密钥才被截短(先截到 255 个字符,再逐字符截到 sizeof(to_buffer(key)) <= 255,限制按字节算,一个汉字占三个字节),再交给 efun::crypt();普通密码原样散列,已存的密码散列不受影响(scripts/lpc_add_sefun.py crypt)。
翻页器 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。
disembark:在船舰以外的地方对 0 调用函数(2026-10-21,KB 06 §7.332)
cmds/std/disembark.lpc 只有人在船舱房间里才给 env(船舰对象)赋值,否则 env 是 0,接着 if (!env->is_space_ship() && !env->is_shuttle()) return notify_fail("你不在任何船舰中。\n"); 对 0 调用函数:原驱动答 0,于是走到提示;这个驱动抛 Bad argument 1 to EFUN call_other() Expected: object, string, array, Got: int(0),玩家在任何普通房间敲 disembark 都是运行时错误。条件前面加 !objectp(env) ||,提示文字不变。加载检查通过;扫描时是 disembark 的裸命令触发的。shzs 和 zzhj 同一处(前者简体、后者繁体)。
NPC 的 chat() 在 chat_msg 为空数组时下标越界(2026-10-21,KB 06 §7.334)
NPC 基类的 chat() 是 if (arrayp(msg = query(...))) { if (random(100) < chance) { rnd = random(sizeof(msg)); if (stringp(msg[rnd])) ...,不检查列表是否为空。本库现有的 NPC 文件里没有字面写成空 chat_msg 的(扫描只认 set("chat_msg", ({ })));守卫挡的是运行时才为空的列表和以后新增的 NPC。在 random(100) < chance 前面加 sizeof(msg) &&(scripts/lpc_fix_chat_empty.py;if (random(100) > chance) return 0; 的写法是 !sizeof(msg) ||)。改动:/std/char/npc.lpc(共 1 个文件)。
巫师命令不带参数时对 0 调用 efun(2026-10-21,KB 06 §7.336)
巫师(管理员)把命令敲成不带参数时,驱动把 0 传给字符串参数;下面的命令第一句就把这个 0 交给 efun,运行时报 Bad argument 1 to ...,这条指令从来没有用过。用 scripts/lpcc_bare.py 不登录、在一次 lpcc 求值里以 0 调用 main() 逐个确认后,由 scripts/lpc_fix_bare_arg.py 在第一处使用参数的语句前加守卫:文件自带 int help(object me) 的,守卫是 if (!arg) return help(me);(help() 定义在 main() 之后的 1 个文件补了原型 int help(object me);,否则编译报 Undefined function help);没有 help() 的是 return notify_fail("…\n");。改动(2 个文件,括号里是接住 0 的 efun):/cmds/arch/grep.lpc(sscanf)、/cmds/wiz/test.lpc(present)。加载检查 HEAD 与工作树对照,没有退步。
注册到不存在函数的 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.,同一个动词的其他处理函数不再尝试(不是最新的一条就悄悄跳过)。删除了 2 条注册(1 个文件,scripts/lpc_fix_dead_add_action.py),动词留给别的处理函数:/d/mochen/dongwuchang.lpc(do_ci、do_da)。最多的函数名:do_ci 1 处、do_da 1 处。
按字节写的汉字循环、茶馆猜诗和同盟频道标题(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 区间 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(一格两个空格)。本库 3 处(1 个文件)。证明(lpcc_eval.py hhsj):tribar_graph(6,9,12) 在 HEAD 画出整条 12 个■,改后为 6 个■+3 个□;麻将 strlen(tempB)/2 是两字符牌码,未改。
无参数时命令对 0 的调用(玩家/--all-dirs 残留,2026-10-27,KB 06 §7.336 Also)
无参数命令把 0 交给 present / sscanf / file_exists 等会运行时报错。lpc_fix_bare_arg.py --all-dirs 在首次使用参数前加守卫。多行 if (arg && !sscanf)(吐纳默认消耗)与已有 can_learn/get_object 守卫的误报已回退;本库本批改动见该提交。
深度功能测试(2026-10-27,§6.10 未知 pragma save_binary/optimize)
删除本库中 FluffOS 不认的 #pragma save_binary / #pragma optimize… 行。