Minecraft Wiki

除另有声明,转载时均必须注明出处若簡繁轉換出錯,請以遊戲內為準请勇于扩充与修正内容有兴趣逛逛我们的微博沟通交流,欢迎到社区专页需要协助,请在告示板留言

了解更多

Minecraft Wiki
Advertisement

本模块生成一个带有战利品信息的表格。

用法

以下具体信息请查看对应模板的文档。

all函数

嵌套模板:Template:LootChest

隐式参数输入若干结构ID值,生成这些结构箱子中的战利品信息。战利品ID值取决于JSON文件中的值。

若Java和基岩版的结构ID值不同的,需要同时输入参数。

{{LootChest|bastion_bridge|bastion_other|bastion_hoglin_stable|<!-- Java -->bastion_treasure|<!-- Bedrock -->buriedtreasure}}

item函数

嵌套模板:Template:LootChestItem

隐式参数输入若干物品的命名空间ID,生成这些物品可被获取的结构名信息。

{{LootChestItem|emerald|apple}}

维护

模块使用JSON文件生成信息表。

版本 JSON版本号 最后更新日期 操作
Java版 1.20 2023年6月19日 (日) 07:56 (UTC) 查看 历史 更新
Java版开发版 1.20.2-rc1 2023年9月16日 (六) 07:48 (UTC) 查看 历史 更新
基岩版 1.20.0 2023年6月7日 (三) 16:42 (UTC) 查看 历史 更新
基岩版测试版 1.20.40.20 2023年9月16日 (六) 09:59 (UTC) 查看 历史 更新
Java版愚人节快照 23w13a_or_b 2023年4月2日 (日) 12:41 (UTC) 查看 历史 更新

JSON的数据结构是:

{
    "structure ID": {
    ...
    },
    "structure ID": {
    ...
    }
}

这些JSON可通过脚本生成(下载),将此脚本与游戏战利品表JSON放置在同一层级,然后执行(python JsonMaker.py),会得到structureList.txt(名称列表)以及result.txt(最终结果文件),然后将result.txt上传即可。

生成JSON时需要注意的事项:

  • Java版的战利品表位于游戏jar文件的data/minecraft/loot_tables/chests(正式内容)下以及data/minecraft/datapacks/实验性数据包名称/data/minecraft/loot_tables/chests(实验性内容)下。
    • 生成Java版正式版JSON时,即便此正式版有实验性内容,实验性内容也不应包含在内。
    • 生成Java版开发版JSON时,需要先将各实验性数据包中的战利品表先应用到正式内容上再生成。实验性数据包中的战利品表如与正式内容的同名,则用实验性的替换正式的。
  • 基岩版的战利品表位于游戏安装文件的assets/behavior_packs/vanilla/loot_tables/chestsassets/behavior_packs/vanilla_正式版版本号/loot_tables/chests(正式内容)下以及assets/behavior_packs/experimental_实验性内容名称/loot_tables/chests(实验性内容)下。
    • 生成基岩版正式版JSON时,需要先将各版本的战利品表按版本号从前到后的顺序依次应用到vanilla再生成。文件名有冲突的则直接用新的替换旧的。
    • 生成基岩版测试版JSON时,需要先用生成正式版JSON的方法,把各正式版合并后,再把实验性内容合并到正式版内容上。文件名有冲突的则直接用实验性的替换正式版的。
  • JSON格式不允许注释,如遇到生成出的JSON中有注释的,应该将其去除。

配置

模块使用配置页面进行控制。

页面:Module:LootChest/config

  • switch (对开发/Beta版进行开关)
  • header (表格开头的文本,用于不同语言本地化)
  • report (报错信息)
  • mark (物品前后缀的标注信息)
  • debug
    • onlyJava (只显示Java版的内容)
    • onlyBedrock (只显示bedrock的内容)
  • style (两个生成表的自定义样式)
  • json (生成表的JSON文件页面名)
  • functions (指定读取哪些function至下一级转换)
    • functionsName (对应的function名,其中包含了一个表。表的第一个值是函数的数值对应,会读取为函数的value值。如果指定二三值且存在这两个值,自动使用a-b式链接)
  • customize (定制物品名/结构名的转换方案,如果启用则使用config末尾的函数替代代码中的对应的函数。
  • itemLink (输入物品命名空间ID和配置,返回显示内容的函数,如果customize中启用本函数。)
  • struLink (同上)

转换

模块使用转换JSON表进行物品名,结构名等的转换。
页面:Module:LootChest/cov.json

  • structure
    • text (结构的显示文本,输入到Sprite的text参数,结构ID→显示文本)
    • sprite-data-type (结构Sprite的数据类型,默认为EnvSprite)
    • sprite-id (用于生成图的结构ID,输入到Sprite的id参数,结构ID→Sprite ID)
  • item
    • sprite-data-type (设置物品Sprite的数据类型,默认为ItemSprite)
    •  cov (item的结构转换表)
      • id/name/text/link (默认将item的命名空间ID输入到Sprite的1参数,可用这些键值替代模板的参数)
      • function (如果存在某个函数指定,那使用function内的表重新覆盖Sprite参数)
        • id/name/text/link
      • aux (如果存在物品附加值,那使用aux内的表重新覆盖Sprite参数)
        • id/name/text/link (默认将item的命名空间ID输入到Sprite的1参数,可用这些键值替代模板的参数)
        • function (如果存在某个函数指定,那使用function内的表重新覆盖Sprite参数)
          • id/name/text/link
  • note (注释信息)
    • functions (函数指定的注释,具有某个函数定义则添加对应注释)
      • functionName (对应的function名)
        • valueName (对应function的值内容)
    • assign (自定义的注释,格式为命名空间ID:注释内容)

本地化

请将本段文本翻译至其他语言。

结构名和物品名使用Module:Sprite生成一个带图标的链接,这意味着如果本地没有此模块,将无法使用内置转换函数。不过可以在配置中启用独立转换函数(参见配置页文档)。

对于物品名,默认会将命名空间ID作为Module:Sprite的一参数传入,可以通过转换表来补充或改变参数内容(参见转换表文档)。如果一参数没有被转换,那么会进行简单处理(下划线替换,后缀删除等)。另外,如果一个物品属于方块的数据组,那么需要在转换组中为物品特殊声明(type=block),才可以正常生成Sprite图标。

对于结构名,没有一个标准的命名格式,因此必须同时传入本地化翻译和Module:Sprite要求的参数值。同样,如果数据组特殊,也需要特殊声明(data-type=BlockSprite)。

对于注释,转换表使用了两种方案。一,对于损坏或魔咒,有模板注释自动添加。二,可以通过制定命名空间ID给其添加注释。

对于以上三者,如果有特殊的使用需求,则可以在配置中启用独立转换函数。

此模块目前处于Beta版,有问题或需求建议优先在相关讨论话题中进行通知,以进行代码统一修改。


语言
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 = '在[[1.11]]中,',
	
	-- 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-wood-only"]    = { "block", id='acacia-wood', link="Wood", title="金合欢木头"},
		["activator-rail"]      = { "block", title="激活铁轨"},
		["apple"]               = { "item"},
        ["arrow"]               = { "item" },
		["beetroot-seeds"]      = { "item", link="Beetroot Seeds",plural=false},
		["bone"]                = { "item",plural=false},
		["book"]                = { "item" },
		["bread"]               = { "item" },
		["bucket"]              = { "item" },
        ["chainmail-chestplate"] = { "item", link="Armor", cannot_stack=true },
		["coal"]                = { "item" },
		["compass"]             = { "item" },
		["detector-rail"]       = { "block", title="探测铁轨" },
		["diamond"]             = { "item" },
        ["diamond-chestplate"]  = { "item", id="diamond-chestplate", link="Diamond Chestplate", cannot_stack=true },
        ["diamond-hoe"]         = { "item", id="diamond-hoe", link="Diamond Hoe", cannot_stack=true },
		["disc-13"]             = { "item", title="音乐唱片(13)", link="Music Disc", cannot_stack=true },
		["disc-cat"]            = { "item", title="音乐唱片(Cat)", link="Music Disc", cannot_stack=true },
		["emerald"]             = { "item" },
		["empty-map"]           = { "item", link="Map", title="空地图" },
		["enchanted-book"]      = { "item", cannot_stack=true, note="level-book" },
		["enchanted-book-rnd"]  = { "item", id='enchanted-book', title="附魔书", link="Enchanted Book", cannot_stack=true, note="random-book" },
		["ender-pearl"]         = { "item" },
		["flint-and-steel"]     = { "item", cannot_stack=true },
		["golden-apple"]        = { "item", title="普通金苹果" },
		["golden-chestplate"]   = { "item", link="Armor", cannot_stack=true },
		["golden-sword"]        = { "item", link="Sword", cannot_stack=true },
		["gold-ingot"]          = { "item" },
		["gold-nugget"]         = { "item" },
		["gunpowder"]           = { "item" },
		["diamond-horse-armor"] = { "item", title="钻石马铠", link="Horse Armor", cannot_stack=true },
		["golden-horse-armor"]    = { "item", title="金马铠", link="Horse Armor", cannot_stack=true },
		["iron-horse-armor"]    = { "item", title="铁马铠", link="Horse Armor", cannot_stack=true },
		["iron-boots"]          = { "item", link="Armor", cannot_stack=true },
		["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 },
		["iron-pickaxe"]        = { "item", link="Pickaxe", cannot_stack=true },
		["iron-sword"]          = { "item", link="Sword", cannot_stack=true },
		["lapis-lazuli"]        = { "item" },
		["melon-seeds"]         = { "item" },
		["name-tag"]            = { "item" },
		["notch-apple"]         = { "item", id='golden-apple', link="Golden Apple", title="附魔金苹果" },
		["nether-wart"]         = { "item" },
		["oak-sapling"]         = { "block", link="Sapling" },
		["oak-wood"]            = { "block", link="Wood", title="橡木、金合欢、丛林木或桦木" },
		["oak-wood-only"]       = { "block", id='oak-wood', link="Wood", title="橡木" },
		["obsidian"]            = { "block" },
		["paper"]               = { "item" },
		["powered-rail"]        = { "block", title="充能铁轨" },
		["pumpkin-seeds"]       = { "item" },
		["rail"]                = { "block", title="铁轨" },
		["redstone"]            = { "item" },
		["rotten-flesh"]        = { "item" },
		["sand"]                = { "block" },
		["saddle"]              = { "item", cannot_stack=true },
		["raw-salmon"]          = { "item" },
		["spider-eye"]          = { "item" },
		["stick"]               = { "item" },
		["stone-axe"]           = { "item", link="Axe", cannot_stack=true, },
		["stone-pickaxe"]       = { "item", link="Pickaxe", cannot_stack=true },
		["string"]              = { "item" },
		["torch"]               = { "block" },
		["wheat"]               = { "item" },
		["wood-planks"]         = { "block", title="橡木木板" },
		["wooden-axe"]          = { "item", link="Axe", cannot_stack=true },
		["wooden-pickaxe"]      = { "item", link="Pickaxe", cannot_stack=true },

		["enchanted-diamond-boots"]      = { "item", title="附魔的钻石靴子", id="diamond-boots", link="Diamond Boots", note="end-ench-equipment", cannot_stack=true },
		["enchanted-diamond-chestplate"] = { "item", title="附魔的钻石胸甲", id="diamond-chestplate", link="Diamond Chestplate", note="end-ench-equipment", cannot_stack=true },
		["enchanted-diamond-helmet"]     = { "item", title="附魔的钻石头盔", id="diamond-helmet", link="Diamond Helmet", note="end-ench-equipment", cannot_stack=true },
		["enchanted-diamond-leggings"]   = { "item", title="附魔的钻石护腿", id="diamond-leggings", link="Diamond Leggings", note="end-ench-equipment", cannot_stack=true },
		["enchanted-diamond-pickaxe"]    = { "item", title="附魔的钻石镐", id="diamond-pickaxe", link="Diamond Pickaxe", note="end-ench-equipment", cannot_stack=true },
		["enchanted-diamond-shovel"]     = { "item", title="附魔的钻石锹", id="diamond-shovel", link="Diamond Shovel", note="end-ench-equipment", cannot_stack=true },
		["enchanted-diamond-sword"]      = { "item", title="附魔的钻石剑", id="diamond-sword", link="Diamond Sword", note="end-ench-equipment", cannot_stack=true },
		["enchanted-iron-boots"]         = { "item", title="附魔的铁靴子", id="iron-boots", link="Iron Boots", note="end-ench-equipment", cannot_stack=true },
		["enchanted-iron-chestplate"]    = { "item", title="附魔的铁胸甲", id="iron-chestplate", link="Iron Chestplate", note="end-ench-equipment", cannot_stack=true },
		["enchanted-iron-helmet"]        = { "item", title="附魔的铁头盔", id="iron-helmet", link="Iron Helmet", note="end-ench-equipment", cannot_stack=true },
		["enchanted-iron-leggings"]      = { "item", title="附魔的铁护腿", id="iron-leggings", link="Iron Leggings", note="end-ench-equipment", cannot_stack=true },
		["enchanted-iron-pickaxe"]       = { "item", title="附魔的铁镐", id="iron-pickaxe", link="Iron Pickaxe", note="end-ench-equipment", cannot_stack=true },
		["enchanted-iron-shovel"]        = { "item", title="附魔的铁锹", id="iron-shovel", link="Iron Shovel", note="end-ench-equipment", cannot_stack=true },
		["enchanted-iron-sword"]         = { "item", title="附魔的铁剑", id="iron-sword", link="Iron Sword", note="end-ench-equipment", cannot_stack=true },

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

	notes = {
		["level-book"] = "<ref group='注' name='level-book'>附魔的概率与在[[附魔台]]上成功进行1个30级的附魔的概率相同,但是多个附魔并不会减少这个概率。</ref>",
		["end-ench-equipment"] = "<ref group='注' name='end-city-enchantment'>在相同的箱子里相同种类的物品拥有的附魔都是相同的。附魔的几率是在[[附魔台]]上进行1个20-39级之间的附魔的概率相同。<!-- Yes, really 39 even though the table normally only goes to 30  --></ref>",
		["random-book"] = "<ref group='注' name='random-book'>所有种类的附魔都有相同的概率,附魔的等级的概率也是相同的。</ref>",
        ["nothing"] = "<ref group='注' name='nothing'>“无”不表示生成空箱子的几率,而是表示随机战利品生成器''在这次尝试''中不添加任何战利品。</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 = "[[村庄]]",
			link   = "[[村庄]]铁匠铺",
			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},
						["iron-horse-armor"]    = {1,1,1},
						["golden-horse-armor"]  = {1,1,1},
						["diamond-horse-armor"] = {1,1,1},
						["saddle"]              = {1,1,3}
					}
				},
			},
			poolsDev = {}
		},
		["stronghold-altar"] = { -- stronghold_corridor.json
			header      = "祭坛",
			superheader = "[[要塞]]",
			link        = "[[要塞]]祭坛",
			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},
						["iron-horse-armor"]    = {1,1,1},
						["golden-horse-armor"]  = {1,1,1},
						["diamond-horse-armor"] = {1,1,1},
						["enchanted-book"]      = {1,1,1},
					}
				},
			},
			poolsDev = {}
		},
		["stronghold-library"] = { -- stronghold_library.json
			header      = "图书馆",
			superheader = "[[要塞]]",
			link        = "[[要塞]]图书馆",
			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      = "储藏室",
			superheader = "[[要塞]]",
			link        = "[[要塞]]储藏室",
			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 = "[[箱子|奖励箱]]",
			link   = "[[箱子|奖励箱]]",
			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 = "[[地牢]]",
			link   = "[[地牢]]",
			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},
						["golden-horse-armor"]  = {1,1,10},
						["iron-horse-armor"]    = {1,1,15},
						["diamond-horse-armor"] = {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 = "[[废弃矿井]]",
			link   = "[[运输矿车]]里,",
			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 = "[[下界要塞|下界]]<br>[[下界要塞|要塞]]",
			link   = "[[下界要塞]]",
			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},
						["golden-horse-armor"]  = {1,1,8},
						["iron-horse-armor"]    = {1,1,5},
						["diamond-horse-armor"] = {1,1,3},
						["obsidian"]            = {2,4,2},
					}
				},
			},
			poolsDev = {}
		},
		["desert-temple"] = { -- desert_pyramid.json
			header = "[[沙漠神殿]]",
			link   = "[[沙漠神殿]]",
			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},
						["iron-horse-armor"]    = {1,1,15},
						["golden-horse-armor"]  = {1,1,10},
						["diamond-horse-armor"] = {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 = "[[丛林神庙]]",
			link   = "[[丛林神庙]]",
			pools = {
				{
					rolls = {2,6},
					items = {
						["diamond"]             = {1,3,3},
						["iron-ingot"]          = {1,5,10},
						["gold-ingot"]          = {2,7,15},
						["emerald"]             = {1,3,2},
						["iron-horse-armor"]    = {1,1,1},
						["golden-horse-armor"]  = {1,1,1},
						["diamond-horse-armor"] = {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   = "[[丛林神庙]]",
			pools = {
				{
					rolls = {1,2},
					items = {
						["arrow"] = {2,7,30}
					}
				},
			},
			poolsDev = {}
		},
		["end-city"] = { -- end_city_treasure.json
			header = "[[末地城]]",
			link   = "[[末地城]]",
			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},
						["iron-horse-armor"]    = {1,1,1},
						["golden-horse-armor"]  = {1,1,1},
						["diamond-horse-armor"] = {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 = "[[雪屋]]",
			link   = "[[雪屋]]",
			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 = {}
		},
		["woodland-mansion"] = { -- woodland_mansion.json
			header = "[[林地府邸]]",
			link   = "[[林地府邸]]",
			pools = {
				{
					rolls = {1,3},
					items = {
						["lead"]                  = {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},
						["chainmail-chestplate"]  = {1,1,10},
						["diamond-hoe"]           = {1,1,15},
						["diamond-chestplate"]    = {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 = {},
		},
	},

	-- 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",
		["mansion"] = "woodland-mansion"
	},

	-- 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"] = "下界要塞",
        ["dungeon"] = "地牢",
		["fortress"] = "下界要塞",
		["desert"] = "沙漠神殿",
		["jungle"] = "丛林神庙",
		["desert-temple"] = "沙漠神殿",
		["jungle-temple"] = "丛林神庙",
        ["igloo"] = "雪屋",
        ["end-city"] = "末地城",
        ["village-blacksmith"] = "村庄铁匠铺",
        ["village"] = "村庄铁匠铺",
        ["blacksmith"] = "村庄铁匠铺",
        ["stronghold-altar"] = "要塞祭坛",
        ["stronghold-storeroom"] = "要塞储藏室",
        ["stronghold-library"] = "要塞图书馆",
        ["altar"] = "要塞祭坛",
        ["storeroom"] = "要塞储藏室",
        ["library"] = "要塞图书馆",
        ["mineshaft"] = "废弃矿井",
        ["woodland-mansion"] = "林地府邸",
        ["jungle-temple-dispenser"] = "丛林神庙发射器"
	},
	
	-- these descriptions are used:
	-- * in column <abbr> titles,
	-- * and above the table when only a single column-type is chosen
	
	columns = {
		["stacksize"] = '在这个箱子里能找到多少组这样的物品(对于不可堆叠的物品则为物品数)。',
		["weight"] = '这个物品相对于箱子里面的其他物品的权重。',
		["items"] = '预计每个箱子里出现的物品数量,这个数值采用了许多箱子的数据进行平均而得出的。',
		["chance"] = '表示该物品在一个箱子里面出现的几率。',
		["chests"] = '预计为了该物品而要搜索的箱子的数量。'
	},
	
	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:无有效对象</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;">未知物品“' .. 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
	end
	
	local Autolink = require( 'Module:Autolink' )
	table.insert( html, Autolink.xlink(item_display_name, 'nolink') )
	table.insert( html, '有' )

	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 = { '' }
		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, '以及' )
			end
			if chest.chance == 1 then
				table.insert( html_per_stack, "所有的" )
			else
				table.insert( html_per_stack, string.format("%.1f", chest.chance*100) )
				table.insert( html_per_stack, "%的" )
			end
			if chest.chest_type == 'minecart with chest' then
				table.insert( html_per_stack, p.chests[chest.chest_name].link )
				table.insert( html_per_stack, '的[[运输矿车]]里' )
			elseif chest.chest_type == 'dispenser' then
				table.insert( html_per_stack, p.chests[chest.chest_name].link )
				table.insert( html_per_stack, '的[[发射器]]里' )
			else
				table.insert( html_per_stack, p.chests[chest.chest_name].link )
				table.insert( html_per_stack, '的箱子里' )
			end
			table.insert( html_per_stack, sep )
		end
		if nc > 2 then
			table.insert( html_per_stack, '皆' )
		end
		table.insert( html_per_stack, '以' )
		table.insert( html_per_stack, stacksize )
        if p.items[itemname].cannot_stack == nil then
           table.insert( html_per_stack, '个' )
        else
           table.insert( html_per_stack, '份')
        end
	    table.insert( html_per_stack, '为一组的形式出现' )
		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, ',' ) 
		end
		table.insert( html, '也有' )
		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,
	
	
	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, "数值代表" )
				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, "每个" )
			table.insert( html, display_name or chest_name )
			if chest_type ~= 'chest' and chest_type ~= 'minecart with chest' then
				table.insert( html, "包含" )
			else
				table.insert( html, "箱子包含" )
			end
			if #allRolls == 1 then
				table.insert( html, allRolls[1] )
			else
				table.insert( html, #allRolls )
				table.insert( html, '组' )
				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, '以及' )
				table.insert( html, allRolls[#allRolls] )
			end
			table.insert( html, "叠物品,并伴有以下的分布:\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, '和' )
							table.insert( row, allRolls[#allRolls] )
						end
						table.insert( row, '组)</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, "' style='white-space:nowrap'> 堆叠数 </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, "' style='white-space:nowrap'> 权重 </abbr></th>\n" )
					end
					if columns['items'] ~= nil then
						table.insert( html, headersort_th_open )
						table.insert( html, p.columns['items'] )
						table.insert( html, "' style='white-space:nowrap'> # 物品 </abbr></th>\n" )
					end
					if columns['chance'] ~= nil then
						table.insert( html, headersort_th_open )
						table.insert( html, p.columns['chance'] )
						table.insert( html, "' style='white-space:nowrap'> 几率 </abbr></th>\n" )
					end
					if columns['chests'] ~= nil then
						table.insert( html, headersort_th_open )
						table.insert( html, p.columns['chests'] )
						table.insert( html, "' style='white-space:nowrap'> # 箱子数量 </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