Ultimate Demon Realm (nitan_ceshi)

✅ 可玩

泥潭III测试版 / 《終極魔界》

nitan_ceshi

🔑 fluffos / Mud@2026 更新 6b79392 2026-09-04 源码 下载 ZIP

▶ 开始游玩 · Play Now

站点内部配置自称"泥潭三"(nitan.3),但连线后看到的实际招牌是《終極魔界》("Ultimate Demon Realm")——一个套在"泥潭"引擎上的主题皮肤。属于 NT/nitan/Lonely 一脉(与本项目转换的 nitan170911、nitan6 同源),是这条脉络里比较早期的一个内部快照版本;与近亲 nitan_san 逐文件比对显示,两者在 `d/`(中原城市地图,如长安、北京、洛阳,以及峨嵋、华山、崑崙、恒山、嵩山五大门派和更外围的边疆地区)路径下约 98% 的同名文件字节完全相同,是同一份被写好的江湖世界;而内功心法、玩家指令、管理员守护进程等引擎层则分化明显(约三分之一文件不同),说明两份档案更像是同一套代码在不同时期各自独立留存的快照,而非各自从零编写。新角色取姓名、选性格、"洗"天赋点数后,由盘古在"生命之谷"(d/register)安排投胎——沿用盘古开天、转世投胎的创世神话——才算真正"出生"进入江湖,登陆后的常驻场景是客店一类的传统江湖据点;与同系的 nitan170911 不同,这一支不需要外部 MySQL 数据库,注册与存档全部走本地文件,开箱即可完整体验注册到游戏内的整个流程。

English

An early internal test snapshot from the NT/nitan/Lonely engine lineage (shared with sibling games nitan170911, nitan6, and nitan_san in this collection), internally labeled 'Mire 3' but branded in-game as 'Ultimate Demon Realm' — a thematic skin layered over the nitan engine. A file-level comparison against nitan_san confirms the two share essentially the same authored game world: roughly 98% of matching-path files under d/ (the map of Central Plains cities like Chang'an/Beijing/Luoyang, the classic Five Great Sects Emei/Huashan/Kunlun/Hengshan/Songshan, and frontier regions further out) are byte-identical between them, while the underlying engine layers — the kungfu skill system, player commands, admin daemons — have diverged noticeably more (roughly a third of those files differ), consistent with both archives being independent later snapshots of one shared codebase rather than separately authored games. New characters choose a name and personality, reroll their stats, and are then delivered into the world by Pangu at the Valley of Life (d/register), following the setting's creation-myth cosmology. Unlike its relative nitan170911, this branch needs no external MySQL database — everything runs on local files, so the full registration-to-gameplay flow works out of the box.

README

在线试玩

https://mudlibs.fluffos.info/nitan_ceshi/

管理员账号 / Admin account

警告:对外公开架设前请务必修改这两个密码。

本地运行

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

游戏端口:40054。文件数量较多,驱动启动后需要二三十秒完成预加载。

NOTES · 移植与修复记录

nitan_ceshi — 泥潭III测试版 / "终极魔界" (NT/nitan/Lonely mudlib lineage)

Archive: archives/泥潭III测试版.rar (archive #60). Port: 40054. Status: done (boots clean, connects, full registration flow verified end-to-end with real Chinese names reaching the actual game world — no MySQL backend needed here).

What this is

The mudlib's own config (adm/etc/config) self-identifies as internet mud name : nitan.3 — i.e. this genuinely is "泥潭三"/"nitan III", matching the archive's own title ("泥潭III测试版" = "Mud Pit III test version"). The live banner branding is actually 《終極魔界》 ("Ultimate Demon Realm") — a re-skin/theme layered on top of the "nitan" engine, same relationship as e.g. wmkj(#55)'s "自称wmkj但banner显示别的" case. A 小熊泥苑.txt readme in the archive root credits a separate hosting site ("小熊泥苑"/dtxy.126.com, author 小熊/torrow0812) — this is a *site*, not the mudlib's own name; kept the nitan_ceshi slug rather than renaming, since "泥潭III测试版" doesn't collapse cleanly to a single alternate title (noting here per the task's guidance to record any discrepancy).

Nested one level: the archive extracts to raw/nitan/ (not top-level), same as several other archives in this batch — work/ was built from raw/nitan/ directly so work/ itself is the mudlib root.

15,099 raw files / 13,497 .lpc after conversion — moderate-large, but not in the same "tens of thousands" mega-lib bracket as nitan170911 (#21, ~54,600 files) or nitan6 (#22, ~23,100 files).

Lineage confirmation

Confirmed same "NT/nitan/Lonely" engine family as nitan170911/nitan6 via diff against their raw archives, but this is an earlier/differently laid-out snapshot, not a byte-identical fork:

Crucially, the core sec.15 architecture bug does NOT apply here — verified by reading feature/dbase.c directly: it already has real, local set/query/delete/add/set_temp/query_temp/delete_temp methods (not just the storage variables), exactly the shape sec.15's fix prescribes for nitan170911/nitan6. adm/simul_efun/wizard.c here is a tiny 2-function file (wizhood/wiz_level) with no set/query/delete fallback at all — meaning this snapshot predates (or never had) the regression where those got demoted into a simul_efun fallback. Confirmed zero efun::set(/efun::query(/efun::delete(/efun::addn( call sites anywhere in this lib (the "trap inside the fix" pattern from sec.15 simply doesn't exist here). This made the single biggest fix-class from nitan170911/nitan6 a non-issue for this lib — most of the work here was a different set of bugs specific to this snapshot (below), not a rediscovery of sec.15.

Fixes applied (with why)

1. config.fluffos: master file/simulated efun file set to /adm/single/master / /adm/single/simul_efun (this snapshot's actual layout, not /adm/kernel/...). 2. adm/simul_efun/chinese.lpc's is_chinese() (sec.15h): GBK byte-range check (str[i] < 161, i % 2 alternating-lead-byte gating) rewritten as a CJK Unicode codepoint range check (0x4e00-0x9fff); min-length bound strlen(str) < 2 (bytes) → < 1 (chars). 3. adm/daemons/logind.lpc's check_legal_name() (sec.15h): internal strlen(name) < 2< 1; both call sites' maxlen argument check_legal_name(arg, 4)check_legal_name(arg, 2) (confirmed correct by the prompt text itself: "不要超过两个汉字" = "no more than two Chinese characters" = maxlen 2, not 4); combined surname+name length gate strlen(fname) < 4< 2. 4. adm/daemons/named.lpc (sec.15h, the PATH()/sliding-window family): #define PATH(name) (name[0..1] + ...) ("first GBK char", 2 bytes) → name[0..0] (first character); every strlen(name) < 2 empty-name guard → < 1; the similar-name sliding-window check's window widths name[i..i+3]/name[i..i+5] (2/3-GBK-char byte windows) → name[i..i+1]/name[i..i+2] (2/3-character windows), loop bound i <= l - 4i <= l - 2, inner i + 6 <= l guard → i + 3 <= l, and the length-4-bytes pre-check → length-2-chars. Verified directly: a single-character surname ("秦"/"林") and single-character given name ("风") both passed validation cleanly through to password setup on two independent runs. 5. master.lpc's valid_override() (sec.14): upgraded 2-arg (file, name) to 3-arg varargs (file, name, main_file), checking main_file against SIMUL_EFUN_OB/MASTER_OB too — free, low-risk, matches the documented apply signature. 6. master.lpc: added get_include_path() (sec.15o) proactively — wasn't defined at all; without it, a real VM-context compile triggered mid-connection gets no include path for angle-bracket #includes. Didn't visibly surface as a failure in this pass (this lib's own code mostly uses absolute quoted #include "/path.lpc" internally), but it's free/correct so kept it in rather than wait for it to bite later. 7. adm/etc/preload: commented out /adm/daemons/network/dns_master (sec.15p, standing policy) — intermud/cross-mud daemon, never needed for registration-flow testing, can hang boot. (No literal .c-suffixed entries needed sec.15c's fix here — this lib's preload file already stored bare extension-less paths.) 8. LONELY_IMPROVED-gated efun::X() calls to efuns that were never real on ANY driver we have (new sub-pattern of sec.15/15b — a #define LONELY_IMPROVED in include/globals.h, the *global* include file, means these branches are always compiled in, unlike a normal feature flag). Checked every real FluffOS .spec file (~/src/fluffos/src/packages/*/*.spec) to confirm each is genuinely absent, not just misspelled: - adm/simul_efun/util.lpc: sort_string, filter_ansi, file_crypt, file_valid each had a working pure-LPC #else fallback already written (just gated off) — flipped the guard to #if 0 so the fallback is always used instead of reinventing anything. - adm/simul_efun/message.lpc's sort_msg(): same efun::sort_string pattern, same fix. - adm/simul_efun/file.lpc's file_lines(): same pattern, same fix. - count_add/count_mul/count_sub/count_div/count_lt/ count_gt/count_le/count_ge/count_eq in util.lpc: these wrap a bespoke MudOS-fork arbitrary-precision bignum arithmetic efun (count(n1, op, n2)) that never existed on any driver in this project — but they're called ~1000+ times across this lib (currency/damage math) with no #else fallback at all, so this was a hard compile-blocker for simul_efun.lpc itself. Restored as ordinary 64-bit int arithmetic. First attempt used a bare (int) cast ((int)n1 + (int)n2) — this compiles fine but is WRONG on this driver: (int) is a type-assertion cast here, not a string-to-int *parse*, so a real call site passing a numeric string (count_mul(..., "50000"), hit during actual NPC stat setup — chard.lpc's setup_char()) crashed at runtime with *Bad argument 2 to * because the string reached the arithmetic operator unconverted. Fixed by routing through this lib's own atoi() simul_efun (intp(n) ? n : atoi(n)) instead of a bare cast — caught this by watching debug.log during interactive play, not from a static read. - binary_valid() in util.lpc: was gated #ifndef LONELY_IMPROVED (i.e. only compiled in when the special driver patch is *absent*) — but since LONELY_IMPROVED is unconditionally defined in this lib's global include, it never compiled at all, and adm/daemons/ versiond.lpc calls it unconditionally regardless of the flag ("Undefined function binary_valid", a genuine boot-time compile failure for versiond). Made the trivial return 1; stub unconditional. 9. adm/daemons/timed.lpc:349 (sec.15f): array localtime = localtime(realtime); — bare array as a full type-by-itself declaration; on this driver it silently fails to declare a usable variable, and combined with the initializer here it was a hard syntax error, unexpected L_DEFINED_NAME / Illegal LHS compile failure (blocked timed.lpc, which every connecting player's uptime/online-count banner line routes through). Fixed to mixed *localtime = localtime(realtime); (variable name shadowing the localtime() efun call on the same line is fine on this driver). 10. u/lonely/rmtree.lpc never wired into the simul_efun composition (new sec.15b-family gap): adm/daemons/updated.lpc and cmds/skill/invent.lpc call a bare rmtree(dir) simul_efun ("Undefined function rmtree" — hit live, right after gender selection, during new-character setup). A complete, self-contained rmtree/cptree implementation (recursive delete/copy using only real efuns: file_size/get_dir/rm/rmdir/mkdir/cp) already existed as a standalone object file at /u/lonely/rmtree.lpc but was never #included into adm/single/simul_efun.lpc. Added the #include rather than reimplementing — the existing code was already correct, just disconnected. 11. adm/simul_efun/message.lpc's message() wrapper (sec.15s): ~all internal callers (message_system(), etc.) invoke this 4-arg wrapper with fewer than 4 arguments; this driver pads the missing trailing arg with a raw int 0, and the real message() efun rejects that shape for its 4th ("exclude") argument — *Bad argument 4 to EFUN message(). This specifically broke the mudlib's own error handler (master.lpc's error_handler()message("channel:debug", ..., ob), only 3 args) — every single runtime error was itself crashing the error-reporting path, compounding into "Error in mudlib error handler" noise on top of the real error. Fixed once at the shared root: if (! exclude) exclude = ({}); before delegating to efun::message(). 12. clone/user/user.lpc:792: if (is_killing(ob)) — pre-existing lib typo. is_killing(string id) (defined in feature/attack.lpc) takes a string id; every other call site in this entire codebase (60+ checked) correctly passes ob->query("id") when calling from inside another object; this one direct (non-call_other, same-object) call passed the raw object instead — Bad type for argument 1 of is_killing (string vs object). Since this is a *direct* function call (not ->), the driver's static type checker enforces the declared parameter type strictly, and this single call site blocked /clone/user/user — the player body class — from compiling at all, silently breaking character-creation completion right after gender selection. Same-shape, same-impact bug as sec.15b's query_shadowed() finding on tianxia (archive #50) — "the player body class fails to compile" is now a recognized recurring failure mode worth checking first whenever registration input is accepted but the player never actually lands in the game world. Fixed to is_killing(ob->query ("id")), matching every sibling call site's convention. 13. adm/daemons/eventd.lpc and adm/daemons/storyd.lpc (new .c.lpc rename-fallout variant, extending sec.2): both do get_dir(DIR + "*.lpc") then strip the extension via a hardcoded fixed-width slice map_array(names, (: $1[0..<3] :)) — this cutoff (length-3) was correct for the *original* 2-character .c extension but leaves a trailing l on every entry now that the extension is the 4-character .lpc (e.g. "emei.lpc"[0..<3]"emei.l", not "emei"). This directly caused eventd.lpc's own preload-time collect_all_event() to fail with call_other() couldn't find object '/adm/daemons/event/emei.l' on every single boot (confirmed: 3 occurrences in log/debug.log, one per pre-fix boot attempt; zero since the fix). Fixed both to [0..<5] (cutoff moved by the same +2 the extension grew by). Not fixed (lower confidence, not observed failing, not exercised by the registration-flow test): adm/npc/ luban.lpc (2 occurrences) and cmds/adm/refsum.lpc (2 occurrences) use the identical [0..<3] pattern against what are very likely also .lpc-suffixed filenames (player-housing build tool / summon-list rebuild command) — flagged here for whoever next touches those features, per this project's "fix what a real failure surfaces, don't blind-sweep" convention (sec.15f/6b).

Confirmed NOT needed (checked, didn't apply)

Interactive test transcript / outcome

Two independent full end-to-end registration runs via mudclient.py (driver on port 40054, libs/nitan_ceshi/config.fluffos), each with a real 3-10-letter-lowercase login id, a y confirmation, a genuine single-character Chinese surname, a genuine single-character Chinese given name, admin password ×2, normal password ×2, and a gender letter:

Run 1 — id qinfeng, surname , name , gender male: banner renders correctly (UTF-8 Chinese intact, ANSI colors correct), uptime/ online-count lines print clean (no crash — these route through CHINESE_D/TIME_D), username validates, confirm-new-character prompt appears, surname/given-name both accepted on the first try (validating the sec.15h character-count fix), password setup (both admin and regular, with confirmation) completes, gender selection completes, player body (/clone/user/user) compiles and loads (is_killing fix), reaches 目前权限:(player). Verified via the actual saved data file (data/user/q/qinfeng.o): "surname":"秦","purename":"风","name":"秦风" — stored correctly, zero encoding corruption.

Run 2 (after the count_int/rmtree/eventd fixes above) — id linfeng, surname , name , gender female: identical flow, plus continued play afterward — look returns the actual starting room description ("注册房间" / Registration Room, with real email-registration-reminder text, a sign/look sign hint, and the new-player starter-gift notice), a second look re-displays it correctly, quit triggers the (intentional, non-bug — matches the documented sec.15j "anti-throwaway-account" family) "new account must stay online 30 minutes or it will be deleted, quit anyway? (y/n)" gate, and n correctly aborts the quit ("您选择了放弃退出(quit),继续游戏。"). Verified via saved data: data/user/l/linfeng.o"surname":"林","purename":"风", "name":"林风","gender":"女性".

Run 3 (reconnect test, after eventd/storyd fix) — re-connecting as qinfeng with the *admin* password correctly detected the existing account, prompted for the password, recognized the admin-password login path, and correctly demanded a normal-password reset before proceeding ("你采用了管理密码进入游戏,因此请你先修改你的普通密码。") — confirms the returning-player login branch (not just fresh registration) also works.

log/debug.log across all runs shows only two categories of non-blocking, pre-existing (not driver-compat) noise, both confirmed via direct code read, neither touched by registration/login:

lpcc sweep

Not run. 13,497 .lpc files — smaller than the nitan170911/nitan6 mega-lib bracket, but per AGENTS.md sec.6b's xo_final precedent (only 7,174 files, already drove the host to ~214MB free / heavy swap after ~12 minutes), this lib's size is squarely in "risky, not clearly safe" territory. Combined with several other agents' driver processes already running concurrently against this same host during this pass (confirmed via ps/free -hwuhanzhan and nitan_san, archives #58 and #61, both mid-flight), running a full lpcc --batch sweep here risked compounding memory pressure for no corresponding benefit: the boot + three-independent-interactive-test approach above already found and fixed every real driver-compat bug in this lib (sec.15h ×3 files, sec.14, sec. 15o, sec.15p, the LONELY_IMPROVED/efun:: family ×6 sites, sec.15f, the rmtree gap, sec.15s, the is_killing typo, and the eventd/ storyd rename-fallout) — a full sweep would mostly re-surface the same long-tail false positives (the quest set_information bug, content requiring specific runtime context) documented above, at real cost to run safely. Per the task's own guidance ("rely on boot + connect test"), treating that as sufficient verification for this lib.

Driver process notes (environment quirk, not a mudlib bug)

Backgrounding the driver via a plain ... & inside a single Bash tool call (even with nohup) got silently reaped by the sandbox shortly after the invoking tool call returned, on the first two boot attempts — no crash message, process just vanished from ps. Using the Bash tool's own run_in_background: true worked more reliably but still occasionally exited (exit code 1, no fatal message in the driver's own log) sometime after a clean boot + working interactive session, on a host that also had 2-3 other agents' driver processes running concurrently. The most reliable pattern found: setsid nohup <driver> ... & disown from inside the Bash tool call, fully detaching from the invoking shell's process group — this is what finally produced a driver that survived across several independent tool-call boundaries for the final confirmation runs. Noted here in case it helps whoever picks up the next archive in this batch.

Re-verification pass: driver rebuild + formatter + WASM (2026-07-23)

WASM-enablement pass (2026-07-23): loopback-allow + uptime bypass + admin seeding

Gates patched (loopback = 127.0.0.1, any 127.*, or an empty/malformed non-dotted-quad string, which is what current WASM builds return):

Admin account: fluffos, normal password Mud@2026, 管理密码 (recovery password, must differ from normal per this lib's rules) Mud@2026admin, Chinese name 浮浮 (surname 浮 + given 浮 + full-name re-confirmation step). Granted (admin) via /adm/etc/wizlist. Verified: registration via the real flow (目前权限:(admin) at entry), reconnect, and update /adm/daemons/band.lpc succeeds. Saves at data/login/f/fluffos.o + data/user/f/fluffos.o (untracked but not gitignored — orchestrator must add). Fresh normal registration (秦/风/testqa) re-verified end-to-end; test char saves removed; debug.log clean apart from the documented pre-existing quest set_information noise.

Fail-closed retrofit (2026-07-24)

The uptime() startup-grace bypass and the per-IP multi-login cap exemption above originally applied their loopback carve-out backwards in one respect: both required sscanf(ipname, ...) == 4 to SUCCEED before exempting anything, which meant a malformed/unparseable IP (falling that parse) skipped the gate too — i.e. malformed was fail-open by omission, the same class of bug as the other libs' explicit !stringp clauses. band.lpc's is_banned()/is_multi_login() had the more usual explicit !stringp(...)-as-loopback form. All four tightened to strict loopback only ("127.0.0.1", "::1", "127." prefix); is_banned()'s original fail-safe (malformed format ⇒ banned, return 1) restored below the carve-out. Re-verified loopback fluffos login, look, score, update /adm/daemons/band.lpc, and quit all still work after tightening.

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

泥潭三/终极魔界基础版。状态已从过时的 limited 修正——这份档案自己的 README 里从未记录过任何缺陷说明,本轮重新测试也没有发现:管理员登录(fluffos/Mud@2026)被识别为巫师账号("没有设置巫师专用密码"的提示按预期出现,只是装饰性警告),干净地进入游戏世界,quit 干净。和 nitan6(015)、nitan_san(041-1)是同一家族/同一流程。

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

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

本档案没有传统意义的新手帮助文档(doc/help/register/ 下全是空文件桩: toc/speciall/xkx01~xkx36);实际的"新手入门必读"是角色创建流程 中盘古(d/register/npc/pangu.lpc)赠送的同名书籍,读过之后才走 register → 选定角色 → washto 洗任督二脉 → born <地名> 出生。全程 两组密码:管理密码(找回专用,规则上必须与普通密码不同)+ 普通密码, 注册时各输入两次确认。

修复的程序性 bug

- §9 格式化工具盲点(file-specific,非本次引入)file.lpc 使用大括号独占一行的风格(void cat(string file)\n{,而非项目里 常见的 K&R 同行 {),本工具在这份文件上 TOKEN MISMATCH, refusing to write;用 git show HEAD:... 取出编辑前的原文件单独 跑一遍格式化工具,同样失败,证实此为该文件已有的格式化盲点,与本 次编辑无关。改为手工核对 §9 文档记录的 3 类已知盲点 grep 规则(均 干净),未跑自动格式化工具于此文件。

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

测试覆盖

进程卫生附注

清理了两处与本次修复无关的测试残留:(a) 管理员账号 wizlian 测试技能 授予 + 现场走动导致的 data/{login,user}/f/fluffos.o 存档漂移 (skills/mud_age/food/water 等字段),已用 git checkout -- 还原;(b) 两个测试角色(nitandeep/nitandeq)的 data/{login,user}/n/*.o 存档文件,已删除,未纳入本次提交。

WASM 未验证说明

按本 session 约定:emsdk 固定从 storage.googleapis.com 拉取,被本 session 出站代理策略拒绝(curl -sS $HTTPS_PROXY/__agentproxy/status 返回 403),WASM 编译/运行验证本轮继续跳过,仅做原生驱动(linux-debug 预设,ASAN/UBSAN)下的完整 §10.7 测试。

深度功能测试(2026-08-12,round two,新驱动重测)

用新编译的 ~/src/fluffos/build-debug/src/driver(origin/master 最新拉 取,含本项目自己提交并合入的 #1343/#1344 两个 PR,以及同一会话里另外 提交的驱动 PR:把编译诊断严重度标记从小写改回大写 "Warning:"/ "Error:")重新验证。

to_int() 任务计数器修复

adm/daemons/combatd.lpc/cmds/std/whisper.lpc 里全部 quest_count = ... % 500 已经是 to_int(query(...)) % 500 的修复后形状,无需改动。

log_error()adm/single/master.lpc)和 message()adm/simul_efun/ message.lpc)之前的 round-one 记录已经确认正确修复(大小写无关匹配 + exclude 守卫),本轮核对无需改动。

补做此前明确记录但未修的两个真实 bug

早前的 round-one 记录("Interactive test transcript / outcome"章节)把 下面两个问题明确归类为"pre-existing、not driver-compat、长尾内容问 题、未修"——但本会话在 ntii/nteset_information 类型不匹配)和 xfbhh(缺失存档目录)上分别独立确认了同样的形状是真实的程序 bug 而 非内容问题,所以本轮回头补上:

1. inherit/misc/quest.lpcset_information() 实现本体早就是 mixed info(.lpc 文件自己的注释显示"Same fix already applied to sibling nitan_san"),但 include/quest.h 的函式原型声明还停留在 string info——两者不一致导致所有传闭包 (: ask_npc :) 的呼叫点仍 然编译期报"Bad type for argument 2 of set_information", adm/daemons/quest/{capture,trace,search,judge,shen,explore,supply, deliver}.lpc 共 9 个任务档案全部编译失败。修复:把 quest.h 的原型 声明也改成 mixed info,和实现对齐。现场验证:修复前后各干净 注册一次角色对比,log/debug.log 里"Bad type for argument 2"报错行 数从多条降为 0(用总行数不变来确认干净跑没有再新增任何一条)。同 一血统的 nitan_san 也有逐字节相同的 quest.h 原型/实现不一致, 一并修复(未在本轮单独跑完整 playthrough 验证,留给 nitan_san 自 己那一轮)。 2. adm/daemons/toptend.lpc(十大排行榜精灵)完全没有 create()**, 因此以无 euid 运行,而 securityd.lpcvalid_write()/data/topten/ 没有像 /data/board//data/maze//data/business/ 那样开白名单——每次角色进入游戏触发 topten_checkplayer()topten_save() 都命中"Wrong permissions for opening file /data/topten/rich.txt for overwrite."。修复:加 protected void create() { seteuid(ROOT_UID); mkdir("/data/topten"); }seteuid 沿用这份档案自己 boardd.lpc 已经在用的同款修法;额 外加 mkdir() 是因为这个专案的 .gitignore 专门排除了 libs/*/work/data/topten/——纯运行期排行榜数据,不作为源码提交—— 所以光在这台机器上手动 mkdir/提交空目录占位并不能在全新 clone 后 生效,让代码自己在运行期创建目录才是真正持久的修法)。现场验 证:先把 data/topten/ 目录整个删除,重启驱动,注册一个全新角 色——create() 自动重建了目录和全部 5 个排行榜档案,注册流程正确 显示"你名列最近十大富翁/魔头/高手/老手/悲情人物排行榜第一名!", 全程 debug.log 总行数保持不变(0 条新报错)。同一血统的 nitan_santoptend.lpc 有逐字节相同的缺失 create() 问题(这 台机器本地碰巧已经有 data/topten/ 目录和内容,但那份内容本身也不 受 git 追踪,全新 clone 一样会踩坑),一并用相同修法修复。

完整游玩测试范围

沿用既有记录的"注册成功进入注册房间,欢迎序列/排行榜播报正确显示"作 为及格线;quit 的新账号 30 分钟保留确认流程此前已验证过。战斗/死亡 循环仍未触达,留给下一次专门测试。

本轮结论

驱动升级后 nitan_ceshi 整体状态良好:任务计数器 to_int()/ log_error()/message() 三处此前修复均确认无需改动;补做并修复了 round-one 明确记录但当时误判为"长尾内容问题"的两个真实程序 bug(quest.h 原型与实现不一致、toptend.lpc 缺失 create() 导致的目录权限问题),两 处都现场验证过(含删除目录测试运行期自愈)。同一血统的 nitan_san 已 经顺手同步了这两个修法(未做完整 playthrough,留给它自己的轮次)。测 试账号(qinshijiu/linshier/wangershi)存档留在 data/ 下作为佐 证,未清理(未跟踪文件,不纳入本次提交)。

AGENTS.md §7.100 修复(2026-08-19,批次五)

ROOM 基类冗余 replace_program(ROOM); 自崩溃地雷(详见 AGENTS.md §7.100):3250 个房间文件的 create() 里紧跟 inherit ROOM; 之后 都有这一行多余调用,永久设下"待替换"标记,第一次对该房间对象绑 定闭包就会崩溃。自带建房工具 clone/misc/roommaker.lpc 的字符串 拼接代码生成模板里也烤了同一个地雷。

修复:脚本化删除所有房间文件里独立成行的 replace_program(ROOM);, 加上 roommaker.lpc 里手动摘除字符串拼接片段。git diff --stat: 3250 files changed,与预期精确吻合(0 处遗留匹配,全部干净)。

验证:build-debug 驱动真实冷启动,端口 40054 正常监听, debug.log 全程干净。既有管理员账号 fluffos/Mud@2026 登录正常 (巫师休息室,look/quit),全程无新增 "cannot replace"/"cannot bind" 日志行。

``§7.112`` residual-gap closure (2026-08-20)

Corpus re-scan (grep -rl 'call_out("death_stage"' ... | filter for missing guard) found unguarded init()-scheduled death_stage() call_out chain(s) in d/death/npc/bai.lpc, d/death/npc/hei.lpc that the original two-wave sweep (see AGENTS.md §7.112) missed -- same reconnect-triggered duplicate-chain bug, different filename/lineage. Added the standard query_temp("death_stage_active")/set_temp/delete_temp re-entry guard, adapted per file's own exit points. Compile-verified via lpcc --batch.

§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): 6 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.

深度功能测试(2026-09-04,shop)

Independent live pass on this slug (port 40054, build-debug driver). 2026-08-12 already completed 峨嵋苏梦清拜师 persist; this pass only exercises a paid shop purchase. First send is gb, then id fluffos / password Mud@2026. #undef DB_SAVE. Admin has no wizpwd yet. register [email protected] drops into 生命之谷. Birth is choose 1washto 20 20 20 20born 扬州人氏 (lands at /d/city/kedian; help rules more-pager — send q first).

Shop: 客店 游讯 intercepts list/buy. Real vendor is /d/city/zuixianlou 店小二 (F_DEALER). list shows 烤鸡腿 80 文. clone /clone/money/gold works (release server : local). buy jitui deducted one gold into 99 两白银 + 20 文铜钱 and delivered 烤鸡腿. feature/dealer.lpc already #include <dbase.h>, so mixin query("vendor_goods") resolves; no this_object() patch needed.

Bug fixed: kungfu/class/huashan/{yue-buqun,yue-wife,feng-buping}.lpc recruit_apprentice() wrote add("apprentice_availavble", -1) (extra “av”) while attempt_apprentice()/reset() use "apprentice_available". Same typo nitan_san/nitan3 already live-verified. Corrected (LF-only). qingcheng/yu.lpc is not in this tree.