info.html · 介绍 · play.html · 游玩 · llms.txt · 下载与本地运行 · ZIP · GitHub
「最终幻境」(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
- id:
fluffos - 密码 / password:
Mud@2026 - 中文名 / display name: 浮浮
- 权限 / level:
(admin)—— 通过/adm/etc/wizlist中的fluffos (admin)行授权。
警告:这是一个公开的默认密码,仅供本地/浏览器试玩。正式对外开服前
请务必修改此密码。
本地运行
cd libs/zzhj
~/src/fluffos/build-debug/src/driver config.fluffos游戏端口:40099。
NOTES · 移植与修复记录
最终幻境.zip → zzhj
- Archive:
archives/最终幻境.zip. Mudlib root at the archive top level, alongside a bundled Windowsmudos.exe/mudos.log(ignored — our own driver is used). ~1.6k raw files, 643.lpcfiles after conversion — a small, focused lib (not a mega-lib). - Identified via the archive's own
README/readme.txt: this is "The Final Frontier" v0.6e ("最终边界"/"最终幻境"), an ES2-mudlib extension by Spock (bbs.csmc.edu.tw/spock), Traditional Chinese/BIG5-origin ("由著名的『打混蟑螂史巴克』所創立" — in-game banner credits "Spock, the roach").config.cfg'sname :field and the in-game banner both confirm 最终幻境/The Final Frontier as the actual mud name — matches the archive filename, no stale-name surprise (contrast AGENTS.md §5.1'sdtsl2/xkxz2cases). - Proposed number: 061 (new, unique).
- Port: 40099 (as assigned; confirmed free).
- Status: DONE — boots clean, full registration verified end-to-end with a real Chinese name (韩风 natively, 沐晨 under WASM), admin (
fluffos) verified viaupdateon both drivers.
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)
- The archive's own in-game banner states the mud is no longer under active development by its original author ("即日起, 本 mud 停止研發") — cosmetic/historical, does not affect playability.
- lpcc sweep not re-run this session (no fresh
lpcc_fail.log); the real boot + full interactive registration/admin test on both drivers is the verification gate actually used here (small lib, fast enough to fully play-test directly).
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)
- Admin shortcut: no dedicated
setskill/grant-sect admin command exists incmds/wiz/,cmds/adm/, orcmds/arch/(checked all three) — but the genericcall <obj>-><func>(<args>)wizard command (cmds/wiz/call.lpc) works as the de facto shortcut. Live-verified:call shenqiao->query_skill("unarmed")→0,call shenqiao->set_skill("unarmed", 50)→50,call shenqiao->query_skill("unarmed")→50. Documented honestly per §10.7 point 4 rather than claiming a dedicated command exists. - Organic path — found broken by multiple independent, pre-existing content gaps, none introduced by this project's conversion (all present in the very first commit that added this lib's tree unchanged):
- 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)
- Read
cmds/std/kill.lpc,cmds/std/attack.lpc,feature/attack.lpcin full. This lib has nofightcommand at all (despitedoc/help/combatexplicitly documentingfightas the safe non-lethal alternative tokill) — grepped forfight.lpc/surrender.lpcand any"fight"add_action string, zero hits, and no.old/.bakbackup copies exist either (unlike the learn/practice case, this one has no leftover draft to restore from — it appears to genuinely never have shipped in this frozen snapshot). So there is nocan_speak-style safe/unsafe split to find here —killis the ONLY combat-starting command, and by its own source it's unconditionally lethal against a non-player target (if(!userp(obj)) obj->kill_ob(me);— the target always retaliates with realkill_ob(), not the softerfight_ob()). PvP is the only case wherekillisn't automatically mutual. - The
no_fightroom flag IS live-verified working:kill joan(a harmless newbie-hall NPC) in the starting hall correctly returned<神諭> 這裡不准戰鬥.and did not start combat. Every room reachable from spawn within the newbie academy (checked all ofentrance/training_1_info/stairs_1/stairs_2/cafe) isno_fight-flagged by design — a deliberate newbie safe-zone, not a bug. The other player-reachable transporter destination (ceresspace station) has combat allowed but zero combat-capable NPCs (only unlivinng shuttle vehicles). The one guildhall with actual combat NPCs is the same one blocked above. Given no safely-reachable fight-capable target exists within a reasonable navigation/risk budget this pass, the actual damage-exchange path was verified by code read only, not live combat — documented explicitly as unverified-live per §10.7 point 6, not presented as tested.
发现但判定为既有设计、未改动的现象
- The archive's own in-game banner states development stopped ("即日起, 本 mud 停止研發") — this deep-test pass independently found concrete evidence backing that claim:
learn/practiceshipped as.oldfiles, an unplaced example skill-book, 9 of 10 sects with no room placement anywhere, and 4 separate missing-function/missing-slot gaps blocking the one sect that IS reachable. All pre-existing, present in the very first commit for this lib, none introduced by this project's conversion — a frozen, genuinely-unfinished snapshot, consistent with the shipped banner. kill's unconditional lethality against non-player targets (no in-lib safe-sparring alternative) is internally consistent withdoc/help/newbie's own warning ("在 FF 中別任意砍殺人類的 NPC") — the game clearly intendskillto be a real, risky choice; the missingfightcommand is a content gap (see above), not something papered over by a design decision elsewhere.
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:
libs/zzhj/work/obj/user.lpclibs/zzhj/work/adm/obj/master.lpclibs/zzhj/work/adm/simul_efun/file.lpc
§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:
libs/zzhj/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). 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… 行。