Module:Sandbox/User:Towelcat/Store locations list

From Old School RuneScape Wiki
Jump to navigation Jump to search
Module documentation
This documentation is transcluded from Template:Module sandbox/doc. [edit] [history] [purge]
Module:Sandbox/User:Towelcat/Store locations list requires .

This module is a sandbox for Towelcat. It can be used to test changes to existing modules, prototype new modules, or just experimenting with lua features.

Invocations of this sandbox should be kept in userspace; if the module is intended for use in other namespaces, it should be moved out of the sandbox into a normal module and template.

This default documentation can be overridden by creating the /doc subpage of this module, as normal.

-- <pre>
local p = {}

local commas = require("Module:Addcommas")._add
local params = require('Module:Paramtest')
local yesNo = require("Module:Yesno")
local currencyImage = require("Module:Currency Image")
local purge = require("Module:Purge")._purge
local tb = require('Module:Trailblazer Region')._main

local p2pIcon = '[[File:Member icon.png|frameless|link=Pay-to-play]]'
local f2pIcon = '[[File:Free-to-play icon.png|frameless|link=Free-to-play]]'

function p.main(frame)
    return p._main(frame:getParent().args)
end

function p._main(args)
    local item, limit = params.defaults{
                            {args[1], mw.title.getCurrentTitle().text},
                            {args.Limit, 500}
                        }
    mw.log(string.format('Searching for shops that sell: %s', item))

    -- Get parsed smw data
    local data = p.getData(item, limit)

    -- Create the header of the output
    local headerText = "<div class=\"seealso\">This list was created dynamically. For help, see [[Template:Store locations list/FAQ|the FAQ]].</div>\n"
        .. "<div class=\"seealso\">To force an update of this list, click " .. purge('res', 'here', 'span') .. ".</div>\n"
    local restbl = mw.html.create('table')
    restbl:addClass('wikitable sortable align-center-3 align-center-4 align-center-5 align-center-6 align-center-7')
        :tag('tr')
            :tag('th'):wikitext('Seller'):done()
            :tag('th'):wikitext('Location'):done()
            :tag('th'):wikitext('Number<br/>in stock'):attr('data-sort-type', 'number'):done()
            :tag('th'):wikitext('Restock<br/>time'):attr('data-sort-type', 'number'):done()
            :tag('th'):wikitext('Price<br/>sold at'):attr('data-sort-type', 'number'):done()
            :tag('th'):wikitext('Price<br/>bought at'):attr('data-sort-type', 'number'):done()
            :tag('th'):wikitext('Members?'):done()
            -- :tag('th'):wikitext('[[Trailblazer]] region'):done()
        :done()

    -- Create the rows for the output table
    for _, shop in ipairs(data) do
    	for i, location in ipairs(shop.location) do
	        restbl:tag('tr')
	            :tag('td'):wikitext(shop.seller):done()
	            :tag('td'):wikitext(location):done()
	            :tag('td')
	                :attr({['data-sort-value']=shop.stockSortValue})
	                :wikitext(shop.stock)
	            :done()
	            :tag('td')
	                :attr({['data-sort-value']=shop.restockSortValue})
	                :wikitext(shop.restock)
	            :done()
	            :tag('td')
	                :attr({['data-sort-value']=shop.sellSortValue})
	                :wikitext(shop.sellvalue)
	            :done()
	            :tag('td')
	                :attr({['data-sort-value']=shop.buySortValue})
	                :wikitext(shop.buyvalue)
	            :done()
	            :tag('td'):wikitext(shop.members):done()
	            -- :tag('td'):addClass(shop.region[i] and '' or 'table-na'):wikitext(shop.region[i] and tb(shop.region[i]) or 'N/A'):done()
	        :done()
		end
    end

    return headerText .. tostring(restbl)
end

function p.getData(itemName, limit)
    -- Query smw
    local q = {
        '[[Sold item::'..itemName..']]',
        '?Sold by',
        '?Sold by.Store Is members only = Store Is members only',
        '?Sold by.Store location = Store location',
        '?Sold by.Has subobject.Store location=Store location subobj',
        -- '?Sold by.Trailblazer Region = Trailblazer Region',
        -- '?Sold by.Has subobject.Trailblazer Region=Trailblazer Region subobj',
        '?Sold by.Is members only = Is members only',
        '?Sold by.NPC location = NPC location',
        '?Sold by.Has subobject.NPC location=NPC location subobj',
        '?Sold item image',
        '?Sold item',
        '?Sold item text',
        '?Store stock',
        '?Restock time',
        '?Store sell price',
        '?Store buy price',
        '?Store currency',
        '?Store notes',
        offset = 0,
        limit = limit or 500,
    }
    local t1 = os.clock()
    local smwdata = mw.smw.ask(q)
    local t2 = os.clock()
    local data = {}

    if smwdata == nil then
        error('The item "' .. itemName .. '" is not sold in any shop, please check for typos[[Category:Empty store lists]]', 0)
    end
    mw.log(string.format('SMW (store locations list): entries: %d, time elapsed: %.3f ms.', #smwdata, (t2 - t1) * 1000))

    table.sort(smwdata, function(a, b) return b['Store sell price'] < a['Store sell price'] end)

    -- Iterate through each shop instance of item
    for _, item in ipairs(smwdata) do
        local members, location, region = {}, {}, {}

        if type(item['Store Is members only']) == 'boolean' then
            table.insert(members, item['Store Is members only'])
        elseif type(item['Is members only']) == 'boolean' then
            table.insert(members, item['Is members only'])
        end
        
        if type(item['Store location subobj']) == 'table' then
            for _, v in ipairs(item['Store location subobj']) do
                table.insert(location, v)
            end
        elseif type(item['Store location']) == 'string' then
            table.insert(location, item['Store location'])
        elseif type(item['NPC location subobj']) == 'table' then
            for _, v in ipairs(item['NPC location subobj']) do
                table.insert(location, v)
            end
        elseif type(item['NPC location']) == 'string' then
            table.insert(location, item['NPC location'])
        end

        -- if type(item['Trailblazer Region subobj']) == 'table' then
        --     for _, v in ipairs(item['Trailblazer Region subobj']) do
        --         table.insert(region, v)
        --     end
        -- elseif type(item['Trailblazer Region']) == 'string' then
        --     table.insert(region, item['Trailblazer Region'])
        -- end
        
        item['Location'] = location
        -- item['Region'] = region
        
        if #members == 1 then
            item['Members'] = members[1]
        else
            item['Members'] = members
        end

        -- Loop over smw return items
        -- item['Store location'] = 'x'
        -- item['Store Is members only'] = 'Yes'
        -- Process the item and add it to the final data table
        local dataline = p.processData(item, editbtn)
        table.insert(data, dataline)
    end

    return data
end

function p.processData(item, editbtn)
    local seller = item['Sold by'] or ""
    local namenotes = item['Store notes']
    if namenotes then
        seller = seller .. ' ' .. namenotes
    end
    
    local location = item['Location']
    local region = item['Region']

    if type(location) == 'table' and #location == 0 then
        location = {editbtn}
    end

    if type(region) == 'table' and #region == 0 then
        region = {editbtn}
    end
    
    local stock = item['Store stock'] or ''
    local stockSortValue = 0
    if stock == '∞' then
        stock = '<span style="font-size:120%;">∞</span>'
        stockSortValue = '10e50'
    elseif stock == 'N/A' then
        stockSortValue = '10e99'
    else
        stock = tonumber(stock)
        if stock then
            stockSortValue = stock
            stock = commas(stock)
        else
            stock = editbtn    -- If stock can't be converted to a number it will default to the edit button
        end
    end
    
    local restock = item['Restock time'] or ''
    local restockSortValue = 0
    if restock == 'N/A' then
    	restockSortValue = '10e99'
    else
    	restock = tonumber(restock)
    	if restock then
    		restockSortValue = restock
    		restock = ticktime(restock)
    	else
    		restock = editbtn    -- If restock can't be converted to a number it will default to the edit button
    	end
    end
    
    local currency = item['Store currency']

    local sellvalue = item['Store sell price'] or ''
    local sellSortValue = 0
    if not(sellvalue == 1e10) then
        sellvalue = tonumber(sellvalue)
        if sellvalue then
            sellSortValue = sellvalue
            sellvalue = commas(sellvalue)
            local currencyImg = currencyImage(currency, sellSortValue) or ''
            if(params.has_content(currencyImg)) then
                currencyImg = string.format('[[File:%s|link=%s]] ', currencyImg, currency)
                sellvalue = currencyImg .. sellvalue
            end
        else
            sellvalue = editbtn    -- If sellvalue can't be converted to a number it will default to the edit button
        end
    else
        sellSortValue = sellvalue
        sellvalue = 'N/A'
    end
    
    local buyvalue = item['Store buy price'] or ''
    local buySortValue = 0
    if not(buyvalue == 'N/A') then
        buyvalue = tonumber(buyvalue)
        if buyvalue then
            buySortValue = buyvalue
            buyvalue = commas(buyvalue)
            local currencyImg = currencyImage(currency, buySortValue) or ''
            if(params.has_content(currencyImg)) then
                currencyImg = string.format('[[File:%s|link=%s]] ', currencyImg, currency)
                buyvalue = currencyImg .. buyvalue
            end
        else
            buyvalue = editbtn -- If sellvalue can't be converted to a number it will default to the edit button
        end
    end
    
    -- members only?
    local members = item['Members']
    if type(members) == 'table' then
        -- contains yes and/or no
        local hasYes, hasNo = false, false
        for _, value in ipairs(members) do
            if yesNo(value) then
                hasYes = true
            elseif not(yesNo(value)) then
                hasNo = true
            end
        end
        if hasYes and hasNo then
            members = f2pIcon.."/"..p2pIcon
        elseif hasYes then
            members = p2pIcon
        elseif hasNo then
            members = f2pIcon
        else
            members = editbtn -- Unsupported type for yesNo, default to editbtn
        end
    elseif yesNo(members) then
        members = p2pIcon
    elseif not(yesNo(members)) then
        members = f2pIcon
    else -- Unsupported type for yesNo, default to editbtn
        members = editbtn
    end

    return {
        seller = seller,
        location = location,
        region = region,
        stock = stock,
        stockSortValue = stockSortValue,
        restock = restock,
        restockSortValue = restockSortValue,
        sellvalue = sellvalue,
        sellSortValue = sellSortValue,
        buyvalue = buyvalue,
        buySortValue = buySortValue,
        members = members
    }
end

function editbutton(title)
    local link = string.gsub(mw.title.getCurrentTitle():fullUrl("action=edit"), mw.title.getCurrentTitle().fullText, title)
    link = string.gsub(link, ' ', '_')
    link = string.format("<span class='plainlinks'>[%s '''?''' (edit)]</span>", link)
    return link
end

function ticktime(ticks)
	local ret = ''
	local days = math.floor(ticks/144000)
	local hours = math.floor(ticks%144000/6000)
	local minutes = math.floor(ticks%6000/100)
	local seconds = ticks%100*0.6
	if days > 0 then
		ret = ret .. days .. 'd '
	end
	if hours > 0 then
		ret = ret .. hours .. 'h '
	end
	if minutes > 0 then
		ret = ret .. minutes .. 'm '
	end
	if seconds > 0 then
		ret = ret .. seconds .. 's'
	end
	return ret
end

--[[ DEBUG COPYPASTA
= p._main({'Saw'})
--]]

return p