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

From Yugipedia
Jump to: navigation, search
(more small fixes)
(Don't know why this isn't working. Just taking shots in the dark now.)
 
(6 intermediate revisions by 2 users not shown)
Line 164: Line 164:
  
 
return difference
 
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
 
end
  
Line 210: 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
Line 215: Line 250:
 
-- Get a character's pronoun
 
-- Get a character's pronoun
 
-- @return string "he", "she", or "they"
 
-- @return string "he", "she", or "they"
function Character.getPronoun()
+
function Character:getPronoun()
if (gender == 'male')  then return 'he' end
+
local map = { ['male'] = 'he', ['female'] = 'she' }
if (gender == 'female') then return 'she' end
+
 
return 'they'
+
return map[self.gender] or 'they'
 
end
 
end
  
 
-- Get a character's objective pronoun
 
-- Get a character's objective pronoun
 
-- @return string "him", "her", or "them"
 
-- @return string "him", "her", or "them"
function Character.getObjectivePronoun()
+
function Character:getObjectivePronoun()
if (gender == 'male')  then return 'him' end
+
local map = { ['male'] = 'him', ['female'] = 'her' }
if (gender == 'female') then return 'her' end
+
 
return 'them'
+
return map[self.gender] or 'them'
 
end
 
end
  
Line 233: Line 268:
 
function Character:renderResponses()
 
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>'
 
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. '
+
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()) .. ' is willing to talk about that topic (maximum 5).</p>'
+
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')
+
local chart = mw.html.create('table'):attr('class', 'wikitable hlist sortable toggleable-columns-table')
  
 
local theadRow = chart:tag('tr')
 
local theadRow = chart:tag('tr')
Line 265: Line 301:
 
row:tag('td'):wikitext(response and response:renderItemList())
 
row:tag('td'):wikitext(response and response:renderItemList())
 
row:tag('td'):wikitext(response and response.message)
 
row:tag('td'):wikitext(response and response.message)
row:tag('td'):wikitext(renderEffect(group.trust[rating]) .. '%')
+
row:tag('td'):wikitext(renderTrustEffect(group.trust[rating]))
 
row:tag('td'):wikitext(renderEffect(group.mood[rating]))
 
row:tag('td'):wikitext(renderEffect(group.mood[rating]))
 
row:tag('td'):wikitext(renderEffect(group.card[rating]))
 
row:tag('td'):wikitext(renderEffect(group.card[rating]))
Line 300: Line 336:
 
-- @return string
 
-- @return string
 
function Response:renderItemList()
 
function Response:renderItemList()
local list = mw.html.create('ul'):attr('class', 'hlist')
+
local list = mw.html.create('ul')
  
 
for _, item in pairs(self.items) do
 
for _, item in pairs(self.items) do

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