Document Control¶
| Field | Value |
|---|---|
| Document ID | modders-item-scripts-distributions |
| Version | 1.0.0 |
| Status | approved |
| Confidence | Medium |
| Category (track) | Modders |
| Build | both |
| Owner | PZ Knowledge-Base Pipeline |
| Created | 2026-10-07 |
| Updated | 2026-10-08 |
| Review due | 2027-01-07 |
| Game versions verified | 41.78.16 (Umbrella stubs), 42.20 (Umbrella 42.20.0 stubs), 42.21 (Umbrella 42.21.0 stubs and the 42.20.1 to 42.21 notes); ScriptsDocs pages are stamped 42.21.0 |
Executive Summary¶
Most content mods in Project Zomboid are defined twice: once in plain-text
script files under media/scripts/ (items, recipes, fixing and evolved
recipes), and once in Lua tables that decide where those items spawn as loot.
This document covers both layers: the block syntax shared by all script files,
the item block and its ItemType classes, the Build 42 craftRecipe format
with its inputs and outputs children against the Build 41 Recipe
block, item tags, the evolvedrecipe and fixing blocks, and the three
distribution files that drive world loot [7] [8] [9] [18].
The headline change for porters: B42 replaced the single-line B41 recipe
description with a structured craftRecipe block whose ingredients live in a
child inputs block and whose results live in outputs [9] [10]. B42 also
turned item tags from a fixed enum into a registry that mods can extend [3]
[22], and renamed the item-class parameter from Type to ItemType [8].
Distribution tables kept their file names and overall shape, but the B42 pass
added and removed room and container entries [4].
Script syntax is not covered by Umbrella, which is Lua-only. The API-existence
gate therefore only validates the Lua symbols named in code spans here
(distribution events, ItemTag registration); the script grammar is sourced
from the generated ScriptsDocs reference [7] and the game's own patch notes.
Confidence is Medium: the script reference is primary and generated against
game version 42.21.0, which now matches the 42.21.0 stubs this document was
re-checked against, but the 42.13-era registry guide was not re-confirmed and
no in-game test was run [7] [2] [28].
Key Takeaways¶
- Script files are plain-text data, not code: a
moduleblock wrapping blocks such asitem,craftRecipe,evolvedrecipeandfixing. (cited) (both) - The
itemblock's behaviour is selected byItemType; the oldTypeparameter is marked deprecated, replaced byItemTypeas of 42.13.0. (cited) (B42) - B42 recipes are
craftRecipeblocks with requiredinputsand usuallyoutputschildren; the B41Recipeblock is listed on the wiki as the Build 41 format and is not documented in ScriptsDocs. (cited) (both) - B42 item tags are namespaced (
base:egg) and a mod can register its own through Lua at load time. (cited) (B42) - Loot lives in Lua:
ProceduralDistributions.listholds weighted item lists, and room/container tables reference them by name. (cited) (both) - Three distribution events exist on both builds:
Events.OnPreDistributionMerge,Events.OnDistributionMergeandEvents.OnPostDistributionMerge. (cited) (both) - The two builds' Umbrella stubs describe the Pre event differently; which event is safest for edits is not settled by a primary source. (cited) (both)
- ScriptsDocs is stamped 42.21.0, the same release as the re-checked stubs; parameter detail was not diffed against 42.20.0 game files. (cited) (B42)
- The 42.21.0 distribution and
ItemTagstubs are identical to the 42.20.0 ones, and the three distribution events read the same. (cited) (B42)
Purpose¶
This document answers: "I want to add an item, a way to make it, and a way to
find it in the world: which files, which block syntax, and what changed
between Build 41 and Build 42?" It goes deeper than modders-foundation,
which only introduces script files, module blocks and the craftRecipe
headline, and it is the modding-side companion to players-crafting-chains,
which holds the player-facing facts about the crafting overhaul.
Scope¶
Covered: script file layout, module and imports blocks, the item block and
common parameters, craftRecipe with inputs/outputs/itemMapper, the
B41 Recipe block at the level the sources support, evolvedrecipe,
fixing, item tags, translation keys for scripts, and the Lua distribution
tables and events that place items in the world.
Not covered: vehicle, model, sound and entity/fluid script blocks (own
documents), full per-parameter tables (use ScriptsDocs, linked below), Lua
APIs beyond the named distribution/tag symbols (modders-lua-api-surface),
event semantics in general (modders-events-callbacks), and mod folder
layout (modders-foundation, modders-modinfo-modid-conventions). The
B41-format Recipe block syntax is not reproduced because no primary source
documenting it was reachable (see Open Questions).
Definitions¶
- Script file — a
.txtfile undermedia/scripts/in a mod or the game; a custom block format, not a programming language [27]. - Module — the namespace block wrapping script entries;
Baseis the game's own, and full IDs take the formmodule.id[13]. - Full type —
module.id, for exampleBase.Nails[8] [13]. - Soft override — redefining an existing block merges or replaces it depending on block type instead of failing; ScriptsDocs marks each block as supporting it or not [7] [27].
- ItemType — the item-block parameter selecting the item class
(
base:food,base:weapon, ...) and thus which parameters apply [8]. - Item tag — a namespaced string label on an item, queried from Lua, Java and recipes [8] [15].
- Procedural distribution — a named loot list (rolls plus weighted items) referenced by room and container tables [16] [18].
Build Applicability¶
| Build | Applies | Verified against | Notes |
|---|---|---|---|
| B41 (legacy41) | Yes, partially | Umbrella 41.78.16 stubs [19] [21] [24]; wiki block list [27] | Recipe block and Lua distribution tables; ScriptsDocs does not cover B41 [7] |
| B42 (stable) | Yes | Umbrella 42.21.0 stubs [32] [33] [34] [35] (earlier check: 42.20.0 stubs [18] [20] [22] [23]); ScriptsDocs stamped 42.21.0 [7] | Stable 42.21 released 2026-09-28 [2] |
Game 42.21 stable was released on 2026-09-28 [2] [6] and 41.78.21 legacy hotfixes on 2026-08-26 [5] [6].
42.21 re-baseline (2026-10-07). This revision re-checked the document
against the official 42.20.1, 42.20.2, 42.20.3, 42.20.4, 42.21 unstable and
42.21 stable posts [29] [30] [5] [36] [2], the TIS forum 42.21 patch-note list
[31] (abridged to "selected" for its long fix lists), and the 42.21.0 Umbrella
stubs [32] [33] [34] [35] (commit 13d01f9ee58fa48773553920db56d06f0005e7f8;
the upstream 42.20.0 tag was later moved, so commits are cited, not tags).
None of those notes mentions item, craftRecipe, evolvedrecipe, fixing
or loot-distribution script syntax, and the three distribution stubs and the
ItemTag stub are byte-identical to their 42.20.0 versions [32] [34]. The
ScriptsDocs site is itself generated from 42.21.0 data (its page title reads
"PZ API Documentation 42.21.0") [7], so script parameter details were never
42.20-specific and have not been diffed against 42.20.0 game files. Unchanged
statements are carried forward from 42.20 with no contradicting change found;
nothing was re-tested in-game. The TIS 42.13 migration guide [28] was not
re-confirmed by any 42.21 source; its registry classes still exist with
unchanged members in the 42.21.0 index [34]. The B41 side rests on the
41.78.16 stub pin; the legacy line has since moved to 41.78.21 [5].
Reference¶
Script file anatomy¶
Scripts are text files ending in .txt under media/scripts/, with no
mandated folder organisation; the wiki advises a subfolder named after the
mod to reduce clashes [27]. Entries are blocks delimited by braces, parameters
are Key = Value, pairs whose trailing comma is mandatory even on the last
line, and comments use /* ... */ only [27]. The root of every script file
may only contain module blocks [13] (sandbox option scripts are the
documented exception) [27].
A module block is a namespace and carries a mandatory ID; Base is the
game's namespace. The module page lists as permitted children, among others,
item, craftRecipe, evolvedrecipe, fixing, fluid, entity, model,
sound, vehicle and imports [13]. The Recipe block is not in that
list [13], and ScriptsDocs has no page for it, while the wiki still lists it
as the Build 41 recipe block [27].
An imports block inside a module gives direct access to other modules'
entries without a prefix; ScriptsDocs notes that Base is already parsed and
suggests referencing IDs with their module instead [13]. The wiki adds that
unqualified references search the current module, then imports, then Base,
then all others, and that this is inconsistent between block types [27].
Writing a block whose ID already exists is a soft override for item and
craftRecipe blocks, while whole-file replacement happens when a mod uses
the same relative path as an existing script file [27].
The item block¶
An item block lives in a module, takes a mandatory ID without spaces, and
may have child blocks including component FluidContainer and
component Durability [8]. Its ItemType is required and must be one of
base:alarmclock, base:alarmclockclothing, base:animal, base:clothing,
base:container, base:drainable, base:food, base:key, base:literature,
base:map, base:moveable, base:normal, base:radio, base:weapon or
base:weaponpart; parameters specific to one class (for example
Calories for food or ClipSize for weapons) are only loaded for that
class [8]. The older Type parameter is flagged deprecated since 42.13.0,
replaced by ItemType [8].
Representative general parameters documented for the block [8]:
| Parameter | Documented role |
|---|---|
Weight |
Encumbrance, float, default 1.0 |
DisplayCategory |
Key suffix for the inventory category label (IGUI_ItemCat_<value>) |
Tags |
Semicolon-separated list of item tags |
EvolvedRecipe |
Which evolved recipes the item may be an ingredient in, as name:quantity pairs |
ConditionMax |
Durability pool, integer, default 10 |
DisplayName |
Deprecated since 42.13.0 in favour of a translation entry |
The item's visible name comes from a translation entry keyed by the item's
full type in the ItemName translation file, and ScriptsDocs warns that
without a translation entry the weight will not work in game [8].
craftRecipe (B42)¶
A craftRecipe block sits in a module, has a mandatory ID that may contain
spaces, and requires an inputs child; outputs, itemMapper and
overlayMapper children are optional [9]. Defined inside an entity it
becomes the build recipe of that buildable instead of an item recipe [9].
craftRecipe supports soft overrides [9]. Documented parameters include [9]:
| Parameter | Documented role |
|---|---|
tags |
Required list; must include at least one crafting-bench tag such as AnySurfaceCraft or InHandCraft |
time |
Crafting time, integer, default 50, unit not specified |
timedAction |
Timed action script for animation, sounds and calorie cost |
category |
Menu category, default Miscellaneous; label via an IGUI_CraftingCategories_ key |
SkillRequired |
Skill:level pairs separated by semicolons |
xpAward |
Skill:xp pairs |
NeedToBeLearn |
Whether the recipe must be learned first |
AutoLearnAll / AutoLearnAny |
Skill thresholds that grant the recipe automatically |
MetaRecipe |
Links recipes so that knowing one grants the other, one direction only |
OnCreate, OnTest, OnFailed, OnUpdate, OnAddToMenu |
Lua callbacks named as global functions |
AllowBatchCraft |
Batch slider, default true |
CanWalk |
Whether the player may walk while crafting, default false |
Tooltip |
Key in the Tooltip translation file |
The recipe name is translated by an entry in the Recipes translation
file keyed by the recipe ID alone, without the module [9]. OnCreate
functions receive the craft data and the character, and OnTest receives
an item and the character and returns a boolean [9]. Custom crafting-bench
tags are created by adding a component CraftBench to an entity script [9].
The inputs block has no ID and no parameters of its own; it may be a child
of craftRecipe or of component CraftRecipe [10]. The documented example
lines show the grammar: an input line starts with item, a count, then
either a bracketed list of full types or a tags [...] selector, optionally
followed by mode:keep or mode:destroy, a flags [...] list and a
mappers [...] reference, and a fluid line of the form fluid 1.0 [Petrol]
also appears [9]. The outputs block has no ID or parameters; each line is
item <quantity> <full type> or item <quantity> mapper:<mapperID> [10]. An
itemMapper child block declares a table from input item to output item
with an optional default [9] [14].
The recipe page's own examples place the recipe in the Base module and
show crafts that keep a tool via mode:keep while consuming logs, and a
lantern refill using a mapper [9]. Recipe lists in the crafting UI are
filtered by the bench tags and learning state; the player-facing view of that
system is in players-crafting-chains.
The B41 Recipe block¶
The wiki's block list describes Recipe as the block used to define recipes
in Build 41 [27]. The Build 41.78.16 Umbrella stub for the Java Recipe
class exposes the data model behind it: a name, category, result, sources,
required skills, time to make, a tooltip, flags such as hidden, learn
requirement and "can be done from floor", and Lua hooks for create, test,
can-perform and give-XP [24]. The B42.20.0 stubs still ship a Recipe class
[25] and so do the 42.21.0 stubs, with the same Java methods [35]. The
42.21.0 index lists six fewer members on the Recipe name than the 42.20.0
index (GetItemTypes, OnCanPerform, OnCreate, OnGiveXP, OnTest,
WeaponParts); these names are not in the Java stub text at either commit,
so their origin was not traced here [25] [35]. Whether 42.21 still parses
Recipe blocks in scripts is not established by any source cited here (see
Open Questions).
evolvedrecipe and fixing¶
An evolvedrecipe block, in a module, defines a dynamic recipe whose
ingredients are added across several steps, with stats from each ingredient
summed into the product; documented parameters include BaseItem,
ResultItem, MaxItems, Name, Cookable, CanAddSpicesEmpty,
AddIngredientIfCooked, AddIngredientSound and MinimumWater [11]. An
item opts in as an ingredient via its own EvolvedRecipe parameter [8] [11].
A fixing block, in a module, defines how an item can be repaired, with the
documented parameters Require, Fixer, GlobalItem and ConditionModifier;
its soft-override status is listed as unknown, and most parameters have no
description [12]. The Java classes behind both blocks exist in the B41 and
B42 stubs [19] [24] [25], which is consistent with both blocks surviving the
B42 crafting overhaul. ScriptsDocs lists the evolvedrecipe and fixing
parameters but states nothing about which builds they apply to [7] [11] [12].
Item tags¶
On B42, an item's Tags value is a semicolon-separated list of namespaced
tags such as base:egg and base:hasmetal. The Java-side field names
(for example ItemTag.AEROSOL) map to those script names (base:aerosol) [8] [15].
A mod defines its own tag by registering it from Lua with
ItemTag.register("yourmodid:yourtagname") (B42) in registries.lua and then using the
registered ID in item scripts [8] [22] [28]. The 42.13.0 patch notes record
that ItemTag was refactored from an enum into a class with registry
support [3]. The B41 Umbrella index has no ItemTag class [19]. Recipe
inputs can select by tags [...] [9].
Registries (42.13 and later)¶
The Build 42.13 modding migration guide, a first post by an Indie Stone
moderator on the official forum dated 2025-12-11, states that from 42.13 a
set of identifiers must be declared from Lua before scripts can use them [28].
The declaring file must be named exactly registries.lua, sit in the mod's
media folder, and is loaded before scripts and before all other Lua [28].
The guide lists eleven registries: CharacterTrait, CharacterProfession,
ItemTag, Brochure, Flier, ItemBodyLocation, ItemType, MoodleType,
WeaponCategory, Newspaper and AmmoType [28].
Each registry is declared with a register call taking a namespaced ID of the
form namespace:name, for example the guide's ItemTag.register("testmod:bobbypin")
(B42) [28]. Two registries take more arguments: Newspaper takes a list of
entry names, and AmmoType takes an item key built from an item name and an
item type [28]. The Umbrella 42.20.0 index confirms a register member on all
eleven registry classes, and an ItemKey.new constructor, so the call shapes
exist in the 42.20.0 Lua surface (B42) [22] [18]. The registry classes are
absent from the 41.78.16 index, apart from unrelated same-named ItemType and
MoodleType classes (B41) [19].
Registered IDs are then used verbatim in scripts. The guide's example
shows a character_trait_definition whose CharacterTrait parameter holds the
registered trait ID, a character_profession_definition whose
CharacterProfession parameter and GrantedTraits reference registered IDs,
an item whose Tags value is a registered tag, and a recipe input selecting a
vanilla tag written with its namespace (tags[base:screwdriver]) [28]. That
last form shows recipe tag selectors are namespaced like item tags, which
resolves the unnamespaced tags [Saw] ambiguity in the ScriptsDocs example [9].
The guide's script-side changes are: the item DisplayName parameter is
removed and the name is read only from the Module.ItemId translation key; Type is
renamed ItemType and requires an entry in the ItemType registry; and Tags
require the ItemTag registry [28]. Base-game scripts, it adds, are now
generated from Java code and read as before, so they are good examples [28].
Where sources differ: ScriptsDocs calls DisplayName and Type deprecated as
of 42.13.0 with a replacement, not removed [8]; the guide says removed and
renamed [28]. ScriptsDocs lists base:-prefixed ItemType values as a fixed
allowed list [8], whereas the guide says custom ones can be registered [28];
the two are not contradictory but the allowed list on that page does not show
mod-registered values. The guide's recipe example uses the spelling
needTobeLearn, while the 42.13.0 patch notes say that spelling was removed in
the builder in favour of needToBeLearn, and ScriptsDocs documents the latter [3] [9] [28].
The guide dates from the 42.13 era; this document checked it against the
42.20.0 and 42.21.0 stubs and 42.21-stamped ScriptsDocs, and no registry
detail was changed or re-tested in-game. In the 42.21.0 index all eleven
registry classes still carry a register member with unchanged membership
compared with 42.20.0 [28] [7] [34]. The 42.20.1 to 42.21 notes neither
confirm nor contradict the guide's registry or script-side statements [29] [31].
Loot distribution files¶
World loot is data in three Lua files that Umbrella stubs under
lua/server/Items/ [18] [19] [32]: Distributions.lua, ProceduralDistributions.lua
and SuburbsDistributions.lua. The B42 stubs describe the shapes with typed
annotations [18], and the 42.21.0 stubs of the same three files are unchanged
from 42.20.0 [32]:
ProceduralDistributions.listmaps a list name to a table withrolls(integer) anditems, an array alternating item name and weight, plus optional flags such asjunk,bags,isShop,isWorn,isRotten,maxMap,stashChanceandonlyOne[18] [16].- A room's container entry is either a procedural distribution itself or a
table with
procedural = trueand aprocListof entries withname,min,maxandweightChance, and optionalforceForItems,forceForRooms,forceForTilesandforceForZones[18]. ScriptsDocs statesforceForZonesdoes nothing [17]. - Room tables may carry fields such as
isShop,outfitfields,vehiclesandprofessionChance[18]. - Vanilla
rollssemantic: the roll count applies to each item entry individually rather than once per list [16].
The B41 stub of ProceduralDistributions.lua embeds vanilla data in which
items appear with bare names, such as Baseball followed by a weight [19]. The
B42 stub for the same file carries only the type annotations, not vanilla
entries [18], so the B42 name format cannot be confirmed from it.
Global helper functions in the same stub files exist in both builds'
indexes: ClearAllDistributionItems, RemoveItemFromDistribution,
ReplaceItemInDistribution, MergeDistributionRecursive and
DeepPrintDistributionTable [18] [19]. Three events cover the merge phase:
Events.OnPreDistributionMerge, Events.OnDistributionMerge and
Events.OnPostDistributionMerge, present in both builds' stubs [20] [21], and
unchanged in the 42.21.0 events stub [33]. The B42 stub
describes the Pre event as "triggered after the distribution tables have
been merged", the same wording as the post event's near-twin, whereas the B41
stub speaks of the plain event as "fires when the tables merge" [20] [21]. The
42.21.0 stub keeps the same wording for the Pre event [33].
B41 vs B42 Delta¶
| Area | Build 41.78 (B41) | Build 42.20 to 42.21 (B42) |
|---|---|---|
| Recipe block | Recipe block [27] |
craftRecipe with inputs/outputs children; documented in ScriptsDocs [9] [10] |
| Recipe knowledge | Java Recipe exposes learn flag and Lua hooks [24] |
NeedToBeLearn, AutoLearn*, MetaRecipe, research parameters [9]; the see-all-recipes cheat was removed in 42.13.0 and replaced by a handcraft-panel tickbox [3] |
| Item class parameter | Type (wiki-era usage; deprecation noted only on B42 docs) [8] |
ItemType with base: values; Type deprecated since 42.13.0 [8]; ScriptsDocs stamped 42.21.0 |
| Item tags | No ItemTag class in the stub index [19] |
Namespaced tags, ItemTag refactored to a registry-backed class in 42.13.0; mods can register tags [3] [22] |
| Build recipes | Multistagebuild block [27] |
entity script holds a craftRecipe as its build recipe [9] [27] |
| Cooking recipes | evolvedrecipe class present [19] |
Same block; MinimumWater and a frozen-food rule appear in the docs and notes [3] [11] |
| Distribution stubs | Stub embeds vanilla list data [19] | Stub is annotation-only, identical at 42.20.0 and 42.21.0 [18] [32] |
| Distribution content | Baseline | 42.13.0 "Updated loot distribution"; 42.14.0 added agriworker, campworker and hunterstorage rooms and removed containers unused by TIS maps; .223 references became 5.56 [3] [4] |
| Distribution events | Pre, plain and Post events present [21] | Same three events, 42.20.0 and 42.21.0 [20] [33] |
| Doc coverage | No ScriptsDocs for B41 [7] | ScriptsDocs generated from game data, stamped 42.21.0 [7] |
| Tag/registry loading | n/a | registries.lua declares tags, item types, traits, professions and more before scripts load; 42.13.0 notes say mods may fill registries [3] [28] |
The 42.20.0 stable notes add two loot-adjacent entries: a fix so the same building no longer shows different loot to different players, and a fix for an exploit allowing arbitrary item spawning through mod data [1].
42.20.1 to 42.21 changes that touch script and translation authors. The
42.20.1 notes say mods can now write .json files, and that mod translations
should use %% to display a literal %; the 42.20.2 notes add that a
temporary workaround accepts both ways but "will be removed in a future
unstable update", with error logs flagging affected strings [29] [30]. The
42.21 notes list an updated localization system enabling more translatable
strings, and a fix replacing console printing with a RuntimeException when
missing translations or missing recipes are detected [36] [31]. They also list
a fix for wrong recipes used in a generated trait script class; the notes give
no detail on script syntax for any of these [31]. The 42.20.4 notes removed
loadstring and loadstream and 42.21 re-enabled them [5] [2] [31].
Practical Guidance¶
The snippets below are illustrative templates built from the cited block shapes, not copies of game files; check each against ScriptsDocs [7] and your target build before shipping.
An item (B42 form; on B41 the class parameter was Type):
module Base {
item MyMod_Widget {
ItemType = base:normal,
DisplayCategory = Material,
Weight = 0.5,
Tags = base:hasmetal,
}
}
Add "Base.MyMod_Widget": "Widget" to your ItemName translation file, keyed
by the full type, so the name and weight work [8]. Prefix your item IDs with
your mod name when using Base [27].
A B42 recipe splitting it into parts:
module Base {
craftRecipe MyMod_SplitWidget {
timedAction = Making,
Time = 80,
Tags = InHandCraft,
category = Miscellaneous,
inputs {
item 1 [Base.MyMod_Widget],
}
outputs {
item 2 Base.Nails,
}
}
}
Add "MyMod_SplitWidget": "Split widget" to the Recipes translation file,
keyed by the bare recipe ID [9]. Remember that Tags needs at least one
crafting-bench tag [9].
Adding loot, as a Lua file in media/lua/server/:
local function addMyLoot()
local list = ProceduralDistributions.list.SomeVanillaList
table.insert(list.items, "MyMod_Widget")
table.insert(list.items, 4)
end
Events.OnPreDistributionMerge.Add(addMyLoot)
Replace SomeVanillaList with a real list name taken from the B42
procedural-distribution reference [16] [18]. The items array alternates name
and weight [18], so always insert the pair in order. Use the item name format
you see in the vanilla data for your target build; B41 uses bare names [19].
Working habits that follow from the sources:
- Reference item IDs with the module prefix everywhere to dodge the inconsistent unqualified lookup [13] [27].
- Prefer new module names for your own scripts, since redefining a block ID soft-overrides it, which also lets a mod change vanilla items by accident [8] [9] [27].
- Do your distribution edits in one function bound to one event, and use the helper functions to remove or replace vanilla entries rather than writing your own loops [18].
- Keep dual-build mods split: B41 script files at the mod root, B42 files in
the version folder, as
modders-foundationdescribes. - Re-pull the ScriptsDocs page for any block you rely on after each game update, because it is generated from game data [7] [26].
Common Pitfalls & Troubleshooting¶
- "My script is ignored / parses oddly." Missing trailing commas, or
//comments, break parsing; only/* */comments work [27]. - "My weight shows as zero." Add the
ItemNametranslation entry; the docs say weight does not work without it [8]. - "My B41 recipe vanished on B42."
craftRecipeis the documented B42 format and ScriptsDocs has noRecipeblock, so rewrite it [9] [27]. - "Recipe is not in the menu."
tagsis required and needs a crafting bench tag; also check learn requirements andOnAddToMenureturns [9]. - "My recipe name shows as the ID." The
Recipestranslation key is the bare recipe ID, no module prefix [9]. - "My custom tag does nothing." On B42 the tag must be registered in
registries.lua(exact filename, inmedia) and the namespaced ID used in the item script [8] [22] [28]. - "My trait, profession or item type is rejected." Those IDs need their own registry entries first, in the same file [28].
- "Edits to distributions have no effect." The merge events exist for this phase; the stub descriptions of the Pre event conflict, so test which event runs after the vanilla tables load in your build [20] [21].
- "My mod's loot used a container that vanished." 42.14.0 removed containers not used by TIS maps from the Distributions file [4].
- "A mod using
loadstringbroke after 42.20.4." Those functions were removed in 42.20.4 and re-enabled in 42.21 [2] [5]. - "A
%in my translation string shows wrongly." Write%%for a literal percent; the temporary both-ways handling is to be removed [30]. - "A missing translation or recipe now throws an error." 42.21 turned the detection of missing translations and recipes into a RuntimeException rather than console output, so fix the missing entries [31].
Community Notes & Unverified Claims¶
Claim 1 — Distribution edits belong in Events.OnPreDistributionMerge¶
- Claim: Modding guides and community mods commonly register loot edits on
Events.OnPreDistributionMergeso their changes participate in the merge. - Why unverified: The Umbrella stubs only give one-line event descriptions that conflict between Pre and post wording [20] [21]; no primary source states the intended mod pattern.
- Confidence: Low. Widely repeated and plausible but not primary-sourced here; the template above uses it as an assumption.
Claim 2 — B42 distribution item names still use bare IDs¶
- Claim: Mod authors report that loot-list entries use bare item names
such as
Baseballrather than full types, on B42 as on B41. - Why unverified: Only the B41 stub embeds vanilla names [19]; the B42 stub is annotation-only [18].
- Confidence: Low. The B41 evidence is solid but B42 is not verified.
Claim 3 — Modded items in a custom module work in distributions¶
- Claim: Community advice says items defined in a custom module need the
full type in distribution lists while
Baseitems use bare names. - Why unverified: No cited source states the lookup rule for distribution entries; ScriptsDocs only calls module lookup inconsistent in general [13].
- Confidence: Low. Unverified inference from the general lookup warning.
Risks & Caveats¶
- Version skew. ScriptsDocs is stamped 42.21.0 [7] and the Umbrella stubs are now 42.21.0 [32]; the 42.13-era migration guide [28] and the wiki page stamped 42.17.0 [27] are older, and parameter defaults could differ from 42.20.
- Wiki lag. The pzwiki Scripts page is stamped 42.17.0 and says it may be out of date [27].
- Generated docs are incomplete. Many ScriptsDocs parameters carry the
type
Unknownor "no description" [8] [12]; absence of a description is not evidence a parameter is useless. - B41 recipe syntax gap. This document cannot give B41
Recipegrammar from a primary source. - No in-game test. No snippet here has been run in a game build.
- Stubs are not engine truth. Umbrella describes the Lua surface only; it says nothing about script grammar [18].
Verification Steps¶
- Open
media/scripts/in the installed game and read an existingitem,craftRecipeandevolvedrecipeblock next to ScriptsDocs [7] [8] [9]. - Check
ItemTypeis accepted: define the item snippet above on 42.21 and spawn it with the debug item list. - Test the recipe snippet; confirm the menu entry appears and the name
resolves through the
Recipestranslation [9]. - In the Umbrella 42.21.0 checkout (commit 13d01f9e) open
library/events.luaand search forDistributionMerge[33] (42.20.0 file: [20]); do the same at the 41.78.16 pin underlibrary/Events/Events.lua[21]. - Open the game's
media/lua/server/Items/ProceduralDistributions.luaand record the item name format and a real list name [16] [18]. - Print the merged tables after load using
DeepPrintDistributionTable[18] to see which event sees vanilla data. - Grep ScriptsDocs for the Item page's version header to compare with your installed build [7].
Open Questions¶
- Does 42.21 still parse the B41
Recipeblock? The B42 stubs still ship the class [25] [35], but ScriptsDocs does not list the block [13]. - Which of the three merge events runs after vanilla tables are fully populated, and does that differ between builds? [20] [21]
- What is the exact item-name rule in B42 distribution lists (bare or full type), and for custom modules?
- Is the old
Typeparameter still honoured by 42.21, or only rejected as the guide implies? ScriptsDocs says deprecated, the guide says renamed [8] [28] - Did parameter defaults change between 42.20.0 and 42.21.0? The 42.21 notes mention no script-parameter change, but ScriptsDocs has no 42.20.0 edition to diff [7] [31]
References¶
Primary Sources — official patch notes, ScriptsDocs generated from game data, pinned Umbrella stubs.
- [1] The Indie Stone — Build 42.20.0 Stable Released (29 July 2026). https://steamcommunity.com/games/108600/announcements/detail/1839676055882259 Accessed 2026-10-07.
- [2] The Indie Stone — Build 42.21 Stable Released (28 September 2026). https://steamcommunity.com/games/108600/announcements/detail/1844751498231307 Accessed 2026-10-07.
- [3] The Indie Stone — Build 42.13.0 UNSTABLE Multiplayer Released (11 December 2025). https://steamcommunity.com/games/108600/announcements/detail/1818752592122972 Accessed 2026-10-07.
- [4] The Indie Stone — Build 42.14.0 Unstable Released (16 February 2026). https://steamcommunity.com/games/108600/announcements/detail/1824644522845673 Accessed 2026-10-07.
- [5] The Indie Stone — 42.20.4 STABLE & 42.19.2 UNSTABLE & 41.78.21 LEGACY Hotfixes Released (26 August 2026). https://steamcommunity.com/games/108600/announcements/detail/1842212951296601 Accessed 2026-10-07.
- [6] Valve — Steam News Web API (ISteamNews), app 108600 (mirror used to date the posts above). https://api.steampowered.com/ISteamNews/GetNewsForApp/v2/?appid=108600&count=100&maxlength=0 Accessed 2026-10-07.
- [7] PZ-Wiki-Modding — ScriptsDocs index (site "PZ API Documentation 42.21.0"). https://pz-wiki-modding.github.io/PZ-API-Docs/scripts.html Accessed 2026-10-07.
- [8] PZ-Wiki-Modding — ScriptsDocs: item. https://pz-wiki-modding.github.io/PZ-API-Docs/scripts/item.html Accessed 2026-10-07.
- [9] PZ-Wiki-Modding — ScriptsDocs: craftRecipe. https://pz-wiki-modding.github.io/PZ-API-Docs/scripts/craftrecipe.html Accessed 2026-10-07.
- [10] PZ-Wiki-Modding — ScriptsDocs: inputs and outputs. https://pz-wiki-modding.github.io/PZ-API-Docs/scripts/inputs.html and https://pz-wiki-modding.github.io/PZ-API-Docs/scripts/outputs.html Accessed 2026-10-07.
- [11] PZ-Wiki-Modding — ScriptsDocs: evolvedrecipe. https://pz-wiki-modding.github.io/PZ-API-Docs/scripts/evolvedrecipe.html Accessed 2026-10-07.
- [12] PZ-Wiki-Modding — ScriptsDocs: fixing. https://pz-wiki-modding.github.io/PZ-API-Docs/scripts/fixing.html Accessed 2026-10-07.
- [13] PZ-Wiki-Modding — ScriptsDocs: module, imports and ROOT-Scripts. https://pz-wiki-modding.github.io/PZ-API-Docs/scripts/module.html , https://pz-wiki-modding.github.io/PZ-API-Docs/scripts/imports.html and https://pz-wiki-modding.github.io/PZ-API-Docs/scripts/root_files/scripts.html Accessed 2026-10-07.
- [14] PZ-Wiki-Modding — ScriptsDocs: itemMapper. https://pz-wiki-modding.github.io/PZ-API-Docs/scripts/itemmapper.html Accessed 2026-10-07.
- [15] PZ-Wiki-Modding — PZ API Docs: Item Tags. https://pz-wiki-modding.github.io/PZ-API-Docs/java/item_tags.html Accessed 2026-10-07.
- [16] PZ-Wiki-Modding — PZ API Docs: Procedural distributions properties. https://pz-wiki-modding.github.io/PZ-API-Docs/mapping/procedural_distributions_properties.html Accessed 2026-10-07.
- [17] PZ-Wiki-Modding — PZ API Docs: ItemPickerContainer properties. https://pz-wiki-modding.github.io/PZ-API-Docs/mapping/item_picker_container_properties.html Accessed 2026-10-07.
- [18] PZ-Umbrella — Umbrella 42.20.0 (commit 58204fc4), Distributions.lua, ProceduralDistributions.lua, SuburbsDistributions.lua. https://github.com/PZ-Umbrella/Umbrella/blob/58204fc47895ba249592519cedecc7cfbaaebd60/library/lua/server/Items/Distributions.lua , https://github.com/PZ-Umbrella/Umbrella/blob/58204fc47895ba249592519cedecc7cfbaaebd60/library/lua/server/Items/ProceduralDistributions.lua and https://github.com/PZ-Umbrella/Umbrella/blob/58204fc47895ba249592519cedecc7cfbaaebd60/library/lua/server/Items/SuburbsDistributions.lua Accessed 2026-10-07.
- [19] PZ-Umbrella — Umbrella 41.78.16 (commit fa2e7e19), the same three distribution stubs. https://github.com/PZ-Umbrella/Umbrella/blob/fa2e7e19799740b57902f1cb4e989225c295c05e/library/Lua/server/Items/Distributions.lua , https://github.com/PZ-Umbrella/Umbrella/blob/fa2e7e19799740b57902f1cb4e989225c295c05e/library/Lua/server/Items/ProceduralDistributions.lua and https://github.com/PZ-Umbrella/Umbrella/blob/fa2e7e19799740b57902f1cb4e989225c295c05e/library/Lua/server/Items/SuburbsDistributions.lua Accessed 2026-10-07.
- [20] PZ-Umbrella — Umbrella 42.20.0 events.lua. https://github.com/PZ-Umbrella/Umbrella/blob/58204fc47895ba249592519cedecc7cfbaaebd60/library/events.lua Accessed 2026-10-07.
- [21] PZ-Umbrella — Umbrella 41.78.16 Events.lua. https://github.com/PZ-Umbrella/Umbrella/blob/fa2e7e19799740b57902f1cb4e989225c295c05e/library/Events/Events.lua Accessed 2026-10-07.
- [22] PZ-Umbrella — Umbrella 42.20.0 ItemTag.lua. https://github.com/PZ-Umbrella/Umbrella/blob/58204fc47895ba249592519cedecc7cfbaaebd60/library/java/zombie/scripting/objects/ItemTag.lua Accessed 2026-10-07.
- [23] PZ-Umbrella — Umbrella 42.20.0 CraftRecipe.lua. https://github.com/PZ-Umbrella/Umbrella/blob/58204fc47895ba249592519cedecc7cfbaaebd60/library/java/zombie/scripting/entity/components/crafting/CraftRecipe.lua Accessed 2026-10-07.
- [24] PZ-Umbrella — Umbrella 41.78.16 Recipe.lua. https://github.com/PZ-Umbrella/Umbrella/blob/fa2e7e19799740b57902f1cb4e989225c295c05e/library/Candle/zombie.scripting.objects/Recipe.lua Accessed 2026-10-07.
- [25] PZ-Umbrella — Umbrella 42.20.0 Recipe.lua. https://github.com/PZ-Umbrella/Umbrella/blob/58204fc47895ba249592519cedecc7cfbaaebd60/library/java/zombie/scripting/objects/Recipe.lua Accessed 2026-10-07.
- [26] PZ-Wiki-Modding — pz-scripts-data (the data repository ScriptsDocs is generated from). https://github.com/PZ-Wiki-Modding/pz-scripts-data Accessed 2026-10-07.
- [28] The Indie Stone Forums — Modding Migration Guide (42.13), first post by moderator nasKo, 2025-12-11, with attachments "Migration Guide.pdf" and "testmod_registries.zip" (attachments need a forum sign-in; read from the user-downloaded copies). https://theindiestone.com/forums/topic/88499-modding-migration-guide-4213/ Retrieved 2026-10-07 (host bot-blocks checkers).
- [29] The Indie Stone — 42.20.1 STABLE Hotfix Released (Steam announcement, 2026-08-05). https://steamcommunity.com/games/108600/announcements/detail/1840310314338766 Accessed 2026-10-07.
- [30] The Indie Stone — 42.20.2 STABLE Hotfix Released (Steam announcement, 2026-08-05). https://steamcommunity.com/games/108600/announcements/detail/1840310314339441 Accessed 2026-10-07.
- [31] The Indie Stone Forums — 42.21 Patch Notes, topic 101693, first post by Rockjaw, 2026-09-23 (list abridged to "selected" items for its long fix lists). https://theindiestone.com/forums/topic/101693-4221-patch-notes/ Accessed 2026-10-07 (host bot-blocks automated checkers).
- [32] PZ-Umbrella — Umbrella 42.21.0 (commit 13d01f9e), Distributions.lua, ProceduralDistributions.lua, SuburbsDistributions.lua. https://github.com/PZ-Umbrella/Umbrella/blob/13d01f9ee58fa48773553920db56d06f0005e7f8/library/lua/server/Items/Distributions.lua , https://github.com/PZ-Umbrella/Umbrella/blob/13d01f9ee58fa48773553920db56d06f0005e7f8/library/lua/server/Items/ProceduralDistributions.lua and https://github.com/PZ-Umbrella/Umbrella/blob/13d01f9ee58fa48773553920db56d06f0005e7f8/library/lua/server/Items/SuburbsDistributions.lua Accessed 2026-10-07.
- [33] PZ-Umbrella — Umbrella 42.21.0 events.lua. https://github.com/PZ-Umbrella/Umbrella/blob/13d01f9ee58fa48773553920db56d06f0005e7f8/library/events.lua Accessed 2026-10-07.
- [34] PZ-Umbrella — Umbrella 42.21.0 ItemTag.lua. https://github.com/PZ-Umbrella/Umbrella/blob/13d01f9ee58fa48773553920db56d06f0005e7f8/library/java/zombie/scripting/objects/ItemTag.lua Accessed 2026-10-07.
- [35] PZ-Umbrella — Umbrella 42.21.0 Recipe.lua. https://github.com/PZ-Umbrella/Umbrella/blob/13d01f9ee58fa48773553920db56d06f0005e7f8/library/java/zombie/scripting/objects/Recipe.lua Accessed 2026-10-07.
- [36] The Indie Stone — Re-population of the Dead: Build 42.21 Unstable Released (Steam announcement, 2026-09-23). https://steamcommunity.com/games/108600/announcements/detail/1844751498218925 Accessed 2026-10-07.
Fact-Only Sources (no prose reuse) — pzwiki (CC BY-NC-SA 3.0): cite URL + revision id; facts only, never prose.
- [27] PZwiki — Scripts (revision 1442815, page version 42.17.0). https://pzwiki.net/wiki/Scripts Accessed 2026-10-07. Fact-only source.
Secondary & Corroborating — none used.
Community & Creator — none used; see quarantined claims.
Further Reading
Further Reading¶
- The CraftRecipe class stub, for the Java side of the recipe model (see [23]): https://github.com/PZ-Umbrella/Umbrella/blob/58204fc47895ba249592519cedecc7cfbaaebd60/library/java/zombie/scripting/entity/components/crafting/CraftRecipe.lua
- Room distribution reference tables: https://pz-wiki-modding.github.io/PZ-API-Docs/mapping/rooms_distributions.html
Related Documents¶
modders-foundation— parent overview: mod layout,mod.info, script file introduction.modders-lua-api-surface— the Lua API behind recipe callbacks and tags.modders-events-callbacks— event semantics for the distribution events.modders-modinfo-modid-conventions— Mod ID and naming hygiene.modders-first-mod-tutorial-b42— end-to-end B42 mod using these blocks.modders-porting-b41-to-b42— porting checklist, including recipes.players-crafting-chains— player-side facts of the crafting overhaul.admins-workshop-mod-wiring— server-side mod deployment.meta-style-guide— how documents in this knowledge base are written.
Revision History¶
| Version | Date | Author | Change | Approved By |
|---|---|---|---|---|
| 0.1.0 | 2026-10-07 | KB Pipeline (virtual agent) | Initial draft. | — |
| 0.2.0 | 2026-10-07 | KB Pipeline (virtual agent) | Added the 42.13+ registry system from the official migration guide; resolved the ItemType and tag-registration open questions. | — |
| 0.3.0 | 2026-10-07 | KB Pipeline (virtual agent) | Re-baselined 42.20 to 42.21: re-checked against Umbrella 42.21.0 stubs (distribution and ItemTag stubs unchanged; Recipe name loses six members) and the 42.20.1 to 42.21 notes (%% translations, .json writes, localization update, missing-translation/recipe exception, loader re-enable). Sources: Steam posts [29] [30] [36] [2] [5], forum notes [31], Umbrella 42.21.0 [32] [33] [34] [35]. |
— |
| 1.0.0 | 2026-10-08 | Orchestrator (KB Pipeline) | Approved and frozen — release kb-release-2026.10.08 (42.21 re-baseline; validated against 42.21 and 41.78.21, Umbrella 42.21.0 @ 13d01f9). Content is the reviewed 0.3.0 text. | Project owner (user instruction 2026-10-08) |