Module:AlchemistPassiveList: Difference between revisions
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', |
||
'? |
'?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', |
||
' |
'?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 |
-- 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 |
|||
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 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 |
|||
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 |
: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) |
||
: |
:done() |
||
:ELSE() |
|||
:addClass('table-bg-grey') |
|||
:node(unknown_value_cell) |
|||
:css{ ['text-align'] = 'center' } |
|||
:END() |
|||
:END() |
|||
:tag('td') |
|||
:css{ ['border-right'] = '0', ['padding-right'] = '0', ['text-align'] = 'right' } |
|||
:attr{ ['data-sort-value'] = item.name } |
|||
:wikitext(item.outputQuantity .. ' ×') |
|||
: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 .. '× [[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( |
: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() |
||
: |
:node(unknown_value_cell) |
||
:addClass('table-na') |
|||
:attr{ colspan = '21' } |
|||
:wikitext('N/A') |
|||
:done() |
|||
:END() |
:END() |
||
:IF(item. |
: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() |
||
: |
: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 .. ' ×')
: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 .. '× [[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