Jump to content
Discussions

Module:Infobox

From Undertale Wiki

Helper functions for formatting infobox data and autocategorization based on it.

Documentation

Package items

infobox.location(frame) (function)
Formats a location parameter. Complex logic in this function is supposed to both deduce which location is something happening in and which page should the page be categorized under. Location parameters that pass through this function are even allowed to be separated by bullet points and it'll parse them as separate locations. Location formats parsed by this function are: Invalid locations are trimmed and returned.
Parameter: frame Scribunto frame object (table)
Returns: Formatted location (string)
infobox.itemtype(frame) (function)
Formats an item's type and weapon subtype.
Parameter: frame Scribunto's frame object (table)
Returns: Formatted item type and weapon subtype (string)
infobox.act(frame) (function)
Formats a given enemy's ACT field in the infobox.
Parameter: frame Scribunto frame object (table)
Returns: Formatted ACTs (string)
infobox.paramcat(frame) (function)
Used for appending the Enemies category if the gold argument is supplied, and the Vendors category if the wares argument is supplied (this is how we determine their respective categories should be applied).
Parameter: frame Scribunto frame object (table)
Returns: The same thing with the category added (string)
infobox.undertale(frame) (function)
Formats the parameter for linking back to Undertale Wiki. Used only on Deltarune Wiki.
Parameter: frame Scribunto frame object (table)
Returns: Formatted returning character parameter (string)
infobox.sell(frame) (function)
Automatically deduces an item's selling value based on its buying value. Used only on Deltarune Wiki.
Parameter: frame Scribunto frame object (table)
Returns: Item's selling value (string)
infobox.locationcats() (function)
Categorizes a location page under Category:Locations, as well as under a category named by itself, if it exists.
Returns: Location's categories (string)
infobox.itemdata(frame) (function)
Stores item infobox data in item and item_type buckets.
Parameter: frame Scribunto frame object (table)
infobox.itemtable(frame) (function)
Generates a table listing of items of a certain type.
Parameter: frame Scribunto frame object (table)
Returns: Table with items listed (string)
infobox.classification(frame) (function)
Formats the infobox field for Lightner/Darkner classification and categorizes the article. Only used on Deltarune Wiki.
Parameter: frame Scribunto frame object (table)
Returns: List of all subject classifications (string)

Private items

category(t, c, sortkey) (function • local)
Adds a category into a specified string (represented as a table). Only works if the current page is in the main namespace.
Parameters:
  • t String to insert the category in (table)
  • c Category to insert (table)
  • sortkey The sort key for this category (string|nil)
--- Helper functions for formatting infobox data and autocategorization based on
--  it.
--  @module             infobox
--  @alias              p
--  @require            Module:User error
--  @require            Module:Yesno
--  @author             [[User:KockaAdmiralac|KockaAdmiralac]]
--  @author             [[User:Jacky720|Jacky720]]
--  <nowiki>
require('strict')
local p = {}

--  Package imports.
local yesno = require('Module:Yesno')
local util = require('Module:Util')
local data = mw.loadData('Module:Infobox/data')

--  Package variables.
local title = mw.title.getCurrentTitle()

--  Private logic.

--- Adds a category into a specified string (represented as a table).
--  Only works if the current page is in the main namespace.
--  @function           category
--  @param              {table} t String to insert the category in
--  @param              {table} c Category to insert
--  @param              {string|nil} sortkey The sort key for this category
--  @local
local function category(t, c, sortkey)
    if sortkey == nil and title.text == c then
        sortkey = '*'
    end
    -- TODO: Get rid of hardcoded page name, because other language wikis need
    -- to translate this and it's not obvious.
    if title.namespace == 0 and title.text ~= 'Items' then
        table.insert(t, '[[Category:')
        table.insert(t, c)
        if sortkey ~= nil and sortkey ~= '' then
            table.insert(t, '|')
            table.insert(t, sortkey)
        end
        table.insert(t, ']]')
    end
end

local function multicategory(t, c)
    for _, cat in ipairs(c) do
        category(t, cat)
    end
end

--  Package items.

--- Formats a location parameter.
--  Complex logic in this function is supposed to both deduce which location is
--  something happening in and which page should the page be categorized under.
--  Location parameters that pass through this function are even allowed to
--  be separated by bullet points and it'll parse them as separate locations.
--  Location formats parsed by this function are:
--  <pre>Card Castle &rarr; [[Card Castle]]</pre>
--  <pre>[[Card Castle]] &rarr; [[Card Castle]]</pre>
--  <pre>Card Castle (F1) &rarr; [[Card Castle#F1|Card Castle]] (F1)</pre>
--  <pre>[[Card Castle]] (F1) &rarr; [[Card Castle#F1|Card Castle]] (F1)</pre>
--  <pre>Card Castle#F1 &rarr; [[Card Castle#F1|Card Castle]] (F1)</pre>
--  <pre>[[Card Castle#F1]] &rarr; [[Card Castle#F1|Card Castle]] (F1)</pre>
--  <pre>[[Island Board (Original Game)]] &rarr; [[Island Board (Original Game)]]</pre>
--  Invalid locations are trimmed and returned.
--  @function           p.location
--  @param              {table} frame Scribunto frame object
--  @returns            {string} Formatted location
function p.location(frame)
    local str = {}
    local index = 0
    local categories = {}
    local infotype = frame.args[2]
    for _, location in ipairs(mw.text.split(frame.args[1], '*', true)) do
        local trimmed = mw.text.trim(location)
        if trimmed ~= '' then
            index = index + 1
            if index == 2 then
                table.insert(str, 1, '* ')
            end
            local link, text = mw.ustring.match(trimmed, '^%[%[([^%]]+)%]%]%s*%(?([^)]*)%)?$')
            if link == nil then
                link, text = mw.ustring.match(trimmed, '([^%](]+)%s*%(?([^)]*)%)?$')
            end
            if link then
                link = mw.text.trim(link)
                if index > 1 then
                    table.insert(str, '\n* ')
                end
                local spl = mw.text.split(link, '#', true)
                local name = spl[1]
                local hash = spl[2]
                if text and text ~= '' and not hash then
                    hash = text
                end
                local ldata = data.locations[name]
                if ldata then
                    if ldata.link then
                        link = ldata.link
                    end
                    if ldata.categories then
                        multicategory(categories, ldata.categories)
                    end
                    if ldata.condcats and infotype and ldata.condcats[infotype] then
                        multicategory(categories, ldata.condcats[infotype])
                    end
                    if ldata.nolink then
                        table.insert(str, link)
                    else
                        table.insert(str, '[[')
                        table.insert(str, name)
                        if hash then
                            table.insert(str, '#')
                            table.insert(str, hash)
                            table.insert(str, '|')
                            table.insert(str, name)
                            table.insert(str, ']]')
                            table.insert(str, ' (')
                            table.insert(str, hash)
                            table.insert(str, ')')
                        else
                            table.insert(str, ']]')
                        end
                    end
                else
                    table.insert(str, trimmed)
                end
            end
        end
    end
    return table.concat(str) .. table.concat(categories)
end

--- Formats an item's type and weapon subtype.
--  @function           p.itemtype
--  @param              {table} frame Scribunto's frame object
--  @returns            {string} Formatted item type and weapon subtype
function p.itemtype(frame)
    local str = {}
    for _, itemtype in ipairs(mw.text.split(frame.args[1], ',', true)) do
        itemtype = mw.text.trim(itemtype)
        if data.itemtypes[itemtype] then
            if str[1] then
                if str[1] ~= '* ' then
                    table.insert(str, 1, '* ')
                end
                table.insert(str, '\n* ')
            end
            table.insert(str, itemtype)
            -- Categorize as Swords, Axes, Scarves, or Rings instead, based on equip parameter
            if itemtype == 'Weapon' and data.weapontypes[frame.args[2]] then
                category(str, data.weapontypes[frame.args[2]], frame.args[3])
            else
                category(str, data.itemtypes[itemtype], frame.args[3])
            end
        end
    end
    return table.concat(str)
end

--- Formats a given enemy's ACT field in the infobox.
--  @function           p.act
--  @param              {table} frame Scribunto frame object
--  @returns            {string} Formatted ACTs
function p.act(frame)
    local str = {}
    local index = 0
    local nocheck = frame.args[2]
    nocheck = mw.text.trim(nocheck)
    nocheck = mw.text.split(nocheck, '%s*,%s*')
    for _, battle in ipairs(mw.text.split(frame.args[1], '*', true)) do
        -- battle: A given battle's ACTs, passed to the function 
        --  e.g. "Cry (First box encounter)"
        -- acts: The ACTs OTHER than Check
        --  e.g. "Cry"
        -- form: The form or battle with these ACTs
        --  e.g. "First box encounter"
        -- "nocheck" parameter (frame.args[2]) prevents auto-adding Check.
        battle = mw.text.trim(battle)
        if battle ~= '' then
            index = index + 1
            if index == 2 then
                table.insert(str, 1, '* ')
            end
            if index > 1 then
                table.insert(str, '\n* ')
            end
 
            local acts, form = mw.ustring.match(battle, '^([^(]*)%s*%(?([^)]*)%)?$')
            if not yesno(nocheck[index] or nocheck[1], false) then
                if acts ~= '' then
                    table.insert(str, 'Check, ')
                else
                    table.insert(str, 'Check ')
                end
            end
            table.insert(str, acts)
            if form ~= '' then
                table.insert(str, ' (')
                table.insert(str, form)
                table.insert(str, ')')
            end
        end
    end
    return table.concat(str)
end

--- Used for appending the Enemies category if the <code>gold</code> argument
--  is supplied, and the Vendors category if the <code>wares</code> argument
--  is supplied (this is how we determine their respective categories should
--  be applied).
--  @function           p.paramcat
--  @param              {table} frame Scribunto frame object
--  @returns            {string} The same thing with the category added
function p.paramcat(frame)
	local param = frame.args[1]
	if param == nil or param == '' then
		return
	end
    local str = {param}
    category(str, frame.args[2])
    return table.concat(str)
end

--- Formats the parameter for linking back to Undertale Wiki.
--  Used only on Deltarune Wiki.
--  @function           p.undertale
--  @param              {table} frame Scribunto frame object
--  @returns            {string} Formatted returning character parameter
function p.undertale(frame)
    local str = {}
    local names = frame.args[1]
    if names == nil or names == '' then
    	return
    end
    if yesno(names, false) then
        if frame.args[2] == '' then
			-- No name specified
            names = title.text
        else
            names = frame.args[2]
        end
    end
    
    -- Iterate over multiple names
	local namesList = {}
    for _, splitName in ipairs(mw.text.split(names, ',', true)) do
        local name = mw.text.trim(splitName)
		table.insert(namesList, string.format('[[ut:%s|%s]]', name, name))
    end

	table.insert(str, table.concat(namesList, ', '))
    if frame.args[2] == '' then
		-- Don't include category for NPC pages with separated infoboxes
        category(str, 'Returning characters')
    end
    return table.concat(str)
end

--- Automatically deduces an item's selling value based on its buying value.
--  Used only on Deltarune Wiki.
--  @function           p.sell
--  @param              {table} frame Scribunto frame object
--  @returns            {string} Item's selling value
function p.sell(frame)
    local val = tonumber(frame.args[1])
    if val then
        return math.ceil(val / 2) .. ' D$'
    end
end

--- Categorizes a location page under [[:Category:Locations]], as well as under
--  a category named by itself, if it exists.
--  @function           p.locationcats
--  @returns            {string} Location's categories
function p.locationcats()
    local cats = {}
    category(cats, 'Locations')
    if data.locationcats[title.text] then
        category(cats, title.text)
    end
    return table.concat(cats)
end

--- Stores item infobox data in item and item_type buckets.
--  @function           p.itemdata
--  @param              {table} frame Scribunto frame object
function p.itemdata(frame)
	if title.namespace ~= 0 then
		return
	end
	local args = frame:getParent().args
	local item = args.name or args.title or title.text
	bucket('item').put({
		name = item,
		description = args.flavortext,
		effects = args.effects and mw.text.killMarkers(args.effects) or nil,
		source = args.source,
		buy = args.buy,
		id = args.id and tonumber(mw.ustring.match(args.id, '^%d+')) or 999
	})
	if args.type ~= nil then
		for _, itemtype in ipairs(mw.text.split(args.type, ',', true)) do
			bucket('item_type').put({item = item, type = mw.text.trim(itemtype)})
		end
	end
end

--- Generates a table listing of items of a certain type.
--  @function           p.itemtable
--  @param              {table} frame Scribunto frame object
--  @returns            {string} Table with items listed
function p.itemtable(frame)
	local itemtype = frame.args[1]
	local data = bucket('item_type')
		.where('type', itemtype)
		.join('item', 'item_type.item', 'item.name')
		.select(
			'item.page_name',
			'item.name',
			'item.description',
			'item.effects',
			'item.source',
			'item.buy',
			'item.id'
		)
		.orderBy('item.id')
		.run()

	local itemtable = mw.html.create('table')
		:attr('class', 'wikitable items-table')
		:tag('tr')
			:tag('th')
				:wikitext('Name')
			:done()
			:tag('th')
				:wikitext('Description')
			:done()
			:tag('th')
				:wikitext('Effects')
			:done()
			:tag('th')
				:wikitext('Source')
			:done()
			:tag('th')
				:wikitext('Buy')
			:done()
		:done()
	for _, item in ipairs(data) do
		itemtable:tag('tr')
			:tag('td')
				:wikitext(table.concat({'[[', item['item.page_name'], '|', item['item.name'], ']]'}))
			:done()
			:tag('td')
				:newline()
				:wikitext(item['item.description'] or '')
				-- See [[Module:Soundtrack]] for why we need the second newline.
				:newline()
			:done()
			:tag('td')
				:newline()
				:wikitext(item['item.effects'] or 'N/A')
				:newline()
			:done()
			:tag('td')
				:newline()
				:wikitext(p.location({args = {item['item.source'] or ''}}))
				:newline()
			:done()
			:tag('td')
				:newline()
				:wikitext(item['item.buy'] or 'N/A')
				:newline()
			:done()
		:done()
	end
	return tostring(itemtable:done())
end

--- Formats the infobox field for Lightner/Darkner classification and
--  categorizes the article. Only used on Deltarune Wiki.
--  @function           p.classification
--  @param              {table} frame Scribunto frame object
--  @returns            {string} List of all subject classifications
function p.classification(frame)
	local out = {}
	for cat in mw.text.gsplit(frame.args[1], ',', true) do
		local trimmedCat = mw.text.trim(cat)
		if trimmedCat == 'Lightner' or trimmedCat == 'Darkner' then
			table.insert(out, string.format('\n* [[%s]]', trimmedCat))
			category(out, trimmedCat .. 's')
		end
	end
	return table.concat(out)
end

function p.leitmotif(frame)
	local formattedList = {}
	for _, leitmotif in ipairs(util.parseCommaList(frame.args[1])) do
		table.insert(formattedList, string.format(
			'[[Leitmotifs#%s|%s]]',
			leitmotif, leitmotif
		))
	end
	return util.formatBulletList(formattedList)
end

return p
--  </nowiki>