-
Notifications
You must be signed in to change notification settings - Fork 0
Loot Spawns and Crafting
Audience: Engine Developer Status: ✅ Ready
The reward and economy layer: what drops when a mob dies, how item quality and rarity roll, how world bosses respawn on a schedule, how characters advance along tracks, and how crafting and salvage move materials through the economy. As everywhere, the engine supplies mechanism (a loot resolver, a scheduler engine, grant ops, a recipe/salvage runtime) and content supplies every table, tier, and recipe.
Related: Abilities & Effects (the op vocabulary these build on), Combat System (death triggers loot), Orchestration & Directors (scheduled spawns), Pack Entity Reference.
resolveLoot runs from die() before the threat table is scrubbed (threat is the eligibility source), on the dying mob's zone goroutine with the per-zone seeded RNG.
- Personal loot only. Each eligible looter rolls the entire table independently, and drops are delivered directly into that looter's inventory — the corpse holds only the body. Shared/contested loot is not implemented.
- Eligibility = threat: every player who dealt any damage. Tag/group eligibility is not implemented.
-
Roll kinds:
guaranteed/weighted_one(pick exactly one),chance(probability gate then one pick),weighted_n(N independent picks). Rolls within a table are independent, not mutually exclusive. Weighting uses the entry's weight, else its rarity tier's default, else 1;quality_floorkeeps only entries at or above a tier order. -
Pity (bad-luck protection): a per-
chance-roll{key, step, cap}raises the effective chance bymisses × stepup tocap; miss counters are per-looter, per-key, and persisted (a hit resets to 0). -
on_roll(ctx)Lua hatch: runs once per looter after the declarative rolls, inspectsctx.looter/ctx.source, and returns additional prototype refs the caller delivers. It's a read-only decision (can't bypass delivery or spoof a source), fail-closed (no drops on error), capped at 64.
-
rarity_tier_defs:order(the ordinal /quality_floorkey), defaultweight,color,binds(items of this tier bind on creation — the top-tier no-trade sink), and salvage-derivation fields. The rarity ladder is entirely content. -
affix_defs: a reusable named{attr, min, max}. A quality pool references one inline or byref(resolved at build time; an unknown ref becomes an inert empty affix flagged by a boot lint). -
Per-instance quality roll:
{affixes, count, levelMin, levelMax}rolls aLevelandcountaffixes (with replacement). This is a coarse v1 — a repeated attribute takes the last roll (no pool de-dup). -
Item-delta persistence:
Quality{Level, Affixes}is the per-instance delta over the shared prototype — two drops of the same proto differ only here. A worn affix's stat effect is applied by theWearergear modifier source (Abilities & Effects); persistence stores the delta (Persistence & Durability).
Not hot-reloadable: loot tables and their resolved affixes are baked at build time; a running shard keeps boot values until restart.
World-boss schedules are long-timer and owned by the director, distinct from short-cycle zone resets. The scheduler engine (schedule.go) is pure and deterministic given a now, so restart-safety is exhaustively testable: IsDue, AfterSpawn, and AfterDeath (which sets the next spawn to death + interval — so "weekly" means seven days after it dies). on_missed policy handles a window that passed during downtime (spawn_if_overdue vs skip_to_next). State is persisted one key per schedule via a versioned CAS; the tick loop is leader-gated so exactly one director fleet-wide spawns.
The engine provides the scheduler + broadcast + reschedule. The actual spawn and death-report are content Lua (an
on_world("spawn.boss")handler spawns the boss; the boss'son("death")signalsboss.diedback up). Cron/wall-clock scheduling is not implemented — only interval-after-death. And the production director-script that consumes a custom event is not yet authored — see Orchestration & Directors.
A track (track_defs) is the single abstraction for every advancement mode — they differ only in which event feeds the progress attribute. level stays an attribute: levelAttr merely names which attribute (if any) a step raises. Thresholds are ascending; crossing thresholds[i] reaches step i+1, whose grant op-list runs. Two ops drive it:
-
grant_track— add a track at step 0, idempotent (never resets progress; multiclass/reload-safe). -
advance_track— raise the progress attribute, then apply the grants of every newly-crossed step (a big XP award can jump several levels). Each step's grants run once (the stored step is the high-water, so a reload restores the step without re-running grants). FiresOnTrackStep(andOnLevelfor a level track).
The four modes are all the same machinery — only which handler calls advance_track differs: XP-auto (an OnKill handler), use-based (an OnSkillUse handler; a gated/refused op cancels the fire so you can't train past a gate), train-at-trainer (a trainer ability), and point-buy (a spend-points ability; chargen point-buy applies as attribute base on first spawn).
A bundle (bundle_defs) has a kind discriminator (class/race/background/feat/talent/profession) and a grant op-list; apply_bundle runs it on the same context so every grant composes. Multiclass, join-a-guild, and chargen all funnel here. Grant-op precedence is op-list order — there is no separate priority system; nesting runOps on a shared context is the composition.
-
Binding & the single trade gate:
bind_on_pickupbinds on personal-loot delivery,bind_on_equipon wear/wield.transferBlockedis the single gate every transfer (give / drop-to-ground / put-in-shared-container) consults. Binding restricts transfer only — a bound item can still be equipped, destroyed, and deconstructed by its owner. -
Stackable materials: an item with
maxStack > 0;Stack{count}is per-instance state, merged/split on pickup/craft/salvage (default max 1000). -
Recipes (
recipe_defs):craft_recipere-validates every gate as a backstop (profession membership, skill level, station room-flag), validates all inputs before consuming any (all-or-nothing), then consumes and produces. Output quality is a coarse band (qualityBase + skill level); rich affix rolls are deferred.craft <name>resolves via the Diku isname/ordinal grammar, andlist_recipesprints exactly the names it accepts. -
Professions are not a new table — a profession is an ordinary bundle (
kind: profession) whose grants hand out craft verbs, the skill track, and alearn_professionop. Membership (the only new state) is capped (contentmax_professions, default 2); anuncappedgathering/utility bundle is unlimited. -
Salvage / disenchant:
salvage_itemconsumes a held source (even a bound one — destruction isn't transfer) and rolls a salvage table by reusing the loot resolver. The table is per-item override, else the rarity tier default, else the verb's fixed table. A skill gate (tier.salvageSkill + item Level) plus an over-skill bonus grants extra chance-roll-only passes (so a scarce guaranteed component isn't N-multiplied). Only the base pass advances the player's pity counter — a bonus pass re-rolls at the pity-adjusted (buffed) odds but neither consumes nor compounds it, so one over-skilled salvage can't burn the bad-luck standing several times over. Components bind by tier (tier.binds) — top-tier essence is a no-trade sink, low/mid stays tradeable to feed the market.
Deferred / known gaps:
augment_itemis a flat-stat-bump stub (deep affixes/sockets not built); rich craft-output affix rolls are deferred; and per-instance quality is coarse (a repeated affix attribute takes the last roll, with no pool de-dup).
TelosMUD — Wiki under construction.
- Builder Reference
- Builder Commands
- Trust Tier Model
- Pack Authoring
- Pack MUD Settings
- Pack Lua Scripting
- Pack Lua Hooks
- Pack Entity Reference
- Building Instanced Zones
- Engine Developer Reference
- Architecture Overview
- Entity Component Model
- Zone Runtime & Actor Model
- Instanced Zones
- Command Parser & Targeting
- Edge & Protocol
- GMCP Reference
- Persistence & Durability
- Content Loading & Hot Reload
- Abilities & Effects
- Combat System
- Loot, Spawns & Crafting
- Accounts & Auth Internals
- Orchestration & Directors
- Scoped Event Bus
- Cross-Shard Handoff
- Lua Sandbox Internals
- Distributed Systems Model
- RPC & Protobuf