Difference between revisions of "Module:Tag Force present responses"

From Yugipedia
Jump to: navigation, search
(Correction to what the "trust" values mean. Display it as the change in score and hover to see what that equates to in hearts.)
(Don't know why this isn't working. Just taking shots in the dark now.)
 
(2 intermediate revisions by the same user not shown)
Line 222: Line 222:
 
table.insert(self.responses, response)
 
table.insert(self.responses, response)
 
end
 
end
 +
end
 +
 +
self:setSmwData()
 +
end
 +
 +
-- Store Semantic MediaWiki data
 +
function Character:setSmwData()
 +
for _, response in pairs(self.responses) do
 +
-- Get an array of page names for each of the response's items
 +
local itemLinks = {}
 +
for _, item in pairs(response.items) do
 +
table.insert(itemLinks, getItemLink(item))
 +
end
 +
 +
-- Create a subobject for the response
 +
mw.smw.subobject({
 +
'Owner name    = ' .. self.name,
 +
'Game          = ' .. self.game,
 +
'Description    = ' .. response.message,
 +
'Numeric rating = ' .. response.rating,
 +
'Has items      = ' .. table.concat(itemLinks, '*'),
 +
'+sep=*'
 +
})
 
end
 
end
 
end
 
end

Latest revision as of 23:12, 3 May 2024

local InputParser = require('Module:Input parser')

-- Object for the character
-- (main object for this module)
--
-- @field pageName  string
-- @field name      string
-- @field gender    string    'male' or 'female' (needed for pronouns, otherwise will use they/them)
-- @field game      string
-- @field responses table<Response>
local Character = {
	pageName  = mw.title.getCurrentTitle().text,
	name      = nil,
	gender    = nil,
	game      = nil,
	responses = {}
}

-- Object for a response the character makes
-- (A character should have a response for each group-rating combination)
-- 
-- @field group   string        The name of the item group the response is to
-- @field rating  number        Number between 1 and 5
-- @field message string        What the character says when giving this reaction
-- @field items   table<string> The items that trigger this response
local Response = {
	group    = nil,
	rating   = nil,
	message  = nil,
	items    = nil,
}

-- Object for an item group
-- @field name    string
-- @field trust   table<number> Five numbers showing the effect each rating has on the "trust" score
-- @field mood    table<number> Five numbers showing the effect each rating has on the "mood" score
-- @field card    table<number> Five numbers showing the effect each rating has on the "card" score
-- @field dueling table<number> Five numbers showing the effect each rating has on the "dueling" score
-- @field them    table<number> Five numbers showing the effect each rating has on the "them" score
local Group = {
	name    = nil,
	trust   = {},
	mood    = {},
	card    = {},
	dueling = {},
	them    = {}
}

-- List of each group
local groups = {
	['duel'] = {
		name    = 'Duel',
		trust   = { -25,  -10, 5,   10, 25  },
		mood    = { -1.2, 0,   0.8, 1,  1.2 },
		card    = { 0,    1,   1,   2,  2   },
		dueling = { 3,    3,   4,   4,  5   },
		them    = { 0,    1,   1,   2,  2   }
	},
	['hobby'] = {
		name    = 'Hobby',
		trust   = { -25,  -10, 5,   10, 25  },
		mood    = { -1.2,  0,  0.8, 1,  1.2 },
		card    = { 3,     3,  4,   4,  5   },
		dueling = { 0,     1,  1,   2,  2   },
		them    = { 0,     1,  1,   2,  2   },
	},
	['sundry_goods'] = {
		name    = 'Sundry Goods',
		trust   = { -25,  -10, 5,   10, 25  },
		mood    = { -1.2,  0,  0.8, 1,  1.2 },
		card    = {   0,   1,  1,   2,  2   },
		dueling = {   0,   1,  1,   2,  2   },
		them    = {   3,   3,  4,   4,  5   },
	},
	['food'] = {
		name    = 'Food',
		trust   = { -0,   25,   50,  75,  100 },
		mood    = { -1.2,  0,   0,    0,  0   },
		card    = { -1,   -1,   0,    0,  0   },
		dueling = { -1,   -1,   0,    0,  0   },
		them    = { -1,   -1,   0,    0,  0   },
	},
	['figures'] = {
		name    = 'Figures',
		trust   = { -50, -25, 0,   5,  10  },
		mood    = { 0.5, 1,   1.5, 2,  2.5 },
		card    = { -2,  -1,  0,   0,  0   },
		dueling = { -2,  -1,  0,   0,  0   },
		them    = { -2,  -1,  0,   0,  0   },
		messageGroup = 'hobby'
	}
}

-- Normalize input
--
-- @param table args
-- @return table
local function normalizeArgs(args)
	local normalizedArgs = {}

	-- If a parameter just contains whitespace, ignore it
	for param, value in pairs(args or {}) do
	    if (value and mw.text.trim(value) ~= '') then
	    	normalizedArgs[param] = value
	    end
	end

	return normalizedArgs
end

-- Get the page name for a given item
--
-- @param name string The name of the item
-- @return string
local function getItemLink(name)
	-- Map names to page names for items where the two are different
	local map = {
		['Amplifier']                    = 'Amplifier (Tag Force item)',
		['Atlas Rising']                 = 'Atlas Rising (Tag Force item)',
		['Bandanna']                     = 'Bandanna (5D\'s Tag Force)',
		['Bat']                          = 'Bat (item)',
		['Beef Bowl']                    = 'Beef Bowl (item)',
		['Card Ejector Figure']          = 'Card Ejector Figure (Tag Force)',
		['Cyber Tutu Figure']            = 'Cyber Tutu Figure (Tag Force)',
		['Dark Magician Girl Figure']    = 'Dark Magician Girl Figure (Tag Force)',
		['Death Match Duel Rope']        = 'Death Match Duel Rope (Tag Force)',
		['Duel Calculator']              = 'Duel Calculator (Tag Force)',
		['Ebon Magician Curran Figure']  = 'Ebon Magician Curran Figure (Tag Force)',
		['Gold Coin']                    = 'Gold Coin (item)',
		['Junk']                         = 'Junk (item)',
		['Red Dragon Archfiend Figure']  = 'Red Dragon Archfiend Figure (Tag Force)',
		['Sandwich (Green)']             = 'Sandwich (5D\'s Tag Force Green)',
		['Sandwich (Gold)']              = 'Sandwich (5D\'s Tag Force Gold)',
		['Tea']                          = 'Tea (item)',
		['The Daily Duel']               = 'The Daily Duel (Tag Force)',
		['Toothbush']                    = 'Toothbush (Tag Force)',
		['Water']                        = 'Water (item)',
		['White Magician Pikeru Figure'] = 'White Magician Pikeru Figure (Tag Force)',
	}

	-- Get the page name from the map
	-- If it's not in the map, use the item name as the page name
	return map[name] or name
end

-- Get the color for a given rating
-- (The higher the number, the more green. The lower the number, the more red)
--
-- @param rating number Integer between 1 and 5
-- @return string       HSL color string
local function getRatingColor(rating)
	return 'hsl(' .. ((rating - 1) * 30) .. 'deg, 100%, 75%)'
end

-- Render an effect for displaying
-- (Basically add a "+" before positive numbers. Negative numbers already have a "-")
--
-- @param difference number
-- @return {string|number}
local function renderEffect(difference)
	if (difference > 0) then
		return '+' .. difference
	end

	return difference
end

-- Render a "trust" effect for displaying
-- (Shows how much the score increases/decreases by. Hover to see what percentage of a heart that equates to.)
--
-- @param difference number
-- @return {string|number}
local function renderTrustEffect(difference)
	local diff      = renderEffect(difference)
	local heartDiff = renderEffect(difference / 10) .. '%'

	return '<abbr title="' .. heartDiff .. ' of a heart">' .. diff .. '</abbr>'
end

-- Create a new instance of the `Character` object
--
-- @param args table
-- @return Character
function Character:new(args)
	local character = mw.clone(Character)
	character:setData(args)
	return character
end

-- Populate character attributes based on input
--
-- @param args table
function Character:setData(args)
	args = normalizeArgs(args)

	-- If name isn't specified, default to the page name, without parenthetical text
	self.name      = args['character_name'] or mw.text.split(self.pageName, ' %(')[1]
	self.game      = args['game']
	self.gender    = args['gender'] and args['gender']:lower()
	self.responses = {}
	
	local groupNames = { 'duel', 'hobby', 'figures', 'sundry_goods', 'food' }
	
	-- Loop through each group and rating combination
	for _, groupName in pairs(groupNames) do
		for rating = 5, 1, -1 do
			local group = groups[groupName]

			-- Create a response for each combination
			-- And fill with data from input params
			local response = Response:new()

			-- If a group shares its messages with another group
			-- ("Figures" uses the same messages as "Hobby")
			local messageGroup = group.messageGroup or groupName

			response.group    = groupName
			response.rating   = rating
			response.message  = args[messageGroup .. '_' .. rating .. '_response']
			response.items    = InputParser.ulToArray(args[groupName    .. '_' .. rating .. '_items'])

			table.insert(self.responses, response)
		end
	end

	self:setSmwData()
end

-- Store Semantic MediaWiki data
function Character:setSmwData()
	for _, response in pairs(self.responses) do
		-- Get an array of page names for each of the response's items
		local itemLinks = {}
		for _, item in pairs(response.items) do
			table.insert(itemLinks, getItemLink(item))
		end

		-- Create a subobject for the response
		mw.smw.subobject({
			'Owner name     = ' .. self.name,
			'Game           = ' .. self.game,
			'Description    = ' .. response.message,
			'Numeric rating = ' .. response.rating,
			'Has items      = ' .. table.concat(itemLinks, '*'),
			'+sep=*'
		})
	end
end

-- Get a character's pronoun
-- @return string "he", "she", or "they"
function Character:getPronoun()
	local map = { ['male'] = 'he', ['female'] = 'she' }

	return map[self.gender] or 'they'
end

-- Get a character's objective pronoun
-- @return string "him", "her", or "them"
function Character:getObjectivePronoun()
	local map = { ['male'] = 'him', ['female'] = 'her' }

	return map[self.gender] or 'them'
end

-- Render all the information as wikitext
-- @return string
function Character:renderResponses()
	local intro = '<p>In <i>[[' .. self.game .. ']]</i>, ' .. (self.name) .. ' has the following responses when the player gives ' .. (self:getObjectivePronoun()) .. ' a present.</p>'
	intro = intro .. '<p>The "Trust" column shows how much of a heart the present will increase in the level of trust by. '
	intro = intro .. 'The "Card", "Dueling", and "Them" columns show the effect it has on how many more times ' .. (self:getPronoun())
	intro = intro .. (self:getPronoun() == 'they' and ' are' or ' is') ..' willing to talk about that topic (maximum 5).</p>'

	local chart = mw.html.create('table'):attr('class', 'wikitable hlist sortable toggleable-columns-table')

	local theadRow = chart:tag('tr')
	theadRow:tag('th'):attr('scope', 'col'):tag('abbr'):attr('title', 'Rating'):wikitext('★')
	theadRow:tag('th'):attr('data-col-group', 'Group'):wikitext('Group')
	theadRow:tag('th'):attr('data-col-group', 'Items'):wikitext('Items')
	theadRow:tag('th'):attr('data-col-group', 'Response'):wikitext('Response')
	theadRow:tag('th'):attr('data-col-group', 'Effects'):wikitext('Trust')
	theadRow:tag('th'):attr('data-col-group', 'Effects'):wikitext('Mood')
	theadRow:tag('th'):attr('data-col-group', 'Effects'):wikitext('Card')
	theadRow:tag('th'):attr('data-col-group', 'Effects'):wikitext('Dueling')
	theadRow:tag('th'):attr('data-col-group', 'Effects'):wikitext('Them')
	
	local groupNames = { 'duel', 'hobby', 'figures', 'sundry_goods', 'food' }

	for rating = 5, 1, -1 do
		for groupNumber, groupName in pairs(groupNames) do
			local group = groups[groupName]
			local response = self:getResponse(groupName, rating)

			local row = chart:tag('tr')

			if groupNumber == 1 then
				row:tag('td'):attr('rowspan', 5):css('background-color', getRatingColor(rating)):css('color', '#000'):css('text-align', 'center'):wikitext(rating)
			end

			row:tag('td'):wikitext(group.name)
			row:tag('td'):wikitext(response and response:renderItemList())
			row:tag('td'):wikitext(response and response.message)
			row:tag('td'):wikitext(renderTrustEffect(group.trust[rating]))
			row:tag('td'):wikitext(renderEffect(group.mood[rating]))
			row:tag('td'):wikitext(renderEffect(group.card[rating]))
			row:tag('td'):wikitext(renderEffect(group.dueling[rating]))
			row:tag('td'):wikitext(renderEffect(group.them[rating]))
		end
	end

	return intro .. tostring(chart)
end

-- Get a particular response
--
-- @field groupName string  The group that the response is for
-- @field rating    number  The rating from 1 to 5 the character is giving
function Character:getResponse(groupName, rating)
	-- Loop through all responses
	for _, response in pairs(self.responses) do
		-- Stop on the one with the matching group and rating
		if (response.rating == rating and response.group == groupName) then
			return response
		end
	end
end

-- Create a new instance of a `Response` object
-- @return Response
function Response:new(args)
	local r = mw.clone(Response)
	return r
end

-- Render a response's items as a list in wikitext
-- @return string
function Response:renderItemList()
	local list = mw.html.create('ul')

	for _, item in pairs(self.items) do
		local link = getItemLink(item)
		list:tag('li'):wikitext('[[' .. link .. '|' .. item .. ']]')
	end

	return tostring(list)
end

-- The main method that gets invoked by templates
-- @return string
function Character.main(frame)
	-- `frame:getParent().args` should get the template parameters
	-- Default to just `frame`, so the params can be passed directly when debugging
	local args = frame.getParent and frame:getParent().args or frame

	-- Create instance of the character
	local character = Character:new(args)

	-- Render responses for the character
	return tostring(character:renderResponses())
end

return Character