Star Wars Mud

✅ 可玩

swmud

更新 fdf581a 2026-09-12 源码 下载 ZIP 上游 coupdeforce/swmud

▶ 开始游玩 · Play Now

A Star Wars-themed conversion built on top of the Lima mudlib (this collection's own libs/lima, 164) -- its own README describes it as a set of 'additions and changes to the base mudlib' meant to be installed over a full Lima install, which is how this copy was assembled. Ships a genuine Star Wars race roster (13 playable races spanning several human ethnicities plus aliens such as Wookiees and Twi'leks), its own combat/limb/wound system, guild-style character classes (Jedi, smuggler, bounty hunter, and more), crafting, and weapon/armor/lightsaber item trees. New characters land in a working fallback starting room, since the original Star-Wars-specific starting area was never included in this particular git archive. Makes a genuine outbound network connection to the public Intermud-3 router at every boot.

README

A Star Wars-themed LPC mudlib built as an extension of the Lima mudlib (<https://limalib.dev>, FluffOS's own official reference/framework mudlib). Its own README describes it exactly: "This project only includes additions and changes to the base mudlib. It must be installed over the current Lima mudlib." So that's how it's built here: a full copy of this project's already-converted libs/lima/work/ (164, port 40212) with swmud's own ~980-file tree overlaid on top (852 new files, 233 overriding same-path Lima files).

Source: git clone https://github.com/coupdeforce/swmud (last pushed 2016-02-16, commit cf33a51). Slug swmud, number 180, port 40227.

Highlights

Registration flow

new name -> "Is '<Name>' correct?" -> password -> confirm password -> gender (male/female) -> email -> real name -> homepage (optional) -> race selection (type a race name, or list/help races/help stats) -> point-buy attributes (a <stat> [n] / s <stat> [n], done when satisfied) -> dominant hand (left/right) -> team (imperial/rebel/ neutral) -> lands in Void with a starting body, 1000 XP, and a $N the Bantha Fodder title.

Admin account

Created through the mudlib's own real first-boot bootstrap (Lima's "whoever registers first on an empty install becomes admin" convention, inherited by swmud's sw_body_handle_new_logon()) -- not a save-file hand-edit. Verified live: who shows Role Admin Wizard; update /std/race/wookiee and admtool (including its wizard-gated priv 1 submenu) both succeed.

Status

Boots clean. Verified live with a real driver session and a raw socket client: full registration (both a wizard-bootstrap account and a second, ordinary account), race selection across multiple races, point-buy attribute allocation, look/score/who/inventory, admin update/ admtool, and a clean quit, all producing correct output.

1731 of 1860 .lpc files pass a full lpcc_check.sh-style batch compile sweep. Nearly all of the 129 that don't are orphaned Lima demo content (domains/'s stock example rooms/monsters/spells, std/sword.lpc, std/race/unused/troll.lpc, etc. -- content swmud's own game world never uses and that predates this port) hitting the same "swmud rewrote the item/combat API out from under Lima's original demo files" incompatibility documented repeatedly in NOTES.md. See NOTES.md for the full breakdown and what's left unfixed on purpose.

WASM status: playable. The specialized Lima-flavor WASM driver (same NO_ADD_ACTION/NO_WIZARDS/NO_LIGHT build as native lima/swmud) is now packaged per-lib via scripts/custom_drivers/lima_swmud/, so the site can actually boot this game. Registration, race selection, and world entry were verified in-browser; see NOTES.md 「站点基础设施缺口已补上」.

⚠️ Makes a real outbound network connection at boot. `daemons/
imud_d.lpc` preloads and connects to the public Intermud-3 router
network at every boot (ADMIN_EMAIL in include/config.h is a real-
looking value, so Lima's placeholder-based protective guard doesn't
block it). Do not include this lib in high-frequency automated re-boot
loops. See NOTES.md.

Local run

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

Important: this lib needs the same specialized Lima-flavor driver build as libs/lima/ (~/src/fluffos-lima/build-debug, built with NO_ADD_ACTION/NO_WIZARDS/NO_LIGHT defined, OLD_ED/PACKAGE_UIDS undefined) -- it will NOT boot on this project's shared default driver at ~/src/fluffos/build-debug. See libs/lima/NOTES.md for how that driver was built, if the checkout needs to be recreated.

Game port: 40227.

NOTES · 移植与修复记录

swmud -- Star Wars Mud

Source: git clone https://github.com/coupdeforce/swmud (HEAD at clone time: cf33a51, last pushed 2016-02-16, cloned 2026-08-26). Number 180, slug swmud, port 40227. Status: done (clean boot, real registration + character creation + look/score/who/inventory/admin update/ admtool/quit all verified against a live driver).

Architecture: this is not a standalone mudlib

swmud's own README says it outright: "This project only includes additions and changes to the base mudlib. It must be installed over the current Lima mudlib." Confirmed by inspection -- the raw clone is ~980 files with no secure/simul_efun.lpc combiner, no check_config.lpc, no get_root_uid()/master security scaffolding, and macro tables (include/mudlib.h, classes.h, commands.h, daemons.h) that reference dozens of paths outside the archive. This project happens to already have a full working copy of Lima itself onboarded (libs/lima/, 164, git clone https://github.com/fluffos/lima) from earlier this session, so the AGENTS.md \S2.1 "recognize the lineage" playbook applies directly, just at a larger scale than usual:

1. work/ = a full copy of libs/lima/work/ (already fixed for this driver -- see libs/lima/NOTES.md), with every file from swmud's own converted tree overlaid on top. 852 files are swmud-only additions; 233 override a same-path Lima file outright (secure/master.lpc, secure/daemons/secure_d.lpc, std/body.lpc and 14 of its body/* submodules, std/adversary/*, most of cmds/verbs/cmds/player, the trans/cmds "wish" shell command tree, include/*.h, etc). 2. Because this driver requires a different build for anything Lima-based (NO_ADD_ACTION/NO_WIZARDS/NO_LIGHT defined, OLD_ED/PACKAGE_UIDS undefined -- see libs/lima/NOTES.md \S "驱动编译选项冲突"), swmud reuses that exact driver checkout, ~/src/fluffos-lima/build-debug. It will not boot on this project's shared default driver. 3. Encoding: swmud's own raw clone is 100% ASCII/UTF-8 except one Latin-1 copyright symbol (©) in help/wizard/coding/parser, fixed with iconv -f ISO-8859-1 -t UTF-8 (note: plain -f latin-1 fails with "failed to start conversion processing" on this machine's iconv -- use the full charset name ISO-8859-1). scripts/convert_lib.sh ran with UTF-8 as the source encoding (i.e. rename + reference-fixup only) against a staging copy, then that staging tree was rsync'd onto the pre-populated work/ (never run convert_lib.sh directly against work/ here -- it deletes and recreates its target from scratch, which would destroy the Lima base).

Because two independently-evolved snapshots of a large, deeply inheritance-based codebase are being combined, most of the real bugs below are API mismatches between vintages -- a file on one side of the merge calls a function/macro/class that the other side renamed, dropped, or never had -- rather than classic single-archive conversion bugs. Two consistent patterns run through almost everything below:

Real bugs fixed (driver-compat / programming, not content)

1. Dropped macro definitions (the single biggest bug class)

Systematic sweeps (grep every inherit BARE_MACRO;, new(MACRO...), and MACRO->call() site against every #define in include/*.h) found and fixed:

All confirmed by checking the target file actually exists in the merged tree before adding the macro back -- none of these paths were invented.

2. Dropped simul_efun functions

swmud's own secure/simul_efun/{misc,objcalls,path,string}.lpc (4 of the 4 simul_efun source files it ships) replaced Lima's originals wholesale, but are an older/leaner snapshot missing several utility functions that both Lima-base files *and swmud's own files* still call: lima_version()/identify() (misc.lpc; called by secure/ error_handler.lpc and the version command), file_domain() (path.lpc; called by daemons/domain_d.lpc), and punctuate()/tidy_list()/ time_to_string()/weight_to_string()/filepath_ellipsis() (string.lpc; called by 14+ files including cmds/wiz/calls.lpc and swmud's own std/modules/m_companion.lpc). Ported the exact implementations forward from libs/lima/work/secure/simul_efun/*.lpc (unmodified copy-paste, credited in-file) rather than reinventing them.

Also found the exact same already-known bug Lima itself had and fixed upstream: secure/simul_efun/string.lpc's create() builds an "every byte value" lookup table via chr(i) for i in [0,256); this driver's sprintf("%c", 0) (used by the chr() simul_efun override itself) errors on a \0/out-of-range codepoint. Lima's own current string.lpc already fixed this (for (i = 1; i < 255; i++)); swmud's copy had reverted to the original [0, 256) range. Applied the exact same fix Lima uses, verbatim, rather than re-deriving a different one.

3. TYPE array NAME / bare array dialect (§7's recurring bug class 7)

980 sites across swmud's own files used two flavors of the classic old- MudOS array-declaration dialect this driver doesn't accept: TYPE array NAME (405 hand-written + machine-verified sites, e.g. string array names;) and **bare array as a shorthand for mixed *** (a second, narrower dialect specific to this archive -- ~200 more sites, e.g. array args..., array handle_ob(...), class command_info array module_commands()). A two-pass scripted sweep converted both to modern TYPE *name / mixed *name syntax. Two sweep-tooling bugs surfaced and were caught by re-running lpcc_check.sh and fixing forward rather than trusting the first pass:

4. inherit chain size too small once merged (masqueraded as infinite recursion)

/std/body.lpc failed every load attempt with `*Inherit chain too deep:

N for every N` up to 200 tried -- looked like true runaway recursion,

but the real cause (found by bisecting) was a missing file: std/body.lpc has inherit __DIR__ "body/help";, and std/body/ help.lpc does not exist anywhere in this archive or in Lima's base. Compiling a missing inherit target routes through master.lpc's compile_object() virtual-object fallback, which (per its own doc comment) walks up the path looking for a parent .lpc to call virtual_create() on -- for /std/body/help that parent is /std/ body.lpc itself, so resolving the missing inherit re-entered compiling /std/body.lpc, which needed to resolve the same missing inherit again, forever. Removed the dead inherit __DIR__ "body/help"; line (content genuinely absent, not invented) and also inherit __DIR__ "body/wiz_position"; on the same line block -- confirmed *not* just missing but actively dead: std/body/wizfuncs.lpc's own header says "230319, Tsath: Merged wiz_positions into this file," and it already defines query_wiz_position()/set_wiz_position(). inherit chain size was still bumped from Lima's 30 to 60 (this project's common ceiling, used by 137 other libs) as normal headroom for the now-much- larger combined class hierarchy -- it just wasn't the real bug.

One related, still-orphaned file: std/modules/m_exit_obj.lpc (from Lima's base, unreferenced anywhere in the merged tree -- grep confirms nothing inherits M_EXIT_OBJ) calls a 3-argument eval_dest(), but swmud's own replacement std/modules/m_exit.lpc defines a completely different 1-argument eval_dest() (also private, matching the AGENTS.md \S7.48 cross-file-private pattern -- loosened to protected on general principle, though no live caller actually needs it). Left m_exit_obj.lpc as a known lpcc_check.sh failure: it's genuinely dead code with an incompatible signature from a different API vintage, not something to guess a 3-argument implementation for.

5. First-ever player registration crash (real, 100%-reproducible)

The single most severe bug found: every fresh install of this archive crashes on the very first character ever created. secure/user/ sw_body.lpc's sw_body_handle_new_logon() auto-promotes the first-ever registrant to admin (a direct port of Lima's own bootstrap convention) *before* calling create_body(). Inside std/body.lpc's create() -> adversary::create() -> mudlib_setup() -> refresh_stats() -> std/adversary/health/limbs.lpc's set_max_health(), the racial-stat rollout calls check_wizard_set() (an anti-cheat guard meant to stop a *different*, low-ranked wizard from remotely tampering with another player's stats). That guard's thing != link check is unconditionally true at this exact point in the call chain, for *every* new character of *any* account, because link is only ever assigned later, inside enter_game()/init_cmd_hook() -- which hasn't run yet during the body's own constructor. For an ordinary (non-wizard) new account this is harmless (wizardp(thing) is falsy, so the guard short-circuits), but for the bootstrap-admin account -- unavoidable on a fresh install, and also would hit any wizard creating a new character if this mudlib ever supported more than one character per account -- wizardp(thing) is truthy and the guard fires: *Invalid attempt by <name> to set 's max health to <n>. This took real trace-level debugging to isolate (naive write()/printf() debug statements silently vanished at exactly this point in the call stack, because this_player() context is ambiguous mid-construction; switching to write_file()-based logging and reading /log/runtime's actual stack trace was what nailed the true call chain -- see git history of this fix for the full reasoning if this class of bug recurs elsewhere). Fixed with a one-line, minimal guard: only apply the anti-cheat check once link is actually established (if (link && ...) instead of just if (...)), preserving the real anti-cheat behavior for its intended post-login use case.

6. Division by zero in the Character Creation attribute screen

std/modules/m_bodystats.lpc's query_for() (the "Force" stat, with a Star-Wars-specific environmental bonus term) divides by cur_for unconditionally -- but cur_for is legitimately 0 for every freshly rolled, not-yet-allocated character, which is exactly the state the attribute-point-buy screen displays. Crashed the Character Creation "Attributes" screen for every single new character on every single render until the player had already put at least one point into Force. Fixed with a guard returning cur_for unmodified (0) rather than dividing by it, on the reasoning that a character with 0 force sensitivity shouldn't receive an environmental force bonus anyway.

7. team_alignment used but never declared

obj/mudlib/createmenu.lpc's Character Creation "Team" step (imperial/rebel/neutral) calls this_body()->set_team_alignment(n), and secure/daemons/{user_d,finger_d}.lpc's who/finger display code reads "team_alignment" back as a plain global variable via this driver's fetch_variable() reflection mechanism -- but no team_alignment variable, nor set_team_alignment()/query_team_alignment() functions, exist anywhere in the archive. The setter calls were pure no-ops (call_other to an undefined function silently returns 0), and every who/finger lookup on *any* character crashed outright (*Variable named 'team_alignment' does not exist or is not visible!) since the variable genuinely doesn't exist to reflect. Added the missing int team_alignment; variable plus matching accessors to std/ body.lpc, mirroring how race_name already works as a plain reflected variable on the race classes. (The broader legal_body_query list in user_d.lpc also names 8 jedi-sponsorship fields -- jedi_sponsor, sponsored_by, etc -- that are similarly never declared anywhere; left alone since they're outside the everyday who query set that actually gets exercised, per secure/daemons/finger_d.lpc's own shorter 12-field list, so they're not a live crash. Flagged here in case a future jedi-sponsor-specific command surfaces the same gap.)

8. race_name missing from 4 leftover Lima races -> crashed who

std/race/{human,elf,orc,documentation}.lpc are unmodified Lima base files (byte-identical, confirmed via diff) that hardcode query_race() to return a literal string instead of exposing a race_name variable the way every one of swmud's *own* races does (human_corellian, wookiee, defel, etc. all declare string race_name = "...";). who/finger's variable-reflection lookup on race_name crashed for any character of one of these 4 races the same way \S7 did for team_alignment. Since these 4 races are also non-canonical for a Star Wars game (a generic "human"/"elf"/"orc" alongside swmud's own 13 real races, one of which -- human_corellian et al -- already covers "human" properly) and were the same 4 files needing the stat_roll_mods class-inherit fix below, moved them to std/race/unused/ (an existing, already-used-for-this-purpose directory -- human_dathomirian.lpc was already there) alongside troll.lpc (\S9). race_d.lpc's own get_dir(DIR_RACES + "/*.lpc") glob is non-recursive, so this cleanly removes them from the selectable race list without deleting any content.

9. Missing inherit CLASS_STATMODS; broke 5 races' stat-roll class

std/race/{human,elf,orc,troll,documentation}.lpc (all unmodified Lima files) declare a local class stat_roll_mods query_roll_mods() function using a class type defined in std/classes/statmods.lpc, but never inherit CLASS_STATMODS; to bring that class definition into scope -- a real, lpcc_check.sh-confirmed compile failure (Undefined class 'stat_roll_mods') for all 5. Added the missing inherit to all 5. 4 of the 5 (everything except troll.lpc) now compile clean and were kept loadable (before being moved to unused/ per \S8 above, for the separate race_name reason). troll.lpc has a second, deeper incompatibility (below) and stays broken.

10. troll.lpc (leftover Lima demo race) broke 3 *real* swmud races

std/race/troll.lpc additionally calls set_to_hit_bonus()/ set_weapon_class() -- functions that existed in Lima's old combat system but don't exist anywhere in swmud's rewritten std/adversary/* combat model (\S"Architecture" above). This alone would just mean troll fails to load and gets skipped -- except daemons/race_d.lpc's create() loop does if (!load_object(tmp)) { continue; }, and on this driver a failed compile inside load_object() throws an error that propagates past that if/continue guard instead of returning falsy, aborting the entire foreach early. Since get_dir() returns races in filename order and troll.lpc sorts right before twilek.lpc, verpine.lpc, and wookiee.lpc, this silently dropped 3 of swmud's own *real, working, Star-Wars-canonical* races from the selectable list every single boot -- not a cosmetic listing bug, an actual "3 valid races become permanently unselectable" bug, caused entirely by one broken leftover demo file sorting adjacent to them. Fixed by moving troll.lpc to std/race/unused/ (same mechanism as \S8) rather than trying to guess a set_weapon_class()/set_to_hit_bonus() implementation for content that was never part of this game to begin with. Verified live: the race list now shows all 13 real races, including wookiee/twi'lek/verpine, and each is independently selectable.

11. WIZARD_START pointed at broken Lima demo content

include/config.h's WIZARD_START (upstream value: "/domains/std/ Wizroom", Lima's stock "Grand Hall" demo room) fails at runtime: its set_objects() places a virtual "map" object at /domains/std/ map.lpc, which calls set_untouched_desc() -- again, a function that doesn't exist anywhere in swmud's rewritten object API (same pattern as \S10). This crashed move_to_start() for the wizard-fallback path specifically -- i.e. exactly the path this project's own admin-account verification convention exercises. Repointed WIZARD_START at /d/common/void (a real, working room this archive does ship) instead of inventing replacement demo content. This is a deployment substitution, not a "fix" of swmud's own design, since \S12 below means the *real* wizard starting room was never included in the archive either way; ordinary (non-wizard) players already fall through move_ to_start()'s own built-in fallback chain to this same Void room for that reason, so wizards now land in the same well-defined place.

12. The real starting area doesn't exist in this archive at all

include/config.h's START/NEW_PLAYER_START point at /d/coru/main ("Coruscant", the intended real starting location) -- but neither that file nor even a d/coru/ directory exist anywhere in the raw clone or its git history. This is confirmed not a conversion artifact: the d/ tree (swmud's real, non-Lima game-content root) has real, working subtrees for items/weapons/armor/monster templates (d/arm, d/buffs, d/com, d/const, d/mon, d/obj, d/weap) but no room/area content anywhere -- confirming the actual playable map was never committed to this git repository at all (plausibly built live on the original production server and never checked in, a common split for "engine code" vs "game content" in MUD codebases). This is a genuine, severe, pre-existing content gap -- not something fixable within this project's "fix programming bugs, don't invent content" mandate. Fortunately std/body/start.lpc's move_to_start() already has a sensible built-in fallback chain (configured start -> WIZARD_START/ START -> VOID_ROOM) ending at a real, well-written room (/d/common/void.lpc, "Void... This is where players and objects are moved to when something goes wrong. If you end up here, please let a wizard know."), so every new character still lands somewhere coherent and playable rather than crashing -- this was the intended behavior of swmud's own error-handling design, not a workaround this port invented.

13. secure/user/sw_body.lpc's new-character shell path clamp broke wizard commands

Every brand-new character's shell (incarnate(), in the if (is_new) block) unconditionally overwrote its shell's "path" variable to ({"/cmds/player", "/cmds/guild"}). secure/user/shell.lpc's start_shell() already correctly picks WIZ_SHELL (the Lima "wish" shell, /trans/obj/wish, whose own create() smartly defaults path to WIZ_CMD_DIRS/ADMIN_CMD_DIRS for a wizard account) vs PLAYER_SHELL based on wizardp() -- but the very next thing incarnate() did was stomp that smart default back down to the plain player command set, for every new character regardless of wizard status. Combined with \S5's bootstrap-admin-before-create_body() ordering, this permanently locked the very first player on a fresh install (guaranteed to be a wizard) out of every wizard/admin command (update, admtool, ...) forever, since this mudlib is single- character-per-account (no way to "recreate" the character with a wider path later). Fixed by only clamping the path when !wizardp(query_ userid()), letting a wizard's shell keep whatever WIZ_SHELL's own constructor already set up. Verified live: update /std/race/wookiee and admtool (through its wizard-gated priv 1 submenu) both work correctly for the bootstrap-admin account after this fix.

14. NO_NEW_PLAYERS -- deployment change, not a bug fix

include/config.h ships with #define NO_NEW_PLAYERS (an intentional upstream "closed beta" gate -- new registrations are rejected outright except via a pre-approved guest slot). Since this project's whole point is letting site visitors register and actually play, #undef'd it. Documented in-file as a deliberate deployment substitution, matching this project's established convention for this exact situation.

15. Missing <lpscript.h> header (removed, not invented)

swmud's own include/mudlib.h replaced Lima's #include "custom_mudlib.h" (an empty upstream placeholder) with #include <lpscript.h> -- a header that doesn't exist anywhere in this archive *or* in Lima's base, breaking compilation of every single file (it's pulled in via the global include chain). The only 3 references to LPscript anywhere in the merged tree (daemons.h's LPSCRIPT_D path macro, secure/master.lpc's compile_object() handling a hypothetical *.scr file extension, and this include line) need zero symbols from the missing header -- there are no .scr files anywhere in the archive either, so the code path is dead in practice. Removed the #include line rather than fabricating a header for a feature this archive never actually ships content for.

Known, deliberately unfixed gaps (content/design, not bugs)

⚠️ Real outbound network connection at boot (Intermud-3)

Unlike almost every other lib in this corpus (all sandboxed, no outbound connections -- see AGENTS.md \S1.3c/\S7.6), daemons/imud_d.lpc preloads at boot and makes a genuine outbound socket connection to the public Intermud-3 router network. imud_d.lpc's create() has a protective check that refuses to load if ADMIN_EMAIL is still Lima's placeholder "[email protected]" -- exactly the guard that made libs/lima/'s own imud_d refuse to load (see libs/lima/NOTES.md). swmud's include/config.h sets ADMIN_EMAIL to a real-looking value ("[email protected]"), so that guard does not trigger here: create() proceeds to call trigger_reconnect("router") unconditionally at every boot, same as libs/imud/'s intentional demo behavior (see libs/imud/NOTES.md). This means this lib should not be swept into high-frequency automated re-boot loops (round-two/round- three-style re-test cron, lpcc_check.sh-adjacent live-boot sweeps) the way the rest of this project's sandboxed corpus safely can be -- each boot is a real network event against a real third party.

Admin account

Bootstrapped through the mudlib's own real first-boot logic (not a save-file hand-edit): registered fluffos/Mud@2026 as the very first account on a completely clean data/{links,players,pshells,wshells} tree, which sw_body_handle_new_logon() auto-promotes to admin/wizard per Lima's own convention (see \S5 above for the crash this triggered and its fix). Completed full Character Creation (Corellian, right- handed, Rebel alignment) and verified: who shows [Apprentice] Fluffos the Bantha Fodder (Corellian) with Role Admin Wizard; update /std/race/wookiee succeeds (Updated and loaded.); admtool opens and its wizard-gated priv 1 -> administration submenu (showing [admin]- tagged options) is reachable. A second, ordinary (non-wizard) test account (testplayer, Wookiee, Imperial) was also registered end-to-end to confirm the bootstrap-specific fixes above don't regress the normal player path.

Verification record

scripts/mudclient.py-equivalent raw Python socket sessions through the real ~/src/fluffos-lima/build-debug/src/driver, multiple independent boots across the debugging process above: full registration (username, "is this correct?" confirmation, password+confirm, gender, email, real name, homepage) -> race selection (verified against corellian and wookiee, both non-human and human-ethnicity races) -> point-buy attribute allocation -> dominant hand -> team alignment -> lands in Void with a starting body -> look (room description + exits correct) -> score (race/gender/guild/XP/HP/credits all correct) -> who (roster line with role tag, race, location) -> inventory -> admin update/ admtool (bootstrap-admin account only) -> quit (clean disconnect back to the User Menu, debug.log free of new errors). No crashes, zero silent failures, across all of the above after the fixes in this document.

wasm_status 审计(2026-09-01):内容在专用 WASM 驱动上完全可玩、但与 lima 同样卡在站点基础设施上,结论 noboot

meta.jsonwasm_status 此前一直留空(README 的 Status 一节写 "WASM status: not attempted")。本次批量审计(见 [[project_wasm_status_audit]])补上这一步,结论直接参照本收藏 libs/lima(164)自己 2026-09-01 那次审计的先例——见 libs/lima/NOTES.md 的「wasm_status 审计」一节。

复用 lima 那次审计已经建好的专用 WASM 驱动 (~/src/fluffos-lima/build-wasm/src/{fluffos.js,fluffos.wasm}NO_ADD_ACTION/NO_WIZARDS/NO_LIGHT 定义、OLD_ED/PACKAGE_UIDS 未定义,与本 lib 的 README.md/config.fluffos 一贯记载的驱动 要求完全一致,不需要重新编译)。第一次起跑就命中和 lima 自己 secure/simul_efun/misc.lpc 一模一样的 bug:swmud 自己独立重写过 的同名文件(secure/simul_efun/misc.lpc,与 lima 原版逐行对比 差异很大,是 swmud 自己的版本,不是继承 lima 的)里 dump_socket_status() 同样无条件调用 socket_status(),WASM 构建 默认不带 sockets 包,导致 secure/simul_efun 整个编译失败,驱动 拒绝启动。用 lima 已验证过的同一手法修复(#ifdef __PACKAGE_SOCKETS__ 包一层,退化返回空字符串)。

修复后完整验证:fluffos_boot 成功,登入菜单正常显示"Welcome to Star Wars MUD!",走完 new name → 确认 → 密码×2 → 性别 → 邮箱/ 真实姓名/主页(可跳过)→ 种族选择列表正常显示 13 个种族选项,全程 无未捕获错误——这个 lib 的内容本身在专用 WASM 驱动上是完全可玩 的obj/secure/socket.lpc/secure/daemons/ftp_d.lpc/ daemons/imud/finger.lpc 等几个非 simul_efun 级的外围文件编译 失败只是正常的预载跳过,不影响真实登入。

但和 lima 一样卡在同一个站点基础设施缺口上:这个项目的站点打包 管线(write_play_page.sh/build_site.sh)给所有 lib 共用 同一份 WASM 驱动二进制,没有任何按 lib 切换驱动配置的机制——部署 到线上时,swmud 仍然会撞上和用共享驱动跑原生版一模一样的"驱动 配置不匹配"问题(NO_ADD_ACTION/PACKAGE_UIDS 等宏的差异会导致 mudlib 自身的启动期检查失败)。标记 playable 会误导站点实际能 跑什么,因此和 lima 一样定为 noboot——这是站点基础设施层面的 缺口,不是这个 lib 自身内容的问题,等以后站点支持按 lib 覆盖驱动 时可以直接翻正,不需要重新调查。

站点基础设施缺口已补上(2026-09-02/03):wasm_status 翻正为 playable

libs/lima/NOTES.md"站点基础设施缺口已补上"一节——write_play_page.sh/ build_site.sh 加了 per-lib 自定义驱动目录支持,lima/swmud 共用同一份已提交的驱动产物(scripts/custom_drivers/lima_swmud/)。

本地范围内测试站点(只打包这两个 lib)用 Playwright 通过真实 #cmd 输入框验证:fluffos_boot 成功,"Welcome to Star Wars MUD!" 正常 显示,走完 new name → 确认 → 密码×2,控制台无 JS 报错——和本节 前面用 wasm_client.js 跑通的结果一致。meta.jsonwasm_statusnoboot 改为 playable

Deep functional test (first full §10.7 pass, 2026-09-03)

First continuous playthrough. Prior work was onboarding + the WASM driver-override flip — never a §10.7 pass. Admin fluffos/Mud@2026 against ~/src/fluffos-lima/build-debug. Unique world content still does not exist (/d/coru/main absent; players land in /d/common/void). Tested Void, the lima leftover Monster_Room guild-guard path, quit → user-menu → re-enter, and a brief combat attempt.

Bug 1: leftover debug writes on every move

std/modules/m_smartmove.lpc::move_to() printed The destination is a string. / The destination is an object. on every move attempt. Lima's copy of this module does not have those writes — they are swmud debug leftovers. out from Void (the only exit, pointed at the missing START) then correctly says Construction blocks your path. Verified on a fresh driver after removing the two write()s: only the construction message remains.

Bug 2: lima §10.7 guild-guard / GUILD_D fixes never reached this overlay

swmud's work/ was copied from lima *before* lima's 2026-08-27 §10.7 pass, so std/guild_guard.lpc and daemons/guild_d.lpc still had the unguarded query_guild_allies() and the get_dir()-returns-0 load_missions()/load_favors() crash. Ported lima's two guards.

On this lib that was not enough: swmud's std/body.lpc does not inherit body/guilds (lima does, under USE_GUILDS), so guilds_belong() is a missing apply and returns 0. 0 & ({}) then threw *Bad argument 2 to &. Added an arrayp() guard. Verified live: goto /domains/std/Monster_Roomnorth now prints the intended block (The a guard pushes you back. "Guild members only", she growls.) instead of the go-verb parse crash. Caught Non-existant guild - sorcery. still lands in /log/catch (same mudlib error handler : 1 visibility lima documented — not a new leak).

Bug 3: user-menu s/p after quit crashed (single-body vs multi-body API)

swmud's secure/user.lpc is the older single-body_fname vintage and does not inherit user/bodies (lima does; inheriting it here would nomask-collide on set_body_fname). Lima's usermenu still calls query_bodies() / query_selected_body() / set_selected_body() / enter_game(name, fname).

Before the shim: s was *Bad argument 1 to keys() (query_bodies() returned 0); after a first query_bodies stub, s hit *Array index must be positive or zero because n_gen is nosave and defaults to -1; p was *Bad argument 1 to EFUN call_other() because enter_game() did not exist on the user object.

Shims on secure/user/sw_body.lpc: present the one body_fname as a one-entry bodies map (gender clamped to 0..3), plus a varargs enter_game() that forwards to sw_body_handle_existing_logon(0). Verified live: quits lists [1*] Fluffosp lands back in Void with a working prompt.

Observed, not fixed (programming, but needs a careful skill-table read)

kill guard in Monster_Room: repeating *can't find skill unarmed from std/adversary/skills.lpc (SKILL_D->query_skill("unarmed") is 0). Default unarmed skill_used is "unarmed" (m_damage_source_body.lpc); formula code and the lima trainer use "combat/melee/unarmed". This is lima-demo combat on swmud's rewritten skill table — not invented content to "fix" by adding a skill. Left documented; a later pass should decide whether to rename the default or register the short name.

Checklist

Driver killed by exact PID after the pass. Test-session save/log churn (data/links, data/players, data/daemons/guild.o, data/secure/LOG) was reverted and not committed.