Module:AlchemistPassiveList: Difference between revisions

From Brighter Shores Wiki
Jump to navigation Jump to search
Content added Content deleted
m (remove vestigal reference to KP that aren't use any more, add some commenting for how it calculates input price)
(change code base to match PotionList which uses extensive search for all subreceipes and reagents, but keep it showing non-recipe passive activities)
Line 1: Line 1:
require('strict')
require('Module:Mw.html extension')
require('Module:Mw.html extension')
local recipe = require('Module:Infobox Recipe') -- to make use of its extensive material searching function
local param = require( 'Module:Paramtest' )
local param = require( 'Module:Paramtest' )
local currency = require('Module:Currency')
local currency = require('Module:Currency')
local lang = mw.getContentLanguage()
local lang = mw.getContentLanguage()
require("Module:Mw.html extension")



local p = {}
local p = {}
Line 10: Line 10:
-- non dynamic module, no inputs
-- non dynamic module, no inputs
function p.main()
function p.main()
-- returns only directly needed parameter needed for the row,
-- other parameters are determined by subqueries of chained pages
-- returns almost every parameter needed for the row, except buy values for reagents
local query = {
local query = {
'[[Uses facility::Passive Potion Station]] OR [[Variant of::Ebsworth Work]]',
'[[Uses facility::Passive Potion Station]] OR [[Variant of::Ebsworth Work]]',
'?Profession Level A = lvl',
'?Profession Level A = lvl',
'? #- = name',
'? #- = name',
'?Uses item #- = reagents',
'?Recipe JSON = recipeJSON',
'?Value #- = sell',
'?Activity coins = coins',
'?Activity XP = XP',
'?Activity XP = XP',
'?Activity duration = duration',
'?Activity duration = duration',
'?Activity coins = coins',
'?Variant of #- = variant',
'?Variant of #- = variant',
'sort = Profession Level A'
'?Value = sell',
'sort = Profession Level A',
'limit = 500'
}
}
local results = mw.smw.ask(query)
local results = mw.smw.ask(query)

results = p.formatResults(results)
results = p.formatResults(results)


Line 35: Line 36:
end
end


-- makes the html for the cells containing currency directly, no tags needed
-- makes the html for the cells containing currency directly
-- Replaces nil with an "unknown" cell
local function currency_cell(amount)
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' })
return currency._cell(amount, { html = 'yes' })
end
end
Line 43: Line 53:
function p.formatResults(results)
function p.formatResults(results)


-- iterate through potions
-- iterate through potions
for i, item in ipairs(results) do
for _, item in ipairs(results) do
-- recipe in a workable format
-- potions have reagents, but passive ebsworth work does not
if item.variant=='Ebsworth Work' then
if item.variant=='Ebsworth Work' then
-- if it is ebsworth work, sub in different fields for the buy and sell values
-- if it is ebsworth work, sub in different fields for the buy and sell values
item.outputQuantity = 1
item.reagents = {}
item.intermediates = {}
item.buy = 0
item.buy = 0
item.sell = item.coins
item.sell = item.coins
else
else
-- iterate through reagents, adding buy price to running total (individuals not needed)
-- potions always follow the same format, where the reagents are one level down
-- if copying this code for another profession, will need to change how you identify the inputs.
-- starting value 20 is for bottle
item.buy = 20
for j, reagent in ipairs(item.reagents) do
local unpackJSON = mw.text.jsonDecode(item.recipeJSON)
--shamelessley lifted from Module:Products
item.outputQuantity = unpackJSON.output[1].quantity
local shopPriceQuery = '[[:+]][[Sold item::' .. reagent .. ']]|?Shop buy price|mainlabel=' .. reagent
local shopPriceResult = mw.smw.ask(shopPriceQuery) or {}
-- call the module:infobox recipe to extensively search for
local shopPrice = 0
-- all raw materials (to add to prices)
-- all intermediate materials (for intermediate XP and duration)
local Materials = recipe._getTrueRawMaterials(unpackJSON.materials)
if next(Materials) ~= nil then
item.reagents = Materials.rawMaterials
item.intermediates = Materials.intermediateMaterials
end
-- iterate through reagents, adding buy price to running total (individuals not needed)
item.buy = 0
for _, reagent in ipairs(item.reagents) do
--shamelessley lifted from Module:Products
local shopPriceQuery = '[[:+]][[Sold item::' .. reagent.name .. ']]|?Shop buy price|mainlabel=' .. reagent.name
local shopPriceResult = mw.smw.ask(shopPriceQuery) or {}
local shopPrice = 0
if shopPriceResult[1] and shopPriceResult[1]["Shop buy price"] then
shopPrice = tonumber(shopPriceResult[1]["Shop buy price"]) or 0
else
item.buy = nil
end
item.buy = item.buy and item.buy + shopPrice * reagent.quantity
end
-- iterate through intermediaries to add to XP and duration parameters
for _, intermediate in ipairs(item.intermediates) do
-- look up activity XP and add it to running total
local XPQuery = '[[Recipe output::' .. intermediate.name .. ']]|?Activity XP|mainlabel=' .. intermediate.name
local XPResult = mw.smw.ask(XPQuery) or {}
local XPIncrease = 0
if XPResult[1] and XPResult[1]["Activity XP"] then
XPIncrease = tonumber(XPResult[1]["Activity XP"]) or 0
else
XPIncrease = nil
end
-- need to look up both the amount of the item used in this recipe and created in its own recipe to know how much of this xp to use
local QTYused = intermediate.quantity
local QTYQuery = '[[Recipe output::' .. intermediate.name .. ']]|?Recipe JSON|mainlabel=' .. intermediate.name
local QTYResult = mw.smw.ask(QTYQuery) or {}
local QTYmade = 0
if QTYResult[1] and QTYResult[1]["Recipe JSON"] then
QTYmade = mw.text.jsonDecode(QTYResult[1]["Recipe JSON"]) or {}
end
QTYmade = QTYmade.output[1].quantity
item.XP = item.XP and XPIncrease and item.XP + XPIncrease * QTYused / QTYmade;
-- look up activity duration and add it to running total
local durationQuery = '[[Recipe output::' .. intermediate.name .. ']]|?Activity duration|mainlabel=' .. intermediate.name
local durationResult = mw.smw.ask(durationQuery) or {}
local durationIncrease = 0
if durationResult[1] and durationResult[1]["Activity duration"] then
durationIncrease = tonumber(durationResult[1]["Activity duration"]) or 0
else
durationIncrease = nil
end
item.duration = item.duration and durationIncrease and item.duration + durationIncrease * intermediate.quantity
end
end
-- direct values
item.sell = item.sell and item.outputQuantity and item.sell * item.outputQuantity
item.profit = item.sell and item.buy and item.sell - item.buy
item.profitPerXP = item.profit and item.XP and math.floor(item.profit / item.XP * 100) / 100


-- potions made in 200 lots of 0.005, no downtime for passive activities
if shopPriceResult[1] and shopPriceResult[1]["Shop buy price"] then
local batchSize = 200
shopPrice = tonumber(shopPriceResult[1]["Shop buy price"]) or 0
local downtime = 0
end
item.duration = item.duration and item.duration + downtime/batchSize
item.potionPerHour = item.duration and 1 / item.duration * 3600
item.buy = item.buy + shopPrice

end
-- properties per hour
end
item.XPPerHour = item.XP and item.potionPerHour and math.floor(item.XP * item.potionPerHour)
item.profitPerHour = item.profit and item.potionPerHour and math.floor(item.profit * item.potionPerHour)
-- sanitise data, set to 0 if its not there
local lvl = item.lvl or '?'
local buy = item.buy or 0
local sell = item.sell or 0
local XP = item.XP or 0
local duration = item.duration or 0
-- flags for if data values should be shown
item.hasLvl = param.has_content(item.lvl)
item.hasBuy = param.has_content(item.buy)
item.hasSell = param.has_content(item.sell)
item.hasProfit = item.hasBuy and item.hasSell
item.hasXP = param.has_content(item.XP)
item.hasDuration = param.has_content(item.duration)
-- direct values
if item.variant=='Ebsworth Work' then
item.profit = sell - buy
else
item.profit = (sell - buy)*0.005 -- passive potions all have quantity 0.005 per action
end
item.XP = XP
if item.XP==0 then
item.profitPerXP = 0
else
item.profitPerXP = math.floor(item.profit / (item.XP) * 100) / 100
end
-- passive activities have no downtime
item.duration = duration
if item.duration == 0 then
item.potionPerHour = 0
else
item.potionPerHour = 1 / (item.duration) * 3600
end
-- properties per hour
item.XPPerHour = math.floor(item.XP * item.potionPerHour)
item.profitPerHour = math.floor(item.profit * item.potionPerHour)
end
end


return results
return results
end
end


-- make the table
-- make the table
function p.displayTable(results)
function p.displayTable(results)
local out = mw.html.create('table')
local out = mw.html.create('table')
:addClass('wikitable sortable')
:addClass('wikitable sortable')
:tag('tr')
:tag('tr')
Line 129: Line 168:
:done()
:done()
:tag('th')
:tag('th')
:attr{ colspan = '3' }
:wikitext('Potion or Activity')
:wikitext('Potion')
:done()
:done()
:tag('th')
:tag('th')
:wikitext('Reagents (plus bottle)')
:wikitext('Reagents')
:done()
:done()
:tag('th')
:tag('th')
Line 161: Line 201:
:done()
:done()
:done()
:done()

local unknown_value_cell = mw.html.create('td')
:addClass('table-bg-gray')
:css{ ['text-align'] = 'center' }
for i,item in ipairs(results) do
:wikitext("''unknown''")

-- if its not ebsworth work, need a list of reagents
for i, item in ipairs(results) do
local reagentCell = ''
local row = out:tag('tr')
if not(item.variant=='Ebsworth Work') then
:IF(item.lvl)
-- need to generate the text for the reagent cell before starting the row
:tag('td')
for j, reagent in ipairs(item.reagents) do
reagentCell = reagentCell .. '[[File:' .. reagent .. '.png|30px|link=' .. reagent .. ']] [[' .. reagent .. ']]<br>'
end
end
out
:tag('tr')
:tag('td')
:IF(item.hasBuy)
:css{ ['text-align'] = 'center' }
:css{ ['text-align'] = 'center' }
:wikitext(item.lvl)
:wikitext(item.lvl)
:ELSE()
:done()
:ELSE()
:addClass('table-bg-grey')
:node(unknown_value_cell)
:css{ ['text-align'] = 'center' }
:wikitext('unknown')
:END()

: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()
:done()
:IF(not(item.variant=='Ebsworth Work'))

local reagentCell = row:tag('td')
for i, _ in ipairs(item.reagents) do
reagentCell:wikitext(item.reagents[i].quantity .. '&times; [[File:' .. item.reagents[i].name .. '.png|18px|link=' .. item.reagents[i].name .. ']]' .. '[[' .. item.reagents[i].name .. ']]<br>')
end
row
:node(currency_cell(item.buy))
:node(currency_cell(item.sell))
:ELSE()
:tag('td')
:tag('td')
:addClass('table-na')
:wikitext('[[File:' .. item.name .. '.png|30px|link=' .. item.name .. ']] [[' .. item.name .. ']]')
:attr{ colspan = '21' }
:wikitext('N/A')
:done()
:done()
:END()
:IF(not(item.variant=='Ebsworth Work'))
:node(currency_cell(item.profit))
:node(currency_cell(item.profitPerHour))

:IF(item.XP)
:tag('td')
:tag('td')
:wikitext(reagentCell)
:wikitext(item.XP and lang:formatNum(tonumber(item.XP)))
:done()
:done()
:IF(item.hasBuy)
:node(currency_cell(item.buy))
:ELSE()
:tag('td')
:addClass('table-bg-grey')
:attr{ colspan = '10' }
:css{ ['text-align'] = 'center' }
:wikitext('unknown')
:done()
:END()
:IF(item.hasSell)
-- I cannot for the life of me figure out why,
-- but if I put item.sell directly into this function it claims it has value nil
-- it works for other functions to display it directly
-- so here is the workaround I guess
:node(currency_cell(item.buy+200*item.profit))
--:node(currency_cell(item.sell))
:ELSE()
:tag('td')
:addClass('table-bg-grey')
:attr{ colspan = '10' }
:css{ ['text-align'] = 'center' }
:wikitext('unknown')
:done()
:END()
:ELSE()
:ELSE()
:tag('td')
:node(unknown_value_cell)
:addClass('table-na')
:attr{ colspan = '21' }
:wikitext('N/A')
:done()
:END()
:END()

:IF(item.hasProfit)
:IF(item.XPPerHour)
:node(currency_cell(item.profit))
:ELSE()
:tag('td')
:tag('td')
:wikitext(item.XPPerHour and lang:formatNum(tonumber(item.XPPerHour)))
:addClass('table-bg-grey')
:attr{ colspan = '10' }
:css{ ['text-align'] = 'center' }
:wikitext('unknown')
:done()
:done()
:END()
:IF(item.hasProfit and item.hasDuration)
:node(currency_cell(item.profitPerHour))
:ELSE()
:ELSE()
:tag('td')
:node(unknown_value_cell)
:addClass('table-bg-grey')
:attr{ colspan = '10' }
:css{ ['text-align'] = 'center' }
:wikitext('unknown')
:done()
:END()
:END()

:node(currency_cell(item.profitPerXP))
:tag('td')

:IF(item.hasXP)
:wikitext(item.XP)
:ELSE()
:addClass('table-bg-grey')
:css{ ['text-align'] = 'center' }
:wikitext('unknown')
:END()
:done()
:tag('td')
:IF(item.hasXP and item.hasDuration)
:wikitext(lang:formatNum(tonumber(item.XPPerHour)))
:ELSE()
:addClass('table-bg-grey')
:css{ ['text-align'] = 'center' }
:wikitext('unknown')
:END()
:done()
:IF(item.hasXP and item.hasProfit)
:node(currency_cell(item.profitPerXP))
:ELSE()
:tag('td')
:addClass('table-bg-grey')
:attr{ colspan = '10' }
:css{ ['text-align'] = 'center' }
:wikitext('unknown')
:done()
:END()
:done()
:done()
end
end

return out
return out
end
end

Revision as of 02:31, 2 December 2024

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

require('strict')
require('Module:Mw.html extension')
local recipe = require('Module:Infobox Recipe') -- to make use of its extensive  material searching function
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::Passive Potion Station]] OR [[Variant of::Ebsworth Work]]',
		'?Profession Level A = lvl',
		'? #- = name',
		'?Recipe JSON = recipeJSON',
		'?Activity XP = XP',
		'?Activity duration = duration',
		'?Activity coins = coins',
		'?Variant of #- = variant',
		'?Value = sell',
		'sort = Profession Level A',
		'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 potions
	for _, item in ipairs(results) do
		
		-- recipe in a workable format
		if item.variant=='Ebsworth Work' then
			
			-- if it is ebsworth work, sub in different fields for the buy and sell values
    		item.outputQuantity = 1
    		item.reagents = {}
    		item.intermediates = {}
    		item.buy = 0
    		item.sell = item.coins
    	
    	else
    		
			local unpackJSON = mw.text.jsonDecode(item.recipeJSON)
			item.outputQuantity = unpackJSON.output[1].quantity
	
			-- call the module:infobox recipe to extensively search for 
			-- all raw materials (to add to prices) 
			-- all intermediate materials (for intermediate XP and duration)
			local Materials = recipe._getTrueRawMaterials(unpackJSON.materials)
			if next(Materials) ~= nil then
				item.reagents = Materials.rawMaterials
				item.intermediates = Materials.intermediateMaterials
			end
			
			-- iterate through reagents, adding buy price to running total (individuals not needed)
			item.buy = 0
			for _, reagent in ipairs(item.reagents) do
			
				--shamelessley lifted from Module:Products
				local shopPriceQuery = '[[:+]][[Sold item::' .. reagent.name .. ']]|?Shop buy price|mainlabel=' .. reagent.name
				local shopPriceResult = mw.smw.ask(shopPriceQuery) or {}
				local shopPrice = 0		
				
				if shopPriceResult[1] and shopPriceResult[1]["Shop buy price"] then
					shopPrice = tonumber(shopPriceResult[1]["Shop buy price"]) or 0
				else
					item.buy = nil
					end
	
				item.buy = item.buy and item.buy + shopPrice * reagent.quantity
				
			end
			
			-- iterate through intermediaries to add to XP and duration parameters
			for _, intermediate in ipairs(item.intermediates) do
				
				-- look up activity XP and add it to running total
				local XPQuery = '[[Recipe output::' .. intermediate.name .. ']]|?Activity XP|mainlabel=' .. intermediate.name
				local XPResult = mw.smw.ask(XPQuery) or {}
				local XPIncrease = 0
				if XPResult[1] and XPResult[1]["Activity XP"] then
					XPIncrease =  tonumber(XPResult[1]["Activity XP"]) or 0
				else
					XPIncrease = nil
				end
				
				-- need to look up both the amount of the item used in this recipe and created in its own recipe to know how much of this xp to use
				local QTYused = intermediate.quantity		
	
				local QTYQuery = '[[Recipe output::' .. intermediate.name .. ']]|?Recipe JSON|mainlabel=' .. intermediate.name
				local QTYResult = mw.smw.ask(QTYQuery) or {}
				local QTYmade = 0
				if QTYResult[1] and QTYResult[1]["Recipe JSON"] then
					QTYmade =  mw.text.jsonDecode(QTYResult[1]["Recipe JSON"]) or {}
				end
				QTYmade = QTYmade.output[1].quantity
				
				item.XP = item.XP and XPIncrease and item.XP + XPIncrease * QTYused / QTYmade;
				
				-- look up activity duration and add it to running total
				local durationQuery = '[[Recipe output::' .. intermediate.name .. ']]|?Activity duration|mainlabel=' .. intermediate.name
				local durationResult = mw.smw.ask(durationQuery) or {}
				local durationIncrease = 0
				if durationResult[1] and durationResult[1]["Activity duration"] then
					durationIncrease =  tonumber(durationResult[1]["Activity duration"]) or 0
				else
					durationIncrease = nil
				end
				item.duration = item.duration and durationIncrease and item.duration + durationIncrease * intermediate.quantity
				
			end
			
		end
		
		-- direct values
		item.sell = item.sell and item.outputQuantity and item.sell * item.outputQuantity
		item.profit = item.sell and item.buy and item.sell - item.buy
		item.profitPerXP = item.profit and item.XP and math.floor(item.profit / item.XP * 100) / 100

		-- potions made in 200 lots of 0.005, no downtime for passive activities
		local batchSize = 200
		local downtime = 0
		item.duration = item.duration and item.duration + downtime/batchSize
		item.potionPerHour = item.duration and 1 / item.duration * 3600

		-- properties per hour
		item.XPPerHour = item.XP and item.potionPerHour and math.floor(item.XP * item.potionPerHour)
		item.profitPerHour = item.profit and item.potionPerHour and math.floor(item.profit * item.potionPerHour)
	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:Alchemist small icon.png|15px]]  Level')
			:done()
			:tag('th')
				:attr{ colspan = '3' }
				:wikitext('Potion')
			:done()
			:tag('th')
				:wikitext('Reagents')
			:done()
			:tag('th')
				:attr{ colspan = '10' }
				:wikitext('Buy Value')
			:done()
			:tag('th')
				:attr{ colspan = '10' }
				:wikitext('Sell Value')
			:done()
			:tag('th')
				:attr{ colspan = '10' }
				:wikitext('Profit')
			:done()
			:tag('th')
				:attr{ colspan = '10' }
				:wikitext('Profit/hr')
			:done()
			:tag('th')
				:wikitext('XP')
			: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()

			: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()
			
		:IF(not(item.variant=='Ebsworth Work'))

			local reagentCell = row:tag('td')
	
			for i, _ in ipairs(item.reagents) do
				reagentCell:wikitext(item.reagents[i].quantity .. '&times; [[File:' .. item.reagents[i].name .. '.png|18px|link=' .. item.reagents[i].name .. ']]' .. '[[' .. item.reagents[i].name .. ']]<br>')
			end
			
			row
				:node(currency_cell(item.buy))
				:node(currency_cell(item.sell))
				
		:ELSE()
			:tag('td')
				:addClass('table-na')
				:attr{ colspan = '21' }
				:wikitext('N/A')
			:done()
		:END()	
			
		
			:node(currency_cell(item.profit))
			:node(currency_cell(item.profitPerHour))

			:IF(item.XP)
				:tag('td')
					:wikitext(item.XP and lang:formatNum(tonumber(item.XP)))
				: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.profitPerXP))

		:done()
	end

	return out
end

return p