Module:Infobox NPC/sandbox
Documentation for this module may be created at Module:Infobox NPC/sandbox/doc
--------------------------
-- Module for [[Template:Infobox NPC]]
------------------------
local p = {}
-- "imports"
local onmain = require('Module:Mainonly').on_main
local yesno = require('Module:Yesno')
local paramtest = require('Module:Paramtest')
local infobox = require('Module:Infobox')
local cleanimg = require('Module:Clean image').clean
local npcrace = mw.loadData('Module:NPC races')
function p.main(frame)
local args = frame:getParent().args
local ret = infobox.new(args)
ret:defineParams{
{ name = 'name', func = 'name' },
{ name = 'aka', func = 'has_content' },
{ name = 'image', func = imgarg },
{ name = 'imagebackground', func = { name = imgback, params = { 'imagebackground' }, flag = { 'd' } }, dupes = true },
{ name = 'vanchor', func = { name = 'has_content', params = { 'version' }, flag = 'p' } },
{ name = 'release', func = 'release' },
{ name = 'removal', func = 'removal' },
{ name = 'members', func = 'has_content' },
{ name = 'quest', func = { name = questarg, params = { 'quest' }, flag = { 'd' } } },
{ name = 'location', func = { name = locationarg, params = { 'location' }, flag = { 'd' } } },
{ name = 'level', func = 'has_content' },
{ name = 'actions', func = { name = actionarg, params = { 'actions' }, flag = { 'd' } } },
{ name = 'actions_smw', func = { name = actionsmw, params = { 'actions' }, flag = { 'p' } }, dupes = true },
{ name = 'thievelvl', func = { name = thievarg, params = { 'thievelvl' }, flag = { 'd' } } },
{ name = 'thievelvl_smw', func = { name = thievarg, params = { 'thievelvl' }, flag = { 'd' } }, dupes = true },
{ name = 'examine', func = { name = examinearg, params = { 'examine' }, flag = { 'd' } } },
{ name = 'map', func = { name = maparg, params = { 'map' }, flag = { 'd' } } },
{ name = 'intmap', func = { name = intmaparg, params = { 'intmap' }, flag = { 'd' } } },
{ name = 'mapdisp', func = { name = mapdisp, params = { 'map', 'intmap' }, flag = { 'd', 'd' } }, dupes = true },
{ name = 'race', func = racearg },
{ name = 'id', func = { name = iddisp, params = { 'id' }, flag = 'p' } },
{ name = 'objectid', func = { name = iddisp, params = { 'objectid' }, flag = 'p' } },
{ name = 'id_smw', func = { name = idsmw, params = { 'id' }, flag = 'p' }, dupes = true },
{ name = 'objectid_smw', func = { name = idsmw, params = { 'objectid' }, flag = 'p' }, dupes = true },
{ name = 'chisel_links', func = { name = 'make_chisel_links', params = { 'name', '<br>', 'mrnd', 'id', 'mrod', 'objectid' }, flag = { 'p', 'r', 'r', 'p', 'r', 'p' } } },
{ name = 'shop', func = 'has_content' },
{ name = 'gender', func = 'has_content' },
{ name = 'f2pvisible', func ='has_content' },
{ name = 'voice', func ='has_content' },
}
ret:useSMW({
members = 'Is members only',
thievelvl_smw = 'Thieving level'
})
ret:useSMWOne({
id_smw = 'All NPC ID',
objectid_smw = 'All Object ID'
})
ret:useSMWSubobject({
id_smw = 'NPC ID',
objectid_smw = 'Object ID',
-- name = 'NPC name',
members = 'Is members only',
-- location = 'NPC location',
actions_smw = 'Actions',
release = 'Release date',
update = 'Release update',
--removal = 'Removal date',
removalupdate = 'Removal update',
thievelvl_smw = 'Thieving level',
examine = 'Examine'
})
ret:setMaxButtons(4)
ret:create()
ret:cleanParams()
ret:customButtonPlacement(true)
ret:linkParams{
image = 'imagebackground'
}
ret:defineLinks({ links = {{ 'Template:%s', 'Infobox' },
{ 'Template_talk:%s', 'Talk page' }}, colspan = '2' })
ret:defineName('Infobox NPC')
ret:addClass('rsw-infobox plainlinks')
ret:addButtonsCaption()
-- PARAMETER: image
ret:addRow{
{ tag = 'argd', content = 'image', class = 'infobox-image bordered-image', colspan = '2' },
meta = { addClass = ret:param('imagebackground', 'r') }
}
-- PARAMETER: name
ret:addRow{
{ tag = 'argh', content = 'name', class='infobox-header', colspan = '2' }
}
-- PARAMETER: release
-- (update included automatically by infobox)
:addRow{
{ tag = 'th', content = 'Release date', css = { ['white-space'] = 'nowrap' } },
{ tag = 'argd', content = 'release' }
}
-- PARAMETER: removal
if ret:paramDefined('removal') then
ret:addRow{
{ tag = 'th', content = 'Removal' },
{ tag = 'argd', content = 'removal' }
}
end
-- PARAMETER: aka
if ret:paramDefined('aka') then
ret:addRow{
{ tag = 'th', content = 'Also called' },
{ tag = 'argd', content = 'aka' }
}
end
-- PARAMETER: level
if ret:paramDefined('level') then
ret:addRow{
{ tag = 'th', content = '[[Combat level]]', css = { ['white-space'] = 'nowrap' } },
{ tag = 'argd', content = 'level' }
}
end
-- PARAMETER: race
ret:addRow{
{ tag = 'th', content = '[[Races|Race]]' },
{ tag = 'argd', content = 'race' }
}
-- PARAMETER: members
:addRow{
{ tag = 'th', content = '[[Members]]' },
{ tag = 'argd', content = 'members' }
}
-- PARAMETER: quest
ret:addRow{
{ tag = 'th', content = '[[:Category:Quest NPCs|Quest NPC]]' },
{ tag = 'argd', content = 'quest' }
}
-- PARAMETER: location
ret:addRow{
{ tag = 'th', content = '[[Locations|Location(s)]]' },
{ tag = 'argd', content = 'location' }
}
-- PARAMETER: shop
ret:addRow{
{ tag = 'th', content = '[[Shop|Sells items]]' },
{ tag = 'argd', content = 'shop' }
}
-- PARAMETER: gender
ret:addRow{
{ tag = 'th', content = '[[Gender]]' },
{ tag = 'argd', content = 'gender' }
}
-- PARAMETER: actions
ret:addRow{
{ tag = 'th', content = 'Actions' },
{ tag = 'argd', content = 'actions' }
}
-- PARAMETER: thievelvl
if ret:paramDefined('thievelvl') then
ret:addRow{
{ tag = 'th', content = '[[File:Thieving-icon.png|link=Thieving|frameless|20px|alt=Thieving level|Thieving level]] [[Thieving|Level]]' },
{ tag = 'argd', content = 'thievelvl' } }
end
-- PARAMETER: examine
ret:addRow{
{ tag = 'th', content = '[[Examine]]' },
{ tag = 'argd', content = 'examine' }
}
-- PARAMETER: map
local map_defined = ret:paramGrep('mapdisp', function(x) return (x or false) ~= false end)
if map_defined == true then
if ret:paramDefined('map') then
ret:addRow{
{ tag = 'argd', content = 'map', class = 'infobox-map', colspan = '2' } }
elseif ret:paramDefined('intmap') then
ret:addRow{
{ tag = 'argd', content = 'intmap', class = 'infobox-map', colspan = '2' } }
end
end
-- PARAMETER: Advanced data
ret:addRow{
{ tag = 'th', content = 'Advanced data', class = 'infobox-subheader', colspan = '2' },
meta = {addClass = 'advanced-data'}
}
:addRow{
{ tag = 'th', content = 'NPC ID' },
{ tag = 'argd', content = 'id' },
meta = {addClass = 'advanced-data'}
}
if ret:paramDefined('objectid', 'all') then
ret:addRow{
{ tag = 'th', content = 'Object ID' },
{ tag = 'argd', content = 'objectid' },
meta = {addClass = 'advanced-data'}
}
end
ret:addRow{
{ tag = 'th', content = 'Links' },
{ tag = 'argd', content = 'chisel_links' },
meta = {addClass = 'advanced-data'} }
ret:finish()
if onmain() then
local a1 = ret:param('all')
local a2 = ret:categoryData()
ret:wikitext(addcategories(a1, a2))
end
return ret:tostring()
end
function imgarg(arg)
if infobox.isDefined(arg) then
return cleanimg{ file = arg, width = 300, height = 300 }
end
return nil
end
function imgback(arg)
if infobox.isDefined(arg) then
if yesno(arg) then
return 'infobox-imgbg'
end
end
return ''
end
function examinearg(arg)
if infobox.isDefined(arg) then
local r = string.gsub(arg, '*', '<br />\'\'\'•\'\'\' ')
r = string.gsub(r, '<br%s*/?>', '', 1)
return r
end
return nil
end
function thievarg(arg)
arg = string.gsub(arg or '',',','')
return tonumber(arg, 10)
end
function maparg(arg)
if infobox.isDefined(arg) then
local low = string.lower(arg)
if yesno(low) == false then
return nil
elseif low == 'name' then
return string.format('[[File:%s location.png]]', mw.title.getCurrentTitle().text)
elseif string.find(low, '.png') then
return cleanimg{ file = arg, width = 250 }
else
return arg
end
else
return nil
end
end
function racearg(arg)
local ret = { '' }
if infobox.isDefined(arg) then
for _, v in ipairs(npcrace) do
if v.race == string.lower(arg) then
table.insert(ret, v.racelink)
end
end
for i, v in ipairs(ret) do
if (v ~= '') then
ret[i] = string.format('[[%s]]', v)
end
end
r = table.concat(ret, '')
if r ~= '' then
return r
else
--Do not return invalid categories
--return arg
end
end
return nil
end
function intmaparg(arg)
if infobox.isDefined(arg) then
if yesno(arg) == false then
return nil
else
return mw.getCurrentFrame():preprocess( arg )
end
else
return nil
end
end
function mapdisp(map, intmap)
if infobox.isDefined(intmap) or infobox.isDefined(map) then
if ( yesno(map) == false ) or ( string.lower(map) == 'none' ) then
if ( yesno(intmap) == false ) or ( yesno(intmap) == nil ) then
return false
end
elseif ( yesno(intmap) == false ) or ( string.lower(intmap) == 'none' ) then
if ( yesno(map) == false ) or ( yesno(map) == nil ) then
return false
end
else
return true
end
else
return false
end
end
function iddisp(id)
if infobox.isDefined(id) then
if id:lower() ~= 'no' and id:lower() ~= 'none' then
local r = string.gsub(id, ', *', ', ')
return r
elseif id:lower() == 'no' or id:lower() == 'none' then
return 'None'
end
end
return nil
end
function idsmw(id)
if infobox.isDefined(id) and id:lower() ~= 'no' and id:lower() ~= 'none' then
local r = string.gsub(id, ', *', infobox.splitpoint)
return r
end
return nil
end
function questarg(arg)
if infobox.isDefined(arg) then
if string.lower(arg) == 'no' then
return 'No'
else
local islist = mw.ustring.match( arg, '^%s*%*.*\n%*' )
if islist then
local r = '\n' .. arg .. '</ul>'
local span = mw.html.create('span')
if islist then
span:newline()
end
span:wikitext(r)
return tostring(span)
else
local r = mw.ustring.gsub(arg, '%[*Missing, Presumed Death%]*', '!foo!')
r = string.gsub(r, ',%s*', '<br />\'\'\'•\'\'\' ')
r = '\'\'\'•\'\'\' ' .. r
r = mw.ustring.gsub(r, '!foo!', '[[Missing, Presumed Death]]')
return r
end
end
end
return nil
end
function locationarg(arg)
if infobox.isDefined(arg) then
local islist = mw.ustring.match( arg, '^%s*%*.*\n%*' )
if islist then
arg = islist and ('\n' .. arg .. '</ul>') or arg
local span = mw.html.create('span')
if islist then
span:newline()
end
span:wikitext(arg)
span:done()
return tostring(span)
else
return arg
end
end
return nil
end
function actionarg(arg)
if infobox.isDefined(arg) then
if string.lower(arg) == 'none' or string.lower(arg) == 'examine' then
return '\'\'\'•\'\'\' Examine'
end
local r = string.gsub(arg, ',%s*', '<br />\'\'\'•\'\'\' ')
r = '\'\'\'•\'\'\' ' .. r
r = mw.ustring.gsub(r, '%[*[Ww]alk [Hh]ere%]*', '[[Walk here|Walk here]]')
r = mw.ustring.gsub(r, '%[*[Ee]xamine%]*', 'Examine')
if not r:find('Examine') then
r = r .. '<br />\'\'\'•\'\'\' Examine'
end
return r
end
return nil
end
function actionsmw(arg)
if infobox.isDefined(arg) then
if string.lower(arg) == 'none' or string.lower(arg) == 'examine' then
return 'Examine'
end
local r = string.gsub(arg, ',%s*', infobox.splitpoint)
r = mw.ustring.gsub(r, '%[*[Ww]alk [Hh]ere%]*', 'Walk here')
r = mw.ustring.gsub(r, '%[*[Ee]xamine%]*', 'Examine')
if not r:find('Examine') then
r = r .. infobox.splitpoint .. 'Examine'
end
return r
end
return nil
end
function addcategories(args, catargs)
function is_def(x, y)
y = y or 'd'
if infobox.isDefined(x) then
return infobox.isDefined(x[y])
end
return false
end
local ret = { 'Non-player characters' }
-- ID based categories
local misID = {}
if args.id.switches then
for i,v in ipairs(args.id.switches) do
if infobox.isDefined(v) and v ~= 'None' then
table.insert(ret, 'Cache NPCs')
else
misID[i] = true
end
end
elseif args.id.d and args.id.d ~= 'None' then
table.insert(ret, 'Cache NPCs')
end
if args.objectid.switches then
for i,v in ipairs(args.objectid.switches) do
if infobox.isDefined(v) and v ~= 'None' then
table.insert(ret, 'Cache scenery')
if misID[i] then
misID[i] = false
end
end
end
elseif infobox.isDefined(args.objectid.d) and args.objectid.d ~= 'None' then
table.insert(ret, 'Cache scenery')
misID = {}
end
for _,v in pairs(misID) do
if v then
table.insert(ret, 'Needs ID')
end
end
local cat_map = {
-- Added if the parameter has content
defined = {
aka = 'Pages with AKA',
thievelvl = 'Thievable entities',
},
-- Added if the parameter has no content
notdefined = {
image = 'Needs non-player character image',
members = 'Needs members status',
release = 'Needs release date',
examine = 'Needs examine added',
actions = 'Needs actions added',
race = 'Needs race',
gender = 'Needs gender',
},
}
-- Run and add mapped categories
for n, v in pairs(cat_map.defined) do
if catargs[n] and catargs[n].one_defined then
table.insert(ret,v)
end
end
for n, v in pairs(cat_map.notdefined) do
if catargs[n] and catargs[n].all_defined == false then
table.insert(ret,v)
end
end
-- Add the associated race category if matched
local norace = true
if args['race'] and args['race'].d then
local racestr = string.gsub(string.gsub(args['race'].d, '%]%]', ''), '%[%[', '')
for _, v in ipairs(npcrace) do
if (v.racelink == racestr) then
table.insert(ret, v.racecat)
if v.addcat then
for _,k in ipairs(v.addcat) do
table.insert(ret, k)
end
end
norace = false
end
end
end
if norace then
table.insert(ret, 'Needs race')
end
-- Add the associated gender category if matched
if args['gender'] then
if string.lower(args['gender'].d or '') == 'male' then
table.insert(ret, 'Male characters')
elseif string.lower(args['gender'].d or '') == 'female' then
table.insert(ret, 'Female characters')
elseif string.lower(args['gender'].d or '') == 'no' then
table.insert(ret, 'Genderless characters')
end
end
-- Add the associated category if the parameter is valued at yes
if args['voice'] then
if string.lower(args['voice'].d or '') == 'yes' then
table.insert(ret, 'Voice acted NPCs')
end
end
if args['f2pvisible'] then
if string.lower(args['f2pvisible'].d or '') == 'yes' then
table.insert(ret, 'Non-player characters that are visible but not interactive in free-to-play')
end
end
-- Add the associated category if the parameter is not valued at no
if args['shop'] then
if string.lower(args['shop'].d or '') ~= 'no' then
table.insert(ret, 'Merchants')
end
end
if args['quest'] then
if string.lower(args['quest'].d or '') ~= 'no' then
table.insert(ret, 'Quest NPCs')
end
end
-- Map category
if catargs.mapdisp and catargs.mapdisp.all_defined == false then
if args.map then
if args.map.d ~= 'no' then
if args.intmap then
if args.intmap.d ~= 'no' then
table.insert(ret, 'Needs map')
end
end
end
else
if args.intmap then
if args.intmap.d ~= 'no' then
table.insert(ret, 'Needs map')
end
else
table.insert(ret, 'Needs map')
end
end
end
mw.logObject(args['actions'])
mw.logObject(args['actions_smw'])
mw.log(infobox.isDefined(args['actions']))
mw.log(infobox.isDefined(args['actions_smw']))
mw.log(is_def(args['actions']))
mw.log(is_def(args['actions_smw']))
mw.log(string.lower(args['actions_smw'].d or '') == 'examine')
-- Action based categories
if args.actions_smw.switches then
for _,v in ipairs(args.actions_smw.switches) do
if infobox.isDefined(v) then
if v == 'Examine' then
table.insert(ret, 'Non-interactive characters')
else
table.insert(ret, 'Interactive characters')
end
end
end
elseif infobox.isDefined(args.actions_smw.d) then
if args.actions_smw.d == 'Examine' then
table.insert(ret, 'Non-interactive characters')
else
table.insert(ret, 'Interactive characters')
end
end
-- combine table and format category wikicode
for i, v in ipairs(ret) do
if (v ~= '') then
ret[i] = string.format('[[Category:%s]]', v)
end
end
return table.concat(ret, '')
end
return p