Anonymous

Module:Items/SourceTables: Difference between revisions

From Melvor Idle
Overhauled Creation Tables; Add support for Abyssal gems in Item and Loot sources;
m (Simple fix for Firemaking Primary and Secondary products not showing Firemaking as a source)
(Overhauled Creation Tables; Add support for Abyssal gems in Item and Loot sources;)
Line 21: Line 21:
local function doesRecipeHaveItemID(recipe, itemID)
local function doesRecipeHaveItemID(recipe, itemID)
if recipe.productId == itemID then
if recipe.productId == itemID then
return true, nil
return true
elseif Shared.contains(recipe.primaryProducts, itemID) or Shared.contains(recipe.secondaryProducts, itemID) then
elseif Shared.contains(recipe.primaryProducts, itemID) or Shared.contains(recipe.secondaryProducts, itemID) then
return true, nil
return true
elseif type(recipe.products) == 'table' then
elseif type(recipe.products) == 'table' then
for i, product in ipairs(recipe.products) do
return GameData.getEntityByProperty(recipe.products, 'itemID', itemID) ~= nil
if product.itemID == itemID then
local specialReq = nil
if recipe.products[i].minIntensityPercent ~= nil then
specialReq = recipe.products[i].minIntensityPercent .. '% Intensity'
end
return true, specialReq
end
end
end
end
return false, nil
return false
end
end


Line 41: Line 33:
local skill = ''
local skill = ''
local specialReq = nil
local specialReq = nil
local category = nil
local source = nil
local time = 0
local time = 0
local maxTime = nil
local maxTime = nil
Line 47: Line 39:
local isAbyssal = false
local isAbyssal = false
local xp = 0
local xp = 0
local qty = nil
local qty = 1
local req = nil
local costs = nil
local chance = nil


local tables = {}
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 56: Line 49:
local skillIDs = {
local skillIDs = {
['Gathering'] = {
['Gathering'] = {
['Farming'] = { recipeKey = 'recipes' },
['Woodcutting'] = { recipeKey = 'trees' },
['Woodcutting'] = { recipeKey = 'trees' },
['Fishing'] = { recipeKey = 'fish' },
['Fishing'] = { recipeKey = 'fish' },
['Firemaking'] = { recipeKey = 'logs' },
['Firemaking'] = { recipeKey = 'logs' },
['Mining'] = { recipeKey = 'rockData' },
['Mining'] = { recipeKey = 'rockData' },
['Farming'] = { recipeKey = 'recipes' },
['Cartography'] = { recipeKey = 'paperRecipes' },
['Harvesting'] = { recipeKey = 'veinData' }
['Harvesting'] = { recipeKey = 'veinData' }
},
},
Line 79: Line 73:
local skillData = SkillData[localSkillID]
local skillData = SkillData[localSkillID]
local skill = skillData.name
local skill = skillData.name
local lvl, isAbyssal, xp, qty, req, category, time, maxTime = 0, false, 0, 0, nil, nil, 0, nil
local lvl, isAbyssal, xp, qty, source, costs, time, maxTime, chance = 0, false, 0, 1, nil, nil, 0, nil, 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 = doesRecipeHaveItemID(recipe, itemID)
if hasProduct then
if hasProduct then
lvl, isAbyssal = Skills.getRecipeLevelRealm(localSkillID, recipe)
lvl, isAbyssal = Skills.getRecipeLevelRealm(localSkillID, recipe)
xp = recipe.baseAbyssalExperience or recipe.baseExperience
xp = recipe.baseAbyssalExperience or recipe.baseExperience
qty = recipe.baseQuantity or 1
qty = recipe.baseQuantity or 1
source = Icons.Icon({ skill, type='skill', class=(isAbyssal and 'abyss-icon' or '') })
if localSkillID == 'Farming' then
if localSkillID == 'Farming' then
req = { recipe.seedCost }
costs = { recipe.seedCost }
local catData = GameData.getEntityByID(skillData.categories, recipe.categoryID)
local catData = GameData.getEntityByID(skillData.categories, recipe.categoryID)
category = catData.name
qty = 5 * catData.harvestMultiplier
qty = 5 * catData.harvestMultiplier
end
end
Line 102: Line 96:
elseif skillData.baseInterval ~= nil then
elseif skillData.baseInterval ~= nil then
time = skillData.baseInterval / 1000
time = skillData.baseInterval / 1000
elseif localSkillID == 'Cartography' then
time = 5
end
end
if itemID == 'melvorF:Ash' then
-- Item chance and recipe costs
qty = time
if localSkillID == 'Firemaking' then
local itemChanceData = GameData.getEntityByProperty(SkillData.Firemaking.primaryProducts, 'itemID', itemID)
if itemChanceData ~= nil then
chance = itemChanceData.chance .. '%'
elseif itemID == 'melvorD:Generous_Fire_Spirit' then
chance = '0.1%'
end
 
if Shared.contains({ 'melvorD:Generous_Fire_Spirit', 'melvorD:Coal_Ore', 'melvorTotH:Charcoal' }, itemID) then
costs = 'Any ' .. Icons.Icon({ 'Firemaking', 'Melvor Logs', img='Melvor Logo', section='Melvor Logs' })
else
local costItem = Items.getItemByID(recipe.logID)
costs = Icons.Icon({ costItem.name, type='item', qty=1 })
end
 
if itemID == 'melvorF:Ash' then
qty = time
elseif itemID == 'melvorItA:Withered_Ash' or itemID == 'melvorItA:Eternal_Ash' then
qty = math.max(math.floor(recipe.abyssalLevel / 10), 1)
end
elseif localSkillID == 'Cartography' then
local costItem = Items.getItemByID(recipe.costs.items[1].id)
costs = Icons.Icon({ costItem.name, type='item', qty=1 })
elseif localSkillID == 'Harvesting' then
local totalWeight = 0
local itemChanceData = nil
 
for i, product in ipairs(recipe.products) do
totalWeight = totalWeight + (product.weight or 0)
 
if product.itemID == itemID then itemChanceData = product end
end
 
if itemChanceData ~= nil then
chance = Num.round2((itemChanceData.weight / totalWeight * 100), 2) .. '%'
specialReq = itemChanceData.minIntensityPercent .. '% ' .. Icons.Icon({ recipe.name, type='vein', notext=true }) .. ' Intensity'
end
end
end
-- Special requirements
-- Special requirements
if recipe.totalMasteryRequired ~= nil then
if recipe.totalMasteryRequired ~= nil then
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(tables, p.buildCreationTable(skill, lvl, isAbyssal, xp, req, qty, category, time, maxTime, specialReq))
table.insert(tableData, {
-- Assumes item has a single source per skill
['skill'] = skill,
break
['lvl'] = lvl,
['isAbyssal'] = isAbyssal,
['xp'] = xp,
['costs'] = costs,
['qty'] = qty,
['source'] = source,
['time'] = time,
['maxTime'] = maxTime,
['specialReq'] = specialReq,
['chance'] = chance
})
-- Most recipes have a single item source or the item source data
-- is nearly all the same. The following items have some uniqueness
if not Shared.contains({ 'melvorF:Ash', 'melvorItA:Withered_Ash', 'melvorAoD:Paper' }, itemID) then break end
end
end
end
end
Line 122: Line 167:
local skillData = SkillData[localSkillID]
local skillData = SkillData[localSkillID]
local skill = skillData.name
local skill = skillData.name
local lvl, isAbyssal, xp, qty, category, req, time, maxTime = 0, false, 0, 0, nil, nil, 0, nil
local lvl, isAbyssal, xp, qty, source, costs, time, maxTime = 0, false, 0, 1, Icons.Icon({ skill, type='skill' }), nil, 0, nil
for i, recipe in ipairs(skillData.recipes) do
for i, recipe in ipairs(skillData.recipes) do
if recipe.productID == itemID or
if recipe.productID == itemID or
Line 130: Line 175:
xp = recipe.baseAbyssalExperience or recipe.baseExperience
xp = recipe.baseAbyssalExperience or recipe.baseExperience
qty = recipe.baseQuantity or 1
qty = recipe.baseQuantity or 1
-- Recipe Category
source = Icons.Icon({ skill, type='skill', class=(isAbyssal and 'abyss-icon' or '') })
if recipe.categoryID ~= nil then
local catData = GameData.getEntityByID(SkillData[localSkillID].categories, recipe.categoryID)
category = catData.modifierName or catData.name or nil
end
-- Action time
-- Action time
if recipe.baseMinInterval ~= nil then
if recipe.baseMinInterval ~= nil then
Line 142: Line 183:
end
end
elseif recipe.baseInterval ~= nil then
elseif recipe.baseInterval ~= nil then
time = recipe.baseInterval /1000
time = recipe.baseInterval / 1000
elseif skillData.baseInterval ~= nil then
elseif skillData.baseInterval ~= nil then
time = skillData.baseInterval / 1000
time = skillData.baseInterval / 1000
Line 152: Line 193:
if levelUnlock ~= nil then
if levelUnlock ~= nil then
specialReq = Icons._MasteryReq(item.name, levelUnlock.level, false)
specialReq = Icons._MasteryReq(item.name, levelUnlock.level, false)
end
end
if localSkillID == 'Cooking' then
-- Cooking includes the required utility (fire, furnace, pot) as a special requirement
local cookingCatIcon = {
["melvorD:Fire"] = 'Normal Cooking Fire',
["melvorD:Furnace"] = 'Basic Furnace',
["melvorD:Pot"] = 'Basic Pot'
}
local categoryIconName, categoryName = cookingCatIcon[recipe.categoryID], nil
local recipeCategory = GameData.getEntityByID(SkillData.Cooking.categories, recipe.categoryID)
if recipeCategory ~= nil then
categoryName = recipeCategory.modifierName or recipeCategory.name
end
if categoryIconName ~= nil and categoryName ~= nil then
specialReq = Icons.Icon({ 'Cooking', categoryName, section = 'Cooking Upgrades', img = categoryIconName, type = 'upgrade' })
end
end
end
end
Line 168: Line 225:
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', notext=true, qty=itemCost.quantity}))
table.insert(shardCostArray, Icons.Icon({ shard.name, type='item', qty=itemCost.quantity }))
end
end
end
end
-- Other costs
-- Other costs
table.insert(otherCostArray, Common.getCostString({ ["items"] = {}, ["currencies"] = recipe.currencyCosts}))
table.insert(otherCostArray, Common.getCostString({ ["items"] = {}, ["currencies"] = recipe.currencyCosts }))
for j, nonShardID in ipairs(recipe.nonShardItemCosts) do
for j, nonShardID in ipairs(recipe.nonShardItemCosts) do
local nonShard = Items.getItemByID(nonShardID)
local nonShard = Items.getItemByID(nonShardID)
Line 178: Line 235:
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', notext=true, qty=nonShardQty}))
table.insert(otherCostArray, Icons.Icon({ nonShard.name, type='item', qty=nonShardQty }))
end
end
end
end
req = table.concat(shardCostArray, ', ')
costs = 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/>' .. (costLen == 1 and '' or 'and one of the following:<br/>') .. table.concat(otherCostArray, "<br/>'''OR''' ")
costs = costs .. '<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(tables, p.buildCreationTable(skill, lvl, isAbyssal, xp, req, qty, category, time, nil, specialReq))
table.insert(tableData, {
['skill'] = skill,
['lvl'] = lvl,
['isAbyssal'] = isAbyssal,
['xp'] = xp,
['costs'] = costs,
['qty'] = qty,
['source'] = source,
['time'] = time,
['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 reqSubPart = {}
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
table.insert(reqSubPart, itemCost.quantity .. 'x ?????')
costsStr = costsStr .. itemCost.quantity .. 'x ?????'
else
else
table.insert(reqSubPart, Icons.Icon({reqItem.name, type='item', qty=itemCost.quantity}))
costsStr = costsStr .. Icons.Icon({ reqItem.name, type='item', qty=itemCost.quantity })
end
end
end
end
 
costsStr = costsStr .. Common.getCostString({ ["items"] = {}, ["currencies"] = recipe.currencyCosts }, '')
table.insert(reqSubPart, Common.getCostString({ ["items"] = {}, ["currencies"] = recipe.currencyCosts}))
table.insert(tableData, {
table.insert(reqPart, table.concat(reqSubPart, ', '))
['skill'] = skill,
table.insert(qtyPart, Num.formatnum(qty * altCost.quantityMultiplier))
['lvl'] = lvl,
['isAbyssal'] = isAbyssal,
['xp'] = xp,
['costs'] = costsStr,
['qty'] = Num.formatnum(qty * altCost.quantityMultiplier),
['source'] = Icons.Icon({ skill, type='skill' }),
['time'] = time,
['maxTime'] = maxTime,
['specialReq'] = specialReq
})
end
end
local sep = "<br/>'''OR''' "
req = table.concat(reqPart, sep)
local qtyText = table.concat(qtyPart, sep)
table.insert(tables, p.buildCreationTable(skill, lvl, isAbyssal, xp, req, qtyText, category, time, maxTime, specialReq))
-- 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(tables, p.buildCreationTable(skill, lvl, isAbyssal, xp, recipe.itemCosts, qty, category, time, maxTime, specialReq, recipe.currencyCosts))
table.insert(tableData, {
['skill'] = skill,
['lvl'] = lvl,
['isAbyssal'] = isAbyssal,
['xp'] = xp,
['costs'] = recipe.itemCosts,
['qty'] = qty,
['source'] = Icons.Icon({ skill, type='skill' }),
['time'] = time,
['maxTime'] = maxTime,
['specialReq'] = specialReq,
['currencyCost'] = recipe.currencyCosts
})
end
end
end
end
Line 222: Line 307:
-- Gems are handled by _getItemLootSourceTable()
-- Gems are handled by _getItemLootSourceTable()
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 == itemID then
table.insert(tables, p._buildAltMagicTable(altSpell))
table.insert(tableData, {
['skill'] = 'Magic',
['lvl'] = altSpell.level,
['isAbyssal'] = false,
['xp'] = altSpell.baseExperience,
['costs'] = altSpell.runesRequired,
['qty'] = altSpell.productionRatio,
['source'] = Icons.Icon({ altSpell.name, type='spell' }),
['time'] = 2,
['altCosts'] = Magic._getAltSpellCostText(altSpell)
})
end
end
end
end


if Shared.tableIsEmpty(tables) then
-- Add in Astrology creation items manually since each constellation has (mostly)
return ''
-- the same creation information so looping through them is not necessary
else
local stardustChanceData = GameData.getEntityByProperty(SkillData.Astrology.baseRandomItemChances, 'itemID', itemID)
return table.concat(tables, '\r\n')
if stardustChanceData ~= nil then
local namespace, localID = Shared.getLocalID(stardustChanceData.itemID)
local isAbyssal = namespace == 'melvorItA'
table.insert(tableData, {
['skill'] = 'Astrology',
['lvl'] = 1,
['isAbyssal'] = isAbyssal,
['qty'] = qty,
['xp'] = (isAbyssal and 1238 or 5), -- Use the (A)XP value for the first (abyssal) constellation
['source'] = Icons.Icon({ 'Astrology', type='skill', class=(isAbyssal and 'abyss-icon' or '') }),
['time'] = 3,
['chance'] = stardustChanceData.chance .. '%'
})
end
end
end


function p.getAltMagicTable(frame)
if Shared.tableIsEmpty(tableData) then
local spellName = frame.args ~= nil and frame.args[1] or frame
return ''
local spell = Magic.getSpell(spellName, 'altMagic')
if spell == nil then
return Shared.printError('Could not find Alt. Magic spell "' .. spellName .. '"')
else
else
return p._buildAltMagicTable(spell)
return p.buildCreationTable(tableData, item)
end
end
end
end


function p._buildAltMagicTable(spell)
function p.buildCreationTable(tableData, item)
local resultPart = {}
local showSource = false
local imgType = Magic._getSpellIconType(spell)
local showRequirements = false
table.insert(resultPart, '{|class="wikitable"\r\n|-')
local showInputs = false
table.insert(resultPart, '\r\n!colspan="2"|'..Icons.Icon({spell.name, type=imgType}))
local showOutputs = false
table.insert(resultPart, '\r\n|-\r\n!style="text-align:right;"|Requirements')
local showXP = false
table.insert(resultPart, '\r\n|'..Icons._SkillReq('Magic', spell.level))
local showTime = false
local showChance = false
local colspan = -1 -- colspan only needs to be set when there are 3+ columns in the table


local costText = Magic._getAltSpellCostText(spell)
for i, data in ipairs(tableData) do
if costText ~= nil then
if not showSource and tableData[1].source ~= tableData[i].source then
table.insert(resultPart, '\r\n|-\r\n!style="text-align:right;"|Materials')
showSource = true
table.insert(resultPart, '\r\n| ' .. costText)
colspan = colspan + 1
end
if not showRequirements and tableData[1].skill ~= tableData[i].skill then
showRequirements = true
colspan = colspan + 1
end
if not showInputs and tableData[1].costs ~= tableData[i].costs then
showInputs = true
colspan = colspan + 1
end
if not showOutputs and tableData[1].qty ~= tableData[i].qty then
showOutputs = true
colspan = colspan + 1
end
if not showXP and tableData[1].xp ~= tableData[i].xp then
showXP = true
colspan = colspan + 1
end
if not showTime and tableData[1].time ~= tableData[i].time then
showTime = true
colspan = colspan + 1
end
if not showChance and tableData[1].chance ~= tableData[i].chance then
showChance = true
colspan = colspan + 1
end
end
end


--Add runes
colspan = math.max(colspan, 1)
table.insert(resultPart, '\r\n|-\r\n!style="text-align:right;"|Runes\r\n| ' .. Magic._getSpellRunes(spell))


--Now just need the output quantity, xp, and casting time (which is always 2)
local function addCostsRow(row, data, span)
table.insert(resultPart, '\r\n|-\r\n!style="text-align:right;"|Base Quantity\r\n|' .. spell.productionRatio)
local costsRow = row:tag('td'):attr('colspan', span)
table.insert(resultPart, '\r\n|-\r\n!style="text-align:right;"|Base XP\r\n|' .. spell.baseExperience)
if type(data.costs) == 'table' then
table.insert(resultPart, '\r\n|-\r\n!style="text-align:right;"|Cast Time\r\n|2s')
for i, mat in ipairs(data.costs) do
table.insert(resultPart, '\r\n|}')
if i > 1 then costsRow:tag('br') end
return table.concat(resultPart)
end
 
function p.buildCreationTable(skill, lvl, isAbyssal, xp, req, qty, category, time, maxTime, specialReq, currencyCost)
if qty == nil then qty = 1 end
local resultPart = {}
table.insert(resultPart, '{|class="wikitable"')
table.insert(resultPart, '\r\n!colspan="2"|Item ' .. (req == nil and 'Creation' or 'Production'))
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)))
if specialReq ~= nil then table.insert(resultPart, '<br/>'..specialReq) end
 
if req ~= nil then
table.insert(resultPart, '\r\n|-\r\n!style="text-align: right;"|Materials\r\n|')
if type(req) == 'table' then
for i, mat in ipairs(req) do
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
table.insert(resultPart, mat.quantity..'x ?????')
costsRow:wikitext(mat.quantity .. 'x ?????')
else
else
table.insert(resultPart, Icons.Icon({matItem.name, type='item', qty=mat.quantity}))
costsRow:wikitext(Icons.Icon({ matItem.name, type='item', qty=mat.quantity }))
end
end
end
end
if currencyCost ~= nil then
if data.currencyCost ~= nil then
table.insert(resultPart, Common.getCostString({ ["items"] = {}, ["currencies"] = currencyCost }))
costsRow:wikitext('<br>' .. Common.getCostString({ ["items"] = {}, ["currencies"] = data.currencyCost }, ''))
end
end
else
else
table.insert(resultPart, req)
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 showSource then tableHeader:tag('th'):wikitext('Source') end
if showRequirements then tableHeader:tag('th'):wikitext('Requires') 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
local recipeRow = resultTable:tag('tr')
 
if showSource then recipeRow:tag('td'):wikitext(data.source) 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, 1)
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(Icons.Icon({ data.skill, notext=true, type='skill', class=(data.isAbyssal and 'abyss-icon' or '') }))
:wikitext(' ' .. Num.formatnum(data.xp) .. (data.isAbyssal and ' AXP' or ' XP'))
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 or '100%')):addClass('center') end
end
 
if not showSource and tableData[1].source ~= nil then
resultTable:tag('tr')
:tag('th'):wikitext('Source'):css('text-align', 'right')
:tag('td'):attr('colspan', colspan):wikitext(tableData[1].source)
end
if not showRequirements and tableData[1].skill ~= nil and tableData[1].lvl ~= nil then
local reqRow = resultTable:tag('tr')
:tag('th'):wikitext('Requires'):css('text-align', 'right')
 
local reqData = reqRow:tag('td'):attr('colspan', colspan)
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')
:tag('th'):wikitext('Inputs'):css('text-align', 'right')
addCostsRow(costRow, tableData[1], colspan)
end
if not showOutputs and tableData[1].qty ~= nil then
resultTable:tag('tr')
:tag('th'):wikitext('Outputs'):css('text-align', 'right')
:tag('td'):attr('colspan', colspan):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 Exp'):css('text-align', 'right')
:tag('td'):attr('colspan', colspan):wikitext(Num.formatnum(tableData[1].xp) .. (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'):wikitext('Base Time'):css('text-align', 'right')
 
local timeData = timeHeader:tag('td'):attr('colspan', colspan)
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
end
end
if category ~= nil then
if not showChance and tableData[1].chance ~= nil then
table.insert(resultPart, '\r\n|-\r\n!style="text-align:right;"|Recipe Category')
resultTable:tag('tr')
table.insert(resultPart, '\r\n|'..category)
:tag('th'):wikitext('Base Chance'):css('text-align', 'right')
:tag('td'):attr('colspan', colspan):wikitext(tableData[1].chance)
end
end
table.insert(resultPart, '\r\n|-\r\n!style="text-align:right;"|Base Quantity')
table.insert(resultPart, '\r\n|'..qty)
table.insert(resultPart, '\r\n|-\r\n!style="text-align:right;"|Base Experience')
table.insert(resultPart, '\r\n|'..Num.formatnum(xp)..' XP')
table.insert(resultPart, '\r\n|-\r\n!style="text-align:right;"|Base Creation Time')
table.insert(resultPart, '\r\n|'..Shared.timeString(time, true))
if maxTime ~= nil and maxTime > time then table.insert(resultPart, ' - '..Shared.timeString(maxTime, true)) end
table.insert(resultPart, '\r\n|}')


return table.concat(resultPart)
return tostring(resultTable)
end
end


Line 368: Line 562:
}
}
for entity, dungeons in pairs(dungeonEntities) do
for entity, dungeons in pairs(dungeonEntities) do
local iconType = entity == 'Dungeon' and 'dungeon' or 'combatArea'
for i, dungeon in ipairs(dungeons) do
for i, dungeon in ipairs(dungeons) do
if (dungeon.oneTimeRewardID ~= nil and item.id == dungeon.oneTimeRewardID) or
if (dungeon.oneTimeRewardID ~= nil and item.id == dungeon.oneTimeRewardID) or
(type(dungeon.rewardItemIDs) == 'table' and Shared.contains(dungeon.rewardItemIDs, item.id)) then
(type(dungeon.rewardItemIDs) == 'table' and Shared.contains(dungeon.rewardItemIDs, item.id)) then
table.insert(dungeonStrPart, Icons.Icon({dungeon.name, type=iconType, notext=true}))
table.insert(dungeonStrPart, Icons.Icon({dungeon.name, type='combatArea', notext=true}))
elseif dungeon.eventID ~= nil then
elseif dungeon.eventID ~= nil then
-- Is the item dropped from a combat event (e.g. Impending Darkness event)?
-- Is the item dropped from a combat event (e.g. Impending Darkness event)?
Line 380: Line 573:
if item.id == itemRewardID then
if item.id == itemRewardID then
local dungPrefix = (eventCycle == Shared.tableCount(event.itemRewardIDs) and '' or eventCycle .. (eventCycle == 1 and ' cycle' or ' cycles') .. ' of ')
local dungPrefix = (eventCycle == Shared.tableCount(event.itemRewardIDs) and '' or eventCycle .. (eventCycle == 1 and ' cycle' or ' cycles') .. ' of ')
table.insert(dungeonStrPart, dungPrefix .. Icons.Icon({dungeon.name, type=iconType, notext=true}))
table.insert(dungeonStrPart, dungPrefix .. Icons.Icon({dungeon.name, type='combatArea', notext=true}))
break
break
end
end
Line 707: Line 900:
-- Mining: Gems
-- Mining: Gems
if (GameData.getEntityByProperty('randomGems', 'itemID', item.id) ~= nil or
if (GameData.getEntityByProperty('randomGems', 'itemID', item.id) ~= nil or
GameData.getEntityByProperty('randomSuperiorGems', 'itemID', item.id) ~= nil) then
GameData.getEntityByProperty('randomSuperiorGems', 'itemID', item.id) ~= nil or
GameData.getEntityByProperty('randomAbyssalGems', 'itemID', item.id) ~= nil) then
table.insert(lineArray, Icons.Icon({"Mining", type='skill', notext=true})..' [[Mining#Gems|Gem]]')
table.insert(lineArray, Icons.Icon({"Mining", type='skill', notext=true})..' [[Mining#Gems|Gem]]')
elseif item.id == SkillData.Mining.runestoneItemID then
elseif item.id == SkillData.Mining.runestoneItemID then
Line 743: Line 937:
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/>after finding ' .. Icons.Icon({foundItem.name, type='item'})
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,019:
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/>") .. '</div>')
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
Line 944: Line 1,138:
}
}
for entity, dungeons in pairs(dungeonEntities) do
for entity, dungeons in pairs(dungeonEntities) do
local iconType = entity == 'Dungeon' and 'dungeon' or 'combatArea'
for i, dungeon in ipairs(dungeons) do
for i, dungeon in ipairs(dungeons) do
if (dungeon.oneTimeRewardID ~= nil and item.id == dungeon.oneTimeRewardID) or
if (dungeon.oneTimeRewardID ~= nil and item.id == dungeon.oneTimeRewardID) or
(type(dungeon.rewardItemIDs) == 'table' and Shared.contains(dungeon.rewardItemIDs, item.id)) then
(type(dungeon.rewardItemIDs) == 'table' and Shared.contains(dungeon.rewardItemIDs, item.id)) then
table.insert(dropRows, {
table.insert(dropRows, {
source = Icons.Icon({dungeon.name, type=iconType}),  
source = Icons.Icon({dungeon.name, type='combatArea'}),  
level = '[['..entity..']]',
level = '[['..entity..']]',
minqty = 1,  
minqty = 1,  
Line 962: Line 1,155:
for eventCycle, itemRewardID in ipairs(event.itemRewardIDs) do
for eventCycle, itemRewardID in ipairs(event.itemRewardIDs) do
if item.id == itemRewardID then
if item.id == itemRewardID then
local sourceTxt = Icons.Icon({dungeon.name, type=iconType}) .. (eventCycle == Shared.tableCount(event.itemRewardIDs) and '' or ', Cycle ' .. eventCycle)
local sourceTxt = Icons.Icon({dungeon.name, type='combatArea'}) .. (eventCycle == Shared.tableCount(event.itemRewardIDs) and '' or ', Cycle ' .. eventCycle)
table.insert(dropRows, {
table.insert(dropRows, {
source = sourceTxt,  
source = sourceTxt,  
Line 1,085: Line 1,278:


-- Mining: Gems, and also Alt. Magic spells producing random gems
-- Mining: Gems, and also Alt. Magic spells producing random gems
if Shared.contains({'Gem', 'Superior Gem'}, item.type) then
if Shared.contains({'Gem', 'Superior Gem', 'Abyssal Gem'}, item.type) then
local gemKeys = { 'randomGems', 'randomSuperiorGems' }
local gemKeys = { 'randomGems', 'randomSuperiorGems', 'randomAbyssalGems' }
for i, gemKey in ipairs(gemKeys) do
for i, gemKey in ipairs(gemKeys) do
local thisGem, totalGemWeight = nil, 0
local thisGem, totalGemWeight = nil, 0
Line 1,120: Line 1,313:
-- Check for Alt. Magic spells also
-- Check for Alt. Magic spells also
local producesKey = (gemKey == 'randomGems' and 'RandomGem') or 'RandomSuperiorGem'
local producesKey = (gemKey == 'randomGems' and 'RandomGem') or (gemKey == 'randomSuperiorGems' and 'RandomSuperiorGem') or nil
for j, spell in ipairs(Magic.getSpellsBySpellBook('altMagic')) do
if producesKey ~= nil then
if spell.produces ~= nil and spell.produces == producesKey then
for j, spell in ipairs(Magic.getSpellsBySpellBook('altMagic')) do
table.insert(dropRows, {
if spell.produces ~= nil and spell.produces == producesKey then
source = Icons.Icon({spell.name, type=Magic._getSpellIconType(spell)}),  
table.insert(dropRows, {
level = Icons.Icon({'Alternative Magic', type='skill', img='Magic', notext=true}) .. ' Level ' .. spell.level,
source = Icons.Icon({spell.name, type=Magic._getSpellIconType(spell)}),  
levelNum = spell.level,
level = Icons.Icon({'Alternative Magic', type='skill', img='Magic', notext=true}) .. ' Level ' .. spell.level,
minqty = thisGem.minQuantity,  
levelNum = spell.level,
qty = thisGem.maxQuantity,
minqty = thisGem.minQuantity,  
weight = thisGem.weight,  
qty = thisGem.maxQuantity,
totalWeight = totalGemWeight,
weight = thisGem.weight,  
expIcon = Icons.getExpansionIcon(spell.id)})
totalWeight = totalGemWeight,
expIcon = Icons.getExpansionIcon(spell.id)})
end
end
end
end
end
Line 1,455: Line 1,650:
"Signet Ring Half (a)",
"Signet Ring Half (a)",
"Signet Ring Half (b)",
"Signet Ring Half (b)",
"Gold Topaz Ring",
"Astrology Lesser Relic",
"Astrology Lesser Relic",
"Mysterious Stone",
"Mysterious Stone",
"Gold Topaz Ring",
"Charcoal",
"Ash",
"Coal Ore",
"Rune Essence",
"Gold Bar",
"Gold Bar",
"Raw Shrimp",
"Coal Ore",
"Rune Platebody",
"Rune Platebody",
"Arrow Shafts",
"Arrow Shafts",
Line 1,466: Line 1,663:
"Water Rune",
"Water Rune",
"Steam Rune",
"Steam Rune",
"Controlled Heat Potion II",
"Wolf",
"Wolf",
"Cyclops",
"Fox",
"Leprechaun",
"Leprechaun",
"Void Wisp",
"Redwood Logs",
"Redwood Logs",
"Shadow Raven Nest",
"Raw Shrimp",
"Shrimp",
"Carrot Cake",
"Carrot Cake",
"Carrot Cake (Perfect)",
"Carrot Cake (Perfect)",
"Mantalyme Herb",
"Mantalyme Herb",
"Carrot",
"Carrot",
"Controlled Heat Potion II",
"Topaz",
"Topaz",
"Rune Essence",
"Oricha",
"Nightopal",
"Sanguine Blade",
"Sanguine Blade",
"Ring of Power",
"Ring of Power",
Line 1,482: Line 1,684:
"Chapeau Noir",
"Chapeau Noir",
"Stardust",
"Stardust",
"Golden Stardust",
"Abyssal Stardust",
"Rope",
"Rope",
"Ancient Ring of Mastery",
"Ancient Ring of Mastery",
Line 1,487: Line 1,691:
"Gem Gloves",
"Gem Gloves",
"Thief's Moneysack",
"Thief's Moneysack",
"Golden Stardust",
"Golden Star",
"Golden Star",
"Slayer Deterer",
"Slayer Deterer",
Line 1,494: Line 1,697:
"Aranite Brush",
"Aranite Brush",
"Barrier Dust",
"Barrier Dust",
"Shadow Raven Nest",
"Obsidian Tendril",
"Void Wisp"
"Obsidian Bark",
"Obsidian Thorn",
"Obsidian Vein Seed",
"Elite Chest",
}
}
local checkFuncs = {
local checkFuncs = {
--p.getItemSourceTables,
--p.getItemSourceTables,
--p.getCreationTable,
p.getCreationTable,
--p.getItemSources,
--p.getItemSources,
--p.getItemLootSourceTable,
--p.getItemLootSourceTable,