RuneScape Wiki
mNo edit summary
mNo edit summary
Line 632: Line 632:
 
local icon = T.name
 
local icon = T.name
 
-- Check for specified icon
 
-- Check for specified icon
if T.icon then icon = T.icon end
+
if T.icon ~= nil then icon = T.icon end
 
-- Check for flatpacks and adjust
 
-- Check for flatpacks and adjust
 
if eltArgs.disp == "Flatpacks" then icon = icon .. " (flatpack)" end
 
if eltArgs.disp == "Flatpacks" then icon = icon .. " (flatpack)" end
 
-- Check for farming and make adjustments for seed icons
 
-- Check for farming and make adjustments for seed icons
 
if eltArgs.skill == "Farming" then
 
if eltArgs.skill == "Farming" then
if T.seed then
+
if T.seed ~= nil then
 
icon = T.name .. "_" .. T.seed
 
icon = T.name .. "_" .. T.seed
 
end
 
end
Line 646: Line 646:
 
local link, linkTitle = T.name
 
local link, linkTitle = T.name
 
-- Check if a title was specified
 
-- Check if a title was specified
if T.title then linkTitle = T.title end
+
if T.title ~= nil then linkTitle = T.title end
 
-- Setup titled link
 
-- Setup titled link
 
link = '[[' .. T.name .. '|' .. linkTitle .. ']]'
 
link = '[[' .. T.name .. '|' .. linkTitle .. ']]'
 
-- If specified, append additional wiki-links
 
-- If specified, append additional wiki-links
if T.extLink then link = link .. " " .. T.extLink end -- (eg [[Voice of Seren]])
+
if T.extLink ~= nil then link = link .. " " .. T.extLink end -- (eg [[Voice of Seren]])
 
-- Check for Members only
 
-- Check for Members only
 
if T.members == 1 then link = link .. membersOnly end
 
if T.members == 1 then link = link .. membersOnly end
Line 665: Line 665:
 
if not (T.currency == nil) and T.material then
 
if not (T.currency == nil) and T.material then
 
materials = "<div style='text-align:left'>" .. expandedList(T.material,actionsRequired) .. "</div>"
 
materials = "<div style='text-align:left'>" .. expandedList(T.material,actionsRequired) .. "</div>"
elseif T.material then
+
elseif T.material ~= nil then
 
materials = "<div style='text-align:left'>" .. createList(T.material,actionsRequired) .. "</div>"
 
materials = "<div style='text-align:left'>" .. createList(T.material,actionsRequired) .. "</div>"
elseif T.familiar then
+
elseif T.familiar ~= nil then
 
local familiar = mw.text.split(T.familiar, "<")[1]
 
local familiar = mw.text.split(T.familiar, "<")[1]
if T.familiarTitle then familiar = mw.text.split(T.familiarTitle, "<")[1] end
+
if T.familiarTitle ~= nil then familiar = mw.text.split(T.familiarTitle, "<")[1] end
 
 
 
materials = "<div style='text-align:left'>" ..
 
materials = "<div style='text-align:left'>" ..
Line 677: Line 677:
 
 
 
-- Set default currency settings, then determine if alternative used
 
-- Set default currency settings, then determine if alternative used
if T.currency then currency = T.currency end
+
if T.currency ~= nil then currency = T.currency end
 
 
 
-- Mostly for Fishing
 
-- Mostly for Fishing
if T.equipment then
+
if T.equipment ~= nil then
 
local equipmentLink = mw.text.split(T.equipment, "<")[1]
 
local equipmentLink = mw.text.split(T.equipment, "<")[1]
 
-- Check if an equipment link was specified
 
-- Check if an equipment link was specified
if T.eLink then equipmentLink = T.eLink end
+
if T.eLink ~= nil then equipmentLink = T.eLink end
 
 
 
equipment = imageLink{
 
equipment = imageLink{

Revision as of 11:18, 12 January 2018

Documentation for this module may be created at Module:Skill calc/eltGenerator/doc

-- <pre>
local commas        = require('Module:Addcommas')._add
local tables        = require('Module:Tables')
local coins         = require('Module:Coins')._amount
local currency      = require('Module:Currency')._amount
local numbers       = require('Module:Number')._round

local eltData = {}

--[=[ 
        Note: Once all existing calculators have been converted, this Module will be cleaned
              up to remove any spaghetti code.
--]=]



--[=[ 
Generates a No profit, Purely Loss skill table
skills: Construction, Firemaking, Prayer
Inputs:
    v           data from caller
    unitExp     experience per iteration
    needed      required iterations for goal
    fileName    page location
    cost        cost per iteration
    args        additional parameters from caller
returns: 
    Table of data using proper elts based on skill
--]=]
function eltData.generate_NoProfitLoss(frame)
    local T           = frame.args[1]
    local unitExp     = frame.args[2]
    local needed      = frame.args[3]
    local fileName    = frame.args[4]
    local cost        = frame.args[5]
    local eltArgs     = frame.args[6]
    local productCost = frame.args[7]
    local images, links
    local memb = '<sub title="Members only" style="cursor:help; margin-left:3px;">(m)</sub>'

    -- Set default currency settings, then determine if alternative used
    local dispCurr = "int"
    local dispCurr2 = "int"
    if T.currency then dispCurr = T.currency end
    if T.currency2 then dispCurr2 = T.currency2 end

    -- Check for multiple images
    -- This occurs when multiple materials are required
    if T.multi then
        images  = 
                    imageLink{file=mw.text.split(T.multi[1], "<")[1],image=T.multi[1]},
                    imageLink{file=mw.text.split(T.multi[2], "<")[1],image=T.multi[2]}
        links   =
                    '[[' .. mw.text.split(T.multi[1], "<")[1] .. ']]',
                    '[[' .. mw.text.split(T.multi[2], "<")[1] .. ']]'
    -- Single images only at then
    else
        -- Set the image location
        -- Default with using our page for the icon
        local ourIcon = mw.text.split(fileName, "<")[1]
        
        -- Check for flatpacks and adjust
        if eltArgs.disp == "Flatpacks" then ourIcon = ourIcon .. " (flatpack)" end
            
        -- Check if we specified an image location and make adjustments
        if T.image then ourIcon = mw.text.split(T.image, "<")[1] end
        if T.icon then ourIcon = mw.text.split(T.icon, "<")[1] end
        
        -- Check if the icon has been modified
        if T.iconSize then
            images = imageLink{file=mw.text.split(T.name, "<")[1],image=ourIcon,iconSize=T.iconSize}
        else
            images = imageLink{file=mw.text.split(T.name, "<")[1],image=ourIcon}
        end
        
        -- Set the item's [link]
        -- Default with using the item's name
        local ourTitle = mw.text.split(T.name, "<")[1]
        
        -- Check if we specified a page location
        if T.title then ourTitle = T.title end
                
        links  = '[[' .. mw.text.split(T.name, "<")[1] .. '|' .. ourTitle .. ']]'
    end

    -- Set non-link text, if any
    if T.sLink then links = T.sLink .. " " .. links end
    if T.eLink then links = links .. " " .. T.eLink end

    -- Check for Members only
    if T.mem == 1  then links = links .. memb end

    -- Start here and build the elt down through conditionals
    elts =
    {
        images,
        links
    }
    
    -- Prayer needs an override since it is missing parts
    if eltArgs.skill == "Prayer" then
        table.insert(elts, 3, numbers(unitExp, 1))
        table.insert(elts, 4, commas(needed))
        table.insert(elts, 5, coins(cost * needed))
        if not (eltArgs.disp == "Urns") then
            table.insert(elts, 6, coins(string.format("%.2f", (cost / unitExp), 1))) end
    else
        table.insert(elts, 3, numbers(T.level)) -- T.level should be present for all of these
        
        if eltArgs.disp == "Rooms" then
            table.insert(elts, 4, coins(T.coins))
        else
            table.insert(elts, 4, numbers(unitExp, 1))
            if eltArgs.disp == "Milestones" then
                if T.coins then
                        table.insert(elts, 5, 
                    "<div style='text-align:center'>" .. coins(T.coins) .. "</div>")
                else
                    table.insert(elts, 5, "<div style='text-align:center'>-</div>")
                end
            else
                table.insert(elts, 5, commas(needed))
                if not (eltArgs.disp == "Char") then
                    if not (T.currency2 == nil) and T.material2 then
                        table.insert(elts, 6, 
                        "<div style='text-align:left'>" .. createList(T.material,needed) .. "<br />"
                        .. createList(T.material2,needed) .. "</div>")
                    else
                        table.insert(elts, 6, 
                            "<div style='text-align:left'>" .. createList(T.material,needed) .. "</div>")
                    end
                    if eltArgs.skill == "Magic" then
                        table.insert(elts, 7, coins(cost*needed))
                    else
                    --[=[ This should work, just need the Castle War Tickets (Silver & Gold)
                          added to Module:Currency
                        if T.currency2 then
                            table.insert(elts, 7, 
                            "<div style='text-align:left'>" .. coins(cost) .. "<br />"
                            .. printCoins(productCost, dispCurr .. "-dec") .. "</div>")
                            table.insert(elts, 8, 
                            "<div style='text-align:left'>" .. coins(cost * needed) .. "<br />"
                            .. printCoins((productCost * needed), dispCurr .. "-dec") .. "</div>")
                            table.insert(elts, 9, "<div style='text-align:left'>" 
                            .. coins(string.format("%.2f", (cost / unitExp), 1)) .. "<br />"
                            .. printCoins((productCost/unitExp), dispCurr .. "-dec") .. "</div>")
                        else
                    --]=]
                        if not (eltArgs.skill == "Firemaking" and eltArgs.disp == "Barbarian") then
                            table.insert(elts, 7, printCoins(cost, "int"))
                            table.insert(elts, 8, printCoins(cost * needed, "int"))
                            if not (cost == 0 and unitExp == 0) then -- if not (NaN)
                                table.insert(elts, 9, printCoins(cost / unitExp, "dec"))
                            else                table.insert(elts, 9, "-") end
                        end
                        --end
                    end -- Skill == Magic
                end
            end -- Skill == Milestones or Skill ~= Milestones
        end -- Disp ~= Rooms
    
        -- Check for flatpack exception
        -- Add bench image
        if eltArgs.disp == "Flatpacks" then
            table.insert(elts, 3, 
                imageLink{
                    file=mw.text.split(T.bench, "<")[1],
                    image=mw.text.split(T.bench, "<")[1],
                    alt=T.bench})
        end
    end

    return elts
end -- generate_NoProfitLoss

--[=[
Generates a No Profit, No Loss skill table
skills: Agility, Slayer, Thieving
inputs:
    T           Data being processed from 'Module:Skill calc/' .. args.skill .. '/data'
    unitExp     Generated unit exp including bonuses
    needed      Required iterations for goal
    ext         Image/Icon extension
    icon        File name of icon
    altName     Page name
returns:
    Table of data using proper elts based on skill
--]=]
function eltData.generate_NoProfitNoLoss(frame)
    local T         = frame.args[1]
    local unitExp   = frame.args[2]
    local needed    = frame.args[3]
    local altName   = frame.args[4]
    local eltArgs   = frame.args[5]
    local icon      = frame.args[6]
    local ext       = frame.args[7]
    local currLv    = frame.args[8]
    local images, links, sLink, eLink
    local memb = '<sub title="Members only" style="cursor:help; margin-left:3px;">(m)</sub>'
    local icon = ""
    
    if T.icon then icon = T.icon end
    
    -- if no icon is available/set, a blank space will be displayed
    if icon ~= nil then
        icon    =   imageLink
                    {
                        file=T.page,
                        image=icon,
                        ext=ext,
                        iconSize=T.iconSize
                    }
    end

    -- Determine link
    local linkTitle = T.page
    -- Check if an override was provided
    if altName then linkTitle = altName end

    links   =   '[[' .. T.page .. '|' .. linkTitle .. ']]'
    if T.sLink then links = T.sLink .. " " .. links end
    if T.eLink then links = links .. " " .. T.eLink end
    
    -- Check for Members only
    if T.mem == 1 then links = links .. memb end

    elts =
    {
        icon,
        links,
        numbers(T.level)
    }

    if eltArgs.skill == "Slayer" then
        if eltArgs.disp == "Assignments" then
            table.insert(elts, 4, T.level2)
            table.insert(elts, 5, commas(numbers(unitExp,1)))
            if currLv >= T.level2 then      table.insert(elts, 6, commas(needed))
            else                            table.insert(elts, 6, "<div style='text-align:center'>-</div>")
            end
        end
    elseif eltArgs.skill == "Agility" then
        if not (eltArgs.disp == "Milestones" or eltArgs.disp == "Multiples" 
            or eltArgs.disp == "Other") then
            table.insert(elts, 4, commas(numbers(unitExp,1)))
            if currLv >= T.level then       table.insert(elts, 5, commas(needed))
            else                            table.insert(elts, 5, "<div style='text-align:center'>-</div>")
            end
        end
    else
        table.insert(elts, 4, commas(numbers(unitExp,1)))
        if currLv >= T.level then           table.insert(elts, 5, commas(needed))
        else                                table.insert(elts, 5, "<div style='text-align:center'>-</div>")
        end
    end
    
    return elts
end -- generate_NoProfitNoLoss

--[=[
Generates a potential Profit, potential Loss skill table
skills: Fletching, Cooking, Farming, Smithing, Herblore, Summoning
inputs:
    T           Data being processed from 'Module:Skill calc/' .. args.skill .. '/data'
--  unitExp     experience per iteration
--  needed      required iterations for goal
--  fileName    page location
--  rawCost     ingredient cost per iteration
--  productCost product value per iteration
--  args        additional parameters from caller
returns:
    Table of data using proper elts based on skill
--]=]
function eltData.generate_ProfitLoss(frame)
    local T             = frame.args[1]
    local unitExp       = frame.args[2]
    local needed        = frame.args[3]
    local fileName      = frame.args[4]
    local rawCost       = frame.args[5]
    local eltArgs       = frame.args[6]
    local productCost   = frame.args[7]
    local images, links

    -- If alternative currencies are used, the Grand Exchange will not have information
    local materials = ""
    if not (T.currency == nil) and T.material then
        materials = "<div style='text-align:left'>" .. expandedList(T.material,needed) .. "</div>"
    elseif T.material then
        materials = "<div style='text-align:left'>" .. createList(T.material,needed) .. "</div>"
    elseif T.familiar then
        local altTitle = mw.text.split(T.familiar, "<")[1]
        if T.familiarTitle then altTitle = mw.text.split(T.familiarTitle, "<")[1] end
        
        materials = "<div style='text-align:left'>" .. 
                        peLink(mw.text.split(T.familiarIcon, "<")[1], mw.text.split(T.familiar, "<")[1], altTitle) .. 
                    "</div>"
    end
    
    -- Set default currency settings, then determine if alternative used
    local displayCurrency = "int"
    if T.currency then
        displayCurrency = T.currency end
    
    -- Check for multiple images
    -- This occurs when multiple materials are required
    if T.multi then
        images  = 
                    imageLink{file=mw.text.split(T.multi[1], "<")[1],image=T.multi[1]},
                    imageLink{file=mw.text.split(T.multi[2], "<")[1],image=T.multi[2]}
        links   =
                    '[[' .. mw.text.split(T.multi[1], "<")[1] .. ']]',
                    '[[' .. mw.text.split(T.multi[2], "<")[1] .. ']]'
                    
    -- Single images only at then
    else
        -- Set the image location
        
        -- Default with using our page for the icon
        local ourIcon = mw.text.split(fileName, "<")[1]
        
        -- Check for farming and make adjustments for seed icons
        if eltArgs.skill == "Farming" then 
            if T.seed then 
                ourIcon = mw.text.split(T.name, "<")[1] ..  "_" .. mw.text.split(T.seed, "<")[1] 
            end
        end
        
        -- Check if an image location was specified
        if T.image then ourIcon = mw.text.split(T.image, "<")[1] end
        if T.icon then ourIcon = mw.text.split(T.icon, "<")[1] end
            
        images = imageLink{file = mw.text.split(T.name, "<")[1], image = ourIcon}
        
        -- Set the item's [link]
        -- Default with using the item's name
        local ourTitle = mw.text.split(T.name, "<")[1]
        
        -- Check if we specified a page location
        if T.title then ourTitle = T.title end
                
        links  = '[[' .. mw.text.split(T.name, "<")[1] .. '|' .. ourTitle .. ']]'
    end

    elts =
    {
        images,
        links,
        T.level,
        commas(unitExp, 1),
        commas(needed)
    }
    
    if eltArgs.disp == "Forging" then
        table.insert(elts, 6, printCoins( productCost * needed, "int" ))
        table.insert(elts, 7, printCoins( productCost / unitExp, "dec"))
    else
        table.insert(elts, 6, materials)
        
        if not (string.find(eltArgs.disp,"Dungeoneering - ")) then
            table.insert(elts, 7, printCoins( rawCost * needed, displayCurrency ))
            
            if not (eltArgs.skill == "Farming") then
                table.insert(elts, 8, printCoins( productCost * needed, displayCurrency ))
                table.insert(elts, 9, printCoins( (productCost - rawCost) * needed, displayCurrency ))
    
                if T.currency then
                    table.insert(elts, 10, 
                        printCoins( (productCost - rawCost) / unitExp, T.currency .. "-dec" ))
                else
                    table.insert(elts, 10, printCoins( (productCost - rawCost) / unitExp, "dec" ))
                end
            end
        end 
    
        if T.charm then
            table.insert(elts, 3, imageLink{file = mw.text.split(T.charm .. " charm", "<")[1], image = mw.text.split(T.charm .. " charm", "<")[1]})
        end
    end
    return elts
end -- generate_ProfitLoss

--[=[
Generates a Purely Profit, No Loss skill table
skills:
    Divination, Fishing, Mining, Woodcutting, Runecrafting, Hunter
inputs:
    T           Data being processed from 'Module:Skill calc/' .. args.skill .. '/data'
    unitExp     Generated unit exp including bonuses
    needed      Required iterations for goal
    ext         Image/Icon extension
    icon        File name of icon
    altName     Page name
returns:
    Table of data using proper elts based on skill
--]=]
function eltData.generate_ProfitNoLoss(frame)
    local T          = frame.args[1]
    local unitExp    = frame.args[2]
    local needed     = frame.args[3]
    local fileName   = frame.args[4]
    local rawCost    = frame.args[5]
    local eltArgs    = frame.args[6]
    local icon       = frame.args[7]
    local ext        = frame.args[8]
    local income     = frame.args[9]
    local remaining  = frame.args[10]
    local images, links

    -- Default with using item's name for the icon
    local ourIcon = mw.text.split(fileName, "<")[1]
    -- Check if an icon image was specified
    if T.icon then ourIcon = mw.text.split(T.icon, "<")[1] end
    -- Hunter is a little different
    if eltArgs.skill == "Hunter" then
        if T.title and 
           not T.icon  then 
               ourIcon = mw.text.split(T.title, "<")[1] 
        end
    end

    -- Set the item's [link]
    -- Default with using the item's name
    local ourLink       = mw.text.split(T.name, "<")[1]
    local ourTitle      = mw.text.split(T.name, "<")[1]
    local equipmentLink = ""
    local ourIconSize      = 0
    
    -- Check if a page location was specified
    if T.link then ourLink = mw.text.split(T.link, "<")[1] end
    -- Check if a title was specified
    if T.title then ourTitle = mw.text.split(T.title, "<")[1] end
    
    if T.equipment then
        equipmentLink = mw.text.split(T.equipment, "<")[1]
        -- Check if an equipment link was specified
        if T.eLink then equipmentLink = mw.text.split(T.eLink, "<")[1] end
    end
    
    if T.iconSize then ourIconSize = T.iconSize end
    
    -- Set the actual icon image
    images = imageLink{file = ourLink, image = ourIcon, iconSize = ourIconSize}
            
    links  = '[[' .. ourLink .. '|' .. ourTitle .. ']]'
    
    -- Check if there are materials and create a list
    local materialList = "-"
    if T.material then
        materialList = "<div style='text-align:left'>" .. createList(T.material,needed) .. "</div>"
    end
    
    -- Put it all together
    if eltArgs.disp == "Urns" then
        elts =
            {
                images,
                links,
                commas(unitExp,1),
                commas(needed),
                printCoins( (rawCost * needed), "int" )
            }
    elseif eltArgs.skill == "Fishing" then
        elts =
        {
            images,
            links,
            imageLink{
                file=equipmentLink,
                image=mw.text.split(T.equipment, "<")[1],
                alt=equipmentLink},
            materialList,
            T.level,
            commas(unitExp,1),
            commas(needed)
        }
        
        if not (eltArgs.disp == "Dungeoneering") then
            table.insert(elts, 8, printCoins( income * needed, "int" ))
            table.insert(elts, 9, printCoins( rawCost * needed, "int" ))
            table.insert(elts, 10, printCoins( (income - rawCost) * needed, "int" ))
        end
    -- This section also accounts for base rune production multipliers
    elseif eltArgs.skill == "Runecrafting" then
        if eltArgs.disp == "Tiaras" then
            elts = 
            {
                images,
                links,
                materialList,
                commas(unitExp,1),
                commas(needed),
                printCoins( rawCost * needed, "int" ),
                printCoins( (income * needed), "int" ),
                printCoins( (income - rawCost ) * needed, "int" )
            }
        elseif eltArgs.disp == "Runespan - Free" or eltArgs.disp == "Runespan - Members" then
            elts = 
            {
                images,
                links,
                T.level,
                commas(unitExp,1),
                commas(needed)
            }
        else
            elts = 
            {
                images,
                links,
                T.level,
                materialList,
                commas(unitExp,1),
                commas(needed),
                printCoins( rawCost * needed, "int" ),
                printCoins( 
                    (income * needed) * levelMultiplier(ourIcon, tonumber(eltArgs.current)), "int" ),
                printCoins( 
                    ( (income * levelMultiplier(ourIcon, tonumber(eltArgs.current))) - rawCost ) 
                        * needed, "int" )
            }
        end
    elseif eltArgs.skill == "Divination" then
        -- These allow for Cursed modification (tiered experience)
        local modifyExp = 1
        local modifyNeeded = needed
        
        if T.name == "Cursed wisp" or T.name == "Cursed memory" then 
            modifyExp = levelMultiplier(T.name, tonumber(eltArgs.current))
            modifyNeeded = tonumber(math.ceil(remaining / (unitExp * modifyExp))) end
        
        if eltArgs.disp == "Harvest" then
            elts =
            {
                images,
                links,
                T.level,
                commas(unitExp * modifyExp, 1),
                commas(modifyNeeded, 1),
                printCoins( 
                        (income * levelMultiplier(ourIcon, tonumber(eltArgs.current))) 
                            * modifyNeeded, "int" )
            }
        else
            elts =
            {
                images,
                links,
                T.level,
                materialList,
                commas(unitExp * modifyExp, 1),
                commas(modifyNeeded, 1),
                printCoins( (0 - rawCost) * modifyNeeded, "int" )
            }
        end
    else
        elts =
        {
            images,
            links,
            T.level,
        }
        table.insert(elts, 4, commas(unitExp,1))
        table.insert(elts, 5, commas(needed))

        if not (eltArgs.disp == "Dungeoneering" or 
          (eltArgs.skill == "Woodcutting" and eltArgs.disp == "Other") or (eltArgs.skill == "Hunter")) then
            table.insert(elts, 6, printCoins(income * needed, "int")) end
        
        if eltArgs.skill == "Hunter" then
            local targetElt = 6
            
            if (eltArgs.disp == "Nets and Sprites" or
               eltArgs.disp == "Deadfall and Pitfall" or
               eltArgs.disp == "Box Trapping") then
                if T.bait then
                    table.insert(elts, targetElt, pLink(T.bait))
                else
                    table.insert(elts, targetElt, "-")
                end
                
                targetElt = targetElt + 1 
                
            end
            
            if T.product then
                local currency = "Coins"
                if T.currency then currency = T.currency end
                    table.insert(elts, targetElt, inlineProfit(income, needed, T.product, currency))
            else 
                table.insert(elts, targetElt, "-")
            end

        end
    end
            
    return elts
end -- generate_ProfitNoLoss

------------------------------------------------------
-------- Contemplating a global generator ------------
------------------------------------------------------

function eltData.generate_elts(frame)
    -- Don't worry about this function. I will be working on this over time to see if 
    -- everything can be generalized and merged into a single function and remain clear to remove repeated code
    -- Descriptive names make it more readily understandable
    
    local membersOnly = '<sub title="Members only" style="cursor:help; margin-left:3px;">(m)</sub>' -- May be implemented differently

    -- These variables will always be passed through the initial call, even if they are not used
    -- (nil will be passed instead). Trying to use T and eltArgs more in code.
    local T                 = frame.args[1]     -- Individual item data
    local eltArgs           = frame.args[2]     -- Calculator data
    local actionExp         = frame.args[3]     -- Individual item experience with bonuses
    local actionsRequired   = frame.args[4]     -- Calculated iterations using actionExp
    local expRequired       = frame.args[5]     -- User experience data
    local rawCost           = frame.args[6]     -- Cost of materials
    local productCost       = frame.args[7]     -- Income from actions
    local eltTitles         = frame.args[8]     -- Array of elt titles
    
    local currentLevel      = tonumber(eltArgs.current)
    
    local imageExtension = ".png"
    if T.ext then imageExtension = T.ext end
    
    ---------------------------------------
    --- Begin overrides from skill data ---
    ---------------------------------------
    
    ------ Handle icons ------
        
        local icon = T.name
        -- Check for specified icon
        if T.icon ~= nil then icon = T.icon end
        -- Check for flatpacks and adjust
        if eltArgs.disp == "Flatpacks" then icon = icon .. " (flatpack)" end
        -- Check for farming and make adjustments for seed icons
        if eltArgs.skill == "Farming" then 
            if T.seed ~= nil then 
                icon = T.name ..  "_" .. T.seed
            end
        end
    
    ------ Handle title & link ------
        
        local link, linkTitle = T.name
        -- Check if a title was specified
        if T.title ~= nil then linkTitle = T.title end
        -- Setup titled link
        link  = '[[' .. T.name .. '|' .. linkTitle .. ']]'
        -- If specified, append additional wiki-links
        if T.extLink ~= nil then link = link .. " " .. T.extLink end -- (eg [[Voice of Seren]])
        -- Check for Members only
        if T.members == 1  then link = link .. membersOnly end
        
        
    -- Set the actual icon image
    icon = imageLink{file = link, image = icon}
    
    ------ Handle materials ------
        
        local materials, familiar, equipment = ""
        local currency = "coins"
        -- If alternative currencies are used, the Grand Exchange will not have information
        if not (T.currency == nil) and T.material then
            materials = "<div style='text-align:left'>" .. expandedList(T.material,actionsRequired) .. "</div>"
        elseif T.material ~= nil then
            materials = "<div style='text-align:left'>" .. createList(T.material,actionsRequired) .. "</div>"
        elseif T.familiar ~= nil then
            local familiar = mw.text.split(T.familiar, "<")[1]
            if T.familiarTitle ~= nil then familiar = mw.text.split(T.familiarTitle, "<")[1] end
            
            materials = "<div style='text-align:left'>" .. 
                            peLink(T.familiarIcon, mw.text.split(T.familiar, "<")[1], altTitle) .. 
                        "</div>"
        end
        
        -- Set default currency settings, then determine if alternative used
        if T.currency ~= nil then currency = T.currency end
        
        -- Mostly for Fishing 
        if T.equipment ~= nil then
            local equipmentLink = mw.text.split(T.equipment, "<")[1]
            -- Check if an equipment link was specified
            if T.eLink ~= nil then equipmentLink = T.eLink end
            
            equipment = imageLink{
                            file=equipmentLink,
                            image=mw.text.split(T.equipment, "<")[1],
                            alt=equipmentLink}
        end

    ---------------------------------------
    ---- End overrides from skill data ----
    ---------------------------------------
    
    -------------------------------
    --- Begin data calculations ---
    -------------------------------
    
    local grossIncome, grossCost, netIncome = 0
    local avgNet, avgCost = 0
    local modifiedExp = 1   -- default value
    local modifiedNeeded = actionsRequired   -- default value
    
    if eltArgs.skill == "Runecrafting" and
       eltArgs.disp == "Runes" then
        
        grossIncome = (income * actionsRequired) * levelMultiplier(T.name, currentLevel)
        netIncome   = ((income * levelMultiplier(T.name, currentLevel)) - rawCost ) * actionsRequired
    
    elseif eltArgs.skill == "Divination" and                
            T.name == "Cursed wisp" or T.name == "Cursed memory" then
                
            modifiedExp = levelMultiplier(T.name, currentLevel)
            modifiedNeeded = tonumber(math.ceil(actionsRequired / (actionExp * modifiedExp)))
                
    else
        if rawCost ~= nil then
            grossCost = rawCost * actionsRequired end
        
        if productCost ~= nil then
            grossIncome = productCost * actionsRequired end
        
        if (rawCost ~= nil and productCost ~= nil) then
            netIncome = (productCost - rawCost) * actionsRequired 
        elseif rawCost ~= nil and rawCost ~= 0 then
            netIncome = 0 - grossCost -- Force a negative; may not be needed
        elseif productCost ~= nil and grossIncome ~= 0 then
            netIncome = grossIncome
        end
        
        avgNet = netIncome / actionsRequired
        avgCost = netIncome / actionExp
        
    end
    
    -------------------------------
    ---- End data calculations ----
    -------------------------------
    
    -------------------------------
    ---- Begin elt construction ---
    -------------------------------
    
    local generatedValues = 
            {
                icon            = icon,
                link            = link,
                level           = T.level,
                actionExp       = actionExp,
                actionsRequired = commas(actionsRequired),
                netIncome       = printCoins(netIncome, "int"),
                materials       = materials,
                rawCost         = printCoins(rawCost, "int"),
                avgCost         = printCoins(avgCost, "dec"),
                grossCost       = printCoins(grossCost, "int"),
                grossIncome     = printCoins(grossIncome, "int"),
            }
            
    local elts = {}
    
    -- I think this is going to be the cleanest method of the ones we've tried.
    -- Not sure about performance-wise, since every item calls another round of
    --  looping through titles.
    for i, title in ipairs(eltTitles) do
        findEltData(title, generatedValues, elts)
    end
    
    -- These are special cases not worth including in the helper function
    if eltArgs.skill == "Summoning" and 
        eltArgs.disp ~= "Scrolls" then
        local charm = imageLink{
                        file = T.charm .. " charm", 
                        image = T.charm .. " charm"}
        table.insert(elts, charm, 3)                    -- Include summoning charms required
    elseif eltArgs.skill == "Fishing" then
        table.insert(elts, equipment, 3)                -- Include necessary equipment
    elseif eltArgs.skill == "Hunter" then
        local targetElt = 6
        if (eltArgs.disp == "Nets and Sprites" or
           eltArgs.disp == "Deadfall and Pitfall" or
           eltArgs.disp == "Box Trapping") then
            if T.bait then
                table.insert(elts, targetElt, pLink(T.bait))    -- Include necessary bait
            else
                table.insert(elts, targetElt, "-")              -- No bait necessary
            end
            targetElt = targetElt + 1 
        end
        
        if T.product then
            local currency = "Coins"
            if T.currency then currency = T.currency end
                table.insert(elts, targetElt, inlineProfit(income, needed, T.product, currency))    -- Income
        else 
            table.insert(elts, targetElt, "-")  -- Nothing can be sold
        end
        
    end
    
    -------------------------------
    ----- End elt construction ----
    -------------------------------
    
    return elts
end


--------------------------------------
-------- Helper Functions ------------
--------------------------------------

-- ##Antiquated; needs to be phased out for pLink or peLink
function imageLink(params)
    local ext = ".png"
    local iconSize = nil
    if params.iconSize and params.iconSize > 0 then iconSize = params.iconSize end
    if params.ext then ext = params.ext end
    -- param.iconSize sets icon size if using a non-icon sized image.
    -- Replace this if you'd like to set all images to the same size (eg: 30px) without all the extra coding

    if params.alt then
        if params.image == "Bench with lathe" then
            return '[[File:Bench with lathe icon' .. ext .. '|link=' .. params.file .. '|' .. params.file .. ']]'
        elseif (iconSize) then
            return '[[File:' .. params.image .. ext .. '|' .. iconSize .. '|link=' .. params.file .. '|' .. params.alt .. ']]'
        else
            return '[[File:' .. params.image .. ext .. '|link=' .. params.file .. '|' .. params.alt .. ']]'
        end
    elseif not (iconSize == nil) then
        return '[[File:' .. params.image .. ext .. '|' .. iconSize .. 'px|link=' .. params.file .. '|' .. params.file .. ']]'
    else
        return '[[File:' .. params.image .. ext .. '|link=' .. params.file .. '|' .. params.file .. ']]'
    end
end -- imageLink

function createList(mess,a)
    local sentence = ""
    if not (mess == nil) then
        for i, v in ipairs(mess) do

            if (i%2) > 0 then
                sentence = "" .. sentence .. " " .. commas( v * a ) 
            else
                if i == table.getn(mess) then
                    sentence = sentence .. " " .. pLink(v)
                else
                    sentence = sentence .. " " .. pLink(v) .. "<br />"
                end
            end
        end
    else
        sentence = "-"
    end
 
    return sentence
end -- createList

-- This function is used for alternative currencies
-- ##Antiquated; should be phased out for mw.text.split usage
function expandedList(mess, a)
    local sentence = ""
    local follower = 0
    for i, v in ipairs(mess) do
        if type(v) == "number" then
            if follower == 0 then
                sentence = "" .. sentence .. " " .. commas( v * a ) 
                follower = 1
            else follower = 0 end
        else
            local parts = explode(",", v)
            local image = v
            local link = v
            if table.getn(parts) > 1 then
                image = parts[1]
                link = parts[2] end
            
            if i == table.getn(mess) then
                sentence = sentence .. " " .. peLink(image,link,link)
            else
                sentence = sentence .. " " .. peLink(image,link,link) .. "<br />"
            end
        end
    end
 
    return sentence
end

-- This is a simplified implementation of Template:Plink
function pLink(a)
    return "[[File:" .. a .. ".png|link=" .. a .. "]]&nbsp;[[" .. a .. "|" .. a .. "]]"
end -- plink

-- An extended implementation of pLink
function peLink(file, link, title)
    return "[[File:" .. file .. ".png|link=" .. link .. "]]&nbsp;[[" .. link .. "|" .. title .. "]]"
end -- pelink
 
function explain(message)
    local ret = mw.html.create('span'):css({['color'] = "#15f", ['border-bottom'] = "dotted 1px black", ['cursor'] = 'help'}):attr("title", message):wikitext("?")
    return "[" .. tostring(ret) .. "]"
end -- explain

-- This takes the amount of coins needed to display in table, 
--   but filters out 0s to make untradeables look better.
-- This function utilizes Module:Currency for alternative currency handling
function printCoins(amount, category)
    if amount ~= 0 then
        if category == "dec" then
            return coins(string.format("%.2f", amount, 1))
        elseif category == "int" then
            return coins(amount, 1)
        elseif category == "chimes-dec" then
            return currency(string.format("%.2f", amount, 1), "chimes")
        elseif category == "chimes" then
            return currency(amount, "chimes")
--[=[
        elseif category == "cwts" then              return currency(amount, "cwts")
        elseif category == "cwts-dec" then          return currency(string.format("%.2f", amount, 1), "cwts")
        elseif category == "cwtg" then              return currency(amount, "cwtg")
        elseif category == "cwtg-dec" then          return currency(string.format("%.2f", amount, 1), "cwtg")
--]=]
        end
    else
        return "-"
    end
end

--[[ levelMultiplier function
--      input:
--              item    :: key being searched
--              level   :: subject's relevant level
--      output:
--              Returns a base multiplier to modify experience or production levels depending
--               on the item being searched. Most items refer to multiple rune production,
--               but 'cursed' versions within divination give tiered experience.
--]]
function levelMultiplier(item, level)
    local ret = 1
    
    if item == "Air rune" then
        if     level >= 99 then ret = 10 
        elseif level >= 88 then ret = 9
        elseif level >= 77 then ret = 8
        elseif level >= 66 then ret = 7
        elseif level >= 55 then ret = 6
        elseif level >= 44 then ret = 5
        elseif level >= 33 then ret = 4
        elseif level >= 22 then ret = 3
        elseif level >= 11 then ret = 2 end

    elseif item == "Mind rune" then
        if     level >= 112 then ret = 9
        elseif level >= 98 then ret = 8
        elseif level >= 84 then ret = 7
        elseif level >= 70 then ret = 6
        elseif level >= 56 then ret = 5
        elseif level >= 42 then ret = 4
        elseif level >= 28 then ret = 3
        elseif level >= 14 then ret = 2 end
    
    elseif item == "Water rune" then
        if     level >= 114 then ret = 7
        elseif level >= 95 then ret = 6
        elseif level >= 76 then ret = 5
        elseif level >= 57 then ret = 4
        elseif level >= 38 then ret = 3
        elseif level >= 19 then ret = 2 end

    elseif item == "Earth rune" then
        if     level >= 104 then ret = 5
        elseif level >= 78 then ret = 4
        elseif level >= 52 then ret = 3
        elseif level >= 26 then ret = 2 end

    elseif item == "Fire rune" then
        if     level >= 105 then ret = 4
        elseif level >= 70 then ret = 3
        elseif level >= 35 then ret = 2 end

    elseif item == "Body rune" then
        if     level >= 92 then ret = 3
        elseif level >= 46 then ret = 2 end

    elseif item == "Cosmic rune" and level >= 118 then ret = 2
    elseif item == "Chaos rune"  and level >= 74 then ret = 2
    elseif item == "Astral rune" and level >= 82 then ret = 2
    elseif item == "Nature rune" and level >= 91 then ret = 2
    elseif item == "Law rune"    and level >= 110 then ret = 2
    elseif item == "Death rune"  and level >= 131 then ret = 2

    elseif item == "Armadyl rune" then
        if     level >= 99 then ret = 10
        elseif level >= 88 then ret = 9
        elseif level >= 77 then ret = 8
        elseif level >= 72 then ret = 7 end
    
    elseif item == "Blood rune" and level >= 154 then ret = 2
    
    elseif item == "Cursed wisp" then
        if     level >= 95 then ret = 12
        elseif level >= 90 then ret = 11
        elseif level >= 85 then ret = 10
        elseif level >= 80 then ret = 9
        elseif level >= 70 then ret = 8
        elseif level >= 60 then ret = 7
        elseif level >= 50 then ret = 6
        elseif level >= 40 then ret = 5
        elseif level >= 30 then ret = 4
        elseif level >= 20 then ret = 3
        elseif level >= 10 then ret = 2 end
    
    elseif item == "Cursed memory" then
        if     level >= 95 then ret = 64
        elseif level >= 90 then ret = 53
        elseif level >= 85 then ret = 46
        elseif level >= 80 then ret = 41
        elseif level >= 70 then ret = 36
        elseif level >= 60 then ret = 29
        elseif level >= 50 then ret = 22
        elseif level >= 40 then ret = 13
        elseif level >= 30 then ret = 8
        elseif level >= 20 then ret = 6
        elseif level >= 10 then ret = 5
        else ret = 4 end

    end
    
    return ret
end -- levelMultiplier

--[[ findEltData function
--   input:
--          EltTitle    :: A list of elts returned from /elts
--          EltValues   :: An object of calculated and formatted values
--          elts        :: A reference to the elts table for modification
--   output:
--          No values returned; this function directly updates the elts object
--           with the appropriate data.
--]]
function findEltData(EltTitle, EltValues, elts)

    if EltTitle == "" then
        table.insert(elts, EltValues.icon)
    elseif EltTitle == "Name" then
        table.insert(elts, EltValues.link)
    elseif EltTitle == "Level" then
        table.insert(elts, EltValues.level)
    elseif EltTitle == "XP" then
        table.insert(elts, EltValues.actionExp)
    elseif EltTitle == "# needed" then
        table.insert(elts, EltValues.actionsRequired)
    elseif EltTitle == "Materials" then
        table.insert(elts, EltValues.materials)
    elseif EltTitle == "Unit cost" then
        table.insert(elts, EltValues.rawCost)
    elseif EltTitle == "Cost" or
           EltTitle == "Profit" or
           EltTitle == "Profit/Loss" then
        table.insert(elts, EltValues.netIncome)
    elseif EltTitle == "Raw cost" then
        table.insert(elts, EltValues.grossCost)
    elseif EltTitle == "Product cost" then
        table.insert(elts, EltValues.grossIncome)
    elseif EltTitle == "XP cost" or
           EltTitle == "Income/XP" then
        table.insert(elts, EltValues.avgCost)
    end
    
end -- findEltData
        

-- From http://lua-users.org/wiki/SplitJoin
-- ##Antiquated; needs to be replaced throughout with mw.text.split
function explode(d,p)
   local t, ll
   t={}
   ll=0
   if(#p == 1) then
      return {p}
   end
   while true do
      l = string.find(p, d, ll, true) -- find the next d in the string
      if l ~= nil then -- if "not not" found then..
         table.insert(t, string.sub(p,ll,l-1)) -- Save it in our array.
         ll = l + 1 -- save just after where we found it for searching next time.
      else
         table.insert(t, string.sub(p,ll)) -- Save what's left in our array.
         break -- Break at end, as it should be, according to the lua manual.
      end
   end
   return t
end -- explode

--[[ inlineProfit function
--      input:
--              income  :: value of object
--              needed  :: number of actions required to meet goal
--              item    :: two-part item; (icon,link)
--              curr    :: currency being used
--      output:
--              Builds a string of pLinks with their corresponding total-costs
--               meant for an in-line view.
--]]
function inlineProfit(income, needed, item, curr)
    local sentence = ""
    local value = ""
    local parts = explode(",", item)
    local image = item
    local link = item
    
    if income ~= 0 then
        if curr == "Chimes" then
            value = value .. " : " .. currency(income * needed, "chimes")
        else 
            value = value .. " : " .. coins(income * needed, 1)
        end
    end
    
    if table.getn(parts) > 1 then
        image = parts[1]
        link = parts[2] end
        
        sentence = sentence .. " " .. peLink(image,link,link) .. value
    
    return sentence
end -- inlineProfit

--[[ findItem function
--      input:
--              list    :: a table of values
--              item    :: key being searched for
--      output:
--              Returns a boolean for presence within table
--]]
function findItem (list, item)
    local status = false
    for _,v in pairs(list) do
        if v == item then
            status = true
            break
        end
    end
    return status
end -- findItem

return eltData