Nirvana LP312

✅ 可玩

nirvlp312

更新 ab394ed 2026-10-28 源码 下载 ZIP 上游 rumplemintz/Nirvlp312mudlib

▶ 开始游玩 · Play Now

Nirvana, an LPMud 3.1.02-DR running a modified 2.44 mudlib, established 1991-02-26. Unique dump from rumplemintz/Nirvlp312mudlib (Amylaar + LDMud dual master). Village start is the Adventurers' guild then Village Green. English look/score/quit. Not lpmud141 (no master) and not collection questmud.

README

Snapshot of https://github.com/rumplemintz/Nirvlp312mudlib (commit 616cad7, 2017-09-21). LPMud 3.1.02-DR / modified 2.44 mudlib, established 26 February 1991. Slug nirvlp312, number 968, port 40277. This collection’s copy is a snapshot, not a live mirror.

Welcome banner: “Nirvana / An LpMud version 3.1.02-DR / running a modified 2.44 mudlib”. English play. New characters finish creation in the Adventurers' guild; later logins land on the Village Green.

Not a duplicate of lpmud141 (that archive has no master) or collection questmud.

Registration flow

Name → New character → password (≥6, twice) → password hint → gender (male/female) → race (human/elf/dwarf/custom …) → height feet → inches → weight (lbs) → approve (y) → where you heard of Nirvana (none is fine).

Admin / test account

Verified live 2026-09-05: create fluffos / Mud@2026 → Adventurers' guild; reconnect lands on Village Green; look / score / quit.

Local run

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

Game port: 40277.

python3 scripts/mudclient.py 127.0.0.1 40277 --timeout 55 --idle 0.7 \
  --send fluffos --send Mud@2026 --send none \
  --send look --send score --send quit

NOTES · 移植与修复记录

Nirvana LP312 (nirvlp312) — porting notes

Source: git clone https://github.com/rumplemintz/Nirvlp312mudlib (commit 616cad7472279cc97c9693f893940f5336916ff8, “Updated”, 2017-09-21; converted 2026-09-05). Config name Nirvana. Slug nirvlp312, number 968, port 40277.

This collection’s copy is a snapshot, not a live mirror. FluffOS compat shims mean it has diverged from upstream.

Unique Nirvana dump. Welcome: “Nirvana / An LpMud version 3.1.02-DR / running a modified 2.44 mudlib / established February 26, 1991”. Dual Amylaar / LDMud master (#ifndef __LDMUD__). FluffOS takes the Amylaar half. Not lpmud141 (941; that archive has no master). Collection questmud is a different first LDMud port.

Do not onboard this repo again. Do not copy the 115k-file players/ wizard-home tree into work/ (only the few objects the village greenspace clones).

0. Layout

Repo root is the mudlib. /secure/master.c is one line: inherit "/obj/master.c";. Real master /obj/master.c. Simul /obj/simul_efun (Amylaar) / /secure/simul_efun. Player /obj/player.c. Village in room/ (church, vill_green, void, adv_guild).

raw/ is gitignored. rsync excluded .git, players/, pfiles/, log/, doc/, post_dir/, LP_SWAP*, debug logs. A handful of players/ files the village actually clones were copied by hand: players/boltar/things/{esc.h,green_bell.lpc}, players/vertebraker/{ansi.h,obj/news_sign.lpc}, players/sandman/NEWBIE/newbie_dispenser.lpc, players/feldegast/std/color_pad.h, players/nooneelse/esc.h.

1. Convert (2026-09-05)

convert_lib.sh UTF-8: already_utf8=7090 converted=0 lossy=11 skipped_binary=76. 3581 .lpc. 2642 .c" refs rewritten. 117 local angle-bracket includes. 301 files static→nosave.

static→nosave on functions is wrong for this dialect (static logon() meant private). Keep logon() untyped.

Mechanical rewrite (scratchpad/nirvlp312_rewrite.py): 2-arg move_object(A,B) → A->move_object(resolve_ob(B)); add_action(fn); add_verb(v) → add_action(fn, v).

2. FluffOS port

config.fluffos: master /secure/master, simul /obj/simul_efun, global include "/include/auto.h", port 40277, lazy resets : 1, inherit chain 80.

work/include/auto.h: #define status int, extract(), resolve_ob(), 1-arg move_object() via efun::. Do not call simul-only functions from auto.h (circular: simul compiles with auto.h).

Amylaar half of work/obj/master.lpc: get_root_uid/get_bb_uid "root"/"backbone", creator_file returns string "root", valid_* permissive, valid_exec varargs returns 1, safe error_handler, epilog/preload skip players/ lines.

room/std.h and room/std_old.h: create() → call_other(..., "reset", 0) so THREE_EXIT rooms get set_light. Without this, Adventurers' guild and other std_old rooms stay dark and look via test_dark() returns 1 with no text.

work/obj/player.lpc: create() → reset(0) so name = "logon" before logon2.

Dialect / reserved words

Simul shims (Amylaar half)

creator() returns 0 for uid root/backbone (else reset() treats the clone as wizard-cloned and illegal_patchs). Also cat(), atoi(), version(), log_file(), exists(), add_worth stub, caller(), in_editor stub, varargs remove_action/command, 2-arg snoop, text_contains, transfer, pad. Reserved-word renames in resolv_path / waxfuns / m_efuns. format.lpc rewritten (no raise_error). wizlist.lpc stubbed. locklist.lpc inits arrays.

Anti-clone illegal_patch

FluffOS object_name is /obj/player#N (leading slash). Original ab != "obj/player" fired on the users() loop after WELCOME. is_real_player_ob() uses strsrch(n, "obj/player"). reset() if (creator(this_object())) disabled.

Commands (look / score / quit)

TMI cmd_hook is add_action("cmd_hook", ""). Empty-verb add_action is silently dropped when command_giver is unset (input_to / pre-room creation). process_input() is the catch-all.

crypt(p, extract(password,0,1)) does not verify a FluffOS crypt(p, 0) hash ($6$…). Login accepts crypt(p, password) first.

save_me() no-ops without an environment. New characters are saved again after move_object in move_player_to_start.

3. Live verification (2026-09-05, native port 40277)

Driver: ~/src/fluffos/build-debug/src/driver config.fluffos from libs/nirvlp312 (debug.log opens before chdir).

Created fluffos / Mud@2026 (human male 5'10" 150lbs). First landing: Adventurers' guild (look shows advance/cost/raise text, HUD, exits north/west/up). Reconnect after quit (“Saving Fluffos.”) lands on Village Green (bell, news sign, Hall of Apprentices). score stub: Fluffos (level 1), exp 0, coins 0, hp 22/26. quit saves pfiles/f/fluffos.o.

First player is not auto-god. Seeded as a mortal.

WASM not verified this pass.

4. Catch-log reset spam (2026-09-05)

Not a full §10.7. The onboard driver (PID 579874, started 02:21) was left running after look/score/quit — we forgot to kill it, then later timer turns treated “not this-turn” as a hard do-not-kill. User 2026-09-05: that leftover was our own abandoned boot, not a concurrent session. Killed; 40277 freed.

Its error_handler (/log/catch vs /log/runtime) recorded a caught *Bad argument 1 to EFUN call_other() ... Got: int(0) on /room/vill_green.lpc:31 every ~10 minutes for the whole sit. clone_object("players/snow/ITEMS/notice")->move_object(...) — that path was never copied into work/ (only a handful of players/ objects were). catch() hid it from the player; clone_object returning 0 still threw on the chained ->. §7.147 store-then-guard. The board itself is missing; we do not invent a substitute.

Same catch file also had *No program in object '/obj/bull_board' from adv_guild extra_reset. Function was still named new(hd) (L_NEW). Renamed to new_note / add_action("new_note", "note") like the onboard adv_guild/post.lpc reserved-word pass. Player verb stays note.

Cold boot 2026-09-05 17:52 confirmed the 10-minute vill_green spam is gone.

5. 深度功能测试(§10.7, 2026-09-05)

Native port 40277. Driver PID this pass ended 1195821. Live debug.log via /proc/<pid>/fd/3 → libs/nirvlp312/log/debug.log (Boot Time Sat Sep 5 18:00:29). error_handler → /log/catch and /log/runtime. Organic fluffos / Mud@2026.

Path: Village Green → enter hall → east Armory (browse / grab sword / wield sword) → out → east/east/east vill_road2 → north shop (look at sign, list empty) → south Adventurer's guild (cost: must be closer to next level; advance: not enough gold) → kill harry (multi-round; Harry hits; we die: corpse, tombstone, tunnel of white light) → reconnect ghost → church pray / y → “more solid form”, score HP 10/26 → quit persist (ghost cleared, pfiles/f/fluffos.o).

Fixes this pass:

Final cold boot catch/runtime/debug.log/stdout: no new lines across hall / shop / guild / Harry fight / death / pray / quit. (Older leftover catch/runtime lines from the abandoned onboard sit remain in those files.)

score via /bin/play/_score.lpc works for a living player; ghosts get “immaterial state with no scores” (design).

6. Do not redo

Do not re-clone rumplemintz/Nirvlp312mudlib. Do not rsync players/. Do not redo nirvlp312 §10.7. 928/929/932 stay header-encrypted. Skip nitan.zip.

深度功能测试(§10.7,2026-10-04)— negative range ends

scripts/lpc_fix_negative_ranges.py: 108 line(s) in 38 file(s) count a range from the end with < (x[a..-1] -> x[a..<1], x[-2..] -> x[<2..]; KB 06 §7.209). In this driver a negative constant end gave "" / ({ }) and a negative start the whole value, so each of these returned the wrong slice; the compile warning A negative constant as the second element of arr[x..y] is gone from the files that compile. Range lvalues (s[0..-1] = text, the prepend idiom) are left alone. A paired compile of the changed files at HEAD and in the working tree showed no new error.

深度功能测试(§10.7,2026-10-06)— 编译警告(机械部分)

1. scripts/lpc_warnings.py nirvlp312 --fix:359 个 nosave 函数改 protected(19 个去掉修饰),删 845 个未用局部变量,补 14 处 varargs、1 处 return;、45 处无效转义;lpc_audit_removed_locals.py 复核 1354 个,0 个需要处理。改动的 490 个 .lpc 在只含被跟踪文件的树里 HEAD 与新版各编一次:都是 230 个通过,无差异。 2. 逐条看了 “Expression has no side effects”:obj/monster.lpc(及 std/monster.lpc)的 query_armor_params() 用逗号表达式 return (a, b, c, d);,只返回最后一个,改为数组 ({ a, b, c, d })(目前没有调用者);room/test.lpc 的 shorty == "Computer room.\n"; 改为赋值。obj/player.lpc 里 race = "creature"; gender=="male"; 的第二句什么也不做,但意图不明(这一分支本来就是让种族去配合 “creature” 性别),未改;obj/guild.lpc 与 player.lpc 的空 if 块与原档案相同。 3. 启动警告 165 → 26,错误 0;剩下的是 format() 菱形继承(模拟外部函数)、未经类型检查的调用等结构性问题。实测 fluffos 登录、look、score、进学院、军械库 browse、quit 保存正常。本库未经 §9 格式化。

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

scripts/lpc_warnings.py nirvlp312 --fix 只改动了 8 个文件(未用的局部变量、空语句;改动的文件中能加载的 4 个 HEAD 与工作树都通过)。本库 3607 个文件里 1407 个在本驱动下编译不过(缺 LDMud 式 efun、玩家目录头文件等),启动时的 22 条警告都在核心物件里,工具留给手工:obj/living.lpc(声明不在作用域开头的未用局部变量、#if 分支里的 pro_object)、obj/player.lpc(fname、条件表达式值未用、set_top_kill/set_top_boot_xp 参数个数与前面的声明不一致、未带类型检查的函数调用)、obj/guild.lpc 两处空语句、obj/simul_efun.lpc 从两条路径继承 format()。待单独处理。

深度功能测试(§10.7,2026-10-08)— 核心物件的编译警告(手工)

接上一节,启动时剩下的 22 条警告都在核心物件里,逐条手改,启动时警告 22 -> 0:

验证:改动的 8 个文件 HEAD 与工作树分别加载 6 -> 6 通过;新进程完整建人物(密码、提示、性别、种族、身高体重、确认、来源)后 look、score 与 HEAD 输出相同。

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

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

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

Deep test (§10.7, 2026-10-11): strict UTF-8 sweep

Compile warnings cleanup (2026-10-12)

scripts/toolkit_fix.sh plus hand fixes; every warning in a compiling file is gone except the two parser lines listed under "open" below. HEAD vs working tree, each object loaded once: 44 objects, HEAD PASS 25, tree PASS 25, regress 0.

Open: basic/parser.lpc (used by every global/action/*.lpc: throw, climb, search, pick_lock, ...) builds its result with LDMud wide-mapping syntax, args[w, 0] = primary; args[w, 1] = secondary; after m_allocate(1, 2), and the actions read args[G_OBJECT, 1]. FluffOS has no wide mappings: [w, 0] is a comma expression, so every result goes to key 0/1 and args[G_OBJECT] is never set. The action system needs a real port (e.g. args[w] = ({ primary, secondary }) and every reader adjusted) with a live test; the two "Expression has no side effects" warnings on those lines are the marker.

Small repairs to area objects (2026-10-19, KB 06 §7.267–§7.271)

Every changed object was loaded at HEAD and in the tree: no regression.

Kids lost their name, gender and age (2026-10-19, KB 04 6.10)

x != "a" || x != "b" and x == "a" && x == "b": comparison chains of one value that can never differ (2026-10-20, KB 06 7.282)

if (arg != "wan" || arg != "pill") return notify_fail(...) is true whatever arg is, dir == "south" && dir == "north" is never true: the guard under the test never opens, or never closes. The author meant "neither of these" (&&) or "either of these" (||). != chains joined by || became && (only where the statement under the test is a return, a refusal or a guard clause), == chains joined by && became || (scripts/lpc_fix_cmp_chain.py). Changed: /bin/player.lpc (2), /obj/daemons/closed/old_read_write.lpc (2), /obj/player.lpc (2), /obj/player.rump.lpc (2), /obj/player/dr/read_write.lpc (2), /obj/player2.lpc (2), /obj/workfiles/daemons/closed/old_read_write.lpc (2), /obj/workfiles/daemons/closed/readwrite.lpc (2), /obj/workfiles/player.lpc (2), /obj/workfiles/player/dr/read_write.lpc (2), /obj/workfiles/player_fred_mod.lpc (2). Left as written (the body under the test does something else, == and || may have been meant): /obj/daemons/wildcards.lpc (1), /obj/user/channel.lpc (1), /obj/workfiles/daemons/wildcards.lpc (1), /obj/workfiles/user/channel.lpc (1), /obj/workfiles/user/channel_prerump.lpc (1).

(string) casts of numbers (2026-10-20, KB 04 6.22)

bin/wiz/secure/_mkall.lpc, _rm.lpc, _rmdir.lpc: (string)this_player()->query_level() < CREATE is (int) (scripts/lpc_fix_cast_cmp.py). An LDMud lib: the objects do not load under this driver either way; the text is right for the driver they were written for.

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

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

add_action() registrations of functions nobody defines (2026-10-21, KB 06 §7.349)

An add_action("fn", "verb") whose function is defined neither by the object, nor by its headers, nor by its parents, nor by any object derived from it (scripts/lpc_scan_callout_targets.py, descendants checked transitively, then function_exists() in a running driver, scripts/lpc_verify_handlers.py). The driver walks the actor's sentences from the newest one: when that sentence's function does not exist it raises *Function for verb 'drop' not found. and tries no other handler of the verb (an older dead sentence is passed over silently). Removed 1 registrations in 1 files (scripts/lpc_fix_dead_add_action.py), the verbs are left to their other handlers: /closed/nightshade/JUNK7.lpc (summon). Most frequent: summon x1. Left alone (read): /obj/debug.lpc inventory (the object does not compile; the registration waits until it loads), /obj/debug.lpc dest_ob (the object does not compile; the registration waits until it loads), /obj/workfiles/player_fred_mod.lpc cmd_suicide (the object does not compile; the registration waits until it loads), /obj/workfiles/player_fred_mod.lpc follow (the object does not compile; the registration waits until it loads), /obj/workfiles/player_fred_mod.lpc cmd_monitor (the object does not compile; the registration waits until it loads), /obj/workfiles/player_fred_mod.lpc score2 (the object does not compile; the registration waits until it loads), /obj/workfiles/player_fred_mod.lpc cmd_lead (the object does not compile; the registration waits until it loads), /obj/workfiles/player_fred_mod.lpc follow_status (the object does not compile; the registration waits until it loads) and 2 more.

new(MISSING)->move() / carry_object(MACRO(..))->wear() chains guarded (2026-10-22, KB 06 §7.73 addendum)

A statement new(PATH)->move(...); / carry_object(ARMOR_D("x"))->wear(); whose path names no file of this archive: new() answers 0 and ->move() on it raises Bad argument 1 to EFUN call_other(). In create() the object never loads, in reset() every spawn below the first missing one is skipped on every reset. 17 statement(s) in 11 file(s) (clone_object) are now { object new_ob = new(PATH); if (new_ob) new_ob->move(...); } (scripts/lpc_guard_carry_object.py --new: the path is resolved with the macros the file itself sees, an ambiguous macro or a virtual-object path is left). Load check of the 11 changed files, HEAD vs tree: 3 load at HEAD, 6 load now (3 newly loading, 0 regress).

Object paths without a leading slash: guarded chains for a missing item (2026-10-22, KB 06 §7.73 addendum)

A path written without the leading slash (carry_object("d/city/obj/jiasha")->wear();) is root-relative in this driver (new("d/city/obj/changjian") loads /d/city/obj/changjian), so it behaves like the absolute spelling: when the file is not in the archive new() answers 0 and ->wear() on it raises Bad argument 1 to EFUN call_other(), and the whole object does not load. The earlier guard pass skipped these paths as "relative to the cwd at run time: cannot tell". 3 statement(s) in 2 file(s) (obj/wand, players/boltar/casino/doorman, players/boltar/casino/sign) are now guarded blocks (scripts/lpc_guard_carry_object.py). Load check of the 2 changed files, HEAD vs tree: 1 load at HEAD, 2 load now (1 newly loading, 0 regress).

log/ subdirectories nobody created: the logging write_file() / log_file() raises (2026-10-22, KB 06 §7.358)

The code of this lib writes logs into 6 subdirectories of log/: log/MAIN (inherit/base/living.lpc), log/WR (bin/secure/_liblog.lpc), log/errors (secure/master/error_handling.lpc) .... Neither the archive, a git clone nor the site pack has them (no local boot wrote into them, so gen_keep_dirs.py never recorded them), and write_file() raises *Wrong permissions for opening file /log/dlog/money for append. "No such file or directory" for a missing directory: the function that logs stops on that line and what came after it (the reward, the flag, the next step) never runs. In the eval probe this lib's log_file() wrote nothing (the probe object has no write access and the sefun does not make the directory itself), so what a real caller gets was not measured. log/MAIN, log/WR, log/errors, log/mailbox, log/secure, log/syslog/CATCH are now in scripts/wasm_keep_dirs.txt (scripts/lpc_keep_log_dirs.py; the site and the pristine tree create the empty directories from it). Proof (scripts/lpcc_eval.py, an eval object under /adm/daemons or similar writes /log/zzdirprobe/..., fresh processes): the measured table in KB 06 §7.358.

/open/ 上残留的宏参数字面量(2026-10-27,KB 06 §7.352 Also)

lpc_fix_macro_strparam.py 曾把 /open/ 当巫师家跳过。open/cobain/vital.h 与 open/vital/hmm/bleh.h:#define FP(x) find_player("x"),FluffOS 不在字符串里替换参数,FP(某人) 永远找名叫 x 的玩家。改为 find_player(#x)。证明:lpcc_eval HEAD 头文件仍是 find_player("x"),改后为 #x;语言对照 "x" 宏得 x,#x 得实参名。

/open/ 上残留的条件赋值(2026-10-27,KB 06 §7.290 Also)

上一轮台湾系扫过后本库仍有 7 处 if (x = CONST):open/maledicta/dusan/t12|t16 的 str = "sign"、open/tallos/mishtell2 的 what = "scale"、open/wren/items/pouch 的 str="pouch",以及 bankserver / grammar / new_pub。一律改为 ==。证明:lpcc_eval HEAD 上 str="other" 仍走进 if (str = "sign");改后 == 对 other 跳过、对 sign 进入。

fakir ftell 缺 define.h / inherit 次序(2026-10-27,KB 04 §6.25 Also)

open/fakir/ftell 包含不存在的 /players/vertebraker/define.h,且 inherit TREASURE 缺分号并写在全局变量之后。自 open/pestilence/define.h 采纳该头;补 ; 并把 inherit 挪到变量声明前。证明:HEAD 失败;改后加载。

深度功能测试(2026-10-27,§7.209 负下标区间残渣)

[0..-N] / [1..-1] 等改为 [0..<N] / [1..<1]。

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

master / simul_efun / workfiles / define.h 等处的 strong_types / pedantic / no_shadow / no_inherit / no_clone / no_warn_missing_return 已删。/obj/simul_efun 可加载。

深度功能测试(2026-10-27,§6.25 LDMud #'fn 闭包)

简单 #'ident → (: ident :)(跳过 #'? / 'symbol 行)。约 1224 处 / 283 文件。HEAD /basic/alias 报 Illegal character #;树中该错误消失。

深度功能测试(2026-10-27,§6.25 master_ldmud #'fn 残渣)

call_out/set_driver_hook 等行上剩余的简单 #'ident → (: ident :)(仍跳过 ({#' lambda 汤)。

深度功能测试(2026-10-28,remove_call_out 闭包→字符串)

corpse/kernel/simul/lpc 简单形式改为字符串。

深度功能测试(2026-10-28,sort_array 方向闭包)

剩余 LDMud sort_array 的 #'> / #'< 改为 1 / -1(KB 06 7.234)。