Module:Loot

From Veloren Wiki

--helpers
local module_frame = mw.getCurrentFrame()

tier_text = {module_frame:expandTemplate{title="Low"},
	         module_frame:expandTemplate{title="Common"},
	         module_frame:expandTemplate{title="Moderate"},
	         module_frame:expandTemplate{title="High"},
	         module_frame:expandTemplate{title="Epic"},
	         module_frame:expandTemplate{title="Legendary"},
	         module_frame:expandTemplate{title="Artifact"},
	         }
metal_text = {"Bronze", "Iron", "Steel", "Cobalt", "Bloodsteel", "Orichalcum"}
wood_text = {"Wooden", "Bamboo", "Hardwood", "Ironwood", "Frostwood", "Eldwood"}

upper_first = function(str)
	return str:sub(1, 1):upper() .. str:sub(2)
end

str_split_iter = function(str, sep, escape)
	if escape then
		sep = "%"..sep
	end
	return string.gmatch(str, "[^"..sep.."]+")
end

format_probability = function(p_flt)
	-- format probability string
	local p_perc = p_flt * 100
	local p_str = tostring(p_perc)
	if p_str ~= tostring(math.floor(p_perc)) then
		p_str = string.format("%.2f", p_perc)
	end
	return p_str
end

-- worker function
process = function(frame, txt, entries, depth, p_prev, reuse_p)
	
	local p_order = {}
	local hidep
	if not reuse_p then
		--sort indices by drop chance
		for idx, entry in ipairs(entries) do
			p_order[idx] = {idx, entry[1]}
		end
		table.sort(p_order, function(a, b) return a[2] > b[2] end)
		hidep = 0
	else
		-- use entries directly (re-using same probability)
		p_order = entries
		hidep = 1
	end
	
	-- process entries
	for _, val in ipairs(p_order) do
		-- unpack data
		local entry
		if not reuse_p then
			entry = entries[val[1]]
		else
			entry = val	
		end
    	local p_flt, box
    	if not reuse_p then
    		p_flt = entry[1] * p_prev
    		box = entry[2]
    	else
    		p_flt = p_prev
    		box = entry
    	end
    	local box_type = box.t
    	local box_content = box.c
    	
    	-- format probability string
    	local p_str = format_probability(p_flt)
    	
    	-- handle box type
    	if box_type == "Item" then
    		-- single item row
    		local item = box_content[2]
    		txt = txt .. frame:expandTemplate{title='User:Horblegorble/Sandbox/Template/LootRowVariable',
    			                              args={depth=depth, item=item, n=1, p=p_str, hidep=hidep} }
		
		elseif box_type == "Nothing" then
    		-- single row
    		txt = txt .. frame:expandTemplate{title='User:Horblegorble/Sandbox/Template/LootRowVariable',
    			                              args={depth=depth, item="Nothing", p=p_str, hidep=hidep, noimg=1} }
		
    	elseif box_type == "MultiDrop" then
    		-- multidrop
			local nested_box = box_content[1]
			local nested_type = nested_box.t
			local low = box_content[2]
			local high = box_content[3]
			local n_str
			if low == high then
				n_str = tostring(low)
			else
				n_str = string.format("%s - %s", low, high)
			end
			if nested_type == "Item" then
				-- multiple of one item
				local item = nested_box.c[2]
				txt = txt .. frame:expandTemplate{title='User:Horblegorble/Sandbox/Template/LootRowVariable',
	    			                              args={depth=depth, item=item, n=n_str, p=p_str, hidep=hidep} }
			elseif nested_type == "SubTable" then
				-- multidrop from nested table
				local sub_depth = depth + 1
				local sub_box = nested_box.c[1]
				local sub_path = nested_box.c[2]
				
				local path_parts = {}
				for part in str_split_iter(sub_path, '.', true) do
					path_parts[#path_parts+1] = part
				end
				local item_category = path_parts[3]
				local last_part = path_parts[#path_parts]
				local name
				local collapsed = 1

				--material sub tables (hard-code matching for now)
				if item_category == "food" then
					if last_part == "wild_ingredients" then
						name = "Wild Ingredients"
					elseif last_part == "prepared" then
						name = "Prepared Food"
					elseif last_part == "farm_ingredients" then
						name = "Farm Ingredients"
					else
						name = "Food"
					end
				elseif item_category == "materials" then
					local name
					if last_part == "gems" then
						name = "Gems"
					elseif last_part == "underground" then
						name = "Underground Materials"
					else
						name = "Materials"
					end
				else
					name = "Misc"
					collapsed = 0
				end
				
				txt = txt .. frame:expandTemplate{title='User:Horblegorble/Sandbox/Template/LootHeaderVariable',
    			                                  args={depth=sub_depth, collapsed=collapsed, title=name, n=n_str, p=p_str, hidep=hidep} }
				txt = process(frame, txt, sub_box, sub_depth, p_flt, false)
				txt = txt .. frame:expandTemplate{title='User:Horblegorble/Sandbox/Template/LootEndNested'}
			
			elseif nested_type == "All" then
    			local sub_depth = depth + 1
    			local sub_box_content = nested_box.c
    			txt = txt .. frame:expandTemplate{title='User:Horblegorble/Sandbox/Template/LootHeaderVariable',
    			                              args={depth=sub_depth, title="All", collapsed=0, p=p_str, hidep=hidep} }
				txt = process(frame, txt, sub_box_content, sub_depth, p_flt, true)   			                               
				txt = txt .. frame:expandTemplate{title='User:Horblegorble/Sandbox/Template/LootEndNested'}
    		
    			-- spacer row approach
    			-- txt = txt .. frame:expandTemplate{title='User:Horblegorble/Sandbox/Template/LootRowSpacer'}
    			-- txt = process(frame, txt, box_content, sub_depth, p_flt/100, true)
    			-- txt = txt .. frame:expandTemplate{title='User:Horblegorble/Sandbox/Template/LootRowSpacer'}
				
			else
				-- other case (unhandled for now)
				
			end
    	
		elseif box_type == "SubTable" then
    		local sub_depth = depth + 1
    		local sub_box = box_content[1]
			local sub_path = box_content[2]
			local override = false
    		
    		-- sub table header
    		local path_sections = {}
			for section in str_split_iter(sub_path, '.', true) do
			-- for section in string.gmatch(sub_path, "[^%.]+") do
				path_sections[#path_sections+1] = section
			end
			local last_section = path_sections[#path_sections]
			local second_last_section = path_sections[#path_sections-1]
			local is_modular = false
			if last_section ~= nil then
				is_modular = "tier" == string.sub(last_section, 1, 4)
			end
		    local idx_tier
			if is_modular then
				idx_tier = 1 + tonumber(string.sub(last_section, -1, -1))
			end
			local item_category = path_sections[3]

			if item_category == "weapons" then
				if not is_modular then
					-- non-modular weapon
					local name = upper_first(last_section).."  Weapon"
					txt = txt .. frame:expandTemplate{title='User:Horblegorble/Sandbox/Template/LootHeaderVariable',
    			                                      args={depth=sub_depth, title=name, p=p_str, hidep=hidep} }
				else
					if second_last_section == "components" then
						-- primary component
						local name = tier_text[idx_tier].."  Primary Component"
						txt = txt .. frame:expandTemplate{title='User:Horblegorble/Sandbox/Template/LootHeaderVariable',
	    			                                      args={depth=sub_depth, title=name, n=1, p=p_str, hidep=hidep} }
						local metal = metal_text[idx_tier]
						local wood = wood_text[idx_tier]
						local p_wep = string.format("%.2f", 100 * p_flt / 6)
						local page = "Modular Crafting"  -- page link override doesn't seem to work
	    				txt = txt .. frame:expandTemplate{title='User:Horblegorble/Sandbox/Template/LootRowVariable',
    			                              args={depth=sub_depth, item=metal.." Sword Blade", p=p_wep, noimg=1, page=page} }
						txt = txt .. frame:expandTemplate{title='User:Horblegorble/Sandbox/Template/LootRowVariable',
    			                              args={depth=sub_depth, item=metal.." Axe Head", p=p_wep, noimg=1, page=page} }
    			        txt = txt .. frame:expandTemplate{title='User:Horblegorble/Sandbox/Template/LootRowVariable',
    			                              args={depth=sub_depth, item=metal.." Hammer Head", p=p_wep, noimg=1, page=page} }
    			        txt = txt .. frame:expandTemplate{title='User:Horblegorble/Sandbox/Template/LootRowVariable',
    			                              args={depth=sub_depth, item=wood.." Bow Limbs", p=p_wep, noimg=1, page=page} }
    			        txt = txt .. frame:expandTemplate{title='User:Horblegorble/Sandbox/Template/LootRowVariable',
    			                              args={depth=sub_depth, item=wood.." Sceptre Shaft", p=p_wep, noimg=1, page=page} }
    			        txt = txt .. frame:expandTemplate{title='User:Horblegorble/Sandbox/Template/LootRowVariable',
    			                              args={depth=sub_depth, item=wood.." Staff Shaft", p=p_wep, noimg=1, page=page} }
						-- **TODO**
						-- MediaWiki template for primary components of parameterised tier (sans outer header and end)
						override = true
						
					elseif second_last_section == "secondary" then
						-- secondary component
						-- **TODO**
						-- MediaWiki template for secondary components (sans outer header and end)
						override = true
						
					else
						-- modular weapon
						local name = tier_text[idx_tier].."  Weapon"
						txt = txt .. frame:expandTemplate{title='User:Horblegorble/Sandbox/Template/LootHeaderVariable',
	    			                                      args={depth=sub_depth, title=name, n=1, p=p_str, hidep=hidep} }
						local metal = metal_text[idx_tier]
						local wood = wood_text[idx_tier]
						local p_wep = string.format("%.2f", 100 * p_flt / 6)
						local page = "Weapons" -- page link override doesn't seem to work
	    				txt = txt .. frame:expandTemplate{title='User:Horblegorble/Sandbox/Template/LootRowVariable',
    			                              args={depth=sub_depth, item=metal.." Sword", p=p_wep, noimg=1, page=page} }
						txt = txt .. frame:expandTemplate{title='User:Horblegorble/Sandbox/Template/LootRowVariable',
    			                              args={depth=sub_depth, item=metal.." Axe", p=p_wep, noimg=1, page=page} }
    			        txt = txt .. frame:expandTemplate{title='User:Horblegorble/Sandbox/Template/LootRowVariable',
    			                              args={depth=sub_depth, item=metal.." Hammer", p=p_wep, noimg=1, page=page} }
    			        txt = txt .. frame:expandTemplate{title='User:Horblegorble/Sandbox/Template/LootRowVariable',
    			                              args={depth=sub_depth, item=wood.." Bow", p=p_wep, noimg=1, page=page} }
    			        txt = txt .. frame:expandTemplate{title='User:Horblegorble/Sandbox/Template/LootRowVariable',
    			                              args={depth=sub_depth, item=wood.." Sceptre", p=p_wep, noimg=1, page=page} }
    			        txt = txt .. frame:expandTemplate{title='User:Horblegorble/Sandbox/Template/LootRowVariable',
    			                              args={depth=sub_depth, item=wood.." Staff", p=p_wep, noimg=1, page=page} }
    			        
						-- **TODO**
						-- MediaWiki template for complete modular weapon of parameterised tier (sans outer header and end)
						override = true
						
					end
				end
			elseif item_category == "armor" then
				if not is_modular then
					-- specific armor
					local name = upper_first(last_section)
					if name == "Cloth" then
						name = tier_text[1].." Armor"
						txt = txt .. frame:expandTemplate{title='User:Horblegorble/Sandbox/Template/LootHeaderVariable',
    			                                      args={depth=sub_depth, title=name, n=1, p=p_str, hidep=hidep} }
					else
						if name == "Wool" then
							name = "Woolen"
						elseif name == "Silk" then
							name = "Silken"
						elseif name == "Lifecloth" then
							name = "Druid"
						elseif name == "Plate" then
							name = "Primal"
						end
						local image = name.." Armor Set.png"
						name = name.." Armor"
						txt = txt .. frame:expandTemplate{title='User:Horblegorble/Sandbox/Template/LootHeaderVariable',
	    			                            	      args={depth=sub_depth, title=name, image=image, p=p_str, hidep=hidep} }
					end
				else
					-- modular armor tier
					local name = tier_text[idx_tier].."  Armor"
					txt = txt .. frame:expandTemplate{title='User:Horblegorble/Sandbox/Template/LootHeaderVariable',
    			                                      args={depth=sub_depth, title=name, n=1, p=p_str, hidep=hidep} }
				end
			elseif item_category == "food" then
				--food sub tables (hard-code matching for now)
				local name
				if last_section == "wild_ingredients" then
					name = "Wild Ingredients"
				elseif last_section == "prepared" then
					name = "Prepared Food"
				elseif last_section == "farm_ingredients" then
					name = "Farm Ingredients"
				else
					name = "Food"
				end
				txt = txt .. frame:expandTemplate{title='User:Horblegorble/Sandbox/Template/LootHeaderVariable',
    			                                  args={depth=sub_depth, collapsed=1, title=name, p=p_str, hidep=hidep} }
			elseif item_category == "materials" then
				local name
				if last_section == "gems" then
					name = "Gems"
				elseif last_section == "underground" then
					name = "Underground Materials"
				else
					name = "Materials"
				end
				txt = txt .. frame:expandTemplate{title='User:Horblegorble/Sandbox/Template/LootHeaderVariable',
    			                                  args={depth=sub_depth, collapsed=1, title=name, p=p_str, hidep=hidep} }
			else
				-- non weeapon/armor sub table
				-- local name = last_section..second_last_section
				local name = "Misc"
				txt = txt .. frame:expandTemplate{title='User:Horblegorble/Sandbox/Template/LootHeaderVariable',
    			                                  args={depth=sub_depth, collapsed=0, title=name, p=p_str, hidep=hidep} }
			end
			
			-- sub table rows (unless direct template was used)
			if not override then
				txt = process(frame, txt, sub_box, sub_depth, p_flt, false)
			end
			
			-- sub table end 
			txt = txt .. frame:expandTemplate{title='User:Horblegorble/Sandbox/Template/LootEndNested'}
			
    	elseif box_type == "All" then
    		local sub_depth = depth + 1
    		txt = txt .. frame:expandTemplate{title='User:Horblegorble/Sandbox/Template/LootHeaderVariable',
    			                              args={depth=sub_depth, title="All", collapsed=0, p=p_str, hidep=hidep} }
			txt = process(frame, txt, box_content, sub_depth, p_flt, true)   			                               
			txt = txt .. frame:expandTemplate{title='User:Horblegorble/Sandbox/Template/LootEndNested'}
    		
    		-- spacer row approach
    		-- txt = txt .. frame:expandTemplate{title='User:Horblegorble/Sandbox/Template/LootRowSpacer'}
    		-- txt = process(frame, txt, box_content, sub_depth, p_flt/100, true)
    		-- txt = txt .. frame:expandTemplate{title='User:Horblegorble/Sandbox/Template/LootRowSpacer'}
			
		else
			-- fallback (shouldn't reach)
			local name = "Error"
			txt = txt .. frame:expandTemplate{title='User:Horblegorble/Sandbox/Template/LootRowVariable',
    			                              args={depth=depth, item=name, p=0, hidep=1, noimg=1} }
    	end
    	
	end
	
	return txt
	
end

-- mainline code
local module = {}
local drops_json = mw.text.jsonDecode(module_frame:expandTemplate{title="User:Horblegorble/Sandbox/Template/LootData"})
local sources_json = mw.text.jsonDecode(module_frame:expandTemplate{title="User:Horblegorble/Sandbox/Template/SourceData"})

module.drops = function(frame)
	-- generates drops table for an entity
	
	-- handle args
	-- local entity = tostring(frame.args[1])
	-- local loot_page = "User:"..entity.."Loot"
	-- local json = mw.text.jsonDecode(frame:expandTemplate{title=loot_page})
	
	-- get entity name
	-- local page_sections = {}
	-- for idx, section in ipairs(str_split_iter(frame.args[1])) do
	-- 	page_sections[idx] = section	
	-- end
	-- local entity = page_sections[#page_sections]
	local entity = frame.args[1]
	
	local export_date = drops_json[1]
	
	-- find data entry for entity
	local data = false
	for _, entry in ipairs(drops_json[2]) do
		if entry[1] == entity then
			data = entry[2]
			break
		end
	end
	if not data then
		return "entity not found in drops data"
	end
	
	-- table start
    local txt = frame:expandTemplate{title='User:Horblegorble/Sandbox/Template/LootHeaderVariable'}
	
	-- do the work
	txt = process(frame, txt, data, 0, 1.0, false)
	
	-- table end
    txt = txt .. frame:expandTemplate{title='User:Horblegorble/Sandbox/Template/LootEnd',
    								  args={date=export_date} }
    
    return txt
end

module.sources = function(frame)
	-- generates table of entity drop sources for an item
	local item = frame.args[1]
	
	local export_date = sources_json[1]
	local data = false
	for _, entry in ipairs(sources_json[2]) do
		if entry[1] == item then
			data = entry[2]
			break
		end
	end
	if not data then
		return frame:expandTemplate{title='User:Horblegorble/Sandbox/Template/NoSources',
							        args={date=export_date}}
	end
	
	-- sort entries by average
	local p_order = {}
	for idx, entry in ipairs(data) do
		p_order[idx] = {idx, entry[8]}
	end
	table.sort(p_order, function(a, b) return a[2] > b[2] end)
	
	-- table start
	local txt = frame:expandTemplate{title='User:Horblegorble/Sandbox/Template/SourceHeader',
									 args={sortable=1}}
	
	-- do the work
	for _, val in ipairs(p_order) do
		entry = data[val[1]]
		local entity = entry[1]
		if entity ~= "" then
			local variant = entry[2]
			local amount = entry[3]
			local n_sort = entry[4]
			local chance = entry[5]
			local rolls = entry[6]
			local p_sort = entry[7] * 100
			-- local avg = entry[8]
			
			if amount[1] == amount[2] then
				amount = tostring(amount[1])
			else
				amount = string.format("%i-%i", amount[1], amount[2])
			end
			
			if rolls[1] == rolls[2] then
				if rolls[1] == 1 then
					rolls = ''
				else
					rolls = tostring(rolls[1])
				end
			else
				rolls = string.format("%i-%i", rolls[1], rolls[2])
			end
			
	    	local p_str = format_probability(chance)
	    	
	    	local page = ""
	    	if string.sub(entity, 1, 1) == "#" then
	    		page = "Containers"
	    		entity = string.sub(entity, 2, -1)
	    	end
			
			txt = txt .. frame:expandTemplate{title='User:Horblegorble/Sandbox/Template/SourceRow',
											  args={entity=entity, variant=variant, n=amount, n_sort=n_sort,
											  	    p=p_str, rolls=rolls, p_sort=p_sort, page=page}}
		end
	end
	
	-- table end
	local txt = txt .. frame:expandTemplate{title='User:Horblegorble/Sandbox/Template/SourceEnd',
									 args={date=export_date} }
	
	return txt
end

return module
Cookies help us deliver our services. By using our services, you agree to our use of cookies.