Pack MUD Settings
Audience: Builder Status: ✅ Ready
The pack.yaml manifest is where a pack declares MUD-level settings — the handful of knobs that
shape the whole game rather than one entity. This page documents every top-level key of the pack
document, what it’s backed by, and — honestly — what is not modeled here. For the tree format
and merge rules see Pack Authoring; for the entity/def-table schemas see the
Pack Entity Reference.
There is no separate manifest schema
pack.yaml is not a special file with its own schema — it is simply the top-level of the pack
document (the Pack struct). Any top-level key can appear in any file of the tree; by convention
pack.yaml carries only the scalar/global head and lets the other tree files supply the big
list sections. In the demo pack, pack.yaml contains just:
pack: demo
default_combat: melee
and core/pack.yaml contains only pack: core. Everything else (zones, abilities, …) lives in
sibling files and merges in.
Top-level keys
| YAML key | Type | Meaning |
|---|---|---|
pack |
string | The pack name — written to the pack= column on every row. Defaults to the directory/file name if omitted. |
default_combat |
string | The combat profile a player uses when its own prototype names none. Last non-empty wins across the tree. Empty means players have no profile (a degenerate auto-hit). Backed by pack_meta.body.default_combat. |
pvp_lua |
string (Lua) | Optional PvP consent policy: a Lua function(actor, target) returning a boolean. Empty means the engine’s default pvp_allowed; a missing or erroring policy fails closed (denies). Backed by pack_meta.body.pvp_lua. |
license / attribution |
string | Optional per-pack copyright/attribution (e.g. the 5e SRD’s CC-BY notice). Unlike the last-wins singletons, these accumulate per pack — Merge collects one PackCredit per crediting pack in load order, so a later pack can never erase an earlier one’s notice. Surfaced in-game by the credits verb; backed by pack_meta (per-pack). |
formulas |
map<string,string> (Lua) | Optional ruleset-formula overrides keyed by name (regen, and the reserved to_hit/soak/xp_for/…). Merged last-write-wins by name. Backed by formula_defs. |
world_script |
string (Lua) | Optional world-director orchestration script defining on_signal(event, payload) — sandboxed Lua the director runs to react to your zones’ signal-up events (write world state, broadcast down). Backed by pack_meta.body.world_script. See Pack Lua Hooks → world-director script and Orchestration & Directors. |
zones |
list | The world subtree — rooms, exits, prototypes, resets. See Pack Entity Reference §World entities. |
| the def-table sections | list | attributes, resources, damage_types, affects, abilities, combat_profiles, channels, regions, tracks, bundles, rarity_tiers, loot_tables, affix_defs, spawn_schedules, recipes, wear_slots, chargens, trust_tiers, display_defs. Each is documented in the Pack Entity Reference. |
commands |
list | Custom Lua verbs. Appended, not de-duplicated by ref. See Pack Lua Scripting. |
default_combat, pvp_lua, formulas — semantics live elsewhere
These three keys are the pack’s “rules head”, but their runtime behavior is owned by the combat and scripting engine, not by the loader — this page documents only their shape and storage:
default_combatpoints at acombat_profile_defsref (see the entity reference). What a combat profile does — to-hit, avoidance, damage — is described in Combat System.pvp_luais a policy hook; the gate that consults it, and the fail-closed behavior, are covered under scripting (Pack Lua Scripting) and combat.formulasoverride named ruleset formulas. Onlyregenis actually consulted today;to_hit,soak, andxp_forare defined-but-not-wired (reserved). See Pack Lua Hooks for the live-vs-reserved list and Combat System for the formula semantics.
Where MUD-wide scalars are stored: pack_meta
pack_meta is the only “MUD-wide scalars” table: one row per pack, a JSONB body currently
holding default_combat and pvp_lua. A practical consequence — adding a new pack-level
scalar is a body-field write, not a schema migration. The registry/versioning tables
(content_version, content_pack_registry) are written only by the pull/reload machinery and
are not builder-authored (see Content Pack Operations).
What is not a pack.yaml setting
Two honest caveats, both flagged as not-implemented in the loader:
- No
version/dependencies/authorfields. A pack does not carry its own version, declare dependencies on other packs, or record an author insidepack.yaml. Versioning and the content hash are the externalmanifest.yaml’s job (see Pack Authoring → ingestion paths). There is no dependency resolver — cross-pack ordering is purely the operator’s enabled-list order. - No hardcoded game flavor. Consistent with the engine’s pillar (see Overview),
nothing here bakes in a specific ruleset: the stat list, the resources, the damage types, and
the combat model are all def-table content, and
pack.yamlonly names which of your defs serve as defaults.