2,875
edits
No edit summary |
No edit summary |
||
Line 118: | Line 118: | ||
table.sort(itemArray, function(a, b) return a.weight > b.weight end) | table.sort(itemArray, function(a, b) return a.weight > b.weight end) | ||
local | local html = mw.html.create('table') | ||
html:addClass('wikitable sortable stickyHeader') | |||
-- Add header row | |||
local headerRow = html:tag('tr'):addClass('headerRow-0') | |||
headerRow:tag('th'):attr('colspan', '2'):wikitext('Item') | |||
headerRow:tag('th'):wikitext('Value') | |||
headerRow:tag('th'):attr('colspan', '2'):wikitext('Chance') | |||
-- Add item rows | |||
for i, itemDef in ipairs(itemArray) do | for i, itemDef in ipairs(itemArray) do | ||
local item = Items.getItemByID(itemDef.itemID) | local item = Items.getItemByID(itemDef.itemID) | ||
Line 128: | Line 135: | ||
-- If chance is less than 0.10% then show 2 significant figures, otherwise 2 decimal places | -- If chance is less than 0.10% then show 2 significant figures, otherwise 2 decimal places | ||
local fmt = (dropChance < 0.10 and '%.2g') or '%.2f' | local fmt = (dropChance < 0.10 and '%.2g') or '%.2f' | ||
local row = html:tag('tr') | |||
row:tag('td'):addClass('table-img'):wikitext(Icons.Icon({item.name, type='item', notext=true})) | |||
row:tag('td'):wikitext(Icons.Icon({item.name, type='item', noicon=true})) | |||
row:tag('td') | |||
:attr('data-sort-value', item.sellsFor) | |||
:wikitext(Items.getValueText(item)) | |||
row:tag('td') | |||
:css('text-align', 'right') | |||
:attr('data-sort-value', itemDef.weight) | |||
:wikitext(Shared.fraction(itemDef.weight, totalWt)) | |||
row:tag('td') | |||
:css('text-align', 'right') | |||
:wikitext(string.format(fmt, dropChance) .. '%') | |||
if lootValue[currID] == nil then | if lootValue[currID] == nil then | ||
lootValue[currID] = 0 | lootValue[currID] = 0 | ||
Line 139: | Line 156: | ||
end | end | ||
end | end | ||
return | local result = tostring(html) | ||
local averageValueText = 'The average value of a roll on the special fishing loot table is ' .. lootValueText(lootValue) | |||
return result .. '\n' .. averageValueText | |||
end | end | ||
function p.getFishingJunkTable(frame) | function p.getFishingJunkTable(frame) | ||
local | local html = mw.html.create('table') | ||
html:addClass('wikitable sortable stickyHeader') | |||
-- Add header row | |||
local headerRow = html:tag('tr'):addClass('headerRow-0') | |||
headerRow:tag('th'):attr('colspan', '2'):wikitext('Item') | |||
headerRow:tag('th'):wikitext('Value') | |||
local itemArray = {} | local itemArray = {} | ||
Line 158: | Line 180: | ||
table.sort(itemArray, function(a, b) return a.name < b.name end) | table.sort(itemArray, function(a, b) return a.name < b.name end) | ||
-- Add item rows | |||
for i, item in ipairs(itemArray) do | for i, item in ipairs(itemArray) do | ||
local row = html:tag('tr') | |||
row:tag('td'):addClass('table-img') | |||
:wikitext(Icons.Icon({item.name, type='item', notext=true})) | |||
row:tag('td'):wikitext(Icons.Icon({item.name, type='item', noicon=true})) | |||
row:tag('td') | |||
:attr('data-sort-value', item.sellsFor) | |||
:wikitext(Items.getValueText(item)) | |||
end | end | ||
return | return tostring(html) | ||
end | end | ||
Line 269: | Line 295: | ||
end | end | ||
local | local html = mw.html.create('table') | ||
:addClass('wikitable sortable') | |||
-- Add header row | |||
local headerRow = html:tag('tr'):addClass('headerRow-0') | |||
:tag('th'):wikitext('Gem') | |||
:attr('colspan', '2') | |||
:tag('th'):wikitext('[[DLC]]') | |||
:tag('th'):wikitext('Gem Chance') | |||
:tag('th'):wikitext('Gem Price') | |||
-- Add gem rows | |||
for i, gem in ipairs(gemData) do | for i, gem in ipairs(gemData) do | ||
local gemItem = Items.getItemByID(gem.itemID) | local gemItem = Items.getItemByID(gem.itemID) | ||
local gemPct = gem.weight / totalWeight * 100 | local gemPct = gem.weight / totalWeight * 100 | ||
local row = html:tag('tr') | |||
row:tag('td'):addClass('table-img') | |||
:wikitext(Icons.Icon({gemItem.name, type='item', notext=true})) | |||
row:tag('td'):attr('data-sort-value', gemItem.name) | |||
:wikitext('[[' .. gemItem.name ..']]') | |||
row:tag('td'):wikitext(Icons.getDLCColumnIcon(gemItem.id)) | |||
:attr('data-sort-value', Icons.getExpansionID(gemItem.id)) | |||
:css('text-align', 'center') | |||
row:tag('td'):css('text-align', 'right') | |||
:attr('data-sort-value', gemPct) | |||
:wikitext(string.format("%.1f%%", gemPct)) | |||
row:tag('td'):attr('data-sort-value', gemItem.sellsFor) | |||
:wikitext(Items.getValueText(gemItem)) | |||
end | end | ||
return tostring(html) | |||
return | |||
end | end | ||
Line 302: | Line 343: | ||
local skillID = 'Fishing' | local skillID = 'Fishing' | ||
local recipeList = GameData.getEntities(SkillData.Fishing.fish, | local recipeList = GameData.getEntities(SkillData.Fishing.fish, function(obj) | ||
return Skills.getRecipeRealm(obj) == realm.id | |||
end) | |||
table.sort(recipeList, function(a, b) return Skills.standardRecipeSort(skillID, a, b) end) | table.sort(recipeList, function(a, b) return Skills.standardRecipeSort(skillID, a, b) end) | ||
Line 321: | Line 360: | ||
end | end | ||
local | local html = mw.html.create('table') | ||
html:addClass('wikitable sortable stickyHeader') | |||
-- Add header row | |||
local headerRow0 = html:tag('tr'):addClass('headerRow-0') | |||
headerRow0:tag('th'):attr('colspan', '2'):attr('rowspan', '2'):wikitext('Fish') | |||
headerRow0:tag('th'):attr('rowspan', '2'):wikitext(Icons.Icon({'Fishing', type='skill', notext=true}) .. '<br>Level') | |||
headerRow0:tag('th'):attr('rowspan', '2'):wikitext('[[DLC]]') | |||
headerRow0:tag('th'):attr('colspan', '3'):wikitext('Catch Time') | |||
headerRow0:tag('th'):attr('rowspan', '2'):wikitext('XP') | |||
headerRow0:tag('th'):attr('rowspan', '2'):wikitext('Value') | |||
headerRow0:tag('th'):attr('rowspan', '2'):wikitext('XP/s') | |||
local headerRow1 = html:tag('tr'):addClass('headerRow-1') | |||
headerRow1:tag('th'):wikitext('Min') | |||
headerRow1:tag('th'):wikitext('Max') | |||
headerRow1:tag('th'):wikitext('Avg') | |||
-- Add fish rows | |||
for i, recipe in ipairs(recipeList) do | for i, recipe in ipairs(recipeList) do | ||
local fish = Items.getItemByID(recipe.productId) | local fish = Items.getItemByID(recipe.productId) | ||
Line 334: | Line 385: | ||
local timeAvg = (timeMin + timeMax) / 2 | local timeAvg = (timeMin + timeMax) / 2 | ||
local timeSortVal = (recipe.baseMinInterval + recipe.baseMaxInterval) / 2000 | local timeSortVal = (recipe.baseMinInterval + recipe.baseMaxInterval) / 2000 | ||
local level = Skills.getRecipeLevel(skillID, recipe) | local level = Skills.getRecipeLevel(skillID, recipe) | ||
local reqText = Skills.getRecipeRequirementText(skillID, recipe) | local reqText = Skills.getRecipeRequirementText(skillID, recipe) | ||
Line 340: | Line 390: | ||
local XPSec = baseXP / timeSortVal | local XPSec = baseXP / timeSortVal | ||
local sellCurrency = fish.sellsForCurrency or 'melvorD:GP' | local sellCurrency = fish.sellsForCurrency or 'melvorD:GP' | ||
local | |||
local row = html:tag('tr') | |||
row:tag('td') | |||
:addClass('table-img') | |||
:wikitext(Icons.Icon({fish.name, type='item', notext=true})) | |||
row:tag('td') | |||
:attr('data-sort-value', fish.name) | |||
:wikitext('[[' .. fish.name .. ']]') | |||
row:tag('td') | |||
:css('text-align', 'center') | |||
:attr('data-sort-value', level) | |||
:wikitext(level) | |||
row:tag('td') | |||
:css('text-align', 'center') | |||
:attr('data-sort-value', Icons.getExpansionID(fish.id)) | |||
:wikitext(Icons.getDLCColumnIcon(fish.id)) | |||
row:tag('td') | |||
:css('text-align', 'right') | |||
:attr('data-sort-value', timeMin) | |||
:wikitext(string.format("%.1fs", timeMin)) | |||
row:tag('td') | |||
:css('text-align', 'right') | |||
:attr('data-sort-value', timeMax) | |||
:wikitext(string.format("%.1fs", timeMax)) | |||
row:tag('td') | |||
:css('text-align', 'right') | |||
:attr('data-sort-value', timeAvg) | |||
:wikitext(string.format("%.1fs", timeAvg)) | |||
row:tag('td') | |||
:css('text-align', 'right') | |||
:attr('data-sort-value', baseXP) | |||
:wikitext(Shared.formatnum(baseXP)) | |||
row:tag('td') | |||
:attr('data-sort-value', fish.sellsFor) | |||
:wikitext(Items.getValueText(fish)) | |||
row:tag('td') | |||
:css('text-align', 'right') | |||
:wikitext(Shared.round(XPSec, 2, 2)) | |||
end | end | ||
end | end | ||
return | return tostring(html) | ||
end | end | ||
function p.getFishingAreasTable(frame) | function p.getFishingAreasTable(frame) | ||
Line 375: | Line 444: | ||
local skillID = 'Fishing' | local skillID = 'Fishing' | ||
local | local html = mw.html.create('table') | ||
html:addClass('wikitable sortable stickyHeader') | |||
-- Add header row | |||
local headerRow = html:tag('tr'):addClass('headerRow-0') | |||
headerRow:tag('th'):wikitext('Name') | |||
headerRow:tag('th'):wikitext('Fish') | |||
headerRow:tag('th'):wikitext('[[DLC]]') | |||
headerRow:tag('th'):wikitext('Fish Chance') | |||
headerRow:tag('th'):wikitext('Junk Chance') | |||
headerRow:tag('th'):wikitext('Special Chance') | |||
local fishAreas = GameData.getEntities(SkillData.Fishing.areas, | -- Get fishing areas | ||
local fishAreas = GameData.getEntities(SkillData.Fishing.areas, function(obj) | |||
return Skills.getRecipeRealm(obj) == realm.id | |||
end) | |||
-- Add rows for each fishing area | |||
for i, area in ipairs(fishAreas) do | for i, area in ipairs(fishAreas) do | ||
local row = html:tag('tr') | |||
row:tag('td') | |||
:css('text-align', 'left') | |||
:wikitext(area.name) | |||
local fishArray = {} | local fishArray = {} | ||
Line 397: | Line 475: | ||
end | end | ||
end | end | ||
row:tag('td') | |||
:wikitext(table.concat(fishArray, '<br/>')) | |||
row:tag('td') | |||
:css('text-align', 'center') | |||
:wikitext(Icons.getDLCColumnIcon(area.id)) | |||
:attr('data-sort-value', Icons.getExpansionID(area.id)) | |||
row:tag('td') | |||
:css('text-align', 'right') | |||
:wikitext(area.fishChance .. '%') | |||
row:tag('td') | |||
:css('text-align', 'right') | |||
:wikitext(area.junkChance .. '%') | |||
row:tag('td') | |||
:css('text-align', 'right') | |||
:wikitext(area.specialChance .. '%') | |||
end | end | ||
return tostring(html) | |||
return | |||
end | end | ||
function p.getThievingGeneralRareTable(frame) | function p.getThievingGeneralRareTable(frame) | ||
Line 418: | Line 506: | ||
end | end | ||
local | local html = mw.html.create('table') | ||
html:addClass('wikitable sortable') | |||
-- Add header row | |||
local headerRow = html:tag('tr') | |||
headerRow:tag('th'):wikitext('Item') | |||
headerRow:tag('th'):wikitext('[[DLC]]') | |||
headerRow:tag('th'):wikitext('Qty') | |||
headerRow:tag('th'):wikitext('Price') | |||
headerRow:tag('th'):attr('colspan', '2'):wikitext('Chance') | |||
-- Add rows for each rare item | |||
for i, drop in ipairs(SkillData.Thieving.generalRareItems) do | for i, drop in ipairs(SkillData.Thieving.generalRareItems) do | ||
-- If an npcID has been passed and the item is NPC specific, only display | -- If an npcID has been passed and the item is NPC specific, only display the item if it may be obtained while pickpocketing that NPC | ||
local npcMatch = (npc == nil or drop.npcs == nil or Shared.contains(drop.npcs, npc.id)) | |||
local npcMatch = ( | local realmMatch = (npcRealm == nil or drop.realms == nil or Shared.contains(drop.realms, npcRealm)) | ||
local realmMatch = ( | |||
if npcMatch and realmMatch then | if npcMatch and realmMatch then | ||
local thisItem = Items.getItemByID(drop.itemID) | local thisItem = Items.getItemByID(drop.itemID) | ||
local odds = drop.chance | local odds = drop.chance | ||
local row = html:tag('tr') | |||
row:tag('td') | |||
:attr('data-sort-value', thisItem.name) | |||
:wikitext(Icons.Icon({thisItem.name, type='item'})) | |||
row:tag('td') | |||
:wikitext(Icons.getDLCColumnIcon(thisItem.id)) | |||
:attr('data-sort-value', Icons.getExpansionID(thisItem.id)) | |||
:css('text-align', 'center') | |||
row:tag('td') | |||
:wikitext('1') | |||
row:tag('td') | |||
:attr('data-sort-value', thisItem.sellsFor) | |||
:wikitext(Items.getValueText(thisItem)) | |||
row:tag('td') | |||
:css('text-align', 'right') | |||
:attr('data-sort-value', odds) | |||
:wikitext(Shared.fraction(1, Shared.round2(1/(odds/100), 0))) | |||
row:tag('td') | |||
:css('text-align', 'right') | |||
:attr('data-sort-value', odds) | |||
:wikitext(Shared.round(odds, 4, 4) .. '%') | |||
end | end | ||
end | end | ||
return | return tostring(html) | ||
end | end | ||
function p._getThievingNPCCurrencyText(npc) | function p._getThievingNPCCurrencyText(npc) | ||
Line 612: | Line 719: | ||
function p.getThievingNPCTable(frame) | function p.getThievingNPCTable(frame) | ||
local args = frame.args or frame:getParent().args | |||
local realmName = args.realm | |||
local realm = Skills.getRealmFromName(realmName) | |||
if realm == nil then | |||
return Shared.printError('Failed to find a realm with name ' .. (realmName or 'nil')) | |||
end | |||
local skillID = 'Thieving' | |||
local root = mw.html.create('table') | |||
:addClass('wikitable sortable stickyHeader') | |||
-- Header row | |||
local headerRow = root:tag('tr') | |||
:addClass('headerRow-0') | |||
:tag('th'):attr('colspan', '2'):wikitext('Name') | |||
:tag('th'):wikitext('Area') | |||
:tag('th'):wikitext(Icons.Icon({'Thieving', type='skill', notext=true}) .. '<br>Level') | |||
:tag('th'):wikitext('[[DLC]]') | |||
:tag('th'):wikitext('Experience') | |||
:tag('th'):wikitext('Max Hit') | |||
:tag('th'):wikitext('Perception') | |||
:tag('th'):wikitext('Currency') | |||
:tag('th'):wikitext('Unique Drop') | |||
local npcArray = GameData.getEntities(SkillData.Thieving.npcs, | |||
function(obj) | |||
return Skills.getRecipeRealm(obj) == realm.id | |||
end | |||
) | |||
table.sort(npcArray, function(a, b) return Skills.standardRecipeSort(skillID, a, b) end) | |||
for i, npc in ipairs(npcArray) do | |||
local level = Skills.getRecipeLevel(skillID, npc) | |||
local baseXP = npc.baseAbyssalExperience or npc.baseExperience | |||
local area = Skills.getThievingNPCArea(npc) | |||
local currSortAmt = npc.currencyDrops[1].quantity | |||
local row = root:tag('tr') | |||
row:tag('td'):wikitext(Icons.Icon({npc.name, type='thieving', notext=true})) | |||
row:tag('td'):attr('data-sort-value', npc.name) | |||
:wikitext('[[' .. npc.name .. ']]') | |||
row:tag('td'):wikitext(area.name) | |||
row:tag('td'):wikitext(level) | |||
:css('text-align', 'center') | |||
row:tag('td'):wikitext(Icons.getDLCColumnIcon(npc.id)) | |||
:css('text-align', 'center') | |||
:attr('data-sort-value', Icons.getExpansionID(npc.id)) | |||
row:tag('td'):css('text-align', 'right') | |||
:wikitext(Shared.formatnum(baseXP)) | |||
row:tag('td'):css('text-align', 'right') | |||
:wikitext(Shared.formatnum(npc.maxHit * 10)) | |||
row:tag('td'):css('text-align', 'right') | |||
:attr('data-sort-value', npc.perception) | |||
:wikitext(Shared.formatnum(npc.perception)) | |||
row:tag('td'):attr('data-sort-value', currSortAmt) | |||
:wikitext(p._getThievingNPCCurrencyText(npc)) | |||
if npc.uniqueDrop ~= nil then | |||
local uniqueDrop = Items.getItemByID(npc.uniqueDrop.id) | |||
if npc.uniqueDrop.quantity > 1 then | |||
row:tag('td'):attr('data-sort-value', uniqueDrop.name) | |||
:wikitext(Icons.Icon({uniqueDrop.name, type='item', qty=npc.uniqueDrop.quantity})) | |||
else | |||
row:tag('td'):attr('data-sort-value', uniqueDrop.name) | |||
:wikitext(Icons.Icon({uniqueDrop.name, type='item'})) | |||
end | |||
else | |||
row:tag('td'):wikitext(' ') | |||
end | |||
end | |||
return tostring(root) | |||
end | end | ||
function p.getThievingAreaTable(frame) | function p.getThievingAreaTable(frame) | ||
local args = frame.args or frame:getParent().args | |||
local realmName = args.realm | |||
local realm = Skills.getRealmFromName(realmName) | |||
if realm == nil then | |||
return Shared.printError('Failed to find a realm with name ' .. (realmName or 'nil')) | |||
end | |||
local skillID = 'Thieving' | |||
local root = mw.html.create('table') | |||
:addClass('wikitable sortable stickyHeader') | |||
-- Header row | |||
local headerRow = root:tag('tr') | |||
:addClass('headerRow-0') | |||
headerRow:tag('th'):wikitext('Area') | |||
headerRow:tag('th'):wikitext(Icons.Icon({'Thieving', type='skill', notext=true}) .. '<br>Level') | |||
headerRow:tag('th'):wikitext('NPCs') | |||
headerRow:tag('th'):wikitext('Unique Drops') | |||
local areas = GameData.getEntities(SkillData.Thieving.areas, | |||
function(obj) | |||
return Skills.getRecipeRealm(obj) == realm.id | |||
end | |||
) | |||
for i, area in ipairs(areas) do | |||
local minLevel, npcList, areaItemList = nil, {}, {} | |||
-- Build NPC list & determine minimum Thieving level | |||
if area.npcIDs and not Shared.tableIsEmpty(area.npcIDs) then | |||
for j, npcID in ipairs(area.npcIDs) do | |||
local npc = Skills.getThievingNPCByID(npcID) | |||
local level = Skills.getRecipeLevel(skillID, npc) | |||
if not minLevel or level < minLevel then | |||
minLevel = level | |||
end | |||
table.insert(npcList, Icons.Icon({npc.name, type='thieving'})) | |||
end | |||
else | |||
table.insert(npcList, '') | |||
end | |||
-- Build area unique item list | |||
if area.uniqueDrops and Shared.tableCount(area.uniqueDrops) > 0 then | |||
for k, drop in ipairs(area.uniqueDrops) do | |||
local areaItem = Items.getItemByID(drop.id) | |||
if areaItem then | |||
local iconDef = {areaItem.name, type='item'} | |||
if drop.quantity > 1 then | |||
iconDef.qty = drop.quantity | |||
end | |||
table.insert(areaItemList, Icons.Icon(iconDef)) | |||
else | |||
table.insert(areaItemList, 'Unknown[[Category:Pages with script errors]]') | |||
end | |||
end | |||
else | |||
table.insert(areaItemList, '') | |||
end | |||
-- Generate table row | |||
local row = root:tag('tr') | |||
row:tag('td'):wikitext(area.name) | |||
row:tag('td'):wikitext(minLevel) | |||
:css('text-align', 'center') | |||
row:tag('td'):wikitext(table.concat(npcList, '<br/>')) | |||
row:tag('td'):wikitext(table.concat(areaItemList, '<br/>')) | |||
end | |||
return tostring(root) | |||
end | |||
function p._getFarmingTable(realmID, category) | function p._getFarmingTable(realmID, category) | ||
Line 875: | Line 1,015: | ||
function p.getFarmingFoodTable(frame) | function p.getFarmingFoodTable(frame) | ||
local root = mw.html.create('table') | |||
:addClass('wikitable sortable stickyHeader') | |||
-- Header row | |||
local headerRow = root:tag('tr') | |||
:addClass('headerRow-0') | |||
headerRow:tag('th'):attr('colspan', '2'):wikitext('Crop') | |||
headerRow:tag('th'):wikitext(Icons.Icon({"Farming", type="skill", notext=true}) .. '<br>Level') | |||
headerRow:tag('th'):wikitext('[[DLC]]') | |||
headerRow:tag('th'):wikitext('Healing') | |||
headerRow:tag('th'):wikitext('Value') | |||
local recipes = GameData.getEntities(SkillData.Farming.recipes, | |||
function(recipe) | |||
local product = Items.getItemByID(recipe.productId) | |||
return product ~= nil and product.healsFor ~= nil and product.healsFor > 0 | |||
end | |||
) | |||
table.sort(recipes, function(a, b) return a.level < b.level end) | |||
for i, recipe in ipairs(recipes) do | |||
local product = Items.getItemByID(recipe.productId) | |||
if product and product.healsFor and product.healsFor > 0 then | |||
local row = root:tag('tr') | |||
row:tag('td'):wikitext(Icons.Icon({product.name, type='item', notext='true'})) | |||
row:tag('td'):wikitext('[[' .. product.name .. ']]') | |||
row:tag('td'):css('text-align', 'center') | |||
:wikitext(recipe.level) | |||
row:tag('td'):css('text-align', 'center') | |||
:attr('data-sort-value', Icons.getExpansionID(product.id)) | |||
:wikitext(Icons.getDLCColumnIcon(product.id)) | |||
row:tag('td'):css('text-align', 'right') | |||
:attr('data-sort-value', product.healsFor) | |||
:wikitext(Icons.Icon({"Hitpoints", type="skill", notext=true}) .. ' ' .. (product.healsFor * 10)) | |||
row:tag('td'):css('text-align', 'right') | |||
:attr('data-sort-value', product.sellsFor) | |||
:wikitext(Items.getValueText(product)) | |||
end | |||
end | |||
return tostring(root) | |||
end | |||
function p.getFarmingPlotTable(frame) | |||
local skillID = 'Farming' | |||
local areaName = frame.args ~= nil and frame.args[1] or frame | |||
local category = GameData.getEntityByName(SkillData.Farming.categories, areaName) | |||
if category == nil then | |||
return Shared.printError('Invalid farming category. Please choose Allotments, Herbs, Trees or Special') | |||
end | |||
local patches = GameData.getEntities(SkillData.Farming.plots, | |||
function(plot) | |||
return plot.categoryID == category.id | |||
end | |||
) | |||
table.sort(patches, | |||
function(a, b) | |||
local abyssA, abyssB = a.abyssalLevel or 0, b.abyssalLevel or 0 | |||
if abyssA == abyssB then | |||
if a.level == b.level then | |||
return a.id < b.id | |||
else | |||
return a.level < b.level | |||
end | |||
else | |||
return abyssA < abyssB | |||
end | |||
end | |||
) | |||
if Shared.tableIsEmpty(patches) then | |||
return '' | |||
end | |||
local root = mw.html.create('table') | |||
:addClass('wikitable sortable stickyHeader') | |||
-- Header row | |||
local headerRow = root:tag('tr') | |||
headerRow:tag('th'):wikitext('Plot') | |||
headerRow:tag('th'):wikitext('Requirements') | |||
headerRow:tag('th'):wikitext('Cost') | |||
for i, patch in ipairs(patches) do | |||
local level = Skills.getRecipeLevel(skillID, patch) | |||
local reqText = Skills.getRecipeRequirementText(skillID, patch) | |||
local costText = Common.getCostString({ items = patch.itemCosts, currencies = patch.currencyCosts }, 'Free') | |||
local costVal = (patch.currencyCosts and patch.currencyCosts[1] and patch.currencyCosts[1].quantity) or 0 | |||
local row = root:tag('tr') | |||
row:tag('td'):wikitext(i) | |||
row:tag('td'):css('text-align', 'right') | |||
:attr('data-sort-value', level) | |||
:wikitext(reqText) | |||
row:tag('td'):css('text-align', 'right') | |||
:attr('data-sort-value', costVal) | |||
:wikitext(costText) | |||
end | |||
return tostring(root) | |||
end | end | ||
function p. | function p._buildAstrologyConstellationTable(realmID) | ||
local modTypes = { | |||
{ | |||
name = 'Standard', | |||
modKey = 'standardModifiers', | |||
levels = SkillData.Astrology.standardModifierLevels, | |||
inUse = false | |||
}, | |||
{ | |||
name = 'Unique', | |||
modKey = 'uniqueModifiers', | |||
levels = SkillData.Astrology.uniqueModifierLevels, | |||
inUse = false | |||
}, | |||
{ | |||
name = 'Abyssal', | |||
modKey = 'abyssalModifiers', | |||
levels = SkillData.Astrology.abyssalModifierLevels, | |||
inUse = false | |||
}, | |||
} | |||
local recipes = GameData.getEntities(SkillData.Astrology.recipes, | |||
function(cons) | |||
return Skills.getRecipeRealm(cons) == realmID | |||
end | |||
) | |||
table.sort(recipes, | |||
function(a, b) | |||
return Skills.getRecipeLevel('Astrology', a) < Skills.getRecipeLevel('Astrology', b) | |||
end | |||
) | |||
-- Determine which mod types are in use | |||
for _, recipe in ipairs(recipes) do | |||
for _, modType in ipairs(modTypes) do | |||
if not modType.inUse then | |||
local recipeMods = recipe[modType.modKey] | |||
if recipeMods ~= nil and not Shared.tableIsEmpty(recipeMods) then | |||
modType.inUse = true | |||
end | |||
end | |||
end | |||
end | |||
local root = mw.html.create() | |||
local tableRoot = root:tag('table') | |||
tableRoot:addClass('wikitable stickyHeader') | |||
-- Header rows | |||
local headerRow1 = tableRoot:tag('tr'):addClass('headerRow-0') | |||
headerRow1:tag('th'):attr('rowspan', 2) | |||
:attr('colspan', 2) | |||
:wikitext('Constellation') | |||
headerRow1:tag('th'):attr('rowspan', 2) | |||
:wikitext(Icons.Icon({ "Astrology", type='skill', notext='true' }) .. '<br>Level') | |||
headerRow1:tag('th'):attr('rowspan', 2) | |||
:wikitext('[[DLC]]') | |||
headerRow1:tag('th'):attr('rowspan', 2) | |||
:wikitext('XP') | |||
headerRow1:tag('th'):attr('rowspan', 2) | |||
:wikitext('Skills') | |||
local headerRow2 = tableRoot:tag('tr'):addClass('headerRow-1') | |||
for _, modType in ipairs(modTypes) do | |||
if modType.inUse then | |||
headerRow1:tag('th'):attr('colspan', 2):wikitext(modType.name .. ' Stars') | |||
headerRow2:tag('th'):wikitext(Icons.Icon({'Mastery', notext=true}) .. '<br>Level') | |||
headerRow2:tag('th'):wikitext('Modifiers') | |||
end | |||
end | |||
-- Data rows | |||
for _, cons in ipairs(recipes) do | |||
local modData = Skills._getConstellationModifiers(cons) | |||
local name = cons.name | |||
local skillIconArray = {} | |||
for _, skillID in ipairs(cons.skillIDs) do | |||
table.insert(skillIconArray, Icons.Icon({Constants.getSkillName(skillID), type='skill'})) | |||
end | |||
-- Calculate maximum rows needed | |||
local maxRows = 1 | |||
for _, modTypeData in pairs(modData) do | |||
maxRows = math.max(maxRows, Shared.tableCount(modTypeData)) | |||
end | |||
-- Iterate through rows | |||
for rowIdx = 1, maxRows do | |||
local row = tableRoot:tag('tr') | |||
if rowIdx == 1 then | |||
row:tag('td'):attr('rowspan', maxRows) | |||
:wikitext(Icons.Icon({name, type='constellation', size=50, notext=true})) | |||
:css('text-align', 'center') | |||
row:tag('td'):attr('rowspan', maxRows) | |||
:wikitext(name) | |||
row:tag('td'):attr('rowspan', maxRows) | |||
:wikitext(cons.level) | |||
:css('text-align', 'center') | |||
row:tag('td'):css('text-align', 'center') | |||
:attr('data-sort-value', Icons.getExpansionID(cons.id)) | |||
:attr('rowspan', maxRows) | |||
:wikitext(Icons.getDLCColumnIcon(cons.id)) | |||
row:tag('td'):attr('rowspan', maxRows) | |||
:wikitext(cons.baseExperience) | |||
:css('text-align', 'right') | |||
row:tag('td'):attr('rowspan', maxRows) | |||
:wikitext(table.concat(skillIconArray, '<br/>')) | |||
:css('text-wrap', 'nowrap') | |||
end | |||
-- Modifiers data | |||
for _, modType in ipairs(modTypes) do | |||
if modType.inUse then | |||
local masteryLevel = modType.levels[rowIdx] | |||
local rowModData = modData[modType.modKey][rowIdx] | |||
local cell1 = row:tag('td') | |||
local cell2 = row:tag('td') | |||
if masteryLevel ~= nil and rowModData ~= nil then | |||
cell1:wikitext(masteryLevel) | |||
:css('text-align', 'right') | |||
cell2:wikitext(Modifiers.getModifiersText(rowModData, false, false, 10)) | |||
else | |||
cell1:attr('colspan', 2) | |||
:wikitext('N/A') | |||
:addClass('table-na') | |||
end | |||
end | |||
end | |||
end | |||
end | |||
return tostring(root) | |||
end | end | ||
edits