The Final Frontier

✅ 可玩

最终幻境 (The Final Frontier)

zzhj

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

▶ 开始游玩 · Play Now

「最终幻境」(The Final Frontier,简称 FF)是一个改写自「东方故事II」(ES2) 函数库的太空科幻题材 MUD,由 Spock 创立——是本项目 ES II/东方故事大家族里罕见的科幻换皮版本,而非武侠题材。新角色从「新手學院大廳」起步,创角时需要自行分配六项人物属性(力量/敏捷/智力/注意/體質/技術)点数,总和须为 60,游戏内的传送装置还能抵达一处「谷神星」太空站;存档自带的游戏公告声明作者已停止后续开发,十个职业/门派设定里目前也只有一个真正在世界地图上拥有落脚房间,是一份真正停摆、内容未完工的历史存档。存档原为繁体中文(BIG5)内容,已转换为 UTF-8。

English

The Final Frontier (FF), a space-opera science-fiction MUD adapted from the 'Dongfang Gushi II' (Eastern Story II, ES2) codebase, founded by Spock — a rare sci-fi reskin within this collection's ES II/Eastern Story family, rather than the usual wuxia setting. New characters start in a newbie-academy hall and hand-allocate six attribute points (Strength/Agility/Intelligence/Perception/Constitution/Technique summing to 60) rather than rolling them; a transporter also reaches a 'Ceres' space station. Its own in-game banner announces that development has stopped: only 1 of 10 character classes/sects has a room placing it in the world at all, and even that one is currently inaccessible, leaving it a genuinely frozen, unfinished snapshot rather than a complete game.

README

在线试玩

https://mudlibs.fluffos.info/zzhj/

管理员账号 / Admin account

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

本地运行

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

游戏端口:40099。

NOTES · 移植与修复记录

最终幻境.zip → zzhj

Triage / lineage

Genuine LPC mudlib. This is the ES II / 东方故事 mega-family per AGENTS.md §11 (explicit in-game credit: "FF 的 MUD 函數庫改寫自東方故事 II, 在此叩謝" — "FF's MUD library is adapted from ES2, thanks"), but a distinct, much smaller/differently-shaped game from either sjcs or sanjieshenhua — confirmed via diff (369-line master.lpc/331-line securityd.lpc/658-line logind.lpc here vs 495/416 and 316/747 for the other two). Not a derivative of either sibling in this batch.

State at handoff (this session)

A previous agent session had already: extracted the archive, converted encoding/renamed, written config.fluffos (port 40099), applied the §7.1 load_object(SECURITY_D) recursion guard in master.lpc, fixed private→nosave nomask on command_hook (old copy kept alongside as feature/command.c.old for reference), disabled dns_master in preload, seeded fluffos (admin) in adm/etc/wizlist, and had ALREADY run a full registration test through to a real Chinese name (fluffos/浮浮 and a second test account qinfeng/秦风 both have complete .o saves under data/user//data/login/). This lib had no ban/site/uptime gates to begin with (grepped for is_banned/sited/uptime()-gates — none found), so no loopback-allow patch was needed here (documented as a deliberate no-op, not an oversight). No NOTES.md/README.md existed yet. This session verified the existing work end-to-end (native + WASM, including the admin update check that hadn't been run yet) and found no further code fixes were needed — default_trusted_write here already includes "(admin)" for / out of the box (unlike sibling sanjieshenhua's commented-out default), so the admin write-ACL just worked on the first try.

Verification (native)

Booted cd libs/zzhj && ~/src/fluffos/build-debug/src/driver config.fluffos — clean boot, zero fatal errors in log/debug.log.

Full registration flow (fresh id haifengc, real Chinese name 韩风): English id (3-20 lowercase letters; note — unlike the two 三界 siblings, this lib has no special new keyword: ANY unregistered id goes straight to a "create new character?" confirm) → y → Chinese name (1-10 hanzi) → password (≥5 chars) → confirm → email → 6-attribute point-buy (str/dex/int/not/con/tec, each within a fixed per-attribute range, must sum to exactly 60 — e.g. 10 10 10 10 10 10) → gender (m/f) → entered FF 新手學院大廳 (newbie academy hall). look, score (full attribute+combat stat card), and quit all correct.

Admin: logged in as fluffos/Mud@2026 (already registered by the prior session, display name 浮浮, (admin) status shown immediately via the pre-seeded wizlist line) → update /adm/obj/master.lpc → 重新編譯 /adm/obj/master.lpc﹕成功﹗ → quit clean. No data-file fix needed (unlike sanjieshenhua) — this lib's securityd.lpc ships a live (uncommented) "/" : ({"Root","(admin)","(arch)"}) in default_trusted_write.

Verification (WASM)

node scripts/wasm_client.js ~/src/fluffos/build-wasm/src libs/zzhj — same full registration flow (fresh id wasmren, real Chinese name 沐晨) reached the same starting room; look/score/quit all correct. Admin login as fluffos + update /adm/obj/master.lpc also succeeded under WASM. This lib is fully playable under WASM — no IP-format/sockets-absent blockers hit on this login path, and no ban/site gate existed to need a loopback patch in the first place.

Known remaining issues (documented, not fixed)

How to run

cd libs/zzhj
~/src/fluffos/build-debug/src/driver config.fluffos
python3 ../../scripts/mudclient.py 127.0.0.1 40099 --timeout 20 --idle 1.0 \
  --send "yourid" --send "y" --send "你的中文名" \
  --send "yourpass" --send "yourpass" --send "[email protected]" \
  --send "10 10 10 10 10 10" --send "m" \
  --send "look" --send "score" --send "quit"

WASM long-sit boot-watch pass (2026-07)

200s scripts/wasm_boot_watch.sh sit: completely clean, zero grep hits beyond the known-benign early Unable to open log file: "log/debug.log" line and the harmless nosave crash(string error, ...) false-positive — no new findings. Proactively fixed adm/simul_efun/object.lpc's file_owner() (return name → return dir) as part of a repo-wide port of a bug found live on sibling zhonghua2 (misattributes 3-level-deep /u/<wiz>/<subdir>/<file> log_error writes to a bogus path); didn't fire in this lib's own sit, fixed proactively since it's the identical shared file. Retest: fresh registration (id haiyunb) through look/quit, clean.

深度功能测试 / Deep functional test (AGENTS.md §10.7)

Full continuous session: read doc/help/newbie, doc/help/combat, doc/help/skill first (this lib's own newbie primer, kill/fight distinction, and skill-learning overview) → fresh registration (id shenqiao, real Chinese name 沈翘) → look/score/i at every state change → guildhall/sect-join organic path (blocked, see below, but not before it surfaced 4 real bugs) → admin-shortcut skill grant via call → combat-mechanism code read + no_fight gate live-check → quit (no new-account grace-period/delete window exists — grepped, none found, so a real quit was used, not a simulated disconnect) → debug.log grep → real wall-clock reconnect (~9 min gap, spent drafting this section and auditing all 9 other class masters via update) → confirmed state persisted (room, stats, id/password).

Bugs found and fixed

1. §7.90 (maximum evaluation cost too low for this lib's own make_body() cold-compile), harsher variant matching the xyj2000f/xiyouji450 shape exactly. config.fluffos shipped 300000; /std/char's full inheritance chain (feature/action, feature/attack, feature/command, feature/damage, feature/ skill, ...) compiling for the first time during logind.lpc::make_body() (called from get_email(), the very next step after entering an email address during registration) reliably tripped Eval interrupted: object adm/obj/master cost limit reached, limit: 300000 usec / *Too long evaluation. Execution aborted., 100% reproducible on a fresh driver process — every new registration silently hung right after the email prompt, no player-visible error. Confirmed by reproducing on a fresh boot, then fixing (5000000, this project's common raised value) and reproducing a clean full registration on a second fresh boot with zero further cost limit reached hits in debug.log. 2. §7.11 (log_file() missing assure_file() guard). adm/simul_efun/file.lpc's log_file() did a bare write_file(LOG_DIR + file, text) with no directory guard; logind.lpc::get_gender() (the last registration step, right before enter_world()) calls log_file("USAGE", ...). This lib got lucky in that a bare 2-arg write_file() into a missing dir just silently no-ops on this driver build rather than throwing (unlike xixingzhanji's 3-arg overwrite-mode variant), so it didn't crash registration outright — but the USAGE log was silently never written on a fresh checkout (no work/log/ tree shipped). Fixed with this lineage's established pattern: assure_file(LOG_DIR + file); write_file(...) plus a forward declaration (same-file forward-reference needed, assure_file() is defined textually after log_file()). Verified: work/log/USAGE now gets created and appended on every registration/login. 3. New instance of the §8.3a private eval_function() / start_call_out() shape, independently confirmed on this ES2-derived-but-distinct lineage (zzhj is explicitly NOT a derivative of any other lib in this batch per AGENTS.md §11, so this is a fresh, unrelated occurrence of the same underlying driver quirk, not a copy-paste). feature/action.lpc's start_call_out() schedules call_out("eval_function", delay, fun), but eval_function() was declared private in the same file — once feature/action gets inherited into std/char.lpc (the universal player/NPC base), the driver's own internal call_out dispatch sees DECL_HIDDEN instead of DECL_PRIVATE and silently no-ops with apply() with insufficient permission whenever any temporary-condition recovery call_out actually fires. Fixed identically to precedent: dropped private. 4. **New, codebase-wide finding: two bare function calls (exert_function, map_skill) referenced by nearly every class/guild master NPC's create() (daemon/class/*/master.lpc, champion.lpc, executioner.lpc, taolord.lpc, ...) were never implemented ANYWHERE in this archive. exert_function is used as (: exert_function, "powerup" :) in chat_msg_combat arrays (8 files); map_skill(base, special) is called directly in create() to presumably link a base skill to a sect's signature technique (9 files). Neither is defined in any inherited base, any simul_efun, or anywhere else in the tree (grep -rn returns zero definitions, only call sites). Compounding effect: exert_function is a compile-time "Undefined variable" error (file fails to compile at all); map_skill compiles fine but throws "Undefined function called: map_skill" as an uncaught RUNTIME error mid-create(). On daemon/class/fighter/guildhall.lpc (the ONLY class/guild room placed anywhere in the entire game world — see below), this uncaught error propagated up through std/room.lpc's make_inventory() → reset() → setup() → create() chain, which is itself called UNCAUGHT from feature/move.lpc's move() (call_other(dest, "???"), line 70, not wrapped in catch()) — meaning literally EVERY attempt to enter this one reachable guildhall aborted mid-move(), silently parking the mover in /obj/void.lpc ("虛無") instead. Fixed both as safe no-op stubs in the shared bases already universally inherited (feature/attack.lpc for exert_function, since it's part of std/char.lpc's inherit chain; feature/skill.lpc for map_skill, same reasoning) — deliberately NOT guessing at real combat-flavor/skill-linkage behavior (game-design judgment call, out of scope per §10.7). This unblocked champion.lpc and 7 of the 9 other class masters (assassin, beggar, lama, scholar, bonze, ronin, executioner — verified via update on each) to compile and create() cleanly. Not a new AGENTS.md catalog entry: checked §11 first — zzhj is explicitly not a derivative of any sibling in this batch, so this exact missing-function pair has no portability value to other libs; documented here only. 5. §7.20 flavor 2 (net-dead reconnect never restores location), confirmed instance — AGENTS.md already flags FF/ES2-derived codebases sharing this exact net_dead()/VOID_OB/user_dump() shape as likely-affected, and this is that shape exactly. obj/user.lpc's own reconnect() method correctly restores query_temp("last_location") (set by net_dead() when the connection drops) via move(last_loc) — but nothing ever called it. grep -rn "->reconnect(" work/ returned zero hits, the exact tell described in §7.20. The login flow actually reconnects through adm/daemons/logind.lpc's own differently-scoped reconnect(ob, user, silent), which only does set_link/set_body/exec + channel announcements and never touches location. Live-reproduced before fixing: registered fresh, let the connection idle-close without quit (net_dead), reconnected — landed in "虛無" (/obj/void.lpc) instead of 新手學院大廳, zero trace in debug.log (exactly as §7.20 describes — the hardest bug class in the catalog to spot). Fixed per the established pattern: added user->reconnect() to logind.lpc's reconnect(), called before the "reconnected" announcement so it fires in the real room, not the void. Re-verified live post-fix**: same disconnect/reconnect sequence now correctly lands back in 新手學院大廳.

Skill/sect acquisition: both paths tested, organic path found broken (pre-existing, not fixed further)

- learn/practice/apprentice — the commands doc/help/skill and doc/help/combat themselves document — exist ONLY as cmds/std/learn.old / cmds/std/practice.old (no live .lpc), and even learn.old's own logic calls ob->recognize_apprentice(me), a function that doesn't exist anywhere either — restoring the .old file as-is would introduce a NEW crash on first use, so this isn't a simple §7.94 rename-restore; left alone. - study (the other documented organic path, per doc/help/skill) IS a live, well-formed command — but the only object anywhere in the archive with a "skill" property for it to read is obj/example/book.lpc, an unplaced template file (grepped, zero references from any room/NPC). Nothing studyable actually exists in the reachable game world. - Of the 10 daemon/class/*/ sects defined in code, exactly ONE (fighter) has ANY room (guildhall.lpc) placing its NPCs anywhere in the game world at all — grepped every other class directory name against the whole tree, zero references outside each class's own subdirectory. The other 9 sects' master NPCs are unreachable dead code regardless of any function-availability fix. - Even after fixing exert_function/map_skill (bug 4 above) so fighter/guildhall.lpc's champion NPC spawns cleanly, the master NPC (蕭辟塵, the actual sect teacher and the one do_join's join command would lead toward) still fails create() on carry_object(__DIR__"icy_girth")->wear(): icy_girth.lpc/icy_cloth.lpc inherit WAIST; / inherit CLOTH;, but no WAIST/CLOTH macro or std/armor/{waist,cloth}.lpc exists anywhere (only 15 slots are defined: belt/boots/cloak/coat/earring/gloves/head/l_armor/mask/neck/ pants/ring/shield/u_armor/wrists). BELT and COAT/U_ARMOR are plausible substitutes by name, but which (if either) matches the author's actual intent is a design guess, not a mechanical fix — left undone. Auditing the other 9 classes via update (admin) turned up yet MORE independent missing functions in the same shape (swordsman/master.lpc: perform_action undefined; taoist/taolord.lpc: cast_spell undefined) — since none of those 9 classes are reachable anyway (no room places them), these were left unfixed as pure academic findings, not touched. - Net result: the organic sect-join path (join command itself, read and confirmed correct/self-contained in std/room/class_guild.lpc) could not be live-verified — the one room it would work from can't currently be entered due to the WAIST/CLOTH gap above. Documented as unverified-live, not silently presented as tested.

Combat mechanism: read, gate live-verified; live damage exchange not reached (documented, not faked)

发现但判定为既有设计、未改动的现象

WASM

Not re-verified under WASM this pass (native-only this session; this project's WASM build path is permanently blocked). Confirm via: curl -sS "$HTTPS_PROXY/__agentproxy/status" — emsdk's storage.googleapis.com dependency is denied by the proxy, unchanged from every other lib checked this session. The prior WASM pass (2026-07, above) already covers WASM-specific gates (loopback exemptions, admin seed) and found the lib fully playable there; the 5 fixes in this pass are driver-behavior-general (eval-cost ceiling, missing-directory guard, private-visibility, two missing-function stubs, a dead reconnect-location-restore call) and apply identically under WASM once that build path is unblocked.

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

Round-two re-verification against the current native build-debug driver (post-upgrade — pulls in PRs #1343/#1344 and the corpus-wide %-operator float-crash fix). Standard checklist + live playthrough-style verification.

Findings:

1. AGENTS.md §7.108 (obj/user.lpc's reconnect() missing enable_commands()): this lib has the kick-duplicate-login pattern (adm/daemons/logind.lpc calls user->reconnect() on the character body). Fixed by adding enable_commands(); as the first statement. Live-verified with two concurrent telnet sessions: session 2 logged in as fluffos, confirmed the "趕出去, 取而代之嗎? (y/n)" prompt with y, and the resulting session correctly dispatched look (real room description) and score (real stat panel). 2. AGENTS.md §7.10 (adm/obj/master.lpc's log_error()): had no compile-severity filter at all — every message, including routine compile warnings, was unconditionally written to the admin's screen. Added the standard strsrch(message, "arning:") == -1 guard. 3. adm/simul_efun/file.lpc: cat()'s write(read_file(file)) had no null-guard; changed to write(read_file(file) || ""). log_file() already correctly called assure_file() first — no change needed there. 4. Already correct, no change needed: cmds/wiz/update.lpc (only update.lpc in this lib) already guards with environment(me) &&. No adm/daemons/closed.lpc exists, so AGENTS.md §7.107 does not apply. maximum evaluation cost was already 5000000.

Live verification summary: booted the native driver on port 40099 (clean boot, only pre-existing unused-variable/unknown-pragma warnings, no fatals; Initializations complete / Accepting telnet connections both printed). Logged in as the seeded fluffos admin (Mud@2026), confirmed real write access via update /adm/simul_efun/file (recompiled successfully). Ran the two-session kick-duplicate-login reconnect test described above and confirmed the §7.108 fix live. No fatal errors in the driver's console output. Killed the driver by exact PID when done.

本轮修改的文件 / Files modified this round:

§7.114 fix: private input_line() broke multi-line board post (2026-08-19)

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). Per AGENTS.md §7.114, this silently breaks the recursive input_to() re-arm on every line after the first, since the function is reached through the inherited mixin rather than defined directly on the player object. Fix: dropped private (one-line change, input_line was never player-typeable as a command anyway).

Live-verified on a fresh driver boot (port 40099), fresh character (秦柒壹肆/qinqiba): post <title> → two body lines → . → 留言完畢. (success). read 23 confirmed both Body line one. and Body line two. were saved (not truncated after the first line, which is the pre-fix symptom). Killed the driver by exact PID when done.

Files modified this pass:

§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). 38 real live

replace_program(ROOM); occurrences fixed: 36 standalone room files (obj/void.lpc, d/test/*.lpc x7, d/newbie/*.lpc x6, d/wiz/*.lpc x2, d/death/*.lpc x4, a 14-file d/maniac/*.lpc cluster, daemon/class/scholar/entrance.lpc) plus this lib's own room-building tool obj/roommaker.lpc's string-builder template — so newly-built rooms were inheriting the bug too. One additional grep hit (the same file, line 37) is a harmless documentation string inside the tool's help-text LONG block ("如果你要在房間的程式碼中使用 set 以外的函式, 請先刪除: replace_program(ROOM) 這一行." — advising room authors to delete that line themselves) — not executable code, correctly left untouched. 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.

Shop + 拜师 (2026-09-04)

Paid shop works; organic 拜师 is still a content gap (unchanged from the 2026-07 deep test). Native driver on port 40099, admin fluffos/Mud@2026.

Shop. The academy cafeteria (d/newbie/cafe.lpc) is free (order sandwich / etc.; the wall menu says 免費提供) — not a paid vendor. The only F_VENDOR NPC in the archive is 酒館老闆 Mark Simons in 黃玉酒館 (/d/maniac/topaz_pub). That room is not on the newbie transporter (guestroom / ceres only); reached via admin goto. list shows 紅葡萄酒 四十枚銅幣 and 小麥麵包 二枚銅幣. A silver coin is not enough change for a 2-copper bread (你沒有足夠的零錢﹐而對方也找不開... — can_afford case 2, buyer denominations only). After cloning two copper: buy bread from bartender charges immediately, the bartender delays delivery through do_chat, then hands over 小麥麵包.

拜师. Organic learn/practice/apprentice still exist only as cmds/std/*.old; recognize_apprentice is still missing; restoring the .old files would crash. The fighter guildhall master still fails create() on missing WAIST/CLOTH. No reachable teacher — content, not a programming bug to invent around.

Bug fixed. std/item/combined.lpc's destruct_me() was private and reached via call_out("destruct_me", 1) after a stackable hits amount 0. Same inherited-mixin DECL_PRIVATE → DECL_HIDDEN shape as AGENTS.md §7.114 / the combined-item addendum (xuanjianlu / demonangel). Live before the fix: paying exactly 2 copper for bread left 二枚銅幣 in inventory forever (and the leftover stack saved across quit). Dropped private. After the fix, the same exact-2-copper buy + 3s wait leaves the bread and no copper.

File modified: libs/zzhj/work/std/item/combined.lpc (CRLF preserved).

深度功能测试(§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)— 房间列出的物件缺档时房间照常加载

房间基类 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)— 编译警告整理

scripts/lpc_warnings.py zzhj --fix 加 scripts/lpc_fix_no_effect.py --apply,共改动 83 个 .lpc 和 1 个 .h(多为删去未用的局部变量)。HEAD 与工作树分别加载(新进程):77 -> 77 通过,无回退;改过的头文件的 1 个包含者 1 -> 1 通过。启动时警告 17 -> 0;新进程登录(输入名字)正常。

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

scripts/toolkit_fix.sh 一轮去掉 obj/example/dumpling.lpc 重复的 inherit ITEM(它从没载入过,现在载入);照 shzs(bb0751cc7d4):feature/container.lpc、std/equip.lpc、std/money.lpc、obj/bandage.lpc、obj/token.lpc 的 query_autoload() 改 mixed,obj/user.lpc 没用的 last_cmd、std/space_ship/space_ship_room.lpc 没用的 doors(与 F_DOOR 的同名,九艘飞船 obj/ss/* 的警告都源自它)删去。能编译的文件警告清零;改动的 10 个对象在 HEAD 与工作树各载入一次:HEAD PASS 8,tree PASS 9,regress 0。

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 用了原系统的物品路径(最常见:/obj/longsword)。每处改为 { object carried_ob = carry_object(...); if (carried_ob) carried_ob->wear(); }(scripts/lpc_guard_carry_object.py):NPC 照常出现,只是不带这件东西;文件补回来(或是虚拟对象)照样会带上。载入检查:改动的文件改前能载入 0 个,改后 0 个(0 个原来载入不了),没有退步;其余 1 个另有原因(多为 set_skill() 了本库没有的武功)。

去掉的预定义宏 SAVE_EXTENSION(2026-10-18,KB 04 §6.11)

老版 MudOS 给每个 LPC 对象预先定义了 SAVE_EXTENSION(".o");FluffOS 的 ChangeLog(COMPAT_BUSTER 一条)把它删了,改用 __SAVE_EXTENSION__。本库没有自己 #define 这个宏,用到它的文件一律 Undefined variable 'SAVE_EXTENSION',整个对象载入不了。改成 __SAVE_EXTENSION__(scripts/lpc_fix_predefined_macro.py):adm/daemons/network/netmail.lpc、obj/token.lpc。token 是帮派领袖信物;netmail 是网络邮件守护进程(本库缺 mailer.h 等头文件,改后仍载入不了)。改后用 lpcc 逐个载入这些对象:1 个通过,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 个通过。

补回丢掉的基类宏(2026-10-18,KB 04 §6.13)

inherit F_XXX; 里的宏本库任何头文件都没有定义,报 syntax error, unexpected L_IDENTIFIER, expecting L_STRING or '(',整个对象载入不了;宏指向的基类文件本库其实有,别的库都把这个宏定义成同一个路径。在全局头文件 include/globals.h 里补上:SSERVER → /std/sserver(10 个文件)。(scripts/lpc_restore_macros.py)改后用 lpcc 逐个载入这些对象:10 个里 10 个通过。

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)。

tail 指令:tail(file) 驱动里没有(2026-10-20,KB 06 §7.291)

cmds/*/tail.lpc 调用 MudOS 的 tail() efun,FluffOS 没有,指令编译不过。模拟 efun 文件里补了 tail(file)(Discworld 家族的兼容版:文件最后约 20 行,从完整的一行开始,存在返回 1;scripts/lpc_add_sefun.py tail)。

登录密码超过 255 字节:crypt() 抛错(2026-10-20,KB 06 §7.294)

驱动的 crypt() 对超过 255 字节的密钥直接报错(Error in crypt(), check your salt),老驱动则按任意长度散列。在登录提示符下输入 256 字节以上的密码,密码检查那一行就抛错,连线停在一个裸的 > 提示符上,登录走不完(password 指令的旧密码检查同样);用 300 个 x 当参数的扫描发现的。/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])) ...,不检查列表是否为空。本库有 1 个 NPC 文件写成 set("chat_msg", ({ }))(或 chat_msg_combat)并带正的 chat_chance(例如 /daemon/class/ronin/master.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) ||)。改动:/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 与工作树对照,没有退步。

(: 函数 :) 指针指向对象自己没有定义的函数(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。 还剩 2 个函数没有补(chat_msg_combat 2):原型还在函数体丢了、或者根本没写过,没有可以直接补回的捐赠(别的库同一路径的文件里没有这个函数,或者它还要用本库没有的辅助函数、签名不同),不编造:/daemon/class/swordsman/master.lpc:perform_action、/daemon/class/taoist/taolord.lpc:cast_spell。 另有 1 处函数体被作者整段注释掉(指针没跟着删),是有意关掉的,没动。

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

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

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

原档按字节算字符串区间(一个汉字 2 字节):name[2..3] 是名字的第二个字,name[0..1] == "澄" 问名字是不是以「澄」开头。转成 UTF-8 之后,这个驱动的区间和 strlen() 都按字符算(strlen("澄观") 是 2,"澄观"[0..1] 是两个字),老算术原样留着、意思全变:拜入少林 / 武当 / 峨嵋等派的玩家被改成错误的法名(二字名 张三 变成一个字的 澄,更长的名字取到第三个字)。

本库 1 处(1 个文件):拼名字的赋值 1 处。例:name[0..1] → name[0..0](/daemon/class/bonze/master.lpc:104)。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,不要重跑。

按字节写的汉字循环、茶馆猜诗和同盟频道标题(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… 行。