Minecraft Wiki
Advertisement
[Ver | Editar | Purgar]DocumentaciónVer código ↴
Véase también: Chest loot

Maintenance

The data for Java release versions is current as of 1.15.2. 23:21, 15 April 2020 (UTC)
The data for Java snapshots is current as of 20w17a. 15:38, 22 April 2020 (UTC)
The data for Bedrock release versions is current as of 1.14.60. 04:02, 19 April 2020 (UTC)
The data for Bedrock beta versions is current as of beta 1.16.0.57. 04:02, 19 April 2020 (UTC)

.base usage (Template:LootChest)

Generates a table of the contents of the designated chests, with columns corresponding to various statistics about the availability of those items.

Invoking

It takes any number of chest parameters, and any number of column parameters, in no particular order.

If no chest parameters are listed, it displays them all; likewise for column parameters.

{{#invoke:LootChest|base
 [ |<chestParam1> ... |<chestParamN> ]
 [ |<columnHideParam1> ... |<columnHideParamN> ]
}}

Chest parameters

bonus,
desert-temple ( desert ),
dungeon,
end-city,
igloo,
jungle-temple ( jungle ),
jungle-temple-dispenser,
mineshaft,
nether-fortress ( nether, fortress ),
stronghold-altar ( altar ),
stronghold-library ( library ),
stronghold-storeroom ( storeroom ),
village-blacksmith ( blacksmith, village )

Column parameters

chance: the odds of getting any of this item in a single chest.,
chests: the number of chests expected to search, to find any of this item.,
items: the number of items expected per chest, averaged over a large number of chests.,
stacksize: the size of stacks (or for unstackable items, number) of this item found in this chest.,
weight: the weight of this item relative to other items in the chest.

Example

{{#invoke:LootChest|base}} → all chests and all columns

{{#invoke:LootChest|base|weaponsmith|jungle|bonus|chance|stacksize}} → only weaponsmith and jungle chests, and only 'stacksize' and 'chance' columns

.base2 usage (Template:LootChestItem inline)

Prints a summary of this item's availability in the various worldgen chests.

Invoking

It takes exactly one item name as a parameter.

{{#invoke:LootChest|base2|<itemParam>}}

Item parameters

acacia-wood, acacia-wood-only, activator-rail, apple, arrow, beetroot-seeds, bone, book, bread, bucket, coal, compass, detector-rail, diamond, disc-13, disc-cat, emerald, empty, empty-map, enchanted-book, enchanted-book-rnd, enchanted-diamond-boots, enchanted-diamond-chestplate, enchanted-diamond-helmet, enchanted-diamond-leggings, enchanted-diamond-pickaxe, enchanted-diamond-shovel, enchanted-diamond-sword, enchanted-iron-boots, enchanted-iron-chestplate, enchanted-iron-helmet, enchanted-iron-leggings, enchanted-iron-pickaxe, enchanted-iron-shovel, enchanted-iron-sword, ender-pearl, flint-and-steel, gold-ingot, gold-nugget, golden-apple, golden-chestplate, golden-sword, gunpowder, horse-armor-diamond, horse-armor-gold, horse-armor-iron, iron-boots, iron-chestplate, iron-helmet, iron-ingot, iron-leggings, iron-pickaxe, iron-sword, lapis-lazuli, melon-seeds, name-tag, nether-wart, notch-apple, oak-sapling, oak-wood, oak-wood-only, obsidian, paper, powered-rail, pumpkin-seeds, rail, raw-salmon, redstone, rotten-flesh, saddle, sand, spider-eye, stick, stone-axe, stone-pickaxe, string, torch, wheat, wood-planks, wooden-axe, wooden-pickaxe

Example

{{#invoke:LootChest|base2|iron-ingot}}

Iron ingots can be found in 18.8% of dungeon chests in stacks of 1–4; in 23.4% of stronghold altar chests, 19.2% of nether fortress chests, 18.2% of desert temple chests, 46.1% of village blacksmith chests, 32.0% of chest minecarts in abandoned mine shafts, 44.5% of jungle temple chests, and 35.6% of stronghold storeroom chests, all in stacks of 1–5; and in 39.4% of End city chests in stacks of 4–8.

{{#invoke:LootChest|base2|esmeralda}}

unknown item "esmeralda"

.base3 usage (Template:LootChestItem table)

Prints a summary of this item's availability in the various worldgen chests in the form of a table.

Invoking

It takes exactly one item name as a parameter.

{{#invoke:LootChest|base3|<itemParam>}}

Item parameters

Same as above

Example

{{#invoke:LootChest|base3|esmeralda}}Error en la secuencia de órdenes: la función «base3» no existe.

Source

  • The data is set up within p so that it can be pulled directly from (or compared directly to) the minecraft loot table files.
  • stack size given here (and given in code) can be larger than the stackable size of the item, prominently in the case of enchanted books. However this fact does not affect the calculated values. This is because the game puts the right number of items, but unstacked rather than stacked.

Data structure

  • p.items
'<item-id>' = {
This key must match a sprite name for the items/blocks defined in Module:BlockSprite or Module:ItemSprite, unless id is included in the item definition.
'<sprite-type>'
Either item or block.
[, id='<sprite-id>']
Use this to specify a sprite defined in Module:BlockSprite or Module:ItemSprite. Otherwise it uses the sprite with the name given by item-id.
[, link='<item-link>']
A link to a page that is different from the sprite-id name. Used in Template:LootChest.
[, title='<item-text>']
A name for an item that is different from the sprite-id name.
[, cannot_stack=false]
Use this to indicate that the item comes in groups rather than in stacks. Used in Template:LootChestItem.
[, plural=(false|'<custom-plural-word>')]
Use false when a word has no plural, like 'Nether Wart'. Use a custom plural word when you cannot simply append an 's' to the base word to make it plural, like 'Bottles o' Enchanting'. Used in Template:LootChestItem.
[, preserve_case=false]
Use false when an item name should follow the capitalization exactly specified in title, and not follow sentence case, like 'TNT'.
[, note='<note-name>']
Indicates that a note appears next to this item in the table. (notes are defined directly below the item list)
}
  • p.notes
'<note-name>' = '<note-full-text>'
  • p.chests[n].poolsJava[n]
  • p.chests[n].poolsJavaUpcoming[n]
  • p.chests[n].poolsBedrock[n]
  • p.chests[n].poolsBedrockUpcoming[n]
    • rolls
{ <min-number-of-stacks>, <max-number-of-stacks> }
  • p.chests[n].poolsJava[n].items
  • p.chests[n].poolsJavaUpcoming[n].items
  • p.chests[n].poolsBedrock[n].items
  • p.chests[n].poolsBedrockUpcoming[n].items
'<item-id>' = { <min-stack-size>, <max-stack-size>, <item-weight> }
  • p.synonyms
'<chest-name-synonym>' = '<original-interally-valid-chest-name>'
Allows additional chest names to be used as parameters, in addition to the ones defined in p.chests.
  • p.display_names
'<chest-name-given-via-parameter>' = '<name-displayed-in-single-chest-table>'
If a single chest parameter is used, this defines the name it is called in the summary text above the table.
  • p.columns
'<column-name>' = '<column-full-description>'
The column descriptions, found either in the tooltip on the column header, or in the summary text above the table.

Functions

The following functions are made available at the top of the file, for ease of inspection.

  • calc_average_amount_this_item_per_chest
average number of a certain item (not number of stacks), per-chest (not per-structure).
  • calc_chance_any_of_this_item_per_chest
chance that at least one of a certain item is present, per-chest (not per-structure).

Item tests

{{#invoke:LootChest|base2_test}}



Acacia or dark oak wood can be found in 68.4% of bonus chests in stacks of 1–3.

Activator rails can be found in 27.1% of chest minecarts in abandoned mine shafts in stacks of 1–4.

Apples can be found in 33.7% of stronghold altar chests, 61.6% of village blacksmith chests, 74.3% of igloo chests, and 50.0% of stronghold storeroom chests, all in stacks of 1–3; and in 83.8% of bonus chests in stacks of 1–2.

Arrows can be found in all dispensers in jungle temples in stacks of 2–7.

Beetroot seeds can be found in 21.5% of End city chests in stacks of 1–10, and in 18.8% of dungeon chests and 32.0% of chest minecarts in abandoned mine shafts in stacks of 2–4.

Bones can be found in 29.0% of desert temple chests and 72.2% of jungle temple chests in stacks of 4–6, and in 59.0% of desert temple chests and 57.8% of dungeon chests in stacks of 1–8.

Books can be found in 94.6% of stronghold library chests in stacks of 1–3.

Bread can be found in 35.3% of dungeon chests in stacks of 1; in 33.7% of stronghold altar chests, 61.6% of village blacksmith chests, 45.0% of chest minecarts in abandoned mine shafts, and 50.0% of stronghold storeroom chests, all in stacks of 1–3; and in 61.5% of bonus chests in stacks of 1–2.

Buckets can be found in 18.8% of dungeon chests in stacks of 1.

Coal can be found in 27.4% of dungeon chests and 74.3% of igloo chests in stacks of 1–4, and in 32.0% of chest minecarts in abandoned mine shafts and 35.6% of stronghold storeroom chests in stacks of 3–8.

Compasses can be found in 11.0% of stronghold library chests in stacks of 1.

Detector rails can be found in 27.1% of chest minecarts in abandoned mine shafts in stacks of 1–4.

Diamond horse armor can be found in 2.5% of stronghold altar chests, 11.8% of nether fortress chests, 6.3% of desert temple chests, 5.7% of village blacksmith chests, 7.7% of dungeon chests, 4.6% of End city chests, and 5.4% of jungle temple chests, all in groups of 1.

Diamonds can be found in 7.4% of stronghold altar chests, 19.2% of nether fortress chests, 6.3% of desert temple chests, 16.3% of village blacksmith chests, and 15.5% of jungle temple chests, all in stacks of 1–3; in 10.5% of chest minecarts in abandoned mine shafts in stacks of 1–2; and in 21.5% of End city chests in stacks of 2–7.

Emeralds can be found in 7.7% of igloo chests in stacks of 1, in 18.2% of desert temple chests and 10.5% of jungle temple chests in stacks of 1–3, and in 9.1% of End city chests in stacks of 2–6.

Empty maps can be found in 11.0% of stronghold library chests in stacks of 1.

Enchanted books can be found in 2.5% of stronghold altar chests, 72.2% of stronghold library chests, 5.4% of jungle temple chests, and 4.0% of stronghold storeroom chests, all in groups of 1.

Enchanted books can be found in 23.7% of desert temple chests, 15.1% of dungeon chests, and 14.1% of chest minecarts in abandoned mine shafts, all in groups of 1.

Enchanted diamond boots can be found in 13.4% of End city chests in groups of 1.

Enchanted diamond chestplates can be found in 13.4% of End city chests in groups of 1.

Enchanted diamond helmets can be found in 13.4% of End city chests in groups of 1.

Enchanted diamond leggings can be found in 13.4% of End city chests in groups of 1.

Enchanted diamond pickaxes can be found in 13.4% of End city chests in groups of 1.

Enchanted diamond shovels can be found in 13.4% of End city chests in groups of 1.

Enchanted diamond swords can be found in 13.4% of End city chests in groups of 1.

Enchanted iron boots can be found in 13.4% of End city chests in groups of 1.

Enchanted iron chestplates can be found in 13.4% of End city chests in groups of 1.

Enchanted iron helmets can be found in 13.4% of End city chests in groups of 1.

Enchanted iron leggings can be found in 13.4% of End city chests in groups of 1.

Enchanted iron pickaxes can be found in 13.4% of End city chests in groups of 1.

Enchanted iron shovels can be found in 13.4% of End city chests in groups of 1.

Enchanted iron swords can be found in 13.4% of End city chests in groups of 1.

Ender pearls can be found in 23.4% of stronghold altar chests in stacks of 1.

Flint and steel can be found in 19.2% of nether fortress chests in groups of 1.

Gold horse armor can be found in 2.5% of stronghold altar chests, 29.4% of nether fortress chests, 12.4% of desert temple chests, 5.7% of village blacksmith chests, 15.1% of dungeon chests, 4.6% of End city chests, and 5.4% of jungle temple chests, all in groups of 1.

Gold ingots can be found in 12.2% of stronghold altar chests, 49.8% of nether fortress chests, 26.0% of village blacksmith chests, 17.0% of chest minecarts in abandoned mine shafts, and 19.0% of stronghold storeroom chests, all in stacks of 1–3; in 18.2% of desert temple chests, 54.0% of End city chests, and 60.2% of jungle temple chests, all in stacks of 2–7; and in 9.7% of dungeon chests in stacks of 1–4.

Gold nuggets can be found in 57.9% of igloo chests in stacks of 1–3.

Golden apples (enchanted) can be found in 2.6% of desert temple chests, 3.1% of dungeon chests, and 1.4% of chest minecarts in abandoned mine shafts, all in stacks of 1.

Golden apples (normal) can be found in 2.5% of stronghold altar chests, 23.7% of desert temple chests, 22.2% of dungeon chests, 28.2% of chest minecarts in abandoned mine shafts, and all igloo chests, all in stacks of 1.

Golden chestplates can be found in 19.2% of nether fortress chests in groups of 1.

Golden swords can be found in 19.2% of nether fortress chests in groups of 1.

Gunpowder can be found in 59.0% of desert temple chests and 57.8% of dungeon chests in stacks of 1–8.

Iron boots can be found in 12.2% of stronghold altar chests and 26.0% of village blacksmith chests in groups of 1.

Iron chestplates can be found in 12.2% of stronghold altar chests and 26.0% of village blacksmith chests in groups of 1.

Iron helmets can be found in 12.2% of stronghold altar chests and 26.0% of village blacksmith chests in groups of 1.

Iron horse armor can be found in 2.5% of stronghold altar chests, 19.2% of nether fortress chests, 18.2% of desert temple chests, 5.7% of village blacksmith chests, 22.2% of dungeon chests, 4.6% of End city chests, and 5.4% of jungle temple chests, all in groups of 1.

Iron ingots can be found in 18.8% of dungeon chests in stacks of 1–4; in 23.4% of stronghold altar chests, 19.2% of nether fortress chests, 18.2% of desert temple chests, 46.1% of village blacksmith chests, 32.0% of chest minecarts in abandoned mine shafts, 44.5% of jungle temple chests, and 35.6% of stronghold storeroom chests, all in stacks of 1–5; and in 39.4% of End city chests in stacks of 4–8.

Iron leggings can be found in 12.2% of stronghold altar chests and 26.0% of village blacksmith chests in groups of 1.

Iron pickaxes can be found in 12.2% of stronghold altar chests, 26.0% of village blacksmith chests, 7.0% of chest minecarts in abandoned mine shafts, and 4.0% of stronghold storeroom chests, all in groups of 1.

Iron swords can be found in 12.2% of stronghold altar chests and 26.0% of village blacksmith chests in groups of 1.

Lapis lazuli can be found in 17.0% of chest minecarts in abandoned mine shafts in stacks of 4–9.

Melon seeds can be found in 18.8% of dungeon chests and 32.0% of chest minecarts in abandoned mine shafts in stacks of 2–4.

Music disc (13) can be found in 22.2% of dungeon chests in groups of 1.

Music disc (cat) can be found in 22.2% of dungeon chests in groups of 1.

Name tags can be found in 29.0% of dungeon chests and 42.3% of chest minecarts in abandoned mine shafts in stacks of 1.

Nether wart can be found in 19.2% of nether fortress chests in stacks of 3–7.

Nothing can be found in 18.2% of desert temple chests and 7.0% of chest minecarts in abandoned mine shafts in stacks of 1.

Oak saplings can be found in 26.0% of village blacksmith chests in stacks of 3–7.

Oak, spruce, birch or jungle wood can be found in 68.4% of bonus chests in stacks of 1–3.

Obsidian can be found in 26.0% of village blacksmith chests in stacks of 3–7, and in 8.0% of nether fortress chests in stacks of 2–4.

Paper can be found in 94.6% of stronghold library chests in stacks of 2–7.

Powered rails can be found in 27.1% of chest minecarts in abandoned mine shafts in stacks of 1–4.

Pumpkin seeds can be found in 18.8% of dungeon chests and 32.0% of chest minecarts in abandoned mine shafts in stacks of 2–4.

Rails can be found in 78.4% of chest minecarts in abandoned mine shafts in stacks of 4–8.

Raw salmon can be found in 61.5% of bonus chests in stacks of 1–2.

Redstone can be found in 27.4% of dungeon chests in stacks of 1–4, and in 12.2% of stronghold altar chests, 17.0% of chest minecarts in abandoned mine shafts, and 19.0% of stronghold storeroom chests, all in stacks of 4–9.

Rotten flesh can be found in 57.9% of igloo chests in stacks of 1, in 29.0% of desert temple chests and 62.8% of jungle temple chests in stacks of 3–7, and in 59.0% of desert temple chests and 57.8% of dungeon chests in stacks of 1–8.

Saddles can be found in 2.5% of stronghold altar chests, 35.7% of nether fortress chests, 23.7% of desert temple chests, 16.3% of village blacksmith chests, 29.0% of dungeon chests, 13.4% of End city chests, and 15.5% of jungle temple chests, all in groups of 1.

Sand can be found in 59.0% of desert temple chests in stacks of 1–8.

Spider eyes can be found in 29.0% of desert temple chests in stacks of 1–3.

Sticks can be found in 68.4% of bonus chests in stacks of 1–12.

Stone axes can be found in 14.9% of igloo chests and 25.0% of bonus chests in groups of 1.

Stone pickaxes can be found in 25.0% of bonus chests in groups of 1.

String can be found in 59.0% of desert temple chests and 57.8% of dungeon chests in stacks of 1–8.

Torches can be found in 65.7% of chest minecarts in abandoned mine shafts in stacks of 1–16.

Wheat can be found in 35.3% of dungeon chests in stacks of 1–4, and in 57.9% of igloo chests in stacks of 2–3.

Wood planks can be found in 68.4% of bonus chests in stacks of 1–12.

Wooden axes can be found in 75.0% of bonus chests in groups of 1.

Wooden pickaxes can be found in 75.0% of bonus chests in groups of 1.


Notes

[Ver | Editar | Purgar]La documentación arriba es transcluída desde Módulo:LootChest/doc.
local p = {

	calc_average_amount_this_item_per_pool = function( 
			min_stacksize, max_stacksize,
			min_pool_rolls, max_pool_rolls, 
			item_weight, pool_total_item_weight )

		local avg_stacksize = ( min_stacksize + max_stacksize ) / 2
		local avg_rolls = ( min_pool_rolls + max_pool_rolls ) / 2
		
		return avg_stacksize * avg_rolls * item_weight / pool_total_item_weight
		
	end,
	
	calc_chance_any_of_this_item_per_pool = function( 
			min_pool_rolls, max_pool_rolls,
			item_weight, pool_total_item_weight )

		local avg_rolls = ( min_pool_rolls + max_pool_rolls ) / 2
		local relativeweight = item_weight / pool_total_item_weight
		
		return 1 - math.pow( 1 - relativeweight, avg_rolls )
		
	end,
	
	dev = 'In 1.10 ',
	
	-- these define which sprite, label and link to use, in the table,
	-- and 'cannot_stack' and 'plural' dictate how to display the single-item summary
	
	-- NOTE: order in this list doesn't matter.

	items = {
		["acacia-wood"]         = { "block", link="Wood", title="Acacia or Dark Oak Wood", plural=false },
		["acacia-wood-only"]    = { "block", id='acacia-wood', link="Wood", title="Acacia Wood", plural=false },
		["activator-rail"]      = { "block", title="Activator Rails", plural=false },
		["apple"]               = { "item" },
		["arrow"]               = { "item" },
		["beetroot-seeds"]      = { "item", link="Beetroot Seeds", plural=false },
		["bone"]                = { "item" },
		["book"]                = { "item" },
		["bread"]               = { "item", plural=false },
		["bucket"]              = { "item" },
		["coal"]                = { "item", plural=false },
		["compass"]             = { "item" },
		["detector-rail"]       = { "block", title="Detector Rails", plural=false },
		["diamond"]             = { "item" },
		["disc-13"]             = { "item", title="Music Disc (13)", link="Music Disc", cannot_stack=true, plural=false },
		["disc-cat"]            = { "item", title="Music Disc (Cat)", link="Music Disc", cannot_stack=true, plural=false },
		["emerald"]             = { "item" },
		["empty-map"]           = { "item", link="Map", title="Empty Map" },
		["enchanted-book"]      = { "item", cannot_stack=true, note="level-book" },
		["enchanted-book-rnd"]  = { "item", id='enchanted-book', title="Enchanted Book", link="Enchanted Book", cannot_stack=true, note="random-book" },
		["ender-pearl"]         = { "item" },
		["flint-and-steel"]     = { "item", cannot_stack=true, plural=false },
		["golden-apple"]        = { "item", title="Golden Apple (Normal)", plural="Golden Apples (Normal)" },
		["golden-chestplate"]   = { "item", link="Armor", cannot_stack=true },
		["golden-sword"]        = { "item", link="Sword", cannot_stack=true },
		["gold-ingot"]          = { "item" },
		["gold-nugget"]         = { "item" },
		["gunpowder"]           = { "item", plural=false },
		["horse-armor-diamond"] = { "item", title="Diamond Horse Armor", link="Horse Armor", cannot_stack=true, plural=false },
		["horse-armor-gold"]    = { "item", title="Gold Horse Armor", link="Horse Armor", cannot_stack=true, plural=false },
		["horse-armor-iron"]    = { "item", title="Iron Horse Armor", link="Horse Armor", cannot_stack=true, plural=false },
		["iron-boots"]          = { "item", link="Armor", cannot_stack=true, plural=false },
		["iron-chestplate"]     = { "item", link="Armor", cannot_stack=true },
		["iron-helmet"]         = { "item", link="Armor", cannot_stack=true },
		["iron-ingot"]          = { "item" },
		["iron-leggings"]       = { "item", link="Armor", cannot_stack=true, plural=false },
		["iron-pickaxe"]        = { "item", link="Pickaxe", cannot_stack=true },
		["iron-sword"]          = { "item", link="Sword", cannot_stack=true },
		["lapis-lazuli"]        = { "item", plural=false },
		["melon-seeds"]         = { "item", plural=false },
		["name-tag"]            = { "item" },
		["notch-apple"]         = { "item", id='golden-apple', link="Golden Apple", title="Golden Apple (Enchanted)", plural="Golden Apples (Enchanted)" },
		["nether-wart"]         = { "item", plural=false },
		["oak-sapling"]         = { "block", link="Sapling" },
		["oak-wood"]            = { "block", link="Wood", title="Oak, Spruce, Birch or Jungle Wood", plural=false },
		["oak-wood-only"]       = { "block", id='oak-wood', link="Wood", title="Oak Wood", plural=false },
		["obsidian"]            = { "block", plural=false },
		["paper"]               = { "item", plural=false },
		["powered-rail"]        = { "block", title="Powered Rails", plural=false },
		["pumpkin-seeds"]       = { "item", plural=false },
		["rail"]                = { "block", title="Rails", plural=false },
		["redstone"]            = { "item", plural=false },
		["rotten-flesh"]        = { "item", plural=false },
		["sand"]                = { "block", plural=false },
		["saddle"]              = { "item", cannot_stack=true },
		["raw-salmon"]          = { "item", plural=false },
		["spider-eye"]          = { "item" },
		["stick"]               = { "item" },
		["stone-axe"]           = { "item", link="Axe", cannot_stack=true },
		["stone-pickaxe"]       = { "item", link="Pickaxe", cannot_stack=true },
		["string"]              = { "item", plural=false },
		["torch"]               = { "block" },
		["wheat"]               = { "item", plural=false },
		["wood-planks"]         = { "block", plural=false },
		["wooden-axe"]          = { "item", link="Axe", cannot_stack=true },
		["wooden-pickaxe"]      = { "item", link="Pickaxe", cannot_stack=true },

		["enchanted-diamond-boots"]      = { "item", id="diamond-boots", link="Diamond Boots", note="end-ench-equipment", cannot_stack=true, plural=false },
		["enchanted-diamond-chestplate"] = { "item", id="diamond-chestplate", link="Diamond Chestplate", note="end-ench-equipment", cannot_stack=true },
		["enchanted-diamond-helmet"]     = { "item", id="diamond-helmet", link="Diamond Helmet", note="end-ench-equipment", cannot_stack=true },
		["enchanted-diamond-leggings"]   = { "item", id="diamond-leggings", link="Diamond Leggings", note="end-ench-equipment", cannot_stack=true, plural=false },
		["enchanted-diamond-pickaxe"]    = { "item", id="diamond-pickaxe", link="Diamond Pickaxe", note="end-ench-equipment", cannot_stack=true },
		["enchanted-diamond-shovel"]     = { "item", id="diamond-shovel", link="Diamond Shovel", note="end-ench-equipment", cannot_stack=true },
		["enchanted-diamond-sword"]      = { "item", id="diamond-sword", link="Diamond Sword", note="end-ench-equipment", cannot_stack=true },
		["enchanted-iron-boots"]         = { "item", id="iron-boots", link="Iron Boots", note="end-ench-equipment", cannot_stack=true, plural=false },
		["enchanted-iron-chestplate"]    = { "item", id="iron-chestplate", link="Iron Chestplate", note="end-ench-equipment", cannot_stack=true },
		["enchanted-iron-helmet"]        = { "item", id="iron-helmet", link="Iron Helmet", note="end-ench-equipment", cannot_stack=true },
		["enchanted-iron-leggings"]      = { "item", id="iron-leggings", link="Iron Leggings", note="end-ench-equipment", cannot_stack=true, plural=false },
		["enchanted-iron-pickaxe"]       = { "item", id="iron-pickaxe", link="Iron Pickaxe", note="end-ench-equipment", cannot_stack=true },
		["enchanted-iron-shovel"]        = { "item", id="iron-shovel", link="Iron Shovel", note="end-ench-equipment", cannot_stack=true },
		["enchanted-iron-sword"]         = { "item", id="iron-sword", link="Iron Sword", note="end-ench-equipment", cannot_stack=true },

		["empty"]                        = { "block", id="air", link='', title='Nothing', plural=false, note="nothing" },
	},

	notes = {
		["level-book"] = "<ref group='note' name='level-book'>Enchantment probabilities are the same as a level-30 enchantment on an [[enchantment table]], but the chance of multiple enchantments is not reduced.</ref>",
		["end-ench-equipment"] = "<ref group='note' name='end-city-enchantment'>Enchanted items of the same type in the same chest will have the same enchantments. Enchantment probabilities are the same as a level-20 to level-39 <!-- Yes, really 39 even though the table normally only goes to 30  --> enchantment on an [[enchantment table]].</ref>",
		["random-book"] = "<ref group='note' name='random-book'>All enchantments are equally probable, and any level of the enchantment is equally probable.</ref>",
		["nothing"] = "<ref group='note' name='nothing'>'Nothing' does not refer to the chance of an empty chest.  Instead, it refers to the chance that the random loot generator will not add any loot ''on a single roll''.</ref>",
	},
	
	-- NOTE: order here doesn't matter.  
	--		 * in the table, chests will sort in alphabetical order
	--       * in the table, items will sort by chance, then by avg#, then alphabetically.
	--       * If poolsDev is omitted, pools will be used. To omit a pool entirely in the dev version, set poolsDev = {}.
	
	chests = {
		["village-blacksmith"] = { -- village_blacksmith.json
			header = "[[Village]]",
			link   = "[[village]] blacksmith",
			pools = {
				{
					rolls = {3,8},
					items = {
						["diamond"]             = {1,3,3},
						["iron-ingot"]          = {1,5,10},
						["gold-ingot"]          = {1,3,5},
						["bread"]               = {1,3,15},
						["apple"]               = {1,3,15},
						["iron-pickaxe"]        = {1,1,5},
						["iron-sword"]          = {1,1,5},
						["iron-chestplate"]     = {1,1,5},
						["iron-helmet"]         = {1,1,5},
						["iron-leggings"]       = {1,1,5},
						["iron-boots"]          = {1,1,5},
						["obsidian"]            = {3,7,5},
						["oak-sapling"]         = {3,7,5},
						["horse-armor-iron"]    = {1,1,1},
						["horse-armor-gold"]    = {1,1,1},
						["horse-armor-diamond"] = {1,1,1},
						["saddle"]              = {1,1,3}
					}
				},
			},
			poolsDev = {}
		},
		["stronghold-altar"] = { -- stronghold_corridor.json
			header      = "Altar",
			superheader = "[[Stronghold]]",
			link        = "[[stronghold]] altar",
			pools = {
				{
					rolls = {2,3},
					items = {
						["ender-pearl"]         = {1,1,10},
						["diamond"]             = {1,3,3},
						["iron-ingot"]          = {1,5,10},
						["gold-ingot"]          = {1,3,5},
						["redstone"]            = {4,9,5},
						["bread"]               = {1,3,15},
						["apple"]               = {1,3,15},
						["iron-pickaxe"]        = {1,1,5},
						["iron-sword"]          = {1,1,5},
						["iron-chestplate"]     = {1,1,5},
						["iron-helmet"]         = {1,1,5},
						["iron-leggings"]       = {1,1,5},
						["iron-boots"]          = {1,1,5},
						["golden-apple"]        = {1,1,1},
						["saddle"]              = {1,1,1},
						["horse-armor-iron"]    = {1,1,1},
						["horse-armor-gold"]    = {1,1,1},
						["horse-armor-diamond"] = {1,1,1},
						["enchanted-book"]      = {1,1,1},
					}
				},
			},
			poolsDev = {}
		},
		["stronghold-library"] = { -- stronghold_library.json
			header      = "Library",
			superheader = "[[Stronghold]]",
			link        = "[[stronghold]] library",
			pools = {
				{
					rolls = {2,10},
					items = {
						["book"]                = {1,3,20},
						["paper"]               = {2,7,20},
						["empty-map"]           = {1,1,1},
						["compass"]             = {1,1,1},
						["enchanted-book"]      = {1,1,10},
					}
				},
			},
			poolsDev = {}
		},
		["stronghold-storeroom"] = { -- stronghold_crossing.json
			header      = "Storeroom",
			superheader = "[[Stronghold]]",
			link        = "[[stronghold]] storeroom",
			pools = {
				{
					rolls = {1,4},
					items = {
						["iron-ingot"]          = {1,5,10},
						["gold-ingot"]          = {1,3,5},
						["redstone"]            = {4,9,5},
						["coal"]                = {3,8,10},
						["bread"]               = {1,3,15},
						["apple"]               = {1,3,15},
						["iron-pickaxe"]        = {1,1,1},
						["enchanted-book"]      = {1,1,1},
					}
				},
			},
			poolsDev = {}
		},
		["bonus"] = { -- spawn_bonus_chest.json
			header = "[[Chest#Bonus chest|Bonus]]",
			link   = "[[Chest#Bonus chest|bonus]]",
			pools = {
				{
					rolls = {1,1},
					items = {
						["stone-axe"]           = {1,1,1},
						["wooden-axe"]          = {1,1,3},
					}
				},
				{
					rolls = {1,1},
					items = {
						["stone-pickaxe"]       = {1,1,1},
						["wooden-pickaxe"]      = {1,1,3}
					}
				},
				{
					rolls = {3,3},
					items = {
						["apple"]               = {1,2,5},
						["bread"]               = {1,2,3},
						["raw-salmon"]          = {1,2,3},
					}
				},
				{
					rolls = {4,4},
					items = {
						["stick"]               = {1,12,10},
						["wood-planks"]         = {1,12,10},
						["oak-wood"]            = {1,3,10},
						["acacia-wood"]         = {1,3,10},
					}
				},
			},
			poolsDev = {}
		},
		["dungeon"] = { -- simple_dungeon.json
			header = "[[Dungeon]]",
			link   = "[[dungeon]]",
			pools = {
				{
					rolls = {1,3},
					items = {
						["saddle"]              = {1,1,20},
						["golden-apple"]        = {1,1,15},
						["notch-apple"]         = {1,1,2},
						["disc-13"]             = {1,1,15},
						["disc-cat"]            = {1,1,15},
						["name-tag"]            = {1,1,20},
						["horse-armor-gold"]    = {1,1,10},
						["horse-armor-iron"]    = {1,1,15},
						["horse-armor-diamond"] = {1,1,5},
						["enchanted-book-rnd"]  = {1,1,10},
					}
				},
				{
					rolls = {1,4},
					items = {
						["iron-ingot"]          = {1,4,10},
						["gold-ingot"]          = {1,4,5},
						["bread"]               = {1,1,20},
						["wheat"]               = {1,4,20},
						["bucket"]              = {1,1,10},
						["redstone"]            = {1,4,15},
						["coal"]                = {1,4,15},
						["melon-seeds"]         = {2,4,10},
						["pumpkin-seeds"]       = {2,4,10},
						["beetroot-seeds"]      = {2,4,10},
					}
				},
				{
					rolls = {3,3},
					items = {
						["bone"]                = {1,8,10},
						["gunpowder"]           = {1,8,10},
						["rotten-flesh"]        = {1,8,10},
						["string"]              = {1,8,10},
					}
				},
			},
			poolsDev = {}
		},
		["mineshaft"] = { -- abandoned_mineshaft.json
			chest_type = "minecart with chest",
			header = "[[Mineshaft]]",
			link   = "[[abandoned mine shaft]]s",
			pools = {
				{
					rolls = {1,1},
					items = {
						["golden-apple"]        = {1,1,20},
						["notch-apple"]         = {1,1,1},
						["name-tag"]            = {1,1,30},
						["enchanted-book-rnd"]  = {1,1,10},
						["iron-pickaxe"]        = {1,1,5},
						["empty"]				= {1,1,5},
					}
				},
				{
					rolls = {2,4},
					items = {
						["iron-ingot"]          = {1,5,10},
						["gold-ingot"]          = {1,3,5},
						["redstone"]            = {4,9,5},
						["lapis-lazuli"]        = {4,9,5},
						["diamond"]             = {1,2,3},
						["coal"]                = {3,8,10},
						["bread"]               = {1,3,15},
						["melon-seeds"]         = {2,4,10},
						["pumpkin-seeds"]       = {2,4,10},
						["beetroot-seeds"]      = {2,4,10},
					}
				},
				{
					rolls = {3,3},
					items = {
						["rail"]                = {4,8,20},
						["powered-rail"]        = {1,4,5},
						["detector-rail"]       = {1,4,5},
						["activator-rail"]      = {1,4,5},
						["torch"]               = {1,16,15},
					}
				},
			},
			poolsDev = {}
		},
		["nether-fortress"] = { -- nether_bridge.json
			header = "[[Nether fortress|Nether]]<br>[[Nether fortress|fortress]]",
			link   = "[[nether fortress]]",
			pools = {
				{
					rolls = {2,4},
					items = {
						["diamond"]             = {1,3,5},
						["iron-ingot"]          = {1,5,5},
						["gold-ingot"]          = {1,3,15},
						["golden-sword"]        = {1,1,5},
						["golden-chestplate"]   = {1,1,5},
						["flint-and-steel"]     = {1,1,5},
						["nether-wart"]         = {3,7,5},
						["saddle"]              = {1,1,10},
						["horse-armor-gold"]    = {1,1,8},
						["horse-armor-iron"]    = {1,1,5},
						["horse-armor-diamond"] = {1,1,3},
						["obsidian"]            = {2,4,2},
					}
				},
			},
			poolsDev = {}
		},
		["desert-temple"] = { -- desert_pyramid.json
			header = "[[Desert temple]]",
			link   = "[[desert temple]]",
			pools = {
				{
					rolls = {2,4},
					items = {
						["diamond"]             = {1,3,5},
						["iron-ingot"]          = {1,5,15},
						["gold-ingot"]          = {2,7,15},
						["emerald"]             = {1,3,15},
						["bone"]                = {4,6,25},
						["spider-eye"]          = {1,3,25},
						["rotten-flesh"]        = {3,7,25},
						["saddle"]              = {1,1,20},
						["horse-armor-iron"]    = {1,1,15},
						["horse-armor-gold"]    = {1,1,10},
						["horse-armor-diamond"] = {1,1,5},
						["enchanted-book-rnd"]  = {1,1,20},
						["golden-apple"]        = {1,1,20},
						["notch-apple"]         = {1,1,2},
						["empty"]               = {1,1,15},
					}
				},
				{
					rolls = {4,4},
					items = {
						["bone"]                = {1,8,10},
						["gunpowder"]           = {1,8,10},
						["rotten-flesh"]        = {1,8,10},
						["string"]              = {1,8,10},
						["sand"]                = {1,8,10},
					}
				},
			},
			poolsDev = {}
		},
		["jungle-temple"] = { -- jungle_temple.json
			header = "[[Jungle temple]]",
			link   = "[[jungle temple]]",
			pools = {
				{
					rolls = {2,6},
					items = {
						["diamond"]             = {1,3,3},
						["iron-ingot"]          = {1,5,10},
						["gold-ingot"]          = {2,7,15},
						["emerald"]             = {1,3,2},
						["horse-armor-iron"]    = {1,1,1},
						["horse-armor-gold"]    = {1,1,1},
						["horse-armor-diamond"] = {1,1,1},
						["saddle"]              = {1,1,3},
						["enchanted-book"]      = {1,1,1},
						["bone"]                = {4,6,20},
						["rotten-flesh"]        = {3,7,16}
					}
				},
			},
			poolsDev = {}
		},
		["jungle-temple-dispenser"] = { -- jungle_temple_dispenser.json
			chest_type = "dispenser",
			link   = "[[jungle temple]]s",
			pools = {
				{
					rolls = {1,2},
					items = {
						["arrow"] = {2,7,30}
					}
				},
			},
			poolsDev = {}
		},
		["end-city"] = { -- end_city_treasure.json
			header = "[[End city]]",
			link   = "[[End city]]",
			pools = {
				{
					rolls = {2,6},
					items = {
						["diamond"]             = {2,7,5},
						["iron-ingot"]          = {4,8,10},
						["gold-ingot"]          = {2,7,15},
						["emerald"]             = {2,6,2},
						["beetroot-seeds"]      = {1,10,5},
						["saddle"]              = {1,1,3},
						["horse-armor-iron"]    = {1,1,1},
						["horse-armor-gold"]    = {1,1,1},
						["horse-armor-diamond"] = {1,1,1},
						["enchanted-diamond-sword"]      = {1,1,3},
						["enchanted-diamond-boots"]      = {1,1,3},
						["enchanted-diamond-chestplate"] = {1,1,3},
						["enchanted-diamond-leggings"]   = {1,1,3},
						["enchanted-diamond-helmet"]     = {1,1,3},
						["enchanted-diamond-pickaxe"]    = {1,1,3},
						["enchanted-diamond-shovel"]     = {1,1,3},
						["enchanted-iron-sword"]         = {1,1,3},
						["enchanted-iron-boots"]         = {1,1,3},
						["enchanted-iron-chestplate"]    = {1,1,3},
						["enchanted-iron-leggings"]      = {1,1,3},
						["enchanted-iron-helmet"]        = {1,1,3},
						["enchanted-iron-pickaxe"]       = {1,1,3},
						["enchanted-iron-shovel"]        = {1,1,3},
					}
				},
			},
			poolsDev = {}
		},
		["igloo"] = {
			header = "[[Igloo]]",
			link   = "[[igloo]]",
			pools = {
				{
					rolls = {2,8},
					items = {
						["apple"]               = {1,3,15},
						["coal"]                = {1,4,15},
						["gold-nugget"]         = {1,3,10},
						["stone-axe"]           = {1,1,2},
						["rotten-flesh"]        = {1,1,10},
						["emerald"]             = {1,1,1},
						["wheat"]               = {2,3,10}
					}
				},
				{
					rolls = {1,1},
					items = {
						["golden-apple"]        = {1,1,1},
					}
				},
			},
			poolsDev = {}
		},
	},

	-- these values are used:
	-- * in place of the keys, when the key is used as a parameter
	
	-- chest-param -> internally-valid-chest-param
	
	synonyms = {
		["desert"] = "desert-temple",
		["jungle"] = "jungle-temple",
		["nether"] = "nether-fortress",
		["fortress"] = "nether-fortress",
		["village"] = "village-blacksmith",
		["blacksmith"] = "village-blacksmith",
		["altar"] = "stronghold-altar",
		["storeroom"] = "stronghold-storeroom",
		["library"] = "stronghold-library"
	},

	-- these values are used:
	-- * in the header-description of a table showing only a single chest
	-- * if the key is not here, but it is a valid chest parameter,
	--   that header-description will default to use the key string from p.chests,
	--   e.g. "nether-fortress"
	
	-- chest-param -> description-string
	
	display_names = {
		["nether-fortress"] = "Nether fortress",
		["nether"] = "Nether fortress",
		["fortress"] = "Nether fortress",
		["desert"] = "desert temple",
		["jungle"] = "jungle temple",
		["desert-temple"] = "desert temple",
		["jungle-temple"] = "jungle temple"
	},
	
	-- these descriptions are used:
	-- * in column <abbr> titles,
	-- * and above the table when only a single column-type is chosen
	
	columns = {
		["stacksize"] = 'the size of stacks (or for unstackable items, number) of this item found in this chest.',
		["weight"] = 'the weight of this item relative to other items in the chest.',
		["items"] = 'the number of items expected per chest, averaged over a large number of chests.',
		["chance"] = 'the odds of getting any of this item in a single chest.',
		["chests"] = 'the number of chests expected to search, to find any of this item.'
	},
	
	current_frame = nil
}

p.base = function( ... )

	p.current_frame = mw.getCurrentFrame()

	local args = { ... }
	if args[1] == p.current_frame then 
		args = require( 'Module:ProcessArgs' ).merge( true )
	else
		args = args[1]
	end
	
	-- transform args into usable list
	
	local chests, columns = q.massage_args( args )
	
	if #chests == 0 then
		return "<span style='font-style:italic; color:red;'>Module:LootChest: no valid arguments</span>"
	end

	q.fill_in_chest_derivative_data( chests )
	
	-- construct an ordered list dictating the order of the rows
	
	local ordered_item_rows, ordered_item_rows_dev

	local ret = {}
	if args.dev and args.dev ~= '0' then
		local ordered_item_rows = q.construct_ordered_item_rows( chests, 'Dev' )
		if q.tablelength( ordered_item_rows ) > 0 then
			table.insert( ret, q.print_table( chests, columns, ordered_item_rows, 'Dev' ) )
		end
	else
		local ordered_item_rows = q.construct_ordered_item_rows( chests, '' )
		local ordered_item_rows_dev = q.construct_ordered_item_rows( chests, 'Dev' )

		if q.tablelength( ordered_item_rows ) > 0 then
			table.insert( ret, q.print_table( chests, columns, ordered_item_rows, '' ) )
		end
		if q.tablelength( ordered_item_rows_dev ) > 0 and q.compare_tables( ordered_item_rows, ordered_item_rows_dev ) then
			table.insert( ret, p.current_frame:preprocess( p.dev ) .. q.lcfirst( q.print_table( chests, columns, ordered_item_rows_dev, 'Dev' ) ) )
		end
	end

	return table.concat( ret, '\n\n' )
end

p.doc = function()

	local valid_args = {}
	for chest_name, val in pairs(p.chests) do
		local synonyms = {}
		for syn, orig in pairs(p.synonyms) do
			if orig == chest_name then
				table.insert( synonyms, syn )
			end
		end
		if #synonyms > 0 then
			chest_name = chest_name .. " ( " .. table.concat( synonyms, ", " ) .. " )"
		end
		table.insert( valid_args, chest_name )
	end
	table.sort( valid_args )
	return table.concat( valid_args, ",\n<br>" )

end

p.doc2 = function()

	local valid_args = {}
	for column_name, val in pairs(p.columns) do
		table.insert( valid_args, column_name .. ": " .. val )
	end
	table.sort( valid_args )
	return table.concat( valid_args, ",\n<br>" )

end

p.doc3 = function()

	local valid_args = {}
	for item_name, val in pairs(p.items) do
		table.insert( valid_args, item_name )
	end
	table.sort( valid_args )
	return table.concat( valid_args, ", " )

end

p.base2 = function( ... )

	p.current_frame = mw.getCurrentFrame()

	local args = { ... }
	if args[1] == p.current_frame then 
		args = require( 'Module:ProcessArgs' ).merge( true )
	else
		args = args[1]
	end
	
	local itemname = args[1]
	
	if p.items[itemname] == nil then
		return '<span style="color:red;">unknown item "' .. itemname .. '"</span>'
	end
	
	local chances, devChances
	if args.dev and args.dev ~= '0' then
		chances = q.single_item_find_values( itemname, 'poolsDev' )
		devChances = {}
	else
		chances = q.single_item_find_values( itemname, 'pools' )
		devChances = q.single_item_find_values( itemname, 'poolsDev' )
	end
	
	local html = {}

	if q.tablelength( chances ) > 0 then
		table.insert( html, p.base2_sub( itemname, chances ) )
	end
	if q.tablelength( devChances ) > 0 and q.compare_tables( chances, devChances ) then
		table.insert( html, p.current_frame:preprocess( p.dev ) .. q.lcfirst( p.base2_sub( itemname, devChances ) ) )
	end

	return table.concat( html, ' ' )
end

p.base2_sub = function( itemname, chances )
	local html = {}
	local item_display_name = ''
	
	if p.items[itemname].plural ~= nil and p.items[itemname].plural ~= false then
		item_display_name = p.items[itemname].plural
	else
		if p.items[itemname].title ~= nil then
			item_display_name = p.items[itemname].title
		else
			item_display_name = string.gsub( itemname, '-', ' ' )
		end
		if p.items[itemname].plural == nil or p.items[itemname].plural ~= false then
			item_display_name = q.single_item_plural( item_display_name )
		end
	end
	
	item_display_name = q.capitalize( item_display_name )
	
	table.insert( html, item_display_name )
	table.insert( html, ' can be found ' )

	local html_stacks = {}
	local stack_sep = ', '
	local ns = q.tablelength( chances )
	local s = 0

	for stacksize, chest_details in pairs( chances ) do
		s = s + 1
	
		local html_per_stack = { 'in ' }
		local c = 0
		local nc = q.tablelength( chest_details )
		local sep = q.tern( nc > 2, ', ', ' ' )
		if nc > 2 and s ~= ns then
			stack_sep = '; '
		end
		for k, chest in pairs( chest_details ) do
			c = c + 1
			if c == nc and nc > 1 then
				table.insert( html_per_stack, 'and ' )
			end
			if chest.chance == 1 then
				table.insert( html_per_stack, " all " )
			else
				table.insert( html_per_stack, string.format("%.1f", chest.chance*100) )
				table.insert( html_per_stack, "% of " )
			end
			if chest.chest_type == 'minecart with chest' then
				table.insert( html_per_stack, ' [[Minecart with Chest|chest minecarts]] in ' )
				table.insert( html_per_stack, p.chests[chest.chest_name].link )
			elseif chest.chest_type == 'dispenser' then
				table.insert( html_per_stack, ' [[dispenser]]s in ' )
				table.insert( html_per_stack, p.chests[chest.chest_name].link )
			else
				table.insert( html_per_stack, p.chests[chest.chest_name].link )
				table.insert( html_per_stack, ' chests' )
			end
			table.insert( html_per_stack, sep )
		end
		if nc > 2 then
			table.insert( html_per_stack, 'all ' )
		end
		table.insert( html_per_stack, 'in ' )
		if p.items[itemname].cannot_stack ~= nil then
			table.insert( html_per_stack, 'groups of ' )
		else
			table.insert( html_per_stack, 'stacks of ' )
		end
		table.insert( html_per_stack, stacksize )
	
		table.insert( html_stacks, table.concat( html_per_stack ) )
	end
	
	local stackwise_summaries = ''
	if #html_stacks == 1 then
		table.insert( html, html_stacks[1] )
	else
		for i = 1, #html_stacks - 1 do
			table.insert( html, html_stacks[ i ] )
			table.insert( html, stack_sep ) 
		end
		table.insert( html, 'and ' )
		table.insert( html, html_stacks[#html_stacks] )
	end
	
	table.insert( html, '.' )
	
	return table.concat( html )
	
end

p.base2_test = function()

	items = {}
	for item_name, v in pairs( p.items ) do
		table.insert( items, p.base2{ item_name } .. '\n\n' )
	end

	table.sort( items )
	
	return table.concat(items)
end

q = {

	tablelength = function(T)
		local count = 0
		for _ in pairs(T) do count = count + 1 end
		return count
	end,
	
	single_item_find_values = function( itemname, key )
	
		local chances = {}

		for chest_name, chest in pairs( p.chests ) do
			local poolchances = {}
			for k, pool in pairs( chest[key] or chest.pools or {} ) do
				local poolitem = pool.items[itemname]
				if poolitem ~= nil then
				
					local stacksize = poolitem[1]
					if poolitem[1] ~= poolitem[2] then
						stacksize = stacksize .. "–" .. poolitem[2]
					end
					
					local itemweight = poolitem[3]
					
					local pool_total_item_weight = 0
					for itemname, item in pairs(pool.items) do
						pool_total_item_weight = pool_total_item_weight + item[3]
					end
				
					local chance = p.calc_chance_any_of_this_item_per_pool( 
						pool.rolls[1], pool.rolls[2],
						itemweight, pool_total_item_weight )

					if poolchances[stacksize] == nil then
						poolchances[stacksize] = chance
					else
						poolchances[stacksize] = poolchances[stacksize] + (1 - poolchances[stacksize]) * chance
					end
				end
			end
			for stacksize, chance in pairs( poolchances ) do
				if chances[stacksize] == nil then
					chances[stacksize] = {}
				end
				table.insert( chances[stacksize], { ["chance"]=chance, ["chest_name"]=chest_name, ["chest_type"]=( chest.chest_type or "chest" ) } )
			end
		end

		return chances
		
	end,
	
	single_item_plural = function( itemname )
	
		if string.sub( itemname, -2 ) == 'ss' 
			or string.sub( itemname, -2 ) == 'ch' 
			or string.sub( itemname, -2 ) == 'sh' 
			or string.sub( itemname, -1 ) == 's' then 
				return itemname .. 'es' 
		end
		
		return itemname .. 's'
	
	end,
	
	massage_args = function( args )

		-- find what columns to put
		
		local columns = {}
		
		for k, _arg in pairs(args) do
			if p.columns[_arg] ~= nil then
				columns[_arg] = true
			end
		end
		
		if q.tablelength(columns) == 0 then
			for column_name, v in pairs(p.columns) do
				columns[column_name] = true
			end
		end
		
		-- find what chests to show

		local chests = {}
		
		for k, _arg in pairs(args) do
			if p.chests[_arg] ~= nil then
				table.insert( chests, _arg )
			elseif p.synonyms[_arg] ~= nil then 
				table.insert( chests, p.synonyms[_arg] )
			end
			if p.display_names[_arg] ~= nil then
				local chestname = _arg
				if p.chests[chestname] == nil then 
					chestname = p.synonyms[_arg]
				end
				p.chests[chestname].display_name = p.display_names[_arg]
			end
		end
		
		if #chests == 0 then
			for chest_name, chest in pairs(p.chests) do
				local chest_type = ( chest.chest_type or "chest" )
				if chest_type == "chest" or chest_type == "minecart with chest" then
					table.insert( chests, chest_name )
				end
			end
		end
		
		table.sort( chests )
		
		return chests, columns
		
	end,

	sort_items = function( e1, e2 )
		
		if e1.chanceany ~= e2.chanceany then return ( e1.chanceany > e2.chanceany ) end
		if e1.avgamount ~= e2.avgamount then return ( e1.avgamount > e2.avgamount ) end
		
		if e1.material == nil then
			
			e1.material = 0
			if string.find( e1.itemname, "leather" ) ~= nil then e1.material = 1 end
			if string.find( e1.itemname, "iron" ) ~= nil then e1.material = 2 end
			if string.find( e1.itemname, "gold" ) ~= nil then e1.material = 3 end
			if string.find( e1.itemname, "diamond" ) ~= nil then e1.material = 4 end
			e1.armor = 0
			if string.find( e1.itemname, "helmet" ) ~= nil or string.find( e1.itemname, "cap" ) ~= nil then e1.armor = 1 end
			if string.find( e1.itemname, "chestplate" ) ~= nil or string.find( e1.itemname, "tunic" ) ~= nil then e1.armor = 2 end
			if string.find( e1.itemname, "leggings" ) ~= nil or string.find( e1.itemname, "pants" ) ~= nil then e1.armor = 3 end
			if string.find( e1.itemname, "boots" ) ~= nil then e1.armor = 4 end
			
		end
		
		if e2.material == nil then
			
			e2.material = 0
			if string.find( e2.itemname, "leather" ) ~= nil then e2.material = 1 end
			if string.find( e2.itemname, "iron" ) ~= nil then e2.material = 2 end
			if string.find( e2.itemname, "gold" ) ~= nil then e2.material = 3 end
			if string.find( e2.itemname, "diamond" ) ~= nil then e2.material = 4 end
			e2.armor = 0
			if string.find( e2.itemname, "helmet" ) ~= nil or string.find( e2.itemname, "cap" ) ~= nil then e2.armor = 1 end
			if string.find( e2.itemname, "chestplate" ) ~= nil or string.find( e2.itemname, "tunic" ) ~= nil then e2.armor = 2 end
			if string.find( e2.itemname, "leggings" ) ~= nil or string.find( e2.itemname, "pants" ) ~= nil then e2.armor = 3 end
			if string.find( e2.itemname, "boots" ) ~= nil then e2.armor = 4 end
		
		end
		
		if e1.material ~= e2.material then return ( e1.material < e2.material ) end
		if e1.armor ~= e2.armor then return ( e1.armor < e2.armor ) end
		
		return ( e1.itemname < e2.itemname )
		
	end,
	
	fill_in_chest_derivative_data = function( chest_names )

		for k, chest_name in pairs(chest_names) do
			local chest = p.chests[chest_name]
			if chest == nil then break end

			chest.allRolls = {}
			chest.itemData = {}
			for k, pool in pairs( chest.pools or {} ) do
				table.insert( chest.allRolls, q.tern( pool.rolls[1] == pool.rolls[2], pool.rolls[1], pool.rolls[1]..'–'..pool.rolls[2] ) )

				local total_weight = 0
				for itemname, item in pairs(pool.items) do
					total_weight = total_weight + item[3]
				end
				pool.totalweight = total_weight

				q.fill_in_chest_item_details( chest.itemData, pool, #chest.allRolls )
			end

			chest.allRollsDev = {}
			chest.itemDataDev = {}
			for k, pool in pairs( chest.poolsDev or chest.pools or {} ) do
				table.insert( chest.allRollsDev, q.tern( pool.rolls[1] == pool.rolls[2], pool.rolls[1], pool.rolls[1]..'–'..pool.rolls[2] ) )

				local total_weight = 0
				for itemname, item in pairs(pool.items) do
					total_weight = total_weight + item[3]
				end
				pool.totalweight = total_weight

				q.fill_in_chest_item_details( chest.itemDataDev, pool, #chest.allRollsDev )
			end
		end
	end,

	fill_in_chest_item_details = function( data, pool, ct )
		for item_name, item in pairs(pool.items) do
			if p.items[item_name] then
				local min_stacksize = item[1]
				local max_stacksize = item[2]
				local min_pool_rolls = pool.rolls[1]
				local max_pool_rolls = pool.rolls[2]
				local item_weight = item[3]
			
				if data[item_name] == nil then
					data[item_name] = {
						avgamount = 0,
						chanceany = 0,
						itemname = item_name,
						sortsize = {},
						sortweight = {},
						sizes = {},
						weights = {},
					}
					for i = 1, ct-1 do
						data[item_name].sortsize[i] = 0
						data[item_name].sortweight[i] = 0
						data[item_name].sizes[i] = '—'
						data[item_name].weights[i] = '—'
					end
				end

				data[item_name].avgamount = data[item_name].avgamount + p.calc_average_amount_this_item_per_pool( 
					min_stacksize, max_stacksize, 
					min_pool_rolls, max_pool_rolls, 
					item_weight, pool.totalweight )
					
				data[item_name].chanceany = data[item_name].chanceany + (1 - data[item_name].chanceany) * p.calc_chance_any_of_this_item_per_pool(
					min_pool_rolls, max_pool_rolls, 
					item_weight, pool.totalweight )

				data[item_name].sortsize[ct] = ( min_stacksize + max_stacksize ) / 2
				data[item_name].sortweight[ct] = item_weight;
				data[item_name].sizes[ct] = q.tern( min_stacksize == max_stacksize, min_stacksize, min_stacksize .. '–' .. max_stacksize )
				data[item_name].weights[ct] = p.current_frame:expandTemplate{ title = 'frac', args = { item_weight, pool.totalweight } }
			end
		end

		for item_name, d in pairs(data) do
			if not d.sizes[ct] then
				d.sortsize[ct] = 0
				d.sortweight[ct] = 0
				d.sizes[ct] = '—'
				d.weights[ct] = '—'
			end
		end
	end,

	construct_ordered_items_from_first_chest = function( chest_names, suffix )
		local items_from_first_table = {}
		local item_chests = {}
		local item_names_ordered = {}
		for item_name, item in pairs( p.chests[chest_names[1]]['itemData'..suffix] ) do
			table.insert( items_from_first_table, item )
		end
		
		table.sort( items_from_first_table, q.sort_items )
		
		for k, item in pairs( items_from_first_table ) do
			table.insert( item_names_ordered, item.itemname )
			item_chests[item.itemname] = true
		end
		
		return item_names_ordered, item_chests
	end,

	get_ordered_items_from_other_chests = function( chest_names, item_chests, suffix )
		local items_not_from_first_table = {}
		
		for chest_idx = 2, #chest_names do
			for item_name, item in pairs( p.chests[chest_names[chest_idx]]['itemData'..suffix] ) do
				if item_chests[item_name] == nil then
					p.items[item_name].itemname = item_name
					table.insert( items_not_from_first_table, p.chests[chest_names[chest_idx]]['itemData'..suffix][item_name] )
					item_chests[item_name] = true
				end
			end
		end

		table.sort( items_not_from_first_table, q.sort_items )
		
		return items_not_from_first_table
	end,

	add_other_items_to_first_list = function( chest_names, item_names_ordered, item_chests, items_not_from_first_table )
		for k, item in pairs( items_not_from_first_table ) do
			table.insert( item_names_ordered, item.itemname )
		end
		
		return item_names_ordered
	end,

	set_up_ordered_item_rows = function( chest_names, item_names_ordered, suffix )
		for k, itemname in pairs(item_names_ordered) do
			item_names_ordered[k] = {itemname}
			for chest_idx = 1, #chest_names do
				if suffix == 'Dev' or p.chests[chest_names[chest_idx]]['pools'..suffix] ~= nil then
					local item_data = p.chests[chest_names[chest_idx]]['itemData'..suffix][itemname]
					if item_data == nil then
						table.insert( item_names_ordered[k], false )
					else
						table.insert( item_names_ordered[k], item_data )
					end				
				end
			end
		end

		return item_names_ordered
	end,

	construct_ordered_item_rows = function( chest_names, suffix )
		-- for the first chest, sort its by chance desc, then by avg amount desc, then alphabetically asc
		local item_names_ordered, item_chests = q.construct_ordered_items_from_first_chest( chest_names, suffix )
		
		if #chest_names > 1 then
			-- after that, sort all the remaining items in list order
			local items_not_from_first_table = q.get_ordered_items_from_other_chests( chest_names, item_chests, suffix )
			item_names_ordered = q.add_other_items_to_first_list( chest_names, item_names_ordered, item_chests, items_not_from_first_table )
		end

		-- set up item_names_ordered so that each is a row, representing chest values
		item_names_ordered = q.set_up_ordered_item_rows( chest_names, item_names_ordered, suffix )
		
		return item_names_ordered
	end,

	print_table = function( chest_names, columns, ordered_item_rows, suffix )

		local html = {}
		
		local use_roll_row = false
		local use_superheader = false
		local superheader_sizes = {}
		for i = 1, #chest_names do
			sh = p.chests[chest_names[i]].superheader
			if sh ~= nil then
				if superheader_sizes[sh] == nil then
					superheader_sizes[sh] = 0
				end
				superheader_sizes[sh] = superheader_sizes[sh] + 1
				use_superheader = true
			end
			local allRolls = p.chests[chest_names[i]]['allRolls'..suffix]
			if #allRolls > 1 then
				use_roll_row = true
			end
		end
		if columns['stacksize'] == nil and columns['weight'] == nil then
			use_roll_row = false
		end
		
		local rowspan = ( 1 + q.tern( #chest_names > 1, 1, 0 ) + q.tern( use_superheader, 1, 0 ) )
		local hide_col_description = rowspan > 1 and q.tablelength(columns) == 1
		if use_roll_row then
			rowspan = rowspan + 1
		end
		
		if q.tablelength(columns) == 1 then
			for column_name, v in pairs(columns) do
				table.insert( html, "Values represent " )
				table.insert( html, p.columns[column_name] )
				table.insert( html, "\n" )
			end
		end

		if #chest_names == 1 then
		
			if q.tablelength(columns) == 1 then
				table.insert( html, "<br>" )
			end
		
			local chest_name = chest_names[1]
			local allRolls = p.chests[chest_name]['allRolls'..suffix]
			local chest_type = p.chests[chest_name].chest_type or "chest"

			local display_name = p.chests[chest_name].display_name

			chest_name = chest_name:gsub( "-", " " )
			
			table.insert( html, "Each " )
			table.insert( html, display_name or chest_name )
			if chest_type ~= 'chest' and chest_type ~= 'minecart with chest' then
				table.insert( html, " contains " )
			else
				table.insert( html, " chest contains " )
			end
			if #allRolls == 1 then
				table.insert( html, allRolls[1] )
			else
				table.insert( html, #allRolls )
				table.insert( html, ' groups of ' )
				local s = q.tern( #allRolls > 2, ', ', ' ' )
				for i = 1, #allRolls-1 do
					table.insert( html, allRolls[i] )
					table.insert( html, s )
				end
				table.insert( html, 'and ' )
				table.insert( html, allRolls[#allRolls] )
			end
			table.insert( html, " item stacks, with the following distribution: \n" )
		end
		
		table.insert( html, '<div style="overflow:auto">\n' )
		table.insert( html, "<table class='wikitable sortable jquery-tablesorter'>\n" )
		table.insert( html, "<tr>\n" )
		table.insert( html, "<th rowspan=" )
		table.insert( html, ( rowspan - q.tern( hide_col_description, 1, 0 ) ) )
		table.insert( html, "></th>\n" )
		
		local superheader_cols_used = {}
		
		if #chest_names > 1 then
			local row1, row2 = {}, {}

			for i = 1, #chest_names do
			
				if suffix == 'Dev' or p.chests[chest_names[i]]['pools'..suffix] ~= nil then
					local allRolls = p.chests[chest_names[i]]['allRolls'..suffix]
					local colspan = q.tablelength(columns)
					local allRollsSpan = #allRolls == 0 and 1 or #allRolls
					if columns['stacksize'] ~= nil then
						colspan = colspan - 1 + allRollsSpan
					end
					if columns['weight'] ~= nil then
						colspan = colspan - 1 + allRollsSpan
					end
					local row = row1
					
					rowspan = 1
					if use_superheader then
						sh = p.chests[chest_names[i]].superheader
						if sh ~= nil then
							if superheader_cols_used[sh] == nil then
								table.insert( row, "<th colspan=" )
								table.insert( row, ( colspan * superheader_sizes[sh] ) )
								table.insert( row, ">" )
								table.insert( row, sh )
								table.insert( row, "</th>\n" )
								superheader_cols_used[sh] = 0
							end
							row = row2
						else
							rowspan = rowspan + 1
						end
					end
					if use_roll_row and hide_col_description and #allRolls < 2 then
						rowspan = rowspan + 1
					end

					table.insert( row, "<th colspan=" )
					table.insert( row, colspan )
					if rowspan > 1 then
						table.insert( row, " rowspan=" )
						table.insert( row, rowspan )
					end
					table.insert( row, ">" )
					table.insert( row, p.chests[ chest_names[i] ].header )
					if #allRolls > 0 then
						table.insert( row, ' <br><span style="font-weight:normal; font-style:italic; font-size:11px;">(' )
						if #allRolls == 1 then
							table.insert( row, allRolls[1] )
						else
							local s = q.tern( #allRolls > 2, ', ', ' ' )
							for i = 1, #allRolls-1 do
								table.insert( row, allRolls[i] )
								table.insert( row, s )
							end
							table.insert( row, 'and ' )
							table.insert( row, allRolls[#allRolls] )
						end
						table.insert( row, ' stacks)</span>' )
					end
					table.insert( row, "</th>\n" )
				end
			end
			
			table.insert( html, table.concat( row1 ) )
			table.insert( html, "</tr><tr>\n" )
			if #row2 then
				table.insert( html, table.concat( row2 ) )
				table.insert( html, "</tr><tr>\n" )
			end
		end

		if not hide_col_description then
			local headersort_th_open
			if use_roll_row then
				headersort_th_open = "<th rowspan='2' class='headersort' role='columnheader button' data-sort-type='number'> <abbr title='"
			else
				headersort_th_open = "<th class='headersort' role='columnheader button' data-sort-type='number'> <abbr title='"
			end
			for i = 1, #chest_names do
				if suffix == 'Dev' or p.chests[chest_names[i]]['pools'..suffix] ~= nil then
					local allRolls = p.chests[chest_names[i]]['allRolls'..suffix]
					local allRollsSpan = #allRolls == 0 and 1 or #allRolls
					local headersort_th_colspan_open
					if #allRolls > 1 then
						headersort_th_colspan_open = "<th colspan='" .. allRollsSpan .. "' role='columnheader'> <abbr title='"
					else
						headersort_th_colspan_open = headersort_th_open
					end

					if columns['stacksize'] ~= nil then
						table.insert( html, headersort_th_colspan_open )
						table.insert( html, p.columns['stacksize'] )
						table.insert( html, "'> Stack Size </abbr></th>\n" )
					end
					if columns['weight'] ~= nil then
						table.insert( html, headersort_th_colspan_open )
						table.insert( html, p.columns['weight'] )
						table.insert( html, "'> Weight" )
						table.insert( html, "</abbr></th>\n" )
					end
					if columns['items'] ~= nil then
						table.insert( html, headersort_th_open )
						table.insert( html, p.columns['items'] )
						table.insert( html, "'> # Items </abbr></th>\n" )
					end
					if columns['chance'] ~= nil then
						table.insert( html, headersort_th_open )
						table.insert( html, p.columns['chance'] )
						table.insert( html, "'> Chance </abbr></th>\n" )
					end
					if columns['chests'] ~= nil then
						table.insert( html, headersort_th_open )
						table.insert( html, p.columns['chests'] )
						table.insert( html, "'> # Chests </abbr></th>\n" )
					end
				end
			end
			table.insert( html, "</tr><tr>\n" )
		end
		
		if use_roll_row then
			local rowcols = ( columns['stacksize'] ~= nil and 1 or 0 ) + ( columns['weight'] ~= nil and 1 or 0 )
			for i = 1, #chest_names do
				local allRolls = p.chests[chest_names[i]]['allRolls'..suffix]
				if #allRolls > 1 then
					for j = 1, rowcols do
						for k = 1, #allRolls do
							table.insert( html, "<th class='headersort' role='columnheader button' data-sort-type='number' style='font-weight:normal'>" )
							table.insert( html, allRolls[k] )
							table.insert( html, "×</th>\n" )
						end
					end
				end
			end
			table.insert( html, "</tr><tr>\n" )
		end

		for i = 1, #ordered_item_rows do
			if type( ordered_item_rows[i] ) == "table" then
				for j = 1, #ordered_item_rows[i] do

					local chest_item = ordered_item_rows[i][j]
					
					if type( chest_item ) == "table" then
					
						local avg_amount = string.format("%.3f", chest_item.avgamount)
						local chance_any = string.format("%.1f", chest_item.chanceany*100) .. "%"
						local num_chests = string.format("%.1f", 1/chest_item.chanceany)
						
						table.insert( html, "\n" )
						if columns['stacksize'] ~= nil then
							for k = 1, #chest_item.sizes do
								table.insert( html, "<td style='text-align:center;' data-sort-value='" )
								table.insert( html, chest_item.sortsize[k] )
								table.insert( html, "'>" )
								table.insert( html, chest_item.sizes[k] )
								table.insert( html, "</td>" )
							end
						end
						if columns['weight'] ~= nil then
							for k = 1, #chest_item.sizes do
								table.insert( html, "<td style='text-align:center;' data-sort-value='" )
								table.insert( html, chest_item.sortweight[k] )
								table.insert( html, "'>" )
								table.insert( html, chest_item.weights[k] )
								table.insert( html, "</td>" )
							end
						end
						if columns['items'] ~= nil then
							table.insert( html, "<td style='text-align:center;'>" )
							table.insert( html, avg_amount )
							table.insert( html, "</td>" )
						end
						if columns['chance'] ~= nil then
							table.insert( html, "<td style='text-align:right;'>" )
							table.insert( html, chance_any )
							table.insert( html, "</td>" )
						end
						if columns['chests'] ~= nil then
							table.insert( html, "<td style='text-align:right;'>" )
							table.insert( html, num_chests )
							table.insert( html, "</td>" )
						end
							
					elseif type( chest_item ) == "boolean" then
						local allRolls = p.chests[chest_names[j-1]]['allRolls'..suffix]
						local allRollsSpan = #allRolls == 0 and 1 or #allRolls

						table.insert( html, "\n" )
						if columns['stacksize'] ~= nil then
							for k = 1, allRollsSpan do
								table.insert( html, "<td data-sort-value='0' style='text-align:center;'>—</td>" )
							end
						end
						if columns['weight'] ~= nil then
							for k = 1, allRollsSpan do
								table.insert( html, "<td data-sort-value='0' style='text-align:center;'>—</td>" )
							end
						end
						if columns['items'] ~= nil then
							table.insert( html, "<td data-sort-value='0' style='text-align:center;'>—</td>" )
						end
						if columns['chance'] ~= nil then
							table.insert( html, "<td data-sort-value='0' style='text-align:right;'>—</td>" )
						end
						if columns['chests'] ~= nil then
							table.insert( html, "<td data-sort-value='9e99' style='text-align:right;'>—</td>" )
						end
					else
						if i > 1 then
							table.insert( html, "</tr><tr>" )
						end
						
						local item = p.items[chest_item]
						
						local s = require( 'Module:Sprite' )
						table.insert( html, "\n<td>" )
						local image, spriteCat = s.link{ 
							id=item.id or chest_item, 
							link=item.link or string.gsub(chest_item,'-',' '), 
							text=item.title or q.titlecase(string.gsub(chest_item,'-',' ')), 
							settings= q.tern( item[1] == 'item', 'ItemSprite', 'BlockSprite' )
						}
						table.insert( html, image )
						table.insert( html, spriteCat )
						if item.note and p.notes[item.note] then
							table.insert( html, p.current_frame:preprocess( p.notes[item.note] ) )
						end
						table.insert( html, "</td>" )
					end
					
					if j == #ordered_item_rows[i] then
						table.insert( html, "</tr>" )
					end
					
				end
				table.insert( html, "\n" )
			end
		end
		
		table.insert( html, "</table></div>" )
		
		return table.concat( html )
		
	end,
	
	titlecase = function( str )
		local buf = {}
		for word in string.gfind(str, "%S+") do
			if word == "and" then
				table.insert( buf, word )
			else
				local first, rest = string.sub( word, 1, 1 ), string.sub( word, 2 )
				table.insert( buf, string.upper(first) .. string.lower(rest) )
			end
		end    
		return table.concat( buf, " " )
	end,
	
	capitalize = function( str )
		return ( string.lower(str):gsub( "^%l", string.upper ) )
	end,

	lcfirst = function( str )
		return ( string.gsub( str, "^%u", string.lower ) )
	end,
	
	tern = function( cond , T , F )
		if cond then return T else return F end
	end,

	compare_tables = function( a, b )
		local seen = {}
		for k, v in pairs( a ) do
			if type( v ) ~= type( b[k] ) then
				return true
			end
			if v ~= b[k] then
				return true
			end
			if type( v ) == 'table' and q.compare_tables( v, b[k] ) then
				return true
			end
			seen[k] = true
		end
		for k, v in pairs( b ) do
			if not seen[k] then
				return true
			end
		end
		return false
	end,
}

string.lpad = function(str, len, char)
	if char == nil then char = ' ' end
	return string.rep(char, len - #(''..str)) .. str
end

return p
Advertisement