FANDOM


-- <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 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 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 then linkTitle = T.title end
        -- Setup titled link
        --link  = '[[' .. T.name .. '|' .. linkTitle .. ']]'
        link = '[[' .. T.name .. ']]'
        -- If specified, append additional wiki-links
        if T.extLink 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,needed) .. "</div>"
        elseif T.material then
            materials = "<div style='text-align:left'>" .. createList(T.material,needed) .. "</div>"
        elseif T.familiar then
            local familiar = mw.text.split(T.familiar, "<")[1]
            if T.familiarTitle 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 then currency = T.currency end
 
        -- Mostly for Fishing 
        if T.equipment then
            local equipmentLink = mw.text.split(T.equipment, "<")[1]
            -- Check if an equipment link was specified
            if T.eLink 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 ---
    -------------------------------
 
    -- Establish sets of skills to find common elt patterns
    local noIncome  = {"Firemaking", "Prayer", "Construction", "Magic"}
    local noCost    = {"Woodcutting", "Mining", "Divination"}
    local production    = {"Cooking", "Crafting", "Fletching", "Runecrafting", "Herblore", "Smithing", "Summoning"}
    local addMaterials = {"Dungeons-Materials", "Fletching-Dungeoneering", "Summoning-Dungeoneering - Pouches", "Hunter"}
    local materialCost = {"Magic", "Farming", "Divination-Conversion"}
    local exceptions = {"Construction-Other", "Runecrafting-Runespan - Members", "Runecrafting-Runespan - Free", "Smithing-Forging", "Woodcutting-Other"}
 
    local generatedValues = 
            {
                icon = icon,
                link = link,
                level = T.level,
                actionExp = actionExp,
                actionsRequired = actionsRequired,
                netIncome = netIncome,
                materials = materials,
                rawCost = rawCost,
                avgCost = avgCost,
                grossCost = grossCost,
                grossIncome = grossIncome,
            }
    local elts = {}
 
    for i, title in ipairs(eltTitles) do
        findEltData(title, generatedValues, elts)
    end
 
    --[[
    -- Create base elt table to build from
    -- /Elts must be kept similar to maintain this
    elts =
        {
            icon,
            link,
            T.level
        }
 
    if eltArgs.disp ~= "Milestones" and
       eltArgs.skill ~= "Slayer" and
       not(string.find(eltArgs.disp, "Agility - ")) then
        table.insert(elts, actionExp)                           -- Add experience per action
        table.insert(elts, commas(actionsRequired))             -- Add # actions required
 
        -- Catch unique tables
        if eltArgs.disp == "Urns" then
            table.remove(elts, 3)                               -- Urns do not have level reqs
            table.insert(elts, printCoins( netIncome, "int" ))  -- Add net income from actions
 
        elseif eltArgs.disp == "Rooms" then
            table.insert(elts, printCoins( netIncome, "int" ))  -- Add total cost from actions
 
        else
 
            -- Firemaking, Prayer, Construction, Magic
            if (findItem(noIncome, eltArgs.skill) or 
                findItem(noIncome, eltArgs.skill .. '-' .. eltArgs.disp) ) and
                not(findItem(exceptions, eltArgs.skill)) and
                not(findItem(exceptions, eltArgs.skill .. '-' .. eltArgs.disp)) then
                table.insert(elts, materials)                   -- List of materials used
                table.insert(elts, rawCost)                     -- Cost of materials used
                table.insert(elts, netIncome)                   -- Total cost of materials
                table.insert(elts, avgCost)                     -- Cost/XP
 
            -- Woodcutting, Mining, Divination
            elseif findItem(noCost, eltArgs.skill) or 
               findItem(noCost, eltArgs.skill .. '-' .. eltArgs.disp) then
                table.insert(elts, netIncome)                   -- Total income of training
 
            -- Cooking, Crafting, Fletching, Runecrafting, Herblore, Smithing, Summoning
            elseif findItem(production, eltArgs.skill) or 
               findItem(production, eltArgs.skill .. '-' .. eltArgs.disp) then
 
                if eltArgs.skill ~= "Fishing" then
                    table.insert(elts, materials)               -- List of materials used
                else
                    table.insert(elts, materials, 4)            -- Override location of materials
                end
 
                table.insert(elts, grossCost)                   -- Cost of materials used
                table.insert(elts, grossIncome)                 -- Cost of materials created
                table.insert(elts, netIncome)                   -- Total income of training
                table.insert(elts, avgCost)                     -- Cost/XP
 
            -- Odds and ends
            elseif findItem(addMaterials, eltArgs.skill) or 
               findItem(addMaterials, eltArgs.skill .. '-' .. eltArgs.disp) then
                table.insert(elts, materials)                   -- List of materials needed
 
            -- Odds and ends
            elseif findItem(materialCost, eltArgs.skill) or 
               findItem(materialCost, eltArgs.skill .. '-' .. eltArgs.disp) then
                table.insert(elts, materials)                   -- List of materials needed
                table.insert(elts, netIncome)                   -- Total cost of training
 
            end
 
            if eltArgs.skill == "Prayer" then
                table.remove(elts, 3)                           -- Prayer does not have level reqs
                table.insert(elts, netIncome)                   -- Total cost of materials
                table.insert(elts, avgCost)                     -- income/XP
 
            elseif 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 == "Divination" then
                table.insert(elts, printCoins( netIncome, "int" ))  -- Add total cost from actions    
 
            elseif eltArgs.skill == "Fishing" then
                table.insert(elts, equipment, 3)                -- Include necessary equipment
 
            elseif eltArgs.disp == "Tiaras" then
                table.remove(elts, 3)                           -- Tiaras do not have a level req
 
            elseif eltArgs.disp == "Forging" then
                table.insert(elts, grossCost)                   -- Total cost of materials
                table.insert(elts, avgCost)                     -- income/XP
 
            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
 
    elseif eltArgs.skill == "Construction" then
        table.insert(elts, netIncome)                           -- Construction always costs 
 
    end
    --]]
 
    -------------------------------
    ----- End elt construction ----
    -------------------------------
 
    return elts
end
 
 
--------------------------------------
-------- Helper Functions ------------
--------------------------------------
 
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
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
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
 
-- This takes an item and the player's level to find the base multiplier where applicable
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
 
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
 
 
-- From http://lua-users.org/wiki/SplitJoin
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
 
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
 
-- Make it easier to find items in a set
-- A little heavy : if someone can find a better way, replace.
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
 
return eltData
Community content is available under CC-BY-SA unless otherwise noted.