Jump to content

Quick Guide: How To Mod The Loot Distribution System (Distributions.lua, ProceduralDistributions.lua)

Recommended Posts

This is a visual guide for mappers and modders who need to add or modify PZ's loot entries using the new ProceduralDistributions.lua approach.


Whilst the ProceduralDistributions.lua file has been in the game for quite a while (i.e. the Gigamart shelves having distinct loot types), TIS will be eventually using this file to populate containers with loot in all its building 'room definitions' (Build 41.51 onward).


So What's Changed?

For those familiar with adding loot to PZ's loot tables, the old approach to editing lua files involved adding items directly to the tables named after room definitions in the Distribution.lua file. The downside of this was that loot tended to be a hodge-podge collection of items rather than a logical or thematic grouping of items like you would find in a store's shelves.


The new approach use the ProceduralDistribution.lua to maintain the same loot tables, but classifies them by some distinct purpose or category rather than room definition. For example: BakeryBread, BakeryCake, BakeryPie are all new loot tables in this file, and each will ensure a distinct set of bakery items appear in a container.


Using this new approach, the Distributions.lua file no longer needs a massive list of items under each room definition, but instead randomly roles against a list of ProceduralDistribution loo tables to populate each container. This the above bakery example, it ensures a Bakery with multiple display cases has a good chance of spawning either bread, cakes or pies in each rather than all of these bakery items jumbled together.


Of course there are many other positives to this new approach which most experience modders will figure out as they look and play around with the files.


Important Note For Mods Designed Before Build 41.51?

Now there is one down side to this new (and fantastic) change...it will break alot of loot related mods on the PZ Workshop designed for earlier builds than 41.51. This unfortunately means players will need to be patient until their favorite loot-related mods are updated.


This may also mean some classics that are no longer updated may need to be put to rest (mercifully un-ticked from your mod list :( ). In any instance, players should always be mindful that modders are not obligated to update their mods, nor should they be harassed to do so....play nice and treat others the way you expect them to respond to you.


So How Does This New Loot System Work?

Here is a visual guide on how to link all the necessary elements of each file depending on the room definition:


Loot System Explained v3.png

Edited by TheCommander
Link to comment
Share on other sites

  • nasKo pinned this topic

Please make a normal kerning between letters. This is killing the eyes, and because of this I cannot translate your texts in the picture - through the service of translating images into my language.

The explanatory texts can simply be placed in the main text of the post ... under the picture, and everyone will be happy.

Edited by Nebula
Link to comment
Share on other sites

I typed it real quick




This room is using the 'bedroom' loot definition.
It contains furniture which acts as the following container types: 'wardrobe' and 'sidetable'.
Note the double bunk associated with the theme of a kids room. This is important as the loot generation method will check the sprite name of furniture to understand the intended purpose of the room.

This is the Distributions.lua file. Each entry in this file tells the game what type of loot to generate based on the container types, furniture and zones present in the room. In our example, you can see the container types specified along with the rules it must follow.

Each container type entry has the following properties:
    procedural = if true, indicates the entry uses loot tables from the procedural_distribution.lua file.
    name = the name of the loot tables from the procedural_distribution.lua file.
    min = the amount of times minimum this loot table should appear in this container type. 0 (zero) indicates there is a chance it might not spawn in this container, 1 indicates it must spawn at least once in the container. If you set the value to 10, then assuming there were 10 or more of the container type in the room, it would spawn in 10 of those containers.
    max = As you might guess, it does the same thing as 'min' but in this case sets the upper limit on how many times this loot table can be used. Typically a vanilla entry will have a value of 99 set given that most rooms do not contain the same container type more than a dozen times at most. If you set it to 2 (for example), then a third container of this type would ignore this loot table which may lead to it either looking for an alternative entry or spawning nothing (empty).
    forceForItems = indicates that if the room has furniture with any of the specified spritenames, then it must use this loot table as a priority over any other entries.
    forceForZone = Similar to forceForItem, if the room is located in a part of the map that is designated with the specified zone type, then it will use this loot table as a priority over any other entries. In this above example, a trailer house on the vanilla map is typically located in areas of the map designated as 'TrailerPark'. That's how the game knows to spawn those trailer trash style zombies.
Notes to mappers:
    - The spritenames and offset values for furniture items can be identified via TileZed's 'Tile Properties' screen.
    - Container type names can also be identified via the properties of the furniture via the same 'Tile Properties' screen.
    - Zones can be viewed and defined via WorldEd.
This is the ProceduralDistributions.lua file. This file contains the various items that a room definition can use in game. In our example, it shows all the various wardrobe entries that get used. We typically refer to these as the 'loot tables' which tell the game what items to include in a container when it randomly generates contents.

Each loot table entry is structured as follows:
    rolls = the amount of times the game will roll to add an item to the container. There is a lot of complex magic that goes into these rolls which this guide does not cover. If you need to know more, then it's recommended to look into the code or ask on the discord.
    items = a list of the items that will be considered. The number that appears after the item is the 'weight' Think of it as the chance it has of appearing over the other items. A weight of 100 should make the item appear almost always, where as a very small number such as '0.5' would make it quite rare. Balancing these numbers can be challenging, so if you want something to appear either make the weight higher or consider adding the same item in the table multiple times.
    junk (not shown in example) = some entries will also have a 'junk' entry which is structured in a similar manner to 'items'. The junk entry allows the loot table to ensure that specific junk-type items (e.g. pens, toys) also get thrown into the mix of items when the container is populated. The junk entry can also be used to ensure a specific type of item has a better chance of appearing if it is also listed here.



Link to comment
Share on other sites

@TheCommander  Thanks for the heads up...


Can you explain to me how we would go about adding Procedural lists ?

and also give me the list of new procedural lists ?

or point me in the direction of where that info might be ? Thanks for any info you might share...


[edit]   DoH!!  Disregard... figured it out...

Edited by Arsenal26
Link to comment
Share on other sites

  • 3 weeks later...

@TheCommanderIs there a way to add a reference to a prodecural list (like a custom list) in an existing container in an existing room?


Im tryin to add a new reference to the "pharmacystorage" room on the "metal_shelves" container like so:

table.insert(Distributions.pharmacystorage.metal_shelves.procList,'{name="CustomList", min=1, max=6}');

This line of code keeps throwing a nullpointer, saying that "metal_shelves" does not exist on the pharmacystorage element. From Distributions.lua:


pharmacystorage = {
        isShop = true,
        metal_shelves = {
            procedural = true,
            procList = {
                {name="MedicalStorageDrugs", min=1, max=6},
                {name="MedicalStorageTools", min=1, max=4},
                {name="MedicalStorageOutfit", min=1, max=2},
        fridge = {
            procedural = true,
            procList = {
                {name="FridgeWater", min=0, max=12},
        freezer = {
            rolls = 0,
            items = {
        counter = {
            procedural = true,
            procList = {
                {name="MedicalClinicDrugs", min=1, max=4},
                {name="MedicalClinicTools", min=1, max=2},
                {name="MedicalClinicOutfit", min=1, max=2},



What am i missing here?


EDIT: I have since found a solution that no longer throws any errors, and from what i can tell from the object stack in the debugger, the custom procedural distribution list gets added to the existinng room refinition. However, the game does not seem to want to pull items from the custom list, even though i have given the custom items a high priority, and ensured that min = max in the proc. dist. list

Edited by Erivan
Updatedet Knowledge
Link to comment
Share on other sites

Back in the day we were able to use "table.insert" to put things into the lists. Does "table.insert" still work? And as an example old code:


    table.insert(ProceduralDistributions["list"]["vendingpop"].items, "DragonsDrinks.7thSea");
    table.insert(ProceduralDistributions["list"]["vendingpop"].items, 50.0);


How do you insert them now that the loot codes have changed, what needs to be changed here? I don't want to overwrite the lists and make it incompatible with other mods.


I found something that works, nevermind: 


Edited by A Calm Dragon
Link to comment
Share on other sites

  • 5 months later...

Hello, thank you for this guide. Please tell me if it is possible to change the spawn of loot. Namely, to make it like in Dayz. So that there are not many items (do less than in the "very little" settings), but they respawn, for example, every 30 minutes real time(the game allows you to add loot every game day at least). And the lost that the survivor did not touch for a long time was replaced with another one. This would be very convenient on servers and solved two problems.
1) When a new survivor appears and can't find anything to survive.
2) There will not be a situation where the fastest survivor collected a lot of different weapons and ammunition at one time from a gun store or a police station.

P.S. Sorry if the question is stupid, I'm just learning modding and my English level is not high.

Edited by leorpd
Link to comment
Share on other sites

  • 7 months later...

If your mod contains a lot of items which shall be distributed, you might use this snippet as well for a single ItemDistributions.lua per mod:

local ItemDist = {
  -- LootableMaps
    Distributions = {
      {"CrateMaps", 50},
      {"CrateMaps", 20},
      {"CrateMechanics", 2},
      {"GasStorageMechanics", 2},
      {"MagazineRackMaps", 20},
      {"MagazineRackMaps", 10},
      {"StoreShelfMechanics", 2},
      {"StoreShelfMechanics", 2},
    Items = {
  -- Technical Magazines
    Distributions = {
      {"BookstoreMisc", 2},
      {"CrateMagazines", 1},
      {"LibraryBooks", 1},
      {"LivingRoomShelf", 0.1},
      {"LivingRoomShelfNoTapes", 0.1},
      {"LivingRoomSideTable", 0.1},
      {"LivingRoomSideTableNoRemote", 0.1},
      {"MagazineRackMixed", 1},
      {"PostOfficeMagazines", 1},
      {"ShelfGeneric", 0.1},
      {"ToolStoreBooks", 1},
    Items = {
  -- next item distribution group
  -- ...

local function getLootTable(strLootTableName)
  return ProceduralDistributions.list[strLootTableName]

local function insertItem(tLootTable, strItem, iWeight)
  table.insert(tLootTable.items, strItem)
  table.insert(tLootTable.items, iWeight)

local function preDistributionMerge()
  for i=1, #ItemDist do
    for j=1, #(ItemDist[i].Distributions) do
      for k=1, #(ItemDist[i].Items) do
        local tLootTable = getLootTable(ItemDist[i].Distributions[j][1])
        local strItem = ItemDist[i].Items[k]
        local iWeight = ItemDist[i].Distributions[j][2]
        insertItem(tLootTable, strItem, iWeight)

Junk isn't accounted for yet, but can easily be added

Link to comment
Share on other sites

Create an account or sign in to comment

You need to be a member in order to leave a comment

Create an account

Sign up for a new account in our community. It's easy!

Register a new account

Sign in

Already have an account? Sign in here.

Sign In Now
  • Create New...