info.html · 介绍 · play.html · 游玩 · llms.txt · 下载与本地运行 · ZIP · GitHub
ES II 引擎家族(`adm/obj/master.lpc`,"original from Lil, rewritten by Annihilator"),飞白工作室出品的《书剑飘零》官方教学版,是同一批"书剑飘零"基础档案的精简子集——与同门 `sjplii`(书剑飘零II)同源,也和另一份档案 `sjpl2` 共享底子:约 2,491/2,550 个档案与 `sjpl2` 约 13,000 档案的路径重合,并非另起炉灶的独立作品;虽然名字里也带"书剑",但和 Century/adm-single 家族的 `sjecl`/`sje` 属于完全不同的引擎谱系,纯属巧合。新角色的出生地由角色创建时选择的"出生状况"(书香门第/商贾之家/贫寒农家/武力世家)决定,分别落在山东泰安或福州的一户普通民居,而非长安城;长安城的"大慈恩寺"只在角色已保存的出生点失效时才作为兜底,长安城本身仍以唐代真实地标为骨架展开(开远门、朱雀门、大慈恩寺、保定殿等),是游戏地图的另一大可探索区域。除了常见的拜师门派体系,还提供一条独立的"镖师"生涯:加入"红旗镖局"(含帐房、佛堂、武器库等一整套镖局建筑)只需申请即可上任,不必事先拜师,随时可退出;武学招式多为原创命名("醉棍""风刃""无尘步"等),不是直接照搬金庸小说里的招式名称,自成一套武侠世界观。巫师账号会遇到一处刻意保留的"吵闹"设计:新角色第一次创建时因为多个档案首次编译,会看到一串"你发现事情不大对了"提示——都只是无害的编译警告,不影响游戏本身。
English
The official tutorial edition of Feibai Studio's Stray Book and Sword, built on the ES II engine (adm/obj/master.lpc, "original from Lil, rewritten by Annihilator"). It is a trimmed-down subset of the same base archive as siblings sjplii and sjpl2 (Stray Book and Sword II) — 2,491 of its ~2,550 files share a path with sjpl2's own ~13,000-file tree — rather than an independently-written game; despite also carrying the words "Book and Sword," it belongs to an entirely different engine lineage from the Century/adm-single family's sjecl and sje, a naming coincidence and nothing more. A character's "birth circumstance" (scholarly/merchant/poor-farmer/martial family) determines their actual starting home — a commoner household in Tai'an, Shandong, or in Fuzhou, not Chang'an; Chang'an's Great Compassion Temple only serves as a fallback if a saved start room fails to load. Chang'an itself is still modeled on real Tang-dynasty landmarks (its gates use real names — Kaiyuan, Zhuque, Qixia, Yanping, Tonghua, Yanxing — alongside the Great Compassion Temple and Baodian Hall) and forms a second major explorable region. Beyond the usual sect apprenticeships, there's an independent career track with the Red Flag Escort Agency (complete with counting house, chapel, and armory), joinable and leaveable on request without a master, and move names are largely original rather than lifted straight from Jin Yong's novels. One quirk that looks like a bug but isn't: every compile warning is broadcast live to online players, so a brand-new character's first `look` can trigger a burst of "something feels off" messages — all harmless "unused local variable" warnings from first-time file compiles.
README
本次修复的关键 bug
1. master.lpc 的 report_error() 在 CHANNEL_D 尚未加载时呼叫
它(§7.60 类的第三个变体——这份档案里 log_error()/
standard_trace()/report_error() 是三个各自独立的函数,只有
report_error() 缺了保护):补上 find_object(CHANNEL_D) 判断。
2. adm/daemons/whod.lpc 用了未定义的 REMOTE_DIR 常量,而这
个精灵在 preload 列表里,直接导致它编译失败。硬盘上没有对应的目
录可以推断原意,但 get_dir() 对不存在的目录只会返回空数组,所
以在 globals.h 里补上 #define REMOTE_DIR "/data/remote/" 是
安全的(哪怕这个目录本身从未真正被创建)。
3. §7.41 类损坏的存档数据:adm/daemons/emoted.lpc 的
create() 对自己损坏的 emoted.o 存档做了未加保护的
restore(),preload 时未捕获抛出——已包一层 catch(),并显式补
上 emote=([]) 兜底。
4. §7.34 类调试遗留:adm/daemons/logind.lpc 的 get_resp()/
get_name()(角色创建流程中确认中文名字的两条并行路径)各留了
一行 printf("%O\n", ob),会在设定密码提示前把登录物件的内部路
径(/obj/login#N)原样打印给玩家看——已删除两行。
5. 一处编译期 ERROR:d/fuzhou/npc/chess_player.lpc(棋摊老板
韦守儒)的 play_chess() 把继承自 feature/name.lpc 的本地方法
name(int raw) 当成"取得对方名字"的自由函数误用为
name(this_player())——传对象给一个只接受 int 的参数,编译直接
报错,导致这个 NPC 全程无法编译,福州"茶馆"(d/fuzhou/
tearoom2)填充该 NPC 时级联出 *No program in object 崩溃並反
复刷屏。已改为 this_player()->name(),顺带删掉同一行紧挨着的一
处无意义 printf 调试输出(§7.34 类)。
6. §7.86 类第三个变体:obj/board/wizard_j.lpc(巫师工作进度报
告板)inherit "/std/jboard" 之后又多余 replace_program(
"/std/jboard"),与已修复的 31 处 BULLETIN_BOARD/inherit
实例是同一 bug 形状,只是换了一个板类基类名字;/std/jboard.lpc
自己的 do_report()/do_describe_project() 也用
this_player()->edit((: lfun, ... :)) 建闭包,一样会崩。已删除
多余的 replace_program() 调用。
排查过程中确认"不是 bug"的现象
注册过程中反复出现"你发现事情不大对了,但是又说不上来。"——这是这
份档案自己(有点吵闹但故意如此)的设计:master.lpc 的
log_error() 会把每一次编译警告都告诉当时正好连线中的玩家,而
新角色第一次创建时,其继承的各个 feature 档案(alias/damage/more/
move/skill/troop)恰好都是第一次编译。临时让 error_handler 无条
件显示完整细节后确认:每一条都只是无害的"Unused local variable"警
告。
管理员账号 / Admin account
- ID:
fluffos - 密码 / Password:
Mud@2026(标准注册流程完成,update指令验 证过读写权限正常) - 权限 / Level:
(admin),/adm/etc/wizlist里早已有fluffos (admin)一行,注册该 id 后自动获得。
警告:对外公开架设前请务必修改此密码。
本地运行
cd libs/sjplgfjxb
~/src/fluffos/build-debug/src/driver config.fluffos游戏端口:40134。
NOTES · 移植与修复记录
WASM 修复摘要(迁移自 meta.json 的 group_note)
ES II 血统(adm/obj/master.lpc,"original from Lil, rewritten by Annihilator"),飞白工作室《书剑飘零》教学版。WASM 修复:(1)§7.60 类的 master.lpc report_error()→CHANNEL_D 编译期崩溃(这是这个模式的第三个呼叫点,在常见的 log_error()/standard_trace() 之外——report_error() 在这里是它自己独立的函式),已用 find_object(CHANNEL_D) 守卫。(2)adm/daemons/whod.lpc 用了未定义的 REMOTE_DIR 常量,破坏了它(被预载)的编译——已在 globals.h 里加上 #define REMOTE_DIR "/data/remote/"(硬盘上没有对应目录可以推断原意,但 get_dir() 对不存在的目录只会返回空数组,所以这样做是安全的,哪怕这个目录本身从未真正被创建)。(3)§7.41 类损坏的存档数据:adm/daemons/emoted.lpc 的 create() 对自己损坏的 emoted.o 做了未加保护的 restore(),预载时抛出未被捕获的异常;已包一层 catch(restore()),并显式补上 emote=([]) 兜底。深入调查后排除了一个疑似 bug:注册过程中反复出现的"你发现事情不大对了"讯息是这份 mudlib 自己的(有点吵闹但故意如此的)设计——master.lpc 的 log_error() 会把当时正好连线中的玩家告知每一次编译警告,而新角色第一次创建时其继承的各个 feature 档案(alias/damage/more/move/skill/troop)恰好都是第一次编译;临时让 error_handler 无条件显示完整细节后确认,每一条都只是无害的"Unused local variable"警告。管理员账号播种:fluffos (admin) 加入 adm/etc/wizlist(这份档案没有 sj 里那种 securd/securityd 分裂——securityd.lpc 在这里是真正、唯一的安全精灵)。已验证:完整注册(id→确认→名字→密码→确认→电子邮件→性别→出生地选择)→look/score/quit 全部干净,权限正确显示 (admin),update 成功。LPC 格式化工具对全部 2310 个档案运行;还原了 1 个确认有损坏的档案(一种丢引号的损坏,不是常见的 CJK 重新加空格形态,但被同一个去空格比对扫描抓到),覆盖 17 个格式化工具触碰过的 CJK 间距档案;这份档案里没有 ASCII 地图档案。格式化后重新验证过,干净。
§7.86 跨库扫描修复(留言板 post 崩溃)
BULLETIN_BOARDinherit+ 多余replace_program()致命形状(AGENTS.md §7.86,post命令崩溃):全档案 31 处命中,已删除多余的replace_program(...)调用(保留inherit),逐文件保留原有行尾格式(CRLF/LF 按文件原样)。本次为跨库 §7.86 扫描修复(触发原因:该 bug 已在 6+ 个互不相关的血统家族独立确认,属于近乎普遍的拷贝粘贴模式),仅做编译检查(驱动干净启动、端口正常监听),未做完整 §10.7 深度游玩测试。
深度功能测试(§10.7,2026-08-08)
血统澄清
README.md 一直写"ES II 引擎家族",但 AGENTS.md §11 的"ES II / 东方故事
mega-family"成员列表(es1_win/esI、xkx2001/bmxkx2001、
xuanjianlu、syxjl 等)里并没有 sjplgfjxb/sjplii 这一支——本次没
有专门去 diff 核心档案确认这支到底是不是同一个 §11 家族的成员,只是确认
了 master.lpc 文件头注释"original from Lil, rewritten by Annihilator"
与 §11 家族描述的血统吻合。留给下次同族横向比对(尤其是 sjplii)时顺
手做一次真正的 diff 确认,而不是只看注释文本。
本次修复的 bug(均已在原生驱动上逐条改前/改后验证,见下)
1. §7.34 类调试遗留,adm/daemons/logind.lpc 两处:get_resp()
(第 273 行,接受随机中文名字路径)和 get_name()(第 308 行,自
己输入中文名字路径)各有一行 printf("%O\n", ob);,紧跟在中文名
字确认之后、密码提示之前,把登录物件的内部路径原样打印给玩家——例
如注册时输入中文名"云中鹤"后,屏幕上会多出一行 /obj/login#0。
两条路径都命中(对应"接受系统建议的随机名字"和"自己打字取名"两条
分支),已各删一行。改前:register→...→您的中文名字:云中鹤 后
紧接着输出 /obj/login#0,然后才是"请设定您的密码:";改后:中
文名字确认后直接跳到"请设定您的密码:",无任何内部路径泄漏,用一
个全新注册的 sjplcheck(中文名"钱塘潮")账号验证过。
2. 一处真正的编译期 error(不只是 warning):
d/fuzhou/npc/chess_player.lpc(棋摊老板"韦守儒",第 39-40 行)
play_chess() 里 printf("%s", name(this_player())); 和
command("give chess to " + name(this_player())); 把继承自
feature/name.lpc 的本地方法 varargs string name(int raw)
(返回*自己*的名字/显示名,参数是"要不要去掉头衔"的整数开关)当
成"取得*对方*名字"的自由函数误用,传了一个 object 进去。驱动的
静态类型检查在裸调用(非 ->)上直接拒绝,报错原文:
d/fuzhou/npc/chess_player.lpc:39:36: error: Bad type for argument
1 of name ( int vs object )(第 40 行同样报错)。这两行 error
(不是 warning)导致这个 NPC 档案全程无法编译——福州"茶馆"
(d/fuzhou/tearoom2)第一次填充这个 NPC 时,master.lpc 的
report_error()/log_error() 链会级联把
*No program in object '/d/fuzhou/npc/chess_player'! 连同一份
完整的物件状态 dump 反复转发给当时在线的每一个人,刷屏严重。修
复:printf 那行本身也是一处无意义的调试输出(§7.34 同款,删
除),command("give chess to " + name(this_player())); 改为
command("give chess to " + this_player()->name());。改前:
update /d/fuzhou/npc/chess_player 报上面两行 error;改后:
重新编译 /d/fuzhou/npc/chess_player.lpc:成功!,debug.log
里此后再没有 chess_player 相关的 No program in object。
3. §7.86 类第三个变体(新基类名字):obj/board/wizard_j.lpc
(巫师"工作进度报告"留言板,/d/wiz/jobroom)inherit
"/std/jboard"; 之后,create() 尾巴又多余调用了
replace_program("/std/jboard");——和已经扫描修复过的 31 处
BULLETIN_BOARD/BBS_BOARD 实例是同一个致命形状,只是这份档案
的留言板基类不叫 BULLETIN_BOARD 而是 /std/jboard.lpc(它自己
的 do_report()/do_describe_project() 也是
this_player()->edit((: lfun, ... :)) 建闭包,同样会撞上"cannot
bind an lfun fp to an object with a pending replace_program()")。
已删除多余的 replace_program()。改前:编译时确认过
wizard_j.lpc/wizard_bb.lpc 与其余 31 处一样带着这个形状(当
时只做过编译检查,没做过 post 的实机验证);改后:以 fluffos
管理员账号在 /d/wiz/hall(普通 BULLETIN_BOARD 板,编号已在此
前的批量修复里处理过)post test title → 输入正文 → . 结束,
留言完毕。,look board 正确显示
[ 1] test title 云中鹤 (Sat Aug 8 05:05);update
/obj/board/wizard_j 单独重新编译也确认无报错(只有两条与本次修
改无关的 Unused local variable 'myid' warning)。检测方法:
grep -rn 'replace_program' work --include='*.lpc',对每个命中
反查它前面 inherit 的是哪个基类,而不是只搜
BULLETIN_BOARD/BBS_BOARD 这两个最常见的名字。
排查过程中确认"不是 bug"的现象
kill shao nian/look shao nian一度像是present()/id()失 效:d/fuzhou/eroad2街上的"江湖少年"NPC(obj/npc/shaonian. lpc)打kill shaonian(不带空格)反复报"这里没有这个人。",甚 至连打kill 江湖少年(中文全名)也一样失败,一度怀疑是feature/name.lpc的id()(this_player()->visible(this_ object())那个早退分支)或present()出了问题。临时在id()里加了一行write_file()追踪(str/this_object()/this_player()/my_id/visible()返回值),重启驱动复现后发 现:这个 NPC 的set_name("江湖少年", ({ "shao nian" }));——真正 的 id 是带空格的两个词"shao nian",不是"shaonian"一个词(对照同一 份档案里kill.lpc自己也大量使用"body guard"/"taoist guard"这类 带空格的多词 id,是这份 mudlib 一贯的命名习惯)。改用kill shao nian(带空格)复测,命中了正确的对象,但 NPC 恰好在同 一时刻被自己的chat_msg触发的random_move()带离房间(这个 NPC 的chat_chance是 15,且没有战斗中禁止走动的锁定),指令送达 时人已经走了——不是玩家/驱动的 bug,是"打错 id + 目标恰好在闲聊时 随机走动"两个巧合叠加。work/feature/name.lpc的id()/visible ()本身逻辑正确,已移除追踪代码,不做任何修改。- README 原文"新角色从长安城的'大慈恩寺'起步"不准确:
adm/daemons/logind.lpc的enter_world()实际按角色创建时选的 "出生状况"(0-3)从start_loc数组(山东泰安两间、福州两间民 居)里选出生地,START_ROOM(/d/city/ciensi大慈恩寺)只在!catch(load_object(startroom))判定失败(出生地房间加载失败)时 才作为兜底使用——本次用 4 种出生状况分别注册验证,全部落在对应的start_loc房间(例如"武力世家"落在/d/fuzhou/minzhai4,"商贾之 家"的女性角色落在/d/shandong/ta/minzhai2),从未见过兜底路径被 触发。已改写README.md的"内容亮点"第一条为准确描述,长安城本身 仍然存在且以真实唐代地标为骨架(城门/大慈恩寺等),只是不是新手的 默认出生点。
已验证正常工作(原生驱动,fluffos/Mud@2026 管理员账号 + 两个
一次性测试角色"赵日天"/"钱塘潮")
- 完整注册流程(英文 id → 确认 → 中文名字 → 密码 → 确认 → 邮箱 → 性 别 → 出生状况)→
look/score→quit→ 二次连线(get_passwd路径,非首次注册路径)全部干净;quit后debug.log只有无关的Unused local variablewarning,没有 §7.16 类quit崩溃。 - 性别分支验证:男性"武力世家"(力量偏高)与女性"商贾之家"(初始
combat_exp被enter_world()直接设成 100,其余出生状况的男性 角色是 10)两条分支的score都正常,食物/饮水均正确初始化为满值 (无 §8.9 类 wrong-object 食物/饮水 bug)。 - 战斗:
kill fatman(大胖子,福州东路的一个友善摊贩型 NPC)触发的 一整套攻防交换、"半昏迷"提示、unconcious()→disable_player()全 面封锁指令→call_out("revive", ...)自动苏醒的循环,在持续数分钟 的连续搏斗(含用管理员call me->set("kee",1)等指令人为压低生命 值做压力测试)下没有触发任何崩溃或debug.log报错;wimpy环境 变量驱动的自动逃跑(env/wimpy)也正常触发过一次。 - 留言板:见上面"已修复"第 3 条,
post/look board均正常。 maximum evaluation cost : 700000(本项目最常见的默认值)在本次 移动、注册、战斗全过程中一次也没有触发cost limit reached——不 需要按 §7.90 上调。
死亡/复活流程:仅代码走读,未能在预算内实机触发(诚实标注为未验
证)
std/char.lpc 的 heart_beat() 只有当 eff_kee/eff_sen/eff_gin
(而不是 kee/sen/gin)跌破 0,或 kee/sen/gin 跌破
-10*dur 时才会调用真正的 die();否则只会反复调用
unconcious()(见上一节验证过的"半昏迷→自动苏醒"循环)。本次尝试过
两种方式让测试角色真正死亡:
1. 管理员账号 fluffos 用 call 指令把自己的 kee/gin/sen 直
接设成 1、并把 env/wimpy 设成 0(关闭自动逃跑)后继续和大胖子
互殴——结果只反复触发 unconcious()(因为 eff_kee 等派生字段
没有同步跌破 0),且 disable_commands() 在昏迷期间连 call 指
令本身都被封锁,没能在昏迷的间隙里补一刀把 eff_kee 也设成负
数。
2. 另注册的一次性非管理员角色"赵日天"(普通玩家权限)没有 call
指令的路径权限(不在 PLR_PATH 搜索范围内),且附近能找到的两个
可攻击目标(大胖子 combat_exp 5、"卧龙岗强盗" d/fuzhou/npc/
gangster.lpc 未被任何房间引用、是死内容)双方战力都太弱,几分钟
的持续搏斗里角色和大胖子交替进入又走出"半昏迷"状态,始终没有真
正累积到 eff_kee<0 的门槛。
在预算内没有进一步升级测试(例如去几个路程较远、combat_exp 高得多的
真正杀气 NPC,如 d/city/npc/bing.lpc,combat_exp 30000,在长安城城
门一带)。改为代码走读死亡序列:feature/damage.lpc::die() 把
userp() 角色的 gin/kee/sen 都设成 1、ghost=1、存档后
move(DEATH_ROOM)(/d/death/gate,鬼门关),DEATH_ROOM->start_
death() 之后由 d/death/npc/wgargoyle.lpc(白无常)的 init() 排
定 call_out("death_stage", 5, ...),五阶段对话后 reincarnate() +
move() 到复活地点。两点值得记录、供下次(尤其是 sjplii)复用:
wgargoyle.lpc的init()有if (!previous_object() || !userp(previous_object()) || wizardp(previous_object())) return;——完全跳过wizardp()为真的对象,即标准种子管理员账号fluffos即使真的死了,也永远不会被这个 NPC 驱动的复活序列 接管(这正是 AGENTS.md §10.7 检查清单第 6a 条描述的陷阱)。下次要 验证死亡/复活全流程,必须用一个非管理员的一次性测试角色,且要给 它准备足够强的对手(或用call直接把eff_kee/eff_sen/eff_gin都设成负数,绕开缓慢的自然搏斗)。death_stage()本身带着 AGENTS.md §7.68 已撤回的裸 guard 形状 (if (!ob || !present(ob)) return;,五阶段对话之间没有重试)。 按 §7.68 的撤回结论,没有在代码层面套用那个"改成重试"的旧补 丁——没有实机确认过"(1) 鬼魂在这个房间里是否真的被禁止自行移动" 和"(2) 是否存在某个外部系统会强制把鬼魂带离房间"这两个前提,任何 一个不成立,"5 秒对话中途被打断就永远卡住"就更可能是"鬼魂自己走 丢,靠重新进入房间的init()重新触发"这种有意设计,而不是 bug。 留给下次真正实机跑通死亡序列时再确认。
管理员账号播种
adm/etc/wizlist 里此前已经有 fluffos (admin) 一行,但账号本身
(data/{login,user}/f/fluffos/)在这次会话之前从未被真正注册/提
交过。本次走标准注册流程创建(id fluffos,密码 Mud@2026),登
录后 目前权限:(admin) 正确显示,update /d/fuzhou/npc/chess_
player、update /obj/board/wizard_j 两次写权限验证都成功(§1.5
第 3 步的标准检查)。
§7.100 sweep (2026-08-19)
Fixed the corpus-wide inherit ROOM; ... replace_program(ROOM); redundant-replace bug (AGENTS.md §7.100). 228 live occurrences deleted: 227 via scripted sweep (fix_710_room.py), plus 1 hand-fixed roommaker-tool template (obj/roommaker.lpc, simple string-builder variant). 23 already-commented-out instances left untouched. No real .lpc source found under work/data/. Verified via build-debug driver boot: clean compile, zero new "cannot replace"/"cannot bind" debug.log lines; confirmed serving via raw-socket connect on port 40134.
§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.
AGENTS.md §7.19 sweep (2026-09-01): enable_player() reentrancy from init()
Same corpus-wide bug class as mhxy/wuhanzhan (AGENTS.md §7.19): this
lib's feature/command.lpc enable_player() wrapper (around the raw
enable_commands() efun) is reachable from an NPC's init() via a
redundant create()-then-init()-calls-setup()/reset_me() chain --
confirmed via a body-aware static scan of every init() in this lib: 15
NPC files call setup()/reset_me() from init() (e.g. npc/wu43.lpc,
npc/wu33.lpc, npc/wu11.lpc), after create() already made the
object living(). Calling enable_commands() a second time on an
already-living() object makes the driver re-invoke that object's own
init() as a side effect, re-entering the same chain while the
original call is still on the stack -- genuine reentrancy, crashing
with "Too deep recursion" (most likely on an NPC's first-ever
preload/compile).
feature/damage.lpc's revive() calls enable_player() again while
the object is still living(). (cmds/std/sleep.lpc's wakeup() has
its own me->enable_player(); call commented out/dead in this lib, so
revive() alone is the confirmed legitimate re-enable path here.) This
confirms a bare if (living(this_object())) return; guard would be the
WRONG fix -- used the same true reentrancy-flag fix as mhxy instead: a
nosave private int in_enable_player_now; set for the duration of the
wrapper's body, guarding only genuine same-call-stack reentrancy while
leaving the legitimate revive re-enable unaffected. enable_player()
had a single fall-through exit (no early returns), so one
guard-at-top + one clear-at-bottom pair was sufficient. Verified via a
single-file lpcc --batch compile check (PASS) -- not individually
live-boot-tested.
深度功能测试(2026-09-03,第三轮)
新角度:2026-08-08 第一轮已经走完注册、战斗、留言板;死亡/复活当时 只做了代码走读。本轮补商店,并顺带实机确认红旗镖局拜师已经写入存档。
- 商店(燕云客栈店小二 / 酒馆酒保)是真 bug,已修:
d/city/npc/waiter.lpc的vendor_goods列了/d/city/obj/food/dishes/dish01–dish10,jiubao.lpc列了dish16–dish20,但这份教学版子集里整个d/city/obj/food/dishes/目录从未随档(只有一个无关的apple.lpc)。feature/vendor.lpc的do_vendor_list()/buy_object()对name[i]->name()/query("id")没有守卫,list或buy一碰到缺失档案就*call_other() couldn't find object '/d/city/obj/food/dishes/dish07'(vendor.lpc:73/:13),连已经存在的/obj/example/chicken_leg等货物也一起买不成。手足sjplii带着 完整dishes/物件,所以那边不会踩这个洞;不要从sjplii抄菜谱 进来——那是另一份完整档的内容,不是这份教学版丢掉的源文件。 修复:删掉两份 NPC 里指向缺失物件的键;feature/vendor.lpc的list/buy/compelete_trade对file_size(path+".lpc")/file_size(path+".c")都小于 0 的键continue,一个坏键不能再拖垮整张货表。 - 改后冷启动验证(端口 40134,
fluffos/Mud@2026,中文名云中鹤):goto /d/city/kezhan,list列出椒盐排骨 / 鱼香肉丝 / 烤鸡腿 / 包子 / 牛皮酒袋 / 油辣猪排;clone /obj/money/gold后buy fried chicken leg from waiter成功(「你向店小二买下一根烤鸡 腿」)。goto /d/city/jiuguan,酒保list列出包子 / 牛皮酒袋 / 生烧扒翅,无崩溃。 - 拜师已写入存档:上一轮会话里
goto /d/city/biaoju/kufang、bai zhuang(庄容)成功。本轮冷启动 + 断线重连后score仍是 「红旗镖局趟子手」「你的师父是庄容。」save本身第一轮已经确认 回「档案储存完毕。」,本轮未再踩到影子文件。 - 日志:live
debug.log为libs/sjplgfjxb/log/debug.log(fd 在 chdir 进work/之前打开)。本轮无call_other() couldn't find object、无error:/Too deep recursion。work/log/log只有 既有的 Unused local variable 编译警告(含vendor.lpc里预先就 在的未使用list变量,不是这次引入的)。error_handler()把 追踪写回 debug.log,没有另一份独立 runtime-error 日志。 - 结论:两家商店
list/buy通过;红旗镖局拜师跨冷启动仍在; 修了缺失菜谱键 + vendor 缺档守卫。死亡/复活仍未实机触发。