FANDOM


-- <pre>
-- Facilitates accessing data about Heroes, and displaying the information in meaningful ways.
-- Information is stores on sub pages in the format: "Module:Hero/Test the Hero" (where capitalization is the same as it would be in-game).
-- For more information on how the Hero data is stored, see Project:Hero_data
--
 
local p = {}
 
local heroSkills = require('Module:Skill')
local paramtest = require('Module:Paramtest')
local is_empty = paramtest.is_empty
local default_to = paramtest.default_to
local has_content = paramtest.has_content
 
local _ElemCatTable = { attack="[[Category:Attack heroes]]", fire="[[Category:Fire heroes]]", water="[[Category:Water heroes]]", wood="[[Category:Wood heroes]]", support="[[Category:Support heroes]]" }
local _baseCatTable = { story="[[Category:Story heroes]]", normal="[[Category:Normal heroes]]", fairy="[[Category:Fairies]]", raid="[[Category:Raid heroes]]" }
local _dashImages = { none="File:Dash - none.png", ["4 adjacent"]="File:Dash - 4 adjacent.png", ["8 adjacent"]="File:Dash - 8 adjacent.png", heal="File:Dash - heal.png", buff="File:Dash - buff.png", vertical="File:Dash - vertical.png", horizontal="File:Dash - horizontal.png", ["2 radius"]="File:Dash - 2 radius.png", repeats="File:Dash - repeat.png", path="File:Dash - path.png", ["machine gun"]="File:Dash - machine_gun.png", bomb="File:Dash - bomb.png" }
local _typesIcons = { attack="File:Attack medal.png", support="File:Support medal.png", fire="File:Fire medal.png", water="File:Water medal.png", wood="File:Wood medal.png" }
 
-- [expensive] - pFile: name of file with the "File:"
local function fileExists(pFile)
    return mw.title.new( pFile, 'File' ).exists == true
end
 
--
-- Merge table 2 onto table 1 - http://stackoverflow.com/a/1283608/1411473
--
-- @param t1 {table} Base table
-- @param t2 {table} Table to merge
-- @return {table} Merged table
local function tableMerge(t1, t2)
    for k,v in pairs(t2) do
        if type(v) == "table" then
            if type(t1[k] or false) == "table" then
                tableMerge(t1[k] or {}, t2[k] or {})
            else
                t1[k] = v
            end
        else
            t1[k] = v
        end
    end
    return t1
end
 
-- http://stackoverflow.com/a/15706820/1411473
local function spairs(t, order)
    -- collect the keys
    local keys = {}
    for k in pairs(t) do keys[#keys+1] = k end
 
    -- if order function given, sort by it by passing the table and keys a, b,
    -- otherwise just sort the keys 
    if order then
        table.sort(keys, function(a,b) return order(t, a, b) end)
    else
        table.sort(keys)
    end
 
    -- return the iterator function
    local i = 0
    return function()
        i = i + 1
        if keys[i] then
            return keys[i], t[keys[i]]
        end
    end
end
 
local function green(text)
    return '<span class="greentext">'..text..'</span>'
end
 
--
-- mw.loadData shortcut for loading hero data tables
--
-- @param heroName {string} Hero to retrieve
-- @return {table} Table of hero data
--
function p.loadHero( heroName )
    local noError, data = pcall( mw.loadData, 'Module:Hero/' .. heroName )
 
    if noError then
        return data
    end
 
    -- error( data )
    return nil;
end
 
--
-- mw.loadData shortcut for merging data for a specific hero's evolution
--
-- @param heroData {string} Hero to retrieve
-- @param stars {int} Star version of Hero to retrieve
-- @return {table} Table of hero data
--
local function normalizeHeroEvolution(heroData, stars)
    if heroData.evolutions[stars] ~= nil then
        return tableMerge(tableMerge({}, heroData), heroData.evolutions[stars])
    end
    return error( "Invalid star amount entered" )
end
 
--
-- Returns the string for the respective passive ability
--
-- @param passive {string} keyword for the passive
-- @param val {int} value for the passive.
--
local function getPassive( passive, val, val2 )
    -- passive
    if passive=="critical" then
         return "Team's Critical Rate +"..green(val.."%")
    elseif passive=="attack" then
         return "Team's ATK +"..green(val.."%")
    elseif passive=="fire" then
         return "Team's Fire ATK +"..green(val.."%")
    elseif passive=="water" then
         return "Team's Water ATK +"..green(val.."%")
    elseif passive=="wood" then
         return "Team's Wood ATK +"..green(val.."%")
    elseif passive=="elemental" then
         return "All elemental ATK +"..green(val.."%")
    elseif passive=="defense" then
         return "Team's DEF +"..green(val.."%")
    elseif passive=="hp" then
         return "Team's HP +"..green(val.."%")
    elseif passive=="perfect" then
         return "[[Perfect Attack]] power +"..green(val.."%")
    elseif passive=="super" then
         return "[[Super Skill]] power +"..green(val.."%")
    elseif passive=="mp" then
         return "Team's MP recovery rate +"..green(val.."%")
    -- active
    elseif passive=="revive" then
         return "Revives a fallen team member each turn ("..green(val.."%").." chance)"
    elseif passive=="chain" then
         return "ATK/Heal +"..green(val.."%").." for "..green(val2).." chains"
    elseif passive=="lastdungeon" then
         return "Heals "..green(val.."%").." HP before last dungeon battle"
    elseif passive=="atkdecrease" then
         return "Physical ATK damage dealt to party decreases by "..green(val.."%")..""
    elseif passive=="superdecrease" then
        return "Super move damage dealt to the party decreases by +"..green(val.."%")..""
    else
        return val and passive..": "..val.."%" or passive
    end
end
 
local function getDash( dash, val, val2 )
    if dash=="4 adjacent" then
        return "Attacks 4 adjacent blocks with "..green(val.."%").." ATK/Fire/Water/Wood."
    elseif dash=="8 adjacent" then
        return "Attacks 8 adjacent blocks with "..green(val.."%").." ATK/Fire/Water/Wood."
    elseif dash=="heal" then
        return "Recovers the HP of all allies by the amount of Heal."
    elseif dash=="buff" then
        return "Increases ATK/Fire/Water/Wood of all allies by the amount of ATK Buff."
    elseif dash=="vertical" then
        return "Attacks enemies in the same horizontal line with "..green(val.."%").." ATK/Fire/Water/Wood."
    elseif dash=="horizontal" then
        return "Attacks enemies in the same vertical line with "..green(val.."%").." ATK/Fire/Water/Wood."
    elseif dash=="2 radius" then
        return "Attacks enemies in a 2-block radius with "..green(val.."%").." ATK/Fire/Water/Wood."
    elseif dash=="repeat" then
        return "Repeats the previous action with "..green(val.."%").." efficiency."
    elseif dash=="path" then
        val2 = val2 or 75;
        return "Attacks enemies in the path "..green(val.."").." times with "..green(val2.."%").." ATK/Fire/Water/Wood."
    elseif dash=="machine gun" then
        return "Attacks an enemy with "..green(val.."%").." ATK/Fire/Water/Wood per each move. Damage increases by "..green("10%").." per attack."
    elseif dash=="bomb" then
        return "Drops a bomb on the enemy's path. Each bomb damages an enemy, who's within 3x3 blocks, with "..green(val.."%").." ATK/Fire/Water/Wood."
    else
        return val and dash..": "..val.."%" or dash
    end
end
 
function p.getDashImage( dash, size )
    return _dashImages[dash] and "[[".._dashImages[dash]..(size and "|"..size.."px" or "").."|"..dash.."]]" or "?"
end
 
function p.getTypeIcon( type, size )
    return _typesIcons[type] and "[[".._typesIcons[type]..(size and "|"..size.."px" or "").."|"..type.."]]" or "?"
end
 
function p._icon( heroData, size, center )
    local sizeText = size and '|'..size..'px' or ''
    return '[[File:'..heroData.image..sizeText..(center and '|center' or '')..'|'..(fileExists(heroData.image) and 'Image of '..heroData.name or 'Image')..']]'
end
 
local function starColorClass( num )
    return 'color-'..num..'star'
end
 
function p._evolutionStars( num )
    local t = { } -- returnStringParts
    for i = 1,num do t[#t+1] = '★' end
    return '<span class="'..starColorClass(num)..'">'..table.concat(t,"")..'</span>'
end
 
function p._evolutionNum( num )
    return '<span class="'..starColorClass(num)..'">'..num..'</span>'
end
 
function p._infotable( heroData )
    local t = { } -- returnStringParts
    t[#t+1] = '{| class="wikitable herobox"'
    t[#t+1] = '| colspan="2" |'..p._icon(heroData, 50, true)
    t[#t+1] = '! colspan="4" |'..p.getTypeIcon(heroData.type, 21)..' '..heroData.name..'<br>'..p._evolutionStars(heroData.stars)
    t[#t+1] = '|-'
    t[#t+1] = '! colspan="6" |'..heroData.desc
    t[#t+1] = '|-'
 
    local function addDataIfExisits(t, title, val, count, unit)
        if val then
            t[#t+1] = '!'..title
            t[#t+1] = '|'..val..(unit or '')
            if (count+1)%3 == 0 then
                t[#t+1] = '|-'
            end
            return count+1
        end
        return count
    end
 
    local tCount = 0
    tCount = addDataIfExisits(t, "ATK", heroData.attack, tCount)
    tCount = addDataIfExisits(t, "HEAL", heroData.heal, tCount)
    tCount = addDataIfExisits(t, "HP", heroData.hp, tCount)
    tCount = addDataIfExisits(t, "TAUNT", heroData.taunt, tCount)
    tCount = addDataIfExisits(t, "DEF", heroData.defense, tCount)
    tCount = addDataIfExisits(t, "FREEZE", heroData.freeze, tCount, "%")
    tCount = addDataIfExisits(t, "CRIT", heroData.critical, tCount, "%")
    tCount = addDataIfExisits(t, "ATK BUFF", heroData.buff, tCount, "%")
    tCount = addDataIfExisits(t, "FIRE", heroData.fire, tCount)
    tCount = addDataIfExisits(t, "WATER", heroData.water, tCount)
    tCount = addDataIfExisits(t, "WOOD", heroData.wood, tCount)
 
    if tCount%3 == 1 then
        t[#t+1] = '!\n|\n!\n|'
        t[#t+1] = '|-'
    elseif tCount%3==2 then
        t[#t+1] = '!\n|'
        t[#t+1] = '|-'
    end
 
 
    t[#t+1] = '! colspan="6" | Hero Tier'
    t[#t+1] = '|-'
    t[#t+1] = '!PvP'
    t[#t+1] = '|'..heroData.tierPvP
    t[#t+1] = '!PvE'
    t[#t+1] = '|'..heroData.tierPvE
    t[#t+1] = '!TOWER'
    t[#t+1] = '|'..heroData.tierTower
    t[#t+1] = '|-'
 
    t[#t+1] = '! colspan="2" |'..p.getDashImage(heroData.dash, 60)
    t[#t+1] = '| colspan="4" |<b>[[Dash|DASH]] SKILL</b><br>'..getDash(heroData.dash, heroData.dashValue, heroData.dashValue2)
    t[#t+1] = '|-'
 
    t[#t+1] = '! colspan="2" |<b>SKILL</b>'
    local tSkill = heroData.skill;
    if heroData.name == "Ringo the Bard" then tSkill = tSkill..'-Ringo' end
    if heroData.name == "Lulu the Princess" then tSkill = tSkill..'-Lulu' end
    if heroData.name == "BMO" then tSkill = tSkill..'-BMO' end
    if heroData.name == "Party Pat" then tSkill = tSkill..'-Pat' end
    if heroData.name == "Dice" then tSkill = tSkill..'-Dice' end
    if heroData.name == "Driard the Queen of Wood Elemental" then tSkill = tSkill..'-Driard' end
    t[#t+1] = '| colspan="4" | '..heroSkills._skillMessage(tSkill, heroData.skillLevel)
    t[#t+1] = '|-'
 
    t[#t+1] = '! colspan="2" |<b>PASSIVE</b>'
    t[#t+1] = '| colspan="4" |'..getPassive(heroData.passive, heroData.passiveValue, heroData.passiveValue2)
    t[#t+1] = '|-'
 
    t[#t+1] = '|}'
 
    t[#t] = t[#t]..(_ElemCatTable[heroData.type] or "") .. (_baseCatTable[heroData.base] or "") .. "[[Category:Heroes]]"
 
    return table.concat(t,"\n")
end
 
function p._infobox( heroData, heroName )
    local t = { } -- returnStringParts
    t[#t+1] = '{{Infobox hero'
    t[#t+1] = '|title='..p.getTypeIcon(heroData.type, 30)..' '..heroData.name..'<br>'..p._evolutionStars(heroData.stars)
    t[#t+1] = '|image='..p._icon(heroData, 50, true)
    t[#t+1] = '|caption='..heroData.desc
 
    local function addDataIfExisits(t, varname, val, count)
        if val then
            local tRow = math.floor(count / 3)
            if tRow > 0 then tRow = tRow+1 else tRow='' end
            t[#t+1] = '|'..varname..tRow.."="..val
            return count+1
        end
        return count
    end
 
    local tCount = 0
    tCount = addDataIfExisits(t, "attack", heroData.attack, tCount)
    tCount = addDataIfExisits(t, "heal", heroData.heal, tCount)
    tCount = addDataIfExisits(t, "hp", heroData.hp, tCount)
    tCount = addDataIfExisits(t, "taunt", heroData.taunt, tCount)
    tCount = addDataIfExisits(t, "defense", heroData.defense, tCount)
    tCount = addDataIfExisits(t, "freeze", heroData.freeze, tCount)
    tCount = addDataIfExisits(t, "critical", heroData.critical, tCount)
    tCount = addDataIfExisits(t, "buff", heroData.buff, tCount)
    tCount = addDataIfExisits(t, "fire", heroData.fire, tCount)
    tCount = addDataIfExisits(t, "water", heroData.water, tCount)
    tCount = addDataIfExisits(t, "wood", heroData.wood, tCount)
 
    t[#t+1] = '|tierPvP='..heroData.tierPvP
    t[#t+1] = '|tierPvE='..heroData.tierPvE
    t[#t+1] = '|tierTower='..heroData.tierTower
 
    t[#t+1] = '|dashimage='..p.getDashImage(heroData.dash, 'center|'..'80x60')
    t[#t+1] = '|dash='..getDash(heroData.dash, heroData.dashValue, heroData.dashValue2)
    local tSkill = heroData.skill;
    if heroData.name == "Ringo the Bard" then tSkill = tSkill..'-Ringo' end
    if heroData.name == "Lulu the Princess" then tSkill = tSkill..'-Lulu' end
    if heroData.name == "BMO" then tSkill = tSkill..'-BMO' end
    if heroData.name == "Party Pat" then tSkill = tSkill..'-Pat' end
    if heroData.name == "Dice" then tSkill = tSkill..'-Dice' end
    if heroData.name == "Driard the Queen of Wood Elemental" then tSkill = tSkill..'-Driard' end
    t[#t+1] = '|skill='..heroSkills._skillMessage(tSkill, heroData.skillLevel)
    t[#t+1] = '|passive='..getPassive(heroData.passive, heroData.passiveValue, heroData.passiveValue2)
 
    t[#t+1] = '|bottom=<div style="text-align: right;"><small>[ [[Module:Hero/'..heroName..'|update hero values]] ]</small></div>'
    t[#t+1] = '}}'
 
    t[#t] = t[#t]..(_ElemCatTable[heroData.type] or "") .. (_baseCatTable[heroData.base] or "") .. "[[Category:Heroes]]"
 
    return table.concat(t,"\n")
end
 
function p.infobox(frame)
    local args = frame:getParent().args
 
    if is_empty(args[1]) then error("Invalid parameter (empty)") end
    local heroName = args[1]
 
    local hero = p.loadHero( heroName, true )
    if hero == nil then return "<div class='error'>No data for hero by the name '[[Module:Hero/"..heroName.."|"..heroName.."]]'</div>"; end
 
    if not is_empty(args[2]) then
        hero = normalizeHeroEvolution( hero, tonumber(args[2]) )
        return p._infobox( hero, heroName )
    else
 
        local t = { } -- returnStringParts
        t[#t+1] = '<div class="infobox-hero-tabbr" style="float:right;">'
        t[#t+1] = '<tabber>'
        for i, v in spairs( hero.evolutions, function(t,a,b) return t[b].stars < t[a].stars end ) do
            t[#t+1] = '|-| '..i..' Star='
            t[#t+1] = p._infobox( normalizeHeroEvolution(hero, i), heroName )
        end
        t[#t+1] = '</tabber>'
        -- t[#t+1] = '<div style="clear:right; text-align: right; margin: -12px 0 10px;"><small>[ [[Module:Hero/'..heroName..'|update hero values]] ]</small></div>'
        t[#t+1] = '</div>'
 
        return frame:preprocess( table.concat(t,"\n") )
    end
end
 
return p

Ad blocker interference detected!


Wikia is a free-to-use site that makes money from advertising. We have a modified experience for viewers using ad blockers

Wikia is not accessible if you’ve made further modifications. Remove the custom ad blocker rule(s) and the page will load as expected.