Module:DunHero

-- -- 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:DunSkill') local paramtest = require('Module:DunParamTest') local is_empty = paramtest.is_empty local default_to = paramtest.default_to local has_content = paramtest.has_content

local _ElemCatTable = { attack="", fire="", water="", wood="", support="" } local _baseCatTable = { story="", normal="", fairy="", raid="" } 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 ' '..text..' ' 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 ) local noError, data = pcall( mw.loadData, 'Module:DunHero/' .. 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.."%").."" else return val and passive..": "..val.."%" or passive end end

local function getDash( dash, val ) 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 return "Attacks enemies in the path "..green(val.."").." times with "..green("75%").." 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 ""..size.."px" or "").."|"..dash.."" or "?" end

function p.getTypeIcon( type, size ) return _typesIcons[type] and ""..size.."px" or "").."|"..type.."" or "?" end

function p._icon( heroData, size, center ) local sizeText = size and '|'..size..'px' or '' return '' 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 ''..table.concat(t,"")..' ' end

function p._evolutionNum( num ) return ''..num..' ' 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..' '..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" |DASH SKILL '..getDash(heroData.dash, heroData.dashValue) t[#t+1] = '|-' t[#t+1] = '! colspan="2" |SKILL' 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" |PASSIVE' 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 "") .. ""   return table.concat(t,"\n") end

function p._infobox( heroData ) local t = { } -- returnStringParts --   t[#t+1] = '{{Infobox hero' t[#t+1] = '{{DunHeroInfobox' t[#t+1] = '|title='..p.getTypeIcon(heroData.type, 30)..' '..heroData.name..' '..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) 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= [ update hero values ] ' t[#t+1] = '}}' t[#t] = t[#t]..(_ElemCatTable[heroData.type] or "") .. (_baseCatTable[heroData.base] or "") .. ""   return table.concat(t,"\n") end

function p.HJFjunk(frame) -- have to use p. -series because want p._infobox ? end function HJFjunk(h,aa) --   local junk = normalizeHeroEvolution(h,s) local j = { } -- returnStringParts j[#j+1] = ' ' j[#j+1] = 'much more nonsense... ' --   j[#j+1] = '|title='..p.getTypeIcon(h.type, 75)..' '..h.name..' '..p._evolutionStars(h.stars) j[#j+1] = '|title='..p.getTypeIcon(h.type, 75)..' '..h.name..' '..aa --   t[#t+1] = '|image='..p._icon(heroData, 50, true) --   t[#t+1] = '|caption='..heroData.desc return table.concat(j,"\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 " No data for hero by the name '"..heroName.."' "; end

--   return hero.name .. hero.type .. hero.desc -- [====[       if not is_empty(args[2]) then junk = HJFjunk( hero,tonumber(args[2]) ) return junk --       return 'nonsense' --       hero = normalizeHeroEvolution( hero, tonumber(args[2]) ) --       return p._infobox( hero, heroName ) --       return frame:preprocess( p._infobox( hero, heroName ) ) else local t = { } -- returnStringParts t[#t+1] = ' ' t[#t+1] = ' ' 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] = ' ' -- t[#t+1] = ' [ update hero values ] ' t[#t+1] = ' ' return frame:preprocess( table.concat(t,"\n") ) end --]====] end

return p