Xia Ke Xing 100 (Ode to Gallantry — Centennial Edition)

✅ 可玩

侠客行一百 (Xia Ke Xing - Yi Bai)

xiakexing100

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

▶ 开始游玩 · Play Now

取材自金庸小说《侠客行》,作者 "Coollizard" 与 "xkx100" 团队自 2001 年起维护,属于本项目"Century 家族"(`adm/single/` 目录结构)武侠 mudlib 分支之一,是这批游戏中文件数量最多的一个(转换后约 1.2 万个 LPC 文件),经比对代码库与本项目另两款同名"侠客行"游戏 xiakexing2017、xiakexing3(二者彼此是关系密切的近亲)截然独立;游戏世界以北京、长安、洛阳、扬州等真实历史地名为骨架,覆盖全国多个"出生地",新角色从随机分配的出生城市客栈起步,创建时可选择冒险、谨慎、可人、睿智、坚韧五种性格类型,影响初期属性倾向;可通过寺前武僧一类 NPC 拜入少林门下,在木人桩前安全习武过招;此外还有一套与现实时间并行显示的独立"侠客行历法"。

English

Based on Jin Yong's novel Ode to Gallantry (Xia Ke Xing), developed since 2001 by author Coollizard and the xkx100 team. It belongs to this collection's "Century" mudlib family (built around an adm/single/ directory layout) and is the largest of that group by file count — roughly 12,000 LPC files after conversion, and confirmed to have a distinct codebase from this collection's other two Xia-Ke-Xing-titled libs (xiakexing2017, xiakexing3), which are themselves close siblings of each other. Its map is built around real historical Chinese cities, including Beijing, Chang'an, Luoyang, and Yangzhou, with new characters starting at a randomly assigned home-city inn (e.g. Jiaxing's "Misty Rain Tower"); at creation, players also pick one of five personality types (Adventurous, Cautious, Likable, Wise, Resilient) that nudges their starting stat spread. New characters can apprentice into the Shaolin sect through the monk Qingwei at the temple square, becoming a lay disciple of Shaolin's 41st generation, and spar safely against the temple's wooden training dummy while learning kung fu. An independent "Xia Ke Xing calendar" clock runs alongside real time.

README

内容亮点

在线试玩

https://mudlibs.fluffos.info/xiakexing100/

管理员账号 / Admin account

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

本地运行

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

游戏端口:40037。这是本批游戏中体积最大的一个,启动后请稍等片刻 再连接。

NOTES · 移植与修复记录

xiakexing100 — 侠客行一百

Archive: 侠客行100.rar. Port: 40037. Status: done (boots clean and quick, full registration flow verified end-to-end including a real Chinese name).

What this is

"侠客行一百", credited to "Coollizard & xkx100 2003-2004", http://yoyo.xm.fj.cn/xkx100, up since 2001-01-14 per its own connection banner. Same "Century-family" adm/single/{master,simul_efun} layout as shiji/zhonghua2/shujian2008/etc. ~14,227 raw files, 12,209 after .c.lpc rename — the largest lib processed in this session run.

Fixes applied

1. AGENTS.md §15h, standard shape: is_chinese()'s GBK lead-byte check → CJK codepoint check; check_legal_name()'s byte-count bound < 4 || > 10 → character-count bound < 2 || > 5, removed the i%2==0 even-byte-offset gate. 2. Confirmed NOT needed, via source reading: no §4 fix (master.c's valid_write gates via find_object only, valid_read is a bare return 1;); no deep named.lpc fix (named.c exists but lacks the PATH()/sliding-window pattern seen in the nitan-family shape — a simpler, different implementation here). 3. AGENTS.md §15p: /adm/daemons/network/dns_master was in adm/etc/preload — removed proactively before the first boot attempt. Booted clean in under 20 seconds, zero compile errors, no hang.

Interactive test result — full registration flow

No hidden pre-id prompts. Verified the complete registration path in one continuous connection: id xkxbtest → confirm yreal Chinese name 秦风 (avoiding "韦小宝"/Wei Xiaobao — a famous Jin Yong character found in this lib's banned_name list) → accepted, proceeds straight to "请设定您的密码:".

lpcc sweep

12,209 files, 12,118 pass / 91 fail (99.3%). Failure tail dominated by an accept_hit type-mismatch cluster (120 of the reported instances across files, string vs object argument), plus the usual handful of missing globals/syntax typos — not triaged individually per AGENTS.md §6b/§13. Memory stayed comfortably healthy throughout the sweep despite this being the largest lib in the current session run (~13GB free consistently, lpcc RSS peaked well within normal range, no pressure requiring an early kill).

Re-verification pass (driver rebuild + LPC formatter + WASM build)

WASM-enablement pass (loopback-allow / admin seeding)

Applied the four standard WASM-first changes (AGENTS.md §1.3b/§1.3e/§1.5).

1. Loopback always allowed — ban list + per-IP throttles (adm/daemons/logind.lpc:73-124)

logon() ran BAN_D->is_banned(), an in_login > 10 per-IP in-progress-login throttle, and BAN_D->is_multi() (per-IP character cap) unconditionally. Added an is_local local computed once and gated all three on !is_local.

Written fail-closed from the start (2026-07-24): is_local = (stringp(lip) && (lip == "127.0.0.1" || strsrch(lip, "127.") == 0)) — only a genuine loopback-shaped string is treated as local; an unparseable/non-string ip is NOT local and still goes through the ban list and both throttles. (An earlier partial pass on this file had used the fail-open shape seen on this batch's other four libs — !stringp(lip) || lip == "127.0.0.1" || strsrch(lip, "127.") == 0 || sscanf(lip, "%*d.%*d.%*d.%*d") != 4, which let ANY malformed ip bypass every gate — but that was corrected to the fail-closed form above before this pass was considered complete; see the sibling libs' NOTES.md entries for the full rationale: the old WASM driver bug that produced garbage query_ip_number() output is now fixed, so there is no reason left to treat "can't parse it" as "must be loopback".)

2. Uptime startup gates — none present

No uptime() < N connection-rejection gate exists in this lib. All uptime() hits are in-game content: gambling rooms (d/*/duchang*.lpc, npc/douji, npc/saigui), NPC/room respawn timers, cooldowns, and adm/daemons/autosaved.lpc's once-per-boot data-file initialization (if (uptime() < 400) { ...write_file... } — first-boot bootstrap of some /data/* flags, not a connection gate). Nothing to bypass.

3. Anti-flood throttles — covered by item 1

No separate registration-throttle daemon exists; the per-IP protection in this lib IS the in_login/BAN_D->is_multi() checks patched above, already loopback-exempt.

4. Admin account seeded — fluffos / Mud@2026 / 浮浮

Registered through the real flow (id fluffosy → 浮浮 → test1234/confirm → talent 1/20/20/20/y → personality 0 → email → m), landed in a random starting room. Granted (admin) by appending fluffos (admin) to adm/etc/wizlist (securityd.lpc's get_status() reads this file into wiz_status). Verified: login as fluffos shows 目前权限:(admin), update /adm/daemons/logind重新编译 /adm/daemons/logind.lpc:成功!.

Save files for the orchestrator to force-add (untracked, not gitignored):

Bonus fix: quit/exit was silently broken for EVERY player (pre-existing, not WASM-related)

While verifying the admin account's quit, discovered cmds/usr/exit.lpc's savequit() never actually let anyone quit: int a = 1; is reassigned inside the if (link_ob) {...} branch to a = (link_ob->save()), and link_ob (me->query_temp("link_ob")) is the /clone/user/login connection object set by enter_world()/reconnect() on every login, not just a rare possession/reconnect edge case. FluffOS's save_object() efun returns the byte-size of the text written on success (confirmed by reading ~/src/fluffos/src/vm/internal/base/object.cc's save_object_recurse(), which accumulates and returns textsize), not a 0/1 boolean — so a ends up as some multi-hundred-byte count, and the final check if (a == 1 && me->save()) was false for virtually every quit, for every character, admin or not. The player saw all the normal quit text ("你共停留了...欢迎下次再来!") followed immediately by a scary "警告:档案保存失败,无法退出游戏,请马上联系巫师解决。" and was never actually disconnected (destruct(me) never reached). Confirmed present verbatim in the original raw archive (raw/xkx100/cmds/usr/exit.c), so this is a decades-old author typo/driver-assumption mismatch, not something introduced by this project's conversion or by the WASM pass. Fixed: if (a == 1 && me->save())if (a && me->save()) (test truthiness, matching the efun's actual 0=fail/nonzero=success contract). Verified with a fresh registration and with the fluffos admin account: quit now completes cleanly with no warning and no lingering interactive body.

Retest (2026-07-24)

Fresh boot, fresh registration (id qinlanx/qintestb, real Chinese names 秦岚新/秦测三) through look/score/quit — landed in a starting room, correct score output, clean quit with no warning. fluffos/Mud@2026 admin login verified: look then update /adm/daemons/logind重新编译 ... 成功!, then clean quit (the bonus fix above). Zero 执行时段错误 lines in debug.log across the whole session (the one hit from an unrelated missing-log/nosave/ directory surfaced only while probing the quit bug with the call wizard command directly on a userp target — log/ is fully gitignored/regenerated at boot, not a real defect worth chasing further here). Test characters removed afterward; fluffos kept. Reverted an incidental data/topten.o leaderboard diff caused by the test registrations (pre-existing tracked file, not meant to churn from QA runs).

深度功能测试 / Deep functional test (AGENTS.md §10.7, 2026-07-24)

One continuous native session (~/src/fluffos/build-debug/src/driver, port 40037), following the §10.7 checklist end to end: read help intro/help newbie/help newbie-basic/help newbie-shaolin1 first, registered a real Chinese name (qftester / 秦风, password test1234, born 嘉兴/group 3, talents 20/20/20/20, personality 0), landed at /d/jiaxing/yanyu ("烟雨楼"), look/score/i/hp all correct. Explored on foot toward 牛家村 reading room .lpc source (d/jiaxing/*.lpc) to navigate since exit lists intermittently hide under the lib's night-time darkness gate. Used the wizard spgo/ summon commands (via the seeded fluffos admin) purely to fast-travel the SAME test character to distant content (少林寺 练武场/广场) rather than trekking the whole map by foot — the actual sect-join, skill-learn, combat, and shop interactions below were all performed by the ordinary player character, not the admin.

Safe sparring: the newbie guide's suggested targets (a village 小孩/女孩) both declined fight — traced this to their attitude being genuinely "friendly" in their own create() (/d/village/npc/ kid.lpc, /d/village/npc/girl.lpc), which inherit/char/npc.lpc's accept_fight() is coded to always decline (case "friendly": ... return 0;) — working as designed, not a bug (a different, unrelated /d/jiaxing/npc/boy.lpc//d/village/npc/boy.lpc with attitude: "peaceful" momentarily looked like a mismatch until the actual live object path was confirmed via call obj->query(...) — red herring, not reused). Used the lib's own documented, code-confirmed-safe wooden-dummy mechanic instead (d/shaolin/obj/mu-ren.lpc, accept_fight() checks me->query("damaged")/a random(fight_times)>=10 break-chance, exactly the §10.7-item-3 shape): fight mu at /d/shaolin/wuchang1 exchanged several rounds of blows with correct combat text, halt ended it cleanly, hp/i afterward correct, zero debug.log errors.

Skill/sect join: followed help newbie-shaolin1's documented path — apprentice biqiu (清为比丘 at /d/shaolin/guangchang1w) immediately accepted as a 俗家弟子/少林派第四十一代弟子 (no manual ask ... about 出家/kneel needed for this particular monk); score showed 师父/称谓 updated correctly; skills biqiu listed the master's own skill roster; xue biqiu dodge 1 (organic NPC-teacher path) advanced 基本躲闪 from unlearned to 1/0, cha confirmed it. Both the sect-join and skill-learn steps worked correctly, no separate admin-command shortcut was tested (none is needed/expected in this lib — apprentice IS the join mechanism).

quit → debug.log → reconnect (§10.7 items 5, 8, 9): clean quit produced no warning (confirms the pre-existing savequit() fix from the "Bonus fix" section above still holds) and left zero new debug.log lines. Net-dead (dropped the connection without quit) and reconnected PROMPTLY (a few seconds later): worked correctly, position/state intact. Net-dead and NOT reconnecting until the real timeout elapsed found a new, live-reproduced bug — see below. Separately, clean quit followed by a genuine ~75-real-second wall-clock gap, then a FULL fresh login (not a net-dead reconnect) via qftester/test1234: correctly restored sect membership, skill, and all score fields from the on-disk save file (data/user/q/qftester.ofamily mapping, skills/learned mappings, dbase.qi/jing etc. all intact).

Shop purchase (§10.7 item 6): character had no starting funds ("你没有存款"), so used the admin account to clone /clone/money/coin, call coin->set_amount(500), spgive qftester coin (funding only — the purchase itself was performed by the ordinary player character). list at 烟雨楼's 店小二 showed the menu correctly; buy jitui (30 文) succeeded, correctly made change into higher denominations (500 铜钱 → 1 烤鸡腿 + 4 两白银 + 70 文铜钱); eat jitui consumed it. No errors.

Not verified live: progression to a real death/respawn cycle — the session budget went to the net-dead bug investigation below instead; code review only (d/city/ghost*.lpc/鬼门关 revival flow referenced by help newbie-basic's〖死亡〗section was read but not exercised). A sect promotion (拜达摩/升辈) is a multi-hour undertaking per the newbie guide's own admission and was not attempted.

Bug found and fixed: tell_room() 2-arg wrapper crashes the net-dead force-quit handler — matches AGENTS.md §7.12 exactly (severity-escalated instance)

adm/simul_efun/message.lpc's tell_room() wrapper:

varargs void tell_room(mixed ob, string str, object *exclude) {
  if (ob) message("tell_room", str, ob, exclude);   // BEFORE
}

Every 2-argument call site leaves exclude as LPC's default int 0 (not an empty array), and the real message() efun's 4th argument rejects a bare 0. clone/user/user.lpc's user_dump() — the NET_DEAD_TIMEOUT-driven (900s / 15 real minutes, include/user.h) force-quit handler that runs when a net-dead player never reconnects — calls tell_room(environment(), ..., "\n") with only 2 args at its very first line (the DUMP_NET_DEAD case). This is byte-for-byte the same lib/function/case/timeout shape AGENTS.md §7.12 documents as "severity-escalated" from dtsl's deep functional test: the crash aborts user_dump() at that exact statement, so the two lines after it ("/cmds/usr/exit"->savequit(this_object())) never run — silently disabling the entire net-dead force-quit safety net: a player who net-deads and never manually reconnects would stay alive in server memory forever (never actually saved-and-removed via this path) until a driver restart.

Live-reproduced (not just pattern-matched): temporarily lowered NET_DEAD_TIMEOUT from 900 to 12 (include/user.h), ran the wizard update /clone/user/user command to recompile it, connected as qftester, dropped the connection without quit, waited past the shortened timeout:

执行时段错误:*Bad argument 4 to EFUN message()
Expected: object, array,  Got: int(0).
程式:/adm/single/simul_efun.lpc 第 77 行
呼叫来自:/clone/user/user.lpc 的 user_dump() 第 75 行,物件: /clone/user/user#105 ("秦风")
呼叫来自:/adm/single/simul_efun.lpc 的 tell_room() 第 77 行

Fixed (the standard AGENTS.md §7.12 wrapper fix, protects every 2-arg call site in the lib at once, not just this one):

varargs void tell_room(mixed ob, string str, object *exclude) {
  if (ob) message("tell_room", str, ob, exclude || ({}));   // AFTER
}

Re-verified with the same shortened-timeout methodology: no crash, debug.log clean, and who afterward showed only the admin online — qftester was correctly force-quit-and-saved this time (confirms the two previously-dead lines, including savequit(), now execute). Restored NET_DEAD_TIMEOUT to 900 and did a full clean driver restart before finishing (the test-only timeout value was never left in place).

Note for the project: two other confirmed "Century/adm-single" lineage siblings (AGENTS.md §11) — shiji and xjcq2000 — still carry the exact same unfixed 2-arg tell_room() wrapper in their own adm/simul_efun/message.lpc (checked via grep during this pass, not fixed — out of scope for this task, which is xiakexing100-only). shujian2008, xkxz2, and zhonghua2 (same family) already carry the fix from earlier passes. Worth a follow-up pass on shiji/ xjcq2000 specifically for this bug given xjcq2000 is also the lib AGENTS.md §10.8 documents hitting an unrelated driver-fatal crash ~25 minutes into its own net-dead soak — the two are different bugs but both live in the same net-dead code path family.

Observation, not fixed (design ambiguity, see §10.7's scope note): two independent day/night clocks can visibly contradict each other

cmds/std/look.lpc's exit-listing darkness gate (天色太黑了,你看不清明显的出路) keys off NATURE_D->game_time(), which derives an in-game shichen (時辰) hour from a heavily-compressed calendar clock (adm/daemons/natured.lpc: #define TIME_TICK ((time()%(60*24*3600))*365) — 60 mud-years pass every 60 real days, i.e. roughly 6 mud-hours per real minute, confirmed live: the session's in-game date advanced across several 时辰 within a couple of real minutes). The SEPARATE sun-position flavor line (NATURE_D->outdoor_room_description()) keys off current_day_phase, a nosave variable advanced by its own independent real-time call_out("update_day_phase", ...) cycle. These two clocks are not synchronized and were observed live disagreeing outright in the same room printout — "一轮火红的夕阳正徘徊在西方的地平线上"(sunset flavor text) immediately followed by "天色太黑了,你看不清明显的出路" (darkness gate, only fires for 亥/子/丑/寅时) moments apart, and at one point "太阳正高挂在西方的天空中"(afternoon flavor text) paired with the SAME darkness message. Purely cosmetic/exit-listing (movement in a known direction still works even when the list is hidden — confirmed by navigating through several "dark" rooms via directions read from source), and both clocks' formulas are pure LPC business logic with no encoding/efun/grammar involvement, so this is very plausibly authentic original-game behavior rather than anything this project's conversion introduced. Documented per §10.7's scope note rather than "fixed" by guessing which clock should govern the gate.

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

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

针对驱动升级(quest_times/win_times %-operator 修复 + Warning/warning 大小写回退兼容)做的重测。

发现并修复的 PROGRAMMING bug

1. log_file()adm/simul_efun/file.lpc)完全没有 assure_file() 保护(AGENTS.md §7.11-class):已加上前向声明 + assure_file(LOG_DIR + file);

Proactive checks(无需改动)

实测过程

管理员 fluffos/Mud@2026(此前 WASM 阶段已注册并提交存档)用真 实密码重新连线,落地在此前保存的地点(车马店),score 正常显示 天赋/属性,quit 前的游戏内状态与存档一致。全程 debug.log 只有 正常的编译期提示(Unknown #pragma 等价的 In file included from 追踪行、未使用局部变量),无运行时错误。驱动按精确 PID 结 束;测试期间产生的存档时间戳增量已 git checkout -- 还原,未提 交无关变化。

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

ROOM 基类冗余 replace_program(ROOM); 自崩溃地雷(详见 AGENTS.md §7.100):4430 处命中,其中 d/huangshan/banshan.lpc 是本项目已见 过多次的"同一个 create() 里两处独立冗余调用"形状(setup() 前 后各一次),两处均删除。自带建房工具 clone/misc/roommaker.lpc 的 字符串拼接模板同样修复。

git diff --stat:4428 files changed, 1 insertion(+), 4430 deletions(-), 与预期精确吻合。

验证:build-debug 驱动真实冷启动,端口 40037 正常监听。既有管理 员账号 fluffos(登录密码为 Mud@2026,与原始注册记录的 test1234 不同,二者都在 NOTES 中留档过)登录,目前权限:(admin) 确认,车马店→南大街→车马店多房间走访无误,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): 4 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.