Romance of the Three Kingdoms MUD (sgz snapshot)

✅ 可玩

三国志MUD

sgzmudsgz

更新 66a3bd8 2026-10-28 源码 下载 ZIP

▶ 开始游玩 · Play Now

2000 年前后的 Lima mudlib 三国志游戏,来源是档案 `145_sgzmudsgz_三国志MUDsgz.tar.gz` 里的 `sgz/lib` 树(同档还有 `sgz_old` / `sgzmud`,本馆只用这一份)。和馆里已经 playable 的 `sanguozhi`(162,GitHub `fluffos/sanguozhi`)是同一家族的**不同快照**。145 已改到共享默认 FluffOS(不再需要 `ARRAY_RESERVED_WORD` / `fluffos-wilderness`)。

English

A year-2000 Lima-mudlib Three Kingdoms game from the sgz/lib tree of archive 145. Distinct from the later GitHub sanguozhi snapshot (162). Runs on the shared default FluffOS (no ARRAY_RESERVED_WORD). New players start in 华阴草庐 (/a/huayin/vhall) with water-mirror NPC, a village map, nations, troops and historical horses.

README

新玩家在华阴草庐(/a/huayin/vhall)落地:水镜先生、大砍刀、草庐留言板;西边是小村中心。中文名不能用三国人物真名(刘备、赵云会被拒)。AUTO_WIZ 在这份存档里是关掉的;Admin 域里已经有 2011 年线上巫师,所以新号是凡人,直接进档案世界,不必先走巫师大厅的轮回台。

内容亮点

在线试玩

https://mudlibs.fluffos.info/sgzmudsgz/

试玩账号 / Play account

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

本地运行

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

游戏端口:40196。走共享默认 FluffOS,不要用捆绑的 32 位 ELF,也不要再用 ~/src/fluffos-wilderness。

NOTES · 移植与修复记录

sgzmudsgz(三国志MUD)-- 当前 FluffOS 移植笔记

档案 archives/145_sgzmudsgz_三国志MUDsgz.tar.gz。嵌套树里只有 sgz/lib 是完整可玩 mudlib(sgz_old / sgzmud 不用)。2026-08-05 曾按「必须跟 32 位 Linux 2.0 捆绑 ELF」清出馆外;用户 2026-09-11 要求改到当前 FluffOS。这不是空骨架,不要造 void。

编号 145,端口 40196。手足 sanguozhi(162)是已经改过共享 FluffOS 的后来快照,不能拿 162 顶替 145。

驱动

不再需要 #define ARRAY_RESERVED_WORD / ~/src/fluffos-wilderness。 Lima array 类型已改成 mixed * / string *(leftover 656), check_config.lpc 的 create() 已掏空,master.lpc 补了 UID applies。set_this_player() 按 sanguozhi 全部 no-op(默认驱动只在 NO_ADD_ACTION 分支暴露这个 efun)。

走共享默认驱动:

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

站点 WASM 也走共享 ~/src/fluffos/build-wasm/src,不再进 scripts/custom_drivers/wilderness/。wilderness 自己仍要那份二进制。

config.fluffos:mudlib directory 指 work/,log directory : /log 相对启动 CWD(必须 cd libs/sgzmudsgz 再跑 driver), inherit chain size : 300,global include file : <global.h>。

转码

GB18030→UTF-8(排除 *.tbz2 / *.zip / *.exe / WWW.bak): already_utf8=2214 converted=5461 lossy=74 skipped_binary=78,约 3546 个 .lpc。登录中文是干净的。

当前 FluffOS 上编不过 / 连不上的修法

无类型 array 再下标,现代驱动把元素当成 unknown:

.c→.lpc 后缀长度:cmd_d / spell_d / quest_d / troop_type_d / cmds/player/cmd 的 [0..<3] 改 [0..<5], 否则 quit/help 对不上。

global.h 补 ADDR_SERVER_IP / ADMIN_EMAIL(login.lpc 和 secure_d 要用)。is_chinese() / valid_chinese_id() 改 Unicode 0x4e00–0x9fff(§8.1)。simul_efun/string.lpc 的 create() 去掉 nosave,跳过 chr(0)。master.lpc parser_error_message 的 array descs → mixed * descs。check_config.lpc 的 create() 去掉 nosave。

doc_d.lpc 后半段 get_dir 类型仍编不过(preload catch,不挡登录)。

机械去掉 array 关键字时,Lima string array a, b 里的标量 b 曾被误加成 string *。char_obj 因此编不过,登录会被送去极乐世界。 已按 sanguozhi 把混写声明改回(char_obj / check / country_d 等)。

实测(本机默认 FluffOS,端口 40196)

fluffos / Play2026x / 云游。Admin 域已有历史成员, 号是凡人,进档案 START /a/huayin/vhall 草庐:水镜先生、 大砍刀、草庐留言板。look / west(小村中心)/ score(云游 / fluffos / 汉末 / 白身)/ quit 都通。

不要用捆绑的 etc/driver 32 位 ELF。不要用 ~/src/fluffos-wilderness。

WASM(2026-09-11 leftover 656)

共享默认 ~/src/fluffos/build-wasm/src:fluffos / Play2026x 进草庐,look / score(云游)/ quit 通过。socket.lpc 在 WASM 下没有 socket efun(I3/HTTP),不挡登录。doc_d 仍编不过,preload catch。

深度功能测试(§10.7,2026-09-13)

本轮在共享 mudlib 上另开驱动端口 41196(PID 4010321,本会话 拉起;未动 既有 40196/PID 2421649)。账号 sgzptac / Play26aa / 测辛。

发现并修复

1. HZK2ASC_D 在 UTF-8 库上整题崩成 ====== BUG ======。 HZK16/24 点阵按 GBK 索引;转码后 hzk2asc16/24 失败。 work/daemons/hzk2asc_d.lpc:转换失败时回退明文 s。 2. 厨娘砍柴交工的机器人题依赖 HZK,UTF-8 下不可答。 work/sgdomain/robot/queitem.lpc:改为明文分类题,并在 四选一串里加 、 分隔。zi.lpc:字号题同样去掉 HZK 包装。 3. **挖地(digsoil)对象仍挂在旧 wiz/emperor/huayin 虚图,未接进 已转码的 a/huayin/*。** 新手「ask money」也指去 digsoil—— 本轮不造房,记为已知缺口;经济切片改走砍柴。

游玩证据

日志

Do not invent digsoil rooms. Empty numbering rows (mhxy2002/fy4/jy/ hylib/dtxy) stay confirmed duplicates.

深度功能测试(§10.7,2026-10-04)— 连续两次未捕获的错误会让会话哑掉

secure/user/inputsys.lpc 只在输入处理函数正常返回后才用 modal_recapture() 重新挂上 input_to()。处理函数里一次 未捕获的错误会跳过它,下一行输入走 process_input() 兜底;兜底里再出一次错,驱动(comm.cc 的 process_input)就对这条 连接永远停用 process_input(),之后每一行都落到普通命令解析器,只回「What?」,只有重连才能恢复。原树复现:往 cmds/player 放一条 main() 里 int *a; a[0] = 1; 的命令,连敲两次,再 look。玩家把同一条出错的命令敲两遍就会碰上。

dispatch_modal_input() 现在把处理函数调用和 ! 转义都包进 catch(),其后照旧 modal_recapture()(上游 Lima 的做法); error_handler() 仍会给玩家打印错误和「Trace written to」(日志改记 /log/catch)。实测:连续四次出错后 look、i、 !look 都正常。KB 06 §7.217。

深度功能测试(§10.7,2026-10-05)— here-document terminators

scripts/lpc_fix_heredoc_terminator.py --all --apply: 1 here-document block(s) repaired (0 with the terminator glued to the last text line, 1 with it indented), so End of file in text block no longer hides the room or object behind them: wiz/lei/room/startroom.lpc. The terminator must start its line (the lexer's own test, KB 04 §6.10); a glued one lost its newline in the GBK -> UTF-8 conversion together with a half character, which stays out.

2026-10-05 — T array a, b 转换遗漏

四个 nation_menu.lpc(cmds/area、wiz/edc、wiz/xiaobai/menu、wiz/mimi)的 string * keys, dis; 由原文 string array keys, dis; 转换而来,dis 丢了 *(MudOS 的 array 属于类型,两个名字都是数组)。补回 *;运行时驱动不检查局部变量类型,所以以前也能用(KB 03)。

深度功能测试(§10.7,2026-10-06)— 编译警告整理

scripts/lpc_warnings.py sgzmudsgz --fix:无用局部变量 216 个、varargs 8 处、裸 return 3 处、nosave 函数 136 个改 protected(8 个去掉),共改动 136 个 .lpc。HEAD 与工作树分别加载(新进程):134 -> 134 通过,无回退;scripts/lpc_audit_removed_locals.py HEAD 检查 291 个删除的声明,0 条需看。 手工:

启动时警告 139 -> 0;新进程登录(标题画面、new 注册、英文名确认)正常。

深度功能测试(§10.7,2026-10-08)— .lpc 后缀的定宽切片

.c 改名 .lpc 时只改了字符串没改切片宽度:f[<2..] == ".lpc" 拿两个字符比四个字符,永远不成立(!= 永远成立),按后缀筛文件、去后缀的代码因此从不运行或截成 x.l(KB 06 §7.238)。scripts/lpc_lpc_suffix_slice.py --apply 改了 8 处比较、2 处去后缀(如 daemons/doc_d.lpc);改动的文件 HEAD 与工作树分别加载(新进程),无回退。

深度功能测试(§10.7,2026-10-08)— 编译警告整理

scripts/lpc_warnings.py sgzmudsgz --fix 加 scripts/lpc_fix_no_effect.py --apply,共改动 311 个 .lpc(多为删去未用的局部变量)。HEAD 与工作树分别加载(新进程):306 -> 306 通过,无回退。启动时警告 0 -> 0;新进程登录(输入名字)正常。 (这一轮用分块扫描重跑:上一轮单次 lpcc --batch 中途死掉,只扫到 3546 个文件里的 1452 个。) 记录、未改:分块扫描时 daemons/warai_d/warai_d.lpc、wiz/edc/code/troop_d.lpc、wiz/edc/code/warai_d.lpc 让 lpcc 进程死掉(Too deep recursion)。它们是放在子目录里的旧副本,inherit __DIR__ + "warai_d/attack" 指向不存在的 .../warai_d/warai_d/attack,master 的 compile_object() 又按“上一级同名文件”去找 warai_d.lpc 的 virtual_create(),于是加载自己、无限递归。真正在用的是 /daemons/warai_d.lpc、/daemons/troop_d.lpc(include/daemons.h),这几个副本没人加载。

深度功能测试(§10.7,2026-10-11):“无副作用表达式”警告复查

编译警告收尾(2026-10-12)

scripts/toolkit_fix.sh 一轮加手工收尾,能编译的文件警告清零。改动的对象加全部继承 FURNITURE/M_MOUNTABLE 的家具 HEAD 与工作树各载入一次:58 个,HEAD PASS 58,tree PASS 58,regress 0。

旧驱动的类型宽松:缺省参数、无类型形参、数组初始化、class 变量(2026-10-19,KB 04 §6.19、§6.20)

原来的 MudOS 把调用少传的参数补 0、把没写类型的形参当 mixed、不检查变量的声明类型与初始值,也允许变量叫 class;这个驱动在编译时全部拒绝,整个物件载入失败。修了 2 个文件:/secure/modules/m_file.lpc、/wiz/flee/law/ev_judge.lpc(scripts/lpc_round_files.py 的修复轮:调用处补写 0、无类型形参补 mixed、string X = ({...}) 补星号、void 函数的返回值,以及 class 变量改名 pick_class)。逐个文件在 HEAD 和改后载入对比:这些文件里 0 个原来载入失败、现在载入,没有退步。

member_array('/', str) 改为 strsrch(str, "/"):字符字面量的 member_array 按字节搜索(2026-10-20,KB 06 §7.283)

member_array('/', str) 里的 '/' 是整数,驱动按 UTF-8 字节搜索,返回字节偏移(带第三个参数时起点也是字节);最新的 FluffOS(923cdbc0)在字符串里有非 ASCII 文字时,对每个调用点警告一次(Warning: member_array(int, string) searches BYTES)。而 str[0..idx-1] 按字符切,中文字符串会在错误的位置截断。改为 strsrch(str, "/")(找不到同样返回 -1,按字符计数;scripts/lpc_fix_member_array_char.py,JSON 编码器等少数几处手改)。改动:/daemons/channel_d.lpc(2 处)、/daemons/guild_d.lpc(1 处)、/daemons/help_d.lpc(1 处)、/daemons/news_d.lpc(2 处)、/daemons/sghelp_d.lpc(1 处)、/daemons/soul_d.lpc(2 处)、/obj/helpsys.lpc(1 处)、/secure/daemons/cmd_d.lpc(2 处)、/secure/daemons/secure_d.lpc(5 处)、/sgdomain/modules/war_grid.lpc(1 处)、/std/grid_server.lpc(1 处)、/std/modules/m_ansi.lpc(1 处)、/std/modules/m_glob.lpc(1 处)、/std/modules/m_set.lpc(1 处)、/std/room/parsedsc.lpc(2 处)、/trans/obj/admtool/security.lpc(1 处)。

if (x = 常量):条件里写成赋值的比较(2026-10-20,KB 06 §7.290)

if (arg = "button" || arg = "按钮")、if (!arg || arg = "") return 0;、else if (check = 0 && tempB != ""):把 == 写成了 =,条件的值就是那个常量,分支对所有非零数和任何字符串(连 "" 都算)永远成立、对 0 永远不成立,变量还被覆盖;驱动对此没有任何警告。每一处 = 改成 ==(scripts/lpc_fix_cond_assign.py,共 11 处)。改动:/cmds/verbs/money.lpc(1 处)、/sgdomain/troops/bowman.lpc(2 处)、/sgdomain/troops/cavalry.lpc(2 处)、/sgdomain/troops/commando.lpc(2 处)、/sgdomain/troops/footman.lpc(2 处)、/sgdomain/troops/infantry.lpc(2 处)。

登录密码超过 255 字节:crypt() 抛错(2026-10-20,KB 06 §7.294)

驱动的 crypt() 对超过 255 字节的密钥直接报错(Error in crypt(), check your salt),老驱动则按任意长度散列。在登录提示符下输入 256 字节以上的密码,密码检查那一行就抛错,连线停在一个裸的 > 提示符上,登录走不完(password 指令的旧密码检查同样);用 300 个 x 当参数的扫描发现的。/secure/simul_efun.lpc 里补了一个同名的 simul_efun crypt(key, salt):只有超长的密钥才被截短(先截到 255 个字符,再逐字符截到 sizeof(to_buffer(key)) <= 255,限制按字节算,一个汉字占三个字节),再交给 efun::crypt();普通密码原样散列,已存的密码散列不受影响(scripts/lpc_add_sefun.py crypt)。

tell、stell、passwd 编译不过:Lima 模块的两处类型笔误(2026-10-20,KB 04 §6.21)

加载检查:依赖 M_INPUT 的 51 个对象,HEAD 通过 46 个,tree 通过 49 个,回归 0(还不通过的两个:trans/obj/ed_session.lpc 需要驱动没有的 ed_cmd,secure/obj/mailers/mailer.lpc 没有诊断,HEAD 也一样)。

data/daemons/obj.o:三个对象的文件名带 .c(2026-10-21,KB 03 §4.2 第 9 项)

OBJ_D(daemons/obj_d.lpc)的表里 buyi、mantou、wotou 的 file_name 是 /sgdomain/obj/.../xxx.c,archive 里这三个文件是 .lpc:clone_obj() 里的 new() 失败,函数返回错误串 this object files is an illegual file,调用方把它当对象去 ->move():call_other() couldn't find object 'this object files is an illegual file '(第二遍扫描里 look 那一行)。表里的三个名字改成 .lpc。

存档里的 .c 文件名改成 .lpc(2026-10-21,KB 03 §4.2 第 9 项)

存档里写着 "/d/city/npc/wei.c" 这样的文件名;extract 时源文件已经全部改成 .lpc,而驱动对带扩展名的路径只认字面,new() / load_object() / move() 都找不到它,调用方多半把失败当成「没有这个东西」悄悄跳过。本库 4 个存档共 9 处按 scripts/lpc_fix_save_dotc.py 改成 .lpc(只改 .lpc 存在而 .c 不存在的字符串;玩家存档、备份、留言板、巫师目录和文件索引缓存不动)。改动:/data/area/changan.o(5 处)、/data/area/wuling.o(2 处)、/data/daemons/areas.o(1 处)、/data/daemons/char.o(1 处)(共 4 个存档)。

从末尾按字节取汉字、书剑开帮长度(2026-10-23,KB 06 §7.364)

§7.360 只折了数字下标的 [a..b],从末尾取的 [<2..<1](GBK 下一个汉字)和 [<4..<1](两个字)还留着:开帮 gcreate 的帮助写「二至六个汉字 / 3到8个英文字母」,检查却是 (strlen%2)==1 || <4 || >12,末字对 ({ "帮","会",… }) 用 gname2[<2..<1] 永远对不上;少林 / 峨嵋法名 "明" + name[<2..<1]、死讯 killer[<2..<1] != "。"、兵器改名的 can_name 同样坏掉。scripts/lpc_fix_tail_slice.py 只改汉字语境(对照非 ASCII 字面量、can_name / valid_group_name、拼名字),ASCII 补零 / ctime / 复数词尾 / .lpc 不动;[<2..<1]→[<1..<1],[<4..<1]→[<2..<1],开帮门槛按帮助改写。本库 从末尾切片 1 个文件。证明(scripts/lpcc_eval.py bxsj):HEAD 上 斧头帮[<2..<1] 对不上「帮」;改后 [<1..<1] 对上;长度放行 斧头帮/fut;"明"+"张三"[<1..<1] 得「明三」。

open/pos 国名尾字切片(2026-10-27,KB 06 §7.364 Also)

open/pos.lpc 改国名时用 nam[<2..<1]!="国"(GBK 两字节),本驱动按字符算会多吃一字。lpc_fix_tail_slice 的 SKIP 去掉 /open/ 后改为 [<1..<1]。证明:HEAD 仍是 [<2..<1],改后是 [<1..<1]。

offspring RTF 外壳(2026-10-27,KB 04 §6.25 Also)

wiz/emperor/baby/offspring.lpc 整文件是 RTF({\rtf1…),不是 LPC。剥出内嵌源码;按同系 free.lpc 补 master/is_busy;去掉引用未定义 NAME/typ 的换装行。同目录 base_offspring 的 get_info 误写 return ret → return info。证明:HEAD RTF 语法错;改后两文件均可加载。

深度功能测试(2026-10-27,§6.25 ziguang/test/ff 去分号)

wiz/ziguang/test/ff 丢了 inherit 后的 ; 与几乎所有语句终结符。用同库完好的 wiz/fire/obj/huoba 覆盖。证明:HEAD 失败;改后加载。

深度功能测试(2026-10-27,§6.10 未知 pragma save_binary/optimize)

删除本库中 FluffOS 不认的 #pragma save_binary / #pragma optimize… 行。