Marvel Database
No edit summary
(updated version for portable infoboxes)
Line 3: Line 3:
 
local getArgs = require('Module:Arguments').getArgs
 
local getArgs = require('Module:Arguments').getArgs
 
local h = require("Module:HF")
 
local h = require("Module:HF")
local design = require('Module:Design')
+
local design = require('Module:Design/Sandbox')
 
local standard = require("Module:StandardizedName")
 
local standard = require("Module:StandardizedName")
 
local units = require('Module:Units')
 
local units = require('Module:Units')
Line 15: Line 15:
 
local categories = {}
 
local categories = {}
 
local output_categories = {}
 
local output_categories = {}
local output_infobox = {}
 
 
local output = {}
 
local output = {}
   
 
table.insert(output, '{{DEFAULTSORT:'..standard.name_for_sorting({pagename})..'|noerror}}')
 
table.insert(output, '{{DEFAULTSORT:'..standard.name_for_sorting({pagename})..'|noerror}}')
 
table.insert(output_categories, 'Characters')
 
table.insert(output_categories, 'Characters')
-- infobox
 
value, categories = design.add_infobox_page_title_and_image(args, pagename, page_type)
 
output_categories = h.join_tables(output_categories, categories)
 
table.insert(output_infobox, value)
 
 
table.insert(output_infobox, design.add_infobox_official_name(args, page_type) )
 
 
value = args.CurrentAlias
 
if not h.isempty(value) and not h.isempty(args.CurrentAliasRef)
 
then value = value..args.CurrentAliasRef
 
end
 
table.insert(output_infobox, design.add_infobox_row('Current Alias', value) )
 
 
table.insert(output_infobox, design.add_infobox_row_collapsible('Aliases', args.Aliases) )
 
table.insert(output_infobox, design.add_infobox_row_collapsible('Editorial Names', args.EditorialNames) )
 
 
table.insert(output_infobox, design.add_infobox_row_collapsible('Relatives', args.Relatives, true) )
 
table.insert(output_infobox, design.add_infobox_row_collapsible('Affiliation', args.Affiliation, true) )
 
table.insert(output_infobox, design.add_infobox_row_collapsible('Base of Operations', args.BaseOfOperations, true) )
 
 
value, categories = p.group_status(args)
 
output_categories = h.join_tables(output_categories, categories)
 
table.insert(output_infobox, value)
 
 
value, categories = p.group_characteristics(args)
 
output_categories = h.join_tables(output_categories, categories)
 
table.insert(output_infobox, value)
 
 
value, categories = p.group_origin(args, pagename)
 
output_categories = h.join_tables(output_categories, categories)
 
table.insert(output_infobox, value)
 
 
value, categories = design.add_infobox_appearances_and_creators(args, page_type)
 
output_categories = h.join_tables(output_categories, categories)
 
table.insert(output_infobox, value)
 
 
 
table.insert(output_categories, p.lua_get_outdated_fields(args) )
 
table.insert(output_categories, p.lua_get_outdated_fields(args) )
   
Line 116: Line 79:
 
table.insert( output, design.add_links_and_references(args, pagename) )
 
table.insert( output, design.add_links_and_references(args, pagename) )
 
--
 
--
output_infobox = design.create_infobox( table.concat(output_infobox) )
 
 
output_categories = h.add_categories(output_categories)
 
output_categories = h.add_categories(output_categories)
 
output = table.concat(output)
 
output = table.concat(output)
 
 
return frame:preprocess(output_infobox..output)..output_categories
+
return frame:preprocess(output)..output_categories
 
end
 
end
   
Line 146: Line 108:
 
or not h.isempty(args.Citizenship2) -- temporarily, to correctly put all citizenships into "Citizenship" field
 
or not h.isempty(args.Citizenship2) -- temporarily, to correctly put all citizenships into "Citizenship" field
 
or not h.isempty(args.UnusualSkinColour2)
 
or not h.isempty(args.UnusualSkinColour2)
  +
or not h.isempty(args.MaritalStatus2)
 
or not h.isempty(args.PowersAbilitiesHeader)
 
or not h.isempty(args.PowersAbilitiesHeader)
 
or not h.isempty(args.ParaphernaliaHeader)
 
or not h.isempty(args.ParaphernaliaHeader)
Line 159: Line 122:
   
 
--------------------------------------------------------------------------------------------------
 
--------------------------------------------------------------------------------------------------
function p.get_cause_of_death(args)
+
function p.get_current_alias(frame)
  +
local args = getArgs (frame)
  +
local value = args.CurrentAlias
  +
local ref = args.CurrentAliasRef or ''
  +
  +
return value..ref
  +
end
  +
  +
  +
--------------------------------------------------------------------------------------------------
  +
function p.get_aliases(frame)
  +
local args = getArgs (frame)
  +
local list = {args.Codenames, args.EditorialNames, args.Nicknames, args.Impersonations, args.Aliases}
  +
local labels = {'Codenames', 'Editorial Names', 'Nicknames', 'Impersonations', 'Other Aliases'}
  +
local i
  +
local output = {}
  +
  +
for i = 1, 5 do
  +
if not h.isempty(list[i])
  +
then
  +
if labels[i] == 'Other Aliases' and table.concat(output) == ''
  +
then table.insert(output, list[i])
  +
else table.insert(output, design.span(labels[i]..':').bold..'<br>'..list[i])
  +
end
  +
end
  +
end
  +
output = mw.text.listToText(output, '<br>', '<br>')
  +
  +
return output
  +
end
  +
  +
  +
--------------------------------------------------------------------------------------------------
  +
function p.get_relatives(frame)
  +
local args = getArgs (frame)
  +
local list = {args.Ancestors, args.Grandparents, args.Parents, args.Siblings, args.Spouses, args.Children, args.Descendants, args.Relatives}
  +
local labels = {'Ancestors', 'Grandparents', 'Parents', 'Siblings', 'Spouses', 'Children', 'Descendants', 'Other Relatives'}
  +
local i
  +
local output = {}
  +
  +
for i = 1, 8 do
  +
if not h.isempty(list[i])
  +
then
  +
if labels[i] == 'Other Relatives' and table.concat(output) == ''
  +
then table.insert(output, list[i])
  +
else table.insert(output, design.span(labels[i]..':').bold..'<br>'..list[i])
  +
end
  +
end
  +
end
  +
output = mw.text.listToText(output, '<br>', '<br>')
  +
  +
return design.add_infobox_row_collapsible({output})
  +
end
  +
  +
  +
--------------------------------------------------------------------------------------------------
  +
function p.get_living_status(frame)
  +
local args = getArgs (frame)
  +
local living_status = args.Status
  +
local output_categories = {}
  +
local output = ''
  +
  +
if not h.isempty(args.Death)
  +
then
  +
table.insert(output_categories, 'Deceased Characters')
  +
output = h.LinkToCategory('Deceased Characters', 'Deceased')
  +
else
  +
table.insert(output_categories, 'Living Characters')
  +
output = h.LinkToCategory('Living Characters', 'Alive')
  +
if not h.isempty( p.get_cause_of_death(frame) )
  +
then
  +
output = output..'; '..h.LinkToCategory('Formerly Deceased', 'formerly deceased')
  +
table.insert(output_categories, 'Formerly Deceased')
  +
end
  +
end
  +
if not h.isempty(living_status)
  +
then output = output..' '..living_status
  +
end
  +
  +
return output
  +
end
  +
  +
  +
--------------------------------------------------------------------------------------------------
  +
function p.get_cause_of_death(frame)
  +
local args = getArgs (frame)
 
local killed = args.KilledBy
 
local killed = args.KilledBy
 
local casualty = args.CasualtyOf
 
local casualty = args.CasualtyOf
Line 204: Line 252:
 
end
 
end
   
return output, output_categories
+
return output..h.add_categories(output_categories)
 
end
 
end
   
   
 
--------------------------------------------------------------------------------------------------
 
--------------------------------------------------------------------------------------------------
function p.get_citizenship(args)
+
function p.get_marital_status(frame)
  +
local function get_value_and_remainder(value)
  +
local i
  +
local remainder = ''
  +
  +
i = string.find(value, ' ')
  +
if i ~= nil
  +
then
  +
remainder = ' '..string.sub(value, i+1, #value)
  +
value = string.sub(value, 1, i-1)
  +
end
  +
  +
return value, remainder
  +
end
  +
local args = getArgs (frame)
  +
local value = args.MaritalStatus
  +
local value2 = args.MaritalStatus2
  +
local list = {'Married', 'Divorced', 'Engaged', 'Separated', 'Single', 'Widowed'}
  +
local l = {}
  +
local output_categories = {}
  +
local output = {}
  +
  +
if not h.isempty(value)
  +
then
  +
output = {}
  +
l = h.explode(';', value)
  +
for i = 1, #l do
  +
value, remainder = get_value_and_remainder(h.trim(l[i]))
  +
if h.in_list(list, value)
  +
then
  +
table.insert(output, h.LinkToCategory(value..' Characters', value)..remainder )
  +
table.insert(output_categories, value..' Characters')
  +
else
  +
table.insert(output, h.LinkToCategory('Marital Status Needing Correction', value) )
  +
end
  +
end
  +
output = mw.text.listToText(output, ',<br>', ',<br>')
  +
end
  +
  +
--if not h.isempty(value2)
  +
-- then table.insert(output, ' '..value2)
  +
--end
  +
  +
return output..h.add_categories(output_categories)
  +
end
  +
  +
  +
--------------------------------------------------------------------------------------------------
  +
function p.get_occupation(frame)
  +
local args = getArgs (frame)
  +
local value = args.Occupation
  +
local occupations = require('Module:CharacterInfoboxOccupation')
  +
local output_categories = {}
  +
local output = ''
  +
  +
if not h.isempty(value)
  +
then
  +
for key, v in pairs(occupations) do
  +
if string.find( string.lower(value), key ) ~= nil
  +
then
  +
for i, category in ipairs(v) do
  +
table.insert(output_categories, category)
  +
end
  +
end
  +
end
  +
output = value
  +
end
  +
  +
return design.add_infobox_row_collapsible({value})..h.add_categories(output_categories)
  +
end
  +
  +
  +
--------------------------------------------------------------------------------------------------
  +
function p.get_citizenship(frame)
  +
local args = getArgs (frame)
 
local citizenship = require('Module:Citizenship')
 
local citizenship = require('Module:Citizenship')
 
local value1 = args.Citizenship
 
local value1 = args.Citizenship
Line 248: Line 370:
 
 
 
if not h.isempty(value2)
 
if not h.isempty(value2)
  +
then output = output..' '..value2
then
 
output = output..' '..value2
 
 
end
 
end
   
return output, output_categories
+
return output..h.add_categories(output_categories)
end
 
 
 
--------------------------------------------------------------------------------------------------
 
function p.get_marital_status(value, value2)
 
local list = {'Married', 'Divorced', 'Engaged', 'Separated', 'Single', 'Widowed'}
 
local output_categories = {}
 
local output = {}
 
 
if not h.isempty(value)
 
then
 
if h.in_list(list, value)
 
then
 
table.insert(output, h.LinkToCategory(value..' Characters', value) )
 
table.insert(output_categories, value..' Characters')
 
else
 
table.insert(output, h.LinkToCategory('Marital Status Needing Correction', value) )
 
end
 
end
 
 
if not h.isempty(value2)
 
then table.insert(output, ' '..value2)
 
end
 
 
return table.concat(output), output_categories
 
end
 
 
 
--------------------------------------------------------------------------------------------------
 
function p.get_occupation(value)
 
local occupations = require('Module:CharacterInfoboxOccupation')
 
local output_categories = {}
 
local output = ''
 
 
if not h.isempty(value)
 
then
 
for key, v in pairs(occupations) do
 
if string.find( string.lower(value), key ) ~= nil
 
then
 
for i, category in ipairs(v) do
 
table.insert(output_categories, category)
 
end
 
end
 
end
 
output = value
 
end
 
 
return output, output_categories
 
 
end
 
end
   
Line 338: Line 411:
   
 
--------------------------------------------------------------------------------------------------
 
--------------------------------------------------------------------------------------------------
function p.get_weight(value, value2)
+
function p.get_weight(frame)
 
local function lbs_to_kg(weightLbs)
 
local function lbs_to_kg(weightLbs)
 
return h.round(weightLbs * units['lbs'].kg, 2)
 
return h.round(weightLbs * units['lbs'].kg, 2)
Line 372: Line 445:
 
return output
 
return output
 
end
 
end
  +
local args = getArgs (frame)
  +
local value = args.Weight
  +
--local value2 = args.Weight2
 
local weight
 
local weight
 
local weightLbs = 0
 
local weightLbs = 0
Line 413: Line 489:
 
end
 
end
   
if not h.isempty(value2)
+
--if not h.isempty(value2)
then output = output.." " ..value2
+
-- then output = output.." " ..value2
end
+
--end
   
return output, output_categories
+
return output..h.add_categories(output_categories)
 
end
 
end
   
Line 469: Line 545:
   
 
--------------------------------------------------------------------------------------------------
 
--------------------------------------------------------------------------------------------------
function p.get_height(value, value2)
+
function p.get_height(frame)
 
local function ft_to_m(heightFt)
 
local function ft_to_m(heightFt)
 
return tonumber( string.format("%.2f", heightFt * units['ft'].m) )
 
return tonumber( string.format("%.2f", heightFt * units['ft'].m) )
Line 497: Line 573:
 
return output
 
return output
 
end
 
end
  +
local args = getArgs (frame)
  +
local value = args.Height
  +
local value2 = args.Height2
 
local height
 
local height
 
local height_ft
 
local height_ft
Line 528: Line 607:
 
end
 
end
   
if not h.isempty(value2)
+
--if not h.isempty(value2)
then output = output.." " ..value2
+
-- then output = output.." " ..value2
end
+
--end
   
return output, output_categories
+
return output..h.add_categories(output_categories)
 
end
 
end
   
   
 
--------------------------------------------------------------------------------------------------
 
--------------------------------------------------------------------------------------------------
function p.get_eyes(eyes1, eyes2, eyeballs)
+
function p.get_eyes(frame)
 
local function eyeballs_color(value)
 
local function eyeballs_color(value)
 
local category = ''
 
local category = ''
Line 597: Line 676:
 
return value, remainder
 
return value, remainder
 
end
 
end
  +
local args = getArgs (frame)
  +
local eyes = args.Eyes
  +
local eyes2 = args.Eyes2
  +
local eyeballs = args.Eyeballs
 
local list = {}
 
local list = {}
 
local category = ''
 
local category = ''
Line 605: Line 688:
 
local output = ''
 
local output = ''
 
 
if not h.isempty(eyes1)
+
if not h.isempty(eyes)
 
then
 
then
list = h.explode(';', eyes1)
+
list = h.explode(';', eyes)
eyes1 = {}
+
eyes = {}
 
for i = 1, #list do
 
for i = 1, #list do
 
value, remainder = get_value_and_remainder(h.trim(list[i]))
 
value, remainder = get_value_and_remainder(h.trim(list[i]))
 
value, category = iris_color(value)
 
value, category = iris_color(value)
 
table.insert(output_categories, category)
 
table.insert(output_categories, category)
table.insert(eyes1, '\n* '..value..remainder)
+
table.insert(eyes, '\n* '..value..remainder)
 
end
 
end
eyes1 = mw.text.listToText(eyes1, '', '')
+
eyes = mw.text.listToText(eyes, '', '')
if not h.isempty(eyes2)
+
--if not h.isempty(eyes2)
then eyes1 = eyes1..' '..eyes2
+
-- then eyes = eyes..' '..eyes2
end
+
--end
output = '\n'..design.span('Irises:').bold..eyes1
+
output = '\n'..design.span('Irises:').bold..eyes
 
end
 
end
   
Line 636: Line 719:
 
end
 
end
   
return output, output_categories
+
return output..h.add_categories(output_categories)
 
end
 
end
   
   
 
--------------------------------------------------------------------------------------------------
 
--------------------------------------------------------------------------------------------------
function p.get_hair(hair, hair2)
+
function p.get_hair(frame)
 
local function get_value_and_remainder(value)
 
local function get_value_and_remainder(value)
 
local exceptions_list = {'light brown', 'platinum blond', 'strawberry blond', 'no hair'}
 
local exceptions_list = {'light brown', 'platinum blond', 'strawberry blond', 'no hair'}
Line 708: Line 791:
 
return output, output_categories
 
return output, output_categories
 
end
 
end
  +
local args = getArgs (frame)
  +
local hair = args.Hair
  +
local hair2 = args.Hair2
 
local category = ''
 
local category = ''
 
local value
 
local value
Line 729: Line 815:
 
output = mw.text.listToText(output, ',<br>', ',<br>')
 
output = mw.text.listToText(output, ',<br>', ',<br>')
 
end
 
end
if not h.isempty(hair2)
+
--if not h.isempty(hair2)
then output = output..' '..hair2
+
-- then output = output..' '..hair2
end
+
--end
 
 
return output, output_categories
+
return output..h.add_categories(output_categories)
 
end
 
end
   
   
 
--------------------------------------------------------------------------------------------------
 
--------------------------------------------------------------------------------------------------
function p.get_skin(skin, skin2)
+
function p.get_skin(frame)
 
local function get_value_and_remainder(value)
 
local function get_value_and_remainder(value)
 
local exceptions_list = {'light green', 'green, yellow', 'no skin'}
 
local exceptions_list = {'light green', 'green, yellow', 'no skin'}
Line 788: Line 874:
 
return output, output_categories
 
return output, output_categories
 
end
 
end
  +
local args = getArgs (frame)
  +
local skin = args.UnusualSkinColour
  +
--local skin2 = args.UnusualSkinColour2
 
local category = ''
 
local category = ''
 
local value
 
local value
Line 808: Line 897:
 
output = mw.text.listToText(output, ',<br>', ',<br>')
 
output = mw.text.listToText(output, ',<br>', ',<br>')
 
end
 
end
if not h.isempty(skin2)
+
--if not h.isempty(skin2)
then output = output..' '..skin2
+
-- then output = output..' '..skin2
end
+
--end
 
 
return output, output_categories
+
return output..h.add_categories(output_categories)
 
end
 
end
   
   
 
--------------------------------------------------------------------------------------------------
 
--------------------------------------------------------------------------------------------------
function p.get_gender(gender, gender2)
+
function p.get_gender(frame)
 
local function get_value_and_remainder(value)
 
local function get_value_and_remainder(value)
 
local i
 
local i
Line 846: Line 935:
 
return output, output_categories
 
return output, output_categories
 
end
 
end
  +
local args = getArgs (frame)
  +
local gender = args.Gender
  +
--local gender2 = args.Gender2
 
local category = ''
 
local category = ''
 
local value
 
local value
Line 866: Line 958:
 
output = mw.text.listToText(output, ',<br>', ',<br>')
 
output = mw.text.listToText(output, ',<br>', ',<br>')
 
end
 
end
if not h.isempty(gender2)
+
--if not h.isempty(gender2)
then output = output..' '..gender2
+
-- then output = output..' '..gender2
end
+
--end
  +
  +
return output..h.add_categories(output_categories)
  +
end
  +
  +
  +
--------------------------------------------------------------------------------------------------
  +
function p.get_unusual_features(frame)
  +
local args = getArgs (frame)
  +
local value = args.UnusualFeatures
  +
local list = require('Module:CharacterInfoboxUnusualFeatures')
  +
local output_categories = p.get_categories_from_keywords(value, list.valid, list.exceptions)
 
 
return output, output_categories
+
return value..h.add_categories(output_categories)
 
end
 
end
   
   
 
--------------------------------------------------------------------------------------------------
 
--------------------------------------------------------------------------------------------------
  +
function p.get_ctry(frame)
function p.get_categories_from_keywords(value, valid, exceptions)
 
  +
local substitutes = require('Module:CharacterInfoboxCtry')
local output = {}
 
  +
local args = getArgs (frame)
 
  +
local value = args[1]
if not h.isempty(value) -- Field isn't blank
 
  +
local output = ''
then -- Grab a valid pair and use it
 
  +
for validKey, validValue in pairs(valid) do
 
  +
if not h.isempty(value)
-- If you find the validKey in the field, and there are no exceptions for this validKey, then categorize
 
  +
then
if string.find(string.lower(value), validKey) ~= nil and type(exceptions[validKey]) ~= "table"
 
then
+
output = value
  +
if string.find(value, "%[%[.+%]%]") == nil
for valueKey, valueCategoryName in ipairs( validValue ) do
 
  +
then
table.insert(output, valueCategoryName)
 
  +
if type(substitutes[value]) == "string"
end
 
  +
then output = h.Link(substitutes[value])
end
 
  +
end
 
end
 
end
 
end
 
end
  +
 
return output
 
return output
 
end
 
end
   
   
-- ********************* GROUPS *********************
 
 
--------------------------------------------------------------------------------------------------
 
--------------------------------------------------------------------------------------------------
function p.group_status(args)
+
function p.get_origin(frame)
local header = 'Status'
+
local args = getArgs (frame)
  +
local list = require('Module:CharacterInfoboxOrigins')
local living_status = args.Status
 
local cause_of_death
+
local value = args.Origin
local value
+
local output = ''
local category
 
local output_categories = {}
 
local output = {}
 
 
-- living status
 
cause_of_death, category = p.get_cause_of_death(args)
 
 
if not h.isempty(args.Death) --or living_status == 'Dead'
 
then
 
table.insert(output_categories, 'Deceased Characters')
 
value = h.LinkToCategory('Deceased Characters', 'Deceased')
 
else
 
table.insert(output_categories, 'Living Characters')
 
value = h.LinkToCategory('Living Characters', 'Alive')
 
if not h.isempty(cause_of_death)
 
then
 
value = value..'; '..h.LinkToCategory('Formerly Deceased', 'formerly deceased')
 
table.insert(output_categories, 'Formerly Deceased')
 
end
 
end
 
if not h.isempty(living_status)
 
then value = value..' '..living_status
 
end
 
table.insert(output, design.add_infobox_row('Living Status', value) )
 
output_categories = h.join_tables(output_categories, category)
 
table.insert(output, design.add_infobox_row_collapsible('Cause of Death', cause_of_death) )
 
 
 
-- identity
 
value = args.Identity
 
 
if not h.isempty(value)
 
if not h.isempty(value)
 
then
 
then
  +
output = p.get_categories_from_keywords(value, list.valid, list.exceptions)
category = value..' Identity Characters'
 
  +
output = value..h.add_categories(output)
table.insert(output_categories, category)
 
value = h.LinkToCategory(category, value)
 
 
end
 
end
if not h.isempty(args.Identity2)
 
then value = value..' '..args.Identity2
 
end
 
table.insert(output, design.add_infobox_row('Identity', value) )
 
--
 
value, category = p.get_citizenship(args)
 
output_categories = h.join_tables(output_categories, category)
 
table.insert(output, design.add_infobox_row('Citizenship', value) )
 
 
 
  +
return output
value, category = p.get_marital_status(args.MaritalStatus, args.MaritalStatus2)
 
  +
end
output_categories = h.join_tables(output_categories, category)
 
table.insert(output, design.add_infobox_row('Marital Status', value) )
 
 
value, category = p.get_occupation(args.Occupation)
 
output_categories = h.join_tables(output_categories, category)
 
table.insert(output, design.add_infobox_row_collapsible('Occupation', value) )
 
   
table.insert(output, design.add_infobox_row('Education', args.Education) )
 
 
return design.add_infobox_group(output, header), output_categories
 
end
 
   
 
--------------------------------------------------------------------------------------------------
 
--------------------------------------------------------------------------------------------------
  +
function p.get_categories_from_keywords(value, valid, exceptions)
function p.group_characteristics(args)
 
local header = 'Characteristics'
 
local value
 
local category
 
local output_categories = {}
 
 
local output = {}
 
local output = {}
 
value = args.CharRef
 
if not h.isempty(value)
 
then header = header..'<ref>'..value..'</ref>'
 
end
 
-- gender
 
value, category = p.get_gender(args.Gender, args.Gender2)
 
output_categories = h.join_tables(output_categories, category)
 
table.insert(output, design.add_infobox_row('Gender', value) )
 
-- weight
 
value, category = p.get_weight(args.Weight, args.Weight2)
 
output_categories = h.join_tables(output_categories, category)
 
table.insert(output, design.add_infobox_row('Weight', value) )
 
-- height
 
value, category = p.get_height(args.Height, args.Height2)
 
output_categories = h.join_tables(output_categories, category)
 
table.insert(output, design.add_infobox_row('Height', value) )
 
-- eyes
 
value, category = p.get_eyes(args.Eyes, args.Eyes2, args.Eyeballs)
 
output_categories = h.join_tables(output_categories, category)
 
table.insert(output, design.add_infobox_row('Eyes', value) )
 
-- hair
 
value, category = p.get_hair(args.Hair, args.Hair2)
 
output_categories = h.join_tables(output_categories, category)
 
table.insert(output, design.add_infobox_row('Hair', value) )
 
-- skin
 
value, category = p.get_skin(args.UnusualSkinColour, args.UnusualSkinColour2)
 
output_categories = h.join_tables(output_categories, category)
 
table.insert(output, design.add_infobox_row('Unusual Skin Color', value) )
 
-- unusual features
 
value = require('Module:CharacterInfoboxUnusualFeatures')
 
category = p.get_categories_from_keywords(args.UnusualFeatures, value.valid, value.exceptions)
 
output_categories = h.join_tables(output_categories, category)
 
table.insert(output, design.add_infobox_row('Unusual Features', args.UnusualFeatures) )
 
   
  +
if not h.isempty(value) -- Field isn't blank
return design.add_infobox_group(output, header), output_categories
 
  +
then -- Grab a valid pair and use it
end
 
  +
for validKey, validValue in pairs(valid) do
 
  +
-- If you find the validKey in the field, and there are no exceptions for this validKey, then categorize
 
  +
if string.find(string.lower(value), validKey) ~= nil and type(exceptions[validKey]) ~= "table"
--------------------------------------------------------------------------------------------------
 
  +
then
function p.group_origin(args, pagename)
 
  +
for valueKey, valueCategoryName in ipairs( validValue ) do
local function ctry(value)
 
  +
table.insert(output, valueCategoryName)
local substitutes = require('Module:CharacterInfoboxCtry')
 
local output = ''
 
if not h.isempty(value)
 
then
 
output = value
 
if string.find(value, "%[%[.+%]%]") == nil
 
then
 
if type(substitutes[value]) == "string"
 
then output = h.Link(substitutes[value])
 
 
end
 
end
 
end
 
end
end
+
end
return output
 
 
end
 
end
  +
return output
local value
 
local categories
 
local output_categories = {}
 
local output = {}
 
 
value = require('Module:CharacterInfoboxOrigins')
 
category = p.get_categories_from_keywords(args.Origin, value.valid, value.exceptions)
 
output_categories = h.join_tables(output_categories, category)
 
table.insert(output, design.add_infobox_row('Origin', args.Origin) )
 
 
value, categories = design.add_infobox_reality(args, pagename, '/Characters')
 
output_categories = h.join_tables(output_categories, categories)
 
table.insert(output, value)
 
 
table.insert(output, design.add_infobox_row('Place of Birth', ctry(args.PlaceOfBirth) ) )
 
table.insert(output, design.add_infobox_row('Place of Creation', ctry(args.PlaceOfCreation) ) )
 
table.insert(output, design.add_infobox_row('Place of Death', ctry(args.PlaceOfDeath) ) )
 
table.insert(output, design.add_infobox_row('Place of Destruction', ctry(args.PlaceOfDestruction) ) )
 
 
return design.add_infobox_group(output, 'Origin'), output_categories
 
 
end
 
end
 
   
 
return p
 
return p

Revision as of 12:52, 15 May 2021

Documentation for this module may be created at Module:Character Template/doc

-- module for Marvel Database:Character Template
local p = {}
local getArgs = require('Module:Arguments').getArgs 
local h = require("Module:HF")
local design = require('Module:Design/Sandbox')
local standard = require("Module:StandardizedName")
local units  = require('Module:Units')	
local list_of_power_grids = mw.loadData('Module:Power Grid/List')

function p.main(frame)
	local args = getArgs(frame)
	local pagename = mw.title.getCurrentTitle().text
	local page_type = 'Character'
	local value
	local categories = {}
	local output_categories = {}
	local output = {}

	table.insert(output, '{{DEFAULTSORT:'..standard.name_for_sorting({pagename})..'|noerror}}')
	table.insert(output_categories, 'Characters')
	table.insert(output_categories, p.lua_get_outdated_fields(args) )

-- sections
	value, categories = design.add_quote(args)
	output_categories = h.join_tables(output_categories, categories)
	table.insert(output, value)

	table.insert( output, design.add_overview_and_toc(args.Overview) )
	
	value = args.HistoryText
	if h.isempty(value)
		then table.insert(output_categories, 'Character History Needed')
		else table.insert( output, design.add_section('History', value, 2) )
	end
	
	table.insert( output, design.add_section('Personality', args.Personality, 2) )
	
	if not h.isempty(args.Powers) 
	or not h.isempty(args.Abilities) 
	or not h.isempty(args.Strength) 
	or not h.isempty(args.Weaknesses) 
	or list_of_power_grids[pagename] ~= nil
	or h.exists(pagename..'/Power Grid')
		then
			table.insert( output, design.add_header('Powers and Abilities', 2) )
			if list_of_power_grids[pagename] ~= nil
				then 
					value, categories = require('Module:Power Grid').lua_main(pagename)
					output_categories = h.join_tables(output_categories, categories)
					table.insert(output, value)
				elseif h.exists(pagename..'/Power Grid')
					then table.insert(output, '{{:'..pagename..'/Power Grid}}')
			end
			table.insert( output, design.add_section('Powers', args.Powers, 3) )
			table.insert( output, design.add_section('Abilities', args.Abilities, 3) )
			table.insert( output, design.add_section('Physical Strength', args.Strength, 3) )
			table.insert( output, design.add_section('Weaknesses', args.Weaknesses, 3) )
	end
	
	if not h.isempty(args.Equipment) or not h.isempty(args.Weapons)or not h.isempty(args.Transportation) 
		then
			table.insert( output, design.add_header('Paraphernalia', 2) )
			table.insert( output, design.add_section('Equipment', args.Equipment, 3) )
			table.insert( output, design.add_section('Weapons', args.Weapons, 3) )
			table.insert( output, design.add_section('Transportation', args.Transportation, 3) )
	end

	table.insert( output, design.add_section('Notes', args.Notes, 2) )
	table.insert( output, design.add_section('Trivia', args.Trivia, 2) )

	table.insert( output, design.add_header('See Also', 2) )
	--add links to standard sub-pages/categories - "Appearances", "Minor Appearances", Mentions", "Images", "Quotes" and "Gallery" 
	value, categories = design.add_links_to_standard_subpages(pagename, page_type)
	output_categories = h.join_tables(output_categories, categories)
	output = h.join_tables(output, value)
	
	table.insert( output, design.add_section('Recommended Reading', args.Recommended, 2) )
	
	table.insert( output, design.add_links_and_references(args, pagename) )
--
	output_categories = h.add_categories(output_categories)
	output = table.concat(output)
	
	return frame:preprocess(output)..output_categories
end

--------------------------------------------------------------------------------------------------
function p.lua_get_outdated_fields(args)
	local output = ''
	
	if  not h.isempty(args.Custom)
		or not h.isempty(args.CustomLabel)
		or not h.isempty(args.CustomSection1)
		or not h.isempty(args.CustomText1)
		or not h.isempty(args.CustomSection2)
		or not h.isempty(args.CustomText2)
		or not h.isempty(args.NotesHeader)
		or not h.isempty(args.TriviaHeader)
		or not h.isempty(args.LinksHeader)
		or not h.isempty(args.HistoryHeader)
		or not h.isempty(args.RecommendedHeader)
		or not h.isempty(args.PersonalityHeader)
		or not h.isempty(args.Height2)
		or not h.isempty(args.Weight2)
		or not h.isempty(args.Eyes2)
		or not h.isempty(args.Hair2)
		or not h.isempty(args.Gender2)
		or not h.isempty(args.Citizenship2) -- temporarily, to correctly put all citizenships into "Citizenship" field
		or not h.isempty(args.UnusualSkinColour2)
		or not h.isempty(args.MaritalStatus2) 
		or not h.isempty(args.PowersAbilitiesHeader)
		or not h.isempty(args.ParaphernaliaHeader)
		or not h.isempty(args.DiscoverAndDiscussHeader)
		or not h.isempty(args.OtherMedia)
		or not h.isempty(args.UniverseRef)
			then output = 'Outdated Fields/Character'
	end

	return output	
end


--------------------------------------------------------------------------------------------------
function p.get_current_alias(frame)
	local args = getArgs (frame)
	local value = args.CurrentAlias
	local ref = args.CurrentAliasRef or ''

	return value..ref
end


--------------------------------------------------------------------------------------------------
function p.get_aliases(frame)
	local args = getArgs (frame)
	local list = {args.Codenames, args.EditorialNames, args.Nicknames, args.Impersonations, args.Aliases}
	local labels = {'Codenames', 'Editorial Names', 'Nicknames', 'Impersonations', 'Other Aliases'}
	local i
	local output = {}

	for i = 1, 5 do
		if not h.isempty(list[i])
			then
				if labels[i] == 'Other Aliases' and table.concat(output) == '' 
					then table.insert(output, list[i])
					else table.insert(output, design.span(labels[i]..':').bold..'<br>'..list[i])
				end
		end
	end
	output = mw.text.listToText(output, '<br>', '<br>') 

	return output
end


--------------------------------------------------------------------------------------------------
function p.get_relatives(frame)
	local args = getArgs (frame)
	local list = {args.Ancestors, args.Grandparents, args.Parents, args.Siblings, args.Spouses, args.Children, args.Descendants, args.Relatives}
	local labels = {'Ancestors', 'Grandparents', 'Parents', 'Siblings', 'Spouses', 'Children', 'Descendants', 'Other Relatives'}
	local i
	local output = {}
	
	for i = 1, 8 do
		if not h.isempty(list[i])
			then
				if labels[i] == 'Other Relatives' and table.concat(output) == '' 
					then table.insert(output, list[i])
					else table.insert(output, design.span(labels[i]..':').bold..'<br>'..list[i])
				end
		end
	end
	output = mw.text.listToText(output, '<br>', '<br>') 
	
	return design.add_infobox_row_collapsible({output})
end


--------------------------------------------------------------------------------------------------
function p.get_living_status(frame)
	local args = getArgs (frame)
	local living_status = args.Status
	local output_categories = {}
	local output = ''
	
	if not h.isempty(args.Death)
		then
			table.insert(output_categories, 'Deceased Characters')
			output = h.LinkToCategory('Deceased Characters', 'Deceased')
		else
			table.insert(output_categories, 'Living Characters')
			output = h.LinkToCategory('Living Characters', 'Alive')
			if not h.isempty( p.get_cause_of_death(frame) )
				then 
					output = output..'; '..h.LinkToCategory('Formerly Deceased', 'formerly deceased')
					table.insert(output_categories, 'Formerly Deceased')
			end
	end 
	if not h.isempty(living_status)
		then output = output..' '..living_status
	end

	return output
end


--------------------------------------------------------------------------------------------------
function p.get_cause_of_death(frame)
	local args = getArgs (frame)
	local killed = args.KilledBy
	local casualty = args.CasualtyOf
	local suicide = args.Suicide
	local sacrifice = args.Sacrifice
	local cause = args.CauseOfDeath
	local link = ''
	local i
	local output_categories = {}
	local output = ''
	
	if not h.isempty(cause)
		then 
			if #cause > 500
				then output = '<br>\n'..cause
				else output = cause
			end
	end
	
	if not h.isempty(killed)
		then
			killed = h.explode(";", killed)
			for i = 1,#killed do
				link = h.break_link(h.trim(killed[i]), 1)
				table.insert(output_categories, 'Killed by '..link)
			end
	end
	
	if not h.isempty(casualty)
		then
			casualty = h.explode(";", casualty)
			for i = 1,#casualty do
				link = h.break_link(h.trim(casualty[i]), 1)
				table.insert(output_categories, link..' casualties')
			end
	end
	
	if not h.isempty(suicide)
		then table.insert(output_categories, 'Suicide')
	end
	
	if not h.isempty(sacrifice)
		then table.insert(output_categories, 'Self-sacrifice')
	end

	return output..h.add_categories(output_categories)
end


--------------------------------------------------------------------------------------------------
function p.get_marital_status(frame)
	local function get_value_and_remainder(value)
		local i
		local remainder = ''

		i = string.find(value, ' ')
		if i ~= nil
			then 
				remainder = ' '..string.sub(value, i+1, #value)
				value = string.sub(value, 1, i-1)
		end

		return value, remainder
	end
	local args = getArgs (frame)
	local value = args.MaritalStatus
	local value2 = args.MaritalStatus2
	local list = {'Married', 'Divorced', 'Engaged', 'Separated', 'Single', 'Widowed'}
	local l = {}
	local output_categories = {}
	local output = {}
	
	if not h.isempty(value)
		then
			output = {}
			l = h.explode(';', value)
			for i = 1, #l do
				value, remainder = get_value_and_remainder(h.trim(l[i]))
				if h.in_list(list, value)
					then 
						table.insert(output, h.LinkToCategory(value..' Characters', value)..remainder )
						table.insert(output_categories, value..' Characters')
					else 
						table.insert(output, h.LinkToCategory('Marital Status Needing Correction', value) )
				end
			end
			output = mw.text.listToText(output, ',<br>', ',<br>')
	end

	--if not h.isempty(value2)
	--	then table.insert(output, ' '..value2)
	--end
	
	return output..h.add_categories(output_categories)
end


--------------------------------------------------------------------------------------------------
function p.get_occupation(frame)
	local args = getArgs (frame)
	local value = args.Occupation
	local occupations = require('Module:CharacterInfoboxOccupation')
	local output_categories = {}
	local output = ''
	
	if not h.isempty(value)
		then
			for key, v in pairs(occupations) do
				if string.find( string.lower(value), key ) ~= nil 
					then
						for i, category in ipairs(v) do
							table.insert(output_categories, category)
						end
				end
			end
			output = value
	end

	return design.add_infobox_row_collapsible({value})..h.add_categories(output_categories)
end


--------------------------------------------------------------------------------------------------
function p.get_citizenship(frame)
	local args = getArgs (frame)
	local citizenship = require('Module:Citizenship')
	local value1 = args.Citizenship
	local value2 = args.Citizenship2
	local valueUpper
	local valueLower
	local value
	local substitute
	local list = {}
	local i
	local output_categories = {}
	local output = {}
	
	if not h.isempty(value1)
		then list = h.explode(',', value1) 
	end

	for i = 1, #list do
		value = h.trim(list[i])
		valueUpper = h.firstToUpper(value)
		valueLower = string.lower(value)
		value = citizenship.valid[valueUpper]
		substitute = citizenship.substitutes[valueLower]
		if value == true 
			then 
				table.insert(output, h.LinkToCategory(valueUpper, valueUpper) )
				table.insert(output_categories, valueUpper)
			elseif type(substitute) == "string" 
				then 
					table.insert(output, h.LinkToCategory(substitute, valueUpper) )
					table.insert(output_categories, substitute)
			else 
				table.insert(output, list[i])
		end
	end
	
	output = mw.text.listToText(output, ', ', ', ')
	
	if not h.isempty(value2)
		then output = output..' '..value2
	end

	return output..h.add_categories(output_categories)
end


--------------------------------------------------------------------------------------------------
function p.get_weight_value_and_unit(value)
	local list = {'lbs', 'ton', 'oz', 'kg'}
	local remainder = ''
	local unit = ''
	local output = value

	if string.find(value, 'Variable') ~= nil
		then 
			output = 'Variable'
			remainder = string.match(value, 'Variable(.*)')
		else
			for i = 1, 4 do
				unit = list[i]
				output, remainder = string.match(value, '(%d+.*%d*)'..unit..'(.*)')
				if output ~= nil
					then break
					else output = value
				end
			end
			if output == value
				then unit = ''
			end
	end
	
	if h.isempty(remainder)
		then remainder = ''
	end

	return output, unit, remainder
end


--------------------------------------------------------------------------------------------------
function p.get_weight(frame)
	local function lbs_to_kg(weightLbs)
		return h.round(weightLbs * units['lbs'].kg, 2)
	end
	local function get_weight_category(weightLbs)
		local i
		local output
		if weightLbs < 10
			then output = 'Weight 0-9 lbs ('..lbs_to_kg(10)..' kg)'
		elseif weightLbs >= 10 and weightLbs < 20
			then output = 'Weight 10-19 lbs ('..lbs_to_kg(10)..'-'..lbs_to_kg(20)..' kg)'
		elseif weightLbs >= 20 and weightLbs < 300
			then
				i = 20
				while i <= 280 do
					if weightLbs >= i and weightLbs < i + 20
						then output = 'Weight '..i..'-'..(i+19)..' lbs ('..lbs_to_kg(i)..'-'..lbs_to_kg(i+20)..' kg)'
					end
					i = i + 20
				end
		elseif weightLbs >= 300 and weightLbs < 1000
			then
				i = 300
				while i <= 900 do
					if weightLbs >= i and weightLbs < i + 100
						then output = 'Weight '..i..'-'..(i+99)..' lbs ('..lbs_to_kg(i)..'-'..lbs_to_kg(i+100)..' kg)'
					end
					i = i + 100
				end
    	elseif weightLbs >= 1000
    		then output = 'Weight above 1000 lbs ('..lbs_to_kg(1000)..' kg)'
    	end
    	return output
    end
	local args = getArgs (frame)
    local value = args.Weight
    --local value2 = args.Weight2
    local weight
    local weightLbs = 0
    local weightKg  = 0
	local unit = ""
	local remainder
	local i
	local category
	local list = {}
	local output_categories = {}
	local output = {}

	if not h.isempty(value)
		then
			list = h.explode(';', value)
			for i = 1, #list do
				weight, unit, remainder = p.get_weight_value_and_unit(list[i])
				if unit ~= ''
					then
						weightLbs = h.round( weight * units[unit].lbs , 2 )
						weightKg  = weight * units[unit].kg
						if weightKg < 1
        					then weightKg = h.round( weightKg * 1000, 2 ) .. " gram"
        					elseif weightKg > 1000
            					then weightKg = h.round( weightKg / 1000, 2 ) .. " ton"
        					else weightKg = h.round( weightKg, 2 ) .. " kg"
    					end
    					category = get_weight_category(weightLbs)
    					table.insert(output_categories, category)
    					table.insert(output, h.LinkToCategory(category, weightLbs .. " lbs (" .. weightKg .. ")")..remainder)
					elseif weight == 'Variable'
						then
							category = 'Variable Weight'
							table.insert(output_categories, category)
							table.insert(output, h.LinkToCategory(category, weight)..remainder)
					else
						table.insert(output, weight..remainder)
				end
			end
			output = mw.text.listToText(output, ',<br>', ',<br>')
	end

	--if not h.isempty(value2) 
	--	then output = output.." " ..value2
	--end

	return output..h.add_categories(output_categories)
end


--------------------------------------------------------------------------------------------------
function p.get_height_value(value, value2)
	local function round(m)
		return tonumber( string.format("%.2f", m) )
	end
	local feet = string.match(value, "(%d+)'")
	local inches = string.match(value, '(%d+)"')
	local metres
	local remainder = ''
	local output = ''

	if feet ~= nil
		then
			if inches == nil
				then 
					inches = '0'
					metres = feet * units['ft'].m
					remainder = string.match(value, "%d+'(.+)")
				else
					metres = (feet * units['ft'].m) + (inches * units['in'].m)
					remainder = string.match(value, '%d+"(.+)')
			end

			if metres < 1
				then output = round(metres * 100)..' cm'
				elseif metres >= 1000
					then output = round(metres / 1000)..' km'
				else output = round(metres)..' m'
			end
	
			if inches ~= '0'
				then output = feet..'′'..inches..'″'..' ('..output..')'
				else output = feet..'′'..' ('..output..')'
			end
		elseif string.find(value, 'Variable') ~= nil
			then 
				output = 'Variable'
				remainder = string.match(value, 'Variable(.*)')
	end
	if h.isempty(remainder)
		then remainder = ''
	end

	return output, remainder, feet, inches
end


--------------------------------------------------------------------------------------------------
function p.get_height(frame)
	local function ft_to_m(heightFt)
		return tonumber( string.format("%.2f", heightFt * units['ft'].m) )
	end
	local function get_height_category(heightFt, heightIn)
		local output
		heightFt = tonumber(heightFt)
		if heightFt < 1
			then output = 'Height 0-1 ft. ('..ft_to_m(1)..' m)'
    	elseif heightFt >= 1 and heightFt < 2
    		then output = 'Height 1-2 ft. ('..ft_to_m(1)..'-'..ft_to_m(2)..' m)'
    	elseif heightFt >= 2 and heightFt < 3
    		then output = 'Height 2-3 ft. ('..ft_to_m(2)..'-'..ft_to_m(3)..' m)'
    	elseif heightFt >= 3 and heightFt < 4
    		then output = 'Height 3-4 ft. ('..ft_to_m(3)..'-'..ft_to_m(4)..' m)'
    	elseif heightFt >= 4 and heightFt < 5
    		then output = 'Height 4-5 ft. ('..ft_to_m(4)..'-'..ft_to_m(5)..' m)'
    	elseif heightFt >= 5 and heightFt < 6
    		then output = 'Height 5 ft. '..heightIn..' in. ('..ft_to_m(5 + heightIn/12)..' m)'
    	elseif heightFt >= 6 and heightFt < 7
    		then output = 'Height 6 ft. '..heightIn..' in. ('..ft_to_m(6 + heightIn/12)..' m)'
    	elseif heightFt >= 7 and heightFt < 8
    		then output = 'Height 7-8 ft. ('..ft_to_m(7)..'-'..ft_to_m(8)..' m)'
    	elseif heightFt >= 8
    		then output = 'Height above 8 ft. ('..ft_to_m(8)..' m)'
    	end
    	return output
    end
	local args = getArgs (frame)
    local value = args.Height
    local value2 = args.Height2
    local height
    local height_ft
    local height_in
	local remainder
	local i
	local category
	local list = {}
	local output_categories = {}
	local output = {}

	if not h.isempty(value)
		then
			list = h.explode(';', value)
			for i = 1, #list do
				height, remainder, height_ft, height_in  = p.get_height_value(list[i])
				if height ~= ''
					then
						if height_ft ~= nil
							then category = get_height_category(height_ft, height_in)
							elseif height == 'Variable'
								then category = 'Variable Height'
						end
    					table.insert(output_categories, category)
    					table.insert(output, h.LinkToCategory(category, height)..remainder)
					else
						table.insert(output, height..remainder)
				end
			end
			output = mw.text.listToText(output, ',<br>', ',<br>')
	end

	--if not h.isempty(value2) 
	--	then output = output.." " ..value2
	--end

	return output..h.add_categories(output_categories)
end


--------------------------------------------------------------------------------------------------
function p.get_eyes(frame)
	local function eyeballs_color(value)
		local category = ''
		local output = ''
		if not h.isempty(value)
			then
				category = value..' Eyeballs'
				output = h.LinkToCategory(category, value)
		end
		return output, category
	end
	local function iris_color(value)
		local category = ''
		local output = ''
		if not h.isempty(value)
			then
				value = string.gsub(value, 'Gray', 'Grey')
				category = value..' Eyes'
				if h.pages_in_category(category, 'pages') > 0
					then output = h.LinkToCategory(category, value)
					elseif value == 'No Iris'
						then 
							category = 'No visible Irises or Pupils'
							output = h.LinkToCategory(category, 'No Visible')
					elseif value == 'No Eyes'
						then 
							category = 'No Eyes'
							output = h.LinkToCategory(category, 'No Eyes At All')
					else category = ''
				end
		end
		return output, category
	end
	local function get_value_and_remainder(value)
		local i
		local j
		local remainder = ''
		
		i, j = string.find(value, 'No Iris')
		if j ~= nil
			then i = string.find(value, ' ', j)
			else
				value = string.gsub(value, '^n%/a', 'No')
				value = string.gsub(value, '^None', 'No')
				value = string.gsub(value, '^No Eyes', 'No')
				value = string.gsub(value, '^No', 'No Eyes')
				i, j = string.find(value, '^No Eyes')
				if j ~= nil
					then i = string.find(value, ' ', j)
					else i = string.find(value, ' ')
				end
		end
		
		if i ~= nil
			then 
				remainder = ' '..string.sub(value, i+1, #value)
				value = string.sub(value, 1, i-1)
		end
		return value, remainder
	end
	local args = getArgs (frame)
	local eyes = args.Eyes
	local eyes2 = args.Eyes2
	local eyeballs = args.Eyeballs
	local list = {}
	local category = ''
	local value
	local remainder
	local i
	local output_categories = {}
	local output = ''
	
	if not h.isempty(eyes)
		then
			list = h.explode(';', eyes)
			eyes = {}
			for i = 1, #list do
				value, remainder = get_value_and_remainder(h.trim(list[i]))
				value, category = iris_color(value)
				table.insert(output_categories, category)
				table.insert(eyes, '\n* '..value..remainder)
			end
			eyes = mw.text.listToText(eyes, '', '')
			--if not h.isempty(eyes2)
			--	then eyes = eyes..' '..eyes2
			--end
			output = '\n'..design.span('Irises:').bold..eyes
	end

	if not h.isempty(eyeballs)
		then
			list = h.explode(';', eyeballs)
			eyeballs = {}
			for i = 1, #list do
				value, remainder = get_value_and_remainder(h.trim(list[i]))
				value, category = eyeballs_color(value)
				table.insert(output_categories, category)
				table.insert(eyeballs, '\n* '..value..remainder)
			end
			eyeballs = mw.text.listToText(eyeballs, '', '')
			output = '\n'..design.span('Eyeballs:').bold..eyeballs..output
	end

	return output..h.add_categories(output_categories)
end


--------------------------------------------------------------------------------------------------
function p.get_hair(frame)
	local function get_value_and_remainder(value)
		local exceptions_list = {'light brown', 'platinum blond', 'strawberry blond', 'no hair'}
		local i
		local j
		local k
		local dyed = false
		local remainder = ''

		value = string.gsub(value, '^n%/a', 'No')
		value = string.gsub(value, '^None', 'No')
		value = string.gsub(value, '^No Hair', 'No')
		value = string.gsub(value, '^No', 'No Hair')
		i, j = string.find(value, 'Dyed ')
		if j ~= nil
			then
				dyed = true
				value = string.gsub(value, 'Dyed ', '')
		end
		for k = 1, #exceptions_list do
			i, j = string.find(string.lower(value), exceptions_list[k])
			if j ~= nil
				then 
					i = string.find(value, ' ', j)
					break
				else i = string.find(value, ' ')
			end
		end
		if i ~= nil
			then 
				remainder = ' '..string.sub(value, i+1, #value)
				value = string.sub(value, 1, i-1)
		end

		return value, remainder, dyed
	end
	local function hair_color(value, dyed)
		local category = ''
		local output_categories = {}
		local output = ''
		if not h.isempty(value)
			then
				value = string.gsub(value, 'Gray', 'Grey')
				value = string.gsub(value, 'Blonde', 'Blond')
				value = string.gsub(value, 'Fair', 'Blond')
				value = string.gsub(value, 'Reddish Brown', 'Auburn')
				if value == 'Bald'
					then category = 'Bald'
					else category = value..' Hair'
				end
				if h.pages_in_category(category, 'pages') > 0
					then output = h.LinkToCategory(category, value)
					elseif value == 'No Hair'
						then
							category = 'No Hair'
							output = h.LinkToCategory(category, 'No Hair At All')
					else category = ''
				end
				table.insert(output_categories, category)
				if dyed == true
					then 
						table.insert(output_categories, 'Dyed Hair')
						output = h.LinkToCategory('Dyed Hair', 'Dyed')..' '..output
				end
		end
		return output, output_categories
	end
	local args = getArgs (frame)
	local hair = args.Hair
	local hair2 = args.Hair2
	local category = ''
	local value
	local remainder
	local dyed
	local i
	local list = {}
	local output_categories = {}
	local output = ''
	
	if not h.isempty(hair)
		then
			output = {}
			list = h.explode(';', hair)
			for i = 1, #list do
				value, remainder, dyed = get_value_and_remainder(h.trim(list[i]))
				value, category = hair_color(value, dyed)
				output_categories = h.join_tables(output_categories, category)
				table.insert(output, value..remainder)
			end
			output = mw.text.listToText(output, ',<br>', ',<br>')
	end
	--if not h.isempty(hair2)
	--	then output = output..' '..hair2
	--end
	
	return output..h.add_categories(output_categories)
end


--------------------------------------------------------------------------------------------------
function p.get_skin(frame)
	local function get_value_and_remainder(value)
		local exceptions_list = {'light green', 'green, yellow', 'no skin'}
		local i
		local j
		local k
		local remainder = ''

		value = string.gsub(value, '^n%/a', 'No')
		value = string.gsub(value, '^None', 'No')
		value = string.gsub(value, '^No Skin', 'No')
		value = string.gsub(value, '^No', 'No Skin')

		for k = 1, #exceptions_list do
			i, j = string.find(string.lower(value), exceptions_list[k])
			if j ~= nil
				then 
					i = string.find(value, ' ', j)
					break
				else i = string.find(value, ' ')
			end
		end
		if i ~= nil
			then 
				remainder = ' '..string.sub(value, i+1, #value)
				value = string.sub(value, 1, i-1)
		end

		return value, remainder
	end
	local function skin_color(value)
		local category = ''
		local output_categories = {}
		local output = ''
		if not h.isempty(value)
			then
				value = string.gsub(value, 'Gray', 'Grey')
				category = value..' Skin'
				if h.pages_in_category(category, 'pages') > 0
					then output = h.LinkToCategory(category, value)
					elseif value == 'No Skin'
						then
							category = 'No Skin'
							output = h.LinkToCategory(category, 'No Skin At All')
					else category = ''
				end
				table.insert(output_categories, category)
		end
		return output, output_categories
	end
	local args = getArgs (frame)
	local skin = args.UnusualSkinColour
	--local skin2 = args.UnusualSkinColour2
	local category = ''
	local value
	local remainder
	local i
	local list = {}
	local output_categories = {}
	local output = ''
	
	if not h.isempty(skin)
		then
			output = {}
			list = h.explode(';', skin)
			for i = 1, #list do
				value, remainder = get_value_and_remainder(h.trim(list[i]))
				value, category = skin_color(value)
				output_categories = h.join_tables(output_categories, category)
				table.insert(output, value..remainder)
			end
			output = mw.text.listToText(output, ',<br>', ',<br>')
	end
	--if not h.isempty(skin2)
	--	then output = output..' '..skin2
	--end
	
	return output..h.add_categories(output_categories)
end


--------------------------------------------------------------------------------------------------
function p.get_gender(frame)
	local function get_value_and_remainder(value)
		local i
		local remainder = ''

		i = string.find(value, ' ')
		if i ~= nil
			then 
				remainder = ' '..string.sub(value, i+1, #value)
				value = string.sub(value, 1, i-1)
		end

		return value, remainder
	end
	local function gender_category(value)
		local category = ''
		local output_categories = {}
		local output = ''
		if not h.isempty(value)
			then
				category = value..' Characters'
				if h.pages_in_category(category, 'pages') > 0
					then output = h.LinkToCategory(category, value)
					else category = ''
				end
				table.insert(output_categories, category)
		end
		return output, output_categories
	end
	local args = getArgs (frame)
	local gender = args.Gender
	--local gender2 = args.Gender2
	local category = ''
	local value
	local remainder
	local i
	local list = {}
	local output_categories = {}
	local output = ''
	
	if not h.isempty(gender)
		then
			output = {}
			list = h.explode(';', gender)
			for i = 1, #list do
				value, remainder = get_value_and_remainder(h.trim(list[i]))
				value, category = gender_category(value)
				output_categories = h.join_tables(output_categories, category)
				table.insert(output, value..remainder)
			end
			output = mw.text.listToText(output, ',<br>', ',<br>')
	end
	--if not h.isempty(gender2)
	--	then output = output..' '..gender2
	--end

	return output..h.add_categories(output_categories)
end


--------------------------------------------------------------------------------------------------
function p.get_unusual_features(frame)
	local args = getArgs (frame)
	local value = args.UnusualFeatures
	local list = require('Module:CharacterInfoboxUnusualFeatures')
	local output_categories = p.get_categories_from_keywords(value, list.valid, list.exceptions)
	
	return value..h.add_categories(output_categories)
end


--------------------------------------------------------------------------------------------------
function p.get_ctry(frame)
	local substitutes = require('Module:CharacterInfoboxCtry')
	local args = getArgs (frame)
	local value = args[1]
	local output = ''
	
	if not h.isempty(value)
		then
			output = value
			if string.find(value, "%[%[.+%]%]") == nil 
				then
					if type(substitutes[value]) == "string" 
						then output = h.Link(substitutes[value])
					end
			end
	end
	
	return output
end


--------------------------------------------------------------------------------------------------
function p.get_origin(frame)
	local args = getArgs (frame)
	local list = require('Module:CharacterInfoboxOrigins')
	local value = args.Origin
	local output = ''
	
	if not h.isempty(value)
		then 
			output = p.get_categories_from_keywords(value, list.valid, list.exceptions)
			output = value..h.add_categories(output)
	end
	
	return output
end


--------------------------------------------------------------------------------------------------
function p.get_categories_from_keywords(value, valid, exceptions)
	local output = {}

	if not h.isempty(value) -- Field isn't blank
		then -- Grab a valid pair and use it
			for validKey, validValue in pairs(valid) do
				-- If you find the validKey in the field, and there are no exceptions for this validKey, then categorize
				if string.find(string.lower(value), validKey) ~= nil and type(exceptions[validKey]) ~= "table" 
					then 
						for valueKey, valueCategoryName in ipairs( validValue ) do
							table.insert(output, valueCategoryName)
						end
				end
			end
	end
	return output
end

return p