Module:Sandbox/User:Alsang/NodeDescriptionChecker: Difference between revisions
Jump to navigation
Jump to search
Content added Content deleted
m (downtime for leatherworker) |
No edit summary |
||
(9 intermediate revisions by the same user not shown) | |||
Line 1: | Line 1: | ||
p = {} |
|||
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() |
function p.main() |
||
-- returns only directly needed parameter needed for the row, |
|||
local query = {'[[~*(skill node)]]', |
|||
-- other parameters are determined by subqueries of chained pages |
|||
'?= node', |
|||
'?Description=nodeDesc', |
|||
-- this is in testing, uncomment out one line to test that type of query |
|||
'?Has subobject.Dropped item = item', |
|||
-- requires pages to be made and have recipes on them or it tends to get an error |
|||
'?Has subobject.Dropped item.Description=itemDesc', |
|||
-- query types that include non-recipe passive activities behave weird and need to be fixed |
|||
'limit=500', |
|||
local query = { |
|||
'sort=Variant of,Profession Level A' |
|||
--'[[Uses facility::One Handed Range (bonewright)||One Handed Melee Workbench (bonewright)||Two Handed Range Workbench (bonewright)||Two Handed Melee Workbench (bonewright)||Shield Vice (bonewright)]]', -- bonewright active |
|||
--'[[Uses facility::Knickknacks workbench]] OR [[Variant of::Divination||Sabertooth Cat Skeleton||Wooly Mammoth Skeleton||Triceratops Skeleton||T-Rex Skeleton||Wendigo Skeleton||Bonemeal Cement]]', -- bonewright passive |
|||
--'[[Uses facility::One Handed Range (stonemason)||One Handed Melee Workbench (stonemason)||Two Handed Range Workbench (stonemason)||Two Handed Melee Workbench (stonemason)||Shield Vice (stonemason)]]', -- stonemason active |
|||
--'[[Uses facility::Stoneware bench]] OR [[Variant of::Statue Sculpture||Ornamental Scuplture||Column Sculpture||Bust Sculpture]]', -- stonemason passive |
|||
--'[[Uses facility::Goblin Forge||Gnome Forge (skill node)]]', -- blacksmith active |
|||
--'[[Uses facility::Jewelry Bench]]', -- blacksmith passive, no non-recipe |
|||
'[[-Sold item.Sold by::Leather stall]][[Recipe JSON::~*]]', -- leatherworker active, the stall sells scraps and we need to ignore those |
|||
--'[[-Sold item.Sold by::Leather Goods]] OR [[Variant of::Upholstery]]', -- leatherworker passive, but the Upholstery activities dont have pages yet |
|||
'?Uses facility #- = facility', |
|||
'?Profession Level A = lvl', |
|||
'? #- = name', |
|||
'?Recipe JSON = recipeJSON', |
|||
'?Activity XP = XP', |
|||
'?Activity duration = duration', |
|||
'?Value = sell', |
|||
'?Activity coins = coins', |
|||
'sort = Profession Level A', |
|||
'limit = 500' |
|||
} |
} |
||
local results = mw.smw.ask(query) |
local results = mw.smw.ask(query) |
||
local same = {} |
|||
local onlyitem = {} |
|||
local onlynode = {} |
|||
local neither = {} |
|||
local different = {} |
|||
for _,page in ipairs(results) do |
|||
if page.nodeDesc == nil and page.itemDesc == nil then |
|||
table.insert(neither,page) |
|||
elseif page.nodeDesc == nil and page.itemDesc ~= nil then |
|||
table.insert(onlyitem,page) |
|||
elseif page.nodeDesc ~= nil and page.itemDesc == nil then |
|||
table.insert(onlynode,page) |
|||
elseif page.nodeDesc == page.itemDesc then |
|||
table.insert(same,page) |
|||
else |
|||
table.insert(different,page) |
|||
end |
|||
end |
|||
local onlyitemN = 0 |
|||
-- criterion for if an entry is a recipe, or a passive activity |
|||
for _, |
for _,_ in ipairs(onlyitem) do |
||
onlyitemN = onlyitemN + 1 |
|||
item.passiveActivity = false -- can delete this entire FOR statement unless there are non-recipe passive activities on the table |
|||
--item.passiveActivity = not(item.facility=='Upholstery station') -- leatherworker has not got upholstery implemented yet, do not use |
|||
end |
end |
||
local onlynodeN = 0 |
|||
results = p.formatResults(results) |
|||
for _,_ in ipairs(onlynode) do |
|||
onlynodeN = onlynodeN + 1 |
|||
return p.displayTable(results) |
|||
end |
|||
local neitherN = 0 |
|||
--for debugging |
|||
for _,_ in ipairs(neither) do |
|||
--return '<pre>'..mw.text.jsonEncode(results, mw.text.JSON_PRETTY)..'</pre>' |
|||
neitherN = neitherN + 1 |
|||
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 |
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.passiveActivity then |
|||
-- if it is a passive activity that is not a recipe |
|||
-- some fields are easy to work out |
|||
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 differentN = 0 |
|||
local QTYQuery = '[[Recipe output::' .. intermediate.name .. ']]|?Recipe JSON|mainlabel=' .. intermediate.name |
|||
for _,_ in ipairs(different) do |
|||
local QTYResult = mw.smw.ask(QTYQuery) or {} |
|||
differentN = differentN + 1 |
|||
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 |
|||
-- a lot of downtime in leatherworker |
|||
-- 1min 40s to go from hide stall to tannery, run round the tannery, run to leather stall, then back to hide stall |
|||
local batchSize = 24 |
|||
local downtime = 100 |
|||
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 |
end |
||
return results |
|||
end |
|||
-- make the table |
|||
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') |
||
:tag('th') |
|||
:wikitext('[[File:Leatherworker small icon.png|15px]] Level') |
|||
:done() |
|||
:tag('th') |
:tag('th') |
||
:attr{ colspan = '3' } |
:attr{ colspan = '3' } |
||
:wikitext(' |
:wikitext('Nodes with no descriptions') |
||
:done() |
:done() |
||
:tag(' |
:tag('td') |
||
:wikitext( |
:wikitext(onlyitemN) |
||
:done() |
:done() |
||
:done() |
|||
:tag('tr') |
|||
:tag('th') |
:tag('th') |
||
: |
:wikitext('Node') |
||
:wikitext('Buy Value') |
|||
:done() |
:done() |
||
:tag('th') |
:tag('th') |
||
:wikitext('Node description') |
|||
:attr{ colspan = '10' } |
|||
:wikitext('Sell Value') |
|||
:done() |
:done() |
||
:tag('th') |
:tag('th') |
||
: |
:wikitext('Item') |
||
:wikitext('Profit') |
|||
:done() |
:done() |
||
:tag('th') |
:tag('th') |
||
:wikitext('Item description') |
|||
:attr{ colspan = '10' } |
|||
:wikitext('Profit/hr') |
|||
:done() |
:done() |
||
:done() |
|||
for _,page in ipairs(onlyitem) do |
|||
out:tag('tr') |
|||
:tag('td') |
|||
:wikitext(page.node) |
|||
:done() |
|||
:tag('td') |
|||
:wikitext(page.nodeDesc) |
|||
:done() |
|||
:tag('td') |
|||
:wikitext(page.item) |
|||
:done() |
|||
:tag('td') |
|||
:wikitext(page.itemDesc) |
|||
:done() |
|||
:done() |
|||
end |
|||
out:tag('tr') |
|||
:tag('th') |
:tag('th') |
||
:attr{ colspan = '3' } |
|||
:wikitext('[[File:Merchant_small_icon.png|18px]] level for<br>discount') |
|||
:wikitext('Items with no descriptions') |
|||
:done() |
:done() |
||
:tag('td') |
|||
:wikitext(onlynodeN) |
|||
:done() |
|||
:done() |
|||
:tag('tr') |
|||
:tag('th') |
:tag('th') |
||
: |
:wikitext('Node') |
||
:wikitext('Profit/hr<br>with [[File:Merchant_small_icon.png|18px]]') |
|||
:done() |
:done() |
||
:tag('th') |
:tag('th') |
||
:wikitext(' |
:wikitext('Node description') |
||
:done() |
:done() |
||
:tag('th') |
:tag('th') |
||
:wikitext(' |
:wikitext('Item') |
||
:done() |
:done() |
||
:tag('th') |
:tag('th') |
||
:wikitext('Item description') |
|||
:attr{ colspan = '10' } |
|||
:wikitext('Coins/XP') |
|||
:done() |
:done() |
||
:done() |
:done() |
||
for _,page in ipairs(onlynode) do |
|||
local unknown_value_cell = mw.html.create('td') |
|||
: |
out:tag('tr') |
||
:css{ ['text-align'] = 'center' } |
|||
:wikitext("''unknown''") |
|||
for i, item in ipairs(results) do |
|||
local row = out:tag('tr') |
|||
:IF(item.lvl) |
|||
:tag('td') |
:tag('td') |
||
:wikitext(page.node) |
|||
:css{ ['text-align'] = 'center' } |
|||
:done() |
|||
:tag('td') |
|||
:wikitext(page.nodeDesc) |
|||
:done() |
|||
:tag('td') |
|||
:wikitext(page.item) |
|||
:done() |
|||
:tag('td') |
|||
:wikitext(page.itemDesc) |
|||
:done() |
: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() |
:done() |
||
end |
|||
:tag('td') |
|||
:addClass('plinkt-image no-border') |
|||
out:tag('tr') |
|||
:css{ ['border-left'] = '0', ['padding-left'] = '0' } |
|||
:tag('th') |
|||
:wikitext('[[File:' .. item.name .. '.png|link=' .. item.name .. '|30px]]') |
|||
:attr{ colspan = '3' } |
|||
:wikitext('Niether Node nor Item has description') |
|||
:done() |
:done() |
||
:tag('td') |
:tag('td') |
||
:wikitext(neitherN) |
|||
:addClass('plinkt-link no-border') |
|||
:wikitext('[[' .. item.name .. ']]') |
|||
:done() |
:done() |
||
:done() |
|||
:IF(not(item.passiveActivity)) |
|||
:tag('tr') |
|||
:tag('th') |
|||
:wikitext('Node') |
|||
for i, _ in ipairs(item.reagents) do |
|||
reagentCell:wikitext(item.reagents[i].quantity .. '× [[File:' .. item.reagents[i].name .. '.png|30px|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() |
:done() |
||
: |
:tag('th') |
||
:wikitext('Node description') |
|||
:done() |
|||
:tag('th') |
|||
:wikitext('Item') |
|||
:done() |
|||
:tag('th') |
|||
:wikitext('Item description') |
|||
:done() |
|||
:done() |
|||
for _,page in ipairs(neither) do |
|||
:node(currency_cell(item.profit)) |
|||
out:tag('tr') |
|||
:node(currency_cell(item.profitPerHour)) |
|||
:tag('td') |
|||
:wikitext(page.node) |
|||
:done() |
|||
:tag('td') |
|||
:wikitext(page.nodeDesc) |
|||
:done() |
|||
:tag('td') |
|||
:wikitext(page.item) |
|||
:done() |
|||
:tag('td') |
|||
:wikitext(page.itemDesc) |
|||
:done() |
|||
:done() |
|||
end |
|||
out:tag('tr') |
|||
:tag('th') |
|||
:attr{ colspan = '3' } |
|||
:wikitext('Node and Item both have descriptions, but they are different') |
|||
:done() |
|||
:tag('td') |
:tag('td') |
||
:wikitext(differentN) |
|||
:css{ ['text-align'] = 'center' } |
|||
:wikitext('???') |
|||
:done() |
:done() |
||
:done() |
|||
:node(currency_cell(item.profitPerHour)) |
|||
:tag('tr') |
|||
:tag('th') |
|||
:wikitext('Node') |
|||
:done() |
|||
:tag('th') |
|||
:wikitext('Node description') |
|||
:done() |
|||
:tag('th') |
|||
:wikitext('Item') |
|||
:done() |
|||
:tag('th') |
|||
:wikitext('Item description') |
|||
:done() |
|||
:done() |
|||
for _,page in ipairs(different) do |
|||
out:tag('tr') |
|||
:tag('td') |
:tag('td') |
||
:wikitext( |
:wikitext(page.node) |
||
:done() |
:done() |
||
:ELSE() |
|||
:node(unknown_value_cell) |
|||
:END() |
|||
:IF(item.XPPerHour) |
|||
:tag('td') |
:tag('td') |
||
:wikitext( |
:wikitext(page.nodeDesc) |
||
:done() |
:done() |
||
: |
:tag('td') |
||
: |
:wikitext(page.item) |
||
: |
:done() |
||
:tag('td') |
|||
:wikitext(page.itemDesc) |
|||
:node(currency_cell(item.profitPerXP)) |
|||
:done() |
|||
:done() |
:done() |
||
end |
|||
return out |
return out |
||
end |
end |
||
return p |
return p |
Latest revision as of 15:41, 31 December 2024
Module documentation
This documentation is transcluded from Module:Sandbox/User:Alsang/NodeDescriptionChecker/doc. [edit] [history] [purge]
This module does not have any documentation. Please consider adding documentation at Module:Sandbox/User:Alsang/NodeDescriptionChecker/doc. [edit]
Module:Sandbox/User:Alsang/NodeDescriptionChecker's function main is invoked by Template:Sandbox/User:Alsang/NodeDescriptionChecker.
p = {}
function p.main()
local query = {'[[~*(skill node)]]',
'?= node',
'?Description=nodeDesc',
'?Has subobject.Dropped item = item',
'?Has subobject.Dropped item.Description=itemDesc',
'limit=500',
'sort=Variant of,Profession Level A'
}
local results = mw.smw.ask(query)
local same = {}
local onlyitem = {}
local onlynode = {}
local neither = {}
local different = {}
for _,page in ipairs(results) do
if page.nodeDesc == nil and page.itemDesc == nil then
table.insert(neither,page)
elseif page.nodeDesc == nil and page.itemDesc ~= nil then
table.insert(onlyitem,page)
elseif page.nodeDesc ~= nil and page.itemDesc == nil then
table.insert(onlynode,page)
elseif page.nodeDesc == page.itemDesc then
table.insert(same,page)
else
table.insert(different,page)
end
end
local onlyitemN = 0
for _,_ in ipairs(onlyitem) do
onlyitemN = onlyitemN + 1
end
local onlynodeN = 0
for _,_ in ipairs(onlynode) do
onlynodeN = onlynodeN + 1
end
local neitherN = 0
for _,_ in ipairs(neither) do
neitherN = neitherN + 1
end
local differentN = 0
for _,_ in ipairs(different) do
differentN = differentN + 1
end
local out = mw.html.create('table')
:addClass('wikitable sortable')
:tag('tr')
:tag('th')
:attr{ colspan = '3' }
:wikitext('Nodes with no descriptions')
:done()
:tag('td')
:wikitext(onlyitemN)
:done()
:done()
:tag('tr')
:tag('th')
:wikitext('Node')
:done()
:tag('th')
:wikitext('Node description')
:done()
:tag('th')
:wikitext('Item')
:done()
:tag('th')
:wikitext('Item description')
:done()
:done()
for _,page in ipairs(onlyitem) do
out:tag('tr')
:tag('td')
:wikitext(page.node)
:done()
:tag('td')
:wikitext(page.nodeDesc)
:done()
:tag('td')
:wikitext(page.item)
:done()
:tag('td')
:wikitext(page.itemDesc)
:done()
:done()
end
out:tag('tr')
:tag('th')
:attr{ colspan = '3' }
:wikitext('Items with no descriptions')
:done()
:tag('td')
:wikitext(onlynodeN)
:done()
:done()
:tag('tr')
:tag('th')
:wikitext('Node')
:done()
:tag('th')
:wikitext('Node description')
:done()
:tag('th')
:wikitext('Item')
:done()
:tag('th')
:wikitext('Item description')
:done()
:done()
for _,page in ipairs(onlynode) do
out:tag('tr')
:tag('td')
:wikitext(page.node)
:done()
:tag('td')
:wikitext(page.nodeDesc)
:done()
:tag('td')
:wikitext(page.item)
:done()
:tag('td')
:wikitext(page.itemDesc)
:done()
:done()
end
out:tag('tr')
:tag('th')
:attr{ colspan = '3' }
:wikitext('Niether Node nor Item has description')
:done()
:tag('td')
:wikitext(neitherN)
:done()
:done()
:tag('tr')
:tag('th')
:wikitext('Node')
:done()
:tag('th')
:wikitext('Node description')
:done()
:tag('th')
:wikitext('Item')
:done()
:tag('th')
:wikitext('Item description')
:done()
:done()
for _,page in ipairs(neither) do
out:tag('tr')
:tag('td')
:wikitext(page.node)
:done()
:tag('td')
:wikitext(page.nodeDesc)
:done()
:tag('td')
:wikitext(page.item)
:done()
:tag('td')
:wikitext(page.itemDesc)
:done()
:done()
end
out:tag('tr')
:tag('th')
:attr{ colspan = '3' }
:wikitext('Node and Item both have descriptions, but they are different')
:done()
:tag('td')
:wikitext(differentN)
:done()
:done()
:tag('tr')
:tag('th')
:wikitext('Node')
:done()
:tag('th')
:wikitext('Node description')
:done()
:tag('th')
:wikitext('Item')
:done()
:tag('th')
:wikitext('Item description')
:done()
:done()
for _,page in ipairs(different) do
out:tag('tr')
:tag('td')
:wikitext(page.node)
:done()
:tag('td')
:wikitext(page.nodeDesc)
:done()
:tag('td')
:wikitext(page.item)
:done()
:tag('td')
:wikitext(page.itemDesc)
:done()
:done()
end
return out
end
return p