Module:Item

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

local string, table, yesno, raritytier, currency, linkmodule, color, itemData = loader.require('String', 'Table', 'Yesno', 'RarityTier', 'Currency', 'Link', 'Color', 'Item/Data') local itemAliases = loader.loadData('Item/Aliases')

local cache = require('Module:Cache') local apiDataCache = cache.itemApiDataCache local apiAliasesCache = cache.itemApiAliasesCache

local addThousandSep = string._formatNum local makeRarity = raritytier._link local makeCurrency = currency._currency local makeEnchant = linkmodule._enchantmentsLink local setColor = color._colorTemplates

local lang = mw.getContentLanguage local frame = mw.getCurrentFrame local exists = table.Set

local p = {}

local itemImage = itemAliases.itemImage local itemReplacements = itemAliases.itemReplacements

-- Due to their sizes, don't load these modules until / unless they are needed local __apidata, __apialiases function p.getApiData if __apidata then return __apidata end __apidata = mw.loadData('Module:Item/ApiData') return __apidata end function p.getApiAliases if __apialiases then return __apialiases end __apialiases = mw.loadData('Module:Item/ApiAliases') return __apialiases end

--- -- Template: Resource Display -- -- Displays item and its amount, alongside its image, drop chance, rarity, enchant, etc --- function p.resourceDisplay(frame) local args = getArgs(frame) local str = args[1] local img = yesno(args['image'] or args['img'] or args['i'], true) local nolink = yesno(args['nolink'] or args['nl'], false) local noErr = yesno(args['noerror'] or args['ne'], false) local ignoreOdds = yesno(args['ignoreodds'], false) local noImagePadding = yesno(args['noimgpad'], false) return string.pcall(p._item, str, img, nolink, noErr, false, ignoreOdds, noImagePadding) end --- -- Template: Item Display -- -- Displays only item, alongside its image, drop chance, rarity, enchant, etc --- function p.itemDisplay(frame) local args = getArgs(frame) local str = args[1] local img = yesno(args['image'] or args['img'] or args['i'], true) local nolink = yesno(args['nolink'] or args['nl'], false) local noErr = yesno(args['noerror'] or args['ne'], false) local ignoreOdds = yesno(args['ignoreodds'], false) local noImagePadding = yesno(args['noimgpad'], false) return string.pcall(p._item, str, img, nolink, noErr, true, ignoreOdds, noImagePadding) end --- -- Functions for use in other modules --- function p._resourceDisplay(str, img, nolink, noErr, ignoreOdds, noImagePadding) return p._item(str, yesno(img, true), nolink, noErr, false, ignoreOdds, noImagePadding) end function p._itemDisplay(str, img, nolink, noErrm, ignoreOdds, noImagePadding) return p._item(str, yesno(img, true), nolink, noErr, true, ignoreOdds, noImagePadding) end

--Module Access Point function p._item(str, img, nolink, noErr, ignoreAmount, ignoreOdds, noImagePadding) local num, num2 --remove commas, they break stuff str = str:gsub(',', ''):gsub('&percnt;', '%%'):gsub('&amp;', '&') local after --determine whether or not the hover text should be displayed local no_hover = str:match('%d+%-+%d+') and true or false if str:match('%s*[^\\];%s*(.-)$') then str, after = str:match('^(.+)%s*;%s*(.-)$') end --separate item and quantity + handle invalid syntax if not ignoreAmount then if str:match('^([%d,%-%?]+%.?[%d,%-]*x? ?or ?[%d,%-%?]+%.?[%d,%-]*x?) (.*)') then num, item = str:match('^([%d,%-%?]+%.?[%d,%-]*x? ?or ?[%d,%-%?]+%.?[%d,%-]*x?) (.*)') elseif str:match('^([%d,%-%?]+%.?[%d,%-]*x?) (.*)') then num, item = str:match('^([%d,%-%?]+%.?[%d,%-]*x?) (.*)') elseif noErr then return str else item = str no_hover = true -- return string.error('Invalid Resource list syntax "%s"', str) end if num and num:match('or') then local tempStr = num num, num2 = tempStr:match('(.+) ?or ?(.+)') end --handle colors (green = standard, red = only when number is '?') text_color = 'Green' if (num and num:match('%?')) or (num2 and num2:match('%?')) then no_hover = true text_color = 'Red' end --remove unnecessary characters from number num = num and num:gsub('[x,]', '') num2 = num2 and num2:gsub('[x,]', '') else if str:match('^[%d,%-%?]+%.?[%d,%-]*x? ?or ?[%d,%-%?]+%.?[%d,%-]*x? (.*)') then item = str:match('^[%d,%-%?]+%.?[%d,%-]*x? ?or ?[%d,%-%?]+%.?[%d,%-]*x? (.*)') elseif str:match('^[%d,%-%?]+%.?[%d,%-]*x? (.*)') then item = str:match('^[%d,%-%?]+%.?[%d,%-]*x? (.*)') else item = str end end --remove unnecessary characters from item item = item:gsub('[%[%]]', '') --unpack and process aliases item = ' '..item..' ' for pattern, replace in pairs(itemReplacements) do		if item:match(pattern) then item = item:gsub(pattern, replace) end end item = mw.text.trim(item) local alt = item -- if item:match('s$') or item:match('[Bb]locks') then -- 	alt = item -- 	item = item:gsub('s$', ''):gsub('[Bb]locks', 'Block') -- end if item:match('[Bb]locks') then alt = item item = item:gsub('[Bb]locks', 'Block') end --generate alternate text if item:match('%|') then item, alt = item:match('(.*)%|(.*)') elseif item:match('[^%%]%!') then item, alt = item:match('(.*)%!(.*)') end --determine whether or not odds should be displayed local odds = nil if item:match('%s%%.+%%') then odds = item:match('.*%s%%(.+)%%') item = item:gsub('(.*)%s%%.+%%(.*)', '%1%2') end if alt:match('%s%%.+%%') then odds = alt:match('.*%s%%(.+)%%') alt = alt:gsub('(.*)%s%%.+%%(.*)', '%1%2') end --determine whether or not enchant should be displayed local enchant = nil if item:match('%s&.+&') then enchant = item:match('.*%s&(.+)&') item = item:gsub('(.*)%s&.+&(.*)', '%1%2') end if alt:match('%s&.+&') then enchant = alt:match('.*%s&(.+)&') alt = alt:gsub('(.*)%s&.+&(.*)', '%1%2') end --change the $rarity$ to actual rarity template alt = alt:gsub(		'(.*)$(.+)$(.*)', 		function(a, b, c) 			return table.concat{				a, 				makeRarity(b, nil, nil, true), 				c,			} 		end	) item = item:gsub('(.*)%s?$.+$%s?(.*)', '%1%2') item = mw.text.trim(item) --convert armor piece string to functional string, pick the proper image (helmet) local item_img = itemImage[item] or item if item:match('(.*) [Pp][Ii][Ee][Cc][Ee]$') then local isPiece = true local foo = item:match('(.*) [Aa][Rr][Mm][Oo][Rr] [Pp][Ii][Ee][Cc][Ee]') or item:match('(.*) [Pp][Ii][Ee][Cc][Ee]') if foo:match('Armor of .*') then local foo = foo:match('Armor of (.*)') alt = 'Armor of '..foo..' Piece' item = 'Armor of '..foo item_img = itemImage[foo] or 'Helmet of '..foo or 'Armor of '..foo..' Helmet' elseif foo:match('.* [Tt][Uu][Xx][Ee][Dd][Oo]') then alt = foo..' Piece' item = foo item_img = foo..' Jacket' elseif foo:match('.*') then alt = foo..' Armor Piece' item = foo..' Armor' item_img = itemImage[foo] or foo..' Helmet' end elseif item:match('(.+) [Aa][Rr][Mm][Oo][Rr]$') and not isPiece then local foo = item:match('(.+) [Aa][Rr][Mm][Oo][Rr]$') item_img = itemImage[foo] or foo..' Helmet' elseif item:match('(.+) [Tt][Uu][Xx][Ee][Dd][Oo]') and not isPiece then local foo = item:match('(.+) [Tt][Uu][Xx][Ee][Dd][Oo]$') item_img = itemImage[foo] or foo..' Tuxedo Jacket' elseif not (item:match('[Aa][Rr][Mm][Oo][Rr] [Oo][Ff] (.*) [Hh][Ee][Ll][Mm][Ee][Tt]') or item:match('[Aa][Rr][Mm][Oo][Rr] [Oo][Ff] (.*) [Cc][Hh][Ee][Ss][Tt][Pp][Ll][Aa][Tt][Ee]') or item:match('[Aa][Rr][Mm][Oo][Rr] [Oo][Ff] (.*) [Ll][Ee][Gg][Gg][Ii][Nn][Gg][Ss]') or item:match('[Aa][Rr][Mm][Oo][Rr] [Oo][Ff] (.*) [Bb][Oo][Oo][Tt][Ss')) and item:match('[Aa][Rr][Mm][Oo][Rr] [Oo][Ff] (.*)') and not isPiece then local foo = item:match('[Aa][Rr][Mm][Oo][Rr] [Oo][Ff] (.*)') item_img = itemImage[foo] or 'Helmet of '..foo end --convert minion string to functional string, pick the proper image (tier I minion head) if item:match('Minion [IVXivx]+') then item = item:gsub('(Minion )[IVXivx]+', '%1') elseif item:match('Minion') then item_img = item..' I'	end local title, title2 --handle the calculations performed on the number, then format it	if not ignoreAmount then if not no_hover then --get amount of stacks and items stacks = math.floor(tonumber(num) / 64) items = tonumber(num) % 64 --add thousand separator to the quantity num = addThousandSep(num) end title = nil if not no_hover then --add hover info about amount in stacks and items if stacks + items * 0.01 > 1 then local str_stacks = lang:plural( stacks, 'stack', 'stacks' ) local str_items = lang:plural( items, 'item', 'items' ) if items > 0 then title = ('%s %s plus %s (%s in total)') :format(addThousandSep(stacks), str_stacks, items, num) else title = ('%s %s (%s items total)') :format(addThousandSep(stacks), str_stacks, num) end end end --same thing as above, but for second number if not no_hover and num2 then --get amount of stacks and items stacks2 = math.floor(tonumber(num2) / 64) items2 = tonumber(num2) % 64 --add thousand separator to the quantity num2 = addThousandSep(num2) end title2 = nil if not no_hover and num2 then --add hover info about amount in stacks and items if stacks2 + items2 * 0.01 > 1 then local str_stacks = lang:plural(stacks2, 'stack', 'stacks') local str_items = lang:plural(items2, 'item', 'items') if items2 > 0 then title2 = ('%s %s plus %s (%s in total)') :format(addThousandSep(stacks2), str_stacks, items2, num2) else title2 = ('%s %s (%s items total)') :format(addThousandSep(stacks2), str_stacks, num2) end end end end local function _getImage(img_, nolink_, item_, nip) return pageExists('File:' .. img_ .. '.png') and string.makeImage(img_, { size=21, link=nolink_ and '' or item_, alt=item_ }) .. ' '			or ( nip and 				or string.makeImage('Blank Icon.png', { size = 21, link =  }) .. ' '			) end --apply formatting local ret = {} if ignoreAmount then ret = { (img and _getImage(item_img, nolink, item, noImagePadding) or ''), nolink and (alt and alt or item) or string.makeLink(item, alt), (enchant and (' (%s)'):format(makeEnchant(enchant)) or ''), ((odds and not ignoreOdds) and ('(%s)'):format(odds) or ''), after and ' '..after or '', }	elseif item:lower:find('^%s*coins?%s*$') then ret = { tostring(makeCurrency(ignoreAmount and nil or num, nil, false, false, img, nolink, true, nil, 'coins')) }	elseif item:lower:find('^%s*bits?%s*$') then ret = { tostring(makeCurrency(ignoreAmount and nil or num, nil, false, false, img, nolink, true, nil, 'bits')) }	elseif item:lower:find('^%s*gems?%s*$') then ret = { tostring(makeCurrency(ignoreAmount and nil or num, nil, false, false, img, nolink, true, nil, 'gems')) }	elseif item:lower:find('^%s*pelts?%s*$') then ret = { tostring(makeCurrency(ignoreAmount and nil or num, nil, false, false, false, nolink, true, nil, 'pelts')) }	elseif num2 then ret = { img and _getImage(item_img, nolink, item, noImagePadding) or '', string.makeTitle(				setColor(text_color, num), 				title, 				{ ignoreTitleNil = true }			), --returns first param if title is nil ' ', setColor(text_color, 'or'), ' ', string.makeTitle(setColor(text_color, num2..'x'), title2, {ignoreTitleNil = true}), --returns first param if title2 is nil ' ',			nolink and (alt and alt or item) or string.makeLink(item, alt), enchant and (' (%s)'):format(makeEnchant(enchant)) or '', (odds and not ignoreOdds) and ('(%s)'):format(odds) or '', after and ' '..after or '', }	else ret = { (img and _getImage(item_img, nolink, item, noImagePadding) or ''), string.makeTitle(num and setColor(text_color, num..'x') or '', title, {ignoreTitleNil = true}), --returns first param if title is nil ' ',			nolink and (alt and alt or item) or string.makeLink(item, alt), (enchant and (' (%s)'):format(makeEnchant(enchant)) or ''), ((odds and not ignoreOdds) and ('(%s)'):format(odds) or ''), after and ' '..after or '', }	end return (table.concat(ret)) --return (table.concat(ret):gsub('%%([^%%])', '%1')) end

function p._api( id ) id = id:upper:gsub(' ', '_') local key = apiAliasesCache:get(id) or id	local a, b = apiDataCache:get(key), itemData.items[key] if a or b then return table.merge({}, table.deepCopy(a or {}, true), table.deepCopy(b or {}, true)) end end

function p._sellPrice( id ) local it = p._api( id ) return it and it.npc_sell_price end

--Finish Module return p