Storm: Rising Tempest

✅ 可玩

风云之风起云涌

fyzfqyy

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

▶ 开始游玩 · Play Now

一个以古龙小说为背景的"风云"MUD。这份档案的实际游戏地图相当单薄:全库只有约 48 个带房间描述的文件,且大多数分散在各个巫师的个人目录下,而不是一套完整的官方城镇/门派地图;唯一较为完整的官方场景是 `quest/kaifeng/` 的开封"衙门",包拯、展昭都驻扎在此。注册流程把管理密码与登录密码彻底分离,比常见的单密码注册更谨慎。

English

A Gu Long-themed “Storm” (风云) MUD whose actual built world is thin: only about 48 files carry real room descriptions, most scattered across individual wizards' personal directories rather than a complete official town/sect map. The one substantially finished official area is the Kaifeng yamen (衙门) scene, populated by Judge Bao (包拯) and Zhanzhao (展昭). Registration uniquely splits a recovery/admin password from the everyday login password. The apprenticeship/sect system itself works, but no NPC in the shipped content ever actually sets a sect to join.

README

内容亮点

注册流程(两套密码)

英文名字 → 确认建立(y/n)→ 中文名字(2-4 个中文字)→ 管理密码 (≥5 字元,用于遗失普通密码时找回、修改密码,平时不要用)→ 确认管 理密码 → 普通密码(≥5 字元,日常登录用,不能和管理密码一样) → 确认密码 → 民族(0-3)→ 性别(m/f)。

本次修复的关键 bug

管理员账号 / Admin account

管理员名单存储在纯文本文件 adm/etc/wizlist 里;账号本身通过正常 注册流程创建(管理密码另设为 AdminPw1,与登录密码不同)。

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

本地运行

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

游戏端口:40133

NOTES · 移植与修复记录

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

风云(古龙小说题材),管理密码+登录密码双密码注册流程。新发现的 bug,已收录进 AGENTS.md §7.60:master.lpc 的 log_error()——每一条普通的编译警告(不只是真正的错误)都会调用它——最后会呼叫 CHANNEL_D->do_channel(...);如果 CHANNEL_D 这时候还没有被预载(取决于它在 adm/etc/preload 里排第几个),这次呼叫会在调用者自己还在编译的过程中,悄悄触发对 channeld.lpc 的一次新编译——这个驱动禁止这种嵌套编译,于是抛出"*Object cannot be loaded during compilation.",又被 log_error() 自己捕获并重新记录一次,如此循环,把一条本来毫无意义的 pragma 警告变成了几万行重复的错误堆栈输出。这个问题只存在于 CHANNEL_D 加载完成之前的启动窗口内(之后完全正常),但足以把真实输出淹没到没法看,因此还是修了:在广播前先判断 find_object(CHANNEL_D)。另外也修复了 is_chinese() 和 check_legal_name() 里经典的 §8.1 中文名字 bug(长度界限+字节步进循环,会静默拒绝所有真实中文名字)。排版格式化工具的第三类盲点检查在 12 个命中里抓到了两处真正的损坏(一份巫师培训测验文字档案和一份带有未转义尾随中文注释的代码速查表)——两处都已还原。管理员账号(fluffos/Mud@2026)通过真实注册流程 + adm/etc/wizlist 播种。

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

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

管理员账号 fluffos/Mud@2026(管理密码 AdminPw1,与上面 WASM 摘要记录的 一致)在本仓库当前 checkout 里其实没有实际的存档数据(只有 data/{login,user}/{a-z}/ 的空骨架目录被播种进 git,账号本身的 .o 存档 从未提交)——先用 ls data/login/f data/user/f 验证过,确认为空后,本轮 按 README 记录的凭证通过真实注册流程重新建立了一次(英文 id 沿用 fluffos,登录密码沿用 Mud@2026,管理密码沿用 AdminPw1)。

新手引导先读了 doc/help/newbie.txt:文档描述的注册流程(单一密码→确认→ email→性别→民族)已经过时,与当前 logind.lpc 实际代码不符——真实流程 是 README 记录的双密码版本(英文名→确认→中文名→管理密码→确认→普通密码→ 确认→民族→性别,注册时不问 email)。doc/help/newbie.txt 关于 apprentice/skills/learn/战斗系统的说明与代码基本一致,仅密码段落已 过时,未改动帮助文档本身(内容维护,不在本轮范围)。

用真实中文名字 云舒(英文 id ceshiwo)走完整个注册流程:look/ score/i 在角色创建后、register <email>+decide(風雲用开封府门口的 神仙姐姐 NPC 做真人自助注册,不是 cmds/arch/register.lpc——那个指令需要 (arch) 权限,是给巫师手动帮别人登记用的,一般新玩家永远碰不到,房间牌子 上写的 register your-email 指的是神仙姐姐身上的本地 register/decide 动作)自助完成注册后,均正确响应、无崩溃。

战斗安全陪练机制:cmds/std/fight.lpc 读到确认,判断依据是 obj->query("can_speak")(不是 civilized)——adm/daemons/race/human.lpccreate() 无条件把人类设成 can_speak=1beast.lpc/monster.lpc 两个种族档案都没有设这个属性,因此人形 NPC 走 fight_ob()/fight_ob() 双向切磋分支,兽类/妖魔走 kill_ob() 真杀分支——与本项目本轮反复确认的 "can_speak/civilized 二选一分流"模式一致,本档案用的是 can_speak。现场 用管理员账号对 quest/kaifeng/npc/zhanzhao.lpc(展昭,人类,can_speak=1) 分别测试了 fight(见下方"发现但判定为既有设计"关于死亡的记录)和真实的 可用 NPC 人数极少这一事实本身(见下)。

组织/门派技能获取:organic 与管理员捷径都验证了,但都撞上同一个内容缺口

修复的程序性 bug

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

未验证事项

Deep functional test round two (2026-08-14)

Independently re-verified against current code rather than trusting the extensive round-one writeup above. All 10+ round-one fixes confirmed still present (code inspection for all, live re-exercise of the highest-value ones — the §7.12 message() type check and the §7.96 START_ROOM fallback, both exercised on literally the first login). Found and fixed one small remaining gap this round's own checklist covers that round one's pass didn't touch.

New fix: adm/simul_efun/file.lpc's cat() still had no null-guard

Round one already fixed log_file()'s assure_file() gap (§7.11) but missed cat()'s separate null-guard need. One-line fix: write(read_file(file) || "");.

Re-verified live: the two highest-value round-one fixes

Verification method

Booted native build-debug driver, admin login (fluffos/Mud@2026) — clean on the first attempt. update /adm/daemons/logind as the real privileged-action check (succeeded). goto /quest/kaifeng/zhengtang as a targeted re-exercise of the make_inventory isolation fix. Two full rapid reconnects, both clean. work/log/debug.log grepped for the original error signatures (Bad argument 4, Wrong permissions, F_SKILL) after the whole session — zero hits; all new log growth was either harmless compile warnings or the already-documented yayi content-gap trace. Driver killed by exact PID after testing; incidental fluffos.o save-timestamp churn reverted before commit.

Files modified this pass

§7.100 sub-threshold instance (2026-08-20)

Found during the §7.100 tail-sweep (below the original 166-lib survey's

=100-occurrence threshold, never checked). 40 live

replace_program(ROOM); occurrences across 31 files: 26 standalone room-file/heredoc-template lines (real .lpc room files, data/group/groom/*.lpc, feature/up.lpc, quest/kaifeng/qianyafang.lpc) plus 14 string-builder-embedded occurrences (literal \n replace_program(ROOM);\n escape sequences inside generated-code strings) across data/group/obj/ling.lpc, data/group/obj/ling-pai.lpc, a garbled-filename duplicate/backup of ling.lpc under data/group/obj/, and this lib's own room-building tools u/island/obj/roommaker.lpc/u/island/obj/roommaker1.lpc (two copies, both fixed — so newly-built rooms were inheriting the bug too). A full post-fix grep confirms 0 live occurrences remain. Verified via a clean native driver boot (zero new debug.log errors, port listening, killed by exact PID after ~8s).

§7.30 uninitialized-mapping accessor sweep (2026-08-20)

Corpus-wide mechanical sweep of the feature/skill.lpc shared-lineage bug (confirmed independently on xiakexing2017/jqxz2015/haiyang2 via round-four testing): 3 accessor(s) in this file returned a raw never-initialized mapping instance variable (defaults to int 0, not ([]), until first assigned), crashing any unguarded keys()/sizeof()/indexing caller for a fresh/untrained character. Fixed at the accessor level (mapp(x) ? x : ([])) per the documented remedy. Verified via lpcc --batch static compile check only (not a live boot) as part of a large mechanical sweep; not individually functionally re-tested live on this lib.

Round three (2026-09-04): shop purchase + 拜师 check

New angle vs prior rounds: live shop + 拜师. Native build-debug driver, port 40133. First send is the English id (no GB/Big5 menu). Admin fluffos/Mud@2026 (wizlist (admin); unused admin-password AdminPw1 this pass). Lands at 世外桃源/REGISTER_ROOM as before.

拜师 — still no legal master (content gap, not a new bug)

Reconfirmed by source: no official NPC set("family", ...) outside u/. apprentice itself is intact. Did not invent a master.

Programming bugs found and fixed this pass

1. is_admin() hardcoded to id island (adm/simul_efun/object.lpc). Wizlist lists lost/island/ fluffos as (admin), and the login banner printed 目前权限:(admin), but is_admin() also required query("id") == "island". clone of anything outside /clone/gift and call both returned 你不能复制物品 / 你不能使用该命令. Aligned is_admin() with is_root(): SECURITY_D->get_status(...) == "(admin)" is enough. Live: call me->set_temp(...) and clone /obj/example/chicken_leg both worked afterward.

2. move() threw on a missing dest path (feature/move.lpc). call_other(dest, "???") on /d/fy/fysquare (never shipped) raised *call_other() couldn't find object and aborted the caller. adm/npc/youxun.lpc create() does that move for the master copy, so the first clone /adm/npc/youxun died at 载入失败. Added file_size + catch before the load; missing dest now returns the existing destination unavailable notify_fail.

3. message_vision() dest int 0 (adm/simul_efun/message.lpc) plus youxun create() announcing after a failed move. After (2), move() returned 0 but create() still called message_vision, and environment(me) was 0, so efun message() got dest int 0 (*Bad argument 3). Guarded message_vision when environment(me) is missing, and only announce in youxun create() when move("/d/fy/fysquare") succeeds. Live: 游讯复制成功,放在这个房间。

4. F_DEALER/F_VENDOR listed missing vendor_goods files via unguarded call_other (feature/dealer.lpc, feature/vendor.lpc). youxun's catalog points at /clone/gift/{feidan,feimao,kuangquan} (directory not shipped); 芳儿/makeupseller point at /d/fy/npc/obj/... (same missing map). list after unlocking can_buy/youxun now prints an empty catalog instead of throwing. Content gap left as-is.

Shop — paid buy verified live

Official town map /d/fy is still missing, so there is no organic walk-up shop. Used the real F_DEALER NPC 游讯 (/adm/npc/youxun, id youxun / you xun): list without the temp flag is the designed refusal 我只卖消息不卖货; after call me->set_temp("can_buy/youxun", 1) the catalog is empty (missing gift files, skipped). Stocked one existing item (clone /obj/example/chicken_leg, id chicken / 烤鸡腿, value 30) via call youxun->set("can_carry", 1) + give chicken to youxun (clone accept_object accepts), funded with clone /obj/money/silver (一两 = 100). buy chicken → 你从游讯那里买下了一根烤鸡腿. Inventory afterward: 六十四文铜钱 + 烤鸡腿 (100 − 30×12/10 = 64; F_DEALER inventory markup val_factor 12). In-session price math + item receipt both confirmed.

Cloned example objects are not autoload; a relog after call me->save() kept the character but dropped the chicken/coins. That is the existing autoload design, not a new save bug. Driver killed by exact PID after the pass. Player-save timestamp churn left uncommitted.