Terraria Mods Wiki
Advertisement

This module is intended to provide functionality to the {{item}} template.


local trim = mw.text.trim
local cargo = mw.ext.cargo

local currentFrame
local args_table
local modname

local getArg = function(key)
	local value = args_table[key]
	if not value then
		return nil
	end
	value = trim(value)
	if value == '' then
		return nil
	end
	return value
end

local function parse(str)
	local args = {}
	for s in mw.ustring.gmatch(str, '%b₫^') do 
		local k,v = mw.ustring.match(s, '^₫(.-):(.*)^$')
		args[k] = v
	end
	args[1] = args['name']
	args[2] = args['text']
	return args
end

-- credit: http://richard.warburton.it
-- this version is with trim.
local function explode(div,str) 
	if (div=='') then return false end
	local pos,arr = 0,{}
	-- for each divider found
	for st,sp in function() return string.find(str,div,pos,true) end do
		arr[#arr + 1] = trim(string.sub(str,pos,st-1)) -- Attach chars left of current divider
		pos = sp + 1 -- Jump past current divider
	end
	arr[#arr + 1] = trim(string.sub(str,pos)) -- Attach chars right of last divider
	return arr
end

local function parseSize(size)
	if not size then return end
	local basescale, width, height
	size, basescale = unpack(explode('*', size))
	if size ~= '' then
		width, height = unpack(explode('x', string.gsub(size, 'px', '')))
		width, height = tonumber(width), tonumber(height)
		if width == 0 then width = nil end
		if height == 0 then height = nil end
	end
	return basescale, width, height
end

local function getInfoFromCargo(image)
	-- try to get from cargo cache
	local result = mw.ext.cargo.query('Imageinfo', 'width, height, cached', {
		where = 'image='.. "'"..image:gsub("'", "\\'"):gsub("'", "\\'").."'",
		orderBy = "cached DESC",
		limit = 1,
	})
	for _, row in ipairs(result) do
		return tonumber(row['width']), tonumber(row['height']), row['cached']
	end
end

local function storeInfoToCargo(imagename)
	local imageTitle = mw.title.new("File:" .. imagename)
	local width, height = imageTitle.file.width, imageTitle.file.height
	if width and width ~= 0 and height and height ~= 0 then
		currentFrame:callParserFunction('#cargo_store:_table=Imageinfo',{
			image = imagename,
			width = width,
			height = height,
			cached = os.time(),
		})
	end
	return width, height
end

local function getSizeInfo(image)
	local width, height, cached = getInfoFromCargo(image)
	-- cache missed, init cache
	if not cached then
		width, height = storeInfoToCargo(image)
	end
	if width == 0 then width = nil end
	if height == 0 then height = nil end
	return width, height
end

local function getImageSize(image, width, height, scale, maxwidth, maxheight)
	-- get size info from image file itself (may be expensive)
	local w, h = getSizeInfo(image) -- store data to cache

	if not width and not height and (scale or maxwidth or maxheight) then
		width, height = w, h
	end

	-- apply scale to width/height if needed
	if scale then
		if width then width = width * scale end
		if height then height = height * scale end
	end

	-- apply maxwidth/maxheight.
	if maxwidth then
		if width then
			if width > maxwidth then width = maxwidth end
		else
			if height then width = maxwidth end
		end
	end
	if maxheight then
		if height then
			if height > maxheight then height = maxheight end
		else
			if width then height = maxheight end
		end
	end

	-- rounding
	if width then width = math.ceil(width) end
	if height then height = math.ceil(height) end

	return width, height
end

local function parseMaxSize(maxsize)
	if not maxsize then return end
	local maxwidth, maxheight = unpack(explode('x', string.gsub(maxsize, 'px', '')))
	maxwidth, maxheight = tonumber(maxwidth), tonumber(maxheight)
	if maxwidth == 0 then maxwidth = nil end
	if maxheight == 0 then maxheight = nil end
	return maxwidth, maxheight
end

local function imagecode(image, link, text, size, scale, maxsize)
	local image_output = '[[File:' .. image .. '|link='.. link .. '|' .. text
	if size or scale or maxsize then
		local basescale, width, height = parseSize(size) -- width,height: number or nil
		scale = (tonumber(scale) or 1) * (tonumber(basescale) or 1)
		if scale == 0 or scale == 1 then
			scale = nil
		end
		local maxwidth, maxheight = parseMaxSize(maxsize)
		width, height = getImageSize(image, width, height, scale, maxwidth, maxheight) -- can be 0
		if width or height then
			return image_output .. '|' .. (width or '') .. 'x' .. (height or '') .. 'px]]'
		else
			return image_output .. ']]'
		end
	else
		return image_output .. ']]'
	end
end

local function images(image, link, text, size, scale, maxsize)
	
	if not image:find('/') then
		return imagecode(image, link, text, size, scale, maxsize)
	end

	image = explode('/', image)
	local result = ''
	if size and size:find('/') then
		size = explode('/', size)
		for i, v in ipairs(image) do
			result = result .. imagecode(v, link, text, size[i], scale, maxsize)
		end
	else
		for i, v in ipairs(image) do
			result = result .. imagecode(v, link, text, size, scale, maxsize)
		end
	end
	return result
end

local getIdText = function(_type)
	local id_text
	if _type == 'item' then -- a shortcut for faster
		id_text = 'Internal [[Item IDs|Item ID]]: '
	elseif _type == 'tile' then
		id_text = 'Internal [[Tile IDs|Tile ID]]: '
	elseif _type == 'wall' then
		id_text = 'Internal [[Wall IDs|Wall ID]]: '
	elseif _type == 'npc' then
		id_text = 'Internal [[NPC IDs|NPC ID]]: '
	elseif _type == 'mount' then
		id_text = 'Internal [[Mount IDs|Mount ID]]: '
	elseif _type == 'buff' or _type == 'debuff' then
		id_text = 'Internal [[Buff IDs|Buff ID]]: '
	elseif _type == 'projectile' then
		id_text = 'Internal [[Projectile IDs|Projectile ID]]: '
	elseif _type == 'armor' then
		id_text = 'Internal [[Armor IDs|Armor ID]]: '
	else
		id_text = 'Internal [[Item IDs|Item ID]]: '
	end
	return id_text
end

local handleModItem = function()
	args_table[1] = args_table[1]:gsub('‡‡', '#') -- decode the hash character, was encoded in {{item}} to prevent expansion to ol
	args_table[2] = args_table[2]:gsub('‡‡', '#')
	if args_table[1]:sub(1, 1) == '#' then
		local pos = args_table[1]:find('@')
		if pos then
			modname = args_table[1]:sub(pos+1)
			args_table[1] = args_table[1]:sub(1, pos-1)
		end
		if args_table[1]:sub(2, 2) == '#' then
			local itemname = args_table[1]:sub(3)
			if not getArg(2) or args_table[2]:sub(1, 2) == '%%' then
				args_table[2] = itemname
			end
			args_table[1] = itemname
			if modname then
				args_table[1] = modname .. '/' .. itemname
				args_table['note'] = (getArg('note') and args_table['note'] .. ' ' or '') .. '(' .. modname .. ')'
				if not getArg('image') then
					local normalized_modname = modname:gsub('^User:', 'User-'):gsub('/', '-')
					args_table['image'] = itemname .. ' (' .. normalized_modname .. ').' .. (getArg('ext') or 'png')
				end
				if not getArg('wrap') then
					args_table['wrap'] = 'y'
				end
			end
		else
			local itemname = args_table[1]:sub(2)
			if not getArg(2) or args_table[2]:sub(1, 2) == '%%' then
				args_table[2] = itemname
			end
			args_table[1] = itemname
			if modname then
				args_table[1] = modname .. '/' .. itemname
				if not getArg('image') then
					local normalized_modname = modname:gsub('^User:', 'User-'):gsub('/', '-')
					args_table['image'] = itemname .. ' (' .. normalized_modname .. ').' .. (getArg('ext') or 'png')
				end
			end
		end
	end
	if getArg(2) and args_table[2]:sub(1, 2) == '%%' then
		args_table[2] = args_table[2]:sub(3)
	end
end


-----------------------------------------------------------------
-- main return object
return {
	
go = function(frame, args)

	currentFrame = frame
	args_table = args or parse(frame.args[1])
	
	modname = getArg('mod') or currentFrame:expandTemplate{ title = 'modname', args = { 'get' } }
	
	handleModItem()
	
	local _arg1 = getArg(1) or ''
	local _nolink = getArg('nolink')
	local _link = _nolink and '' or getArg('link') or _arg1 -- now:  _link == ''  means nolink.
	
	local text = getArg(2) or ''

	local hovertext
	if _arg1 ~= '' then
		hovertext = _arg1
	elseif text ~= '' then
		hovertext = text
	else
		hovertext = _link
	end

	local class = 'i'
	
	local output_image, output_text, output_table = true, true, false
	local _mode = getArg('mode')
	if _mode then
		if _mode == 'image' or _mode == 'imageonly' or _mode =='onlyimage' then
			output_text = false
		elseif _mode == 'text' or _mode == 'noimage' then
			output_image = false
		elseif _mode == 'table' or _mode == '2-cell' then
			output_table = true
		end
	end

	local image_output, text_output
	if output_image then
		local image_arg = getArg('image')
		if not image_arg then
			image_arg = string.gsub(string.gsub(_arg1, ":%s*", " "), "/" , " ")
			image_arg = image_arg .. '.' .. ((not args_table['ext'] or args_table['ext'] == '') and 'png' or args_table['ext'])
		end
		if string.find(image_arg, '%[%[[fF]ile:') then
			image_output = '<span class="img">' .. image_arg .. '</span>'
		else
			image_output = images(image_arg, _link, hovertext, getArg('size'), getArg('scale'), getArg('maxsize'))
		end
	else
		image_output = ''
	end
	
	if output_text then
		local _note, _note2, _showid, _id = getArg('note'), getArg('note2'), getArg('showid'), getArg('id')

		if _id and not _showid then
			_showid = true
		end
		if _showid and (_showid == 'n' or _showid == 'no') then
			_showid = false
		end

		local _wrap
		if _showid or _note2 then
			_wrap = false
		else
			_wrap = getArg('wrap')
		end

		if _link ~= '' then
			if text == _link then
				text = '<span>[['..text..']]</span>'
			else
				text = '<span>[['.._link..'|'..text..']]</span>'
			end
		else
			text = '<span title="'..hovertext..'">'..text..'</span>'
		end

		local content = text -- item name link text first.
		-- '-w' class means 'wrapmode', optimized for multiple lines of text. But it should be disabled for single line text.
		if _wrap then
			-- note in next line
			if _note then
				class = class .. ' -w'
				content = content .. '<span class="note">' .. _note .. '</span>'
			end
		else
			-- note first
			if _note then
				content = content .. '<span class="note">' .. _note .. '</span>'
			end
			if _note2 then
				class = class .. ' -w'
				content = content .. '<div class="note">' .. _note2 .. '</div>'
			end
			if _showid then
				class = class .. ' -w'
				local idtype = (getArg('type') or 'item'):lower()
				local id_text = getIdText(idtype)
				content = content .. '<div class="id">' .. id_text .. _id .. '</div>'
			end
		end
		text_output = '<span>' .. content .. '</span>'
	else
		text_output = ''
	end

	local _class, _css = getArg('class'), getArg('css')
	if _class then
		class = class .. ' ' .. _class
	end
	local attr = {class = class}
	if _css then
		attr.style = _css
	end
	
	if getArg('anchor') then
		text_output = text_output .. '<div class="anchor" id="' .. frame:callParserFunction('anchorencode', _arg1) .. '"></div>'
	end
	if output_table then
		attr.class = class
		local rowspan = getArg('rowspan')
		return (rowspan and (' rowspan='..rowspan..' class="il1c" | ') or ' class="il1c" | ') .. mw.text.tag('span', attr, image_output) .. ' || class="il2c"'.. (rowspan and (' rowspan='..rowspan) or '')..' | ' .. mw.text.tag('span', attr, text_output)
	else
		return mw.text.tag('span', attr, image_output .. text_output)
	end

end,
}
Advertisement