Where items come from: inside the loot machine
From logic/item-acquisition.jsonl (75,809 provenance edges) and
logic/loot-vendor-math.json (decompile-verified: VendorLogic.cs,
SharedVendorTables.cs, the BlueprintUnitLoot.GenerateItems() family) —
build 20212986, patch 2.7.0x.
Every sword you've ever looted has a paper trail. We dumped all of them — 75,809 edges linking items to whatever can grant them — and read the code that rolls the drops.
The provenance census
| Source | Edges | What it means | |---|---:|---| | Units | 26,995 | carried/dropped by creatures | | Dungeon & area loot tables | 25,556 | containers and placeables | | Shared vendor tables | 9,878 | shop stock | | Trash-loot settings | 3,403 | auto-filled junk | | Etudes / dialog cues / answers | 3,582 | story grants | | Buffs, abilities, crafting | 2,592 | everything else |
Story grants are bigger than they feel: 3,582 items arrive through dialog and story state — quest rewards live in conversations, not in the loot system at all.
How a container rolls its contents
GenerateItems() runs every loot component in order, and there are
exactly three kinds (loot-vendor-math.json):
- Fixed pack — adds exactly
m_Countof an item or table. No roll. - Variable pack — count is a uniform integer in
[CountFrom, CountTo], inclusive. Your two-arrows-vs-eleven-arrows roll. - Weighted pick — one roll of
uniform[0, sumWeights), walked down cumulative weights; adds exactly 1 of the winner.
The fourth kind isn't a component but a recursion: a loot entry can point at another loot table, once per count — tables compose into trees, which is why a simple crate can be secretly rolling against a dungeon-level table that rolls again.
Trash loot is priced, not listed: FillLootComponent keeps adding
uniform-random trash items until the pile reaches its target
approximate price. That's why every bandit's pouch is worth about the
same.
Vendor math
sellPrice = round0.5(cost × SellModifier × discount × vendor.SellPriceModifier)
buyPrice = round0.5(cost × discount × vendor.PriceModifier)
Three things the UI never says:
- Selling outside the trade window pays less — the junk-sale path skips the vendor's own modifier entirely.
- Discounts are injectable: kingdom buffs and etudes can attach per-vendor, per-item-type discounts through a generic action wrapper.
- Shop stock generates once and persists. A shared vendor table's
GenerateItems()result is saved with your game; restocking only ever adds newly unlocked fixed items (GetLootDifference). Sold out of the unique cloak? It stays sold out.
Trace any specific item's sources from its page in our Items section.
Sources
logic/item-acquisition.jsonl— all 75,809 provenance edges.logic/loot-vendor-math.json— drop-roll semantics, trash-fill pricing, and both price formulas, each pinned to its class file.- Build: 20212986 (patch 2.7.0x).