RuneScape Wiki

Dag Anonieme Gebruiker,

Maak nu snel een account aan, en geniet van alle extra mogelijkheden! Klik hier om een account aan te maken!
Heb je al een account? Log dan hier in.

Verder veel plezier op de wiki,
de Administrators

MEER LEZEN

RuneScape Wiki

Documentatie voor deze module kan aangemaakt worden op de volgende pagina: Module:Exchange/doc

--[[
{{Helper module|name=Exchange
|fname1=_price(arg)
|ftype1=String
|fuse1=Gets the current median price of item named arg
|fname2=_value(arg)
|ftype2=String
|fuse2=Gets the value of item named arg
}}
--]]
-- <pre>
--
-- Implements various exchange templates
-- See Individual method docs for more details
--
-- See also:
-- - [[Module:ExchangeData]]
-- - [[Module:ExchangeDefault]]
--

local p = {}

-- only load commonly used modules here
local yesno = require( 'Module:Yesno' )
local addcommas = require( 'Module:Addcommas' )._add

-- map redirects to their correct pages
local geRedirects = {
    ['1/2 anchovy pizza'] = '½ anchovy pizza',
    ['1/2 meat pizza'] = '½ meat pizza',
    ["1/2 p'apple pizza"] = "½ p'apple pizza",
    ['1/2 plain pizza'] = '½ plain pizza',
    ['1/3 evil turnip'] = '⅓ evil turnip',
    ['2/3 cake'] = '⅔ cake',
    ['2/3 chocolate cake'] = '⅔ chocolate cake',
    ['2/3 evil turnip'] = '⅔ evil turnip'
}

--
-- Makes sure first letter of item is uppercase
-- Automatically handles any redirects
--
local function checkTitle( item )
    -- upper case first letter to make sure we can find a valid item page
    item = mw.text.split( item, '' )
    item[1] = mw.ustring.upper( item[1] )
    item = table.concat( item )

    -- automatically handle redirects
    if geRedirects[item] ~= nil then
        item = geRedirects[item]
    end

    return item
end
--
-- Simple mw.loadData wrapper used to access data located on module subpages
--
-- @param item {string} Item to retrieve data for
-- @return {table} Table of item data
--
local function load( item )
    item = checkTitle( item )
    local noErr, ret = pcall( mw.loadData, 'Module:Exchange/' .. item )

    if noErr then
        return ret
    end

    error( ret )
end

--
-- Returns the price of an item
--
-- @param item {string} Item to get current price of
-- @param multi {number} (optional) Multiplies the output price by the specified number
-- @param format {boolean} (optional) Format the result with commas (defaults to false)
-- @param round {number} (optional) Round the result to a number of decimal places
-- @return {number|string} Price of item. Will return a string if formatted, else a number.
--
function p._price( item, multi, format, round )
    local price = load( item ).price
    local multi = type( multi ) == 'number' and multi or 1
    local format = type( format ) == 'boolean' and format or false
    local ret = price * multi
    
    -- round the number to X d.p.
    if round ~= nil then
        local multi = 10^( round )
        ret = math.floor( ret * multi + 0.5 ) / multi
    end

    if format then
        return addcommas( ret )
    end

    return ret
end

--
-- Returns the limit of an item
--
-- @param item {string} Item to get the limit of
-- @return {number} Limit of item
--
function p._limit( item )
    return load( item ).limit
end

--
-- Returns the value of an item
--
-- @param item {string} Item to get the value or
-- @return {number} Value of item
--
function p._value( item )
    return load( item ).value
end

--
-- Calculates the difference between the current price and the last price of an item
--
-- @param item {string} Item to calculate price difference for
-- @param format {boolean} `true` if the output is to be formatted with commas
--                         Defaults to `false`
-- @return {number|string} The price difference as a number
--                         If `format` is set to `true` then this returns a string
--                         If either of the prices to calculate the diff from are unavailable, this returns `0` (number)
--
function p._diff( item, format )
    local data = load( item )
    local diff = 0

    if data.price and data.last then
        diff = data.price - data.last

        if format then
            diff = addcommas( diff )
        end
    end

    return diff
end

--
-- {{GEItem}} internal method
--
-- @todo merge into p.table
--
-- @param item {string} Item to get data for
-- @return {string}
--
function p._table( item )
    -- load data and any required modules
    local item = checkTitle( item )
    local data = load( item )
    local timeago = require( 'Module:TimeAgo' )._ago
    local changeperday = require( 'Module:ChangePerDay' )._change

    -- set variables here to make the row building easier to follow
    local div = '<i>Unknown</i>'
    local limit = data.limit and addcommas( data.limit ) or '<i>Unknown</i>'
    local members = '<i>Unknown</i>'

    if data.last then
        local link = 'http://services.runescape.com/m=itemdb_rs/viewitem.ws?obj=' .. data.itemId
        local change = math.abs( changeperday( {data.price, data.last, data.date, data.lastDate} ) )

        if data.price > data.last then
            arrow = '[[File:Up.png|20px|link=' .. link .. ']]'
        elseif data.price < data.last then
            arrow = '[[File:Down.png|20px|link=' .. link .. ']]'
        else
            arrow = '[[File:Unchg.png|40px|link=' .. link .. ']]'
        end

        if change >= 0.04 then
            arrow = arrow  .. arrow .. arrow
        elseif change >= 0.02 then
            arrow = arrow .. arrow
        end

        div = mw.html.create( 'div' )
            :css( 'white-space', 'nowrap' )
            :wikitext( arrow )

        div = tostring( div )
    end

    if data.members == true then
        members = '[[File:P2P icon.png|30px|link=Members]]'
    elseif data.members == false then
        members = '[[File:F2P icon.png|30px|link=Free-to-play]]'
    end

    -- build table row
    local tr = mw.html.create( 'tr' )
        :tag( 'td' )
            :wikitext( '[[File:' .. item .. '.png|' .. item .. ']]' )
            :done()
        :tag( 'td' )
            :css( {
                ['width'] = '15%',
                ['text-align'] = 'left'
            } )
            :wikitext( '[[' .. item .. ']]' )
            :done()
        :tag( 'td' )
            :wikitext( addcommas( data.price ) )
            :done()
        :tag( 'td' )
            :wikitext( div )
            :done()

    if data.alchable == nil or yesno( data.alchable ) then
        local low, high = '<i>Unknown</i>', '<i>Unknown</i>'

        if data.value then
            low = addcommas( math.floor( data.value * 0.4 ) )
            high = addcommas( math.floor( data.value * 0.6 ) )
        end

        tr
            :tag( 'td' )
                :wikitext( low )
                :done()
            :tag( 'td' )
                :wikitext( high )
                :done()
    else
        tr
            :tag( 'td' )
                :attr( 'colspan', '2' )
                :wikitext( '<i>Cannot be alchemised</i>' )
                :done()
    end

    tr
        :tag( 'td' )
            :wikitext( limit )
            :done()
        :tag( 'td' )
            :wikitext( members )
            :done()
        :tag( 'td' )
            :css( 'white-space', 'nowrap' )
            :wikitext( '[[Exchange:' .. item .. '|bekijk]]' )
            :done()
        :tag( 'td' )
            :css( 'font-size', '85%' )
            :wikitext( timeago{data.date} )
            :done()

    return tostring( tr )

end

--
-- {{GEExists}}
--
function p.exists( frame )
    local args = frame:getParent().args
    local item = checkTitle( args[1] or '' )
    local noErr, data = pcall( mw.loadData, 'Module:Exchange/' .. item )

    if noErr then
        return '1'
    end

    return '0'
end

--
-- GEExists for modules
--
function p._exists( arg )
    local item = checkTitle( arg or '' )
    local noErr, data = pcall( mw.loadData, 'Module:Exchange/' .. item )

    if noErr then
        return true
    end

    return false
end

--
-- Internal method for p.highAlchTable, p.lowAlchTable and p.genStoreTable
--
-- @param item {string} The name of the item
-- @param data {table} The item's ge data
-- @param alch {number} The item's alch/sell value
-- @param min {number} (optional) Sets the cap for amount of items that can be converted to gp per hour
-- @param natPrice {number} (optional) Sets the price of a Nature rune (set to `0` by `p.genStoreTable`)
--
local function alchTable( item, data, alch, min, natPrice )
    local timeago = require( 'Module:TimeAgo' )._ago
    local round = require( 'Module:Number' )._round
    -- gen store doesn't need a nat price as it's not used
    -- therefore we'd set it to 0
    local natPrice = natPrice or load( 'Nature rune' ).price
    local profit = alch - data.price - natPrice

    local image = '[[File:' .. item .. '.png|' .. item .. ']]'
    local itemStr = '[[' .. item .. ']]'
    local priceStr = addcommas( data.price )
    local alchStr = addcommas( alch )
    local profitStr = addcommas( profit )
    local roi = tostring( round( ( profit / ( data.price + natPrice ) * 100 ), 1 ) ) .. '%'
    local limit = data.limit and addcommas( data.limit ) or '<i>Unknown</i>'
    local maxProfit = '<i>Unknown</i>'
    local members = '<i>Unknown</i>'
    local members_sortkey = 2
    local details = '[[Exchange:' .. item .. '|view]]'
    local lastUpdated = timeago{data.date}

    if data.limit then
        -- cap at 4800, the maximum number of alchs that can be cast every 4 hours
        -- varies for general store rows
        min = min or 4800 
        min = ( data.limit > min ) and min or data.limit
        maxProfit = addcommas( min * profit )
    end

    mw.log( maxProfit )

    if data.members == true then
        members = '[[File:P2P icon.png|30px|link=Members]]'
        members_sortkey = 1
    elseif data.members == false then
        members = '[[File:F2P icon.png|30px|link=Free-to-play]]'
        members_sortkey = 0
    end

    local tr = mw.html.create( 'tr' )
        :tag( 'td' )
            :wikitext( image )
            :done()
        :tag( 'td' )
            :css( {
                width = '15%',
                ['text-align'] = 'left'
            } )
            :wikitext( itemStr )
            :done()
        :tag( 'td' )
            :wikitext( priceStr )
            :done()
        :tag( 'td' )
            :wikitext( alchStr )
            :done()
        :tag( 'td' )
            :wikitext( profitStr )
            :done()
        :tag( 'td' )
            :wikitext( roi )
            :done()
        :tag( 'td' )
            :wikitext( limit )
            :done()
        :tag( 'td' )
            :wikitext( maxProfit )
            :done()
        :tag( 'td' )
            :wikitext( members )
            :attr('data-sort-value', members_sortkey)
            :done()
        :tag( 'td' )
            :css( 'white-space', 'nowrap' )
            :wikitext( details )
            :done()
        :tag( 'td' )
            :css( 'font-size', '85%' )
            :wikitext( lastUpdated )
            :done()

    return tostring( tr )
end

--
-- {{HighAlchTableRow}}
--
-- @example {{HighAlchTableRow|<item>}}
--
function p.highAlchTable( frame )
    local args = frame:getParent().args
    local item = checkTitle( args[1] )
    local data = load( item )
    local alch = math.floor( data.value * 0.6 )

    return alchTable( item, data, alch )
end

--
-- {{LowAlchTableRow}}
--
-- @example {{LowAlchTableRow|<item>}}
--
function p.lowAlchTable( frame )
    local args = frame:getParent().args
    local item = checkTitle( args[1] )
    local data = load( item )
    local alch = math.floor( data.value * 0.4 )

    return alchTable( item, data, alch )
end

--
-- {{GenStoreTableRow}}
--
-- @example {{GenStoreTableRow|<item>}}
--
function p.genStoreTable( frame )
    local args = frame:getParent().args
    local item = checkTitle( args[1] )
    local data = load( item )
    local alch = math.floor( data.value * 0.3 )

    return alchTable( item, data, alch, 50000, 0 )
end

--
-- {{GEP}}
-- {{GEPrice}}
--
-- @example {{GEPrice|<item>|<format>|<multi>}}
-- @example {{GEPrice|<item>|<multi>}}
-- @example {{GEP|<item>|<multi>}}
--
function p.price( frame )
    -- usage: {{foo|item|format|multi}} or {{foo|item|multi}}
    local args = frame.args
    local pargs = frame:getParent().args
    local item = pargs[1]
    local expr = mw.ext.ParserFunctions.expr
    local round = tonumber( pargs.round )

    if item then
        item = mw.text.trim( item )
    else
        error( '"item" argument not specified', 0 )
    end

    -- default to formatted for backwards compatibility with old GE templates
    local format = true
    local multi = 1

    -- format is set with #invoke
    -- so set it first to allow it to be overridden by template args
    if args.format ~= nil then
        format = yesno( args.format )
    end

    if tonumber( pargs[2] ) ~= nil then
        multi = tonumber( pargs[2] )

    -- indicated someone is trying to pass an equation as a mulitplier
    -- known use cases are fractions, but pass it to #expr to make sure it's handled correctly
    elseif pargs[2] ~= nil and mw.ustring.find( pargs[2], '[/*+-]' ) then
        multi = tonumber( expr( pargs[2] ) )

    -- uses elseif to prevent something like {{GEP|Foo|1}}
    -- causing a formatted output, as 1 casts to true when passed to yesno
    elseif type( yesno( pargs[2] ) ) == 'boolean' then
        format = yesno( pargs[2] )

        if tonumber( pargs[3] ) ~= nil then
            multi = tonumber( pargs[3] )
        end
    end 

    return p._price( item, multi, format, round )
end

--
-- {{GEItem}}
--
-- @example {{GEItem|<item>}}
--
function p.table( frame )
    local args = frame:getParent().args
    local item = args[1]

    if item then
        item = mw.text.trim( item )
    else
        error( '"item" argument not specified', 0 )
    end

    return p._table( item )
end

--
-- experimental limit method for [[Grand Exchange/Buying Limits]]
--
function p.gemwlimit( frame )
    local item  = frame:getParent().args[1]
    local data = mw.loadData( 'Module:Exchange/' .. item )
    
    return data.limit
end

--
-- {{ExchangeItem}}
-- {{GEDiff}}
-- {{GELimit}}
-- {{GEValue}}
-- {{GEId}}
--
-- @example {{ExchangeItem|<item>}}
-- @example {{GEDiff|<item>}}
-- @example {{GELimit|<item>}}
-- @example {{GEValue|<item>}}
-- @example {{GEId|<item>}}
--
function p.view( frame )
    local fargs = frame.args
    local pargs = frame:getParent().args
    local item = pargs[1] or fargs.item
    local view = fargs.view or ''
    local loadView = {limit=true, value=true, itemId=true}

    if item then
        item = mw.text.trim( item )
    else
        error( '"item" argument not specified', 0 )
    end

    view = mw.ustring.lower( view )

    if view == 'itemid' then
        view = 'itemId'
    end

    if view == 'diff' then
        return p._diff( item )

    elseif loadView[view] then
        return load( item )[view]

    else
        local default = require( 'Module:ExchangeDefault' )
        -- handle redirects and casing of item before passing it on
        item = checkTitle( item )
        return default.main( item )
    end
end

return p