4,978
edits
mNo edit summary |
(Initial commit for overhauled Creation Tables (Status: Incomplete)) |
||
Line 18: | Line 18: | ||
['melvorAoD:EarthGolem'] = 'Earth Golem (AoD)' | ['melvorAoD:EarthGolem'] = 'Earth Golem (AoD)' | ||
} | } | ||
function p.testCreationTables() | |||
-- TODO: | |||
-- Fix TODOs throughout file then remove this test function | |||
-- (Major) Either add all the data from _getItemSourceTables into a single table or convert those over to a similar style table as well | |||
-- If a single table is used, a new header will need to be added (maybe?); Could use 'Category'/'Source' | |||
-- Consider adding more skills into the sources; Stardust has a single source from Firemaking | |||
-- Add the recipe as the category, such as 'Mithril Rock' for Mithril Ore | |||
-- Ash and Withered Ash is showing a single source (Needs a fix in _getCreationTable) | |||
-- Add chance data in _getCreationTable (Ex: Ash, Withered Ash, Stardust from FM) | |||
-- If a table has a rowspan of 3 to (maxRows - 1) then the "Global" information needs to have the rowspan attribute (See Coal Ore's Base Quantity) | |||
-- Should Skill XP be Value - Skill Icon - 'XP' or Skill Icon - Value - 'XP' ? | |||
local tables = {} | |||
local checkItems = { | |||
'Dragonite Ore', -- Single source; This should have no change from the live version | |||
'Arrow Shafts', -- Multi source (Costs, Qty) | |||
'Rune Essence', -- Multi source (Category, Time, XP, Qty, Runes) | |||
'Coal Ore', -- Multi source (Same Qty, everything else is different) | |||
'Ash', -- Requires a fix in _getCreationTable | |||
'Withered Ash', -- Requires a fix in _getCreationTable | |||
-- "Circlet of Rhaelyx", -- The following commented out items have no creation source data; This may appear later | |||
-- "Jewel of Rhaelyx", | |||
-- "Signet Ring Half (a)", | |||
-- "Signet Ring Half (b)", | |||
"Gold Topaz Ring", | |||
-- "Astrology Lesser Relic", | |||
-- "Mysterious Stone", | |||
"Gold Bar", | |||
"Raw Shrimp", | |||
"Coal Ore", | |||
"Rune Platebody", | |||
"Yew Longbow", | |||
"Water Rune", | |||
"Steam Rune", | |||
"Controlled Heat Potion II", | |||
"Wolf", -- Melvor Tablet with multiple recipe costs | |||
"Fox", -- Has a base shard cost and multi recipe cost that is also shards | |||
"Leprechaun", -- Has a currency | |||
"Void Wisp", -- Abyssal Tablet with a single recipe | |||
"Redwood Logs", | |||
"Carrot Cake", | |||
"Carrot Cake (Perfect)", | |||
"Mantalyme Herb", | |||
"Carrot", | |||
-- "Topaz", | |||
-- "Sanguine Blade", | |||
-- "Ring of Power", | |||
-- "Infernal Claw", | |||
-- "Chapeau Noir", | |||
"Stardust", | |||
-- "Rope", | |||
-- "Ancient Ring of Mastery", | |||
-- "Mastery Token (Cooking)", | |||
-- "Gem Gloves", | |||
"Thief's Moneysack", | |||
-- "Golden Stardust", | |||
-- "Golden Star", | |||
-- "Slayer Deterer", | |||
-- "Paper", | |||
-- "Lemon", | |||
-- "Aranite Brush", | |||
"Barrier Dust", | |||
-- "Shadow Raven Nest", | |||
'Obsidian Vein Seed' | |||
} | |||
for i, itemID in ipairs(checkItems) do | |||
table.insert(tables, p._getCreationTable(Items.getItem(itemID))) | |||
end | |||
return table.concat(tables, '\n') | |||
end | |||
local function doesRecipeHaveItemID(recipe, itemID) | local function doesRecipeHaveItemID(recipe, itemID) | ||
Line 48: | Line 119: | ||
local xp = 0 | local xp = 0 | ||
local qty = nil | local qty = nil | ||
local | local costs = nil | ||
local | local tableData = {} | ||
local itemID = item.id | local itemID = item.id | ||
--First figure out what skill is used to make this... | --First figure out what skill is used to make this... | ||
Line 79: | Line 150: | ||
local skillData = SkillData[localSkillID] | local skillData = SkillData[localSkillID] | ||
local skill = skillData.name | local skill = skillData.name | ||
local lvl, isAbyssal, xp, qty, | local lvl, isAbyssal, xp, qty, costs, category, time, maxTime = 0, false, 0, 0, nil, nil, 0, nil | ||
for i, recipe in ipairs(skillData[dataProp.recipeKey]) do | for i, recipe in ipairs(skillData[dataProp.recipeKey]) do | ||
local hasProduct, specialReq = doesRecipeHaveItemID(recipe, itemID) | local hasProduct, specialReq = doesRecipeHaveItemID(recipe, itemID) | ||
Line 87: | Line 158: | ||
qty = recipe.baseQuantity or 1 | qty = recipe.baseQuantity or 1 | ||
if localSkillID == 'Farming' then | if localSkillID == 'Farming' then | ||
costs = { recipe.seedCost } | |||
local catData = GameData.getEntityByID(skillData.categories, recipe.categoryID) | local catData = GameData.getEntityByID(skillData.categories, recipe.categoryID) | ||
category = catData.name | category = catData.name | ||
Line 110: | Line 181: | ||
specialReq = Icons.Icon({'Mastery', notext=true}) .. Num.formatnum(recipe.totalMasteryRequired) .. ' total [[' .. skill .. ']] [[Mastery]]' | specialReq = Icons.Icon({'Mastery', notext=true}) .. Num.formatnum(recipe.totalMasteryRequired) .. ' total [[' .. skill .. ']] [[Mastery]]' | ||
end | end | ||
table.insert( | table.insert(tableData, { ['skill'] = skill, ['lvl'] = lvl, ['isAbyssal'] = isAbyssal, ['xp'] = xp, ['costs'] = costs, ['qty'] = qty, ['category'] = category, ['time'] = time, ['maxTime'] = maxTime, ['specialReq'] = specialReq }) | ||
-- Assumes item has a single source per skill | -- Assumes item has a single source per skill | ||
break | break | ||
Line 168: | Line 239: | ||
local shard = Items.getItemByID(itemCost.id) | local shard = Items.getItemByID(itemCost.id) | ||
if shard ~= nil then | if shard ~= nil then | ||
table.insert(shardCostArray, Icons.Icon({shard.name, type='item' | table.insert(shardCostArray, Icons.Icon({shard.name, type='item', qty=itemCost.quantity})) | ||
end | end | ||
end | end | ||
Line 178: | Line 249: | ||
local itemValue = math.max(nonShard.sellsFor, 20) | local itemValue = math.max(nonShard.sellsFor, 20) | ||
local nonShardQty = math.max(1, math.ceil(recipeCost / itemValue)) | local nonShardQty = math.max(1, math.ceil(recipeCost / itemValue)) | ||
table.insert(otherCostArray, Icons.Icon({nonShard.name, type='item' | table.insert(otherCostArray, Icons.Icon({nonShard.name, type='item', qty=nonShardQty})) | ||
end | end | ||
end | end | ||
req = table.concat(shardCostArray, ' | req = table.concat(shardCostArray, '<br>') | ||
if not Shared.tableIsEmpty(otherCostArray) then | if not Shared.tableIsEmpty(otherCostArray) then | ||
local costLen = Shared.tableCount(otherCostArray) | local costLen = Shared.tableCount(otherCostArray) | ||
req = req .. '<br | req = req .. '<br>' .. (costLen == 1 and '' or 'and one of the following:<br>') .. table.concat(otherCostArray, "<br>'''OR''' ") | ||
end | end | ||
specialReq = 'At least 1 ' .. Icons.Icon({'Summoning%23Summoning Marks', item.name, img=item.name, type='mark'}) .. ' mark discovered' | specialReq = 'At least 1 ' .. Icons.Icon({'Summoning%23Summoning Marks', item.name, img=item.name, type='mark'}) .. ' mark discovered' | ||
table.insert( | table.insert(tableData, { ['skill'] = skill, ['lvl'] = lvl, ['isAbyssal'] = isAbyssal, ['xp'] = xp, ['costs'] = req, ['qty'] = qty, ['category'] = category, ['time'] = time, ['maxTime'] = nil, ['specialReq'] = specialReq }) | ||
-- Some items (such as Arrow shafts) have multiple recipes | -- Some items (such as Arrow shafts) have multiple recipes | ||
elseif type(recipe.alternativeCosts) == 'table' then | elseif type(recipe.alternativeCosts) == 'table' then | ||
local reqPart, qtyPart = {}, {} | local reqPart, qtyPart = {}, {} | ||
for j, altCost in ipairs(recipe.alternativeCosts) do | for j, altCost in ipairs(recipe.alternativeCosts) do | ||
local | local costsStr = '' | ||
for k, itemCost in ipairs(altCost.itemCosts) do | for k, itemCost in ipairs(altCost.itemCosts) do | ||
if k > 1 then costsStr = costsStr .. '<br>' end | |||
local reqItem = Items.getItemByID(itemCost.id) | local reqItem = Items.getItemByID(itemCost.id) | ||
if reqItem == nil then | if reqItem == nil then | ||
costsStr = costsStr .. itemCost.quantity .. 'x ?????' | |||
else | else | ||
costsStr = costsStr .. Icons.Icon({reqItem.name, type='item', qty=itemCost.quantity}) | |||
end | end | ||
end | end | ||
costsStr = costsStr .. (Common.getCostString({ ["items"] = {}, ["currencies"] = recipe.currencyCosts}) or '') | |||
table.insert(tableData, { ['skill'] = skill, ['lvl'] = lvl, ['isAbyssal'] = isAbyssal, ['xp'] = xp, ['costs'] = costsStr, ['qty'] = Num.formatnum(qty * altCost.quantityMultiplier), ['category'] = category, ['time'] = time, ['maxTime'] = maxTime, ['specialReq'] = specialReq }) | |||
table.insert( | |||
end | end | ||
-- Finally, normal recipes with a single set of item costs | -- Finally, normal recipes with a single set of item costs | ||
elseif type(recipe.itemCosts) == 'table' and not Shared.tableIsEmpty(recipe.itemCosts) then | elseif type(recipe.itemCosts) == 'table' and not Shared.tableIsEmpty(recipe.itemCosts) then | ||
table.insert( | table.insert(tableData, { ['skill'] = skill, ['lvl'] = lvl, ['isAbyssal'] = isAbyssal, ['xp'] = xp, ['costs'] = recipe.itemCosts, ['qty'] = qty, ['category'] = category, ['time'] = time, ['maxTime'] = maxTime, ['specialReq'] = specialReq, ['currencyCost'] = recipe.currencyCosts }) | ||
end | end | ||
end | end | ||
Line 223: | Line 289: | ||
for i, altSpell in ipairs(Magic.getSpellsBySpellBook('altMagic')) do | for i, altSpell in ipairs(Magic.getSpellsBySpellBook('altMagic')) do | ||
if altSpell.produces == item.id then | if altSpell.produces == item.id then | ||
table.insert( | table.insert(tableData, { ['skill'] = 'Magic', ['lvl'] = altSpell.level, ['isAbyssal'] = false, ['xp'] = altSpell.baseExperience, ['costs'] = altSpell.runesRequired, ['qty'] = altSpell.productionRatio, ['category'] = altSpell.name, ['time'] = 2, ['maxTime'] = 2, ['altCosts'] = Magic._getAltSpellCostText(altSpell) }) | ||
end | end | ||
end | end | ||
if Shared.tableIsEmpty( | if Shared.tableIsEmpty(tableData) then | ||
return '' | return '' | ||
else | else | ||
return | return p.buildCreationTable2(tableData, item) | ||
end | end | ||
end | end | ||
Line 267: | Line 333: | ||
table.insert(resultPart, '\r\n|}') | table.insert(resultPart, '\r\n|}') | ||
return table.concat(resultPart) | return table.concat(resultPart) | ||
end | |||
function p.buildCreationTable2(tableData, item) | |||
local showCategory = false | |||
local showRequirements = false | |||
local showInputs = false | |||
local showOutputs = false | |||
local showXP = false | |||
local showTime = false | |||
local showChance = false | |||
for i, data in ipairs(tableData) do | |||
if not showCategory and tableData[1].category ~= tableData[i].category then showCategory = true end | |||
if not showRequirements and tableData[1].skill ~= tableData[i].skill then showRequirements = true end | |||
if not showInputs and tableData[1].costs ~= tableData[i].costs then showInputs = true end | |||
if not showOutputs and tableData[1].qty ~= tableData[i].qty then showOutputs = true end | |||
if not showXP and tableData[1].xp ~= tableData[i].xp then showXP = true end | |||
if not showTime and tableData[1].time ~= tableData[i].time then showTime = true end | |||
if not showChance and tableData[1].chance ~= tableData[i].chance then showChance = true end | |||
end | |||
local function addCostsRow(row, data) | |||
local costsRow = row:tag('td') | |||
if type(data.costs) == 'table' then | |||
for i, mat in ipairs(data.costs) do | |||
if i > 1 then costsRow:tag('br') end | |||
local matItem = Items.getItemByID(mat.id) | |||
if matItem == nil then | |||
costsRow:wikitext(mat.quantity .. 'x ?????') | |||
else | |||
costsRow:wikitext(Icons.Icon({matItem.name, type='item', qty=mat.quantity})) | |||
end | |||
end | |||
if data.currencyCost ~= nil then | |||
costsRow:wikitext('<br>' .. (Common.getCostString({ ["items"] = {}, ["currencies"] = data.currencyCost }) or '')) | |||
end | |||
else | |||
costsRow:wikitext(data.costs) | |||
end | |||
if data.altCosts ~= nil then | |||
costsRow:wikitext('<br>' .. data.altCosts:gsub(', ', '<br>')) | |||
end | |||
end | |||
local resultTable = mw.html.create('table') | |||
resultTable:addClass('wikitable') | |||
local tableHeader = resultTable:tag('tr') | |||
if showCategory then tableHeader:tag('th'):wikitext('Category') end | |||
if showRequirements then tableHeader:tag('th'):wikitext('Requirements') end | |||
if showInputs then tableHeader:tag('th'):wikitext('Inputs') end | |||
if showOutputs then tableHeader:tag('th'):wikitext('Outputs') end | |||
if showXP then tableHeader:tag('th'):wikitext('Exp') end | |||
if showTime then tableHeader:tag('th'):wikitext('Time') end | |||
if showChance then tableHeader:tag('th'):wikitext('Chance') end | |||
for i, data in ipairs(tableData) do | |||
if data.qty == nil then data.qty = 1 end | |||
local recipeRow = resultTable:tag('tr') | |||
if showCategory then recipeRow:tag('td'):wikitext(data.category) end | |||
if showRequirements then | |||
local tableReqs = recipeRow:tag('td'):wikitext(Icons._SkillReq(data.skill, data.lvl, false, (data.isAbyssal and "melvorItA:Abyssal" or nil))) | |||
if data.specialReq ~= nil then | |||
recipeRow:tag('br'):wikitext(data.specialReq) | |||
end | |||
end | |||
if showInputs and data.costs ~= nil then | |||
addCostsRow(recipeRow, data) | |||
elseif showInputs then | |||
recipeRow:tag('td'):wikitext('N/A'):addClass('table-na') | |||
end | |||
if showOutputs then recipeRow:tag('td'):wikitext(Icons.Icon({item.name, type='item', notext=true, qty=data.qty})):addClass('center') end | |||
if showXP then recipeRow:tag('td'):wikitext(Num.formatnum(data.xp) .. ' ' .. Icons.Icon({data.skill, notext=true, type='skill'}) .. (data.isAbyssal and ' AXP' or ' XP')):addClass('center') end | |||
if showTime then recipeRow:tag('td'):wikitext(Shared.timeString(data.time, true)):addClass('center') end | |||
if showChance then recipeRow:tag('td'):wikitext(data.chance):addClass('center') end | |||
end | |||
if not showCategory and tableData[1].category ~= nil then | |||
resultTable:tag('tr') | |||
:tag('th') | |||
:wikitext('Category') -- TODO: Rename to Source or Recipe? Category makes sense for recipe categories but not really spells. Source could be the skill that's used for non-spells?? | |||
:css('text-align', 'right') | |||
:tag('td'):wikitext(tableData[1].category) -- TODO: Use Icon template for category. This will require adding overrides to the Icons module for each standard recipe category. Icons will (ideally) be required for Alt Magic Recipes as the category will be the spell that is used | |||
-- This value will need to be passed in as a completed link/icon template as the output will vary by recipe (Such as Barrier Dust having both a Spell and 'Special Items' category) | |||
end | |||
if not showRequirements and tableData[1].skill ~= nil and tableData[1].lvl ~= nil then | |||
local reqRow = resultTable:tag('tr') | |||
:tag('th') | |||
:wikitext('Requirements') | |||
:css('text-align', 'right') | |||
local reqData = reqRow:tag('td') | |||
reqData:wikitext(Icons._SkillReq(tableData[1].skill, tableData[1].lvl, false, (tableData[1].isAbyssal and "melvorItA:Abyssal" or nil))) | |||
if tableData[1].specialReq ~= nil then | |||
reqData:wikitext('<br>' .. tableData[1].specialReq) | |||
end | |||
end | |||
if not showInputs and tableData[1].costs ~= nil then | |||
local costRow = resultTable:tag('tr') | |||
costRow:tag('th') | |||
:wikitext('Inputs') | |||
:css('text-align', 'right') | |||
addCostsRow(costRow, tableData[1]) | |||
end | |||
if not showOutputs and tableData[1].qty ~= nil then | |||
resultTable:tag('tr') | |||
:tag('th') | |||
:wikitext('Outputs') | |||
:css('text-align', 'right') | |||
:tag('td'):wikitext(Icons.Icon({item.name, type='item', qty=tableData[1].qty})) | |||
end | |||
if not showXP and tableData[1].xp ~= nil then | |||
resultTable:tag('tr') | |||
:tag('th') | |||
:wikitext('Base Experience') | |||
:css('text-align', 'right') | |||
:tag('td'):wikitext(Num.formatnum(tableData[1].xp) .. ' ' .. Icons.Icon({tableData[1].skill, notext=true, type='skill'}) .. (tableData[1].isAbyssal and ' AXP' or ' XP')) | |||
end | |||
if not showTime and tableData[1].time ~= nil then | |||
resultTable:tag('tr') | |||
local timeHeader = resultTable:tag('th') | |||
timeHeader | |||
:wikitext('Base Creation Time') | |||
:css('text-align', 'right') | |||
local timeData = timeHeader:tag('td') | |||
timeData:wikitext(Shared.timeString(tableData[1].time, true)) | |||
if tableData[1].maxTime ~= nil and tableData[1].maxTime > tableData[1].time then | |||
timeData:wikitext(' - ' .. Shared.timeString(tableData[1].maxTime, true)) | |||
end | |||
end | |||
if not showChance and tableData[1].chance ~= nil then | |||
resultTable:tag('tr') | |||
:tag('th') | |||
:wikitext('Base Recipe Chance') | |||
:css('text-align', 'right') | |||
:tag('td'):wikitext(tableData[1].chance) | |||
end | |||
return '==' .. item.name .. '==\n' .. tostring(resultTable) -- TODO: Remove item.name header | |||
end | end | ||
Line 276: | Line 492: | ||
table.insert(resultPart, '\r\n|-\r\n!style="text-align: right;"|Requirements') | table.insert(resultPart, '\r\n|-\r\n!style="text-align: right;"|Requirements') | ||
table.insert(resultPart, '\r\n|'..Icons._SkillReq(skill, lvl, false, (isAbyssal and "melvorItA:Abyssal" or nil))) | table.insert(resultPart, '\r\n|'..Icons._SkillReq(skill, lvl, false, (isAbyssal and "melvorItA:Abyssal" or nil))) | ||
if specialReq ~= nil then table.insert(resultPart, '<br | if specialReq ~= nil then table.insert(resultPart, '<br>'..specialReq) end | ||
if req ~= nil then | if req ~= nil then | ||
Line 282: | Line 498: | ||
if type(req) == 'table' then | if type(req) == 'table' then | ||
for i, mat in ipairs(req) do | for i, mat in ipairs(req) do | ||
if i > 1 then table.insert(resultPart, '<br | if i > 1 then table.insert(resultPart, '<br>') end | ||
local matItem = Items.getItemByID(mat.id) | local matItem = Items.getItemByID(mat.id) | ||
if matItem == nil then | if matItem == nil then | ||
Line 743: | Line 959: | ||
elseif rareDrop.itemID == 'melvorD:Mysterious_Stone' then | elseif rareDrop.itemID == 'melvorD:Mysterious_Stone' then | ||
local foundItem = Items.getItemByID('melvorD:Crown_of_Rhaelyx') | local foundItem = Items.getItemByID('melvorD:Crown_of_Rhaelyx') | ||
subText = '<br | subText = '<br>after finding ' .. Icons.Icon({foundItem.name, type='item'}) | ||
end | end | ||
if type(rareDrop.gamemodes) == 'table' then | if type(rareDrop.gamemodes) == 'table' then | ||
Line 825: | Line 1,041: | ||
table.insert(resultPart, '* '..table.concat(lineArray, "\r\n* ")) | table.insert(resultPart, '* '..table.concat(lineArray, "\r\n* ")) | ||
else | else | ||
table.insert(resultPart, '<div style="max-width:180px;text-align:right">' .. table.concat(lineArray, "<br | table.insert(resultPart, '<div style="max-width:180px;text-align:right">' .. table.concat(lineArray, "<br>") .. '</div>') | ||
end | end | ||
if addCategories then table.insert(resultPart, table.concat(categoryArray, '')) end | if addCategories then table.insert(resultPart, table.concat(categoryArray, '')) end |