Module:SummoningFocus

local cargo = mw.ext.cargo local Util = require 'Module:Util' local List = require 'Module:ListUtil' local Datetime = require 'Module:DatetimeUtil' local Tab = require 'Module:Tab' local FEHStatUtil = require 'Module:FEHStatUtil' local FocusRates = require 'Module:FocusRates' local SummoningEvent = require 'Module:SummoningEvent' local escq = require 'Module:EscQ'.main1 local toboolean = require 'Module:Bool'.toboolean local lang = mw.getContentLanguage local p = {}

local collectHeroes = function (args) local i = 1 local heroes = {} while not Util.isNilOrEmpty(args['hero' .. i]) do heroes[i] = args['hero' .. i]		i = i + 1 end return heroes end

local makeRarityHeroTable = function (args, focusRarities) -- Make a table that includes a Hero table and a Rarity table. -- If no rarity* parameter for a Hero were given, that hero will be added -- with all rarity values in focusRarities table.. local i = 1 local rarityHero = { Heroes = {}, Rarities = {} } local addHero = function (rarity, hero) table.insert(rarityHero['Heroes'], hero) table.insert(rarityHero['Rarities'], rarity) end while not Util.isNilOrEmpty(args['hero' .. i]) do hero = args['hero' .. i] if Util.isNilOrEmpty(args['rarity' .. i]) then for _, rarity in ipairs(focusRarities) do				addHero(rarity, hero) end else rarities = mw.text.split(args['rarity' .. i], ',') for _, rarity in ipairs(rarities) do				addHero(rarity, hero) end end i = i + 1 end return rarityHero end

p.statsTables = function (frame, heroes) local heroStats = List.map(heroes, function (h)		local q = cargo.query('Units,UnitStats', 'Lv1HP5,Lv1Atk5,Lv1Spd5,Lv1Def5,Lv1Res5,HPGR3,AtkGR3,SpdGR3,DefGR3,ResGR3', { join = 'Units.WikiName=UnitStats.WikiName', where = ("Units._pageName='%s' AND IFNULL(Properties__full,'') NOT LIKE '%%enemy%%'"):format(escq(h)), groupBy = 'Units._pageName', })[1]		if not q then			return {'?/?/?', '?/?/?', '?/?/?', '?/?/?', '?/?/?'}		end		local stats = {tonumber(q.Lv1HP5), tonumber(q.Lv1Atk5), tonumber(q.Lv1Spd5), tonumber(q.Lv1Def5), tonumber(q.Lv1Res5)}		local rates = {tonumber(q.HPGR3), tonumber(q.AtkGR3), tonumber(q.SpdGR3), tonumber(q.DefGR3), tonumber(q.ResGR3)}		local rarity = 5		return List.zip(stats, rates, function (base, rate) return { ('%d/%d/%d'):format(base - 1, base, base + 1), ('%d/%d/%d'):format(					base + FEHStatUtil.getGrowthValue(rarity, rate - 5) - 1,					base + FEHStatUtil.getGrowthValue(rarity, rate),					base + FEHStatUtil.getGrowthValue(rarity, rate + 5) + 1), }		end)	end)

local doMakeTable = function (isLv40) local tbl = mw.html.create('table'):addClass('wikitable'):addClass('unsortable'):css('text-align', 'center')

local row = tbl:tag('tr') row:tag('th'):css('width', '25%'):wikitext('Hero') row:tag('th'):css('width', '15%'):wikitext('HP') row:tag('th'):css('width', '15%'):wikitext('Atk') row:tag('th'):css('width', '15%'):wikitext('Spd') row:tag('th'):css('width', '15%'):wikitext('Def') row:tag('th'):css('width', '15%'):wikitext('Res')

for i, hero in ipairs(heroes) do			local ss = heroStats[i]

local row = tbl:tag('tr') row:tag('td'):css('text-align', 'left'):wikitext(('%s %s'):format( frame:expandTemplate {title = 'UnitIcon', args = {name = hero, size = '50px'}}, hero)) for _, v in ipairs(ss) do				row:tag('td'):wikitext(v[isLv40 and 2 or 1]) end end

return tostring(tbl) end

return doMakeTable(false), doMakeTable(true) end

local SKILL_CATEGORIES = {'weapon', 'assist', 'special', 'passivea', 'passiveb', 'passivec'}

p.skillsTable = function (frame, heroes) local heroSkills = List.map(heroes, function (h)		return List.group_by(cargo.query('Units,UnitSkills,Skills', 'Skills._pageName=page,Skills.Name=name,Scategory', {			join = 'Units.WikiName=UnitSkills.WikiName,UnitSkills.skill=Skills.WikiName',			where = ("Units._pageName='%s' AND IFNULL(Units.Properties__full,'') NOT LIKE '%%enemy%%'"):format(escq(h)),			groupBy = 'UnitSkills.skill',			orderBy = 'skillPos',		}), function (v) return v.Scategory end)	end)

local tbl = mw.html.create('table'):addClass('wikitable'):addClass('unsortable'):css('text-align', 'center')

local row = tbl:tag('tr') row:tag('th'):css('width', '18em'):wikitext('Hero') row:tag('th'):css('width', '9em'):wikitext('Weapon') row:tag('th'):css('width', '9em'):wikitext('Assist') row:tag('th'):css('width', '9em'):wikitext('Special') row:tag('th'):css('width', '9em'):wikitext('Passive A') row:tag('th'):css('width', '9em'):wikitext('Passive B') row:tag('th'):css('width', '9em'):wikitext('Passive C')

for i, hero in ipairs(heroes) do		local ss = heroSkills[i]

local row = tbl:tag('tr') row:tag('td'):tag('div'):css('display', 'inline-block'):wikitext(frame:expandTemplate {title = 'UnitText with Type', args = {name = hero}}) for _, cat in ipairs(SKILL_CATEGORIES) do			local s = ss[cat] row:tag('td'):wikitext(s and table.concat(List.map_self(s, function (skill)				return ('%s'):format(skill.page, skill.name)			end), ' ') or '—') end end

return tostring(tbl) end

function p.focusPage(frame) local ytText if not (Util.isNilOrEmpty(frame.args.youtubeEN) and Util.isNilOrEmpty(frame.args.youtubeJP)) then ytText = tostring(Tab.tabber {			{'English', frame:callParserFunction {name = "#ev:youtube", args = {frame.args.youtubeEN}}},			{'Japanese', frame:callParserFunction {name = "#ev:youtube", args = {frame.args.youtubeJP}}},		}) else ytText = "" end

local rateTbl = mw.html.create("table") :addClass("wikitable") :addClass("default") :css("text-align","center") local headers = rateTbl:tag("tr") headers:tag("th"):wikitext("Rarity") headers:tag("th"):wikitext("Appearance rate")

local focusRarities = {} for i = 5,1,-1 do if not Util.isNilOrEmpty(frame.args["rarity" .. i .."FocusPercent"]) then table.insert(focusRarities, tostring(i)) local row = rateTbl:tag("tr") row:tag("td"):wikitext(i.."★ Focus") row:tag("td"):wikitext(frame.args["rarity" .. i .."FocusPercent"]) end if not Util.isNilOrEmpty(frame.args["rarity" .. i .."SpecialPercent"]) then local row = rateTbl:tag("tr") row:tag("td"):wikitext(i.."★ Special Rate") row:tag("td"):wikitext(frame.args["rarity" .. i .."SpecialPercent"]) end if not Util.isNilOrEmpty(frame.args["rarity" .. i .."Percent"]) then local row = rateTbl:tag("tr") row:tag("td"):wikitext(i.."★") row:tag("td"):wikitext(frame.args["rarity" .. i .."Percent"]) end end

local notesSection if Util.isNilOrEmpty(frame.args.notes) then notesSection = "" else notesSection=" Notes " .. frame.args.notes end

--Determine the pool local isNew = false local startDate if not Util.isNilOrEmpty(frame.args.start) then -- this check is required because lang:formatDate will return the current date if it receives no string parameter startDate = lang:formatDate('Y-m-d', frame.args.start) end local endDate if not Util.isNilOrEmpty(frame.args['end']) then endDate = lang:formatDate('Y-m-d', frame.args['end']) end

if startDate and startDate >= '2019-04-05' then if frame.args.bannerType == 'New Heroes' then isNew = true end if frame.args.bannerType == 'Special' and startDate < '2020-08-02' then local dates = cargo.query('SummoningEvents', 'DATE(StartTime)=Date', {				where = "Name='" .. escq(frame.args.name) .. "'",				groupBy = 'Date',				orderBy = 'Date'			}) if #dates == 0 or dates[1].Date == startDate then isNew = true end end -- Feh Channel Supplement: Changes to Heroes Appearing in Summoning Events and Weekly Revival Schedule Lineup (Notification) if startDate > '2020-08-02' and (				frame.args.bannerType == 'Special'				or frame.args.bannerType == 'New Heroes Revival'				or frame.args.bannerType == 'Hero Fest') then isNew = true end end

local heroTable = collectHeroes(frame.args) local lv1stats, lv40stats = p.statsTables(frame, heroTable) local rarityHeroTable = makeRarityHeroTable(frame.args, focusRarities) local canFocusRatesEnabled = Util.isNilOrEmpty(frame.args['rarity4FocusPercent']) or startDate < '2020-02-07' local canFocusRatesOverride = toboolean(frame.args['showFocusRates']) if canFocusRatesOverride ~= nil then canFocusRatesEnabled = canFocusRatesOverride end

local name = not Util.isNilOrEmpty(frame.args.name) and frame.args.name or mw.title.getCurrentTitle.fullText local wikiname = not Util.isNilOrEmpty(frame.args.wikiname) and frame.args.wikiname or		frame:expandTemplate {title = 'SummoningEventWikiName', args = {name = name, startDate = frame.args.start}} local summoningEventFocusArgs = List.map(List.zip(rarityHeroTable.Heroes, rarityHeroTable.Rarities, function (a, b) return {a, b} end), function (v)		return {title = 'SummoningEventFocusDefinition', args = {wikiname = wikiname, unit = v[1], rarity = v[2]}}	end)

local contents = { frame:expandTemplate { title = 'SummoningEventDefinition', args = { name = name, wikiname = wikiname, from = frame.args.from or frame.args.start ==  and  or Datetime.is_iso8601(frame.args.start) and frame.args.start or (frame.args.start .. ' 07:00:00'), to = frame.args.to or frame.args['end'] ==  and  or Datetime.is_iso8601(frame.args['end']) and frame.args['end'] or (frame.args['end'] .. ' 06:59:59'), eventType = frame.args.eventType or frame.args.bannerType, }		},		table.concat(List.map(summoningEventFocusArgs, function (targs) return frame:expandTemplate(targs) end)), '',		SummoningEvent._table { page = mw.title.getCurrentTitle.text, name = frame.args.name, startDate = startDate, endDate = endDate, heroes = table.concat(heroTable, ";"), extratitle = 'Description', extratext = frame.args.description, },		ytText, ' Appearance rates ', frame:expandTemplate {title = 'Hatnote', args = {"See Summonable Heroes for a full table of the regular pool of summonable heroes."}}, tostring(rateTbl), canFocusRatesEnabled and FocusRates.focusRates(frame, isNew) or '', frame:expandTemplate {title = 'Hatnote', args = {"For more detailed information, see Summon."}}, ' Skills ', p.skillsTable(frame, heroTable), ' Level 40 stats ', lv40stats, notesSection, frame:expandTemplate {title = 'Summoning Event Navbox'}, }	return table.concat(contents) end

return p