Documentation for this module may be created at Module:Page/Memento/doc
--<nowiki>
local p = {}
local h = {}
bit32 = require('bit32')
local cargo = require('Module:CargoUtil')
local util_table = require('Module:TableUtil')
local util_vars = require('Module:VarsUtil')
-- local model = require('Module:Data').model
local render_item_icon = require('Module:Render/Item')._icon2
local render_gear_icon = require('Module:Render/Gear')._icon2
local render_memento_icon = require('Module:Render/Memento')._icon2
local render_unit_icon = require('Module:Render/Unit')._icon2
local enums = require('Module:Data/Enums')
local yesno = require('Module:Yesno')
local skillLink = require("Module:LinkUtils").acdbLink
enums.eCardType = {
[0] = "None",
[1] = "Equipment",
[2] = "Enhance_exp",
[3] = "Enhance_trust"
}
local typeMap = {
[1] = 'Equipment',
[2] = 'Enhance EXP',
[3] = 'Enhance Trust',
}
h.flags = {
NONE = 0x0,
TRIGGER = 0x1,
BUFF = 0x2,
TRIGGER_BUFF = 0x3,
}
local function setdefault(dict, key, value)
dict[key] = dict[key] or value
return dict[key]
end
function h.quote( s )
if not s then return end
return ('%q'):format(s)
end
function h.makeInfobox(args)
local root = mw.html.create('div')
root:addClass('infobox')
root:addClass(args.class)
local heading = root:tag('div')
heading:addClass('heading')
local icon = heading:tag('div')
icon:addClass('infobox-icon')
icon:node(args.icon)
local name = heading:tag('div')
name:addClass('name')
name:wikitext(args.name)
local wrapper = root:tag('div')
wrapper:addClass('wrapper')
local dl = wrapper:tag('dl')
local function printRow(t, label, content)
if content == nil then return end
local dt = t:tag('dt')
dt:wikitext(label)
local dd = t:tag('dd')
dd:wikitext(content)
end
for i, label in ipairs(args.labels) do
printRow(dl, label, args.rows[label])
end
return tostring(root)
end
local cats = {}
function p.getData(iname)
local datapage = cargo.query{
tables = 'ConceptCard',
fields = '_pageName',
where = 'iname = "'..iname..'"',
groupBy = '_pageName, iname',
}[1]
local pagename = datapage and datapage._pageName or 'Data:Game/MasterParam/ConceptCard/'..iname
local frame = mw.getCurrentFrame()
local title = mw.title.new(pagename)
local content = title:getContent()
local args = {}
local params = content:match('^%s*%{%{#invoke:Data%|insert%|(.-)%}%}%s*$')
for param in mw.text.gsplit(params, '|', true) do
local k, v = param:match('([^=]+)=(.+)')
local obj = mw.text.jsonDecode(frame:preprocess(v))
if k == 'gl' or k == 'jp' then obj.server = k end
args[k] = obj
end
return args
end
local maxLevels = {1, 25, 30, 35, 40}
function h.getVCR(data)
local t = {}
local rows = cargo.query{
tables = {
'ConceptCard=CC',
'ConceptCard__trust_item_names=CC_IT_names', 'Item=IT', 'ItemLoc=ITL', 'Pages=ITP',
'ConceptCard__trust_item_counts=CC_IT_counts',
'ConceptCard__trust_artifact_names=CC_AF_names', 'Artifact=AF', 'ArtifactLoc=AFL', 'Pages=AFP',
'ConceptCard__trust_artifact_counts=CC_AF_counts',
},
join = {
'CC._ID=CC_IT_counts._rowID', 'CC._ID=CC_IT_names._rowID', 'CC_IT_names._value=IT.iname', 'IT.iname=ITL.iname', 'IT.iname=ITP.iname',
'CC._ID=CC_AF_counts._rowID', 'CC._ID=CC_AF_names._rowID', 'CC_AF_names._value=AF.iname', 'AF.iname=AFL.iname', 'AF.iname=AFP.iname',
},
where = {
'CC.iname="'..data.iname..'"',
'CC.server="gl"',
'COALESCE(IT.server,CC.server)=CC.server',
'COALESCE(ITL.lang,"english")="english"',
'COALESCE(CC_IT_names._position,0)=COALESCE(CC_IT_counts._position,0)',
'COALESCE(AF.server,CC.server)=CC.server',
'COALESCE(AFL.lang,"english")="english"',
'COALESCE(CC_AF_names._position,0)=COALESCE(CC_AF_counts._position,0)',
},
fields = {
'ITP._pageName=IT_pageName',
'CC_IT_names._position=CC_IT_idx',
'IT.iname=IT_iname',
'IT.icon=IT_icon',
'ITL.name=IT_name',
'IT.rare=IT_rare',
'IT.type=IT_type',
'CC_IT_counts._value=IT_count',
'CC_AF_names._position=CC_AF_idx',
'AFP._pageName=AF_pageName',
'AF.iname=AF_iname',
'AF.icon=AF_icon',
'AFL.name=AF_name',
'AF.rini=AF_rare',
'AF.type=AF_type',
'CC_AF_counts._value=AF_count',
}
}
local items = {}
local gears = {}
for i, row in ipairs(rows) do
local idx = tonumber(row.CC_IT_idx)
if idx then
items[idx] = items[idx] or render_item_icon{data={
_pageName = row.IT_pageName,
iname = row.IT_iname,
icon = row.IT_icon,
name = row.IT_name,
rare = tonumber(row.IT_rare),
type = tonumber(row.IT_type),
}, name='none', count=(tonumber(row.IT_count) or 0) > 1 and tonumber(row.IT_count)}
end
local idx = tonumber(row.CC_AF_idx)
if idx then
items[idx] = items[idx] or render_gear_icon{data={
_pageName = row.AF_pageName,
iname = row.AF_iname,
icon = row.AF_icon,
name = row.AF_name,
rare = tonumber(row.AF_rare),
type = tonumber(row.AF_type),
}, name='none', count=(tonumber(row.AF_count) or 0) > 1 and tonumber(row.AF_count)}
end
end
local t = {}
t[#t+1] = table.concat(items)
t[#t+1] = table.concat(gears)
return #t > 0 and table.concat(t) or nil
end
p.x = h.getVCR
function h.getUnitReward(data)
local iname = data.first_get_unit or ''
if iname == '' then return nil end
local row = cargo.query{
tables = {'Unit=UN', 'UnitLoc=UNL', 'Pages=P'},
join = {'UN.iname = UNL.iname', 'UN.iname = P.iname'},
fields = {
'UN.iname = iname',
'UNL.name = name',
'P._pageName = _pageName',
'UN.rare = rare',
'UN.img = icon',
},
where = {
'UN.iname = "'..iname..'"',
'UN.server = "gl"',
'UNL.lang = "english"',
},
}[1]
return render_unit_icon{data=row, size='small'}
end
function h.getReliefList(iname)
if iname == '' then return nil end
local reliefList = mw.loadData("Module:Data/Extra/MementoReliefList")[iname] or nil
if reliefList == nil then return nil end
local reliefInames = {}
for i, relief in ipairs(reliefList) do
reliefInames[#reliefInames+1] = '"'..relief..'"'
end
local itemList = cargo.query{
tables = {"Item=IT", "ItemLoc=ITL", "Pages=P"},
join = {'IT.iname = ITL.iname', 'IT.iname = P.iname'},
fields = {
'IT.iname = iname',
'ITL.name = name',
'P._pageName = _pageName',
'IT.rare = rare',
'IT.type = type',
'IT.icon = icon',
},
where = {
'IT.server = "gl"',
'ITL.lang = "english"',
'IT.iname IN ('..table.concat(reliefInames, ',')..')',
},
} or {}
if #itemList == 0 then return nil end
local t = {}
for i, reliefData in ipairs(itemList) do
t[#t+1] = render_item_icon{data=reliefData, name='none'}
end
return (table.concat(t) or nil)
end
function h.getMementoGroupIcons(groupList)
if not groupList or groupList == '' then return nil end
local conceptCardGroupList = mw.text.split(groupList, '|')
local groupIcons = {}
for i, group in ipairs(conceptCardGroupList) do
local groupImage = enums.mementoGroupImageFromKey(group) or nil
local groupName = enums.mementoGroupFromKey(group) or ''
if groupImage then
groupIcons[#groupIcons+1] = '[[File:Game,ConceptCardGroupImage,' .. groupImage .. '|64px|alt=' .. groupName..']]'
end
end
return (table.concat(groupIcons) or nil)
end
function h.minQuery(args)
if type(args.fields) == 'string' and args.fields == '*' then
local subModel = mw.loadData('Module:Data/Model/'..args.tables)
local t = {'_pageName', 'server'}
for k,v in pairs(subModel) do
t[#t+1] = k
end
args.fields = t
end
local row = cargo.query(args)[1]
if not row then return end
local obj = {}
for k,v in pairs(row) do
if type(v) == 'table' then
if #v > 0 then obj[k] = v end
elseif v ~= '' then
obj[k] = v
end
end
return obj
end
function h.queryBuff(iname)
if not iname then return end
return h.minQuery{tables='Buff',fields='*', where='iname="'..iname..'" AND server="gl"'}
end
function h.printEffects(root, args)
if not args then return end
if not args.effects then return end
local stat = nil
local card_skills = {}
local abilities = {}
for i, eff in ipairs(args.effects) do
if eff.statusup_skill then
stat = eff
end
if eff.card_skill then
card_skills[#card_skills+1] = eff
end
if eff.abil_iname then
abilities[#abilities+1] = eff
end
end
local maxLevel = maxLevels[args.rare+1]
if stat then
root:tag('h2'):wikitext('Stats')
h.printStatsTable(root, stat.statusup_skill, maxLevel)
end
if #card_skills > 0 then
root:tag('h2'):wikitext('Group skills')
for i, eff in ipairs(card_skills) do
local skill = cargo.query{
tables = {'Skill', 'SkillLoc'},
join = 'Skill.iname = SkillLoc.iname',
fields = {'Skill._pageName', 'name'},
where = {
'Skill.iname = "'..eff.card_skill..'"',
'Skill.server = "gl"',
'SkillLoc.lang = "english"',
},
}[1]
local skillname = skill and skill.name or '???'
root:tag('h3'):wikitext(skillname)
h.printStatsTable(root, eff.card_skill, maxLevel)
if eff.add_card_skill_buff_awake then -- limit break buff
root:tag('h4'):wikitext('Limit Break')
local buff_details = cargo.query{
tables = 'BuffDetail',
fields = {
'idx',
'calc',
'tktag',
'type',
'vini',
'vmax',
'vone',
},
where = {
'BuffDetail.server = "gl"',
'BuffDetail.buff_iname = "'..eff.add_card_skill_buff_awake..'"',
},
orderBy = 'idx',
}
if #buff_details == 0 then
root:tag('div'):wikitext('Missing buff ' .. eff.add_card_skill_buff_awake .. ' from DB')
return
end
-- Show limit break
local tbl = root:tag('table'):addClass('wikitable')
local tr = tbl:tag('tr')
tr:tag('th'):wikitext('Type')
for lb=1,5 do tr:tag('th'):wikitext('LB'..lb) end
for i, buff in ipairs(buff_details) do
tr = tbl:tag('tr')
if tonumber(buff.type or 0) > 0 then
local statName = enums.statNameFromType(buff.type, buff.tktag)
tr:tag('td'):wikitext(statName)
local min, max = buff.vini, buff.vmax
local per = (max - min) / 4
for lb=1,5 do
local value = math.floor((lb - 1) * per + min)
tr:tag('td'):wikitext(string.format('%+d', value))
end
end
end
end
if eff.add_card_skill_buff_lvmax then
root:tag('h4'):wikitext('Max Limit Break')
local buffdetails = cargo.query{
tables = 'BuffDetail',
fields = {
'idx',
'calc',
'tktag',
'type',
'vini',
'vmax',
'vone',
},
where = {
'BuffDetail.server = "gl"',
'BuffDetail.buff_iname = "'..eff.add_card_skill_buff_lvmax..'"',
},
orderBy = 'idx',
}
if #buffdetails == 0 then
root:tag('div'):wikitext('Missing buff '..eff.add_card_skill_buff_lvmax..' from DB')
else
local tbl = root:tag('table'):addClass('wikitable')
local tr = tbl:tag('tr')
tr:tag('th'):wikitext('Type')
for lb=5,5 do tr:tag('th'):wikitext('LB'..lb) end
for i, buff in ipairs(buffdetails) do
tr = tbl:tag('tr')
if tonumber(buff.type or 0) > 0 then
local statName = enums.statNameFromType(buff.type, buff.tktag)
tr:tag('td'):wikitext(statName)
local min, max = buff.vini, buff.vmax
local per = (max - min) / 4
for lb=5,5 do
local value = math.floor((lb - 1) * per + min)
tr:tag('td'):wikitext(string.format('%+d', value))
end
end
end
end
end
if eff.cnds_iname then
h.printEffect(root, eff)
end
end
end
if #abilities > 0 then
root:tag('h2'):wikitext('Vision abilities')
for _, eff in ipairs(abilities) do
h.printAbility(root, eff)
if eff.cnds_iname then
h.printEffect(root, eff)
end
end
end
end
function h.printAbility(root, eff)
if not eff then return end
if not eff.abil_iname then return end
if not eff.abil_iname_lvmax then return end
local ability = {}
local ids = {
eff.abil_iname,
eff.abil_iname_lvmax,
}
local t = {}
local rows = cargo.query{
tables = {
'Ability = AB',
'AbilityLoc = ABL',
'Skill = SK',
'SkillLoc = SKL',
},
join = {
'AB.iname = ABL.iname',
'AB.skl1 = SK.iname',
'SK.iname = SKL.iname',
},
fields = {
'AB.iname = iname',
'AB.type_detail = type_detail',
'AB.slot = slot',
'AB.skl1 = skl1',
'ABL.name = ab_name',
'SKL.iname = sk_iname',
'SKL.name = sk_name',
'SKL.expr = sk_expr',
'SK.atk_type = sk_atk_type',
'SK.atk_det = sk_atk_det',
'SK.elem = sk_elem',
'SK.eff_type = sk_eff_type',
'SK.eff_val_ini = sk_eff_val_ini',
'SK.eff_val_max = sk_eff_val_max',
'SK.count = sk_count',
'SK.cost = sk_cost',
'SK.eff_h = sk_eff_h',
'SK.sran = sk_sran',
'SK.rangemin = sk_rangemin',
'SK.rangemax = sk_rangemax',
'SK.ssco = sk_ssco',
'SK.scope = sk_scope',
},
where = {
'AB.iname IN ('..util_table.concat(ids, ',', h.quote)..')',
'AB.server="gl"',
'ABL.lang = "english"',
'SK.server IS NULL OR SK.server = "gl" AND SKL.lang = "english"',
},
}
for i, row in ipairs(rows) do
t[row.iname] = t[row.iname] or {
name = row.ab_name,
type_detail = row.type_detail,
slot = tonumber(row.slot),
}
if row.skl1 then
t[row.iname].skl1 = t[row.iname].skl1 or {
name = row.sk_name,
iname = row.sk_iname,
expr = row.sk_expr,
atk_type = tonumber(row.sk_atk_type),
atk_det = tonumber(row.sk_atk_det),
elem = tonumber(row.sk_elem),
eff_type = tonumber(row.sk_eff_type),
eff_val_ini = tonumber(row.sk_eff_val_ini),
eff_val_max = tonumber(row.sk_eff_val_max),
count = tonumber(row.sk_count),
cost = tonumber(row.sk_cost),
eff_h = tonumber(row.sk_eff_h),
sran = tonumber(row.sk_sran),
rangemin = tonumber(row.sk_rangemin),
rangemax = tonumber(row.sk_rangemax),
ssco = tonumber(row.sk_ssco),
scope = tonumber(row.sk_scope),
}
end
end
ability.base = t[eff.abil_iname]
ability.max = t[eff.abil_iname_lvmax]
local baseName = ability.base.name
local maxName = ability.max.name
root:tag('h3'):wikitext(baseName)
if maxName ~= baseName then
-- TODO: Cards have different skill name for base and max.
end
for _, key in ipairs{'base', 'max'} do
-- root:tag('h4'):wikitext('Ability '..key)
local ab = ability[key]
local skill = ab.skl1
local abNameLink = 'Ability '..key
if skill and skill.iname then
abNameLink = '['..skillLink(skill.iname)..' '..abNameLink..']'
end
root:tag('h4'):wikitext(abNameLink)
if ab.type_detail then
local abType = enums.EAbilityTypeDetail[ab.type_detail]
if abType and abType ~= 'VisionAbility' then
error('Expected ability type "VisionAbility", but was "'..tostring(abType)..'".')
end
end
local ul = root:tag('ul')
if ab.slot then
local slot = enums.EAbilitySlot[ab.slot]
ul:tag('li'):wikitext('Slot: [[File:MasterAbilityIcon.png|20px|'..slot..'|link=]] '..slot)
end
if skill then
if (skill.atk_type or 0) > 0 then
local atk_type = enums.AttackTypes[skill.atk_type]
if atk_type == 'MagAttack' then
atk_type = 'Magical'
elseif atk_type == 'PhyAttack' then
atk_type = 'Physical'
end
ul:tag('li'):wikitext('DMG Type: [[File:Attack Class '..atk_type..'.png|20px|'..atk_type..'|link=]] '..atk_type)
end
if (skill.atk_det or 0) > 0 then
local atk_det = enums.attackDetailNameFromKey(skill.atk_det)
if atk_det == 'Blow' then
atk_det = 'Strike'
end
ul:tag('li'):wikitext('ATK Type: [[File:Attack Type '..atk_det..'.png|20px|'..atk_det..'|link=]] '..atk_det)
end
if (skill.elem or 0) > 0 then
local elem = enums.elemFromKey(skill.elem)
ul:tag('li'):wikitext('Element: [[File:'..elem..'Element.png|20px|link=]] '..elem)
end
-- Explanation
root:tag('p'):wikitext(skill.expr)
-- Skill effect
if (skill.eff_type or 0) > 0 and skill.eff_val_ini and skill.eff_val_max then
local tbl = root:tag('table'):addClass('wikitable')
tbl:tag('caption'):wikitext('Skill Effect')
local tr = tbl:tag('tr')
tr:tag('th'):wikitext('Type')
tr:tag('th'):wikitext('Min')
tr:tag('th'):wikitext('Max')
tr = tbl:tag('tr')
tr:tag('td'):wikitext(enums.SkillEffectTypes[skill.eff_type])
tr:tag('td'):wikitext((100+skill.eff_val_ini)..'%')
tr:tag('td'):wikitext((100+skill.eff_val_max)..'%')
end
-- Scaling
-- Jewel cost
local ul = root:tag('ul')
if (skill.count or 0) > 0 then
ul:tag('li'):wikitext('Charges: ' .. skill.count)
end
if (skill.cost or 0) > 0 then
ul:tag('li'):wikitext('Jewel Cost: ' .. skill.cost)
end
if (skill.eff_h or 0) > 0 then
ul:tag('li'):wikitext('Height: ' .. skill.eff_h)
end
if skill.sran then
ul:tag('li'):wikitext('Select Range: ' .. enums.ESelectType[skill.sran])
ul:tag('li'):wikitext('Range: ' .. (skill.rangemin or 0) .. '-'.. (skill.rangemax or 0))
end
if skill.ssco then
ul:tag('li'):wikitext('Select Scope: ' .. enums.ESelectType[tonumber(skill.ssco)])
ul:tag('li'):wikitext('Scope: ' .. (skill.scope or 0))
end
end
end
end
function h.printEffect(root, args)
-- Stats
if args.statusup_skill then
h.printStatsTable(root, args.statusup_skill, args.rare)
end
local inames = {}
-- Condition groups
for iname, flag in pairs(h.getTriggerGroups(args.cnds_iname) or {}) do
inames[iname] = inames[iname] or {}
inames[iname].hasConditions = true
end
-- Buff groups
for iname, flag in pairs(h.getBuffGroups(args.add_card_skill_buff_awake) or {}) do
inames[iname] = inames[iname] or {}
inames[iname].hasBuff = true
end
local icons = {
['Trigger + Buff'] = {Unit={},Job={}},
['Trigger'] = {Unit={},Job={}},
['Buff'] = {Unit={},Job={}},
[''] = {Unit={},Job={}},
}
local ids = util_table.concat(util_table.getKeys(inames), ',', h.quote)
if ids == '' then return end
local rows = cargo.query{
tables = {
'Pages',
'Unit', 'UnitLoc',
'Job', 'JobLoc',
},
join = {
'Pages.iname = Unit.iname',
'Unit.iname = UnitLoc.iname',
'Pages.iname = Job.iname',
'Job.iname = JobLoc.iname',
},
fields = {
'Pages.iname = iname',
'Pages._pageName = _pageName',
'Pages.type = entityType',
'COALESCE(Job.ac2d, Job.mdl, Unit.img) = icon',
'COALESCE(JobLoc.name, UnitLoc.name) = name',
},
where = {
'Pages.iname IN ('..ids..')',
'Job.server IS NULL OR Job.server = "gl" AND JobLoc.lang = "english"',
'Unit.server IS NULL OR Unit.server = "gl" AND UnitLoc.lang = "english"',
},
}
for i, row in ipairs(rows) do
local thing = inames[row.iname]
local triggerbuff = {}
if thing.hasConditions then
triggerbuff[#triggerbuff+1] = 'Trigger'
end
if thing.hasBuff then
triggerbuff[#triggerbuff+1] = 'Buff'
end
triggerbuff = table.concat(triggerbuff, ' + ')
local tp = row.entityType
local render_icon = require('Module:Render/'..tp)._icon2
local t = icons[triggerbuff][tp]
t[row.iname] = {
iname = row.iname,
name = row.name,
icon = render_icon({data=row, size='small'}),
}
end
if args.add_card_skill_buff_awake then
for _, triggerbuff in ipairs({'Trigger + Buff', 'Trigger', 'Buff', ''}) do
for _, tp in ipairs({'Unit', 'Job'}) do
local objs = {}
for iname, obj in pairs(icons[triggerbuff][tp]) do
objs[#objs+1] = obj
end
if next(objs) then
local heading = root:tag('h4')
heading:wikitext(tp, ' group')
if triggerbuff ~= '' then
heading:wikitext(' (', triggerbuff:lower(), ')')
end
table.sort(objs, function(a, b)
return a.name < b.name
end)
for i, obj in ipairs(objs) do
root:wikitext(obj.icon)
end
end
end
end
elseif args.abil_iname then
local objs = {}
if next(icons.Trigger.Unit) and next(icons.Trigger.Job) then
local unit_inames = util_table.getKeys(icons.Trigger.Unit)
local job_inames = util_table.getKeys(icons.Trigger.Job)
local un_ids = util_table.concat(unit_inames, ',', h.quote)
local jb_ids = util_table.concat(job_inames, ',', h.quote)
for _, row in ipairs(cargo.query{
tables = {
'Unit',
'Unit__jobsets',
'JobSet',
},
fields = {
'Unit.iname = un_iname',
'JobSet.job = jb_iname',
},
where = {
'Unit.server = "gl"',
'JobSet.server = "gl"',
'Unit.iname IN ('..un_ids..')',
'JobSet.job IN ('..jb_ids..')',
},
join = {
'Unit._ID = Unit__jobsets._rowID',
'Unit__jobsets._value = JobSet.iname',
},
}) do
objs[#objs+1] = {
unit=icons.Trigger.Unit[row.un_iname],
job=icons.Trigger.Job[row.jb_iname],
}
end
local heading = root:tag('h4')
heading:wikitext('Unit and job restriction')
table.sort(objs, function(a, b)
if a.unit.name ~= b.unit.name then
return a.unit.name < b.unit.name
end
return a.job.name < b.job.name
end)
local ul = root:tag('ul')
for _, obj in ipairs(objs) do
local li = ul:tag('li')
li:wikitext(obj.unit.icon, ' + ', obj.job.icon)
end
elseif next(icons.Trigger.Unit) then
local heading = root:tag('h4')
heading:wikitext('Unit restriction')
for iname, obj in pairs(icons.Trigger.Unit) do
objs[#objs+1] = obj
end
table.sort(objs, function(a,b) return a.name < b.name end)
for _, obj in ipairs(objs) do
root:wikitext(obj.icon)
end
elseif next(icons.Trigger.Job) then
local heading = root:tag('h4')
heading:wikitext('Job restriction')
for iname, obj in pairs(icons.Trigger.Job) do
objs[#objs+1] = obj
end
table.sort(objs, function(a,b) return a.name < b.name end)
for _, obj in ipairs(objs) do
root:wikitext(obj.icon)
end
end
end
end
function h.getTriggerGroups(cnds_iname)
-- Condition groups
if not cnds_iname then return end
local rows = cargo.query{
tables = {
'ConceptCardConditions = CCC',
'ConceptCardConditions__birth_id = CCC__UN2',
'JobGroup = JG1',
'JobGroup__jobs = JG1__JB1',
'Job = JB1',
'UnitGroup = UG1',
'UnitGroup__units = UG1__UN1',
'Unit = UN1',
'Unit = UN2',
'Unit = UN3',
},
join = {
'CCC.job_group = JG1.iname',
'JG1._ID = JG1__JB1._rowID',
'JG1__JB1._value = JB1.iname',
'CCC.un_group = UG1.iname',
'UG1._ID = UG1__UN1._rowID',
'UG1__UN1._value = UN1.iname',
'CCC._ID = CCC__UN2._rowID',
'CCC__UN2._value = UN2.birth_id',
'CCC.sex = UN3.sex',
},
fields = {
'COALESCE(JB1.origin, JB1.iname) = jb_iname1',
'UN1.iname = un_iname1',
'UN2.iname = un_iname2',
'UN3.iname = un_iname3',
},
where = {
'CCC.iname = "'..cnds_iname..'"',
'CCC.server = "gl"',
'JG1.server IS NULL OR JB1.server IS NULL OR JG1.server = "gl" AND JB1.server = "gl"',
'UG1.server IS NULL OR UN1.server IS NULL OR UG1.server = "gl" AND UN1.server = "gl" AND UN1.ai = "AI_PLAYER" AND (UN1.notsmn IS NULL OR UN1.hero = 1)',
'UN2.server IS NULL OR UN2.server = "gl" AND UN2.ai = "AI_PLAYER" AND (UN2.notsmn IS NULL OR UN2.hero = 1)',
'UN3.server IS NULL OR UN3.server = "gl" AND UN3.ai = "AI_PLAYER" AND (UN3.notsmn IS NULL OR UN3.hero = 1)',
},
}
local t = {}
for _, row in ipairs(rows) do
for k, v in pairs(row) do
t[v] = h.flags.TRIGGER
end
end
return t
end
function h.getBuffGroups(buff_iname)
if not buff_iname then return end
local rows = cargo.query{
tables = {
'Buff = BF', -- buff
'UnitGroup = UG0', -- buff.un_group
'UnitGroup__units = UG0__UN0',
'Unit = UN0', -- buff.un_group.units
'Buff__custom_targets = BF__CT',
'CustomTarget = CT', -- buff.custom_targets
'CustomTarget__unit_groups = CT__UG1',
'UnitGroup = UG1', -- buff.custom_targets.unit_groups
'UnitGroup__units = UG1__UN1',
'Unit = UN1', -- buff.custom_targets.unit_groups.units
'CustomTarget__units = CT__UN2',
'Unit = UN2', -- buff.custom_targets.units
'Unit = UN3', -- buff.custom_targets.birth_id
'Unit = UN4', -- buff.custom_targets.sex
'CustomTarget__job_groups = CT__JG1',
'JobGroup = JG1', -- buff.custom_targets.job_groups
'JobGroup__jobs = JG1__JB1',
'Job = JB1', -- buff.custom_targets.job_groups.jobs
'CustomTarget__jobs = CT__JB2',
'Job = JB2', -- buff.custom_targets.jobs
},
join = {
'BF.un_group = UG0.iname',
'BF._ID = BF__CT._rowID', 'BF__CT._value = CT.iname',
'UG0._ID = UG0__UN0._rowID', 'UG0__UN0._value = UN0.iname',
'CT._ID = CT__UG1._rowID', 'CT__UG1._value = UG1.iname',
'UG1._ID = UG1__UN1._rowID', 'UG1__UN1._value = UN1.iname',
'CT._ID = CT__UN2._rowID', 'CT__UN2._value = UN2.iname',
'CT.birth_id = UN3.birth_id',
'CT.sex = UN4.sex',
'CT._ID = CT__JG1._rowID', 'CT__JG1._value = JG1.iname',
'JG1._ID = JG1__JB1._rowID', 'JG1__JB1._value = JB1.iname',
'CT._ID = CT__JB2._rowID', 'CT__JB2._value = JB2.iname',
},
fields = {
'UN0.iname = un_iname0',
'UN1.iname = un_iname1',
'UN2.iname = un_iname2',
'UN3.iname = un_iname3',
'UN4.iname = un_iname4',
'COALESCE(JB1.origin, JB1.iname) = jb_iname1',
'COALESCE(JB2.origin, JB2.iname) = jb_iname2',
},
where = {
'BF.iname = "'..buff_iname..'"',
'BF.server = "gl"',
'CT.server = "gl"',
'UG0.server IS NULL OR UN0.server IS NULL OR UG0.server = "gl" AND UN0.server = "gl" AND UN0.ai = "AI_PLAYER" AND (UN0.notsmn IS NULL OR UN0.hero = 1)',
'UG1.server IS NULL OR UN1.server IS NULL OR UG1.server = "gl" AND UN1.server = "gl" AND UN1.ai = "AI_PLAYER" AND (UN1.notsmn IS NULL OR UN1.hero = 1)',
'UN2.server IS NULL OR UN2.server = "gl" AND UN2.ai = "AI_PLAYER" AND (UN2.notsmn IS NULL OR UN2.hero = 1)',
'UN3.server IS NULL OR UN3.server = "gl" AND UN3.ai = "AI_PLAYER" AND (UN3.notsmn IS NULL OR UN3.hero = 1)',
'UN4.server IS NULL OR UN4.server = "gl" AND UN4.ai = "AI_PLAYER" AND (UN4.notsmn IS NULL OR UN4.hero = 1)',
'JG1.server IS NULL OR JB1.server IS NULL OR JG1.server = "gl" AND JB1.server = "gl"',
'JB2.server IS NULL OR JB2.server = "gl"',
},
}
local t = {}
for _, row in ipairs(rows) do
for k, v in pairs(row) do
t[v] = h.flags.BUFF
end
end
return t
end
function h.printStatsTable(root, skill_iname, maxLevel)
if not skill_iname then return end
local rows = cargo.query{
tables = {
'Skill = SK',
'BuffDetail = TBD',
'BuffDetail = SBD',
},
join = {
'SK.t_buff = TBD.buff_iname',
'SK.s_buff = SBD.buff_iname',
},
fields = {
'TBD.idx = t_idx',
'TBD.calc = t_calc',
'TBD.tktag = t_tktag',
'TBD.type = t_type',
'TBD.vini = t_vini',
'TBD.vmax = t_vmax',
'TBD.vone = t_vone',
'SBD.idx = s_idx',
'SBD.calc = s_calc',
'SBD.tktag = s_tktag',
'SBD.type = s_type',
'SBD.vini = s_vini',
'SBD.vmax = s_vmax',
'SBD.vone = s_vone',
},
where = {
'SK.iname="'..skill_iname..'"',
'SK.server="gl"',
'COALESCE(TBD.server,"gl")="gl"',
'COALESCE(SBD.server,"gl")="gl"',
},
}
if #rows == 0 then return end
local t_buff_details = {}
local s_buff_details = {}
for i, row in ipairs(rows) do
local idx = tonumber(row.t_idx)
if idx then
t_buff_details[idx] = {
idx = row.t_idx,
calc = row.t_calc,
tktag = row.t_tktag,
type = row.t_type,
vini = row.t_vini,
vmax = row.t_vmax,
vone = row.t_vone,
}
end
local idx = tonumber(row.s_idx)
if idx then
s_buff_details[idx] = {
idx = row.s_idx,
calc = row.s_calc,
tktag = row.s_tktag,
type = row.s_type,
vini = row.s_vini,
vmax = row.s_vmax,
vone = row.s_vone,
}
end
end
local stats = {
}
for i, buff in ipairs(t_buff_details) do
if tonumber(buff.type or 0) > 0 then
local tp = tostring(buff.type)
local values = {}
local min, max = buff.vini, buff.vmax
local per = (max - min) / (maxLevel - 1)
for level=1,maxLevel do
values[level] = math.floor((level - 1) * per + min)
end
stats[tp] = values
end
end
-- Render
root:tag('h4'):wikitext('Simple stats')
local simple = root:tag('table'):addClass('wikitable')
local tr = simple:tag('tr')
tr:tag('th'):wikitext('Type')
tr:tag('th'):wikitext('Lvl 1')
tr:tag('th'):wikitext('Lvl '..(maxLevel-10))
tr:tag('th'):wikitext('Lvl '..maxLevel)
for i, buff in ipairs(t_buff_details) do
if tonumber(buff.type or 0) > 0 then
local tr = simple:tag('tr')
local tp = tostring(buff.type)
local values = stats[tp]
local statName = enums.statNameFromType(buff.type, buff.tktag)
tr:tag('td'):wikitext(statName)
tr:tag('td'):wikitext(string.format('%+d', values[1]))
tr:tag('td'):wikitext(string.format('%+d', values[maxLevel-10]))
tr:tag('td'):wikitext(string.format('%+d', values[maxLevel]))
end
end
--[==[ Scrollable table?
<div style="display: table">
<div style="max-height: 240px; overflow-y: scroll; box-sizing: border-box; padding: 4px; border: 1px solid #131313">
-- Long table here
</div>
</div>
--]==]
root:tag('h4'):wikitext('Detailed stats')
local detailed = root:tag('div'):css{
display = 'flex',
['flex-wrap'] = 'wrap',
}
for col = 1, maxLevel/10 do
local flexitem = detailed:tag('div'):css{
flex = 0,
background = col % 2 == 0 and 'orange' or 'salmon', -- yum ^_^
}
local wikitable = flexitem:tag('table'):addClass('wikitable')
local tr = wikitable:tag('tr')
tr:tag('th'):wikitext('Level')
for i, buff in ipairs(t_buff_details) do
if tonumber(buff.type or 0) > 0 then
local statName = enums.statNameFromType(buff.type, buff.tktag)
tr:tag('th'):wikitext(statName)
end
end
for row = 1, 10 do
local level = (col - 1) * 10 + row
local tr = wikitable:tag('tr')
tr:tag('td'):wikitext(level)
for i, buff in ipairs(t_buff_details) do
if tonumber(buff.type or 0) > 0 then
local tp = tostring(buff.type)
tr:tag('td'):wikitext(string.format('%+d', stats[tp][level]))
end
end
end
end
end
local renderEventRewardList = function(root, iname)
if iname == nil then return end
local sourceList = cargo.query{tables='EventReward', fields='_pageName,source', where = 'iname="'..iname..'"'} or {}
if #sourceList < 1 then return end
root:tag('h2'):wikitext('Event Reward Sources')
local ul = root:tag('ul')
for ignore, sourceItem in ipairs(sourceList) do
ul:tag('li'):wikitext('[['..sourceItem['_pageName']..']] ('..(sourceItem['source'])..')')
end
end
function p.renderPage(iname)
local card_rows = cargo.query{
tables = {
'ConceptCard = CC',
'ConceptCardLoc = CCLoc',
'ConceptCardEffect = CCE',
},
join = {
'CC.iname = CCLoc.iname',
'CC.iname = CCE.cc_iname',
},
fields = {
'CC.iname = iname',
-- Graphics
'CC.icon = icon',
-- Type
'CC.type = type', -- eCardType
'CC.rare = rare',
'CC.lvcap = lvcap', -- Default defined by rare
'CC.birth_id = birth_id', -- The origin of the memento
'CC.coin_item = coin_item', -- Not sure what this is used for, maybe related to the coin shop
-- Value
'CC.sell = sell', -- Integer",
'CC.not_sale = not_sale', -- Boolean",
'CC.en_cost = en_cost', -- Integer",
'CC.en_exp = en_exp', -- Integer",
'CC.en_trust = en_trust', -- Integer",
-- Rewards
'CC.trust_artifact_names = trust_artifact_names', -- {"String", list='|', dataRef="MasterParam/Artifact"},
'CC.trust_artifact_counts = trust_artifact_counts', -- {"Integer", list='|'},
'CC.trust_item_names = trust_item_names', -- {"String", list='|', dataRef="MasterParam/Item"},
'CC.trust_item_counts = trust_item_counts', -- {"Integer", list='|'},
-- References
'CC.first_get_unit = first_get_unit', -- {"String", dataRef="MasterParam/Unit"}, -- Unit acquired when first obtaining memento
-- Leader Skill
'CC.concept_card_groups = concept_card_groups', -- {"String", list='|', dataRef="MasterParam/ConceptCardGroup"},
'CC.leader_skill = leader_skill', -- {"String", dataRef="MasterParam/Skill"},
-- Labels
'CCLoc.name = name',
'CCLoc.flavor = flavor',
'CCE.abil_iname = abil_iname',
'CCE.abil_iname_lvmax = abil_iname_lvmax',
'CCE.add_card_skill_buff_awake = add_card_skill_buff_awake',
'CCE.add_card_skill_buff_lvmax = add_card_skill_buff_lvmax',
'CCE.card_skill = card_skill',
'CCE.cnds_iname = cnds_iname',
'CCE.is_decrease_eff = is_decrease_eff',
'CCE.skin = skin',
'CCE.statusup_skill = statusup_skill',
},
where = {
'CC.iname = "'..iname..'"',
'CC.server = "gl"',
'CCLoc.lang = "english"',
'COALESCE(CCE.server, "gl") = "gl"',
},
}
mw.logObject(card_rows)
local data = nil
for i, row in ipairs(card_rows) do
data = data or {
iname = row.iname,
icon = row.icon,
type = row.type,
rare = row.rare,
lvcap = row.lvcap,
birth_id = row.birth_id,
coin_item = row.coin_item,
sell = row.sell,
not_sale = row.not_sale,
en_cost = row.en_cost,
en_exp = row.en_exp,
en_trust = row.en_trust,
trust_artifact_names = row.trust_artifact_names,
trust_artifact_counts = row.trust_artifact_counts,
trust_item_names = row.trust_item_names,
trust_item_counts = row.trust_item_counts,
first_get_unit = row.first_get_unit,
concept_card_groups = row.concept_card_groups,
leader_skill = row.leader_skill,
name = row.name,
flavor = row.flavor,
effects = {},
}
data.effects[i] = {
abil_iname = row.abil_iname,
abil_iname_lvmax = row.abil_iname_lvmax,
add_card_skill_buff_awake = row.add_card_skill_buff_awake,
add_card_skill_buff_lvmax = row.add_card_skill_buff_lvmax,
card_skill = row.card_skill,
cnds_iname = row.cnds_iname,
is_decrease_eff = row.is_decrease_eff,
skin = row.skin,
statusup_skill = row.statusup_skill,
}
end
if not data then
return '`'..iname..'` not found in ConceptCard table.'
end
local effects = data.effects
cats[#cats+1] = 'Memento'
local name = data.name
local icon = mw.html.create('div')
icon:addClass('item-icon')
local img = icon:tag('div')
img:addClass('img x-'..data.rare..' y-4')
img:css{
['width'] = '57px',
['height'] = '57px',
['padding'] = '3.5px',
}
img:wikitext('[[File:Game,ConceptCardIcon,',data.icon,'.png|57px]]')
-- Memento extra data
local extra = mw.loadData("Module:Data/Extra/Memento")[iname] or {}
local releaseDates
for _, region in ipairs{'jp', 'gl'} do
local date = extra[region..'Date']
if date then
releaseDates = releaseDates or mw.html.create('ul')
releaseDates:tag('li'):wikitext(region:upper(), ': ', date)
end
end
local root = mw.html.create()
-- Info Box
local infobox = h.makeInfobox{
name = name,
icon = icon,
labels = {
'Type',
'Rank',
'Max level',
'Enhancer cost',
'Enhancer EXP',
'Enhancer trust',
'Vision Clear Reward',
'Gives unit',
'Limit Break Relief',
'Memento Group',
'Source',
'Release dates',
'Global only',
'External links',
},
rows = {
['Type'] = typeMap[tonumber(data.type)],
['Rank'] = (data.rare + 1)..'★',
['Max level'] = maxLevels[data.rare + 1],
['Enhancer cost'] = data.en_cost, -- zeni required to upgrade a memento with this memento
['Enhancer EXP'] = data.en_exp, -- EXP given by this memento
['Enhancer trust'] = data.en_trust,
['Vision Clear Reward'] = h.getVCR(data),
['Gives unit'] = h.getUnitReward(data),
['Limit Break Relief'] = h.getReliefList(iname),
['Memento Group'] = h.getMementoGroupIcons(data.concept_card_groups or ''),
['Source'] = extra.source or 'Unreleased',
['Release dates'] = releaseDates and tostring(releaseDates) or nil,
['Global only'] = extra.glOnly and 'Yes' or nil,
['External links'] = '[http://www.alchemistcodedb.com/card/'..iname:gsub('_','-'):lower()..' AlchemistCodeDB]',
}
}
root:node(infobox)
if tonumber(data.type) and typeMap[tonumber(data.type)] then
cats[#cats+1] = typeMap[tonumber(data.type)] .. ' memento'
end
-- Body
-- Card Image + Flavor
root:tag('div'):addClass('responsive-img')
:css{
['margin'] = 'auto',
['display'] = 'flex',
['flex-direction'] = 'column',
['min-width'] = '300px',
}
:tag('div')
:wikitext('[[File:Game,ConceptCard,', data.icon, '.png|512px]]')
:done()
:tag('div'):addClass('flavor')
:css{
['max-width'] = '1024px',
['padding'] = '8px',
}
:wikitext(data.flavor)
:done()
h.printLeaderSkill(root, data.leader_skill)
-- TODO: Stats + Effects
-- h.printEffects2(root, data.iname)
h.printEffects(root, {
rare = data.rare,
lvmax = data.lvmax,
effects = effects,
})
-- Event Reward Sources
renderEventRewardList(root, iname)
-- Category
for i, cat in ipairs(cats) do
root:wikitext('[[Category:', cat, ']]')
end
-- TODO Implement http://cdn.alchemistcodedb.com/assets/big-card-frames-b34ac394d6035fb657d491b956e2c4764836b51b9361fccc4b31e722a27df510.png
return tostring(root)
end
local function renderTransclude(iname, args)
local type = mw.text.trim(args[1])
args[1] = iname
if type == 'Icon' then
args.data = cargo.query{
tables = {'ConceptCard=CC', 'ConceptCardLoc=CCLoc', 'Pages'},
join = {
'CC.iname = CCLoc.iname',
'CC.iname = Pages.iname',
},
fields = {
'Pages._pageName = _pageName',
'CC.iname = iname',
'CC.server = server',
'CC.rare = rare',
'CC.icon = icon',
'CCLoc.name = name',
},
where = {
('"%s" IN (CC.iname, Pages._pageName)'):format(iname),
('CC.server = "%s"'):format(server),
('CCLoc.lang = "%s"'):format(lang),
'Pages._pageName IS NULL OR Pages.type = "Memento"',
},
}[1]
return render_memento_icon(args)
end
return (cargo.query{
tables = 'ConceptCardLoc',
fields = 'name',
where = 'iname = "'..iname..'" AND lang = "english"',
}[1] or {}).name
end
function p._main(iname, args)
if not args or args.isPage then
return p.renderPage(iname)
else
return renderTransclude(iname, args)
end
end
function p.main(frame)
local args = require('Module:Arguments').getArgs(frame, {parentFirst = true})
return p.renderPage(args[1])
end
function h.printLeaderSkill(root, sk_iname)
if sk_iname == nil then return end
local skill
local rows = cargo.query{
tables = {
'Skill = SK',
'SkillLoc = SK_LOC',
'Buff = BF',
'BuffDetail = BD',
'Buff__custom_targets = BF_CT',
'CustomTarget = CT',
'CustomTarget__concept_card_groups = CT_CCG',
'ConceptCardGroup = CCG',
'ConceptCardGroup__cards = CCG_CC',
'ConceptCard = CC',
'Pages = CC_PAGES',
},
join = {
'SK.iname = SK_LOC.iname',
'SK.t_buff = BF.iname',
'BF.iname = BD.buff_iname',
'BF._ID = BF_CT._rowID, BF_CT._value = CT.iname',
'CT._ID = CT_CCG._rowID, CT_CCG._value = CCG.iname',
'CCG._ID = CCG_CC._rowID, CCG_CC._value = CC.iname',
'CC.iname = CC_PAGES.iname',
},
fields = {
'SK.iname = iname',
'SK.type = type',
'SK.eff_type = eff_type',
'SK.target = target',
'SK.cond = cond',
'SK.timing = timing',
'SK_LOC.name = name',
'SK_LOC.expr = expr',
'BF.iname = t_buff_iname',
'BD.idx = BD_idx',
'BD.calc = calc',
'BD.tktag = tktag',
'BD.type = type',
'BD.vini = vini',
'BD.vmax = vmax',
'BD.vone = vone',
'BF_CT._position = BF_CT_idx',
'CT.birth_id = birth_id', -- Integer
'CT.sex = sex', -- Integer
'CT.dark = dark', -- Integer
'CT.fire = fire', -- Integer
'CT.shine = shine', -- Integer
'CT.thunder = thunder', -- Integer
'CT.water = water', -- Integer
'CT.wind = wind', -- Integer
-- 'CT.concept_card_groups = concept_card_groups', -- List of String
'CT.job_groups = job_groups', -- List of String
'CT.unit_groups = unit_groups', -- List of String
'CT.units = units', -- List of String
'CT_CCG._position = CT_CCG_idx',
'CCG.iname = CCG_iname',
'CCG_CC._position = CCG_CC_idx',
'CC.iname = CC_iname',
'CC.icon = CC_icon',
'CC.type = CC_type',
'CC.rare = CC_rare',
'CC_PAGES._pageName = CC_PAGENAME',
},
where = {
'SK.iname = "'..sk_iname..'"',
'SK.server = "gl"',
'SK_LOC.lang = "english"',
'COALESCE(SK.t_buff, "") = "" OR BF.server = SK.server AND BD.server = SK.server',
'COALESCE(BF.custom_targets__full, "") = "" OR CT.server = SK.server',
'CCG.server = "gl"',
'CC.server = "gl"',
},
orderBy = 'idx',
}
if #rows == 0 then return end
for _, row in ipairs(rows) do
skill = skill or {
iname = row.iname,
name = row.name,
expr = row.expr,
type = enums.ESkillType[tonumber(row.type)],
eff_type = enums.SkillEffectTypes[tonumber(row.eff_type)],
target = enums.ESkillTarget[tonumber(row.target)],
cond = enums.ESkillCondition[tonumber(row.cond)],
timing = enums.ESkillTiming[tonumber(row.timing)],
t_buff = {
iname = row.t_buff_iname,
custom_targets = {},
details = {},
},
}
setdefault(skill.t_buff.details, tonumber(row.BD_idx), {
calc = row.calc,
tktag = row.tktag,
type = tonumber(row.type),
vini = tonumber(row.vini),
vmax = tonumber(row.vmax),
vone = tonumber(row.vone),
})
local custom_target = setdefault(skill.t_buff.custom_targets, tonumber(row.BF_CT_idx), {
birth_id = tonumber(row.birth_id),
sex = tonumber(row.sex),
dark = tonumber(row.dark),
fire = tonumber(row.fire),
shine = tonumber(row.shine),
thunder = tonumber(row.thunder),
water = tonumber(row.water),
wind = tonumber(row.wind),
concept_card_groups = {},
job_groups = row.job_groups,
unit_groups = row.unit_groups,
units = row.units,
})
local concept_card_group = setdefault(custom_target.concept_card_groups, tonumber(row.CT_CCG_idx), {
iname = row.CCG_iname,
concept_cards = {},
})
local concept_card = setdefault(concept_card_group.concept_cards, tonumber(row.CCG_CC_idx), {
iname = row.CC_iname,
icon = row.CC_icon,
type = row.CC_type,
rare = row.CC_rare,
PAGENAME = row.CC_PAGENAME,
})
end
root:newline():tag('h2'):wikitext("Leader Skill")
root:newline():tag('h3'):wikitext(skill.name)
root:newline():tag('p'):wikitext(skill.expr)
if #skill.t_buff.details > 0 then
local tbl = root:newline():tag('table'):addClass('wikitable')
tbl:newline():tag('caption'):wikitext('Target Buff ('..skill.target..') ('..skill.cond..')')
tbl:newline():tag('tr'):tag('th'):attr('colspan', 3):wikitext('Stats')
tbl:newline():tag('tr')
:tag('th'):wikitext('Type'):done()
:tag('th'):wikitext('Min'):done()
:tag('th'):wikitext('Max'):done()
for i, buff in ipairs(skill.t_buff.details) do
local tr = tbl:newline():tag('tr')
local fmt = yesno(buff.calc) and '%+d%%' or '%+d'
local statName = enums.statNameFromType(buff.type, buff.tktag)
tr:tag('th'):wikitext(statName)
tr:tag('td'):wikitext(string.format(fmt, tonumber(buff.vini)))
tr:tag('td'):wikitext(string.format(fmt, tonumber(buff.vmax)))
if buff.tktag then
cats[#cats+1] = statName
end
end
end
for _, custom_target in ipairs(skill.t_buff.custom_targets or {}) do
for _, cc_group in ipairs(custom_target.concept_card_groups or {}) do
local cards = cc_group.concept_cards
root:newline():tag('h4'):wikitext('Memento Group')
local ul = root:newline():tag('ul')
for _, card in ipairs(cards) do
-- local icon = ''
if card.PAGENAME then
local icon = string.format(
'[[File:Game,ConceptCardIcon,%s.png|32px|link=%s]] [[%s]]',
card.icon, card.PAGENAME, card.PAGENAME)
ul:newline():tag('li'):wikitext(icon)
end
end
end
end
end
function p.test(frame)
util_vars.setVar('cargo query count', 0)
-- local root = mw.html.create()
-- h.printLeaderSkill(root, 'SK_LS_TS_ENVYRIA_CLOE_01')
-- return
local x
-- x = p.renderPage('TS_SAGA_BIRGITTA_01')
x = p.renderPage('TS_WADA_SUZUKA_02')
-- x = p.renderPage('TS_GLUTTONY_NIMURU_01')
mw.log(util_vars.getVar('cargo query count'))
--return x
end
p.h = h -- for testing purposes >_<
-- p.test()
return p
--</nowiki>