Module:BlacksmithList

Module documentation
This documentation is transcluded from Module:BlacksmithList/doc. [edit] [history] [purge]
This module does not have any documentation. Please consider adding documentation at Module:BlacksmithList/doc. [edit]
Module:BlacksmithList's function main is invoked by Template:BlacksmithList.
Module:BlacksmithList requires Module:Currency.
Module:BlacksmithList requires Module:Mw.html extension.
Module:BlacksmithList requires Module:Paramtest.
Module:BlacksmithList requires Module:RecipeTreeSearch.
Module:BlacksmithList requires strict.

require('strict')
require('Module:Mw.html extension')
local search = require('Module:RecipeTreeSearch')
local param = require( 'Module:Paramtest' )
local currency = require('Module:Currency')
local lang = mw.getContentLanguage()

local p = {}

-- non dynamic module, no inputs
function p.main()
	-- returns only directly needed parameter needed for the row,
	-- other parameters are determined by subqueries of chained pages
	local query = {
		'[[Uses facility::Goblin Forge||Gnome Forge]]', 
		'?Uses facility = facility',
		'? #- = name',
		'?Activity level = lvl',
		'?Profession Level A = lvlLow',
		'?Profession Level A High = lvlHigh',
		'?Recipe JSON = recipeJSON',
		'?Value = sell',
		'sort = Activity level',
		'limit = 500'
	}
	local results = mw.smw.ask(query)

	results = p.formatResults(results)

	return p.displayTable(results)
	
	--for debugging
	--return '<pre>'..mw.text.jsonEncode(results, mw.text.JSON_PRETTY)..'</pre>'

end

-- makes the html for the cells containing currency directly
-- Replaces nil with an "unknown" cell
local function currency_cell(amount)
	if not amount then
		return mw.html.create('td')
			:addClass('table-bg-gray')
			:css{ ['text-align'] = 'center' }
			:attr{ colspan = '10' }
			:wikitext("''unknown''")
		:done()
	end
	return currency._cell(amount, { html = 'yes' })
end

-- do calculations and determine strings to go in cells
function p.formatResults(results)

	-- iterate through products
	for _, item in ipairs(results) do
		
		-- New module for recipe searching
		local fullRecipe = search.main(item.name)
		item.materials = fullRecipe.materials
		item.outputQuantity = fullRecipe.output[1].quantity
		item.buy = fullRecipe.buyPrice
		item.XP = fullRecipe.xp
		item.duration = fullRecipe.duration
		
		-- iterate through materials, keep track of how many materials are needed from each shop
		item.poleShopTrips = 0
		item.metalShopTrips = 0
		for _, material in ipairs(item.materials) do
		
			-- query which shop sold it, add to running total
			local shopNameQuery = '[[:+]][[Sold item::' .. material.name .. ']]|?Sold by #-|mainlabel=' .. material.name
			local shopNameResult = mw.smw.ask(shopNameQuery) or {}
			local shopName = ''

			if shopNameResult[1] and shopNameResult[1]["Sold by"] then
				shopName = shopNameResult[1]["Sold by"] or ''
			end
			
			if shopName=="Timber Merchant Shop" then
				item.poleShopTrips = item.poleShopTrips + material.quantity
			elseif shopName=="Bobble's Oresome Ores" then
				item.metalShopTrips = item.metalShopTrips + material.quantity
			end

		end
		
		-- direct values
		item.sell = item.sell and item.outputQuantity and item.sell * item.outputQuantity
		item.costPerXP = item.buy and item.XP and math.floor(item.buy / item.XP * 100) / 100
		item.XPPerMetal = item.XP and not(item.metalShopTrips==0) and math.floor(item.XP / item.metalShopTrips * 100) / 100

		-- there will be extra time spent buying and selling items, and moving between stations
		-- assume make enough trips to buy 24 of each material from each shop, per batch of 24 weapons
		local batchSize = 24
		-- 120 seconds moving between stations and selling items per 24 made
		-- 40 seconds per trip to the pole shop
		-- 40 seconds per trip to the metal shop
		-- are these results optimal? no. are they approximate? yes
		local downtime = 120 + item.poleShopTrips * 40 + item.metalShopTrips * 40
		item.duration = item.duration and item.duration + downtime/batchSize
		item.productPerHour = item.duration and 1 / item.duration * 3600

		-- properties per hour
		item.XPPerHour = item.XP and item.productPerHour and math.floor(item.XP * item.productPerHour)
		item.buyPerHour = item.buy and item.productPerHour and math.floor(item.buy * item.productPerHour)	
	end

	return results
end

-- make the table
function p.displayTable(results)
	local out = mw.html.create('table')
		:addClass('wikitable sortable')
		:tag('tr')
			:tag('th')
				:wikitext('[[File:Blacksmith small icon.png|15px]]  Level')
			:done()
			:tag('th')
				:wikitext('[[File:Cryoknight small icon.png|15px]] Levels')
			:done()
			:tag('th')
				:attr{ colspan = '3' }
				:wikitext('Products')
			:done()
			:tag('th')
				:wikitext('Materials')
			:done()
			:tag('th')
				:wikitext('Forge')
			:done()
			:tag('th')
				:attr{ colspan = '10' }
				:wikitext('Buy Value')
			:done()
			:tag('th')
				:attr{ colspan = '10' }
				:wikitext('Cost/hr')
			:done()
			:tag('th')
				:wikitext('XP/item')
			:done()
			:tag('th')
				:wikitext('XP/metal')
			:done()
			:tag('th')
				:wikitext('XP/hr')
			:done()
			:tag('th')
				:attr{ colspan = '10' }
				:wikitext('Coins/XP')
			:done()
		:done()

	local unknown_value_cell = mw.html.create('td')
		:addClass('table-bg-gray')
		:css{ ['text-align'] = 'center' }
		:wikitext("''unknown''")

	for i, item in ipairs(results) do
		local row = out:tag('tr')
			:IF(item.lvl)
				:tag('td')
					:css{ ['text-align'] = 'center' }
					:wikitext(item.lvl)
				:done()
			:ELSE()
				:node(unknown_value_cell)
			:END()
			:IF(item.lvlHigh and item.lvlLow)
				:tag('td')
					:css{ ['text-align'] = 'center' }
					:wikitext(item.lvlLow)
					:wikitext(' – ')
					:wikitext(item.lvlHigh)
				:done()
			:ELSE()
				:node(unknown_value_cell)
			:END()

			:tag('td')
				:css{ ['border-right'] = '0', ['padding-right'] = '0', ['text-align'] = 'right' }
				:attr{ ['data-sort-value'] = item.name }
				:wikitext(item.outputQuantity .. ' &times;')
			:done()
			:tag('td')
				:addClass('plinkt-image no-border')
				:css{ ['border-left'] = '0', ['padding-left'] = '0' }	
				:wikitext('[[File:' .. item.name .. '.png|link=' .. item.name .. '|30px]]')
			:done()
			:tag('td')
				:addClass('plinkt-link no-border')
				:wikitext('[[' .. item.name .. ']]')
			:done()

		local materialCell = row:tag('td')

		for i, _ in ipairs(item.materials) do
			materialCell:wikitext(item.materials[i].quantity .. '&times; [[File:' .. item.materials[i].name .. '.png|18px|link=' .. item.materials[i].name .. ']] [[' .. item.materials[i].name .. ']]<br>')
		end
		
		row
			
			:tag('td')
				:wikitext('[[File:' .. item.facility .. '.png|30px|link=' .. item.facility .. ']] [[' .. item.facility .. '|' .. string.gsub(item.facility,' Forge','') .. ']]')
			:done()
			:node(currency_cell(item.buy))
			:node(currency_cell(item.buyPerHour))

			:IF(item.XP)
				:tag('td')
					:wikitext(item.XP and lang:formatNum(tonumber(item.XP)))
				:done()
			:ELSE()
				:node(unknown_value_cell)
			:END()
			
			:IF(item.XPPerMetal)
				:tag('td')
					:wikitext(item.XPPerMetal and lang:formatNum(tonumber(item.XPPerMetal)))
				:done()
			:ELSE()
				:node(unknown_value_cell)
			:END()
			
			:IF(item.XPPerHour)
				:tag('td')
					:wikitext(item.XPPerHour and lang:formatNum(tonumber(item.XPPerHour)))
				:done()
			:ELSE()
				:node(unknown_value_cell)
			:END()

			:node(currency_cell(item.costPerXP))

		:done()
	end

	return out
end

return p