Module:Hero

From Mighty Party Wiki
Jump to navigation Jump to search

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

-- This module implements [[Template:Hero]].

local data = mw.loadData('Module:Hero/data')
local constants = mw.loadData('Module:Hero/constants')
local icondata = mw.loadData('Module:Icon/data')
local sheet = "https://docs.google.com/spreadsheets/d/1_qPcYUHYez3O7Tpc6n62mxDikiohoDZD6-iP4jIZoTQ/edit#gid=0"

local p = {}

function p._main(args)
    local getHeroData = require ('Module:Hero/getData')
    local hero = args.hero or args[1]
    local attribute = args.attribute or args[2]
    
    if (attribute == "level_info")
    or (attribute == "level_skill") then 
	    local level = args.level or args[3]
	    local info = args.info or args[4]
	    local reborn = args.reborn or args[5] or 0
	    if getHeroData[attribute](hero,level,reborn,info) then 
	    	return getHeroData[attribute](hero,level,reborn,info)
	    else 
	    	return ""
	    end
	elseif (attribute == "hero_skill") then --use level_skill instead for most cases
	    local level = args.level or args[3]
		return mw.getCurrentFrame():preprocess(string.format(hero,level))
	else
	    if getHeroData[attribute](hero) then 
	    	return getHeroData[attribute](hero)
	    else 
	    	return ""
	    end
	end
end

function p.main(frame)
	local args = {}
	for k, v in pairs(frame:getParent().args) do
		args[k] = v
	end
	return p._main(args)
end

function p.herolist()
	--sort the hero table
    keys = {}
    for k in pairs(data) do
        table.insert(keys, k)
    end
    table.sort(keys)
    
    result = {}
    table.insert(result, "A spreadsheet version of this list can be found on [" .. sheet .. " Google Sheets]<br/>")
    
    --hero table
    table.insert(result, '{| class="wikitable filterable sortable"')
    table.insert(result, '!class="unfilterable"|ID')
    table.insert(result, '!class="unfilterable"|Name')
    table.insert(result, '!class="unsortable unfilterable"|Image')
    table.insert(result, '!class="unsortable"|Rarity')
    table.insert(result, '!class="unsortable"|Faction')
    table.insert(result, '!class="unsortable"|Gender')
    table.insert(result, '!class="unsortable"|Type')
    for k, t in ipairs(keys) do
        table.insert(result, '|-')
        table.insert(result, "|'''" .. data[t].id .. "'''")
        table.insert(result, "|'''[[" .. t .. "]]'''")
        if (not data[t].image) or data[t].image == "" then
        	table.insert(result, "|[[File:Icon_question.png|80px]]")
        else
        	table.insert(result, "|[[File:" .. data[t].image .. "|80px]]")
        end
        table.insert(result, "|" .. mw.getCurrentFrame():expandTemplate{title='Icon', args = { data[t].rarity, link='yes', linebreak='yes', align='center'}})
        table.insert(result, "|" .. mw.getCurrentFrame():expandTemplate{title='Icon', args = { data[t].alignment, link='yes', linebreak='yes', align='center'}})
        table.insert(result, "|" .. mw.getCurrentFrame():expandTemplate{title='Icon', args = { data[t].gender, link='yes', linebreak='yes', align='center'}})
        table.insert(result, "|" .. mw.getCurrentFrame():expandTemplate{title='Icon', args = { data[t].type, link='yes', linebreak='yes', align='center'}})
    end
    table.insert(result, "|}")
    return table.concat(result, '\n')
end

function p.herodescriptions()
	--sort the hero table
    keys = {}
    for k in pairs(data) do
        table.insert(keys, k)
    end
    table.sort(keys)
    
    result = {}
    table.insert(result, "A spreadsheet version of this list can be found on [" .. sheet .. " Google Sheets]<br/>")
    
    --hero table
    table.insert(result, '{| class="wikitable filterable sortable"')
    table.insert(result, '!class="unfilterable"|ID')
    table.insert(result, '!class="unfilterable"|Name')
    table.insert(result, '!class="unsortable unfilterable"|Image')
    table.insert(result, '!class="unsortable"|Rarity')
    table.insert(result, '!class="unsortable"|Faction')
    table.insert(result, '!class="unsortable"|Gender')
    table.insert(result, '!class="unsortable"|Type')
    table.insert(result, '!class="unsortable"|Description')
    for k, t in ipairs(keys) do
        table.insert(result, '|-')
        table.insert(result, "|'''" .. data[t].id .. "'''")
        table.insert(result, "|'''[[" .. t .. "]]'''")
        if (not data[t].image) or data[t].image == "" then
        	table.insert(result, "|[[File:Icon_question.png|80px]]")
        else
        	table.insert(result, "|[[File:" .. data[t].image .. "|80px]]")
        end
        table.insert(result, "|" .. mw.getCurrentFrame():expandTemplate{title='Icon', args = { data[t].rarity, link='yes', linebreak='yes', align='center'}})
        table.insert(result, "|" .. mw.getCurrentFrame():expandTemplate{title='Icon', args = { data[t].alignment, link='yes', linebreak='yes', align='center'}})
        table.insert(result, "|" .. mw.getCurrentFrame():expandTemplate{title='Icon', args = { data[t].gender, link='yes', linebreak='yes', align='center'}})
        table.insert(result, "|" .. mw.getCurrentFrame():expandTemplate{title='Icon', args = { data[t].type, link='yes', linebreak='yes', align='center'}})
        table.insert(result, "|" .. data[t].quote)
    end
    table.insert(result, "|}")
    return table.concat(result, '\n')
end

function p.heroevolvelist()
	--sort the hero table
    keys = {}
    for k in pairs(data) do
        table.insert(keys, k)
    end
    table.sort(keys)
    
    result = "A spreadsheet version of this list can be found on [" .. sheet .. " Google Sheets]<br/>\n"
    
    --hero table
    result = result .. '{| class="wikitable filterable sortable"\n'
    result = result .. '!class="unfilterable"|ID\n'
    result = result .. '!class="unfilterable"|Name\n'
    result = result .. '!class="unsortable unfilterable"|Image\n'
    result = result .. '!class="unfilterable"|Evolves From\n'
    result = result .. '!class="unfilterable"|Evolves To\n'
    for k, t in ipairs(keys) do
        result = result .. '|-\n'
        result = result .. "|'''" .. data[t].id .. "'''\n"
        result = result .. "|'''" .. mw.getCurrentFrame():expandTemplate{title='tooltip', args = { t }} .. "'''" .. '\n'
        if (not data[t].image) or data[t].image == "" then
        	result = result .. "|[[File:Icon_question.png|80px]]\n"
        else
        	result = result .. "|[[File:" .. data[t].image .. "|80px]]\n"
        end
    	if (not data[t].evolves_from) then
    		result = result .. '| -\n'
    	else       
	    	if (not data[t].evolves_from[1]) or (data[t].evolves_from[1] == "") then
	    		result = result .. '| -'
	    	else
	    		result = result .. "|" .. mw.getCurrentFrame():expandTemplate{title='tooltip', args = { data[t].evolves_from[1] }}
		    	if (data[t].evolves_from[2]) and (data[t].evolves_from[2] ~= "") then 
		    		result = result .. "<br>" .. mw.getCurrentFrame():expandTemplate{title='tooltip', args = { data[t].evolves_from[2] }}
		    	end
		    	if (data[t].evolves_from[3]) and (data[t].evolves_from[3] ~= "") then
		    		result = result .. "<br>" .. mw.getCurrentFrame():expandTemplate{title='tooltip', args = { data[t].evolves_from[3] }}
			    end    
			end
			result = result .. '\n'
	    end  
    	if (not data[t].evolves_to) then
    		result = result .. '| -\n'
    	else       
	    	if (not data[t].evolves_to[1]) or (data[t].evolves_to[1] == "") then
	    		result = result .. '| -'
	    	else         		
	    		result = result .. "|" .. mw.getCurrentFrame():expandTemplate{title='tooltip', args = { data[t].evolves_to[1] }}
		    	if (data[t].evolves_to[2]) and (data[t].evolves_to[2] ~= "") then 
		    		result = result .. "<br>" .. mw.getCurrentFrame():expandTemplate{title='tooltip', args = { data[t].evolves_to[2] }}
		    	end
		    	if (data[t].evolves_to[3]) and (data[t].evolves_to[3] ~= "") then
		    		result = result .. "<br>" .. mw.getCurrentFrame():expandTemplate{title='tooltip', args = { data[t].evolves_to[3] }}
			    end 
			end
			result = result .. '\n'
	    end  
    end
    result = result .. "|}"  
    return result
end

function p.heroeventlist()
    local getHeroData = require ('Module:Hero/getData')
    
	--sort the hero table
    keys = {}
    for k in pairs(data) do
        table.insert(keys, k)
    end
    table.sort(keys)
    
    --hero table
    result = '{| class="wikitable filterable sortable"\n'
    result = result .. '!class="unfilterable"|ID\n'
    result = result .. '!class="unfilterable"|Name\n'
    result = result .. '!class="unsortable unfilterable"|Image\n'
    result = result .. '!Unlock\n'
    result = result .. '!Release Event\n'
    result = result .. '!class="unfilterable"|Release Date\n'
    result = result .. '!Last Event\n'
    result = result .. '!class="unfilterable"|Last Event Date\n'
    for k, t in ipairs(keys) do
        result = result .. '|-\n'
        result = result .. "|'''" .. data[t].id .. "'''\n"
        result = result .. "|'''" .. mw.getCurrentFrame():expandTemplate{title='tooltip', args = { t }} .. "'''" .. '\n'
        if (not data[t].image) or data[t].image == "" then
        	result = result .. "|[[File:Icon_question.png|80px]]\n"
        else
        	result = result .. "|[[File:" .. data[t].image .. "|80px]]\n"
        end
        if (not data[t].league) or data[t].league == -1 then
        	result = result .. "|[[Global Events|Event Hero]]\n"
        else
        	result = result .. "|[[League|League " .. data[t].league .. ']]\n'
        end
        if data[t].release_event then
        	result = result .. "|[[" .. data[t].release_event .. ']]\n'
        else
        	result = result .. "| -\n"
        end
        if data[t].release_date then
        	result = result .. "|" .. data[t].release_date .. '\n'
        else
        	result = result .. "| -\n"
        end
        if getHeroData["last_event"](t) ~= 'N/A' then
        	result = result .. "|" .. getHeroData["last_event"](t) .. '\n'
        	result = result .. "|" .. string.sub(getHeroData["last_event_key"](t),1,4) .. '-' .. string.sub(getHeroData["last_event_key"](t),5,6) .. '-' .. string.sub(getHeroData["last_event_key"](t),7,8) .. '\n'
        else
        	result = result .. "| -\n"
        	result = result .. "| -\n"
        end
    end
    result = result .. "|}"  
    return result
end

function p.customstatslist(frame)
    local getHeroData = require ('Module:Hero/getData')
	local level = frame.args['level'] or frame.args[1] or 1
	local reborn = frame.args['reborn'] or frame.args[2] or 0
	
	--sort the hero table
    keys = {}
    for k in pairs(data) do
    	if (data[k].rarity == "legendary") then
        	table.insert(keys, k)
        end
    end
    table.sort(keys)
    
    --hero table
    result = '{| class="wikitable filterable sortable" style="text-align:center;"\n'
    result = result .. '!rowspan="2" class="unfilterable"|ID\n'
    result = result .. '!rowspan="2" class="unfilterable"|Name\n'
    result = result .. '!rowspan="2" class="unsortable unfilterable"|Image\n'
    result = result .. '!rowspan="2" class="unsortable"|Faction\n'
    result = result .. '!rowspan="2" class="unsortable"|Gender\n'
    result = result .. '!rowspan="2" class="unsortable"|Type\n'
    result = result .. '!colspan="2" class="unsortable unfilterable"|Level ' .. level .. ' Reborn ' .. reborn .. '<br/>Including [[Soulbind|Soulbinds]]\n'
    result = result .. '|-\n'
    result = result .. '!width = "100px" class="unfilterable"|' .. mw.getCurrentFrame():expandTemplate{title='Icon', args = { 'attack', link='yes', linebreak='yes', align='center'}} .. '\n'
    result = result .. '!width = "100px" class="unfilterable"|' .. mw.getCurrentFrame():expandTemplate{title='Icon', args = { 'hp', link='yes', linebreak='yes', align='center'}} .. '\n'
    for k, t in ipairs(keys) do
        result = result .. '|-\n'
        result = result .. "|'''" .. data[t].id .. "'''\n"
        result = result .. '|style="text-align:center;"' .. "|'''" .. mw.getCurrentFrame():expandTemplate{title='tooltip', args = { t, level, reborn }} .. "'''" .. '\n'
        if (not data[t].image) or data[t].image == "" then
        	result = result .. "|[[File:Icon_question.png|80px]]\n"
        else
        	result = result .. "|[[File:" .. data[t].image .. "|80px]]\n"
        end
        result = result .. "|" .. data[t].alignment .. '\n'
        result = result .. "|" .. data[t].gender .. '\n'
        result = result .. "|" .. data[t].type .. '\n'
	    --soulbinds
	    local soulbindatk = (getHeroData["soulbind1_atk"](t) or 0) + (getHeroData["soulbind2_atk"](t) or 0) + (getHeroData["soulbind3_atk"](t) or 0) + (getHeroData["soulbind4_atk"](t) or 0)
	    local soulbindhp = (getHeroData["soulbind1_hp"](t) or 0) + (getHeroData["soulbind2_hp"](t) or 0) + (getHeroData["soulbind3_hp"](t) or 0) + (getHeroData["soulbind4_hp"](t) or 0)
        result = result .. "|" .. getHeroData["level_info"](t,tostring(level),tostring(reborn),"atk") + soulbindatk .. '\n'
        result = result .. "|" .. getHeroData["level_info"](t,tostring(level),tostring(reborn),"hp") + soulbindhp .. "\n"
    end
    result = result .. "|}"  
    return result
end


function p.heroeswithdebuffs(frame)
    local getHeroData = require ('Module:Hero/getData')
    result = '{| class="wikitable sortable" style="text-align:center;"\n'
    result = result .. '!ID\n'
    result = result .. '!name\n'
    result = result .. '!level\n'
    result = result .. '!type\n'
	
	--sort the hero table
    keys = {}
    for k in pairs(data) do
        table.insert(keys, k)
    end
    table.sort(keys)
    
    for k, hero in ipairs(keys) do
    	local maxlevel = 30;
    	if getHeroData["rarity"](hero) == "common" then
	    	maxlevel = 25;
	    end
	    for level = 1,maxlevel,1 do
	    	--local nextlevel=level+1
	    	local atkbefore = tonumber(getHeroData["level_info"](hero,tostring(level),"0","atk"))
	    	local atkafter = tonumber(getHeroData["level_info"](hero,tostring(level+1),"0","atk"))
	    	if atkafter<atkbefore then
	    		result = result .. "|-\n|" .. data[hero].id .. '\n|' .. hero .. '\n|' .. tostring(level) .. "\n|atk\n"
	    	end
	    	local hpbefore = tonumber(getHeroData["level_info"](hero,tostring(level),"0","hp"))
	    	local hpafter = tonumber(getHeroData["level_info"](hero,tostring(level+1),"0","hp"))
	    	if hpafter<hpbefore then
	    		result = result .. "|-\n|" .. data[hero].id .. '\n|' .. hero .. '\n|' .. tostring(level) .. "\n|hp\n"
	    	end
	    	
	    	local skillbefore = tonumber( data[hero].level[tostring(level)].skill1 ) or 0
	    	local skillafter = tonumber( data[hero].level[tostring(level+1)].skill1 ) or 0
	    	if skillafter<skillbefore then
	    		result = result .. "|-\n|" .. data[hero].id .. '\n|' .. hero .. '\n|' .. tostring(level) .. "\n|skill 1\n"
	    	end
	    	skillbefore = tonumber( data[hero].level[tostring(level)].skill2 ) or 0
	    	skillafter = tonumber( data[hero].level[tostring(level+1)].skill2 ) or 0
	    	if skillafter<skillbefore then
	    		result = result .. "|-\n|" .. data[hero].id .. '\n|' .. hero .. '\n|' .. tostring(level) .. "\n|skill 2\n"
	    	end
	    	skillbefore = tonumber( data[hero].level[tostring(level)].skill3 ) or 0
	    	skillafter = tonumber( data[hero].level[tostring(level+1)].skill3 ) or 0
	    	if skillafter<skillbefore then
	    		result = result .. "|-\n|" .. data[hero].id .. '\n|' .. hero .. '\n|' .. tostring(level) .. "\n|skill 3\n"
	    	end
	    	skillbefore = tonumber( data[hero].level[tostring(level)].skill4 ) or 0
	    	skillafter = tonumber( data[hero].level[tostring(level+1)].skill4 ) or 0
	    	if skillafter<skillbefore then
	    		result = result .. "|-\n|" .. data[hero].id .. '\n|' .. hero .. '\n|' .. tostring(level) .. "\n|skill 4\n"
	    	end
    		
	    end
    end
    result = result .. "|}"  
    return result
end

function p.herostatslist(frame)
    local getHeroData = require ('Module:Hero/getData')
	--local level = frame.args['level'] or frame.args[1]
	--local reborn = frame.args['reborn'] or frame.args[2]
	
	--sort the hero table
    keys = {}
    for k in pairs(data) do
        table.insert(keys, k)
    end
    table.sort(keys)
    
    --hero table
    result = '{| class="wikitable filterable sortable" style="text-align:center;"\n'
    result = result .. '!rowspan="2" class="unfilterable"|ID\n'
    result = result .. '!rowspan="2" class="unfilterable"|Name\n'
    result = result .. '!rowspan="2" class="unsortable unfilterable"|Image\n'
    result = result .. '!rowspan="2" class="unsortable"|Rarity\n'
    result = result .. '!rowspan="2" class="unsortable"|Faction\n'
    result = result .. '!rowspan="2" class="unsortable"|Gender\n'
    result = result .. '!rowspan="2" class="unsortable"|Type\n'
    result = result .. '!colspan="2" class="unsortable unfilterable"|Initial<br/>(Level 1 Reborn 0)\n'
    result = result .. '!colspan="2" class="unsortable unfilterable"|Max<br/>(Level 31/26 Reborn 6/4<br/>Including [[Soulbind|Soulbinds]])\n'
    result = result .. '|-\n'
    result = result .. '!width = "100px" class="unfilterable"|' .. mw.getCurrentFrame():expandTemplate{title='Icon', args = { 'attack', link='yes', linebreak='yes', align='center'}} .. '\n'
    result = result .. '!width = "100px" class="unfilterable"|' .. mw.getCurrentFrame():expandTemplate{title='Icon', args = { 'hp', link='yes', linebreak='yes', align='center'}} .. '\n'
    result = result .. '!width = "100px" class="unfilterable"|' .. mw.getCurrentFrame():expandTemplate{title='Icon', args = { 'attack', link='yes', linebreak='yes', align='center'}} .. '\n'
    result = result .. '!width = "100px" class="unfilterable"|' .. mw.getCurrentFrame():expandTemplate{title='Icon', args = { 'hp', link='yes', linebreak='yes', align='center'}} .. '\n'
    for k, t in ipairs(keys) do
        result = result .. '|-\n'
        result = result .. "|'''" .. data[t].id .. "'''\n"
        result = result .. '|style="text-align:center;"' .. "|'''" .. mw.getCurrentFrame():expandTemplate{title='tooltip', args = { t }} .. "'''" .. '\n'
        if (not data[t].image) or data[t].image == "" then
        	result = result .. "|[[File:Icon_question.png|80px]]\n"
        else
        	result = result .. "|[[File:" .. data[t].image .. "|80px]]\n"
        end
        result = result .. "|" .. data[t].rarity .. '\n'
        result = result .. "|" .. data[t].alignment .. '\n'
        result = result .. "|" .. data[t].gender .. '\n'
        result = result .. "|" .. data[t].type .. '\n'
        result = result .. "|" .. getHeroData["level_info"](t,"1","0","atk") .. '\n'
        result = result .. "|" .. getHeroData["level_info"](t,"1","0","hp") .. "\n"
	    --soulbinds
	    local soulbindatk = (getHeroData["soulbind1_atk"](t) or 0) + (getHeroData["soulbind2_atk"](t) or 0) + (getHeroData["soulbind3_atk"](t) or 0) + (getHeroData["soulbind4_atk"](t) or 0)
	    local soulbindhp = (getHeroData["soulbind1_hp"](t) or 0) + (getHeroData["soulbind2_hp"](t) or 0) + (getHeroData["soulbind3_hp"](t) or 0) + (getHeroData["soulbind4_hp"](t) or 0)
        result = result .. "|" .. getHeroData["level_info"](t,"31","6","atk") + soulbindatk .. '\n'
        result = result .. "|" .. getHeroData["level_info"](t,"31","6","hp") + soulbindhp .. "\n"
    end
    result = result .. "|}"  
    return result
end

function p.heroesbycategory(frame)
	local category = frame.args['category'] or frame.args[1]

	--get a list of aliases
	category = category:match('^%s*(.-)%s*$'):lower() -- trim whitespace and put in lower case
	local parent = category
	local aliases = parent

	for j in pairs(icondata) do
		if j == category then
			if (icondata[parent].parent) then
				parent = icondata[parent].parent
				aliases = parent
			end
			
		    for k in pairs(icondata) do
		    	if (icondata[k].parent == parent) then 
		    		aliases = aliases .. ',' .. k
		    	end
		    end
		end
	end	
	
	--sort the hero table
    keys = {}
    for k in pairs(data) do
    	local skill1 = data[k].skill1 or "noskill"
    	local skill2 = data[k].skill2 or "noskill"
    	local skill3 = data[k].skill3 or "noskill"
    	local skill4 = data[k].skill4 or "noskill"
    	if (data[k].rarity == category) 
    	or (data[k].alignment == category) 
    	or (data[k].gender == category) 
    	or (data[k].type == category) 
    	or string.match(aliases, '%f[%a]' .. skill1 .. '%f[%A]') 
    	or string.match(aliases, '%f[%a]' .. skill2 .. '%f[%A]') 
    	or string.match(aliases, '%f[%a]' .. skill3 .. '%f[%A]') 
    	or string.match(aliases, '%f[%a]' .. skill4 .. '%f[%A]') then
        	table.insert(keys, k)
        end
    end
    table.sort(keys)
    
    result = ""
    --hero table
    result = result .. '{| class="wikitable filterable sortable"\n'
    result = result .. '!class="unfilterable"|ID\n'
    result = result .. '!class="unfilterable"|Name\n'
    result = result .. '!class="unsortable unfilterable"|Image\n'
    result = result .. '!class="unsortable"|Rarity\n'
    result = result .. '!class="unsortable"|Faction\n'
    result = result .. '!class="unsortable"|Gender\n'
    result = result .. '!class="unsortable"|Type\n'
    result = result .. '!class="unsortable unfilterable"|Skills\n'
    for k, t in ipairs(keys) do
        result = result .. '|-\n'
        result = result .. "|'''" .. data[t].id .. "'''\n"
        result = result .. "|'''" .. mw.getCurrentFrame():expandTemplate{title='tooltip', args = { t }} .. "'''" .. '\n'
        if (not data[t].image) or data[t].image == "" then
        	result = result .. "|align=\"center\"|[[File:Icon_question.png|80px]]\n"
        else
        	result = result .. "|align=\"center\"|[[File:" .. data[t].image .. "|80px]]\n"
        end
        result = result .. "|" .. mw.getCurrentFrame():expandTemplate{title='Icon', args = { data[t].rarity, link='yes', linebreak='yes', align='center'}} .. '\n'
        result = result .. "|" .. mw.getCurrentFrame():expandTemplate{title='Icon', args = { data[t].alignment, link='yes', linebreak='yes', align='center'}} .. '\n'
        result = result .. "|" .. mw.getCurrentFrame():expandTemplate{title='Icon', args = { data[t].gender, link='yes', linebreak='yes', align='center'}} .. '\n'
        result = result .. "|" .. mw.getCurrentFrame():expandTemplate{title='Icon', args = { data[t].type, link='yes', linebreak='yes', align='center'}} .. '\n'
--skill logic
		result = result .. '|'
        if (data[t].skill1) and (data[t].skill1 ~= "") then
    		result = result .. "<div style=\"display:inline-block\" class=\"advanced-tooltip\">" .. mw.getCurrentFrame():expandTemplate{title='Icon', args = { data[t].skill1, link='yes'}} .. "<div class=\"tooltip-contents\">" 
    		if (data[t].skill1_unlock) and (data[t].skill1_unlock ~= "") then
    			result = result .. mw.getCurrentFrame():preprocess(string.format(data[t].skill1_desc, data[t].level[tostring(data[t].skill1_unlock)].skill1))
    		else
    			if (data[t].level["1"].skill1) and (data[t].level["1"].skill1 ~= "") then
    				result = result .. mw.getCurrentFrame():preprocess(string.format(data[t].skill1_desc, data[t].level["1"].skill1))
    			else
    				result = result .. mw.getCurrentFrame():preprocess(data[t].skill1_desc)
    			end
    		end
    		result = result .. "</div></div>"
    	end
        if (data[t].skill2) and (data[t].skill2 ~= "") then
    		result = result .. "<br><div style=\"display:inline-block\" class=\"advanced-tooltip\">" .. mw.getCurrentFrame():expandTemplate{title='Icon', args = { data[t].skill2, link='yes'}} .. "<div class=\"tooltip-contents\">"
    		if (data[t].skill2_unlock) and (data[t].skill2_unlock ~= "") then
    			result = result .. mw.getCurrentFrame():preprocess(string.format(data[t].skill2_desc, data[t].level[tostring(data[t].skill2_unlock)].skill2))
    		else
    			if (data[t].level["1"].skill2) and (data[t].level["1"].skill2 ~= "") then
    				result = result .. mw.getCurrentFrame():preprocess(string.format(data[t].skill2_desc, data[t].level["1"].skill2))
    			else
    				result = result .. mw.getCurrentFrame():preprocess(data[t].skill2_desc)
    			end
    		end
    		result = result .. "</div></div>"
    	end
        if (data[t].skill3) and (data[t].skill3 ~= "") then
    		result = result .. "<br><div style=\"display:inline-block\" class=\"advanced-tooltip\">" .. mw.getCurrentFrame():expandTemplate{title='Icon', args = { data[t].skill3, link='yes'}} .. "<div class=\"tooltip-contents\">"
    		if (data[t].skill3_unlock) and (data[t].skill3_unlock ~= "") then
    			result = result .. mw.getCurrentFrame():preprocess(string.format(data[t].skill3_desc, data[t].level[tostring(data[t].skill3_unlock)].skill3))
    		else
    			if (data[t].level["1"].skill3) and (data[t].level["1"].skill3 ~= "") then
    				result = result .. mw.getCurrentFrame():preprocess(string.format(data[t].skill3_desc, data[t].level["1"].skill3))
    			else
    				result = result .. mw.getCurrentFrame():preprocess(data[t].skill3_desc)
    			end
    		end
    		result = result .. "</div></div>"
		end
        if (data[t].skill4) and (data[t].skill4 ~= "") then
    		result = result .. "<br><div style=\"display:inline-block\" class=\"advanced-tooltip\">" .. mw.getCurrentFrame():expandTemplate{title='Icon', args = { data[t].skill4, link='yes'}} .. "<div class=\"tooltip-contents\">"
    		if (data[t].skill4_unlock) and (data[t].skill4_unlock ~= "") then
    			result = result .. mw.getCurrentFrame():preprocess(string.format(data[t].skill4_desc, data[t].level[tostring(data[t].skill4_unlock)].skill4))
    		else
    			if (data[t].level["1"].skill4) and (data[t].level["1"].skill4 ~= "") then
    				result = result .. mw.getCurrentFrame():preprocess(string.format(data[t].skill4_desc, data[t].level["1"].skill4))
    			else
    				result = result .. mw.getCurrentFrame():preprocess(data[t].skill4_desc)
    			end
    		end
    		result = result .. "</div></div>"
    	end	
		result = result .. '\n'
    end
    result = result .. "|}"  
    return result	
end

function p.herosoulbindsbycategory(frame)
	local category = frame.args['category'] or frame.args[1]

	--get a list of aliases
	category = category:match('^%s*(.-)%s*$'):lower() -- trim whitespace and put in lower case
	local parent = category
	local aliases = parent

	for j in pairs(icondata) do
		if j == category then
			if (icondata[parent].parent) then
				parent = icondata[parent].parent
				aliases = parent
			end
			
		    for k in pairs(icondata) do
		    	if (icondata[k].parent == parent) then 
		    		aliases = aliases .. ',' .. k
		    	end
		    end
		end
	end	
	
	--sort the hero table
    keys = {}
    for k in pairs(data) do
    	local skill1 = data[k].skill1 or "noskill"
    	local skill2 = data[k].skill2 or "noskill"
    	local skill3 = data[k].skill3 or "noskill"
    	local skill4 = data[k].skill4 or "noskill"
    	if (data[k].rarity == category) 
    	or (data[k].alignment == category) 
    	or (data[k].gender == category) 
    	or (data[k].type == category) 
    	or string.match(aliases, '%f[%a]' .. skill1 .. '%f[%A]') 
    	or string.match(aliases, '%f[%a]' .. skill2 .. '%f[%A]') 
    	or string.match(aliases, '%f[%a]' .. skill3 .. '%f[%A]') 
    	or string.match(aliases, '%f[%a]' .. skill4 .. '%f[%A]') then
        	table.insert(keys, k)
        end
    end
    table.sort(keys)
    
    result = "A spreadsheet version of this list can be found on [" .. sheet .. " Google Sheets]<br/>\n"
    --hero table
    result = result .. '{| class="wikitable filterable sortable"\n'
    result = result .. '!rowspan="2" class="unfilterable"|ID\n'
    result = result .. '!rowspan="2" class="unfilterable"|Name\n'
    result = result .. '!rowspan="2" class="unfilterable"|Image\n'
    result = result .. '!colspan="4" class="unsortable unfilterable"|Soulbinds\n'    
    -- column for number of heroes requiring this hero for soulbind
    result = result .. '!rowspan="2" class ="unfilterable"|Req. for \n'
    result = result .. '|-\n'
    result = result .. '!class="unsortable unfilterable"|I'
    if (category == "legendary") or (category == "epic") or (category == "rare") or (category == "common") then
    	result = result .. "<br/>(Req. Level " .. mw.getCurrentFrame():expandTemplate{title='HeroConstants', args = { "soulbind", category, "1", "level" }} .. ")\n"
    else
    	result = result .. "\n"
    end
    result = result .. '!class="unsortable unfilterable"|II'
    if (category == "legendary") or (category == "epic") or (category == "rare") or (category == "common") then
    	result = result .. "<br/>(Req. Level " .. mw.getCurrentFrame():expandTemplate{title='HeroConstants', args = { "soulbind", category, "2", "level" }} .. ")\n"
    else
    	result = result .. "\n"
    end    
    result = result .. '!class="unsortable unfilterable"|III'
    if (category == "legendary") or (category == "epic") or (category == "rare") or (category == "common") then
    	result = result .. "<br/>(Req. Level " .. mw.getCurrentFrame():expandTemplate{title='HeroConstants', args = { "soulbind", category, "3", "level" }} .. ")\n"
    else
    	result = result .. "\n"
    end    
    result = result .. '!class="unsortable unfilterable"|IV'
    if (category == "legendary") or (category == "epic") or (category == "rare") or (category == "common") then
    	result = result .. "<br/>(Req. Level " .. mw.getCurrentFrame():expandTemplate{title='HeroConstants', args = { "soulbind", category, "4", "level" }} .. ")\n"
    else
    	result = result .. "\n"
    end
    for k, t in ipairs(keys) do
        result = result .. '|-\n'
        result = result .. "|'''" .. data[t].id .. "'''\n"
        result = result .. "|'''" .. mw.getCurrentFrame():expandTemplate{title='tooltip', args = { t }} .. "'''" .. '\n'
        if (not data[t].image) or data[t].image == "" then
        	result = result .. "|align=\"center\"|[[File:Icon_question.png|80px]]\n"
        else
        	result = result .. "|align=\"center\"|[[File:" .. data[t].image .. "|80px]]\n"
        end
		if data[t].soulbind1 then result = result .. '|<ul><li>' .. mw.getCurrentFrame():expandTemplate{title='tooltip', args = { data[t].soulbind1[1] }} .. '</li></ul>\n'
		else result = result .. '|\n' end
		if data[t].soulbind2 then result = result .. '|<ul><li>' .. mw.getCurrentFrame():expandTemplate{title='tooltip', args = { data[t].soulbind2[1] }} .. '</li><li>' .. mw.getCurrentFrame():expandTemplate{title='tooltip', args = { data[t].soulbind2[2] }} .. '</li></ul>\n' 
		else result = result .. '|\n' end
		if data[t].soulbind3 then result = result .. '|<ul><li>' .. mw.getCurrentFrame():expandTemplate{title='tooltip', args = { data[t].soulbind3[1] }} .. '</li><li>' .. mw.getCurrentFrame():expandTemplate{title='tooltip', args = { data[t].soulbind3[2] }} .. '</li></ul>\n' 
		else result = result .. '|\n' end
		if data[t].soulbind4 then result = result .. '|<ul><li>' .. mw.getCurrentFrame():expandTemplate{title='tooltip', args = { data[t].soulbind4[1] }} .. '</li><li>' .. mw.getCurrentFrame():expandTemplate{title='tooltip', args = { data[t].soulbind4[2] }} .. '</li><li>' .. mw.getCurrentFrame():expandTemplate{title='tooltip', args = { data[t].soulbind4[3] }} .. '</li></ul>\n' 
		else result = result .. '|\n' end
		-- count heroes requiring the given one
		nsamerarity = 0
		nlowerrarity = 0
		for l in pairs(data) do
	    	if (data[l].soulbind1[1] == t) 
    		or (data[l].soulbind2[1] == t) 
   			or (data[l].soulbind2[2] == t) 
   			or (data[l].soulbind3[1] == t) 
   			or (data[l].soulbind3[2] == t) 
    		or (data[l].soulbind4[1] == t) 
    		or (data[l].soulbind4[2] == t) 
   			or (data[l].soulbind4[3] == t) then
	       		if (data[l].rarity == category) then
	       			nsamerarity = nsamerarity+1
	       		else
	       			nlowerrarity = nlowerrarity+1
	       		end
       		end
		end
		-- display found numbers
		if category == "common" then
    		result = result .. "|" .. mw.getCurrentFrame():expandTemplate{title='Icon', args = { "common" }} .. nsamerarity .. "\n"
		elseif category == "rare" then
			result = result .. "|" .. mw.getCurrentFrame():expandTemplate{title='Icon', args = { "rare" }} .. nsamerarity
			result = result .. "<br/>" .. mw.getCurrentFrame():expandTemplate{title='Icon', args = { "common" }} .. nlowerrarity .. "\n"
		elseif category == "epic" then
			result = result .. "|" .. mw.getCurrentFrame():expandTemplate{title='Icon', args = { "epic" }} .. nsamerarity
			result = result .. "<br/>" .. mw.getCurrentFrame():expandTemplate{title='Icon', args = { "rare" }} .. nlowerrarity .. "\n"
		elseif category == "legendary" then
			result = result .. "|" .. mw.getCurrentFrame():expandTemplate{title='Icon', args = { "legendary" }} .. nsamerarity
			result = result .. "<br/>" .. mw.getCurrentFrame():expandTemplate{title='Icon', args = { "epic" }} .. nlowerrarity .. "\n"
    	end
    end
    result = result .. "|}"  
    return result
end

function p.herorequiredsoulbinds(frame)
	local hero = frame.args['hero'] or frame.args[1]
	
	--sort the hero table
    keys = {}
    for k in pairs(data) do
    	if (data[k].soulbind1[1] == hero) 
    	or (data[k].soulbind2[1] == hero) 
    	or (data[k].soulbind2[2] == hero) 
    	or (data[k].soulbind3[1] == hero) 
    	or (data[k].soulbind3[2] == hero) 
    	or (data[k].soulbind4[1] == hero) 
    	or (data[k].soulbind4[2] == hero) 
    	or (data[k].soulbind4[3] == hero) then
        	table.insert(keys, k)
        end
    end
    table.sort(keys)
    
    if table.getn(keys) == 0 then
		result = "[[" .. hero .. "]] is not required for any Soulbinds."
    else
	    --hero table
	    result = '{| class="wikitable filterable sortable"\n'
	    result = result .. '!rowspan="2" class="unfilterable"|ID\n'
	    result = result .. '!rowspan="2" class="unfilterable"|Name\n'
	    result = result .. '!rowspan="2" class="unfilterable"|Image\n'
	    result = result .. '!colspan="4" class="unsortable unfilterable"|Soulbinds\n'
	    result = result .. '|-\n'
	    result = result .. '!class="unsortable unfilterable"|I'
	    if (category == "legendary") or (category == "epic") or (category == "rare") or (category == "common") then
	    	result = result .. "<br/>(Req. Level " .. mw.getCurrentFrame():expandTemplate{title='HeroConstants', args = { "soulbind", category, "1", "level" }} .. ")\n"
	    else
	    	result = result .. "\n"
	    end
	    result = result .. '!class="unsortable unfilterable"|II'
	    if (category == "legendary") or (category == "epic") or (category == "rare") or (category == "common") then
	    	result = result .. "<br/>(Req. Level " .. mw.getCurrentFrame():expandTemplate{title='HeroConstants', args = { "soulbind", category, "2", "level" }} .. ")\n"
	    else
	    	result = result .. "\n"
	    end    
	    result = result .. '!class="unsortable unfilterable"|III'
	    if (category == "legendary") or (category == "epic") or (category == "rare") or (category == "common") then
	    	result = result .. "<br/>(Req. Level " .. mw.getCurrentFrame():expandTemplate{title='HeroConstants', args = { "soulbind", category, "3", "level" }} .. ")\n"
	    else
	    	result = result .. "\n"
	    end    
	    result = result .. '!class="unsortable unfilterable"|IV'
	    if (category == "legendary") or (category == "epic") or (category == "rare") or (category == "common") then
	    	result = result .. "<br/>(Req. Level " .. mw.getCurrentFrame():expandTemplate{title='HeroConstants', args = { "soulbind", category, "4", "level" }} .. ")\n"
	    else
	    	result = result .. "\n"
	    end    
	    for k, t in ipairs(keys) do
	        result = result .. '|-\n'
	        result = result .. "|'''" .. data[t].id .. "'''\n"
	        result = result .. "|'''" .. mw.getCurrentFrame():expandTemplate{title='tooltip', args = { t }} .. "'''\n"
	        if (not data[t].image) or data[t].image == "" then
	        	result = result .. "|align=\"center\"|[[File:Icon_question.png|80px]]\n"
	        else
	        	result = result .. "|align=\"center\"|[[File:" .. data[t].image .. "|80px]]\n"
	        end
			if data[t].soulbind1 then result = result .. '|<ul><li>' .. mw.getCurrentFrame():expandTemplate{title='tooltip', args = { data[t].soulbind1[1] }} .. '</li></ul>\n'
			else result = result .. '|\n' end
			if data[t].soulbind2 then result = result .. '|<ul><li>' .. mw.getCurrentFrame():expandTemplate{title='tooltip', args = { data[t].soulbind2[1] }} .. '</li><li>' .. mw.getCurrentFrame():expandTemplate{title='tooltip', args = { data[t].soulbind2[2] }} .. '</li></ul>\n' 
			else result = result .. '|\n' end
			if data[t].soulbind3 then result = result .. '|<ul><li>' .. mw.getCurrentFrame():expandTemplate{title='tooltip', args = { data[t].soulbind3[1] }} .. '</li><li>' .. mw.getCurrentFrame():expandTemplate{title='tooltip', args = { data[t].soulbind3[2] }} .. '</li></ul>\n' 
			else result = result .. '|\n' end
			if data[t].soulbind4 then result = result .. '|<ul><li>' .. mw.getCurrentFrame():expandTemplate{title='tooltip', args = { data[t].soulbind4[1] }} .. '</li><li>' .. mw.getCurrentFrame():expandTemplate{title='tooltip', args = { data[t].soulbind4[2] }} .. '</li><li>' .. mw.getCurrentFrame():expandTemplate{title='tooltip', args = { data[t].soulbind4[3] }} .. '</li></ul>\n' 
			else result = result .. '|\n' end
		end
		result = result .. "|}"  
	end
    return result
end

function p.countheroesincategory(frame)
	local category1 = frame.args['category1'] or frame.args[1]
	local category2 = frame.args['category2'] or frame.args[2]
	local category3 = frame.args['category3'] or frame.args[3]
	local category4 = frame.args['category4'] or frame.args[4]
	
	--sort the hero table
    keys = {}
    for k in pairs(data) do
    	if ((category1 == null)
    	or (data[k].rarity == category1) 
    	or (data[k].alignment == category1) 
    	or (data[k].gender == category1) 
    	or (data[k].type == category1))
    	and ((category2 == null)
    	or (data[k].rarity == category2) 
    	or (data[k].alignment == category2) 
    	or (data[k].gender == category2) 
    	or (data[k].type == category2))
    	and ((category3 == null)
    	or (data[k].rarity == category3) 
    	or (data[k].alignment == category3) 
    	or (data[k].gender == category3) 
    	or (data[k].type == category3))
    	and ((category4 == null)
    	or (data[k].rarity == category4) 
    	or (data[k].alignment == category4) 
    	or (data[k].gender == category4) 
    	or (data[k].type == category4)) then
        	table.insert(keys, k)
        end
    end
    
	local count = 0
	for _ in pairs(keys) do count = count + 1 end
	return count
end


function p.herostats(frame)
	local getHeroData = require ('Module:Hero/getData')
	local hero = frame.args['hero'] or frame.args[1]
	local reborn = frame.args['reborn'] or frame.args[2] or "0"
    local maxlevel = 31;
    if getHeroData["rarity"](hero) == "common" then
    	maxlevel = 26;
    end
	
    --hero table
    result = '{| class="wikitable" width="100%" style="text-align:center;"\n'
    result = result .. '!style="width:75px"|Level\n'
    result = result .. '!' .. mw.getCurrentFrame():expandTemplate{title='Icon', args = { 'atk', link='yes', linebreak='yes', align='center'}} .. '\n'
    result = result .. '!' .. mw.getCurrentFrame():expandTemplate{title='Icon', args = { 'hp', link='yes', linebreak='yes', align='center'}} .. '\n'
    result = result .. '!Bonus\n'
    result = result .. '![[Might]]\n'
    -- result = result .. '![[Troops]]\n' 
    -- troops not used anymore
    result = result .. '!Required<br>[[League]]\n'
    result = result .. '!Level [[Hero Level Table|Required]]<br>[[Souls]] and [[Gold]]\n'
    result = result .. '!Total [[Hero Level Table|Required]]<br>[[Souls]] and [[Gold]]\n'
    result = result .. '|-'
    for i=1,maxlevel,1 do
        result = result .. '|-\n'
        result = result .. "!" .. i
        if i == 1 or i == 6 or i == 11 or i == 16 or i == 21 or i == 26 or i == 31 then
        	result = result .. "<br/>(" .. (i-1)/5+1 ..  mw.getCurrentFrame():expandTemplate{title='Icon', args = { 'star' }} .. ")"
        end
        result = result .. "\n"
        result = result .. "|" .. getHeroData["level_info"](hero,tostring(i),reborn,"atk") .. mw.getCurrentFrame():expandTemplate{title='Icon', args = { 'atk' }} .. '\n'
        result = result .. "|" .. getHeroData["level_info"](hero,tostring(i),reborn,"hp") .. mw.getCurrentFrame():expandTemplate{title='Icon', args = { 'hp' }} .. '\n'
        result = result .. "|" 
        if i > 1 then 
        	if getHeroData["level_info"](hero,tostring(i),reborn,"atk") ~= getHeroData["level_info"](hero,tostring(i-1),reborn,"atk") then
        		result = result .. " +" .. getHeroData["level_info"](hero,tostring(i),reborn,"atk") - getHeroData["level_info"](hero,tostring(i-1),reborn,"atk") .. mw.getCurrentFrame():expandTemplate{title='Icon', args = { 'atk' }} .. "<br/>"
        	end
        	if getHeroData["level_info"](hero,tostring(i),reborn,"hp") ~= getHeroData["level_info"](hero,tostring(i-1),reborn,"hp") then
        		result = result .. " +" .. getHeroData["level_info"](hero,tostring(i),reborn,"hp") - getHeroData["level_info"](hero,tostring(i-1),reborn,"hp") .. mw.getCurrentFrame():expandTemplate{title='Icon', args = { 'hp' }} .. "<br/>"
        	end
        	if getHeroData["skill1"](hero) 
        	and getHeroData["level_info"](hero,tostring(i-1),reborn,"skill1")
        	and getHeroData["level_info"](hero,tostring(i),reborn,"skill1") ~= getHeroData["level_info"](hero,tostring(i-1),reborn,"skill1")
        	then
        		local prior = getHeroData["level_info"](hero,tostring(i-1),reborn,"skill1")
        		if prior == "" then prior = 0 end
        		if tonumber(prior) == nil then
        			result = result .. 	"Skill 1: " .. getHeroData["level_info"](hero,tostring(i),reborn,"skill1") .. mw.getCurrentFrame():expandTemplate{title='Icon', args = { getHeroData["skill1"](hero) }} .. "<br/>"
        		else
        			result = result .. "Skill 1: +" .. getHeroData["level_info"](hero,tostring(i),reborn,"skill1") - prior .. mw.getCurrentFrame():expandTemplate{title='Icon', args = { getHeroData["skill1"](hero) }} .. "<br/>"
        		end
        	end
        	if getHeroData["skill2"](hero) 
        	and getHeroData["level_info"](hero,tostring(i-1),reborn,"skill2")
        	and getHeroData["level_info"](hero,tostring(i),reborn,"skill2") ~= getHeroData["level_info"](hero,tostring(i-1),reborn,"skill2")
        	then
        		local prior = getHeroData["level_info"](hero,tostring(i-1),reborn,"skill2")
        		if prior == "" then prior = 0 end
        		if tonumber(prior) == nil then
        			result = result .. "Skill 2: " .. getHeroData["level_info"](hero,tostring(i),reborn,"skill2") .. mw.getCurrentFrame():expandTemplate{title='Icon', args = { getHeroData["skill2"](hero) }} .. "<br/>"
        		else
        			result = result .. "Skill 2: +" .. getHeroData["level_info"](hero,tostring(i),reborn,"skill2") - prior .. mw.getCurrentFrame():expandTemplate{title='Icon', args = { getHeroData["skill2"](hero) }} .. "<br/>"
        		end
        	end
        	if getHeroData["skill3"](hero) 
        	and getHeroData["level_info"](hero,tostring(i-1),reborn,"skill3")
        	and getHeroData["level_info"](hero,tostring(i),reborn,"skill3") ~= getHeroData["level_info"](hero,tostring(i-1),reborn,"skill3")
        	then
        		local prior = getHeroData["level_info"](hero,tostring(i-1),reborn,"skill3")
        		if prior == "" then prior = 0 end
        		if tonumber(prior) == nil then
        			result = result .. "Skill 3: " .. getHeroData["level_info"](hero,tostring(i),reborn,"skill3") .. mw.getCurrentFrame():expandTemplate{title='Icon', args = { getHeroData["skill3"](hero) }} .. "<br/>"
        		else
        			result = result .. "Skill 3: +" .. getHeroData["level_info"](hero,tostring(i),reborn,"skill3") - prior .. mw.getCurrentFrame():expandTemplate{title='Icon', args = { getHeroData["skill3"](hero) }} .. "<br/>"
        		end
        	end
        	if getHeroData["skill4"](hero) 
        	and getHeroData["level_info"](hero,tostring(i-1),reborn,"skill4")
        	and getHeroData["level_info"](hero,tostring(i),reborn,"skill4") ~= getHeroData["level_info"](hero,tostring(i-1),reborn,"skill4")
        	then
        		local prior = getHeroData["level_info"](hero,tostring(i-1),reborn,"skill4")
        		if prior == "" then prior = 0 end
        		if tonumber(prior) == nil then
        			result = result .. "Skill 4: " .. getHeroData["level_info"](hero,tostring(i),reborn,"skill4") .. mw.getCurrentFrame():expandTemplate{title='Icon', args = { getHeroData["skill4"](hero) }} .. "<br/>"
        		else
        			result = result .. "Skill 4: +" .. getHeroData["level_info"](hero,tostring(i),reborn,"skill4") - prior .. mw.getCurrentFrame():expandTemplate{title='Icon', args = { getHeroData["skill4"](hero) }} .. "<br/>"
        		end
        	end
        else
        	if reborn == "0" then
        		result = result .. " -"
        	else
        		if getHeroData["reborn"..reborn.."_atk"](hero,tostring(reborn)) ~= nil and getHeroData["reborn"..reborn.."_atk"](hero,tostring(reborn)) ~= "" then
        			result = result .. " +" .. getHeroData["reborn"..reborn.."_atk"](hero,tostring(reborn)) .. mw.getCurrentFrame():expandTemplate{title='Icon', args = { 'atk' }} .. "<br/>" 
        		end
        		if getHeroData["reborn"..reborn.."_hp"](hero,tostring(reborn)) ~= nil and getHeroData["reborn"..reborn.."_hp"](hero,tostring(reborn)) ~= "" then
        			result = result .. " +" .. getHeroData["reborn"..reborn.."_hp"](hero,tostring(reborn)) .. mw.getCurrentFrame():expandTemplate{title='Icon', args = { 'hp' }} .. "<br/>" 
        		end
        		if getHeroData["reborn"..reborn.."_skill"](hero,tostring(reborn)) ~= nil and getHeroData["reborn"..reborn.."_skill"](hero,tostring(reborn)) ~= "" then
        			result = result .. getHeroData["reborn"..reborn.."_skill"](hero,tostring(reborn))
        		end
        	end
        end
        result = result .. '\n'
        if reborn == "0" then
        	result = result .. '|' .. constants["might"][getHeroData["rarity"](hero)][tostring(i)] .. '\n'
        	--result = result .. '|' .. constants["troops"][getHeroData["rarity"](hero)][tostring(i)] .. '\n'
        else
        	local rebornmight = 0
        	--local reborntroops = 0
        	local reborncount = tonumber(reborn)
        	while reborncount > 0 do
        		rebornmight = rebornmight + constants["reborn"][tostring(reborncount)][getHeroData["rarity"](hero)]["might"]	
        		--reborntroops = reborntroops + constants["reborn"][tostring(reborncount)][getHeroData["rarity"](hero)]["troops"]
        		reborncount = reborncount - 1
        	end
        	result = result .. '|' .. constants["might"][getHeroData["rarity"](hero)][tostring(i)] + rebornmight .. '\n'
        	--result = result .. '|' .. constants["troops"][getHeroData["rarity"](hero)][tostring(i)] + reborntroops .. '\n'
        end
        if i > 1 then
	        result = result .. '|' .. constants["leveling"]["league"][getHeroData["rarity"](hero)][tostring(i)] .. '\n'
	        result = result .. '|' .. constants["leveling"]["souls"][getHeroData["rarity"](hero)][tostring(i)] - constants["leveling"]["souls"][getHeroData["rarity"](hero)][tostring(i-1)] .. mw.getCurrentFrame():expandTemplate{title='Icon', args = { getHeroData["rarity"](hero) }} .. "<br\>" .. constants["leveling"]["gold"][getHeroData["rarity"](hero)][tostring(i)] - constants["leveling"]["gold"][getHeroData["rarity"](hero)][tostring(i-1)] .. mw.getCurrentFrame():expandTemplate{title='Icon', args = { "gold" }} .. '\n'
	        result = result .. '|' .. constants["leveling"]["souls"][getHeroData["rarity"](hero)][tostring(i)] .. mw.getCurrentFrame():expandTemplate{title='Icon', args = { getHeroData["rarity"](hero) }} .. "<br\>" .. constants["leveling"]["gold"][getHeroData["rarity"](hero)][tostring(i)] .. mw.getCurrentFrame():expandTemplate{title='Icon', args = { "gold" }} .. '\n'
	    else
	    	result = result .. '| -\n' 
	    	result = result .. '| -\n' 
	    	result = result .. '| -\n' 
	    end
	end
	result = result .. "|}"  
    return result
end


function p.heroskills(frame)
	local getHeroData = require ('Module:Hero/getData')
	local hero = frame.args['hero'] or frame.args[1]
	local reborn = frame.args['reborn'] or frame.args[2] or "0"
    local maxlevel = 31;
    if getHeroData["rarity"](hero) == "common" then
    	maxlevel = 26;
    end
	
    --hero table
    result = '{| class="wikitable" width="100%" style="text-align:center;"\n'
    result = result .. '!style="width:75px"|Level\n'
    if getHeroData["skill1"](hero) then result = result .. '!Skill 1' .. mw.getCurrentFrame():expandTemplate{title='Icon', args = { getHeroData["skill1"](hero) }} .. '\n' end
    if getHeroData["skill2"](hero) then result = result .. '!Skill 2' .. mw.getCurrentFrame():expandTemplate{title='Icon', args = { getHeroData["skill2"](hero) }} .. '\n' end
    if getHeroData["skill3"](hero) then result = result .. '!Skill 3' .. mw.getCurrentFrame():expandTemplate{title='Icon', args = { getHeroData["skill3"](hero) }} .. '\n' end
    if getHeroData["skill4"](hero) then result = result .. '!Skill 4' .. mw.getCurrentFrame():expandTemplate{title='Icon', args = { getHeroData["skill4"](hero) }} .. '\n' end
    result = result .. '|-'
    local oldskill1 = ""
    local oldskill2 = ""
    local oldskill3 = ""
    local oldskill4 = ""
    for i=1,maxlevel,1 do
    	if (getHeroData["skill1"](hero) and oldskill1 ~= getHeroData["level_skill"](hero,tostring(i),reborn,"1"))
    	or (getHeroData["skill2"](hero) and oldskill2 ~= getHeroData["level_skill"](hero,tostring(i),reborn,"2")) 
    	or (getHeroData["skill3"](hero) and oldskill3 ~= getHeroData["level_skill"](hero,tostring(i),reborn,"3")) 
    	or (getHeroData["skill4"](hero) and oldskill4 ~= getHeroData["level_skill"](hero,tostring(i),reborn,"4")) then
	        result = result .. '|-\n'
	        result = result .. "!" .. i
	        if i == 1 or i == 6 or i == 11 or i == 16 or i == 21 or i == 26 or i == 31 then
	        	result = result .. "<br/>(" .. (i-1)/5+1 ..  mw.getCurrentFrame():expandTemplate{title='Icon', args = { 'star' }} .. ")"
	        end
	        result = result .. "\n"
	        if getHeroData["skill1"](hero) then 
	        	oldskill1 = getHeroData["level_skill"](hero,tostring(i),reborn,"1")
	        	result = result .. "|" .. oldskill1 .. "\n"
	        end
	        if getHeroData["skill2"](hero) then 
	        	oldskill2 = getHeroData["level_skill"](hero,tostring(i),reborn,"2")
	        	result = result .. "|" .. oldskill2 .. "\n"
	        end
	        if getHeroData["skill3"](hero) then 
	        	oldskill3 = getHeroData["level_skill"](hero,tostring(i),reborn,"3")
	        	result = result .. "|" .. oldskill3 .. "\n"
	        end
	        if getHeroData["skill4"](hero) then 
	        	oldskill4 = getHeroData["level_skill"](hero,tostring(i),reborn,"4")
	        	result = result .. "|" .. oldskill4 .. "\n"
	        end
		end
	end
	result = result .. "|}"  
    return result
end

function p.dump(frame)
    local hero = frame.args['hero'] or frame.args[1]
    if not hero then return nil end
    return mw.text.jsonEncode(data[hero])
end

function p.export()
    local result = '';
    
	--sort the hero table
    keys = {}
    for k in pairs(data) do
        table.insert(keys, k)
    end
    table.sort(keys)
    
    for k, t in ipairs(keys) do
        result = result .. data[t].id .. ";"
        result = result .. t .. ";"
        result = result .. data[t].rarity .. ";"
        result = result .. data[t].alignment .. ";"
        result = result .. data[t].gender .. ";"
        result = result .. data[t].type .. ";"
		result = result .. data[t].soulbind1[1] .. ";"
		result = result .. data[t].soulbind2[1] .. ";" .. data[t].soulbind2[2] .. ";" 
		result = result .. data[t].soulbind3[1] .. ";" .. data[t].soulbind3[2] .. ";"
		result = result .. data[t].soulbind4[1] .. ";" .. data[t].soulbind4[2] .. ";" .. data[t].soulbind4[3] .. ";"	 
    	if (not data[t].evolves_from) then
    		result = result .. ';;;'
    	else       
	    	if (not data[t].evolves_from[1]) or (data[t].evolves_from[1] == "") then
	    		result = result .. ";"
	    	else
	    		result = result .. data[t].evolves_from[1] .. ";"
	    	end
		    if (not data[t].evolves_from[2]) or (data[t].evolves_from[2] == "") then 
	    		result = result .. ";"
		    else
		    	result = result .. data[t].evolves_from[2] .. ";"
		    end
	    	if (not data[t].evolves_from[3]) or (data[t].evolves_from[3] == "") then
	    		result = result .. ";"
	    	else
	    		result = result .. data[t].evolves_from[3] .. ";"
		    end    
	    end  
    	if (not data[t].evolves_to) then
    		result = result .. ';;;'
    	else       
	    	if (not data[t].evolves_to[1]) or (data[t].evolves_to[1] == "") then
	    		result = result .. ";"
	    	else
	    		result = result .. data[t].evolves_to[1] .. ";"
	    	end
		    if (not data[t].evolves_to[2]) or (data[t].evolves_to[2] == "") then 
	    		result = result .. ";"
		    else
		    	result = result .. data[t].evolves_to[2] .. ";"
		    end
	    	if (not data[t].evolves_to[3]) or (data[t].evolves_to[3] == "") then
	    		result = result .. ";"
	    	else
	    		result = result .. data[t].evolves_to[3] .. ";"
		    end    
	    end 
		result = result .. '<br/>'  
	end
	return "<code>" .. result .. "</code>"
end

--[[For viewing all Hero/data
--@: double shovel replaced for comment block
function p.herodata()
	--sort the hero table
    keys = {}
    for k in pairs(data) do
        table.insert(keys, k)
    end
    table.sort(keys)
    
    --hero table
    result = '{| class="wikitable filterable sortable"\n'
    result = result .. '!class="unfilterable"|ID\n'
    result = result .. '!class="unfilterable"|Name\n'
    result = result .. '!class="unsortable unfilterable"|Image\n'
    result = result .. '!class="unsortable unfilterable"|Quote\n'
    result = result .. '!class="unsortable unfilterable"|Gallery\n'
    result = result .. '!class="unsortable unfilterable"|Gallery Text\n'
    result = result .. '!class="unsortable"|Rarity\n'
    result = result .. '!class="unsortable"|Faction\n'
    result = result .. '!class="unsortable"|Gender\n'
    result = result .. '!class="unsortable"|Type\n'
    result = result .. '!class="unsortable unfilterable"|Evolves From\n'
    result = result .. '!class="unsortable unfilterable"|Evolves To\n'
    result = result .. '|-\n'
    for k, t in ipairs(keys) do
        result = result .. '|-\n'
        result = result .. "|'''" .. data[t].id .. "'''\n"
@        result = result .. "|'''@@" .. t .. "@@'''\n" 
        if (not data[t].image) or data[t].image == "" then
@        	result = result .. "|@@File:Icon_question.png@@\n"
        else
@        	result = result .. "|@@File:" .. data[t].image .. "@@\n" 
        end
        if (not data[t].quote) or data[t].quote == "" then
        	result = result .. "| -\n"
        else
        	result = result .. "|" .. data[t].quote .. "\n"
        end
@        if (not data[t].gallery_image) or data[t].gallery_image == "" then
        	result = result .. "|@@File:Icon_question.png|thumb|300px@@\n" 
        else
@        	result = result .. "|@@File:" .. data[t].gallery_image .. "|thumb|300px@@\n"
        end
        if (not data[t].gallery_text) or data[t].gallery_text == "" then
        	result = result .. "| -\n"
        else
        	result = result .. "|" .. data[t].gallery_text .. "\n"
        end 
        result = result .. "|" .. data[t].rarity .. '\n'
        result = result .. "|" .. data[t].alignment .. '\n'
        result = result .. "|" .. data[t].gender .. '\n'
        result = result .. "|" .. data[t].type .. '\n'
    
--evolve from logic    	
    	if (not data[t].evolves_from) then
    		result = result .. '| -\n'
    	else       
	    	if (not data[t].evolves_from[1]) or (data[t].evolves_from[1] == "") then
	    		result = result .. '| -'
	    	else         		
    			result = result .. "|@@" .. data[t].evolves_from[1] .. '@@' 
		    	if (data[t].evolves_from[2]) and (data[t].evolves_from[2] ~= "") then 
@		    		result = result .. "<br>@@" .. data[t].evolves_from[2] .. '@@'
		    	end
		    	if (data[t].evolves_from[3]) and (data[t].evolves_from[3] ~= "") then
@		    		result = result .. "<br>@@" .. data[t].evolves_from[3] .. '@@'
			    end     
			end
			result = result .. '\n'
	    end
	    
--evolve to logic	    
    	if (not data[t].evolves_to) then
    		result = result .. '| -\n'
    	else       
	    	if (not data[t].evolves_to[1]) or (data[t].evolves_to[1] == "") then
	    		result = result .. '| -'
	    	else         		
@    			result = result .. "|@@" .. data[t].evolves_to[1] .. '@@'
		    	if (data[t].evolves_to[2]) and (data[t].evolves_to[2] ~= "") then 
@		    		result = result .. "<br>@@" .. data[t].evolves_to[2] .. '@@'
		    	end
		    	if (data[t].evolves_to[3]) and (data[t].evolves_to[3] ~= "") then
@		    		result = result .. "<br>@@" .. data[t].evolves_to[3] .. '@@'
			    end     
			end
			result = result .. '\n'
	    end
    end
    result = result .. "|}"  
   
    return result
end

function p.herodata2()
	--sort the hero table
    keys = {}
    for k in pairs(data) do
        table.insert(keys, k)
    end
    table.sort(keys)
    
    --hero table
    result = '{| class="wikitable filterable sortable"\n'
    result = result .. '!class="unfilterable" rowspan="2"|ID\n'
    result = result .. '!class="unfilterable" rowspan="2"|Name\n'
    result = result .. '!class="unsortable unfilterable" colspan="4"|Skills\n'
    result = result .. '!class="unsortable unfilterable" colspan="4"|Soulbind\n'
    result = result .. '!class="unsortable unfilterable" colspan="5"|Reborn\n'
    result = result .. '|-\n'
    result = result .. '!class="unsortable unfilterable"|1\n'
    result = result .. '!class="unsortable unfilterable"|2\n'
    result = result .. '!class="unsortable unfilterable"|3\n'
    result = result .. '!class="unsortable unfilterable"|4\n'
    result = result .. '!class="unsortable unfilterable"|I\n'
    result = result .. '!class="unsortable unfilterable"|II\n'
    result = result .. '!class="unsortable unfilterable"|III\n'
    result = result .. '!class="unsortable unfilterable"|IV\n'
    result = result .. '!class="unsortable unfilterable"|I\n'
    result = result .. '!class="unsortable unfilterable"|II\n'
    result = result .. '!class="unsortable unfilterable"|III\n'
    result = result .. '!class="unsortable unfilterable"|IV\n'
    result = result .. '!class="unsortable unfilterable"|V\n'
    for k, t in ipairs(keys) do
        result = result .. '|-\n'
        result = result .. "|'''" .. data[t].id .. "'''\n"
@        result = result .. "|'''@@" .. t .. "@@'''\n"

--skill logic
        if (not data[t].skill1) or (data[t].skill1 == "") then
    		result = result .. '|align="center"|-\n'
    	else      
    		result = result .. "|" .. data[t].skill1
    		if (data[t].skill1_desc) and (data[t].skill1_desc ~= "") then result = result .. ":" .. mw.getCurrentFrame():preprocess(data[t].skill1_desc) end
    		result = result .. '\n'
    	end
        if (not data[t].skill2) or (data[t].skill2 == "") then
    		result = result .. '|align="center"|-\n'
    	else      
    		result = result .. "|" .. data[t].skill2 
    		if (data[t].skill2_desc) and (data[t].skill2_desc ~= "") then result = result .. ":" .. mw.getCurrentFrame():preprocess(data[t].skill2_desc) end
    		result = result .. '\n'
    	end
        if (not data[t].skill3) or (data[t].skill3 == "") then
    		result = result .. '|align="center"|-\n'
    	else      
    		result = result .. "|" .. data[t].skill3
    		if (data[t].skill3_desc) and (data[t].skill3_desc ~= "") then result = result .. ":" .. mw.getCurrentFrame():preprocess(data[t].skill3_desc) end
    		result = result .. '\n'
    	end
        if (not data[t].skill4) or (data[t].skill4 == "") then
    		result = result .. '|align="center"|-\n'
    	else      
    		result = result .. "|" .. data[t].skill4
    		if (data[t].skill4_desc) and (data[t].skill4_desc ~= "") then result = result .. ":" .. mw.getCurrentFrame():preprocess(data[t].skill4_desc) end
    		result = result .. '\n'
    	end
    	
--soulbind logic 
		result = result .. '|'
		if data[t].soulbind1_atk then result = result .. 'Atk: +' .. data[t].soulbind1_atk end
		if data[t].soulbind1_hp then result = result .. '<br>HP: +' .. data[t].soulbind1_hp end
@		if data[t].soulbind1 then result = result .. '<br>Heroes:<br>- @@' .. data[t].soulbind1[1] .. '@@' end
		result = result .. '\n|'
		if data[t].soulbind2_atk then result = result .. 'Atk: +' .. data[t].soulbind2_atk end
		if data[t].soulbind2_hp then result = result .. '<br>HP: +' .. data[t].soulbind2_hp end
@		if data[t].soulbind2 then result = result .. '<br>Heroes:<br>- @@' .. data[t].soulbind2[1] .. '@@<br>- @@' .. data[t].soulbind2[2] .. '@@' end
		result = result .. '\n|'
		if data[t].soulbind3_atk then result = result .. 'Atk: +' .. data[t].soulbind3_atk end
		if data[t].soulbind3_hp then result = result .. '<br>HP: +' .. data[t].soulbind3_hp end
@		if data[t].soulbind3 then result = result .. '<br>Heroes:<br>- @@' .. data[t].soulbind3[1] .. '@@<br>- @@' .. data[t].soulbind3[2] .. '@@' end
		result = result .. '\n|'
		if data[t].soulbind4_atk then result = result .. 'Atk: +' .. data[t].soulbind4_atk end
		if data[t].soulbind4_hp then result = result .. '<br>HP: +' .. data[t].soulbind4_hp end
@		if data[t].soulbind4 then result = result .. '<br>Heroes:<br>- @@' .. data[t].soulbind4[1] .. '@@<br>- @@' .. data[t].soulbind4[2] .. '@@<br>- @@' .. data[t].soulbind4[3] .. '@@' end
		result = result .. '\n'
    	
--reborn logic
		result = result .. '|'
		if data[t].reborn1_atk then result = result .. 'Atk: +' .. data[t].reborn1_atk end
		if data[t].reborn1_hp then result = result .. '<br>HP: +' .. data[t].reborn1_hp end
		if data[t].reborn1_skill then result = result .. '<br>Skill ' .. data[t].reborn1_skill[1] .. ': ' .. data[t].reborn1_skill[2] end
		result = result .. '\n|'
		if data[t].reborn2_atk then result = result .. 'Atk: +' .. data[t].reborn2_atk end
		if data[t].reborn2_hp then result = result .. '<br>HP: +' .. data[t].reborn2_hp end
		if data[t].reborn2_skill then result = result .. '<br>Skill ' .. data[t].reborn2_skill[1] .. ': ' .. data[t].reborn2_skill[2] end
		result = result .. '\n|'
		if data[t].reborn3_atk then result = result .. 'Atk: +' .. data[t].reborn3_atk end
		if data[t].reborn3_hp then result = result .. '<br>HP: +' .. data[t].reborn3_hp end
		if data[t].reborn3_skill then result = result .. '<br>Skill ' .. data[t].reborn3_skill[1] .. ': ' .. data[t].reborn3_skill[2] end
		result = result .. '\n|'
		if data[t].reborn4_atk then result = result .. 'Atk: +' .. data[t].reborn4_atk end
		if data[t].reborn4_hp then result = result .. '<br>HP: +' .. data[t].reborn4_hp end
		if data[t].reborn4_skill then result = result .. '<br>Skill ' .. data[t].reborn4_skill[1] .. ': ' .. data[t].reborn4_skill[2] end
		result = result .. '\n|'
		if data[t].reborn5_atk then result = result .. 'Atk: +' .. data[t].reborn5_atk end
		if data[t].reborn5_hp then result = result .. '<br>HP: +' .. data[t].reborn5_hp end
		if data[t].reborn5_skill then result = result .. '<br>Skill ' .. data[t].reborn5_skill[1] .. ': ' .. data[t].reborn5_skill[2] end
		result = result .. '\n'
	end

    result = result .. "|}"  
    return result
end]]

return p