Module:Currency

-- local p = {}

local loader = require('Module:Loader') local getArgs = require('Module:Arguments').getArgs

local string, table, yesno = loader.require('String', 'Table', 'Yesno') local currencyData, bazaarData = loader.loadData('Currency/Data', 'Bazaar/Data')

local formatNum, shorten, toNumber = string._formatNum, string._formatShortNum, string._toNumber

local lang = mw.language.getContentLanguage

-- Template:Currency access point -- --

function p.currency(frame) local args = getArgs(frame) local s = tostring(args[1]) if s and s:match(' ') then return s end s = s and s:gsub('%s*([Ss]ky[Bb]lock)?', '') local m = args[2] local useShort = yesno(args['short'] or args['s'], false) local useApproximate = yesno(args['approximate'] or args['approx'] or args['a'], false) local useImage = yesno(args['image'] or args['i'] or args['si'] or args['show_image'], false) local noLink = yesno(args['nolink'] or args['nl'], false) local imageInFront = yesno(args['image_in_front'] or args['iif'], false) local alt = args['alt'] return p._currencyTemplate(s, m, useShort, useApproximate, useImage, noLink, imageInFront, alt) end function p._currencyTemplate(s, m, useShort, useApproximate, useImage, noLink, imageInFront, alt) local curr if s:find('[Gg]ems?') then s = s:gsub('[Gg]ems?', '') curr = 'gems' elseif s:find('[Bb]its?') then s = s:gsub('[Bb]its?', '') curr = 'bits' elseif s:find('[Pp]elts?') then s = s:gsub('[Pp]elts?', '') curr = 'pelts' elseif s:find('[Bb]ingo [Pp]oints?') then s = s:gsub('[Bb]ingo [Pp]oints?', '') curr = 'bingoPoints' else s = s:gsub('[Cc]oins?', '') curr = 'coins' end return p._currency(s, m, {		useShort = useShort, 		useApproximate = useApproximate, 		useImage = useImage, 		noLink = noLink, 		imageInFront = imageInFront, 		alt = alt, 		currency = curr,	}) end

local function getImg(val, t)	if type(t) ~= 'table' then return {t} end if type(t[1]) ~= 'table' then return {t[1]} end for i,v in ipairs(t) do		if (not v.lim or v.lim == 'inf') -- no upper limit, or upper limit is inf or (i == table.length(t)) -- reached last element in table or (val < v.lim) then return v		end end end

-- Module access point function p._currency(...) local s, m, options, useShort, useApproximate, useImage, noLink, imageInFront, alt, currency -- Support numbered arguments if type(({...})[3]) ~= 'table' then s, m, useShort, useApproximate, useImage, noLink, imageInFront, alt, currency = ... else s, m, options = ... useShort, useApproximate, useImage, noLink, imageInFront, alt, currency = options.useShort, options.useApproximate, options.useImage, options.noLink, options.imageInFront, options.alt, options.currency end local a,b = tostring(s):match('^%s*(%-?%d+)%s*%-%s*(%-?%d+)%s*$') if not not a and not not b then s = a		m = b	end if not currency then currency = 'coins' end -- Default values useShort = useShort or false useApproximate = useApproximate or false currency = currencyData[currency] -- If first value is scientific notation if s and string.find(tostring(s), '10%^%d*') then --if not useShort, return scientific notation. if useShort, convert scientific notation to number if not useShort then s = s:gsub('%s+?%*%s+?', ' × ') s = s:gsub('10%^(%d*)', '10%1') return mw.html.create('span') :css('color', currency.color) :wikitext(table.concat({ '', s, '',					currency.name,					' ' }))		else if s:find('%*') then local number = s:match('(%d*)%s?*%s+?10%^%d*') local exponent = s:match('%d*%s?*%s+?10%^(%d*)') s = tonumber(number) * math.pow(10, tonumber(exponent)) else local toShort = s:match('10%^(%d*)') s = math.pow(10, tonumber(toShort)) end end -- If first value isn't a valid number, just return the invalid number as a fallthrough elseif s and toNumber(s) == nil then return s	-- If first value is null, just return colored currency text elseif s == nil then return mw.html.create('span') :css('color', currency.color) :wikitext(table.concat({ '',					alt and alt or currency.name..'s',					' ' }))	end -- Convert params to numbers - nil if not a number s = toNumber(s) m = toNumber(m) local sAsNumber = s	image = '' if (useImage or imageInFront) and currency.images then local img_ = getImg(s, currency.images) image = table.concat{ ''		}		image = image..'&thinsp;' end local tooltip = nil if useShort then if m then tooltip = formatNum(s)..'–'..formatNum(m) elseif s then tooltip = formatNum(s) end s = shorten(s) if m then m = shorten(m) end else s = formatNum(s) if m then m = formatNum(m) end end g = mw.html.create('span') :attr('title', tooltip) :css('font-variant-numeric', 'tabular-nums') if useApproximate then g:wikitext('&#8776;') end if m then t = s..'–'..m..' ' g:wikitext(t) elseif s then t = s..' ' g:wikitext(t) end return mw.html.create('span') :css('color', currency.color) :wikitext(imageInFront and image or '') :node(g) :wikitext(			(imageInFront and  or image),			'',			alt and alt or lang:plural(sAsNumber, currency.name, currency.name..'s'),			' '		) end

function p.currencySlot(s, m, noLink, noarg1) local curr if type(s) ~= 'string' then return end if s:find('[Gg]ems?%s*$') then s = s:gsub('[Gg]ems?%s*$', '') curr = 'gems' elseif s:find('[Bb]its?%s*$') then s = s:gsub('[Bb]its?%s*$', '') curr = 'bits' elseif s:find('[Pp]elts?%s*$') then s = s:gsub('[Pp]elts?%s*$', '') curr = 'pelts' elseif s:find('[Bb]ingo [Pp]oints?%s*$') then s = s:gsub('[Bb]ingo [Pp]ointselts?%s*$', '') curr = 'bingoPoints' elseif s:find('[Cc]oins?%s*$') then s = s:gsub('[Cc]oins?%s*$', '') curr = 'coins' else return end return p._currencySlot(s, m, {		noLink = noLink or false,		noarg1 = noarg1 or false,		currency = curr,	}) end

function p._currencySlot(...) local s, m, options, noLink, noarg1, currency -- Support numbered arguments if type(({...})[3]) ~= 'table' then s, m, noLink, noarg1, currency = checkTypeArgs({			{ 'string', 'number', nilOk=true },			{ 'string', 'number', nilOk=true },			{ 'boolean', nilOk=true },			{ 'boolean', nilOk=true },			{ 'string', nilOk=true },		}, ...) else s, m, options = checkTypeArgs({ { 'string', 'number', nilOk=true }, { 'string', 'number', nilOk=true }, { 'table', nilOk=true } }, ...) noLink, noarg1, currency = options.noLink, options.noarg1, options.currency end if s then assertTrue(type(tostring(s)) == 'string') temp = string.split(tostring(s),'-') if (#temp == 2) then s = temp[1] m = temp[2] end end if not currency then currency = 'coins' end currency = currencyData[currency] -- If first value is scientific notation if s and string.find(tostring(s), '10%^%d*') then --if not useShort, return scientific notation. if useShort, convert scientific notation to number if s:find('%*') then local number = s:match('(%d*)%s?*%s+?10%^%d*') local exponent = s:match('%d*%s?*%s+?10%^(%d*)') s = tonumber(number) * math.pow(10, tonumber(exponent)) else local toShort = s:match('10%^(%d*)') s = math.pow(10, tonumber(toShort)) end -- If first value isn't a valid number, return nil as conversion failed -- If first value is null, also return nil as conversion failed elseif toNumber(s) == nil then return end -- Convert params to numbers - nil if not a number s, m = toNumber(s), toNumber(m) local sAsNumber = s	image = '' local source = currency.images or currency.placeholder local item = getImg(m or s, source)[1] local grouped_num, tooltip if m then grouped_num = ('%.f-%.f'):format(s,m) tooltip = formatNum(s)..'-'..formatNum(m) elseif s then grouped_num = ('%.f'):format(s) tooltip = formatNum(s) end local ret = { name = item, link = noLink and '' or currency.destPage, title = ('%s%s %s'):format(			currency.tooltipcolor, 			tooltip,			lang:plural(sAsNumber, currency.name, currency.name..'s')			), text = '', }	if not noarg1 then ret[1] = grouped_num and ('%s,%s'):format(item,grouped_num) or item end return ret end

local function generateCurrencyFunc(currencyName, substituteRegex) local function _main(s, m, useShort, useApproximate, useImage, noLink, imageInFront, alt) return p._currency(s, m, {			useShort = useShort, 			useApproximate = useApproximate, 			useImage = useImage, 			noLink = noLink, 			imageInFront = imageInFront, 			alt = alt, 			currency = currencyName,		}) end local function main(frame) local args = getArgs(frame) local callfn = _main if args[1] and args[1]:match(' ') then return args[1] end if args[1] then s = args[1]:lower:gsub('[%[%]]+', ):gsub(substituteRegex, ) end local m = args[2] local useShort = yesno(args['short'] or args['s'], false) local useApproximate = yesno(args['approximate'] or args['approx'] or args['a'], false) local useImage = yesno(args['image'] or args['i'] or args['si'] or args['show_image'], false) local noLink = yesno(args['nolink'] or args['nl'], false) local imageInFront = yesno(args['image_in_front'] or args['iif'], false) local alt = args['alt'] return callfn(s, m, useShort, useApproximate, useImage, noLink, imageInFront, alt) end return main, _main end

-- Template:Coins access point p.coins, p._coins = generateCurrencyFunc('coins', '%s*coins?')

-- Template:Bits access point p.bits, p._bits = generateCurrencyFunc('bits', '%s*(skyblock)?bits?')

-- Template:Gems access point p.gems, p._gems = generateCurrencyFunc('gems', '%s*(skyblock)?gems?')

-- Template:Pelts access point p.pelts, p._pelts = generateCurrencyFunc('pelts', '%s*pelts?')

-- Template:Bingo Points access point p.bingoPoints, p._bingoPoints = generateCurrencyFunc('bingoPoints', '%s*bingo coins?')

-- Template:Coins to Dollars -- -- Used to convert value in coins to US Dollars, based on Booster Cookie prices

function p.coins_to_dollars(frame) local args = getArgs(frame) local coins = args[1] local isFormatted = yesno(args['format'] or args['f'], true) return p._coins_to_dollars(coins, type) end

function p._coins_to_dollars(coins, isFormatted) if isFormatted == nil then isFormatted = true end local cookiePriceCoins = bazaarData.products.BOOSTER_COOKIE.buy local cookiePriceGems = 325 local cookiePriceDollars = 4.99 / 675 * cookiePriceGems local coinPriceDollars = cookiePriceCoins / cookiePriceDollars if not isFormatted then return coins / coinPriceDollars end local dollars = coins / coinPriceDollars dollars = dollars * 100 dollars = math.floor(dollars) dollars = dollars / 100 return '$'..formatNum(dollars) end

-- Template:Bits to Coins -- -- Used to convert value in cbits to coins, based on prices across items with fairly stable prices and demand

function p.bits_to_coins(frame) local args = getArgs(frame) local bits = args[1] return p._bits_to_coins(bits) end

function p._bits_to_coins(bits) local conversion = (bazaarData['products']['MAGMA_BUCKET']['buy']-bazaarData['products']['ENCHANTED_LAVA_BUCKET']['buy']*2)/3000 local coins = bits * conversion return p._coins(coins, nil, true, true) end

return p