Module:Infobox Farming

From the RuneScape Wiki, the wiki for all things RuneScape
Jump to navigation Jump to search
Module documentation
This documentation is transcluded from Module:Infobox Farming/doc. [edit] [history] [purge]
Module:Infobox Farming's function main is invoked by Template:Databox Farming.
Module:Infobox Farming requires Module:Currency.
Module:Infobox Farming requires Module:ExchangeLite.
Module:Infobox Farming requires Module:Infobox.
Module:Infobox Farming requires Module:Mainonly.
Module:Infobox Farming requires Module:Skill clickpic.

Generates {{Infobox Farming}}

Arg name Arg type Description
name String The name of the stage on the current page ideally, for example the Tomato seed page's name would be 'Tomato seed'
seed String The seed of the plant in question
seedling String The seedling of the plant in question if applicable
sapling String The sapling of the plant in question if applicable
plant String The link of fully grown plant
planttxt String The actual name of fully grown plant
plantxp number The exact xp you get when planting the plant in question
potxp number The exact xp you get when planting the plant in a pot if applicable
checkxp number The exact xp you get when checking the plants final stage if applicable
harvestxp number The exact xp you get when harvesting produce from the plant
plantlvl number The level required to plant the plant
patch Linked string if available like Allotment The location in which you plant the plant
seedamount number The amount of seeds that are consumed when the plant is planted
protection plink with the option of refs like {{plink|Cabbages (10)}}{{Refn|1 with [[Master farmer outfit]].}} The protection item needed to protect a plant
protectionamount number The default number of protection items needed to protect a plant
cycles number The number of cycles a plant takes to fully grow
cyclelength String (like '10 minutes') The total time of a single cycle
cycletotal String (like '40 minutes') The total time required to fully grow (cyclelength*cycles)
primary String The name of the primary produce of a plant
primarymin number (can be the string 'Varies' if unknown) The minimum number of produce a plant will yield
primarymax number An optional field that consists of the max number of produce a plant will yield
secondary String An optional field that displays the secondary produce of a plant
secondarymin number The minimum number of produce a plant will yield
secondarymax number An optional field that consists of the max number of produce a plant will yield
harvestskill String The name of the skill required to harvest a plant, such as woodcutting for trees
tree String ('no' or 'yes) Indicator if it is a tree plant, such as Oak

Use Module:Infobox Farming/sandbox for testing.


-- <nowiki>
local p = {}

--
-- imports
--
local onmain = require('Module:Mainonly').on_main
local infobox = require('Module:Infobox')
local skillpic = require('Module:Skill clickpic')._main
local ge_price = require('Module:ExchangeLite').price
local amount = require('Module:Currency')._amount

local pageTitle = mw.title.getCurrentTitle().text
local NA_PARAM = "N/A"

function p.main(frame)
    local args = frame:getParent().args
    local ret = infobox.new(args)

    ret:defineParams{
        -- template params
        { name = 'name', func = { name = plant_disp, params = { 'primary', 'planttxt', 'plant' }, flag = { 'p' } } },
        { name = 'plantlvl', func = 'has_content' },
        { name = 'patch', func = 'has_content' },
        { name = 'seed', func = { name = plink_content, params = { 'seed' }, flag = 'p' } },
        { name = 'seedling', func = { name = plink_content, params = { 'seedling' }, flag = 'p' } },
        { name = 'sapling', func = { name = plink_content, params = { 'sapling' }, flag = 'p' } },
        { name = 'plant', func = 'has_content' },
        { name = 'potxp', func = { name = xp_disp, params = { 'potxp' }, flag = 'p' } },
        { name = 'plantxp', func = { name = xp_disp, params = { 'plantxp' }, flag = 'p' } },
        { name = 'checkxp', func = { name = xp_disp, params = { 'checkxp' }, flag = 'p' } },
        { name = 'harvestxp', func = { name = harvest_disp, params = { 'harvestxp', 'harvestskill' }, flag = 'd' } },        
        { name = 'seedamount', func = { name = 'has_content', params = { 'seedamount', '1' }, flag = { 'd', 'r' } } },
        { name = 'protection', func = { name = protection_disp, params = { 'protection', 'protectionamount' }, flag = 'd' } },
        { name = 'cycles', func = 'has_content' },
        { name = 'cyclelength', func = 'has_content' },
        { name = 'cycletotal', func = 'has_content' },
        { name = 'primarymin', func = { name = 'has_content', params = { 'primarymin', '1' }, flag = { 'd', 'r' } } },
        { name = 'primarymax', func = { name = 'has_content', params = { 'primarymax', '1' }, flag = { 'd', 'r' } } },
        { name = 'secondarymin', func = { name = 'has_content', params = { 'secondarymin', '1' }, flag = { 'd', 'r' } } },
        { name = 'secondarymax', func = { name = 'has_content', params = { 'secondarymax', '1' }, flag = { 'd', 'r' } } },
        { name = 'primaryexchange', func = { name = 'has_content', params = { 'primaryexchange', 'gemw' }, flag = { 'd', 'r' } } },
        { name = 'secondaryexchange', func = { name = 'has_content', params = { 'secondaryexchange', 'gemw' }, flag = { 'd', 'r' } } },
        { name = 'tree', func = contentarg },

        -- derived params
        { name = 'plant_disp', func = { name = plant_disp, params = { 'primary', 'planttxt', 'plant' }, flag = 'd' } },
        { name = 'primary_disp', func = { name = plink_content, params = { 'primary' }, flag = 'd' } },
        { name = 'primary_qty', func = { name = drop_qty, params = { 'primarymin', 'primarymax' }, flag = { 'd' } } },
        { name = 'primary_qty_disp', func = { name = 'has_content', params = { 'primary_qty' }, flag = { 'd' } } },
        { name = 'primary_gemw', func = { name = gemwarg, params = { 'primaryexchange', 'primary' }, flag = 'd' } },
        { name = 'primary_range_gemw', func = { name = crop_gemw, params = { 'primaryexchange', 'primary', "primarymin", "primarymax" }, flag = 'd' } },
        { name = 'secondary_disp', func = { name = plink_content, params = { 'secondary' }, flag = 'd' } },
        { name = 'secondary_qty', func = { name = drop_qty, params = { 'secondarymin', 'secondarymax' }, flag = { 'd' } } },
        { name = 'secondary_qty_disp', func = { name = 'has_content', params = { 'secondary_qty' }, flag = { 'd' } } },
        { name = 'secondary_gemw', func = { name = gemwarg, params = { 'secondaryexchange', 'secondary' }, flag = 'd' } },
        { name = 'secondary_range_gemw', func = { name = crop_gemw, params = { 'secondaryexchange', 'secondary', "secondarymin", "secondarymax" }, flag = 'd' } },


        -- SMW params
        { name = 'name_smw', func = { name = 'has_content', params = { pageTitle }, flag = 'r' } },
        { name = 'level_smw', func = { name = smwarg, params = { 'plantlvl' }, flag = 'p' } },
        { name = 'crop_smw', func = { name = smwarg_strip_link, params = { 'primary' }, flag = 'p' } },
        { name = 'crop_item_smw', func = { name = 'has_content', params = { 'crop_smw' }, flag = 'd' } },
        { name = 'crop_item_text_smw', func = { name = 'has_content', params = { 'crop_smw' }, flag = 'd' } },
        { name = 'crop_qty_smw', func = { name = drop_qty_smwarg, params = { 'primary_qty' }, flag = 'd' } },
        { name = 'crop_item_img_smw', func = { name = drop_img_smwarg, params = { 'crop_smw', 'crop_qty_smw', 'primary' }, flag = 'd' } },
        { name = 'crop_qty_hi_smw', func = { name = drop_qty_lo_smwarg, params = { 'primarymin' }, flag = 'd' } },
        { name = 'crop_qty_lo_smw', func = { name = drop_qty_lo_smwarg, params = { 'primarymax' }, flag = 'd' } },
        { name = 'rarity_smw', func = { name = 'has_content', params = { 'Always' }, flag = 'r' } },
        { name = 'rarity_sort_smw', func = { name = 'has_content', params = { '100' }, flag = 'r' } },
    }

    ret:customButtonPlacement(true)
    ret:setAddRSWInfoboxClass(false)
    ret:create()
    ret:cleanParams()
    
    ret:useSMW{
        level_smw = 'Farming level',
    }

    -- only add produced item SMW properties for the 'plant' page if present (else always add)
    -- this is meant to prevent seed items from showing up in source lists for the final crop product
    -- NOTE: if root is specified, assume page uses {{DropsLineWC}} and don't set SMW properties to avoid duplication
    local grown = strip_link(ret:param('plant'))
    local tree = ret:paramDefined('tree')
    if not tree and (not ret:paramDefined('plant') or grown == pageTitle) then
        -- if root is defined, set dropped item SMW properties in subobject
        if ret:paramDefined('primary') then
            ret:useSMWOne{
                crop_smw = 'Produce item',
                crop_item_smw = 'Dropped item',
                crop_item_text_smw = 'Dropped item text',
                crop_item_img_smw = 'Dropped item image',
                crop_qty_smw = 'Drop Quantity',
                crop_qty_hi_smw = 'Quantity High',
                crop_qty_lo_smw = 'Quantity Low',
                name_smw = 'Produce from',
                rarity_smw = 'Rarity',
                rarity_sort_smw = 'Rarity sort',
            }
        end
    end

    ret:defineName('Infobox Seed')
    ret:defineLinks{ hide = true }
    ret:addClass('wikitable')
    ret:css{
        ['text-align'] = 'center',
    }

    -- PARAMETER: name
    ret:addRow{ { tag = 'argh', content = 'name', colspan = '8' } }

    -- header row: Stages
    ret:addRow{ { tag = 'th', content = 'Stages', colspan = '8' } }

    -- PARAMETER: seed, seedling, sapling, grown
    ret:addRow{
        { tag = 'th', content = 'Seed', colspan = '2' },
        { tag = 'th', content = 'Seedling', colspan = '2' },
        { tag = 'th', content = 'Sapling', colspan = '2' },
        { tag = 'th', content = 'Plant', colspan = '2' },
    }
    ret:addRow{
        contentNaIfEmpty(ret, 'seed', '2'),
        contentNaIfEmpty(ret, 'seedling', '2'),
        contentNaIfEmpty(ret, 'sapling', '2'),
        { tag = 'argd', content = 'plant_disp', colspan = '2' },
    }
    
    -- header row: Experience
    ret:addRow{ { tag = 'th', content = '[[Farming]] experience', colspan = '8' } }

    -- PARAMETER: pot, plant, check, harvest
    ret:addRow{
        { tag = 'th', content = 'Pot', colspan = '2' },
        { tag = 'th', content = 'Plant', colspan = '2' },
        { tag = 'th', content = 'Check', colspan = '2' },
        { tag = 'th', content = 'Harvest', colspan = '2' },
    }
    ret:addRow{
        contentNaIfEmpty(ret, 'potxp', '2'),
        contentNaIfEmpty(ret, 'plantxp', '2'),
        contentNaIfEmpty(ret, 'checkxp', '2'),
        contentNaIfEmpty(ret, 'harvestxp', '2'),
    }

    -- header row: Requirements
    ret:addRow{ { tag = 'th', content = 'Requirements', colspan = '8' } }

    -- PARAMETER: plantlvl, patch, seedamount, protection, protectionamount
    ret:addRow{
        { tag = 'th', content = '[[Farming|Farming level]]', colspan = '2' },
        { tag = 'th', content = 'Patch', colspan = '2' },
        { tag = 'th', content = 'Seeds per plant', colspan = '2' },
        { tag = 'th', content = 'Protection cost', colspan = '2' },
    }
    ret:addRow{
        { tag = 'argd', content = 'plantlvl', colspan = '2' },
        { tag = 'argd', content = 'patch', colspan = '2' },
        { tag = 'argd', content = 'seedamount', colspan = '2' },
        contentNaIfEmpty(ret, 'protection', 2),
    }

    -- header row: Growth time
    ret:addRow{ { tag = 'th', content = plinkp('Farming training/Growth guide', 'Hourglass', 'Growth time'), colspan = '8' } }

    -- PARAMETER: cycles, cyclelength, cycletotal
    ret:addRow{
        { tag = 'th', content = 'Cycles', colspan = '2' },
        { tag = 'th', content = 'Cycle length', colspan = '3' },
        { tag = 'th', content = 'Total time', colspan = '3' },
    }
    ret:addRow{
        { tag = 'argd', content = 'cycles', colspan = '2' },
        { tag = 'argd', content = 'cyclelength', colspan = '3' },
        { tag = 'argd', content = 'cycletotal', colspan = '3' },
    }

    -- header row: Produce
    ret:addRow{ { tag = 'th', content = 'Produce', colspan = '8' } }

    -- PARAMETER: primary, primarymin, primarymax, primaryexchange, secondary, secondarymin, secondarymax, secondaryexchange
    ret:addRow{
        { tag = 'th', content = 'Item', colspan = '2' },
        { tag = 'th', content = 'Quantity', colspan = '2' },
        { tag = 'th', content = 'Price', colspan = '2' },
        { tag = 'th', content = 'Total', colspan = '2' },
    }
    ret:addRow{
        { tag = 'argd', content = 'primary_disp', colspan = '2' },
        { tag = 'argd', content = 'primary_qty', colspan = '2' },
        { tag = 'argd', content = 'primary_gemw', colspan = '2' },
        { tag = 'argd', content = 'primary_range_gemw', colspan = '2' },
    }
    if ret:paramDefined('secondary') then
        ret:addRow{
            { tag = 'argd', content = 'secondary_disp', colspan = '2' },
            { tag = 'argd', content = 'secondary_qty_disp', colspan = '2' },
            { tag = 'argd', content = 'secondary_gemw', colspan = '2' },
            { tag = 'argd', content = 'secondary_range_gemw', colspan = '2' },
        }
    end

    if onmain() then
        local a1 = ret:param('all')
        local a2 = ret:categoryData()
        ret:wikitext(addcategories(a1,a2))
    end
    ret:finish()
    return ret:tostring()
end

function split(inputstr)
    local numbers = {}
    local index = 1
    for num in string.gmatch(inputstr, "%d+") do 
        numbers[index] = num
        index = index + 1
    end
    return numbers
end

--
-- param parsing and cleaning funcs
--
function contentarg(arg)
    if infobox.isDefined(arg) and not is_empty(arg) then
        return arg
    else
        return nil
    end
end

function plink_content(arg)
    if infobox.isDefined(arg) and not is_empty(arg) then
        return plink(arg)
    else
        return nil
    end
end

function plant_disp(primary, planttxt, plant)
    if not infobox.isDefined(planttxt) then
        planttxt = plant
    end

    return plink(primary, {img = primary, txt = planttxt, link = plant})
end

function harvest_disp(harvestxp, harvestskill)
    if infobox.isDefined(harvestxp) then
        if infobox.isDefined(harvestskill) then
            return '[[File:' .. harvestskill .. '-icon.png|21x21px|link=]] ' .. harvestxp .. ' XP'
        else
            return harvestxp .. ' XP'
        end
    end

    return nil
end

function xp_disp(harvestxp)
    if infobox.isDefined(harvestxp) then
        return harvestxp .. ' XP'
    end

    return nil
end

function protection_disp(protection, protectionamount)
    if infobox.isDefined(protection) and infobox.isDefined(protectionamount) then
        return protectionamount .. 'x ' .. protection
    end

    return nil
end

function drop_qty(min, max)
    if infobox.isDefined(min) then
        if infobox.isDefined(max) and min < max then
            return min .. ' - ' .. max
        else
            return min
        end
    else
        return nil
    end
end

function drop_img_smwarg(crop, output, name)
    if infobox.isDefined(crop) then
        return '[[File:' .. crop .. '.png|link=' .. crop .. '|alt=' .. crop .. '.png: RS3 ' .. name
            .. ' drops ' .. crop .. ' as produce with rarity Always in quantity ' .. output .. ']]'
    end
    return nil
end

function drop_qty_hi_smwarg(output)
    if output then
        return string.match(output, '^%d+ *%- *(%d+)') or output
    end
    return nil
end

function drop_qty_lo_smwarg(output)
    if output then
        return string.match(output, '^%d+') or output
    end
    return nil
end

function drop_qty_smwarg(output)
    if infobox.isDefined(output) then
        return output
    end
    return 'unknown'
end

function gemwarg(cropexchange, crop)
    if not infobox.isDefined(crop) or is_empty(crop) then
        return nil
    end
    
    crop = strip_link(crop)
    local price = ge_price(crop)
    if price ~= nil then
        return amount(price, 'coins')
    else
        return nil
    end
end

function crop_gemw(cropexchange, crop, crop_min, crop_max)
    if infobox.isDefined(cropexchange) and string.lower(cropexchange) ~= 'gemw' then
        return nil
    elseif not infobox.isDefined(crop) or is_empty(crop) then
        return nil
    end
    
    crop = strip_link(crop)
    local price = ge_price(crop)
    if price ~= nil then
        if crop_min == 'Varies' then
            return amount(price)
        elseif infobox.isDefined(crop_max) then
            return amount(price * crop_min, 'coins') .. ' - ' .. amount(price * crop_max, 'coins')
        else
            return amount(price * crop_min, 'coins')
        end
    else
        return nil
    end
end

function smwarg(arg)
    if infobox.isDefined(arg) then
        if string.lower(tostring(arg)) == 'no' then
            return nil
        end
        return arg
    end
    return nil
end

function smwarg_strip_link(arg)
    if infobox.isDefined(arg) then
        if string.lower(tostring(arg)) == 'no' then
            return nil
        end
        return strip_link(arg)
    end
    return nil
end

function plink(name, opts)
    local file = name.. '.png'
    local link = name
    local text = name
    if type(opts) == 'table' then
        if opts.txt then
            text = opts.txt
        end
        if opts.img then
            file = opts.img.. '.png'
        end
        if opts.link then
            link = opts.link
        end
    end
    if text ~= '' then
        text = string.format(' [[%s|%s]]', link,text)
    end
    return string.format('[[File:%s|link=%s|frameless|35px]]%s', file, link, text)
end

function plinkp(name, img, txt, link)
    return plink(name, {img = img, txt = txt, link = link})
end

--
-- infobox template funcs
--
function contentNaIfEmpty(ret, key, colspan)
    if ret:paramDefined(key) and not ret:paramGrep(key, NA_PARAM) then
        return { tag = 'argd', content = key, colspan = colspan }
    else
        return { tag = 'td', content = NA_PARAM, colspan = colspan, class = 'table-na' }
    end
end

--
-- util funcs
--
function is_empty(arg)
    local strarg = string.lower(tostring(arg))
    
    if strarg == 'no'
    or strarg == 'none'
    or strarg == '0'
    or strarg == 'na'
    or strarg == 'n/a'
    or strarg == 'hide' then
        return true
    end
    
    return false
end

function strip_link(text)
    if text == nil then
        return nil
    end
    
    -- returns "Foo" for: Foo, [[Foo]], [[Foo|Bar]]
    return string.match(text, "[%[]*(.-)[%]%|]") or text
end

--
-- category funcs
--
function addcategories(args, catargs)
    local ret = {}
    
    -- always added
    table.insert(ret, 'Farming')
    
    local cat_map = {
        -- Added if the parameter has content
        defined = {
        },
        -- Added if the parameter has no content
        notdefined = {
            plantlvl = 'Needs Farming level',
            patch = 'Needs Farming patch type',
            cycles = 'Needs Farming grow time',
            cyclelength = 'Needs Farming grow time',
            cycletotal = 'Needs Farming grow time',
            seedamount = 'Needs Farming seeds per patch',
            plantxp = 'Needs Farming XP',
            checkxp = 'Needs Farming XP',
            harvestxp = 'Needs Farming XP',
            primary = 'Needs Farming crop produced',
        },
    }
    
    -- Run and add mapped categories
    for n, v in pairs(cat_map.defined) do
        if catargs[n] and catargs[n].one_defined then
            table.insert(ret, v)
        end
    end
    for n, v in pairs(cat_map.notdefined) do
        if catargs[n] and catargs[n].all_defined == false then
            table.insert(ret, v)
        end
    end
    
    -- combine table and format category wikicode
    for i, v in ipairs(ret) do
        if v ~= '' then
            ret[i] = string.format('[[Category:%s]]', v)
        end
    end

    return table.concat(ret, '')
end

return p
-- </nowiki>