Fengyun Rises Again II

✅ 可玩

风云再起Ⅱ — fy2

fy2

🔑 fluffos / Mud@2026 更新 029a4fd 2026-09-01 源码 下载 ZIP

▶ 开始游玩 · Play Now

河海大学计算机及信息工程学院开发,属于"风云"(Fengyun)武侠引擎家族,与 `fy2005`、`fengyun434`、`fy3xd`、`fy3dz` 同源;其中 `fy2qh`("清华仿写版")经逐文件核实,1,307 个域文件里只有 5 个不同,应视为本档案在另一处站点下的转发副本,而非独立开发的重制版。

English

Developed by the Computer and Information Engineering College of Hohai University, part of this project's "Fengyun" wuxia engine family alongside fy2005, fengyun434, fy3xd, and fy3dz. A file-level check found sibling fy2qh is virtually a byte-for-byte copy of this archive (only 5 of 1,307 domain files differ) — treat that as the same game re-surfaced under a different site label rather than an independently developed remake. Set in a jianghu drawn from Gu Long's wuxia novels, new players choose an ethnicity and start out at the Fengqiuhuang Inn or Chenxiang Town as a novice adventurer; the nearby "Money Gang" offers newcomers an easy first apprenticeship, and two long-running message boards preserve years of player-written poems and reflections.

README

内容亮点

在线试玩

https://mudlibs.fluffos.info/fy2/

管理员账号 / Admin account

警告:公开架站前请务必修改此默认密码。

本地运行

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

游戏端口:40014

NOTES · 移植与修复记录

fy2.rar → fy2

Status: DONE — boots clean, playable over telnet

Zero fixes needed to boot — clean on the first attempt. Full login flow confirmed (name-length validation, re-prompt).

What was fixed

Nothing needed for boot. Routine conversion: .c.lpc refs auto-fixed, 9 local angle-bracket includes converted to quotes automatically, staticnosave (39 files).

Known remaining issues

How to run

cd libs/fy2
~/src/fluffos/build-debug/src/driver config.fluffos
python3 ../../scripts/mudclient.py 127.0.0.1 40014 --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

WASM-enablement pass (loopback / admin seeding)

深度功能测试 / Deep functional test (2026-07-24/25, round two)

First real *playthrough* pass on this lib (all prior passes verified only registration + look/score/quit + WASM boot). Played as an ordinary new player through registration, exploration, organic sect-joining and skill-learning, combat, board reading, the emote system, shop purchase, a real quit with a debug.log grep, prompt AND long-wait net-dead disconnect/reconnect cycles, and a driver restart to confirm save persistence. Native driver (build-debug) only — WASM not re-verified this pass (all fixes are shared LPC/data-file changes with no WASM-specific risk, but stated explicitly rather than silently skipped).

Test characters kept as playthrough evidence (native saves, untracked): qinfengz/秦风 (male, 金钱帮 third-generation disciple under 荆无命, data/user/q/qinfengz/), duanyuu/段誉 (male, used for board/emote verification, data/user/d/duanyuu/), muyi/沐忆 (female, used for the final full-flow regression, data/user/m/muyi/). All in the Han-ethnicity start room 凤求凰客栈.

This lib turned out to share its lineage sibling fengyun434's and zzfy's already-cataloged bug classes almost exactly (confirmed, not just suspected), plus two bug classes new to this catalog.

Bugs found and fixed

1. adm/simul_efun/message.lpc — AGENTS.md §7.12, the shared tell_room() 2-arg exclude bug. Confirmed present (byte-identical to the unfixed copy fengyun434's own NOTES.md flagged as still-outstanding in this lib's own family). Fixed proactively before booting: exclude || ({ }). This was not just theoreticalobj/user.lpc's user_dump() (the NET_DEAD_TIMEOUT=900s force-quit handler, invoked from a call_out with no enclosing catch(), exactly §7.12's escalation shape) calls the 2-arg form on its very first line (tell_room(environment(), query("name") + "断线超过...", ...)), so an unfixed copy of this lib would have silently disabled the net-dead force-quit safety net on literally every timeout, for the same reason dtsl found live. Verified via lpcc (see below) and via exercising tell_room()/message_vision() throughout the whole session (room transitions, combat, board reads) with zero argument-type errors.

2. d/death/npc/bgargoyle.lpc, wgargoyle.lpc, d/death/inn1.lpc — AGENTS.md §7.24, death code stomping the permanent login-location field. All three death/limbo NPCs did ob->set("startroom", base_name(environment(ob))) right after moving a reincarnating/redeemed player to one of two waypoints (/d/fy/church, /u/guanwai/tower) — byte-identical to zzfy's own already-fixed instance of this exact bug, down to the same two waypoint paths and the same flavor-text message. Neither waypoint carries the valid_startroom flag that cmds/usr/save.lpc (the only other place that legitimately updates this field) requires. Fix: removed the set("startroom", ...) line from all three files, matching zzfy's established fix — the move() already handles the immediate post-death placement; future logins keep going to the player's real, previously chosen home. Not exercised via an actual live death this pass (see "Not verified live" below) but the code-shape match to zzfy's already-live-confirmed instance is exact.

3. std/room.lpc's make_inventory() — AGENTS.md §7.25, unguarded new()/move() chain. Reproduced live via lpcc: /obj/sbaa/ym (a room) populates /obj/sbaa/rong (an NPC) via its "objects" mapping; rong.lpc's create() calls set_skill("wu-shun", ...), a skill that doesn't exist in this archive's skill tables, which throws (*F_SKILL: No such skill (wu-shun)) from inside new() — uncaught, this aborted the ENTIRE ROOM's load (Fail to load object /obj/sbaa/ym), not just the one NPC. Fixed with the same catch(ob = new(file)) pattern zzfy already carries, plus an objectp() guard at the reset() call site (case-1 branch) since make_inventory() can now legitimately return 0. Re-verified via lpcc: /obj/sbaa/ym now PASSes.

New bug class: unguarded move()/restore() in a board's setup() collateral-damages its owning room (AGENTS.md §7.7-adjacent, new instance)

std/bboard.lpc's (and the parallel std/jboard.lpc's) setup() did move(loc); ...; restore(); with neither call guarded. Confirmed live, two independent trigger mechanisms:

Fix: catch() around both the move() and restore() calls in both std/bboard.lpc and std/jboard.lpc's setup() — a bad board (missing location, corrupt save data) now degrades to an unpopulated-but-present board object instead of aborting the caller's create().

Data fix, and an important correction to how to fix this class: data/board/fysquare_b.o and data/board/emoted.o (see next section) were the only two GBK-un-transcoded .o files in the whole lib (found by scanning every data/**/*.o for invalid UTF-8) — both re-converted with iconv -f GB18030 -t UTF-8. First attempt at this was itself subtly wrong and worth recording: this driver's save_svalue() writes an embedded real \n inside a saved string as a bare \r byte (NOT \r\n, NOT an escaped \n) — see src/vm/internal/base/object.cc's save_svalue()/restore_string() — and restore_object_from_buff() splits the WHOLE file strictly on literal \n bytes with no bracket-balance continuation logic, so a genuine \r\n pair anywhere in the body (this archive's .o files carry real Windows-style CRLF line endings pre-dating this project, most plausibly from the original Windows-hosted server or a Windows-based archival step) desyncs the whole file's variable-boundary parsing. A first-pass fix that blindly collapsed every \r\n\r broke data/emoted.o in a NEW way (see below) by merging the genuine top-level line boundary between its dbase (...) and emote (...) variables into one un-parseable statement. The correct fix needs a quote-aware scan: walk the decoded text tracking whether the cursor is inside an (unescaped) " string literal, and only collapse \r\n\r when inside one — every \r\n OUTSIDE a string literal is a genuine top-level statement separator and must stay a real \n. Re-derived both data/board/ fysquare_b.o and data/board/poem_b.o (see below) from the pristine git show HEAD:... bytes with this scanner; this restored ALL of poem_b's real 1998-era board posts, including a garbled multi-\r control-sequence-spam post from a player named "杰" that an earlier, cruder attempt at this fix had manually "cleaned" into one line — the quote-aware fix preserves it verbatim as the real archived multi-line content instead.

New bug class: data/board/poem_b.o's own save format was independently malformed (not the same as the class above)

Distinct from the GBK/CRLF issue above: poem_b.o (the "探花诗台" poem board, /d/fy/poemp) was already valid UTF-8 but still threw restore_object(): Illegal file format - 1 (...) — a DIFFERENT parse failure, traced to the exact same root mechanism described above (a genuine embedded \r\n from Windows-style archival splitting the "notes" mapping literal mid-value). Same fix (quote-aware \r\n\r collapse from pristine bytes) resolved it; see the shared writeup above.

New bug class: stale /d/wiz/ paths from a zone rename to /d/waterfog/ (AGENTS.md §7.18, new instance)

d/waterfog/hall1.lpc, d/waterfog/jobroom.lpc (both carry // Room: /d/wiz/....c header comments — the tell), and their two message boards obj/board/wizard_b.lpc/wizard_j.lpc, all hardcoded absolute exits/"location" values under the old /d/wiz/ path, even though the zone's own d/waterfog/entrance.lpc (which DOES exist, alongside the rest of this small wizard-lounge zone) already correctly uses __DIR__-relative exits for the same neighbors — the inconsistency is the tell, exactly per §7.18's detection guidance. A FOURTH live instance of the same stale path: feature/alias.lpc's anti-bot "you look like a script" auto-teleport (repeat_cnt > MAX_REPEAT, a genuinely reachable safety mechanism, not dead code) sent the accused player to load_object("/d/wiz/courthouse") — also nonexistent, would have silently move()d the player into environment 0 (§7.14's "no environment" shape) had it ever fired. Fixed all four to point at /d/waterfog/... (or __DIR__); added an objectp() guard on the alias.lpc teleport as defense-in-depth. Re-verified via lpcc: all affected files now PASS. Left alone, a genuine archive gap: d/waterfog/entrance.lpc's own "north" exit points at /d/wizard/bigroom.lpc (note: wizard, a THIRD spelling, not wiz or waterfog) — this file doesn't exist anywhere in the archive; documented here rather than fabricated per §7.14/AGENTS's missing-content policy.

New bug class: adm/daemons/emoted.lpc's shipped emote database was un-transcoded GBK, silently disabling the entire emote-command system

data/emoted.o (~72KB, the ENTIRE smile/nod/bow/wave/... emote pattern database, hundreds of entries) was raw GBK, same class as fysquare_b.o above. emoted.lpc's create() did if (!restore() && !mapp(emote)) emote = ([]); — restore() threw uncaught, aborting create() before even the set("channel_id", ...) fallback line, so this wasn't just "corrupt data ignored", it was every single emote command silently unrecognized (smile etc. all printed the generic "什麽?" unknown-command message) — reproduced live before the fix, confirmed fixed after (smile/nod both render correctly with their real Chinese flavor text). Same data-fix-plus-defensive-catch() treatment as the board class above; see that section for the quote-aware \r\n scanner this data file also needed (the first, cruder attempt silently produced an EMPTY emote mapping — mapp()-true but sizeof()==0 — because it merged the real top-level line boundary between this file's dbase (...) and emote (...) variables; confirmed via temporary efun::write_file()/keys(emote) instrumentation in create(), removed after diagnosis). Sibling lineage note: fy2qh (confirmed elsewhere to be byte-identical to this archive) carries the exact same corrupted data/emoted.ofysquare_b.o/poem_b.o were NOT checked there but are plausible candidates too, given the identical distribution; worth a follow-up pass on that lib specifically for this class rather than re-discovering it from scratch.

Bug found and fixed: feature/command.lpc's enable_player() — AGENTS.md §7.28, redundant add_action stacking

enable_player() (the shared command_hook dispatcher registration) did a bare add_action("command_hook", "", 1) with no idempotency guard. feature/damage.lpc's revive() — scheduled via a plain call_out every time a character is knocked unconscious in ordinary combat, not just death, so this is a very common repeat-trigger, not an edge case — legitimately re-calls enable_player() while already living(). Per §7.28's own documented caution, a living()-gated guard would be WRONG here (this lib doesn't have the exact mhxy-style sleep/wake shape, but revive()'s legitimate re-enable is the same class of false positive) — used the correct, call-count-independent fix: remove_action("command_hook", "") immediately before the add_action() call. Not reproduced live via an actual knockout+revive cycle this pass (see "Not verified live" below), but the fix is structurally inert for the normal case and was exercised indirectly many times over (every login, movement, apprentice/learn/combat/emote command in this whole session calls through command_hook, all continued working normally after the fix).

What was tested and confirmed working

Not verified live, and why

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

风云再起Ⅱ 基础版。

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

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

Independently re-verified against current code rather than trusting the extensive round-one writeup above. All 9 round-one fixes confirmed still present (code/data inspection for all 9, live re-exercise for the highest-value ones — tell_room, the board/emote data fixes, and the waterfog path fixes' zone was not re-walked but the underlying files were grep-checked). Found and fixed two new standard-checklist gaps, plus one genuinely new §7.90-class eval-cost crash not caught by round one.

New fix: §7.90-class eval-cost abort during make_body() — 100% reproducible on this lib's configured budget

First admin login this pass hit a real, live *Too long evaluation abort during get_passwd()/make_body() (maximum evaluation cost : 300000, the low end of this project's range). Fixed with the established remedy: config.fluffos5000000. Verified: fresh reboot, first login attempt succeeded cleanly (previously failed), zero eval-cost errors for the rest of the session.

New fix: adm/simul_efun/file.lpc — same §7.11-class gap as sibling fengyun434

log_file() had no assure_file() guard, cat() had no null-guard. Fixed both (with the forward declaration this driver requires).

New fix: two active printf("%O\n", ob) debug leaks in logind.lpc

Byte-identical shape and location to fengyun434's own finding earlier this session (both name-confirmation branches, right before the password prompt) — this lib shares that sibling's logind.lpc lineage closely. Removed both.

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

Verification method

Booted native build-debug driver, admin login (fluffos/Mud@2026). update /adm/daemons/logind as the real privileged-action check (succeeded). Two full rapid reconnects, both clean fresh logins (this lib's net_dead() design never void-parks, matching fengyun434's own sibling architecture). Same test-harness pacing note as fengyun434: this lib's id/password prompts need individually-paced sends, not a batched multi burst. Driver killed by exact PID after each reboot (two total: initial boot where the eval-cost crash was found, clean reboot for verification); incidental fluffos.o save-timestamp churn reverted before commit.

Files modified this pass

§7.100 sweep fix (ROOM base-class redundant replace_program())

#define ROOM "/std/room": deleted 525 redundant, live, standalone replace_program(ROOM); lines (kept inherit ROOM;) — 524 caught by the scripted sweep, plus 1 hand-fixed instance in this lib's room-building tool (obj/roommaker.lpc)'s "clone this room" string-builder template. work/data/ holds 85 real .lpc source files (per-account starting-equipment templates named e.g. data/login/g/god/god896950960.lpc), independently checked and confirmed to contain zero occurrences of the bug pattern — not a real gap in the sweep. 3 pre-existing //-commented instances remain untouched, confirmed harmless. Verified via a clean build-debug driver boot (0 new compile errors, port 40014 listening, zero new "cannot replace"/"cannot bind" debug.log lines); no full §10.7 gameplay walkthrough this pass.

§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.