Module:LootChest

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"] = " ", ["end-ench-equipment"] = " ", ["random-book"] = " ", ["nothing"] = " ", },	-- 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 = "Bonus", link  = "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 shafts", 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", 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 temples", 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 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 " Module:LootChest: no valid arguments " 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 " )

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 " )

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 ' unknown item "' .. itemname .. '" ' 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, ' 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, ' dispensers 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, " " ) 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, ' \n' ) table.insert( html, " " ) 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