Loot
This guide reads a loot table from YAML, explains how the roller turns it into
items, and ends with a script that rolls a table and drops the result into a
corpse's pack. It uses the loot module and a real loot
table from src/Moongate.Server/Assets/Templates/Loot/.
Anatomy of a loot table
A loot table is a YAML entry with an Id, a Mode, a number of Rolls, and a
list of Entries. Here is the real undead.low table:
- Id: undead.low
Mode: Weighted
Rolls: 1
NoDropWeight: 3
Entries:
- Weight: 5
ItemTemplateId: gold
Amount: 45
- Weight: 2
ItemTemplateId: bandage
Amount: 4
Each entry names exactly one of:
ItemTemplateId— a specific item template (gold,bandage, …), orItemTag— a tag, from which the roller picks a random tagged item.
An entry setting both, or neither, is skipped with a warning. Amount is either a
fixed Amount, or a range with AmountMin / AmountMax (rolled inclusively).
Weighted vs additive
The Mode decides how each roll reads the entries.
Weighted (the mode undead.low uses) picks one entry per roll, by
weight. NoDropWeight adds a "nothing dropped" slice to the wheel. For
undead.low the weights are NoDropWeight 3 + gold 5 + bandage 2 = 10, so a
single roll is:
| Outcome | Chance |
|---|---|
| nothing | 3/10 |
| 45 gold | 5/10 |
| 4 bandages | 2/10 |
Additive instead walks every entry and includes each independently with
its own Chance (a probability from 0.0 to 1.0, defaulting to 1.0). The
creature tables under Loot/creatures/ use this mode — each line is an
independent drop:
Mode: Additive
Entries:
- ItemTemplateId: gold
AmountMin: 50
AmountMax: 150
Chance: 1.0
- ItemTag: gems
Amount: 1
Chance: 0.25
Here every roll always drops 50–150 gold and drops a random gem a quarter of the time.
Rolls repeats the whole process: a weighted table with Rolls: 2 picks
twice; an additive table with Rolls: 2 walks its entries twice.
Rolling from Lua
loot.roll takes a table id and returns an
array-table of the serials it created. An unknown id is not an error — it logs a
warning and returns an empty table, so a loop over the result is always
safe.
Important
Rolled items are created floating (unplaced). You place them yourself, for
example into a container with
item.add_to_container.
The complete script
This spawns a skeletal knight, then rolls the undead.low table into a backpack
standing in for its corpse pack.
-- scripts/main.lua
events.on("world_ready", function()
local knight = mobile.create_from_template("skeletal_knight_npc", 1, 1425, 1695, 0)
if knight then
log.info("skeletal knight {0} spawned", knight)
end
-- A backpack to act as the corpse's loot container.
local corpse = item.create("backpack", 1, 0)
-- Roll a loot table and drop every result into the pack.
local drops = loot.roll("undead.low")
for _, serial in ipairs(drops) do
local loot_item = item.get(serial)
item.add_to_container(corpse, serial, 0, 0)
log.info("dropped {0} x{1}", loot_item.name, loot_item.amount)
end
if #drops == 0 then
log.debug("undead.low rolled nothing this time")
end
end)
Because undead.low has a NoDropWeight, an empty roll is a normal outcome —
the script handles it rather than treating it as an error.