info.html · 介绍 · play.html · 游玩 · llms.txt · 下载与本地运行 · ZIP · GitHub
融合武侠与仙侠元素的 MUD,属于 ES II 引擎家族(2003 年"炎黄"分支),与同批的「炎黄英雄史」系出同门,都源自同一套 2003 年由"lxtx"改写的引擎版本:新角色从"世外桃源"启程踏上江湖路,可在"猛士型""智慧型""耐力型""敏捷型""均衡型"五种角色定位里择一发展;天赋分配是这批档案里少见的"自选数值"玩法——`washto <膂力> <悟性> <根骨> <身法>` 一次性直接指定四项数值(每项 13-30,总和须为 80),不必先随机再决定接受或重掷;死亡有完整的鬼门关体验,"黑无常"/"白无常"接引,复活固定落脚扬州武庙,这套死亡系统与「炎黄英雄史」逐字节共享;战斗中够强的对手还能主动封死玩家的逃跑路线,不是每次都能全身而退。逐字节比对显示这份档案其实是本项目 `yhwhpublicfi` 的近乎复制版本——两者约 96% 的公共文件完全相同,共享同一张 73 区地图和同一套鬼门关仪式,`yhwhpublicfi` 用的正是这款游戏不带编号的原始名字"炎黄武魂",这份档案名字里的"Ⅱ"就是专为区分两者而加的;另外还带着一整套从未接线的旧版死亡系统备份(`d/death22/`),确认在当前玩法里完全无法触达。
English
A wuxia MUD blended with immortal-cultivation (xianxia) flavor: new characters begin their jianghu journey from a "Land of Peach Blossoms" starting zone and pick one of five role archetypes (Brute, Wise, Enduring, Agile, Balanced) to shape their growth. Character creation is unusually direct for this collection — the `washto <str> <wis> <con> <agi>` command lets players assign all four core stats by hand in one shot (13-30 each, must total 80) instead of rolling and re-rolling. Death sends players through a full underworld sequence escorted by the Black- and White-Guard psychopomps (黑无常/白无常), with revival always landing at the Yangzhou Martial Temple — a system shared byte-for-byte with this collection's sibling "Chronicle of Yan-Huang Heroes" (yhyxs; both trace to the same 2003 ES II engine rewrite by developer "lxtx"). Strong enemies in this game can actively block a losing player's escape route rather than always allowing a clean retreat. A file-level comparison found this build is in fact a near-duplicate of this collection's yhwhpublicfi — 96% of common files byte-identical, same 73-zone map, same underworld ritual — which carries the plain, unnumbered version of this game's own "Soul of Yan-Huang" title; the "II" in this build's own name exists specifically to tell the two apart. Also carries a full unwired backup death-and-revival subsystem (d/death22/) left over from an earlier build, confirmed unreachable in current play.
README
内容亮点
- 注册时设有两套独立密码:一组用于找回普通密码的"管理密码",一组日常 登录密码。
- 更正(2026-08-05):上面提到的"7.68 复活软锁"修复已经撤销——经重新评估,鬼魂"不在场"时放弃复活流程更可能是有意的游戏设计(多数这类档案里鬼魂本身就无法自行移动,离开是一种游荡机制,回来时 init() 会重新触发流程),不是需要强制重试的 bug;详见 NOTES.md。
深度功能测试新发现的 bug(详见 NOTES.md)
死亡/复活系统的 d/death/npc/{hei,bai}.lpc(黑无常/白无常,游戏
里实际生效的一套)有 AGENTS.md §7.68 归档的复活软锁死 bug,已修
复,并现场完整验证了一次真实死亡→鬼门关→复活的全流程。这份档案
还额外带着一整套从未接线的死代码死亡系统(d/death22/,配一个同
样未接线的 logind2.lpc),里面 hei.lpc/bai.lpc 有同样的软
锁死 bug(已一并修复,虽然当前不可达,成本很低);同一批死代码
里还有一对更早版本的"gargoyle"命名文件,其中 bgargoyle.lpc 的
守卫条件被反着写了(!wizardp 而不是 wizardp),如果这份死代
码曾经被接线过,会导致所有普通玩家(非巫师)的复活序列永远不会
被排上日程——因为确认这段代码当前完全不可达,未做修改,只作为
历史存档记录。另外发现并修复了一类和手足档案"炎黄英雄史"完全相
同的 bug:help/rules、clone/game/{8,21}_hlp 三个无扩展名纯文
本帮助文件从未被转成 UTF-8(和"炎黄英雄史"对应文件逐字节相同,
证实是两份档案共享的同一批未转码内容),已用 iconv 转换。
在线试玩
https://mudlibs.fluffos.info/yanhuangwuhun/
管理员账号 / Admin account
- id:
fluffos - 登录密码 / password:
Mud@2026(游戏内"普通密码") - 管理密码 / recovery password:
Admin2026(本 lib 注册时额外设置的 "管理密码",仅用于找回普通密码) - 中文名 / display name: 浮浮(注册时姓氏一栏直接回车跳过)
- 权限 / level:
(admin)—— 最高权限(通过/adm/etc/wizlist授予,SECURITY_D据此判定)。
警告:这是一个公开的默认密码,仅供本地/浏览器试玩。正式对外开服前
请务必修改此密码。
本地运行
cd libs/yanhuangwuhun
~/src/fluffos/build-debug/src/driver config.fluffos游戏端口:40060。
NOTES · 移植与修复记录
yanhuangwuhun — 炎黄武魂 conversion notes
What this is
Archive 炎黄武魂_64bit.rar (#66). Self-identifies (config.cfg name : field,
and the adm/etc/welcome banner) as 「武林群侠传」之炎黄武魂Ⅱ ("Wulin
Qunxia Zhuan: Yanhuang Wuhun II" — "Chronicles of Martial Heroes: Soul of
the Yellow Emperor II"). Two bundled .doc/.docx files at the archive
root ("武林群侠传2(炎黄武魂)修改更新说明.doc" and "炎黄武魂终极版修改思路
及说明.docx") confirm the same real title. The slug yanhuangwuhun (from
the archive filename) differs slightly from the self-identified name but
was kept as-is per the task's port-assignment convention — noted here per
instructions.
Lineage: master.lpc's header comment is the giveaway — "for ES II
mudlib / original from Lil / rewritten by Annihilator (11/07/94) /
modified by Xiang for XKX (12/15/95) / updated by Doing Lu for hell (2K) /
Modify By Linux@lxtx for yh 2003.3" ("yh" = 炎黄/Yanhuang). This is the
same ES II lineage already seen in es1_win/esI/xkx2001/rzrmud/xo/
bmxkx2001/kxkj/yueyingqiyuan/wuhanzhan (a 2003
fork of that common ancestor, done by an author using the handle "lxtx").
adm/single/{master,simul_efun}.c layout (not adm/obj/) matches the
xkx2001/rzrmud branch of that family most closely.
"64bit" in the archive name refers to a bundled prebuilt driver, not the
mudlib: the raw archive contains mudos.exe (a 2006 Win32 MudOS binary)
at the top level AND a separate fluffos64/ directory holding a full
Cygwin-based 64-bit FluffOS driver build (driver.exe + a dozen
cygwhatever.dlls, dated Oct 2016) plus a start64.bat launcher. Both
were ignored entirely, per standing project policy — only the LPC mudlib
source was extracted/converted/run through this project's own FluffOS
build.
- Raw size: ~10,756
.c/.lpcfiles (~87MB raw). Normal-sized lib, NOT a mega-lib — fulllpcc_check.shsweep was run (no memory concerns; host had >2GB free / 16GB+ available throughout). - Port assigned: 40060 (next free per TODO.md after 40056-40059).
Pipeline steps
1. Extracted archives/炎黄武魂_64bit.rar → libs/yanhuangwuhun/raw/ with
scripts/extract.sh (plain unrar, no password/SFX issues).
2. Converted raw/ → work/ with scripts/convert_lib.sh:
- encoding: already_utf8=475 converted=11549 lossy=8 skipped_binary=41
(the 8 lossy files: 2 .bak quest-daemon files, 2 adm/etc/ip/
banned-IP data files, 1 cmds/arch/recovermud.c admin tool — all
non-critical data/dead-tooling, not on the boot/registration path)
- renamed to 10,756 .lpc files (0 stray .c remaining)
- fixed 395 literal ".c" references (.lpc/.h scope) + 5
#include <....c> angle-bracket refs + converted 9 local
angle-bracket <x.lpc> includes to quoted form
- static → nosave touched 63 files (see the counterexample fix
below — this one had an unusually large false-positive collision)
3. Wrote libs/yanhuangwuhun/config.fluffos (port 40060, mudlib directory
pointed at work/, config's original name field 炎黄武魂Ⅱ kept).
Created log/, binaries/, adm/tmp/ dirs (didn't exist in the raw
archive).
4. Read master.lpc/securityd.lpc/chinese.lpc/named.lpc/
logind.lpc/message.lpc proactively before first boot and applied
every applicable catalog fix (below) before ever attempting a full
driver boot.
5. Booted build-debug/src/driver on port 40060 — required two rounds of
fix-then-reboot (see "Fixes found only via a real boot" below) before
reaching a fully clean boot with zero errors.
6. Verified the full registration flow with mudclient.py three
independent times, each in one continuous connection, each reaching an
actual room in the game world.
7. Ran the full lpcc_check.sh sweep (normal-sized lib, no §6b OOM
concern) — iterated twice more after the first sweep to fix newly
discovered content bugs, ending at 10747/10756 = 99.92% pass.
8. Killed the driver by exact PID when done (never used a broad
pkill -f — verified other agents' concurrently-running drivers
for other libs, e.g. huoying, yxcs, haiyang2, were
never touched).
Fixes applied proactively (before first boot), per the AGENTS.md catalog
- §15h (is_chinese GBK byte-range check) —
adm/simul_efun/chinese.lpc'sis_chinese()was the classic whole-string GBK lead/trail-byte-range check (str[i] < 161,str[i] < 176 || str[i] >= 248gated oni%2==0). Rewrote as a CJK Unified Ideographs codepoint range check (str[i] >= 0x4e00 && str[i] <= 0x9fff), dropped thei%2==0byte-lead gate, and changed the length floor from< 2(byte-oriented) to< 1(character-oriented). - §15h (check_legal_name length bounds) —
adm/daemons/logind.lpc'scheck_legal_name(name, maxlen)hadstrlen(name) < 2 || strlen(name) > maxlen(both call sites passmaxlen=4, a byte-oriented "2 Chinese characters" bound). Fixed tostrlen(name) < 1 || strlen(name) > maxlen / 2(halves the effective bound to match character counting; call sites unchanged). Also fixed the SEPARATE combined-length check inget_name()(surname+given-name concatenation):strlen(fname) < 4→< 2, matching the message text's own stated "at least two Chinese characters." - §15h (named.lpc deep fix) —
adm/daemons/named.lpchas the full "deep" shape documented in the catalog:
- #define PATH(name) (name[0..1] + "/" + name) (first GBK char, 2
bytes) → name[0..0] (first character).
- Every strlen(name) < 2 guard (in remove_name, map_name,
who_is, invalid_new_name) → < 1.
- A name[0..1] bucket-key reference in remove_name → name[0..0].
- invalid_new_name()'s sliding-window similar-name check: guard
strlen(name) < 4 → < 2; loop bound i <= l - 4 → i <= l - 2;
2-char-window slices name[i..i+3] (4 bytes) → name[i..i+1];
3-char-window slices name[i..i+5] (6 bytes, guarded by i+6<=l) →
name[i..i+2] (guarded by i+3<=l).
- §15p (DNS/intermud daemon exclusion) — checked
adm/etc/preload:dns_master(which DOES exist as a file,adm/daemons/network/ dns_master.lpc) is simply not listed in preload at all. Nothing to exclude — confirmed viagrep -rl dns_masteracross the whole tree that it's referenced only from its own header file, never invoked. - §14 (valid_override 3-arg) —
master.lpc'svalid_override(file, name)only checked the 2-argfile == SIMUL_EFUN_OBform. Upgraded to the 3-arg(file, name, main_file)signature, addedmain_file == SIMUL_EFUN_OB || main_file == MASTER_OBto the same early-allow check (free insurance fix; per §14 this may never surface on a real boot, and didn't here either — novalid_override-related errors appeared in any boot log). - §15n (custom securityd valid_read blocking compile-time access) —
adm/daemons/securityd.lpchas a genuine custom ACL (exclude_read/trusted_readtables keyed by directory + wiz-status, default-DENY unless a rule matches). Added the standard early-allow forfunc == "load_object"/"recompile_object"/"include"right after the existingfunc == "file_size"allow. Applied proactively — did NOT wait to see the "Read access denied" crash (unlike shujian2008, where this was originally discovered), since the ACL shape was immediately recognizable from a plain read-through.
Fixes found only via a real boot / registration test (not visible from source review alone)
- NEW variant of §15s (message() 4th-arg + a §8b forward-reference interaction) —
adm/simul_efun/message.lpc's localmessage(mixed arg, string message, mixed target, mixed exclude)wrapper delegates toefun::message(...), whose 4th ("exclude") parameter is declaredvoid | object | object *— an explicitint 0(as everytell_room()call with no exclude list produces) fails that type check at runtime ("Bad argument 4 to EFUN message()"). This crashed EVERY daemon whosecreate()callsCHANNEL_D->do_channel(...)→tell_room()during preload (natured, punishd, storyd, eventd, pkd, memoryd, cpud, analectad, rzr_d — 9 preload daemons hit this on the very first boot). First fix attempt (guardif (!exclude) efun::message(arg,message, target); else ...) did NOT fully resolve it — the SAME error still fired afterward but this time fromtell_room()itself, in a live gameplay session (a preloaded room's own NPC/daemon callingtell_room()), tracing tosimul_efun.lpcline 308 (thetell_room()body itself), not to the guardedmessage()function. Root cause: per §8b (same-file forward-reference gotcha),tell_object()/tell_room()/shout()/write()/say()are all defined textually BEFOREmessage()'s own definition in the same composed file, and they call the bare (unprefixed) namemessage(...)— without a prior declaration, the compiler falls back to binding that bare identifier directly to the real EFUN at each of those call sites (since "message" is a known valid symbol, a real efun, rather than an "Undefined function" error), completely bypassing the local override and its guard. Fixed by adding avarargs void message(mixed, string, mixed, mixed);forward declaration at the top of the file, before any of its callers. (The forward declaration itself neededvarargstoo — a first attempt at a strict 4-arg-required declaration broke every 3-arg call site, e.g.message("tell_object", str, ob), with "Wrong number of arguments" compile errors.) Verified vialpccrecompile + a second clean boot + two more full registration-flow tests: zeromessage()-related errors in any subsequent run. - Rename-width bug (
.c→.lpcextension-strip, same shape as the nitan_ceshi/nitan_san precedent) —adm/daemons/eventd.lpcandadm/daemons/storyd.lpcboth doget_dir(DIR + "*.lpc")thenmap_array(names, (: $1[0..<3] :))to strip the extension for afind_object()/destruct()pass over stale preload state —[0..<3]was correct for stripping the OLD 2-character.cextension but leaves a trailing.lafter the rename ("emei.lpc"[0..<3]→"emei.l", not"emei"). This surfaced ascall_other() couldn't find object '/adm/daemons/event/emei.l'duringeventd's preload. Widened both (and two further instances of the identical idiom inadm/npc/ luban.lpc, a "player-built house" NPC that lists/clears/rewrites dynamically-generated room files by the same convention) from[0..<3]to[0..<5](the extension grew by 2 characters, so the cutoff widens by 2). - §3 counterexample (moniHuafu-style
static/nosavestring-literal collateral) — unusually large this time: the blanket\bstatic\b→nosavesed hit 105 occurrences across 60 files, all instances of the pre-existinglog/static/log-subdirectory naming convention (log_file("static/CRASHES", ...),"static/killrecord","static/security","static/quest", etc. — the reallog/static/directory exists on disk) AND severalset/query/add/deletedbase property KEYS using the same word as a namespace prefix (me->query("static/sadly"),me->add("static/marry", 1),me->delete("static")). None of these are thestatic/nosavekeyword — reverted all 105 viased -i 's/"nosave/"static/g'scoped to files that had the collision (safe: the pattern requires an opening quote immediately before the word, which never collides with the real keyword substitution). Verified afterward: zero remaining"nosavestring-literal hits, and a separate grep confirmed no barestatic <type> name(...)function declarations survived anywhere (the actual intended fix is intact).
Content bugs found via the lpcc_check.sh sweep (fixed)
Sweep pass rate before any content fixes: 10732/10756 = 99.78% (24 failures). After fixing the shared-root and individually-diagnosed bugs below: 10747/10756 = 99.92% (9 failures remaining, all confirmed non-bugs or genuine content gaps — see next section).
- §10 (missing closing quote) — the actual root cause of a 4-file cascade:
inherit/condition/damo.lpc'sdie_reason()hadreturn name + HIM "发作身亡了;— the string literal never closed before the;, which swallowed the rest of the file's text as string content until the parser happened to hit the next real"much further down, producing a confusing "syntax error" + a run of "Illegal character" errors at seemingly unrelated later lines (a moved/renumbered version of this same symptom reappeared after an EARLIER, unrelated typo fix in the same file — see below — until this real root cause was found). Fixed by closing the string. This one file isinherited bykungfu/condition/damo_luanqi.lpc,damo_shangshen.lpc, anddamo_zheyuan.lpc— fixing the shared base resolved all 4 sweep failures at once (§8g pattern). - A SEPARATE, also pre-existing bracket typo in the same file (
update_condition()):if (! intp(cnd["level"]) || ! intp(cnd["remain"] || ! stringp(cnd["id"])))— a misplaced/missing)nested the rest of the condition insideintp()'s own argument list. Fixed toif (! intp(cnd["level"]) || ! intp(cnd["remain"]) || ! stringp(cnd["id"])). (This was the FIRST bug found in this file; fixing it alone didn't fully resolve the sweep failure because the §10 quote bug further down the same file was the deeper, still-unfixed cause of the cascade.) - Missing macro, §8g-style (target file exists, macro was just never defined):
TEXT2PIC_D—adm/daemons/text2pic_d.lpcexists on disk, butinclude/globals.hnever defined a macro pointing at it. Used byd/beijing/npc/kangxi.lpcand (transitively)d/beijing/hg.lpc. Added#define TEXT2PIC_D "/adm/daemons/text2pic_d"next to its siblings, resolving both failures at once. - Missing macro, §8g-style:
TYPE_CHARM—include/armor.hdefines aTYPE_HEAD/TYPE_NECK/TYPE_CLOTH/.../TYPE_BOOTSfamily of equipment-slot constants but was simply missing acharmslot, needed byinherit/armor/charm.lpc. Added#define TYPE_CHARM "charm"matching the existing naming convention exactly. - §9 (fullwidth punctuation as code syntax):
d/death/npc/mamian.lpchad 14set_skill("...", 650);calls using a fullwidth right parenthesis)(U+FF09) instead of ASCII)as the actual closing token of the function call (confirmed in code position, not inside a string). Fixed all 14 occurrences (sed 's/650);/650);/g'); this also resolved the separate sweep failure ond/death/yinyangta17.lpc(which referencesmamian). - Missing local variable declarations (typo):
kungfu/skill/ riyue-bian/chan.lpc'sperform()usedap/dpwithout ever declaring them. Addedint ap, dp;alongside the function's other locals. - Missing semicolon (typo):
kungfu/skill/kuihua-mogong/perform/ wswd.lpc'scheck_wd()hadx = me->query("int")with no terminating;before the next statement, producing a cascading syntax error two lines further down. Added the semicolon. - Wrong argument type to
set_name()(typo):d/baituo/obj/bowl.lpccalledset_name("海口大碗", "bowl")— the 2nd arg must be astring *(alias array), not a bare string, per this driver'sset_name()signature (and every sibling item file in this lib already uses the array form). Fixed toset_name("海口大碗", ({"bowl"})). - Duplicate function definition (copy-paste typo):
d/beijing/npc/ dan/danB_6.lpcdefinedquery_autoload()twice, byte-identical bodies. Removed the second (dead) copy. - §15f (bare
arraytype):cmds/help2.lpchadarray efun_search = DEFAULT_EFUN_PATHS;/array help_search = DEFAULT_HELP_PATHS;— the combined declare+initialize form with a barearraytype doesn't parse on this driver ("syntax error, unexpected L_IDENTIFIER" pointing at the variable name). Changed both tomixed *. - Wrong
query()calling convention (genuine content bug, not an encoding/rename artifact):kungfu/class/generate/spekilled.lpc'sset_from_me()didexp = query("combat_exp", me) * 11 / 10;— but this lib's localF_DBASE::query(string prop, int raw)takes a RAW flag as its 2nd argument, not a target object (unlike the "nitan" lineage'squery(prop, ob)redirect convention, which this lib does NOT use — see "confirmed not needed" below). Reading a DIFFERENT object's own property needs an ordinarycall_other. Fixed to(int)me->query("combat_exp") * 11 / 10.
Remaining sweep failures (9) — confirmed non-bugs or genuine content gaps, not fixed
/adm/daemons/story/guiguand/adm/daemons/story/mengzi— CONFIRMED sweep artifacts, not bugs: both daemons'create()callsselect_character(), which filtersall_interactive()(real connected non-wizard players) for a suitable recipient of a random "story" item; if none qualifies (always true under an isolatedlpcccompile with no live connections), the daemon deliberatelydestruct()s itself — by design, not an error. Confirmed by reading both files' full source; neither produces any error in the real boot log, and neither is even on theadm/etc/preloadlist (loaded lazily bystoryd.lpc's directory scan, never actually instantiated without a live candidate player)./kungfu/skill/qingyun-bian— genuine but very low-impact content bug: its globalmapping *actiontable computes"force"/"damage"values via(int)this_player()->query(...)directly in the top-level variable initializer (evaluated once at compile/load time, when there is no real player context —this_player()is 0). Every sibling skill file inkungfu/skill/uses fixed numeric literals in this same table shape instead (confirmed by checking several neighbors, e.g.dugu-jiujian.lpc). This is a genuine authoring bug in one skill's action table, but restructuring it to compute the values inside theperform()function (rather than a global initializer) is a real content change beyond a minimal fix — documented here rather than guessing at the intended numeric values. Only affects players who specifically use the "青云鞭"(Qingyun Whip) skill; does not affect registration, boot, or any other tested path./d/baituo/obj/shedan—inherit PILL;(macro#define PILL "/inherit/medicine/pill"inglobals.h) but no such file exists anywhere in the archive (inherit/medicine/only haspowder.lpc). Genuine missing-content gap, affecting exactly this one poison/pill item; not fabricated a replacement base class per the project's standing policy on missing content (§11/§13)./adm/daemons/vrm_serverand/d/death/heisenlin— referenceSCHEDULE_D, a macro that is never defined anywhere in this archive, and there is noscheduled/schedule_d-named daemon file at all (only ahelp/schedulehelp-text file exists). Genuine missing-content gap — not fabricated a stand-in daemon./adm/daemons/huanjing2003/temp/check_room,huanjing1_pro_b,hj_room_created— all three live under ahuanjing2003/temp/scratch subdirectory, are not#included, inherited, referenced by path, or preloaded ANYWHERE else in the lib (confirmed viagrep -rlfor each basename), and reference genuinely nonexistent headers/simul_efuns (max_min.h,ctime_format()). Orphaned dev/test leftovers (§13-style dead content), left as-is.
Confirmed NOT needed (verified by reading source, not by hitting a crash)
- §4 (lazy security-daemon
load_objectrecursion) —master.lpc'svalid_read/valid_writeonly callfind_object(SECURITY_D), neverload_object(). No recursion risk; confirmed by reading both functions in full. - §7 (missing
get_root_uid/get_bb_uid) — both already implemented inmaster.lpc, returningROOT_UID/BACKBONE_UID. - §8c (
this_player()-override footgun invalid_read) —securityd.lpc'svalid_read/valid_writeuse the passed-inuserparameter'sgeteuid()directly; neither ever overridesuserwiththis_player(). Confirmed by reading both functions in full — noif (this_player()) user = this_player();-shaped code anywhere. - §8d/§15o (
get_include_path()) — checked whether this master.lpc needed the apply (all headers here live under the single sharedinclude/directory, already covered by config'sinclude directoriessetting) and additionally verified directly against the ACTUAL FluffOS driver source (compiler/internal/lexer_utils.cc'sinit_include_path()): whenmaster::get_include_path()is undefined,safe_apply_master_ob()returns a null/error sentinel and the function returns WITHOUT touchinginc_path, which was already reset to the config default (inc_list) by the previous compile'sdeinit_include_path()— i.e. the config default silently continues to apply, contrary to one possible reading of the catalog's §15o write-up. Empirically confirmed too: three full registration-flow tests each triggered dozens of live, mid-connection lazy compiles (rooms, NPCs, the player body class, items) using<ansi.h>/<room.h>/etc, none of which failed to resolve their includes. - §15l (
SIMUL_EFUN_OBdestruct-in-master::create()crash) —master.lpc create()only doeswrite(...)+ none ofcreate()callsdestruct()/efun::destruct()at all. Confirmed by reading the whole function. - §15m (stale
restore()crash masquerading as a maintenance gate) —adm/daemons/versiond.lpc(this lib's version-sync daemon, same family as zhonghua2's bug) callsrestore()unguarded increate(), but (a) no stale/corrupteddata/versiond.owas shipped in this archive (checkeddata/— only 8 unrelated.ofiles exist, noversiond.o), and (b)adm/etc/config'srelease server : localsetting makessetup()setversion_ok = 1immediately regardless ofrestore()'s outcome. No maintenance-gate message ever appeared in any boot/test session. - §15p (DNS daemon preload exclusion) — see above, nothing was actually preloaded, so nothing to exclude.
- §15u (dormant phone-home/self-destruct license check) — grepped
securityd.lpc/master.lpcforrm/unlink/shutdown/rmdircombined with a suspicious opaque gate; found none. - §15v (
LONELY_IMPROVED-styleefun::gating family) — not applicable; this is ES II lineage, not the NT/nitan/Lonely lineage that bug is specific to. No such flag/pattern exists anywhere in this lib. - §15w (
log_error()/error_handler()warning-vs-error conflation) —master.lpc'slog_error()has its player-facing broadcast lines ALREADY commented out by the original author (//if (this_player(1)) efun::write(...) else //if (this_player()) tell_object(...)) — onlyefun::write_file(LOG_DIR + "log", message)is live, so compile warnings routed through this apply are written to a log file only, never shown to a connected player. Confirmed both by reading the function AND empirically: three full registration + gameplay sessions produced zero unexpected system messages. - The "nitan"-lineage simul_efun/dbase architecture bug (§15) — this lib's
adm/simul_efun/*.lpcfiles have no bareset/query/deletesimul_efun definitions at all (confirmed:wizard.lpc,object.lpc,message.lpc,override.lpc,path.lpc,user.lpc,gender.lpc,atoi.lpc,util.lpc,file.lpc— none define these). Property storage goes throughF_DBASE(feature/dbase.lpc) inherited directly by each object, the architecturally-correct pattern (same conclusion as rzrmud/es1_win/xkx2001 and the rest of the ES II family). The §15b family of "only ever called, never defined" nitan-lineage simul_efuns (remove_ansi,noansi_strlen,B2G,db_affected,clr_ansi,changed_match_path,query_bandwide,query_shadowed,addn_temp) were each grepped for call sites: all 0 hits exceptchinese_number(real, already implemented, delegates toCHINESE_D) and 2 commented- outaddn(...)calls (dead code).
Registration flow — read before testing
adm/daemons/logind.lpc's callback chain: logon() → banner → get_id
(English id, check_legal_id: lowercase letters only, 3-10 chars, no
digits — using an id with a digit produces a confusing rejection cascade
that consumes subsequent --send lines as retries; learned this the hard
way on this lib too, see transcript below) → confirm_id (y/n, new
character if yes) → get_surname (Chinese, ≤2 chars, optional — blank
skips) → get_name (Chinese, ≤2 chars) → combined-length check →
NAME_D->invalid_new_name() (duplicate/similar-name/compound-surname
check) → new_ad_password/confirm_ad_password (≥5 chars, admin/backup
password) → new_password/confirm_password (≥3 chars, must differ from
admin password) → get_type (1-5 character archetype, blank defaults to
5/"均衡型") → get_gender (m/f) → make_body() → enter_world(). No
hidden BIG5/student/client-version pre-id gate — the very first prompt IS
the real id prompt (unlike xyzx3/xkxz2). "new"/"none"/
"guest"/"cancel" are explicitly banned ids (routed to a guest/deny path,
not character creation), matching several other libs in this project.
Registration flow — verified transcripts (3 independent runs, one continuous connection each)
Run 1 — id qinfeng, surname 秦, given name 风, type 均衡型
(default/blank), gender m:
您的英文名字...:qinfeng
使用[qinfeng]...您确定吗(y/n)?y
您的中文姓氏...:秦
您的中文名字...:风
请设定您的管理密码:admin1234
请再输入一次...:admin1234
请输入你的普通密码:pass123
请再输入一次...:pass123
请您选择...类型:(blank -> 均衡型)
您要扮演男性(m)的角色或女性(f)的角色?m
你连线进入炎黄武魂Ⅱ。
世外桃源 - ...(full room description, exits west/east/north/south, NPCs 水笙/狄云 present)
> look -> re-displays the same room correctly
> quit -> 欢迎下次再来!Zero errors in debug.log for this run (this WAS the run that first
exposed the message()/tell_room() bug during PRELOAD, before login —
by the time registration itself ran, that had already been fixed).
Run 2 — id qinling, surname 秦, given name 岭, type 耐力型,
gender f: identical successful flow, reached the same starting room
(世外桃源), look/quit both worked. Zero errors in debug.log.
Run 3 (final, post-all-fixes) — id qinhuai, surname 秦, given name
淮, type 智慧型, gender f: identical successful flow, reached the same
starting room, look/quit both worked. Zero errors in debug.log
for the entire session (confirms the message()/tell_room()
forward-declaration fix is fully effective, not just partially).
All three characters' save data confirmed written to disk:
data/login/q/{qinfeng,qinling,qinhuai}.o and
data/user/q/{qinfeng,qinling,qinhuai}.o.
Gotcha hit twice while testing (worth flagging for future libs): using
a login id containing a digit (qinfeng2, qinfeng5) fails
check_legal_id's letters-only check, and the resulting rejection loop
silently consumes every subsequent --send argument as a retry attempt at
the SAME prompt — by the time the script runs out of arguments, the
session is stuck mid-flow with no obvious error. Not a mudlib bug (the
letters-only id rule is intentional and correctly implemented) — just a
reminder to keep test ids simple/pure-alphabetic.
lpcc sweep result
10747 / 10756 = 99.92% pass (9 failures, all confirmed non-bugs/ content gaps documented above — none affect boot, registration, or normal gameplay reachable from the tested paths).
Files changed (relative to libs/yanhuangwuhun/work/)
adm/simul_efun/chinese.lpc— §15his_chinese()fixadm/daemons/logind.lpc— §15hcheck_legal_name()+ combined-length fixadm/daemons/named.lpc— §15h deep fix (PATH macro + sliding window)adm/daemons/securityd.lpc— §15n compile-time-access allowlistadm/single/master.lpc— §14valid_override3-arg upgradeadm/simul_efun/message.lpc— §15s guard + forward declarationadm/daemons/eventd.lpc,adm/daemons/storyd.lpc,adm/npc/luban.lpc(2 sites) — extension-rename-width[0..<3]→[0..<5]fix- 60 files (105 occurrences) — reverted
static/nosavestring-literal collateral (see list logic above; not itemized individually here, all were"static/..."-shaped log paths or dbase property key names) inherit/condition/damo.lpc— §10 missing quote + bracket-mismatch fixinclude/globals.h— addedTEXT2PIC_Dmacroinclude/armor.h— addedTYPE_CHARMmacrod/death/npc/mamian.lpc— §9 fullwidth-paren fix (14 occurrences)kungfu/skill/riyue-bian/chan.lpc— missing local var declarationskungfu/skill/kuihua-mogong/perform/wswd.lpc— missing semicolond/baituo/obj/bowl.lpc—set_name()argument type fixd/beijing/npc/dan/danB_6.lpc— removed duplicate functioncmds/help2.lpc— §15f barearray→mixed *(2 declarations)kungfu/class/generate/spekilled.lpc— wrongquery()call convention fixed tocall_other
2026-07-23: driver rebuild retest + LPC formatter + WASM check
- Formatter: ran
tools/lpc-syntax'sformat-corpus.mjsover all 10756.lpcfiles inwork/; 10722 written, 30 already-conformant, 4 errors (files it refused to touch). Found a real formatter bug while spot-checking: the formatter corrupts a same-line::PARENT_FUNC(...)call when theif (condition wraps across the closing paren onto its own line — it splits::into: :across a line break and drops the matching close-paren, producing invalid syntax (if (: : move(dest, silent)\n)\n{ ... }, an extra stray}left dangling). This is a bug in the formatter itself, not a lib-specific issue — the exact same corruption pattern was found and fixed in 2 other files in *this* lib (inherit/item/task.lpc's::move,kungfu/class/huashan/yue-wife.lpc's::recruit_apprentice) plus 2return (::FUNC(...))-shaped variants (kungfu/skill/{biyun-xinfa,sanku-shengong}.lpc's::valid_learn,d/fuzhou/mishi.lpc's::valid_leave), and independently in 5 sibling libs in this same pass (xlqy_early/xlqy_new2007's sharedd/sky/xitian.lpc,xo_final'ssystem/daemon/user.lpc, 4 files inxuanjianlu,yhyxs's own copies of this lib's 2combined.lpc/yue-wife.lpcbugs, and 18 files inylfyxa3). Fixed all 6 instances in this lib by hand (restored the original::FUNC(...)call and matching brace structure, verified byte-for-byte against the pre-format git blob to make sure the original control flow — e.g.combined.lpc'sreturn 1staying *inside* theif (::move(...))block, not hoisted out — was preserved exactly), then re-ran the formatter over just those files, which now formats them correctly (confirms the bug is specifically the line-wrapped variant, not::in general). Verified all 3 files compile clean vialpcc. Worth reporting upstream to whoever ownstools/lpc-syntax— this is a real, if narrow, formatter regression risk for any::-heavy mudlib, not specific to this batch. - Native retest: rebuilt
~/src/fluffos/build-debug/src/driverbooted clean after the formatter-bug fixes above (zero fataldebug.logerrors). Full registration re-verified with a real Chinese name (秦岭, idqinlingnewto dodge a stale same-session name collision from an earlier throwaway attempt): id/confirm/surname/ given-name/admin-password/password/type/gender all completed, landed in 世外桃源 exactly as the original pass found;lookcorrectly re-displayed the room,quitgave the correct farewell. Zero real debug.log errors. - WASM: booted with the expected non-fatal
socket_*/"Undefined function" preload noise (missingsocketspackage). Found a real, reproducible WASM-specific registration blocker:adm/daemons/ logind.lpc'slogon()calls!VERSION_D->is_version_ok()directly (uncaught — unlike the immediately-precedingcatch(MUDLIST_CMD-> main())on the line above) as part of printing the login banner, *before* the username prompt. Sinceadm/daemons/versiond.lpcusessocket_create/socket_bind/socket_listenand fails to compile entirely under this WASM build (nosocketspackage), callingVERSION_D->is_version_ok()throws "*No program in object" — and because this call is unguarded, the error abortslogon()entirely right there, so the username prompt itself never appears and registration cannot proceed at all under WASM. Confirmed reproducible across multiple attempts/timeouts (60s+); confirmed this is NOT present natively (versiond compiles fine there, full playthrough above was clean). This is a different (and more severe) manifestation of the same documented "no sockets package under WASM" restriction — not a mudlib bug (native is completely unaffected) and not thequery_ip_number()limitation either. Not patched (would require either adding acatch()around a call the mudlib author didn't guard, or a driver-level sockets stub, both out of scope for this smoke-test pass) — documented here and in the README as "does not boot into registration under WASM" rather than "playable." UPDATE (WASM-enablement pass): now patched — see next section; both VERSION_D call sites arefind_object()-guarded per the new §1.3c policy, which should unblock WASM registration (needs a WASM re-test to confirm).
WASM-enablement pass (loopback-allow / gate bypass / admin seed)
Standard WASM-first pass per AGENTS.md §1.3b/c/e and §1.5. Gates patched:
adm/daemons/band.lpcis_banned()(~line 38) — loopback / empty / malformed-IP short-circuitreturn 0;at the top.adm/daemons/logind.lpc— addedis_loopback_conn(object)helper, and:
- logon() BAN_D->is_banned() gate (~line 75) — loopback exempt.
- logon() same-IP multi-login cap (iplimit > 9, ~line 106) —
loopback exempt.
- the WASM registration blocker: both unguarded
VERSION_D->is_version_ok() call sites (banner ~line 87, get_id
hard gate ~line 161) now guarded with find_object(VERSION_D) —
daemon absent (as under WASM, where versiond's sockets usage keeps
it from compiling) ⇒ notice/gate skipped. This was the documented
"no id prompt under WASM" hard blocker.
- No uptime() startup-grace gate or registration-rate throttle in
this lineage's logind (MAX_USERS capacity cap left intact).
Admin account seeded: id fluffos, 普通密码(login pw) Mud@2026,
管理密码(recovery pw) Admin2026, display name 浮浮 (surname prompt
skipped with bare ENTER — the lineage's surname+given-name split flow
rejects 姓=名, so "浮"+"浮" does NOT work; skip the surname instead).
Granted (admin) via fluffos (admin) appended to adm/etc/wizlist.
Verified: real registration flow end-to-end into 世外桃源, relogin →
update /adm/daemons/band → 成功 (score correctly says 还没有出生
until the newbie quality-selection is done — game design). Retest:
fresh normal registration (姓 秦 名 风, f) end-to-end, look/quit
correct; test char saves removed; zero new debug.log errors.
Save files for the orchestrator to add (none gitignored, normal add):
libs/yanhuangwuhun/work/data/user/f/fluffos.olibs/yanhuangwuhun/work/data/login/f/fluffos.o
Fail-closed retrofit for the loopback-allow gate (2026-07-24)
The loopback helper above was originally written matching the
project-wide convention at patch time (AGENTS.md §1.3b), which also
treated an empty/non-string/malformed query_ip_number() result as
loopback, defensively, because the WASM driver used to return garbage
there. That underlying driver bug is now fixed (fluffos commits
e33bb5da "fix: query_ip_number() returned uninitialized garbage under
WASM" and 007bb863 "feat: synthetic resolve() on WASM instead of
raising an LPC error", both 2026-07-23; the locally-built
build-debug/build-wasm binaries already postdate both commits), so
treating unparseable IPs as trusted is a fail-open gap with no remaining
justification. Retrofitted to fail-closed: loopback is now strictly
ip == "127.0.0.1" || ip == "::1" || ip[0..3] == "127." (with a
stringp() guard before the slice) — a malformed/empty IP now falls
through to the NORMAL gate instead of being treated as local. Retested
after tightening: fresh driver boot clean, fluffos loopback login and
its wizard update command both still work; zero new debug.log errors.
WASM 修复摘要(迁移自 meta.json 的 group_note)
yh2003 代码库基础版(炎黄武魂Ⅱ)。状态已从过时的 limited 修正——本轮找到并修复了一个真正的 bug:adm/daemons/logind.lpc 的 check_ok() 在每一次成功登录时都未加保护地呼叫 MESSAGE_D->find_chatter(),而 MESSAGE_D(adm/daemons/network/messaged.lpc)在 WASM 下编译不过(原始的 socket_create()/socket_bind() 呼叫,sockets 包不可用)——由此产生的未捕获'No program in object'运行时错误会在 check_ok() 执行到一半时中止,静默地把连线留在一个损坏状态,之后每一条指令(包括 quit)都回显'什么?',从未真正进入任何房间。已用 find_object(MESSAGE_D) 保护这个呼叫来修复(手足档案 yhyxs 上也应用了同样的修复)。修复后重新验证干净:管理员登录(fluffos/Mud@2026)正常进入游戏世界,'目前权限:(admin)',quit 正常。
深度功能测试(§10.7,2026-08-04)
原生 driver(端口 40060)跑了一遍超出注册流程的完整游玩。这份档案
和它的手足档案 yhyxs(yh2003 血统)几乎共享一切——注册流程逐字
一致,help/newbie 只有示例人名/颜色码的差异,help rules /
clone/game/{8,21}_hlp 三个文件是逐字节相同的内容(见下)——但注
册细节上有一处真实差异:这份档案的天赋重掷指令是 washto <膂力>
<悟性> <根骨> <身法>(一次性直接指定四项数值,总和必须为 80,
每项 13-30 之间),不是 yhyxs 的那种"随机结果 + wash 重掷"交
互式流程——照抄 yhyxs 用法直接输入 wash 会被解析成一个别处也
存在的通用"洗手"动作("你洗了洗手。"),不是这份档案的属性系统,
容易误判为 bug,实际是这条血统内部的一次真实分支演化,读源码
(d/register/yanluodian.lpc)之后才搞清楚正确用法。
主动检查:adm/daemons/logind.lpc 没有 §7.34 printf 残留,没
有 §8.9 食物/饮水按错误对象 age 初始化的问题(写法本来就正确),
MESSAGE_D->find_chatter() 已经用 find_object(MESSAGE_D) 包住
(这份档案自己 WASM 修复阶段已经修好,本轮确认仍然正确)。
发现并修复的问题(详见下方分类):
1. §7.68 复活软锁死,命中数量创下这批测试的记录:六个死亡系统
NPC 文件。这份档案有两整套死亡系统:d/death/(include/
login.h 的 DEATH_ROOM 宏实际指向 /d/death/gate,是真正在游
戏里生效的一套)和 d/death22/(没有任何代码路径引用它,和一
个同样从未被引用的 adm/daemons/logind2.lpc 配对,是这份归档
里附带但从未接线的整套备用/旧版内容)。d/death/npc/
{hei,bai}.lpc(活的) 和 d/death22/npc/{hei,bai}.lpc
(死代码,不可达) 都有同样的
if (!ob || !present(ob)) return; 复活软锁死守卫,全部四个都按
已验证的修法拆分修复(d/death22 那两个虽然当前不可达、无法现
场验证,但如果这套内容未来被重新接线,修复已经提前到位,成本
很低)。
2. 一个更有意思的、真正只存在于死代码里的独立 bug:d/death/
npc/{wgargoyle,bgargoyle}.lpc("gargoyle"命名风格,和活的
hei.lpc/bai.lpc 是同一批"黑无常/白无常"角色的另一套旧版实现,
同样没有任何房间引用它们,属于死代码)除了同样的 §7.68 守卫之
外,bgargoyle.lpc 的 init() 还有一处反向写反的条件:
!wizardp(previous_object()) ——所有其它姊妹文件(包括同目录的
hei.lpc)都是不带 ! 的 wizardp(previous_object())(意思是
"如果来的鬼魂是巫师就放弃处理,交给巫师自己的复活流程"),唯独
bgargoyle.lpc 反过来写成"如果来的鬼魂不是巫师就放弃处
理"——也就是说,如果这个文件真的被接上房间,普通玩家死亡后走
到这个黑无常面前,init() 会直接 return,call_out("death_stage"...)
永远不会被排上日程,复活序列压根不会开始,普通玩家会永久卡成
鬼魂(只有巫师能被正常处理)。因为这个文件本身就是不可达死代
码,这个 bug 现在完全不会触发,没有做任何修改——按 AGENTS.md
已有的"confirmed unreachable"惯例记录,不当作需要修复的活跃
bug,只作为一个有趣的历史存档(大概是这条血统在从"gargoyle"命
名迁移到"hei/bai"命名的某次重构里引入的笔误,新文件修对了,旧
文件的笔误就一直原样留在归档里)。
3. 和 yhyxs 完全相同的 extensionless GBK 文本残留 bug(AGENTS.md
§4.1 已归档条目的第二个具体实例):help/rules、clone/game/
{8,21}_hlp 三个文件,用 Python 做全树 UTF-8 解码扫描后发现内容
和 yhyxs 对应文件逐字节相同(diff 完全无输出),证实这
是两份姊妹档案共享的、从未被转码的同一批原始内容。用相同的
iconv -f GB18030 -t UTF-8 转换,现场用 help rules 验证显示
正常。
发现但确认不是 bug,特意未做修改:d/register/yanluodian.lpc
第 57 行 paizi 提示牌文字"washto选好天赋之后"缺少分隔标点("活
的"版本和它自己的 .bak 死代码副本里写法完全一样,确认是原始存
档里的笔误,不是转码流程造成的)——因为不确定原文缺失的具体标点
是什么(逗号?空格?),按"不要凭空编造内容"的原则未做任何修改,
只在此记录。washto 本身是真实生效的指令(不是打字错误),只是
提示牌上的说明文字标点缺失。
注册与游玩:注册测试角色(秦皇 / id qinhuang),走到"花铁
干"处选性格,washto 20 20 20 20 拿到均衡天赋,born 扬州人氏
投胎,落在扬州客店,食物/饮水 233/300(§8.9 修复生效的直接证
据)。角色带有"武林外传"这本书和先天技能"玄黄聚纳/周天运转/铜皮
铁骨"(和 yhyxs 的角色不同,这条血统的具体门派/技能设计是独立
内容)。
战斗+死亡+复活测试(第三次真实死亡+undisturbed 完整现场验
证):北大街的"欧阳克"(和 jyqxc/yhyxs 里的是同一个反复出
现的固定布景反派角色)。第一次交手把测试角色打到半昏迷但侥幸逃
脱未死;重连时踩到了这条血统的"网络异常断线后短暂拒绝立即重连"
锁定窗口——第一次尝试在异常断线后几秒内立即重连卡在"请输入密
码:"没有任何后续响应,等待接近一分钟后才收到"重新连线完毕"并正
常继续,不是新的驱动级 hang/crash,是已有惯例记录过的"退出/断
线后有一段锁定窗口"现象(第一反应怀疑是又一次 §10.8 类崩溃,
用一个全新 id 的并行连线确认 driver 本身完全正常响应后排除了这个
可能)。第二次交手,角色试图 wimpy 自动逃跑时被欧阳克主动封死
退路("你见势不妙,转身想要逃走。却见欧阳克飞身一闪,已将你的退
路封死。"——比之前几次姊妹档案的战斗多了一个新细节:够强的对手
能主动拦截逃跑,不是每次都能全身而退),连续两下重击(77点+45点
创伤)后被"活活冻死了"(和 yhyxs 一样,战斗伤害叠加当时降雪环
境效果导致的死亡flavor)。死亡后送到鬼门关,"白无常"(刚修复的
活的 d/death/npc/bai.lpc)在场,没有主动打断复活序列,等待
完整走完后重连确认:角色已复活、站在"武庙",hp 显示气血满血
100/100、精气 63/100(仍在恢复中)、潜能从 99 减半到 50(符合死
亡惩罚)。这是本轮系列测试第三次(前两次是 jyqxc/yhyxs)现场
完整验证 §7.68 修复后 undisturbed 路径的正确性。
quit 正常退出("欢迎下次再来!"),driver 全程存活,没有触发
§10.8 类崩溃(和上一次 yhyxs 会话不同)。debug.log 全程没有
真实的 error:/denied/Bad argument/Too deep recursion 行。
formatter 检查(所有改动文件均已是干净格式,无需重排版)、
git status --short libs/yanhuangwuhun/ 复查均确认改动范围干
净——只有七处源码修改(三处 GBK→UTF-8 转码 + 四处 §7.68 修复)是
跟踪变更,测试角色的新存档保持未跟踪、未提交。
更正(2026-08-05):§7.68 复活软锁"修复"已撤销
上面提到的"鬼魂离开/不在场时被永久放弃复活流程"曾被当作 AGENTS.md
§7.68 记录的一类 bug 修复(把单次判定改成每 5 秒重试)。经用户指出并
重新审视:这更可能是有意的游戏设计,不是 bug——大多数这类档案里
鬼魂根本无法自行移动,所以"不在场"要么从未真正发生,要么是"离开去
在阴间游荡,想回来时再走回这个房间、流程会通过 init() 重新从头开始"
这种有意为之的宽松机制,而不是需要强制追上玩家的错误。强行重试还可能
引入新问题:如果鬼魂之后又走回这个房间,旧的重试和 init() 重新触发的
新一轮流程可能同时运行,导致对话重叠错乱。已把这处改动撤销,恢复成
原始的 if (!ob || !present(ob)) return; 单次判定写法(bmxkx2001
除外——那份档案里这确实是一个真实存在、经过实际复现验证的 bug:鬼魂
本身完全无法移动,是另一个不相关的 NPC 强行把鬼魂拖走导致的)。详见
AGENTS.md §7.68 顶部的撤销说明。
§7.86 跨库扫描修复(留言板 post 崩溃)
BULLETIN_BOARDinherit+ 多余replace_program()致命形状(AGENTS.md §7.86,post命令崩溃):全档案 61 处命中,已删除多余的replace_program(...)调用(保留inherit),逐文件保留原有行尾格式(CRLF/LF 按文件原样)。本次为跨库 §7.86 扫描修复(触发原因:该 bug 已在 6+ 个互不相关的血统家族独立确认,属于近乎普遍的拷贝粘贴模式),仅做编译检查(驱动干净启动、端口正常监听),未做完整 §10.7 深度游玩测试。
AGENTS.md §7.100 修复(2026-08-19,批次三)
ROOM 基类冗余 replace_program(ROOM); 自崩溃地雷(详见 AGENTS.md
§7.100):3370 处命中。自带建房工具 clone/misc/roommaker.lpc 的
字符串拼接模板同样修复。
git diff --stat:3369 files changed, 1 insertion(+), 3370 deletions(-),
与预期精确吻合。
验证:build-debug 驱动真实冷启动,端口 40060 正常监听。既有管理
员账号 fluffos/Mud@2026(姓氏栏留空跳过)登录,目前权限:
(admin),世外桃源→桃源茅屋→世外桃源多房间走访无误(与 yhyxs 共
享同一份注册区场景内容,同样改用固定间隔裸 socket 脚本规避活动时
钟提示符),quit 干净退出,全程无新增 "cannot replace"/"cannot
bind" 日志行。
§7.30 uninitialized-mapping accessor sweep (2026-08-20)
Corpus-wide mechanical sweep of the feature/skill.lpc shared-lineage
bug (confirmed independently on xiakexing2017/jqxz2015/haiyang2
via round-four testing): 5 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.
§7.125 sibling-sweep fix: premature set("registered", 1) defeats the registration gate (2026-08-28)
Flagged in AGENTS.md §7.125 as a sibling worth checking (originally
found on zhyx, same yh2003/ES2 lineage). Confirmed byte-identical:
adm/daemons/logind.lpc's enter_world() unconditionally ran
user->set("registered", 1); //user->set("born",1); right after
handing out starting clothing, on every login — permanently
short-circuiting the register-room's valid_leave() gate
(d/register/room{w,s,n}.lpc, "你还不快注册?") and channeld's
registration check from a character's first-ever login onward, since
d/register/npc/shuisheng.lpc's do_decide() (the correct, sole
place this flag should be set, confirmed present and correct in this
lib too) could never matter — the flag was already permanently 1
before the player ever got a chance to register. Fixed by deleting the
premature line in enter_world(). Verified via a clean native driver
boot only (not an independent live walk-out-of-the-room reproduction
on this specific lib — the bug shape and remedy are a verbatim port of
an already live-verified fix from the shared-lineage sibling zhyx).
深度功能测试(2026-09-03,第三轮)
新角度:2026-08-04 第一轮做了注册 / washto / 战斗死亡,没测商店
和拜师。手足 yhyxs 2026-09-01 的路径可直接套。
- 既有
fluffos(admin) 卡在/d/register/entry(registered=1 但从未投胎,score报「还没有出生呐」)。west到花铁干选「阴 险奸诈」,out进阎罗殿,washto 20 20 20 20,born 扬州人氏落地扬州客店。客店店小二不是 vendor(和yhyxs一样)。 - 商店:
goto /d/city/zuixianlou,npc/xiaoer2list列出牛 皮水袋/干粮/包子/烤鸡腿/烤鸭/牛皮酒袋。clone /clone/money/gold后buy jitui成功(「你从店小二那里买下了一根烤鸡腿」),一两 黄金找零成九十九两白银 + 二十文铜钱。 - 拜师:
goto /d/gaibang/inhole,bai li(黎生,无战力门槛) 「我便收你为徒」→ 丐帮第二十代弟子 / 小叫花,师父是黎生。save+quit后重连,score仍是「丐帮第二十代传人 / 师父是 黎生」,银钱仍在;烤鸡腿未随存档回来(食物常见no_save)。 - 日志:本轮 live
debug.log是libs/yanhuangwuhun/log/debug.log(Boot Time Thu Sep 3 21:23:29 2026)。无error:/Too deep recursion/No program。没有 单独的 mudlibwork/log/log。 - 结论:商店 / 有机拜师 / 重连均通过,本轮无新编程 bug 可修。
深度功能测试(§10.7,2026-10-04)— negative range ends
scripts/lpc_fix_negative_ranges.py: 4 line(s) in 1 file(s) count a range from the end with < (x[a..-1] -> x[a..<1], x[-2..] -> x[<2..]; KB 06 §7.209). In this driver a negative constant end gave "" / ({ }) and a negative start the whole value, so each of these returned the wrong slice; the compile warning A negative constant as the second element of arr[x..y] is gone from the files that compile. Range lvalues (s[0..-1] = text, the prepend idiom) are left alone. A paired compile of the changed files at HEAD and in the working tree showed no new error.
深度功能测试(§10.7,2026-10-05)— 房间列出的物件缺档时房间照常加载
房间基类 inherit/room/room.lpc:make_inventory() 用 catch() 包住 new(file),做不出来就返回 0;reset() 的 case 1: 拿到 0 就跳过这一项(if (!objectp(ob[list[i]])) break;)。档案里没有的 NPC 或物品(或 create() 出错的物件)原先会让列出它的房间整个加载失败(Bad argument 1 to environment(),或对 0 的 call_other()),连带这个房间后面的区域;现在房间照常加载,只是少了那个物件,下次 reset() 再试(KB 05 §7.25;scripts/lpc_resilient_room.py、scripts/lpc_room_reset_guard.py)。
验证:探针(scripts/lpc_room_reset_probe.py:房间基类列出一个不存在的物件,再调用 reset())HEAD 单件 崩溃、多件 崩溃,工作树 单件 OK、多件 OK。
深度功能测试(§10.7,2026-10-06)— 与 zhonghua2 同源的三处编译警告
cmds/std/swear.lpc、cmds/std/team/swear.lpc:结义失败提示被多余的;截成两句,fail只剩"……可惜现在有人不在,$N",后半句"的提议只好作罢。"丢了;接回去。
验证:改动的文件和包含 npc/indian 的守护进程在 HEAD 与工作树分别加载(scripts/lpc_listcheck.sh,新进程),无回退。
深度功能测试(§10.7,2026-10-08)— 编译警告整理
scripts/lpc_warnings.py yanhuangwuhun --fix 加 scripts/lpc_fix_no_effect.py --apply,共改动 486 个 .lpc 和 14 个 .h(多为删去未用的局部变量)。HEAD 与工作树分别加载(新进程):484 -> 484 通过,无回退;改过的头文件的 24 个包含者 23 -> 23 通过。启动时警告 2 -> 0;新进程登录(输入名字)正常。
深度功能测试(§10.7,2026-10-08)— .lpc 后缀的定宽切片
.c 改名 .lpc 时只改了字符串没改切片宽度:f[<2..] == ".lpc" 拿两个字符比四个字符,永远不成立(!= 永远成立),按后缀筛文件、去后缀的代码因此从不运行或截成 x.l(KB 06 §7.238)。scripts/lpc_lpc_suffix_slice.py --apply 改了 1 处比较、0 处去后缀(如 adm/daemons/huanjing2003/room_master_hj.lpc);改动的文件 HEAD 与工作树分别加载(新进程),无回退。
深度功能测试(§10.7,2026-10-11):“无副作用表达式”警告复查(批 6)
- 补齐前几批漏掉的同码副本:
your_temp["guarding"];补= 0(反击后清除防守姿态,含u/下的 combatd 拷贝);(: WEAPON_D, "query_action" :)改为(: call_other, WEAPON_D, "query_action" :)(KB 04);mysql_d.lpc的空MSG宏改成空函数;gigicook.lpc的arg == menu_list[0]改为=。 - 改动文件:adm/daemons/combatd2.lpc
- 改动的对象 HEAD 与工作区都能载入,无回退。
深度功能测试(§10.7,2026-10-11):dns_master 空 if
adm/daemons/network/dns_master.lpcquery_services():if (! (mud_svc[mud]["tell"/"finger"] & SVC_KNOWN)) {里只有#if PREF_X & SVC_TCP … #endif,选项关闭时 if 体为空(“无副作用”警告);把#if/#endif挪到 if 外面(KB 04 §6.10,2026-10-07 那次扫描漏掉了! (带空格、大括号另起一行的写法)。载入无回退。
深度功能测试(§10.7,2026-10-11):dns_master 空 if
adm/daemons/network/dns_master.lpcquery_services():if (! (mud_svc[mud]["finger"/"tell"] & SVC_KNOWN))块里只有#if PREF_X & SVC_TCP … #endif,选项关闭时 if 为空(“无副作用”警告报在下一句);把#if/#endif挪到 if 外面(KB 04,2026-10-07 那次扫描漏了! (加括号换行这种写法)。载入无回退。
- 2026-10-12:
clone/misc/swmuding.lpc(神木王鼎)自己声明了一张mapping insects虫表,与继承的clone/misc/muding.lpc的insects同名;读表的是木鼎的代码,读到的是木鼎自己的表,神木王鼎的虫表从来没用上(Redeclaration of global variable 'insects')。改名sw_insects,create()里insects = sw_insects;交给木鼎(nitan170911、wxddym、zjdy 系同修)。HEAD 与工作树各载入一次,regress 0。
编译警告收尾(2026-10-12)
scripts/toolkit_fix.sh 一轮后剩 52 条,手工清零(改动及 d/gumu/obj/fengmi、cmds/std/eat 在 HEAD 与工作树各载入一次:15 个,HEAD PASS 14,tree PASS 14,regress 0)。
adm/daemons/huanjing2003/的四国 NPC/宝物与room_readygo_hj.lpc:一条声明里同一变量先裸声明、再带初值声明,驱动造出两份;scripts/lpc_fix_double_decl.py去掉裸的那份(44 处,9 个文件),运行时不变。feature/food.lpc、feature/liquid.lpc的do_effect()是void,而重载它的蜂蜜d/gumu/obj/fengmi.lpc、d/xiakedao/obj/pigpart.h返回int,eat/drink对only_do_effect物品用这个返回值做命令结果:基类改varargs int do_effect(object me),返回 1(同 nitan3)。adm/daemons/network/cmwhod.lpc五个函数用STATIC_VAR_TAG(nosave)修饰,改protected;adm/daemons/vrm_server.lpc多余的;删去。
- 2026-10-14:新驱动(FluffOS 970d9f09)报
Float value truncated to int(#1426)。1 个文件 1 处:赋值、初始化、return 改写成to_int(...)(值不变,只是写明截断)。改动的对象新进程各载入一次,无回退(scripts/lpc_fix_float_trunc.py,KB 04 §6.10)。
负数伤害当作消耗(2026-10-15,KB 06 §7.241)
receive_damage("neili", -52)、receive_damage("qi", -12) 之类把 add() 的负数写进了 receive_damage():本库 feature/damage.lpc 对负数伤害报错(或归零),练功/运功时报 F_DAMAGE: 伤害值为负值 或消耗失效。已改为正数伤害,内力/精力类改为 add(type, -N)(scripts/lpc_fix_damage_calls.py):/kungfu/skill/duanyun-fu、/kungfu/skill/feifeng-whip、/kungfu/skill/pangen-cuojiefu。
内力/精力当作伤害种类(2026-10-15,KB 06 §7.241 第二类)
本库 feature/damage.lpc 的 receive_damage() 不接受 jingli/neili/force 等种类,me->receive_damage("jingli", 30) 之类在练功、绝招、吸取时报 F_DAMAGE: 伤害种类错误。4 处改为 add(type, -N)(scripts/lpc_fix_damage_calls.py 第二步)。
无门派玩家的 family 映射(2026-10-15,KB 05 §7.30 第三种)
mapping fam = ob->query("family"); 之后直接 fam["family_name"]:没有门派(新人或叛师后)的玩家在学习、练功、拜师、进入门派房间时报 Value being indexed is zero,而不是作者写好的提示。1 处在声明行加上 if (!mapp(fam)) fam = ([ ]);(scripts/lpc_fix_family_guard.py)。
技能按另一门武功的等级取招(2026-10-15,KB 06 §7.243)
这些技能文件是从别的武功复制改名来的,query_action() 仍用原武功的等级查招式表:只会本技能的人等级为 0,取不到招,每次出招都报错。改为读本技能自己的等级(scripts/lpc_fix_action_level.py):dacidabei-shou。
find_player() 只认在世界里的身体(2026-10-15,KB 07 §8.26)
simul_efun 的 filter_player() 加上 environment(ob):注册中途断线留下的、不在任何房间的身体不再被当成玩家,两个以上时 find_player() 不会再报 The player(<id>) has existed in the world.(wllz3 实测过的问题)。本库若注册流程不会留下带玩家 uid 的身体,这一改动不改变行为。
技能名拼错(2026-10-15,KB 06 §7.249)
query_skill() 里的技能名拼错了,或用的是本库改名前的旧名;本库没有这个技能,调用永远得 0:门槛(< N 就拒绝)永远过不去,相关功夫或绝招学不了、用不了;内功互斥(> N 就拒绝)从不生效;公式里这一项一直是 0。经汉字名(提示文字或中文名词典)或纯拼写差异(_/-、少一个连字符、相邻字母颠倒)核对后,改为本库的技能名(scripts/lpc_fix_skill_typo.py):choushui-zhang→chousui-zhang(chousui-zhang);cuhixiao-jifa→chuixiao-jifa(xiaoao-jianghu);hengshan-jianfa→hengshan-jian(/d/henshan/tianquan-hole);lenyue-shengong→lengyue-shengong(lengyue-shengong);matrial-cognize→martial-cognize(qiankun-danuoyi/nuoyi);taiji-shengon→taiji-shengong(taiji-shengong);yaowang-mishu→yaowang-miaoshu(yaowang-miaoshu)。
技能名拼错:技能文件里拼错自己的名字(2026-10-15,KB 06 §7.249)
技能自己的文件(或它的绝招目录)里,query_skill() 读的是差一个字母的自己的名字,永远得 0:“基本功夫要高过本技能”之类的限制从不生效,按等级取招、计算伤害的那一项一直是 0。改为本技能的名字(scripts/lpc_fix_skill_typo.py 的 self 判据):jiujin-shengong→jiuyin-shengong(jiuyin-shengong/perform/zhang);xuanyuan-arror→xuanyuan-arrow(xuanyuan-arrow)。
family 映射内联取下标(2026-10-15,KB 05 §7.30)
ob->query("family")["master_name"]、me->query("family")["family_name"](泥潭式为 query("family", ob)[...])直接对门派映射取下标:没有门派的人(新玩家、叛师者、大多数 NPC)在 NPC 的打招呼和问话、绝招的门派判断、房间的 valid_leave 里报 Value being indexed is zero,而不是得到拒绝。1 处(1 个文件)改为 dbase 路径查询 query("family/master_name"):有门派时值相同,没有时得 0;原有的判断照常生效(scripts/lpc_fix_family_index.py)。给映射赋值的写法未动。
回龙杖「神龙摆尾」从来用不出(2026-10-15,KB 06 §7.246)
if (!objectp(me->query_temp("weapon") || weapon->query("skill_type") != "staff")):括号放错,objectp() 包住了整个 ||,拿着兵器时 objectp(1) 为假,永远“双手应该持杖”;空手时又去读从未赋值的 weapon,报错。改为先存兵器再判断。
set_skill() 遇到本库没有文件的武功不再抛错(2026-10-18,KB 06 §7.256)
feature/skill.lpc 里的 set_skill()、map_skill()、prepare_skill() 碰到没有武功文件的名字就 error("F_SKILL: No such skill (…)"),调用它们的 NPC create() 整个中断:NPC 载入不了,刷出它的房间也少一个人。本库目前没有对象设了缺失的武功;三处都改成 return:这一门武功不给、不映射,对象照常载入,只是少了它(缺的武功本身仍是内容缺口)。(scripts/lpc_guard_set_skill.py)
武功名拼错的 NPC(2026-10-19,KB 06 §7.258)
set_skill("kunlun-shnfa", …)、map_skill("dodge", "shaolin-shnfa") 这样的调用把武功名拼错了:本库没有这个武功文件,有的是拼对的那个。以前这种 NPC 在 create() 里报 No such skill 载入不了;武功缺失时跳过之后它们能载入,可是少了那门武功(set_skill 被跳过,map_skill 映射不到,门派弟子用普通轻功/拳脚)。按核对过的对照表改正,共 16 处、10 个文件:jinyin-baiguzhao→jiuyin-baiguzhao(4 处)、changquana→changquan(4 处)、tiaji-jian→taiji-jian(2 处)、shenhuo-shengong→shenghuo-shengong(2 处)、taiji-shenfong→taiji-shengong(1 处)、yan-fly→yanfly(1 处)、zhoangnan-zhi→zhongnan-zhi(1 处)、jinwu-goufan→jinwu-goufa(1 处)。(scripts/lpc_fix_skill_names.py)
die_reason 的参数个数(2026-10-19,KB 04 §6.10)
/kungfu/condition/corpse_poison.lpc、/kungfu/condition/fire_poison.lpc、/kungfu/condition/freezing.lpc 里的 string die_reason() 覆盖了基类的 die_reason(string name),驱动报 Number of arguments to 'die_reason' disagrees with previous definition。补上 varargs,调用处不用改;改后与 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 文件。
被注释吞掉的语句(2026-10-19,KB 06 §7.274)
/d/baituo/obj/lingshezhang.lpc:set("wposition", "/d/baituo/obj/lingshezhang.lpc")被//*** ADDED BY SCATTER ***注释吞掉
scripts/lpc_fix_swallowed_statement.py 把换行放回去。逐个载入与 HEAD 对比,没有退步。
补回本库没有的基类文件,第二轮(2026-10-19,KB 04 §6.15、§6.18)
宏有定义、基类文件却不在档案里:继承它的对象载入时报 Inherited file '…' does not exist!,编译扫描看不到这一类(scripts/lpc_missing_inherits.py 能列出)。同系的库里有同一个文件,原样拷来(scripts/lpc_restore_bases.py);基类和继承它的对象 include 而本库没有的头文件一起带来。每个基类补回后单独载入,再载入使用它的对象,载不进来、或一个用户也载不进来的撤掉了。
/inherit/medicine/pill←nte:1/1 个继承它的对象载入
逐个与 HEAD 对比载入,没有退步。
x != "a" || x != "b" 和 x == "a" && x == "b":同一个值的比较链永远成立/永远不成立(2026-10-20,KB 06 §7.282)
if (arg != "wan" || arg != "丸") return notify_fail(...) 对任何 arg 都为真,dir == "south" && dir == "north" 永远为假:条件下面的守卫要么永远拦、要么永远不拦。作者要的是“既不是 A 也不是 B”(&&)或“是 A 或 B”(||)。!= 链的 || 改成 &&(仅当条件下面是 return 的拒绝/守卫),== 链的 && 改成 ||(scripts/lpc_fix_cmp_chain.py)。具体是:cross pubu(穿瀑布)永远回答“你要往哪儿穿?”,瀑布后面的密室进不去。改动:/d/mingjiao/shanmen.lpc(1 处)、/d/tiezhang/hhyuan-3.lpc(1 处)。
member_array('/', str) 改为 strsrch(str, "/"):字符字面量的 member_array 按字节搜索(2026-10-20,KB 06 §7.283)
member_array('/', str) 里的 '/' 是整数,驱动按 UTF-8 字节搜索,返回字节偏移(带第三个参数时起点也是字节);最新的 FluffOS(923cdbc0)在字符串里有非 ASCII 文字时,对每个调用点警告一次(Warning: member_array(int, string) searches BYTES)。而 str[0..idx-1] 按字符切,中文字符串会在错误的位置截断。改为 strsrch(str, "/")(找不到同样返回 -1,按字符计数;scripts/lpc_fix_member_array_char.py,JSON 编码器等少数几处手改)。改动:/adm/daemons/vrm_server.lpc(1 处)、/cmds/arch/sameip.lpc(1 处)。
if (x = 常量):条件里写成赋值的比较(2026-10-20,KB 06 §7.290)
if (arg = "button" || arg = "按钮")、if (!arg || arg = "") return 0;、else if (check = 0 && tempB != ""):把 == 写成了 =,条件的值就是那个常量,分支对所有非零数和任何字符串(连 "" 都算)永远成立、对 0 永远不成立,变量还被覆盖;驱动对此没有任何警告。每一处 = 改成 ==(scripts/lpc_fix_cond_assign.py,共 1 处)。改动:/cmds/std/watch.lpc(1 处)。
登录密码超过 255 字节:crypt() 抛错(2026-10-20,KB 06 §7.294)
驱动的 crypt() 对超过 255 字节的密钥直接报错(Error in crypt(), check your salt),老驱动则按任意长度散列。在登录提示符下输入 256 字节以上的密码,密码检查那一行就抛错,连线停在一个裸的 > 提示符上,登录走不完(password 指令的旧密码检查同样);用 300 个 x 当参数的扫描发现的。/adm/single/simul_efun.lpc 里补了一个同名的 simul_efun crypt(key, salt):只有超长的密钥才被截短(先截到 255 个字符,再逐字符截到 sizeof(to_buffer(key)) <= 255,限制按字节算,一个汉字占三个字节),再交给 efun::crypt();普通密码原样散列,已存的密码散列不受影响(scripts/lpc_add_sefun.py crypt)。
get_config(__MUD_PORT__) 经旧版 runtime_config.h 得到字符串(2026-10-20,KB 06 §7.302)
本库的 include/runtime_config.h 是老 MudOS 的编号(整数设置从 15 起,本驱动从 256 起),get_config(__MUD_PORT__) 读到的是另一项设置(字符串),(int) 又只是编译期标注,于是 socket_bind(fd, LOCAL_PORT()) 报 Bad argument 2 to socket_bind(),版本守护进程 port = get_config(__MUD_PORT__) + VERSION_PORT 是字符串相加。头文件自己的注释写明 get_config(__MUD_PORT__) == __PORT__,所以代码里的这个调用(连同外面的 (int) / to_int())改成了驱动的预定义 __PORT__(scripts/lpc_fix_mud_port.py)。改动:/adm/daemons/versiond.lpc(1 处)、/include/getconfig.h(1 处)。
NPC 的 chat() 在 chat_msg 为空数组时下标越界(2026-10-21,KB 06 §7.334)
NPC 基类的 chat() 是 if (arrayp(msg = query(...))) { if (random(100) < chance) { rnd = random(sizeof(msg)); if (stringp(msg[rnd])) ...,不检查列表是否为空。本库现有的 NPC 文件里没有字面写成空 chat_msg 的(扫描只认 set("chat_msg", ({ })));守卫挡的是运行时才为空的列表和以后新增的 NPC。在 random(100) < chance 前面加 sizeof(msg) &&(scripts/lpc_fix_chat_empty.py;if (random(100) > chance) return 0; 的写法是 !sizeof(msg) ||)。改动:/inherit/char/npc.lpc(共 1 个文件)。
blockade / recover:data/keep 不存在,解封之后世界仍然锁着(2026-10-21,KB 06 §7.340)
管理员扫描里 blockade 报 Error copying file from /data/user/f/fluffos.o to /data/keep/fluffos, Error: No such file or directory,随后的 recover 在第一个 cp() 上死于 */data/keep/fluffos: lstat failed,来不及执行最后的 LOGIN_D->set_madlock(0):封锁解不开。data/keep/ 是运行时目录,git 克隆里没有空目录。blockade 在第一次写之前 if (file_size("/data/keep") != -2) mkdir("/data/keep");(mkdir() 失败答 0,不抛错),recover 对没有保存档的玩家 if (file_size(src) < 0) continue;,其余照常恢复、照常解锁(scripts/lpc_fix_keep_dir.py,hy5 上实测:没有保存档时 recover 答“时空解封完毕”,blockade 建出 data/keep 并保存,recover 取回并删除)。改动(2 个文件):/cmds/arch/blockade.lpc、/cmds/arch/recovermud.lpc。
注册到不存在函数的 add_action(2026-10-21,KB 06 §7.349)
add_action("函数", "动词") 绑定的函数,在对象本身、它包含的头文件、它继承的父类和继承它的子类里都没有定义(scripts/lpc_scan_callout_targets.py 静态解析,子类用传递闭包复核,scripts/lpc_verify_handlers.py 运行时 function_exists() 复核)。驱动从玩家最新的一条动作往回找,遇到这样的句子就报 *Function for verb 'drop' not found.,同一个动词的其他处理函数不再尝试(不是最新的一条就悄悄跳过)。删除了 7 条注册(6 个文件,scripts/lpc_fix_dead_add_action.py),动词留给别的处理函数:/adm/npc/referee.lpc(do_halt)、/cmds/usr/top.lpc(do_view)、/d/baituo/obj/shedan.lpc(do_pour)、/d/tianlongsi/munitang.lpc(do_exit)、/d/wudu/huxue2.lpc(do_train)、/inherit/misc/fboard.lpc(do_list)。最多的函数名:do_halt 2 处、do_view 1 处、do_pour 1 处、do_exit 1 处、do_train 1 处。
缺失物品的 new() / carry_object() 调用链加了保护(2026-10-22,KB 06 §7.73 补充)
new(路径)->move(...); / carry_object(宏("x"))->wear(); 这类语句,路径指向的文件在这个压缩包里没有:new() 返回 0,->move() 在 0 上报 Bad argument 1 to EFUN call_other()。在 create() 里这个对象永远加载不了,在 reset() 里第一个缺失物品之后的刷新每次 reset 都被跳过。1 个文件里 1 处(new)改成 { object new_ob = new(路径); if (new_ob) new_ob->move(...); }(scripts/lpc_guard_carry_object.py --new:路径按这个文件自己看到的宏解析,宏名冲突、虚拟对象路径一律跳过)。 对这 1 个改动文件做加载检查(HEAD 与工作区对比):HEAD 能加载 1 个,现在 1 个(新增可加载 0 个,回归 0 个)。
log/ 下的日志子目录没有人建:写日志的 write_file() / log_file() 报错(2026-10-22,KB 06 §7.358)
这个库的代码往 log/ 的 1 个子目录写日志:log/nosave(cmds/arch/recovermud.lpc)。压缩包、git clone 和站点包里都没有这些目录(本地启动没有写过它们,gen_keep_dirs.py 没记),write_file() 对不存在的目录抛 *Wrong permissions for opening file /log/dlog/money for append. "No such file or directory",调用它的函数在写日志那一行中断,后面的奖励、标志、步骤都没有执行。本库的 log_file() 是 write_file(LOG_DIR + file, text),目录不存在就抛同样的错误(实测)。把 log/nosave 记进 scripts/wasm_keep_dirs.txt(scripts/lpc_keep_log_dirs.py;站点和 pristine 树按它建空目录)。证明(scripts/lpcc_eval.py,在 /adm/daemons 这类目录下的求值对象里写 /log/zzdirprobe/...,新进程)见 KB 06 §7.358 的实测表。
汉字按字节切片的老写法没有换成按字符:改法名 "澄" + name[2..3]、辈分判断 name[0..1] == "澄" 等 17 处(2026-10-22,KB 06 §7.360)
原档按字节算字符串区间(一个汉字 2 字节):name[2..3] 是名字的第二个字,name[0..1] == "澄" 问名字是不是以「澄」开头。转成 UTF-8 之后,这个驱动的区间和 strlen() 都按字符算(strlen("澄观") 是 2,"澄观"[0..1] 是两个字),老算术原样留着、意思全变:拜入少林 / 武当 / 峨嵋等派的玩家被改成错误的法名(二字名 张三 变成一个字的 澄,更长的名字取到第三个字);各派掌门的辈分判断(name[0..1] == "澄")永远不成立;NPC 的称呼和提示里取到两个字而不是一个字。
本库 17 处(12 个文件):拼名字的赋值 10 处、与汉字常量比较 6 处、to_chinese()[..] 1 处。例:name[2..3] → name[1..1](/kungfu/class/emei/fengling.lpc:128);name[0..1] → name[0..0](/kungfu/class/emei/tobebonze.h:40);chk[0..1] == "你" → chk[0..0] == "你"(/adm/npc/ganjiang.lpc:544)。scripts/lpc_fix_gbk_slice.py 把下标按字符重算(社区的 UTF-8 版 xkx100utf8 里就是同样的写法,作对照);没有改的:截断(name = name[0..7],现在最多 8 个字,只是放宽)、ASCII 的区间(fname[0..3] == "room"、ctime(time())[4..19])和上下文看不出是汉字的区间。证明(scripts/lpcc_eval.py,bixiecanyang;其余各库是同一份文本):让澄字辈掌门 attempt_apprentice() 一个名叫「张三」的访客,HEAD 的法名是 慧,改后是 慧三;抽样 28 个库的 HEAD / 工作树加载对比 0 退步。工具不幂等([0..3] 折半得 [0..1],又是对齐区间),改过的文件记在 scripts/gbk_slice_converted.txt,不要重跑。
长度检查按字节写,旁边的提示按汉字写:2 处(2026-10-22,KB 06 §7.362)
老档的 strlen() 数字节(一个汉字 2 字节),转成 UTF-8 后它数字符:提示写「必须是 2 到 6 个中文字」的检查还是 strlen(name) < 4 || strlen(name) > 12,于是两三个字的房名、帮会名、群名、聊天室名、称号被提示自己说允许的那句话拒绝,上限却是提示的两倍;留言板的标题检查 i < 4 || i > 24 || i % 2 还会拒绝所有奇数个字的标题(post 你好吗)。本库 2 处(1 个文件):if ((strlen(name) < 4) || (strlen(name) > 12)) {(/adm/npc/luban.lpc:1778)。scripts/lpc_fix_strlen_gate.py 以提示为准:条件里每个 strlen 门槛都恰是提示所说数字的两倍才折半,存长度的变量(i = strlen(arg);)的门槛和 || i % 2 奇偶项、其后循环的 i % 2 == 0 && 一并处理;提示里有英文 / 字母 / 字节的不动。证明(scripts/lpcc_eval.py,bxsj 的留言板,求值对象继承 NPC 并重写 edit() 记录调用,command("post 标题")):HEAD 拒绝「你好」和「你好吗」、放行 23 个字的标题;改后接受前两个、拒绝第三个;shenmo 的 named.lpc invalid_new_name("张三"):HEAD 回 名字只能是2-4个中文字。,改后回 0。抽样 24 + 15 个库的 HEAD / 工作树加载对比 0 退步。
按字节写的汉字循环、茶馆猜诗和同盟频道标题(2026-10-23,KB 06 §7.363)
老档按字节做「一个汉字」:while (i--) if (i % 2 == 0 && !is_chinese(name[i..<0])) 只检查偶数下标,奇数位上的拉丁字母(张a)会过;茶馆猜诗 mixup() 用 strlen(str)/2 再 j=j+j、str[k..k+1] 交换两字节;泥潭系 channeld 的 switch (strlen(fname)) case 4/6/8/10 和 strlen(family)==4/6 按字节长度给同盟 / 门派名加空格。本驱动的 strlen() 和区间都按字符算。scripts/lpc_fix_byte_char.py:去掉奇偶项、把区间改成 name[i..i],按字符重写 mixup() 并把 strlen(first)>=14 折成 7,频道标题的 case / 门派长度改成字符数(对照 aoxiangtianji)。本库 汉字循环 / is_chinese 区间 2 个文件;channeld 同盟 / 门派标题 1 个文件。证明(scripts/lpcc_eval.py):sjplii 的 check_legal_name 在 HEAD 接受「张a」、改后拒绝,两边都接受「张三」;xkx100 的 clubpoem->mixup("离离原上草") 得到「离离原草上」(真交换汉字);nitan_san 两字同盟名得到 【 兄 弟 】。关键对象加载通过。
中文名 / 验证码仍按 GBK 取「两字节一字」(2026-10-23,KB 06 §7.373)
pname = pname[(random(sizeof(pname)) & 0xFFFE)..<1]; pname = pname[0..1]; 在按字符计下标时会取出两个汉字。scripts/lpc_fix_pname_slice.py 去掉掩码并把收尾改成 [0..0](pname/pname2/sec_name/str/str1)。本库 4 处。证明:nt1 生成名长度 2–4;HEAD 常见 3–5。
yuanwai 孤儿 call_out announce_success(2026-10-27,KB 06 §7.349 Also)
d/changan/npc/yuanwai.lpc(及 aoxiangtianji 的 d/city 副本)在 check_daughter 里 call_out("announce_success", …),但本文件从未定义该函数;同系也无实现。到点会 *Undefined function*。cry_daughter 已完成认亲与赠书,删除这对 remove_call_out/call_out。证明:扫描 HIT call_out→announce_success 且无定义;改后残渣 0。
深度功能测试(2026-10-27,§6.25 zhongling tell_object 引号错位)
d/wanjiegu/npc/zhongling(及同路径副本)的 tell_object("who, 钟灵脱下一双绣花鞋。\n") 把对象参数写进了字符串;改为 tell_object(who, "…")。证明:原文错位;改后加载,语料残渣 0。
深度功能测试(2026-10-27,§6.10 未知 pragma save_binary/optimize)
删除本库中 FluffOS 不认的 #pragma save_binary / #pragma optimize… 行。