info.html · 介绍 · play.html · 游玩 · llms.txt · 下载与本地运行 · ZIP · GitHub
配置内自报名为"风云Ⅳ",站内横幅写作"国内经典版"。与 `fengyun434` 是同一套"风云Ⅳ"引擎的不同年份/站点快照,同属本批次的"风云" (Fengyun)武侠引擎家族。
English
The same "Fengyun IV" engine as fengyun434, captured as a different year/site snapshot, with identical Gu Long-inspired wuxia gameplay of choosing an ethnic background and making one's way through jianghu sects. Notable for an ASCII-art CAPTCHA at registration — an unusually early anti-bot measure for this engine family — and for only persisting characters who reach at least 40% experience toward level 2. Active upstream adds MXP/GMCP client protocol support.
README
上游:seikichin/-mud(main @ 32803f7)。本馆以 submodule-patch 跟踪该仓库;work/ 是 submodule,管理员试玩号在 overlay/,FluffOS 兼容补丁在 patches/(含 GMCP 所需的 software json.lpc 挂载)。
内容亮点
- 以古龙武侠小说为背景的江湖世界,玩法与同引擎家族的
fengyun434、fy2一致:选择民族出身、闯荡江湖门派、行侠仗义。 - 注册新角色时会出现一个用 ASCII 字符画出来的数字"验证码"图案,需要 玩家自己读出图案里的数字再手动输入——是这批"风云"引擎里少见的、 自带图形验证码防机器人注册机制的版本。
- 为防止恶意批量注册,只保存等级达到 L2(40%经验)以上角色的存档; 新手角色如果直接
quit,系统会明确提示数据不会被保留。 - 开服后有一个约 5 分钟的系统初始化保护期,这段时间内任何人都无法 登录——是作者刻意设置的启动缓冲机制。
在线试玩
https://mudlibs.fluffos.info/fy2005/
管理员账号 / Admin account
- id:
fluffos - 密码 / password:
Mud@2026 - 中文名 / display name: 浮浮
- 权限 / level:
(admin)—— 最高级别,通过/adm/etc/wizlist中的fluffos (admin)行授权。该账号出生即在巫师休息室(/d/wiz/hall)。
警告:公开架站前请务必修改此默认密码。
本地运行
cd libs/fy2005
~/src/fluffos/build-debug/src/driver config.fluffos游戏端口:40013(开服后约 5 分钟内无法登录,请耐心等待)。
NOTES · 移植与修复记录
fy2005.rar → fy2005
- Archive:
archives/fy2005.rar(48MB — "风云Ⅳ" 2005 build, same lineage as archive #14 (fengyun434), a later/bigger snapshot). Mudlib root atfy2005/fy4/, config atfy2005/bin/config.fy4. - Port: 40013.
- Hosting (2026-09-13):
submodule-patch→https://github.com/seikichin/-mudpin32803f797c5554b0f72852638107449c658f050f(main). Repo root is the mudlib. Upstream is a FluffOS fy2005 tree with MXP/GMCP work; the catalog previously vendored the same lineage fromfy2005.rar. Admin seed lives inoverlay/(upstream.gitignoresdata/login/anddata/user/). Catalog patchpatches/0001-simul-efun-include-software-json.patchflipsadm/obj/simul_efun.lpcto#ifndef __PACKAGE_JSON_EXTENSION__so the shippedjson.lpcprovidesjson_encodeforfeature/gmcp.lpcon catalog FluffOS builds (no PACKAGE_JSON). Apply withpython3 scripts/apply_lib_patches.py fy2005after checkout; source zips apply it automatically. Do not auto-rebase; refresh the pin after reviewing upstream commits.
Upstream cutover smoke (2026-09-13)
- Submodule pin
32803f7boots clean (preload includes upstreammapd/festivald). - Without the json patch,
connect()fails:feature/gmcp.lpc→Undefined function json_encode→ peer hangup. - With the patch applied: banner + GBK/UTF-8 encoding prompt OK.
深度功能测试(2026-09-13,upstream cutover 后第二轮)
Native FluffOS build-debug driver, port 40013, catalog patch +
overlay/ admin seed applied. work/log/debug.log stayed free of
Error / Bad argument / undefined function lines across the whole
session.
Covered end-to-end
- Admin:
fluffos/Mud@2026logs into/d/wiz/hall;goto /d/fy/fysquarelands on 风云天下 with west/east/up/north/south exits and the 盘龙摩天柱 board. - Registration: UTF-8 encoding → new id → CAPTCHA (
feature/nada.lpcmy_number(), solved via a temporaryDEBUG-CAPTCHAwrite that was reverted before commit) → Chinese name → password → email → gender → enter 风云台 with starter bag/food/drink/cloth. - Onboarding funnel (still intact post-cutover):
down→ 十戒碑 (agreeexit; do not leavehelp rulesin its interactive submenu or it eats the next line) → 故乡之路 (setrace 汉族) → 灵池 (distribute10 attr points) → 风云道 (newbie/veteran) →newbie→ 凤求凰客栈 + riddle 「新手入门」(riddlelists it in progress). - Shop: at 凤求凰客栈,
liston 店小二 shows wineskin / dumpling / fried chicken leg with prices and stock. - Commands:
look/score/i/hp/map(南城环云道 ASCII map with 凤求凰客栈 / 祭剑亭 / 南门 etc.) /eat/drink/read letter(points to 天机老人 +quest) /help newbietree /help cmdstree / low-level double-quitretention warning (L2 / 40% XP gate) all behave. - Loopback startup grace:
uptime() < 300gate still exempts127.0.0.1/::1(catalog-era bypass still present in upstream snapshot), so local tests need not wait 5 minutes.
Not covered this pass (honest gaps)
- Live combat: city streets are no-aggro by design (“这里不准战斗” / no hostile NPCs on 环云道 during the walk). Did not leave the city to find a practice target. Admin
gotosquare was verified; outdoor PvE left for a later pass. - Paid shop purchase:
listOK; abuy … from waiterattempt used the wrong object id/name and did not complete a cash transaction. - WASM: not re-run this session (native-only round-two after the submodule cutover).
No new LPC fixes required beyond the existing software-json.lpc
simul_efun patch.
Status: DONE — boots clean; has an intentional 5-minute startup grace period
Booted with zero fixes needed (same clean lineage as fengyun434/fy2).
This build enforces a 5-minute wait before login is allowed
("风云系统正在初始化,请在五分钟后再登陆。" — "Fengyun system is
initializing, please log in again in 5 minutes.") — an intentional
startup-grace mechanic (same shape as xyxy2's 30-second
wait, just longer here), not a bug. Not waited out to confirm the actual
post-wait login flow given the time cost, but the boot itself is clean
(no compile errors, no crashes) and the pre-wait prompt flow (name
validation) works correctly.
What was fixed
Nothing needed for boot. Routine conversion: encoding (12801 converted,
384 already UTF-8/ASCII, 43 skipped binary, 75 lossy), .c→.lpc (9764
files, 1328 refs auto-fixed), 11 local angle-bracket includes converted
to quotes automatically, static→nosave (44 files).
Known remaining issues (documented, not fixed)
- Several
call_other() couldn't find object '/d/ZONE/room.c'errors at boot — traced to plain-text DATA files (quest/dynamic_location,adm/etc/scenery_phase— bare one-path-per-line lists, no LPC string quoting) that still hold literal.cobject-path references.convert_lib.sh's.c"reference fix only scans.lpc/.hsource (quoted-string context); it doesn't touch extensionless data files with bare (unquoted) paths, and blanket-fixing "anypath.ctext anywhere" risks false positives in genuine documentation/help text. Left as-is — affects some quest/scenery room resolution, not the boot/login path. - lpcc sweep: 9696/9764 pass (99.3%) — not fully triaged past confirming a clean boot given time constraints.
How to run
cd libs/fy2005
~/src/fluffos/build-debug/src/driver config.fluffos
# wait 5 minutes after boot before the login name prompt will proceed
python3 ../../scripts/mudclient.py 127.0.0.1 40013 --timeout 10 --send "" --send "look" --send "quit"Post-hoc fix: UTF8-native is_chinese/registration (AGENTS.md §15h)
Applied in a later batch pass across the whole project: is_chinese/is_chinese2
in the shared chinese.lpc simul_efun fragment used GBK byte-range checks that
silently never match real Chinese text once strings are UTF-8 (this driver's
str[i] returns a Unicode codepoint, not a GBK byte). This broke character
registration specifically -- any real Chinese name was rejected. Fixed the
range check to test the CJK Unicode block instead, and halved the
GBK-byte-calibrated length bounds in check_legal_name to match. See
AGENTS.md §15h for the full writeup; confirmed via a real interactive
registration test (Chinese surname + given name reaching the next prompt).
Re-verification pass: driver rebuild + LPC formatter + WASM build
- Formatter:
format-corpus.mjsover all 9764.lpcfiles; 9739 reformatted, 2 unchanged, 23 refused (self-checkerrors, expected). - Proactive fixes applied before the first boot attempt of this pass (found via this same lib's
adm/daemons/securityd.lpc, before even connecting): the sameresolve()-before-wiz_statusWASM-crashing ordering bug asfy3dz/fy3xd/fengyun434(same 风云 engine family) -- reordered + wrapped incatch(). Also found a second, more serious latent bug in the samecreate(): an AGENTS.md-§15u-style "phone-home license expiration" self-destruct --if (local[5]*10000+... > C_YEAR*10000+...) shutdown(0);would kill the entire driver process once the wall clock passesC_YEAR/C_MON/C_MDAY(hardcoded to year 2109 here, so not reachable on any realistic host clock today -- but disabled/commented out as insurance per standing policy rather than left armed, same treatment asmoniHuafu's/fy3dz's equivalent). - Native re-test against rebuilt driver: clean boot, zero fixes needed beyond the two proactive ones above. The documented 5-minute startup grace period (
uptime() < 300) still behaves exactly as described -- confirmed by actually waiting it out this time (prior passes noted the mechanic but didn't wait through it). Full registration flow completed end-to-end for the first time, including the ASCII-art digit CAPTCHA (/feature/nada.lpc'smy_number()): wrote a one-off scripted client (/tmp, not committed) that decodes the CAPTCHA programmatically -- copied the exact 10 digit glyphs fromc_numinnada.lpc(10 rows × 15 chars each) and pattern-matches each of the up-to-8 digit columns in the two rendered row-groups against them (exact match, not fuzzy OCR, since the glyph table itself came straight from the source) -- rather than reading the ASCII art visually turn-by-turn. Verified end-to-end with real Chinese names (唐游/悟空/取经取) reaching the actual starting room (风云台),look/scoreproducing correct output, and the double-quitanti-abuse confirmation (documented in README) working as described. Zero debug.log errors across all runs. - WASM test — full CAPTCHA-solving playthrough completed, not just a boot check: this lib combines two real obstacles for WASM testing that don't affect the other 8 libs in this batch: (a) the same 90s per-connection
LOGIN_TIMEOUT(obj/login.lpc) that exists natively too, and (b) the 5-minuteuptime()grace period, which under the WASM harness's real-time-driven tick clock genuinely takes 5 real minutes of process lifetime to elapse. Pitfall found: an initial attempt kept onefluffos_connect()-created connection open through the whole 5-minute wait (sending periodic keepalive blanks) and got kicked by the 90sLOGIN_TIMEOUTlong before the grace period ended (its own local timer, started at connect time, independent ofuptime()) -- reproduced the "您花在连线进入手续的时间太久了" kick message. Fixed by ticking the driver with no connection open at all for the first 310 real seconds (uptime()advances regardless of connections), then callingfluffos_connect()fresh only after that -- giving the fresh connection its own full 90s window with the grace period already satisfied. With that fix, the full registration flow (encoding → id → CAPTCHA, decoded via the same exact-glyph-match approach as the native test → Chinese name 取经取 → password → email → gender → race) completed cleanly under WASM, reaching 风云台, withlook/score/quit(×2) all producing correct output identical in shape to the native run. Only non-fatal errors are the expected no-sockets-package ones (network/dns_master.lpc'ssocket_create/socket_bind,*No program in objectat preload). This is the only lib in this batch where a full WASM CAPTCHA-gated registration was actually driven to completion, not just verified to boot. Not affected by the documentedquery_ip_number()WASM limitation.
WASM-enablement pass (loopback / admin seeding)
Gates patched (all in work/):
adm/daemons/band.lpcis_banned()(~line 58): loopback / empty / non-string /localhost/127.-prefix short-circuit (return 0). Called fromadm/daemons/logind.lpc:104-105.adm/daemons/logind.lpclogon()(~line 217): the 5-minuteuptime() < 300startup gate now applies only to non-loopback connections (previously destructed every early local/WASM connect; the WASM harness needed a 310s pre-wait — no longer). Original gate kept verbatim for remote connections.adm/daemons/logind.lpclogon()(~line 153): the NETBAR per-IP multi-login cap block is skipped entirely for loopback/empty/ non-string IPs (browser tabs are all loopback).adm/daemons/logind.lpcvalid_wiz_login()(~line 665): the wizard IP-whitelist gate (/adm/etc/wizip/<id>) always passes loopback/ empty/non-string IPs.- KEPT:
LOGIN_TIMEOUTidle kick, quit-twice confirmation, wiz_lock maintenance gate — game design, not hosting protection.
Admin account (§1.5): fluffos / Mud@2026, display 浮浮, status
(admin) via fluffos (admin) appended to /adm/etc/wizlist.
Registered through the REAL flow including the ASCII CAPTCHA (solved by
exact glyph match against feature/nada.lpc's c_num table — note the
glyphs are Chinese numerals 零一二...九, indexes 0-9, plus an unused 十).
As a wizlisted account it spawns in /d/wiz/hall. Verified re-login +
update /adm/daemons/combatd → 成功.
Retest: fresh normal registration (秦风) through encoding + CAPTCHA into
风云台 with working look/score — confirms the uptime-gate bypass
(connected seconds after boot, previously impossible) and that normal
players are unaffected. Test char saves removed; no new debug.log errors.
- Fail-closed retrofit (2026-07-24 security correction): the loopback check(s) above originally also treated an empty/non-string IP as loopback (defensive fallback for the then-broken
query_ip_number()). Since the driver's IP-reporting bug is now fixed upstream (WASM reports a clean127.0.0.1like native), that fallback was removed — loopback is now strictlystringp(ip) && (ip=="127.0.0.1" || ip=="::1" || ip[0..3]=="127."); anything unparseable/empty is untrusted/remote and goes through the original gate logic. Retested: fluffos login +look/quitstill clean over loopback.
Save files to force-add (untracked, NOT gitignored):
libs/fy2005/work/data/user/f/fluffos/fluffos.o,
libs/fy2005/work/data/login/f/fluffos/fluffos.o.
深度功能测试 / Deep functional test (2026-08-06)
第一次完整游玩测试(原生驱动 build,ASAN/UBSAN debug 构建)。测试角
色 id fytesta,中文名 云天河,汉族。本轮 WASM 未重新验证:emsdk 工
具链下载硬编码指向 storage.googleapis.com,本次会话的出口代理策略
性拒绝该域名(403,已用 curl $HTTPS_PROXY/__agentproxy/status 确认
是策略拒绝而非临时故障),本地无法构建 WASM 驱动。
发现并修复:.c→.lpc 改名的长尾后遗症——两张运行期数据表整表引用旧扩展名,导致节庆场景系统崩溃、任务掉落系统整体失效(AGENTS.md §4.2 item 2 新实例)
- 症状:驱动开机预载阶段,
debug.log出现两条被catch()拦截的 运行时错误——*call_other() couldn't find object '/d/huashan/cave.c'与'/d/taishan/yueguan.c'——分别来自adm/daemons/sceneryd.lpc的init_scenery_phase()。 - 根因:
adm/etc/scenery_phase(17 条节庆/天气景观事件表)和quest/dynamic_location(1440 条任务随机放置用的房间列表)两张纯文 本数据表里,每一条房间路径都带着改名前的.c后缀,而这些房间 在work/里早已全部改名成.lpc。FluffOS 的load_object()对显 式扩展名做精确匹配(.c绝不会回退去找.lpc),所以这两张表里的 1457 条路径全部失效——find libs/fy2005/work/d/<path>.lpc逐条核实 全部存在,只是数据表没跟着改名脚本走。sceneryd.lpc的开机自检有catch()包裹,只是记一条系统频道警告,不会崩溃;但同一份数据后续 被scenery_happen()(景观随机触发时调用,adm/daemons/ sceneryd.lpc:122-130)消费时,load_object()返回的 0 直接送进room->init_scenery(),没有catch()也没有objectp()守卫,一 旦某个节庆随机命中(update_scenery_phase()メ里random(RATE) < rate通过),就是一次真实的Bad argument 1 to EFUN call_other()运行时崩溃。quest/dynamic_location那 1440 条被adm/daemons/ taskd.lpc的spread_quest()用来给任务物品随机选房间放置,虽然 那处调用点本身有if (cur_obj) {...}守卫、不会崩溃,但由于 1440 条路径无一例外全部失效,spread_quest()实际上从未能把任务物 品放在地上过(每次都退化成直接交给 NPC),整个"地上拾取任务物品" 这条玩法路径长期完全瘫痪。 - 修复:写小脚本核实每条
.c路径对应的.lpc文件确实存在(17 + 1440 条全部确认存在,零条需要跳过),批量去掉两张数据表里的.c后缀(FluffOS 对无扩展名路径会先找.lpc再找.c,去掉后缀即可 正确解析)。同时给scenery_happen()补上objectp(room)守卫作为 纵深防御——数据表已经修好,理论上不会再命中这条路径,但守卫本身零 成本且符合已有的兄弟调用(init_scenery_phase())写法。 - 验证:修复前重启驱动,
debug.log出现前述两条被拦截的错误,确 认可复现;修复后重启驱动,debug.log对这两个房间(以及另外 15 个 未在这次开机窗口里被抽中的节庆条目)不再报错。scenery_happen()的运行期分支本身要等某次节庆随机事件真正命中才会触发,这次会话时 间预算内没有等到自然触发去现场复现"崩溃前 vs 崩溃后"的对比——如实 记录这一点,而不是假装已经现场复现过。§9格式化自检对两张数据表 不适用(不是.lpc/.h),已确认改动后行数一一对应(1457 处删除 + 1457 处新增,纯粹去掉.c后缀,未触及其它字符)。 - 已有的 AGENTS.md §4.2 item 2("数据文件里裸
.c路径")条目已经涵 盖这个模式,未新增小节;这里的规模(两张表共 1457 条)比该条目原举 的例子大得多,值得作为该模式"能有多大规模"的参考案例。
发现并修复:注册流程里遗留的 printf("%O", ob) 调试输出(AGENTS.md §7.34 新实例,"风云"家族已知模式)
- 症状:注册流程中,玩家刚输入完中文名(自己手动输入的分支,不是 接受系统随机生成名字的分支)之后,屏幕上会多出一行裸露的对象内部 路径,如
/obj/login#29,夹在"您的中文名字:"和"请设定您的密 码:"两行正常提示之间。 - 根因:
adm/daemons/logind.lpc:488(get_name()里"玩家自己输 入名字"分支)有一行未加任何注释的printf("%O\n", ob);,是原作者 遗留的调试脚手架,archive 里就已经是这样(不是本项目转换流程引入 的)。同一函数"接受系统建议的随机名字"分支(get_resp())里有同 一行的注释掉版本(// printf("%O\n", ob);,logind.lpc:450), 说明这份代码曾经在两条平行路径上都打过这行调试输出,后来只有一条 被手工注释掉,另一条被遗漏。AGENTS.md §7.34 已经把这个模式记录为 "风云"(Fengyun)家族的已知通病,在fy330/fy2mg等同引擎的兄弟 档案里各自独立命中过。 - 修复:删除
logind.lpc:488这一行,与 §7.34 记录的既定修法一 致("这行永远不服务于任何玩家可见的目的,直接删掉即可")。 - 验证:修复前用一个临时调试行(另加一行
write(),验证完立刻撤 销,从未提交)读出过 CAPTCHA 明文校验码后完整走过一次注册流程,亲 眼看到修复前/obj/login#29那一行确实出现;修复后update /adm/daemons/logind热更新编译成功,§9格式化自检通过(该文件其 余部分的缩进也顺带被格式化器统一,纯空白改动)。受时间预算限制, 未再跑一次完整注册去现场复认"修复后这行不再出现",但删除一行裸printf是这个模式在本项目里反复验证过的安全修法,风险极低。
关于 CAPTCHA(图形验证码)的测试方法说明
feature/nada.lpc's my_number() 用 c_num 表里 10 个 ASCII 字符画
的中文数字字形,拼成一个 8 位随机数的图形验证码。本轮为了能在自动化
测试里稳定通过这一关,用 git show/直接读源码把 c_num 表的 10 个
字形抽出来写了一个逐字形匹配的小工具(未提交进仓库,纯本地脚手架),
但纯靠字形匹配在实际操作中因为终端输出的时序/换行/颜色码干扰,命中
率不够稳定,最终改用了更简单可靠的办法:临时在 confirm_id() 里加一
行 write() 把 my_number() 已经算出来的明文校验码直接打印出来,验
证完当场撤销这行调试代码(从未提交)。记录这个方法是为了给下一个测
试 fy 家族(fy2、fy330、fy2mg 等同引擎兄弟档案)的人参考——这
类 CAPTCHA 是纯 ASCII 艺术字,没有依赖任何外部图像渲染,本来就是为
了防自动化注册设计的,测试时没有必要真的去做 OCR,直接读源码 + 临时
调试输出是更稳妥的路子。
测试内容与结果
- 注册:GB 编码 → 英文 ID(仅限字母,含数字会被拒绝)→ CAPTCHA (按上文方法解出)→ 真实中文名(云天河)→ 密码(含大小写字母/数 字/符号)→ 确认密码 → 邮箱 → 性别,全程顺利进入
风云台。 - 种族/属性分配:
setrace 汉族(可选汉族/满族/蒙古族/苗族)→distribute <属性拼音>分配 10 点自由属性点,正确扣减剩余点数并在 分配完毕后自动存档。 - 新手引导:
newbie路线启动"新手入门"解谜任务 (riddle命令可查看进度),help newbie的 14 个子菜单条目内容 与游戏内实际系统(学习/吃喝/离开等)描述一致。 - 城内探索:确认"城里不主动挑衅不会被攻击"的设计(
map命令输 出的城市地图与实际房间连接一致,走遍南城多个环云道路口无异常), 出南门后地图延伸到荒野(小山坡、荒凉大道、莽林边缘),均正常。 - 持久化:静默重连(net_dead 后
find_body()重新绑定)——房间 (小山坡顶)、装备、属性全部正确复原,"重新连线完毕"提示正确。真 实完整 quit 未测试到底——README/游戏内提示都明确"经验等级 < L2 (40%)的角色数据不保留",本轮测试角色战斗经验为 0,属于设计内会 被丢弃的范畴,未故意去confirm 那个"再次输入 quit 才真正放弃数据" 的二次确认,避免丢失刚创建的测试角色;这也意味着这条"低等级角色 quit 不保留数据"的具体分支本身未被现场验证到,如实记录为未覆盖。 - 管理员账号:
fluffos/Mud@2026登录,出生于/d/wiz/hall,update /adm/daemons/logind成功,确认写 ACL 正常。 - 战斗/门派:未覆盖——本档案的新手起始区(风云城南城)本身 不会被动遇袭,需要主动走到城外才有敌对目标;沿最近的荒野路径(南 门→小山坡→荒凉大道→莽林边缘)找到的要么是告示写明"猛兽出没,有 去无回"的高危区域,要么是纯风景/NPC房间,同宗弟子限定的"大师兄" 陪练 NPC(
obj/npc/champion.lpc)需要玩家先加入某个门派才能触发 (accept_fight()里me->query("class") != query("class")直接 拒绝跨门派挑战),在本轮的时间预算内没有找到一个新手友好、不需要 远征或先入门派的安全陪练目标。如实标注为未覆盖,而不是默认"和其 它风云家族档案一样所以没问题"——留给下一轮测试或熟悉这份档案地 图的人优先排查。经济/商店同样未覆盖(本档案的商店系统结构与map显示的钱庄/当铺/茶馆等设施看起来是标准 fy 引擎商店实现,未实测)。
WASM 修复摘要(迁移自 meta.json 的 group_note)
风云Ⅳ 2005 构建版。
§7.86 跨库扫描修复(留言板 post 崩溃)
BULLETIN_BOARDinherit+ 多余replace_program()致命形状(AGENTS.md §7.86,post命令崩溃):全档案 8 处命中,已删除多余的replace_program(...)调用(保留inherit),逐文件保留原有行尾格式(CRLF/LF 按文件原样)。本次为跨库 §7.86 扫描修复(触发原因:该 bug 已在 6+ 个互不相关的血统家族独立确认,属于近乎普遍的拷贝粘贴模式),仅做编译检查(驱动干净启动、端口正常监听),未做完整 §10.7 深度游玩测试。
§7.100 扫描修复(ROOM 基类多余 replace_program())
同一形状扩展到全库通用房间基类 #define ROOM "/std/room":删除
1001 处多余的、独立成行的 replace_program(ROOM);(保留
inherit ROOM;)——999 处由脚本批量删除,另外 2 处
(d/fy/wcloud1.lpc、d/fy/tiandoor.lpc)行尾带有开发者注释
//add by ldb(后者还有中文说明"希望刷掉乱走的NPC"),脚本的严格
匹配跳过了它们,手工确认后一并删除——注释表明作者是有意添加该调用
以期"冲掉"游荡 NPC,但技术上仍是同一枚定时炸弹(对已 inherit 的
对象重复 replace_program(),一旦该对象后续绑定任何闭包就会崩溃),
故仍按同一原则删除。本库没有房间建造工具(roommaker.lpc 等),
无需修复第二处。已用 build-debug 驱动干净启动验证(0 个新增编译
错误,端口正常监听);未做完整 §10.7 深度游玩测试。
Round-four re-test (2026-08-20): combat + economy, previously untested
Prior rounds explicitly left combat and economy uncovered (no newbie-safe sparring target found within the time budget; shops looked like a standard fy-engine implementation but were never actually transacted against). This pass closed both gaps.
Combat: confirmed working
obj/npc/champion.lpc's cross-sect accept_fight() gate
(me->query("class") != query("class")) is real and correctly blocks
newbie-unaffiliated challenges, as previously documented — not a bug.
Rather than force a sect join, tested combat via the admin account and
a disposable clone /obj/npc/scavenger (a plain, non-quest NPC with no
accept_fight override) in /d/wiz/hall:
kill scavengerproduced full multi-round attack/defense resolution — hit/parry/dodge/graze outcomes with distinct messages each round, realkee(HP)-pool depletion on both sides, and a low-HP "wimpy" auto-flee kicking in correctly (character fled to an adjacent room, dropped an inventory item in a panic — a real, working low-HP survival mechanic, not a bug).- Confirmed the room-scoped
no_fightflag independently blockskillin a designated safe room (/d/wiz/jobroom: "这里不准战斗。"). - Used the wizard
smash <npc>debug command (calls the NPC's realdie()apply, same code path as a natural HP-zero death) to trigger an actual death/cleanup transition without further risking the under-equipped admin test character: death message printed, NPC destructed, a corpse object (/obj/item/corpse) spawned correctly in the room. Both the corpse and the earlier panic-dropped item weredestroyed afterward as test cleanup (this was a disposable clone, not a placed/shared world NPC). - Net result: multi-round combat resolution, damage, low-HP flee/survival behavior, room-scoped no-fight enforcement, and death/corpse transitions all confirmed working correctly.
Economy: confirmed working, including a real bug found and fixed along the way
Tested the two facilities actually reachable near the newbie zone
(fywest/fysouth maps): d/fy/nanbank.lpc (南宫钱庄, bank) and
d/fy/qianyin.lpc (千银当铺, pawnshop), plus a real vendor purchase at
d/fy/fqkhotel.lpc's 店小二 (inn waiter, functionally the
teahouse-equivalent shop — no room literally named/tagged 茶馆 exists
near the newbie start; the one d/biancheng/teashop.lpc teahouse in
the whole archive is in an unrelated, far-off zone, and
d/fy/npc/teawaiter1.lpc, which reads like a dedicated teahouse
vendor, is dead content — never placed in any room's objects map, and
had its own list/buy add_actions commented out even if it were
reachable).
- Bank:
deposit 100 silver→balancecorrectly showed 一两黄金 (10000 = 100 units × base_value 100);withdraw 30correctly reduced it to 九十九两银子七十文钱 (9970) and paid out matching physical coin. Confirms the same two-tier currency architecture already found onylfyxa3/xyzx3/hc: bankdepositis a separate int stat from physical coin objects.feature/bankowner.lpc'sdo_deposit()/do_withdraw()correctly move value between the two;buy.lpcdefaults to consuming physical coins (see below) but has anenv/e_moneybranch that debits the bank balance directly instead (MONEY_D->charge_him()) — present in the code, not live-tested this round (no time budget to also flip that flag and re-verify), so documented rather than assumed. - Pawnshop:
value <item>andsell <item>both work correctly. A worthless test item (布衣, cloth armor, value 0) correctly triggered "并不值很多钱" with no transaction; a low-but-nonzero-value item (单刀, blade, value 5) sold for 4文钱 (80% of value, matchingdo_sell()'svalue*80/100payout) and was correctly removed from inventory, coin balance increased to match.redeem/pawn(as opposed to outrightsell) were not separately exercised —value/sellalready confirm the shop's core transaction path works. - Buy:
listat 店小二 showed the real vendor_goods table (牛皮酒袋 20文/十个, 包子 15文/三十个, 烤鸡腿 30文/四十根);buy wineskin from waitercompleted a real purchase — item moved into inventory, ALL physical currency was destroyed and reissued as change in the correct denominations (exactly matchesmoneyd.lpc'spay_him(): destroy every cash object, reissueafford - price), arithmetic verified exactly (34文+200两银子 = 20034 total value; paid 20; change 20014 = 14文+2两黄金, confirmed in inventory afterward).
Real bug found and fixed: log_file() had no assure_file() guard (AGENTS.md §7.11 instance)
While setting up test money via the wizard call debug command (call
silver->set_amount(300)), hit a live, uncaught runtime error:
执行时段错误:*Wrong permissions for opening file /log/nosave/CALL_OTHER for append.
"No such file or directory"
程式:/adm/obj/simul_efun.lpc 第 14 行adm/simul_efun/file.lpc's log_file() did a bare
write_file(LOG_DIR + file, text) with no directory-existence guard,
even though a correct, already-written assure_file() helper sits two
functions below it in the same file, unused — the exact AGENTS.md §7.11
pattern (six-plus prior independent instances across unrelated
lineages). This lib's archive never shipped /log/nosave/.
This is not just a debug-tool inconvenience — grepping every
log_file("nosave/...") call site found it also sits on the real
player-facing cmds/usr/suicide.lpc::check_password() path (the
"永远死掉" / permanent-delete branch of the double-confirmation
suicide -f flow, precisely the mechanic last round's NOTES flagged as
untested): the log call is textually BEFORE the actual
rmhirdir() save-directory deletion and destruct(me) calls in that
function. An uncaught error there would silently abort the whole
deletion sequence — the player would see a raw stack trace instead of
the "永别了" farewell message, their save data would NOT actually be
deleted, and destruct(me) would never run, leaving the confirmation
flow in a broken half-state. Also present in master.lpc's own crash
logger (nosave/CRASHES), securityd.lpc's promotion log,
imprison/purge wizard audit logs.
Fix: added a forward declaration (void assure_file(string file);)
plus a call to assure_file(LOG_DIR + file); immediately before the
write_file() in log_file(), matching the established project-wide
fix idiom exactly.
Verified live: reproduced the crash pre-fix (call
silver->set_amount(300) threw the trace above, and the call silently
never executed — confirmed by balance/inventory not reflecting the
intended amount). The regular update <path> wizard command cannot
hot-reload this fix, since /adm/obj/simul_efun is a driver-special
#include-based object, not a normal inherit-based one — attempting
update /adm/obj/simul_efun live threw its own *No program in object
error and did not apply the fix. Restarted the driver clean instead
(old PID killed, fresh boot), then re-ran the identical call
sequence: no error, /log/nosave/ auto-created on demand, and all
subsequent bank/pawnshop/buy transactions above completed without
incident.
Standing bug checklist sanity pass
- §7.90 (eval-cost):
config.fluffosalready carriesmaximum evaluation cost : 5000000(bumped from the 700000 default) — intact. - §7.100 (
ROOMredundantreplace_program()): grepped forreplace_program(ROOM)— 45 hits, all already commented out (//replace_program(ROOM);) from the original sweep — intact, no live instances remain. - §7.111 (
standard_trace()unguardedfile_name(error["object"])):adm/obj/master.lpcalready carries theobjectp(error["object"]) ? file_name(...) : "(driver)"guard — intact. - §7.112 (duplicate
call_out()chain on reconnect viaenable_commands()): no local finding to report; not re-audited in depth this round (out of this round's assigned scope), no symptoms observed. - §7.113 (netdead reconnect never restores
heart_beat): traced the real call graph —LOGIN_D-definedadm/daemons/logind.lpc'sreconnect()unconditionally callsuser->reconnect(), andobj/user.lpc::reconnect()unconditionally doesset_heart_beat(1)in the correctthis_object()context. Clean, matches the already-verified-correct lineage documented for 60+ other libs. - §7.114 (
privateinput_to()target via inherited mixin): noprivate-qualifiedinput_to()callback pattern found in this lib. Not applicable. - §7.115 (
QUESTmacro pointing at a missing global quest-hook file): noQUESTmacro defined anywhere in this lib's includes. Not applicable. - §7.79 (bare 2-arg
addn/addn_temp): zero call sites of either function anywhere in this lib'swork/tree. Not applicable — this lib was never in the affected-lineage list and confirms it cleanly.
Cleanup
No new player/test accounts were created this round (all testing done
through the existing fluffos admin account, already documented and
already save-tracked from earlier passes). Test artifacts (a cloned
scavenger corpse, a panic-dropped starting-kit item, cloned test
currency/weapon/armor consumed by the transactions themselves) were
either consumed by the transactions or explicitly destroyed
afterward. Driver killed by exact PID at session end.
§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.