(sync) |
m (hmm) |
||
Line 906: | Line 906: | ||
) then table.insert(new_lines.to_replace, {stat, stat}) end |
) then table.insert(new_lines.to_replace, {stat, stat}) end |
||
end |
end |
||
− | for n = 1, #new_lines.to_replace do table.insert(to_replace, n, new_lines.to_replace[n]) end |
+ | --for n = 1, #new_lines.to_replace do table.insert(to_replace, n, new_lines.to_replace[n]) end |
if not unit then |
if not unit then |
||
+ | for n = 1, #new_lines.to_replace do table.insert(to_replace, n, new_lines.to_replace[n]) end--hmm |
||
for n = 1, #new_lines do new_lines[n] = unbold(new_lines[n]) end |
for n = 1, #new_lines do new_lines[n] = unbold(new_lines[n]) end |
||
passive_stats = {} |
passive_stats = {} |
Revision as of 12:33, 25 October 2017
local p = {
stat_order = {'HP','MP','ATK','DEF','MAG','SPR'},
equipment = {
_class ={'Weapon', 'Armor', 'Accessory'},
_plural = {Clothes = 'Clothes', Staff = 'Staves'},
Dagger = 1,
Sword = 1,
["Great Sword"] = 1,
Katana = 1,
Staff = 1,
Rod = 1,
Bow = 1,
Axe = 1,
Hammer = 1,
Spear = 1,
Harp = 1,
Whip = 1,
["Throwing Weapon"] = 1,
Gun = 1,
Mace = 1,
Fist = 1,
["Light Shield"] = 2,
["Heavy Shield"] = 2,
Hat = 2,
Helm = 2,
Clothes = 2,
["Light Armor"] = 2,
["Heavy Armor"] = 2,
Robe = 2,
Accessory = 3
},
ability = {
_class = {"Special Ability", "Magic Ability"},
Active = 1,
Passive = 1,
White = 2,
Black = 2,
Green = 2,
Blue = 2
},
ailment = {
Poison = 1,
Blind = 1,
Sleep = 1,
Silence = 1,
Paralyze = 1,
Confuse = 1,
Disease = 1,
Petrify = 1
},
killer = {
--Special thanks to FencerTJ for category names (except he forgot humans)
Avians = 'bird',
Plantoids = "plant",
Aquatics = "aqua",
Beasts = "brute",
Demons = "cysidus",
Dragons = "dra[cg]o",
Fairies = "[sf][pa]ir",--spirit or fairy
Insects = "bug",
Machinas = "m[ae]ch",
Stones = "lith",
Reapers = "undead",
Humans = "man-?"
},
patterns = {
--Not all patterns here. Just those used more than once.
wikilink = '%[%[[^%[%]]+%]%]',
only = '%(%[%[([%w ]+)%]%] only%)',
enable = '([^\n]*Enables access[^\n]-: )([^\n]+)',
multi_break = '[^<]?%s-/?%s*([^>]?.-[^<])%s*/%s-[^>]-',
rng_enable = '\n%(%d+%%%) +[^\n]+: Enables? ',
event = '%(%[?%[?Event[^,]-%)%s*%[?%[?'
},
template = {
evade = 'Chance to evade %s damage taken (%s)'
}
}
local result = {}
function result:_(v)
--simplified version of mw:en:Module:Buffer
if v and v ~= '' then table.insert(self, v) end
return self
end
local esc_seq = string.char(127,4,127,2)
function p.item(frame)
local args, p_args, flags, currentTitle, namespace, invokePage = {}, frame:getParent().args, {}
if p_args.page or args.page then
--No worries. Scribunto is sandboxed, so overwriting mw.title.getCurrentTitle won't affect any other #invokes
local emulate = mw.title.new(p_args.page or args.page)
mw.title.getCurrentTitle = function() return emulate end
end
for k, v in pairs(frame.args) do
--Basic cleaning of arguments and argument grouping
v = mw.text.trim(v)
if v and v~='' and v~='-' then args[k] = v end
end
local stats_sorted, stats = {}, {HP = {}, MP = {}, ATK = {}, DEF = {}, MAG = {}, SPR = {}}
for k, v in pairs(stats) do
--grab percents and integers in the form such that DEF+7, DEF+50% is entered as 'DEF=7+50%'
if args[k] then
v[2] = args[k]:match'%-?%d+%%'
if v[2] then v[1] = args[k]:match'^%+?(%-?%d+)%+'--tolerate ATK=+10
else table.insert(v, args[k]:match'^%+?(%-?%d+)$') end
end
end
if p.equipment[args.type] then
for i = 1, 2 do
--show percentage stats after integer stats
for _, v in ipairs(p.stat_order) do--this line controls order of stats
table.insert(
stats_sorted,
stats[v][i] and (i==1 and '%s+%s' or '[[%s +%s]]'):format(v, stats[v][i])
)
end
end
end
local function link(v, hide_disambiguation)
--[[
Autolinks if does not contain a link. If hide_disambiguation evals true, links "Page (Disambigation)" as
"Page (Disambigation)|Page"
]]
return v and (v:find(p.patterns.wikilink) and v
or hide_disambiguation and v:find'%b()' and v:gsub('([^%(]+) %(([^%)]+)%)', '[[%1 (%2)|%1]]')
or v:gsub('^(.-) -( ?\\?%+?%d?)$', function(a, b)
if v == invokePage then a, b = v, ''
elseif b:sub(2, 2) ~= '+' or not tonumber(b:sub(3, 3)) then a, b = a .. b, '' end
return ('[[%s]]%s'):format(a, b):gsub('\\%+', '+')
end, 1))
end
local function tooltip_link(v, hide_disambiguation)
--Makes tooltip link.
if v == currentTitle then return "'''" .. v .. "'''" end
local fetch, only = {title = ':' .. v, args = {'effect', 'ability', mode = 'fetch'}}
only = frame:expandTemplate(fetch):match('%[%[' .. args.name:gsub('%p', '%%%1') .. '%f[|%]][^%]]-%]%] *%((.- only)%)')
or frame:expandTemplate(
fetch,
rawset(fetch.args, 2, nil),
rawset(fetch.args, 1, 'warning')
):match'[^,]+ only'
only = only and ' (' .. only .. ')' or ''
return ('{{:%s|mode=tooltip%s}}')
:format(v, hide_disambiguation and '' or '|full_pg=1')
.. only
end
local function link2tooltip(v, hide_disambiguation)
--checks all links for Module:Data and replaces them with tooltips when possible. Only use when non-Module:Data pages may be passed
for lookback, wikilink, page in v:gmatch'(.?)(%[%[([^:#][^|%]]+)|?[^%]]*%]%])' do
if lookback ~= '(' and not (page:find':[^ _]' or page:find'#' or stats[page:match'(.+) %+%d'] or mw.title.new(page).redirectTarget) then
local tooltip = frame:preprocess('{{msgnw::' .. page .. '}}')
if tooltip:lower():find'#invoke:data%s*|%s*item' then
v = v:gsub(wikilink:gsub('%p', '%%%1'), tooltip_link(page, hide_disambiguation):gsub('%p', '%%%1'))
end
end
end
return v
end
local function split_link(v, hide_disambiguation, sep, alt_link_func)
--Splits v by commas and joins with sep (or comma if omitted). Links using link() unless passed alt_link_func
local t = {}
for s in mw.text.gsplit(v:gsub("\\,", esc_seq), ',%s*') do
s = mw.text.trim(s)
if s ~= '' then table.insert(t, (alt_link_func or link)(s, hide_disambiguation)) end
end
return table.concat(t, sep or ', '):gsub(esc_seq, ',')
end
local function multi_split(v, head_format, sep, headless_sep)
--Splits by ';' and passes each to split_link(). If first item prefixed by 'text:', treats 'text' as group name
local result = {_=result._}
for x in mw.text.gsplit(v, ';') do
local group, list = x:gsub('\\:', esc_seq):match'^([^:]+): -(.+)$'
group, list = group:gsub(esc_seq, ':'), list:gsub(esc_seq, ':')
result
:_(group and head_format:format(group) or headless_sep)
:_(split_link(list or x, nil, group and sep or headless_sep, group == 'Equipment' and tooltip_link))
:_'\n'
end
return table.concat(result)
end
local function ailment_link(v, hide_disambiguation)
--Autolinks ailments. When hide_disambiguation is nil or true, also autolinks non-ailments.
local status, chance = v:match'^([^%(]-) ?%(([^%)%(]-)%)'
if status and (p.ailment)[status] then
return ('[[Status Ailments#%s|%s]] (%s)'):format(status, status, chance)
elseif status and v:find' status ailments? ' then return (v:gsub(' (status ailments?) ', ' [[Status Ailments|%1]] ', 1)) end
if hide_disambiguation == false then return v end--for args.resist
return link(v, hide_disambiguation)
end
local function materia_ailment_link(v)
--auto-links ailments for materia.
if v then for i, pattern in ipairs{
'Cures? [^\n<]+ to ',
'Inflicts? [^\n<]+ %(',
'Increase resistance to [^\n<]+ %(',
'Increase [^\n<]+ resistance %(',
'[Rr]emove '
} do if v:find(pattern) then
for ailment in pairs(p.ailment) do
v = v:gsub(
" ('*)" .. ailment:lower(),
(' %s1[[Status Ailments#%s|%s]]'):format('%', ailment, ailment:lower()),
1
)
end
flags.groupStatusCure, v =
flags.groupStatusCure or i == 1 and v:find'all allies',
v:gsub(" ('*)(status ailments?)('*) ", ' %1[[Status Ailments|%2]]%3 ', 1)
break
end end end
return v
end
local function icon(v)
--Makes item image. If passed a string, links to it. If passed true, links to the #invoke page (not name param)
return (v and '[[File:%s|%s|link=%s]]' or '[[File:%s|%s]]'):format(
args.image or ('Icon-%s.png'):format(args.name),
args.name or '',
v == true and invokePage or v
)
end
local function recipe()
return args.rec_mat and link2tooltip(frame:preprocess(split_link(args.rec_mat, nil, '<br>', function(v)
local item, quantity, found_img = v:match'(.-) ?%(?(%d+)%)?$'
found_img = mw.text.decode(frame:preprocess('{{msgnw::'.. (item or v) ..'}}')):match'|%s*image%s*=%s*([^<]-%.png)'
return ('{{Item|%s|%s%s}}'):format(item or v, quantity or 1, found_img and '|image=' .. found_img or '')
end)), true)
end
local function widget_sort_stats(close)
--provide html element attributes for Widget:Sort_Stats
local sortdata = {}
for k, v in pairs(stats) do if v[1] or v[2] then
table.insert(sortdata, 'data-'..k..'="'..args[k]..'"')
end end
if args.evade then table.insert(sortdata, 'data-evade="'..args.evade..'"') end
return ' style="text-align:left" class=stats_cell ' .. table.concat(sortdata, ' ') .. (close or ' | ')
end
local function stats_cell(mode_tooltip)
--generates stats cell used on category/shop pages for equipment; if mode_tooltip, hide_disambiguation and return stats table without concat
local only, lines =
args.warning and args.warning:match"Useable by '?'?'?(%a+)'?'?'? only",
{stats_sorted[1] and table.concat(stats_sorted, ', '), _=result._}
lines
:_(args.element and 'Element: ' .. args.element)
:_(args.resist and 'Resistance: ' .. split_link(args.resist, false, nil, ailment_link))
:_(args.effect and 'Effect: ' .. link2tooltip(split_link(args.effect, mode_tooltip, nil, ailment_link), mode_tooltip))
:_(args.ability and 'Ability: ' .. link2tooltip(split_link(args.ability, mode_tooltip), mode_tooltip))--use tooltip_link after module used on all ability pages
:_(args.warning and (only and
("'''%ss only'''"):format(mw.getContentLanguage():ucfirst(only))
or ("'''%s'''"):format(args.warning):gsub(", ?", "<br>")
))
:_(args.used_by and 'Exclusive: ' .. split_link(args.used_by))
return mode_tooltip and lines or lines[1] and table.concat(lines, '<br>')
end
local function randomized_table(v)
--takes a string with multiple lines (separated by <br> or \n) and appends effects to each line from each double bullet in args.ability.
local s = v:gsub('<br ?/?>', '\n')
--if not s:find'\n(%([^\n]+)' then return v end
return args.ability and s:find'\n%(' and
'<table style="margin:0"><tr><td colspan=3>'
.. s
:gsub('\n\n+', '\n')
:gsub("\n%f[%w '{<]", '</td></tr></table>', 1)
:gsub("'''", '')
:gsub('%%', '%%%%')
:gsub(
"\n(%([^\n]+)",
'</td></tr><tr style="vertical-align:top"><td style="white-space:nowrap;padding-left:3em;text-indent:-3em">%1</td><td> - </td><td>%%s'
)
:gsub('(%) +%w+[- ] *%w+[- ] *)(%(?[%w]+)', '%1<wbr>%2')
:format(select(2, unpack(mw.text.split(materia_ailment_link(args.ability):gsub('\n', ''), "%*.-%*%*"))))
.. (not v:find'</table>' and '</td></tr></table>' or '')
or v
end
local function effect_auto_link(v)
--autolink killers, equipment masteries and wields, and status ailments in materia effects
if v:find' killer ' or v:find' against ' then
for cat, initial in pairs(p.killer) do
local match = v:match(" '*(" .. cat:sub(1, -1):lower() .. "%l?)")
or v:match(" '*(" .. initial .. "%l*)")
v = match and v:gsub(match, ('[[:Category:%s|%s]]'):format(cat, match), 1) or v
end
elseif v:find'Increase .- equipped with' or v:find'Allow use' then
for cat in pairs(p.equipment) do
local match = v:match("'*([%a,']+ +'*" .. cat:lower() .. (cat:sub(-1)=='y' and '?i?e?s?)' or 's?)'))
or cat == 'Staff' and
v:match("'*([%a,']+ +'*staves)")
v = match and match:sub(1, 5) ~= 'great' and v:gsub(
match:gsub("^.- '*", '', 1),
('[[:Category:%s|%s]]'):format(
(p.equipment._plural[cat]
or cat:gsub('y$', 'ie') .. 's'
),
match:gsub("^.- '*", '', 1)
),
1
) or v
end
else v = materia_ailment_link(v) end
return v
end
local function passive_stat_boost(effects)
local list, group, last_percent = {[true] = {}, [false] = {}}, {[true] = {}, [false] = {}}, {[true] = {}, [false] = {}}
for i = 1, #p.stat_order do
if args[p.stat_order[i]] then
local positive = tonumber(args[p.stat_order[i]]:match"^'*(%-?%d*)%%'*$") > 0
if group[positive][1] then
if last_percent[positive] ~= args[p.stat_order[i]] then
table.insert(list[positive], ('%s (%s)'):format(table.concat(group[positive], '/'), last_percent[positive]))
group[positive], last_percent[positive] = {}, args[p.stat_order[i]]
end
else last_percent[positive] = args[p.stat_order[i]] end
table.insert(group[positive], p.stat_order[i])
effects[args[p.stat_order[i]]] = (effects[args[p.stat_order[i]]] or 0) + 1
end
end
for _, positive in ipairs{false, true} do
if group[positive][1] then
table.insert(effects, 1, (('%screase %s%s%s (%s)')
:format(
positive and 'In' or 'De',
table.concat(list[positive], ', '),
list[positive][1] and ' and ' or '',
table.concat(group[positive], '/'),
last_percent[positive]
)
:gsub('%(%-', '(')
))
end
end
return effects
end
local function materia_effects(mode_tooltip)
--generates ability materia effects. If passed true as, returns effects as a table without concat.
local effects, transcluded, show_table =
args.effect and mw.text.split(args.effect, '%s*\n%s*') or {},
invokePage ~= currentTitle,
args.ability and (args.type ~= 'Passive' or args.mode == 'category')
for k, v in ipairs(effects) do
local enable, skills = v:match(p.patterns.enable)
if enable then
effects[k] = args.effect:match(p.patterns.wikilink) and
effects[k]:gsub('(\\?)\\,', '%1,')
or enable .. split_link(skills)
while v:find((effects[k + 1] or ''):match'%[(.+)%]%S*%s*=' or '^%$$') do table.remove(effects, k + 1) end
elseif transcluded and args.ability and (v:find':[\n<][b%(][r%d]' or v:find'[Cc]ounter') then
if v:gsub('<br ?/?>', '\n'):find'^[^\n]+:\n%(' then
effects[k] = show_table and randomized_table(v) or v
elseif args.type == 'Passive' then
for name, effect in args.ability:gmatch'%* *([^\n]-) *\n%*%*%s*([^\n]+)' do
effects[k] = v:gsub(
name:gsub('%p', '%%%1'),
'{{tooltip|2=%1|1=%1<br>' .. effect:gsub('%%', '%%%1'):gsub('Randomly use:<br ?/?>', '') .. ' |style=white-space:nowrap}}'
)
end
end
else effects[k] = effect_auto_link(v) end
end
--Note: Below inserted in backwards order to the front of the effects table
if args.evade_m then table.insert(effects, 1, p.template.evade:format('magic', args.evade_m)) end
if args.evade_p then table.insert(effects, 1, p.template.evade:format('physical', args.evade_p)) end
passive_stat_boost(effects)
if args.used_by and not args.learn and args.mode and args.mode ~= 'exclusiveFX' then
table.insert(effects, 'Exclusive: ' .. split_link(args.used_by))
end
return mode_tooltip and effects or effects[1] and table.concat(effects, '<br>'):gsub('(</table>)<br>', '%1')
end
local function type_link(parens)
--makes [[:Category:Weapons]] ([[:Category:Guns]]). If parens is true, places them in parenthesis
return p.ability[args.type] and '[['
.. p.ability._class[p.ability[args.type]]:sub(1, -2)
.. (p.ability[args.type] == 1 and 'ies (%s)]]' or 'ies]]')
:format(args.type)
or p.equipment[args.type] and (parens and ' ([[:Category:%s|%s]])' or '[[:Category:%s|%s]]'):format(
p.equipment._plural[args.type] or args.type:gsub('y$', 'ie') .. 's',
args.type
)
or args.usage and '[[:Category:Materials]]' or '[[Miscellaneous Items]]'
end
local function multi_break(s)
--takes args.hits or arg.MP_cost and splits them by backslash or semicolon, inserting same number of breaks per item as in args.ability
if s and not tonumber(s) and s:find(p.patterns.multi_break) then
local hits = ('/ ' .. s .. ' /'):gmatch(p.patterns.multi_break)
s = {}
for v in mw.text.gsplit(
args.ability
or args.effect:gsub('\nIf used after[^\n]+:', '<br>'):gsub(':\n', '<br>'),
args.ability and '\n%*%*' or '\n'
) do
table.insert(s, ('<br>'):rep(select(2, v:gsub('<br ?/?>', '')) + 1))
table.insert(s, (hits()))
end
if not args.ability then table.remove(s, 1) end
s = table.concat(s)
end
return '\n| ' .. (s or '-')
end
local frame_tooltip = '[[#.|{{Tooltip|style=text-align:left' .. frame:callParserFunction('#tag:nowiki', ';') .. 'white-space:nowrap|hideicon=|'
local function attack_frames(hits, v)
--[[
pass args.hits as first param. Reads args.atk_frm and makes tooltip.
Also recursively splits and tooltips args.atk_frm by / or ; characters if such are present in args.hits
]]
hits = hits ~= '' and hits ~= '-' and hits
if hits and args.atk_frm then
if not v and hits:find(p.patterns.multi_break) then
local split = {
hits = ('/ ' .. hits .. ' /'):gmatch(p.patterns.multi_break),
a_frames = ('/ ' .. args.atk_frm .. ' /'):gmatch(p.patterns.multi_break)
}
for hit_count in split.hits do
local animation = split.a_frames()
table.insert(split, animation and tonumber(hit_count) and attack_frames(hit_count, animation) or hit_count)
end
hits = table.concat(split, ' / ')
else
local output, frames = {_=result._}, mw.text.split(v or args.atk_frm, ' ?[,%-] ?')
output
:_(frame_tooltip)
:_(#frames > 1 and 'Frame delay: ' or 'Attack frame: ')
:_(frames[1])
if #frames > 1 then
for i = 2, #frames do output:_(-tonumber(frames[i]) + tonumber(frames[i - 1])) end
output
:_'<br>Attack frames: '
:_(table.concat(frames, '-'))
else output:_(table.concat(frames, nil, 2, #frames)) end
hits = table.concat(output:_'|':_(mw.text.trim(hits)):_'}}]]')
end
end
return hits
end
local froms, hasExclusiveFX, learned = {
--[[
{parameter name, how-to-obtain title, flag}
Set flag for sources that would not place an ability in Category:Items and to exclude source from how-to-obtain cell for mode=category
1 = list parameter for equipable sources
2 = non-equipment sources or non-list parameter
]]
{'drop', 'Dropped from'},
{'steal', 'Stolen from'},
{'explore', 'Collected from'},
{'shop', args.quartz and 'Fat Chocobo' or 'Shop'},
{'recipe', 'Recipe'},
{'chest', 'Chest'},
{'reward', 'Reward'},
{'equip', 'Equipment', 1},
{'materia', 'Ability Materia', 1},
{'learn', 'Learned by', 2},
{'esper', 'Esper', 2},--because not a comma-separates list
{'enable', 'Enabled by', 2}
},
args.effect and--do not check used_by here
args.effect:match(p.patterns.only)
or args.ability and args.ability:match(p.patterns.only)--use match() not find()
currentTitle, namespace, invokePage =
mw.title.getCurrentTitle().fullText,
mw.title.getCurrentTitle().namespace,
frame:getParent():getTitle()
args.name = args.name or not invokePage:find':' and invokePage
args.mode = args.mode
or p_args.mode
or currentTitle == 'Module:Data' and 'demo'
or currentTitle == 'Ability Awakening' and 'awaken'
or (namespace == 14
or p.ability[args.type] and (
currentTitle == 'Ability Materia'
or currentTitle == (p.ability[args.type] == 1 and
('Special Abilities (%s)'):format(args.type)
or 'Magic Abilities'
)
)
) and 'category'
or invokePage ~= currentTitle and (
(args.recipe or args.reward) and (args.recipe or args.reward):find(
p.patterns.event
.. currentTitle:gsub('_', ' '):gsub('%p', '%%%1')
) and 'event'
or (hasExclusiveFX == currentTitle or args.used_by and args.used_by:find(currentTitle)) and 'exclusiveFX'
or p.equipment[args.type] and 'item'
or 'typeless'
)
local function format_skill_args()
--simplifies pattern matching by allowing newlines and <br> to be used interchangeably
args.effect = args.effect and args.effect
:gsub('(([^\n]+)\n%()', function(match, prev_line)
if prev_line:find'=' then return match end
return prev_line .. '<br>('
end)
:gsub('\n+(If used after)', '\n<br>%1')
if args.ability and not args.ability:find('\n*', 1, 1) then
--automatically takes names from effect param for randomized abilities and transcludes effect if line == '[data]'
local a = mw.text.split(args.ability, '\n')
if a[2] then
args.ability = {}
for name in args.effect:gmatch'<br ?/?>%([^\n<]+%) ([^\n<]+)' do
local abil = table.remove(a, 1)
if abil == '[data]' then
abil = frame:expandTemplate{title = ':' .. name:match'%[%[(.-)[|%]]', args = {'STATS', mode = 'fetch'}}
end
table.insert(args.ability, ('*%s\n**%s'):format(name, abil or 'NO DATA'))
end
args.ability = table.concat(args.ability, '\n')
end
end
end
local function format_split_args(v) return v and v:gsub(' ?; ?', ' / '):gsub(' +', ' '):gsub('^ ?/', '- /'):gsub('/ /', '/ - /') end
if p.ability[args.type] then
learned = not p_args.mode and args.learn and invokePage ~= currentTitle and {args.learn:match('\n|? *%[%[' .. currentTitle .. '.-|?[$|]?%s*(<[^\n]+>)%s*|?[$|] ?(%d%d?%d?)')}
args.hits, args.atk_frm, args.MP_cost =
args.hits and (
args.hits:find'^[dD][^/;]*$' and
((args.mode or learned and learned[1]) and 'D' or 'Default unit attack')
or format_split_args(args.hits)
),
args.atk_frm and format_split_args(args.atk_frm),
args.MP_cost and
format_split_args(args.MP_cost)
or args.type == 'Active' and 0
format_skill_args()
end
if learned and learned[1] then
--Display when transcluded onto a page listed in args.learn
local unmerge, hits = args.type ~= 'Passive' or p_args[1] == 'unmerge'
result
:_'|-\n|'
:_(learned[1])
:_'\n|'
:_(learned[2])
:_'\n|'
:_(icon(true))
:_'\n|style="text-align:left"|'
:_(link(args.name, true))
:_'\n|style="text-align:left"'
:_(unmerge and '|' or ' colspan=3|')
:_(materia_effects():gsub("(%) with [^\n:]+): ?<br ?/?> ?%([^\n]+", '%1'))--save random counter info for mode=conditional
if unmerge then
result
:_(multi_break(attack_frames(args.hits)))
:_(multi_break(args.MP_cost))
end
elseif args.mode and args.mode ~= 'demo' then
local function BADGE()
return ('<p style="text-align:center">%s<br>%s<br>(%s)</p>'):format(
icon(true),
link(invokePage ~= args.name and invokePage .. '|' .. args.name or invokePage),
type_link()
)
end
local function STATS(b)
local v = (p.equipment[args.type] and stats_cell or materia_effects)()
return not (b or p_args.sep or args.mode == 'fetch' or p_args[1] == 'STATS') and v and widget_sort_stats() .. v or v
end
local function extend(sep)
--Reads customization parameters from parent frame. Def = default value, sep = separator
local magic_words = {
STATS = {STATS},
ICON = {icon, true},
TYPE = {type_link},
LINK = {link, table.concat({invokePage, args.name}, '|')},
RECIPE = {recipe},
BADGE = {BADGE}
}
for _, v in ipairs(p_args) do
_ = mw.text.trim(mw.text.killMarkers(v))
if _ ~= '' then
local a, b = v:gsub('\\@', esc_seq):match'^(.-)@(.*)'
result:_(sep or '\n| '):_(
a and (a~='' and
((args[a] or magic_words[a]) and
b:gsub(esc_seq, '@'):format(
frame.args[a] ~= '' and frame.args[a]
or args[a]
or magic_words[a][1](unpack(a == 'STATS' and {nil, b} or magic_words[a], 2))
)
or '-')
or b and b:gsub(esc_seq, '@'))
or frame.args[_] ~= '' and frame.args[_]--return unprocessed non-empty args
or args[_]--for auto args
or magic_words[v] and magic_words[v][1](unpack(magic_words[v], 2))
or p_args.default or '-'
)
end
end
end
if args.mode == 'category' then
--Display when on category page
local obtain, equipped = {}, {}
for i = 1, #froms do
if args[froms[i][1]] and froms[i][3] ~= 2 then
table.insert(froms[i][3] and equipped or obtain,
froms[i][3] and
split_link(args[froms[i][1]]:gsub('%]%] %([^%)]+%)', ']]'), nil, froms[i][3] and '<br>')
or ("'''%s:''' %s"):format(
froms[i][2],
split_link(args[froms[i][1]])
))
end
end
if args.esper then
for esper in args.esper:gmatch'%[%[[^:]-%]%]' do table.insert(equipped, esper) end
end
table.insert(obtain, args.trust and ("'''Trust:''' [[%s]]"):format(args.trust))
table.insert(obtain, args.obtain and multi_split(args.obtain, "'''%s''': ", ', ', '<br ?/?>'))
result
:_'|-\n|'
:_(tonumber(p_args.rowspan) and ('rowspan=%s style="text-align:center"| %s ||')
:format(p_args.rowspan, args.mag_lv or '')
)
:_(args.image and p.ability[args.type] and 'data-sort-value=' .. args.image:match'_(%d+)%.')
:_((' align=center|%s|| %s || '):format(
icon(true),
link(args.name, true)
))
:_((p.equipment[args.type] or args.type == 'Passive') and widget_sort_stats())
:_(p.equipment[args.type] and stats_cell()
or materia_effects())
:_' \n| '
:_(p.ability[args.type] and result
:_(args.MP_cost and ('style="text-align:center"| %s ||'):format(args.MP_cost) or '')
:_(equipped[1] and table.concat(equipped, '<br>') or '-')
:_' || '
and nil
)
:_(obtain[1] and table.concat(obtain, '<br>') or '-')
extend()
elseif args.mode == 'exclusiveFX' then
--Display when current page title matches name of the unit which benefits from an exclusive effect
result
:_(p_args[1] ~= 'rowonly' and ("{| class=wikitable style='text-align:center;width:100%'\n!" ..
(p.equipment[args.type] and "Icon!!Name!!Type!!Effect"
or "style='width:50px'|Icon!!style='width:130px'|Name!!Effect!!style='width:50px'|Hits{{tooltip|style=white-space:nowrap|D {{=}} Default unit attack}}!!style='width:50px'|MP")
))
:_"\n|-\n|"
:_(icon(true))
:_'\n| '
:_(link(args.name, true))
:_'\n|'
:_(p.equipment[args.type] and type_link() ..'\n|')
:_(widget_sort_stats())
:_(p.equipment[args.type] and
(stats_cell() or '')--in case stats_cell() returns nil
or table.concat{
materia_effects(),
multi_break(attack_frames(args.hits)),
multi_break(args.MP_cost)
}
)
if p_args[1] ~= 'rowonly' then result:_'\n|}' end
elseif args.mode == 'conditional' then
local function conditional_row(rowspan, activator)
result
:_'|-\n|colspan=3'
:_(rowspan and result:_' rowspan=' and rowspan)
:_'|Activated by<br>'
:_(activator ~= '' and activator
or args.enable and split_link(args.enable)
or link(args.name)
)
:_'||style="text-align:left"| '
end
local ability_count, isPassive, randomized_counter, unmerge =
args.ability and select(2, ('\n'..args.ability):gsub("%*'''", 0)),
args.type == 'Passive',
args.effect and args.effect:match"Chance to counter[^\n]+with '?'?'?(.-)'?'?'?:<br ?/?>%(%d+%%",
p_args[1] == 'unmerge'
if args.ability then
conditional_row()
if randomized_counter then
result
:_(randomized_counter)
:_'\n|style="text-align:left"| '
:_(randomized_table(materia_effects()):gsub("Chance to counter[^\n]-:", 'Randomly use:'))
:_(multi_break(attack_frames(args.hits)))
:_(multi_break(args.MP_cost))
else
if ability_count > 0 then table.insert(result, 2, ' rowspan=' .. ability_count) end
if args.ability and not args.hits and args.ability:find'>Hits:' then
args.hits, args.MP_cost = {}
for line in args.ability:gmatch'\n%*%*[^\n]+' do
local a, b, h = line:find'<br ?/?>Hits: *(.+)'
if a then
local offset = args.ability:find(line, 3, 1)
args.ability = args.ability:sub(1, offset + a - 2) .. args.ability:sub(offset + b)
table.insert(args.hits, h)
else table.insert(args.hits, '-') end
end
args.hits = table.concat(args.hits, ' / '):gsub('Default unit attack', 'D')
end
result
:_(args.ability and materia_ailment_link(args.ability)
:gsub("\n%* *'''(.-)'''", '|-\n|style="text-align:left"| %1')
:gsub("%* *'''(.-)'''", '%1')
:gsub('%*%*', '| style="text-align:left"'
.. (isPassive and not (args.hits or args.MP_cost or unmerge) and
' colspan=3| '
or '| '
))
)
if unmerge or args.hits or args.MP_cost then
result
:_(multi_break(attack_frames(args.hits)))
:_(multi_break(args.MP_cost))
end
end
elseif args.enable then
if p_args.rowspan == '0' then result:_'\n|-\n|'
else conditional_row(tonumber(p_args.rowspan)) end
result
:_(link(args.name, true))
:_'\n|style="text-align:left"| '
:_(materia_effects())
:_(multi_break(attack_frames(args.hits)))
:_(multi_break(args.MP_cost))
else for line in args.effect:gsub('<br ?/?>%s*%(', '\n('):gmatch'[^\n]*Enable[^\n]+' do if not line:find'%].*=' then
local skills, ability_count = (select(2, line:match(p.patterns.enable)) or line:match' of (.+)')
:gsub('([^\\]), *', '%1@$#')
result:_(result[1] and '\n')
conditional_row(
ability_count > 0 and ability_count + 1,
(line:gsub('\\:', esc_seq):match'^%(%d+%%%) *(.-):' or ''):gsub(esc_seq, ':')
)
for k, v in ipairs(mw.text.split(skills, '@$#')) do--no gsplit because k needed
if k > 1 then result:_'\n|-\n|style="text-align:left"| ' end
local title, page = (v:match'%[%[(.-)[|%]\]' or v):gsub('\\,', ',')
page = mw.title.new(title).exists and frame:expandTemplate{title = ':' .. title, args = {page = title}}
:gsub('Default unit attack', 'D')
local override, page_effect =
frame.args.effect:match('\n%s*effect%[' .. title:gsub('%p', '%%%1') .. '%]%s*=%s*([^\n]+)')
or frame.args.effect:match('\n%s*%[' .. title:gsub('%p', '%%%1') .. '%]effect%s*=%s*([^\n]+)'),
page and page:match("'''Effect:'''\n:([^*=]+)\n")
args.effect = (override or page_effect or 'ERROR - No page or override found for ' .. link(title)):gsub('\\n', '\n')
result
:_(page and link(v, true) or v)--when all abilities use Data, replace all with:
--:_('{{:'..v..'|mode=fetch|STATS|{{tooltip|{{{hits}}}|Attack frame(s): {{{atk_frm}}}}}|MP}}')
:_'\n|style="text-align:left"| '
:_(page and override and '<span class="tool">')
:_(args.effect)
:_(override and page_effect and
"<span class=tip style='width:40em'><u>Automated Warning</u><br>A page exists for ''"
.. link(v)
.. "'' but an override has been set on ''"
.. link(invokePage)
.. "''. If the effect shown is the same as the following, please remove the override:<table class=wikitable style='margin:auto' ><tr><td>"
.. page_effect
.. "</td></tr></table></span></span>")
--args.atk_frm = args.effect:match('\n%s*atk_frm%[' .. title:gsub('%p', '%%%1') .. '%]%s*=%s*([^\n]+)') or args.atk_frm
for i, m in ipairs{{'Hits', 'hits'}, {'MP', 'MP_cost'}} do
result:_(multi_break(
frame.args.effect:match('\n%s*' .. m[2] .. '%[' .. title:gsub('%p', '%%%1') .. '%]%s*=%s*([^\n]+)')
or frame.args.effect:match('\n%s*%[' .. title:gsub('%p', '%%%1') .. '%]' .. m[2] .. '%s*=%s*([^\n]+)')
or page and page:match("'''" .. m[1] .. ":''' ([^\n]+)")
or '-'
))
end
end
end end end
elseif args.mode == 'awaken' then
local function bold(v)
return v and ((v:find"'''" or v:find'</?b>') and v or ("'''%s'''"):format(v)) or ''
end
local function unbold(v, manual_bold)--removes striked text and all tags except those that start with a t (table)
if manual_bold then return v end
return v and (v
:gsub("'''", '')
:gsub('<br><b><s%b></s></b><br>', '\n')
:gsub('<s%b></s>', '')
:gsub('%b<>', function(tag)
if tag == '<wbr>' or tag:find'^</?t' then return tag
elseif tag:sub(2, 3) == 'br' then return '\n' end
return ''
end)
:gsub('font-weight:bold;', '')
)
end
local function calculate_effects()
return unbold(materia_effects())
end
local unit, o_args, passive_stats, effects, new_effects =
p_args[1] ~= 'table' and p_args[1] ~= 'conditional' and p_args[1] or currentTitle == 'Ability Awakening' and 'Error - unspecified unit',
{},
{},
unbold(materia_effects()):gsub('\n', '<br>')
new_effects, passive_stats.lines = effects, passive_stat_boost{}
local function parse_awakening(input)
local to_replace, to_append, recalc, manual_bold = {}, {}
if input then
for _, v in next, {'effect', 'ability'} do
_ = '%s+' .. v .. '%s*=%s*([^=]+%f[\n])([^=]+=?)'
local m, m2, m3 = ('\n' .. input):match(_)
if not m then
_ = '%s+' .. v .. '%s*=%s*([^\n]*)'
m3 = ('\n' .. input):match(_)
end
if m or m3 then
input, args[v], o_args[v], recalc, manual_bold =
('\n' .. input):gsub(_, m2 and m2:find'=' and '%2' or ''),
(m3 or (m2:find'=' and m or m .. m2):gsub('\n%(', '<br>(')):gsub('\\n', '\n'),
args[v],
true,
manual_bold or (m or m3):find"'''" or (m or m3):find"<b>"
end
end
end
input = input and mw.text.split(input, '%s*\n%s*') or {'awk_mat=NO DATA,0'}
for i = 1, #input do
if i == 1 and args[input[i]] then parse_awakening(args[input[i]])
else
local diff = mw.text.split(input[i], '%s*=>%s*')
if diff[2] then
table.insert(to_replace, {diff[1]:gsub('\\n', '\n'), diff[2]:gsub('\\n', '\n')})
else
diff = mw.text.split(input[i], '%s*=%s*')
if diff[2] then
diff[2] = diff[2]:gsub('\\n', '\n')
if diff[2] == '' then diff[2] = nil end
if ({hits=1,atk_frm=1,MP_cost=1})[diff[1]] then diff[2] = format_split_args(diff[2]) end
if stats[diff[1]] then
if diff[2] == '0' or diff[2] == '0%' then diff[2] = nil end
if args[diff[1]] then passive_stats.lines[args[diff[1]]] = passive_stats.lines[args[diff[1]]] - 1 end
o_args[diff[1]], args[diff[1]], passive_stats.changed, passive_stats[diff[1]] = args[diff[1]], diff[2], true, true
elseif (diff[1] == 'evade_p' or diff[1] == 'evade_m') then
if not recalc and args[diff[1]] ~= diff[2] then
local physical, v, evade = diff[1] == 'evade_p' and 'physical', diff[2]--:gsub('%%', '%%%%')
evade = physical or 'magic'
if args[diff[1]] then
table.insert(to_replace, {
new_effects:match(p.template.evade:format(evade, '[^(]+'):gsub('[()]', '%%%1')),
p.template.evade:format(evade, (#(frame.args[diff[1]] or '') > 0 or not unit and args[diff[1]]) and bold(v) or v)
})
else
new_effects = mw.text.split(new_effects, new_effects:find'\n' and '\n' or '<br>')
table.insert(
new_effects,
1 + #passive_stats.lines + (not physical and args.evade_p and 1 or 0),
bold(p.template.evade:format(evade, v))
)
new_effects = table.concat(new_effects, '<br>')
end
end
args[diff[1]] = diff[2]--no recalc
elseif not args[diff[1]] or unbold(diff[2]) ~= unbold(args[diff[1]]) then
o_args[diff[1]], args[diff[1]] =
args[diff[1]] or '0',
({awk_mat=1,name=1,atk_frm=1})[diff[1]] and diff[2] or bold(diff[2])
end
elseif input[i] ~= '' then table.insert(to_append, input[i]) end
end
end
end
if recalc then
if args.ability then
format_skill_args()
new_effects = frame.args.ability and frame.args.ability ~= '' and bold(unbold(materia_effects(), manual_bold))
or unbold(materia_effects(), manual_bold)
:gsub('(<table style=")', '%1font-weight:bold;')
:gsub('(</table>)(.+)', "%1'''%2'''" )
:gsub('^(.+)(<table)', "'''%1'''%2")
else new_effects = bold(unbold(materia_effects(), manual_bold)) end
new_effects, passive_stats.changed = frame:preprocess(new_effects)
local a, b = new_effects:find(effects, 1, 1)
if not a then a, b = new_effects:find(frame.args.effect, 1, 1) end
if a and (not frame.args.ability or frame.args.ability == '') then
new_effects = new_effects:sub(1, a - 1)
.. '<span style="font-weight:normal">' .. effects .. '</span>'
.. new_effects:sub(b + 1)
else
--Unbold if override effect is found in original (assume strikethrough was undesired)
local plain = unbold(new_effects)
if effects:find(plain, 1, 1) or frame.args.effect:find(plain, 1, 1) then new_effects = plain end
end
elseif passive_stats.changed then
new_effects = mw.text.split(new_effects, new_effects:find'\n' and '\n' or '<br>')
local new_lines = passive_stat_boost{to_replace = unit and passive_stats.lines.to_replace or {}}
if #new_lines > #passive_stats.lines then
for n = 1, #new_lines do
local a = new_lines[n]:sub(1, 3)
if not table.concat(passive_stats.lines):find(a) then new_lines[n] = bold(new_lines[n]) end
end
elseif #new_lines < #passive_stats.lines then
for n = 1, #passive_stats.lines do
local a = passive_stats.lines[n]:match'(%u%l%l)rease '
if not table.concat(new_lines):find(a) then
table.insert(new_lines, select(a == 'Inc' and 1 or 2, 1, ("<b><s>%s</s></b>"):format(passive_stats.lines[n])))
end
end
end
for n = 1, #passive_stats.lines do table.remove(new_effects, 1) end
table.insert(new_effects, 1, table.concat(new_lines, '<br>'))
new_effects = table.concat(new_effects, '<br>')
for _, stat in ipairs(p.stat_order) do
if args[stat] then
if passive_stats.lines[args[stat]] == 0 or not passive_stats.lines[args[stat]] then
local percent = args[stat]:sub((args[stat]:find'%d'))
table.insert(new_lines.to_replace, {percent, percent})
end
passive_stats.lines[args[stat]] = (passive_stats.lines[args[stat]] or 0) + 1
end
if passive_stats[stat] and (
not o_args[stat]
or args[stat] and (
o_args[stat]:sub(1, 1) == '-' and args[stat]:sub(1, 1) ~= '-'
or o_args[stat]:sub(1, 1) ~= '-' and args[stat]:sub(1, 1) == '-'
)
) then table.insert(new_lines.to_replace, {stat, stat}) end
end
--for n = 1, #new_lines.to_replace do table.insert(to_replace, n, new_lines.to_replace[n]) end
if not unit then
for n = 1, #new_lines.to_replace do table.insert(to_replace, n, new_lines.to_replace[n]) end--hmm
for n = 1, #new_lines do new_lines[n] = unbold(new_lines[n]) end
passive_stats = {}
end
passive_stats.lines, passive_stats.changed = new_lines
end
for _, diff in ipairs(to_replace) do
local a, b = new_effects:find(diff[1], 1, 1)
if not a then
a, b = new_effects:find(diff[1]:gsub('<br>', '\n'), 1, 1)
if not a then
a, b = new_effects:find(diff[1]:gsub('\n', '<br>'), 1, 1)
if not a then
a, b = new_effects:find(diff[1]:gsub("'''", ''), 1, 1)
if not a then a, b = new_effects:find(unbold(diff[1]), 1, 1) end
end
end
end
if a then
if diff[1] == '' then new_effects = new_effects .. ' ' .. bold(diff[2])
else
if diff[2] == '' then diff[2] = ("<b><s>%s</s></b>"):format(diff[1]:gsub('\n', '<br>'))
else--no bold if inside bold line
local line = new_effects:gsub('<br>', '\n'):match('[^\n]*' .. diff[1]:gsub('%p', '%%%1') .. '[^\n]*')
if not line then line = new_effects:gsub('<br>', '\n'):match('[^\n]*' .. unbold(diff[1]):gsub('%p', '%%%1') .. '[^\n]*') end
if line:sub(1, 3) ~= "'''" or line:sub(-3) ~= "'''" or line:match"^'?'?'?(.-)'?'?'?$":find"'''" then diff[2] = bold(diff[2]) end
end
new_effects = new_effects:sub(1, a - 1)
.. diff[2]
.. (diff[2] == '' and (a == 1 or new_effects:find('\n' .. diff[1], 1, 1)) and
new_effects:sub(b + 1, b + 2):upper()
.. new_effects:sub(b + 3)
or new_effects:sub(b + 1)
)
end
elseif diff[1] == '^' then new_effects = bold(diff[2]) .. ' ' .. new_effects:sub(1, 1):lower() .. new_effects:sub(2)
else table.insert(to_append, "''Error - Unable to find: ''" .. bold(diff[1])) end
end
for k, v in ipairs(to_append) do to_append[k] = bold(effect_auto_link(v)) end
table.insert(to_append, 1, to_replace[1] and effect_auto_link(new_effects) or new_effects)
new_effects = table.concat(to_append, '<br>'):gsub('\n', '<br>'):gsub("'''/'''", '/')
return new_effects
end
local function missing_plus(unit, i) return 'awk_mat=NO DATA,0\nWarning: {{param|' .. unit .. '+' .. i .. '}} undefined' end
if unit then
for i = 1, tonumber(args.max_plus or p_args.max_plus) or 2 do
new_effects = parse_awakening(args[unit .. '+' .. i] or missing_plus(unit, i))
end
new_effects = new_effects:gsub("'+''(''%b'''')'''+"--[[looks wrong but isn't]], "%1"):gsub(("'"):rep(6),'')
local function arg_change(i)
return o_args[i] and ("<br>'''%s %sed to %s'''"):format(
({hits = 'Hit count', MP_cost = 'MP cost'})[i],
tonumber(unbold(args[i])) and
(tonumber(unbold(o_args[i])) > tonumber(unbold(args[i])) and ' reduc' or ' increas')
or 'chang',
unbold(args[i])
) or ''
end
result
:_(p_args[2] and (p_args[2] == 'table' and
'{|class=wikitable\n!Unit!!Abilities!!class=spacer|Base Effects!!class=spacer|Awakening'
or '|-class=subheader\n!colspan=4|'))
:_'\n|-\n|'
:_(p_args[2] and
('rowspan=%s style="text-align:center"|{{Sprite|%s}}<br>[[%s]]\n|')
:format(tonumber(p_args[2]) or tonumber(p_args[3]) or 3, unit, unit))
:_(link(args.name, true))
:_'<br>('
:_(args.awk_mat and args.awk_mat:match'^[^,]+' or '<b>awk_mat</b> undefined')
:_')\n| '
:_(args.ability and effects:sub(1, 7) ~= '<table ' and randomized_table(effects) or effects)
:_'\n| '
:_(args[unit .. '+1'] and new_effects or "''No data for unit named'' " .. bold(unit))
:_((arg_change'hits' .. arg_change'MP_cost'):sub(new_effects:sub(-8) == '</table>' and 5 or 1))
else
if p_args[1] == 'table' then
result:_'{|style="text-align:center;width:100%" class=wikitable\n|-\n!Name!!class=spacer|Effect!!style="width:50px"|{{tooltip|D {{=}} Default unit attack|Hits}}!!style="width:50px"|MP!!style="width:50px"|Type'
for i = 1, 5 do result:_'!!style="width:20px"|T':_(i) end
result:_'!!style="width:100px"|Gil'
elseif p_args[1] == 'conditional' then result:_'|-\n! colspan="11" | Conditional\n|-'
else result:_'|-class=subheader\n!colspan=11|' end
local last_atk_frm = args.atk_frm
for i = 1, tonumber(args.max_plus or p_args.max_plus) or 2 do
new_effects = unbold(new_effects)
parse_awakening(args[(p_args.skill or currentTitle) .. '+' .. i] or missing_plus(p_args.skill or currentTitle, i))
result
:_'\n|-\n|'
:_(link(args.name, true))
:_' +'
:_(i)
:_'\n|style="text-align:left"| '
:_(new_effects
:gsub("'''''%b'''''''", "'''%1'''")
:gsub(("'"):rep(6),'')
:gsub('\n', '<br>')
)
:_(atk_frm ~= args.atk_frm and
(function()
last_atk_frm = args.atk_frm
return multi_break(attack_frames(args.hits)):gsub('[FA]', function(m)return'New '..m:lower()end)
end)()
or multi_break(args.hits)
)
:_(multi_break(args.MP_cost))
if args.awk_mat then
local mats = mw.text.split(args.awk_mat, '%s*,%s*')
for c = 1, #mats - 1 do result:_'\n|':_(mats[c]) end
result
:_'\n|'
:_((' -\n|'):rep(7 - #mats))
:_(frame:expandTemplate{title='Gil', args = {mats[#mats]}})
else
result:_'\n|colspan=7|'
if p_args.skill then
if currentTitle ~= invokePage then result
:_'via '
:_(link(p_args.skill))
:_' +'
:_(i)
else result:_' -'end
else result:_'<b>awk_mat</b> undefined' end
end
args.MP_cost, args.hits = unbold(args.MP_cost), unbold(args.hits)
end
end
elseif args.mode == 'event' then
result
:_'|-\n|'
:_(BADGE())
:_'\n| '
:_(p.equipment[args.type] and stats_cell()
or materia_effects())
if args.recipe then result:_'\n| ':_(recipe()) end
extend()
elseif args.mode == 'custom' then
result:_'|-'
extend()
elseif args.mode == 'fetch' then
extend(p_args.sep)
if p_args.sep ~= '' then table.remove(result, 1) end--removes first sep
elseif args.mode == 'tooltip' then
local wikilink, tip, lines =
link(args.name, not p_args.full_pg),
mw.html.create'td',
(p.equipment[args.type] and stats_cell or materia_effects)(true)
lines[1] = stats_sorted[1] and p.equipment[args.type] and
'Stats: ' .. lines[1]
:gsub('%((%-%d+%%?)%)', '(<span style="color:#f00">%1</span>)')
:gsub('([^ ])(%+%d+%%?)', '%1<span style="color:#0f0">%2</span>')
or lines[1]
for i = 1, #lines do
if lines[i]:find'^<table' then
tip:node(lines[i]:gsub('(<table style=")', '%1font-size:8.5px;'))
lines.table = true
else tip
:tag'div'
:css{
['padding-left']='2ex',
['text-indent']='-2ex',
['font-size']=lines.table and '8.5px' or nil
}
:wikitext(lines[i])
end
end
tip:css{background = '#014'}
return frame:preprocess(tostring(mw.html.create'span'
:addClass'tool'
:tag'span'
:addClass'mobileonly'
:wikitext(wikilink)
:done()
:tag'span'
:addClass'nomobile'
:wikitext(wikilink)
:done()
:tag'span'
:addClass'tip module-tooltip'
:tag'table'
:tag'tr'
:tag'td'
:css{width='90px',['text-align']='center',['vertical-align']='top',padding='12px 6px'}
:attr{rowspan=2}
:wikitext(icon'')
:done()
:tag'td'
:css{padding='5px 0 0 5px',font='15px Arial, sans-serif',height='30px'}
:node(args.name:gsub(' %(%w+%)', ''))
:node((p.equipment[args.type] or p.ability[args.type] == 2) and mw.html.create'span'
:css{float='right',['margin-top']='-9px'}
:wikitext(
frame:expandTemplate{
title = p.equipment[args.type] and 'Equip' or 'Affinity',
args = {args.type == 'Throwing Weapon' and
'Throwing'
or args.type
}
},
p.ability[args.type] and ' Lvl ' .. args.mag_lv .. ' '
)
)
:done()
:done()
:tag'tr'
:node(tip)
:allDone()
))
else
--Display when on a shop page (mode = recipe/item/item2/typeless)
result
:_(('|-\n| %s@\n| %s %s')--don't remove spaces
:gsub('@', args.mode == 'item2' and '{{item|%%s}}' or '%%s')
:format(
args.mode == 'recipe' and 'Recipe for '
or '',
args.mode == 'item2' and args.name or link(args.name, true),
(args.mode == 'typeless' or args.mode == 'recipe') and
(p.equipment[args.type] and '-\n| ' or 'colspan=2' .. (args.mode == 'recipe' and '| ' or ''))
or type_link() .. '\n|',
args.mode == 'recipe' and '-'
or widget_sort_stats() .. (
p.equipment[args.type] and stats_cell()
or materia_effects()
or (args.usage or args.awk_mat) and 'Material'
or '-'
)))
:_(p_args.limit ~= '0' and ('\n|{{%s|%s}}%s'):format(
args.quartz and 'Star Quartz' or 'Gil',
args.quartz
or ({item=1,item2=1})[args.mode] and args.buy_gil
or args.mode == 'recipe' and args.buy_rec
or '?',
p_args.limit and ('<br>(Limit: %s)'):format(p_args.limit) or ''
))
extend()
end
else
--info displayed on item (invoke) page
result
:_'__NOTOC__\n__NOEDITSECTION__'
:_((args.image or args.name) and ('<div class="frame-%s">\n%s\n</div>'):format(
p.equipment[args.type] and 'equip' or p.ability[args.type] and 'ability' or 'item',
icon()
))
:_(args.desc and '\n\n' .. args.desc)
if args.mode then table.remove(result, 1) end--mode = demo
if args.type then
if p.equipment[args.type] then
local materia = {args.effect}
table.insert(materia, args.ability)
for k, v in ipairs(materia) do materia[k] = split_link(v, true, nil, ailment_link) end
result
:_"\n== Statistics ==\n*'''Type:''' "
:_(args.type == 'Accessory' and '[[:Category:Accessories|Accessory]]'
or p.equipment._class[p.equipment[args.type]] .. type_link(true))
:_"\n*'''Stats:''' "
:_(stats_sorted[1] and table.concat(stats_sorted, ', ') or '-')
:_"\n*'''Element:''' "
:_(args.element or '-')
:_"\n*'''Resistance:''' "
:_(args.resist and split_link(args.resist, false, nil, ailment_link) or '-')
:_"\n*'''Additional effect:''' "
:_(#materia > 0 and
link2tooltip(args.ability and (--replace link2tooltip after all abilities use Data
args.effect and
"%s and enables use of %s"
or 'Enables use of %s'
):format(unpack(materia))
or materia[1], true) .. (args.warning and ', ' .. args.warning or '')
or args.warning
or '-'
)
elseif p.ability[args.type] then
flags.rng_enable = args.effect and args.effect:find'%(%d+%%%) [^\n]*Enable' and not args.ability
result
:_"\n== Statistics ==\n*'''Type:''' "
:_(p.ability._class[p.ability[args.type]])
:_' ('
:_(args.type)
:_(p.ability[args.type] == 2 and ' Magic Lv ' .. args.mag_lv)
:_")\n*'''Effect:'''\n:"
:_(materia_effects())
:_(args.hits and "\n*'''Hits:''' " .. attack_frames(args.hits))
:_(args.MP_cost and "\n*'''MP:''' " .. args.MP_cost)
if args.ability or flags.rng_enable then
result
:_'\n==Abilities==\n'
:_(args.ability and materia_ailment_link(args.ability))
if flags.rng_enable then
local r, fake_parent = result, {
getTitle = function() return currentTitle end,
args = {mode = 'conditional'},
getParent = frame.getParent
}
function frame.getParent() return fake_parent end
result = {_ = result._}
frame.getParent, result = fake_parent.getParent, r
:_'{|class=wikitable style="text-align:center;width:100%"\n|-\n! colspan="3" | Condition !! width="130px" | Name !! class="spacer" | Effect !! width="50px" | Hits {{Tooltip|D {{=}} Default unit attack}} !! width="50px" | MP\n'
:_(p.item(frame))
:_'\n|}'
end
end
elseif args.type == 'Item' and args.effect then
result
:_'\n== Effect ==\n'
:_(materia_effects())
end
end
result
:_(args.notes and '\n==Notes==\n')
:_(args.notes)
:_'\n==Crafting recipe==\n'
:_(args.recipe and args.recipe ~= 'none' and
('{|class=wikitable style="text-align:center"\n!Materials!!Gil\n|-\n|align=left|%s\n||{{Gil|%s}}\n|}'):format(
recipe() or '{{param|rec_mat}} is undefined',
args.rec_gil or '?')
or 'None'
)
:_((args.usage or args.quest) and result
:_"\n==Usage=="
:_(args.awk_mat and "\n''Awakening Material''\n:*" .. split_link(args.quest, nil, '\n:*'))
:_(args.usage and "\n''Crafting Material''" .. multi_split(args.usage, "\n:''%s''\n::*", '\n::*', '\n:*'))
:_(args.quest and "\n''Involved in Quest''\n:*" .. split_link(args.quest, nil, '\n:*'))
and nil
)
:_"\n==How to obtain=="
local function simpleTable(v)
local rows = mw.text.split(v, '\n+')
for k, r in ipairs(rows) do
local cells = mw.text.split(r, "%$")
for i, c in ipairs(cells) do
if c:find'^ *%[%[.+%]%] *$' then cells[i] = 'style="text-align:left"| ' .. c end
end
rows[k] = table.concat(cells, ' || ')
end
result
:_'{|class="wikitable sortable" style="text-align:center"\n'
:_(table.concat(rows, '\n|-\n| '))
:_'\n|}'
end
for i = 1, #froms do
if args[froms[i][1]] then
flags.isItem = flags.isItem or not froms[i][3]
result
:_"\n''"
:_(froms[i][2])
:_"''\n:"
if args[froms[i][1]]:find'^{|' then
result:_(args[froms[i][1]])
elseif args[froms[i][1]]:find'^!' then
simpleTable(args[froms[i][1]])
else result
:_"*"
:_(split_link(args[froms[i][1]], nil, '\n:*', froms[i][1] == 'equip' and tooltip_link))
end
end
end
result
:_(args.trust and ("\n''Trust Master Reward''\n:*[[%s]]"):format(args.trust))
:_(args.obtain and multi_split(args.obtain, "\n''%s''\n:*", '\n:*', '\n*'))
:_(args.used_by and "\n==Equippable By==\n:*" .. split_link(args.used_by, nil, '\n:*'))
if args.learn then
local awk = {}
for name in args.learn:gmatch'\n|? *%[%[([^%]|]+)' do
if args[name .. '+1'] then table.insert(awk, {name}) end
end
if args.enable then for skill in args.enable:gsub('\\,', '@$'):gmatch'%f[%w][^,]+' do
if args[skill .. '+1'] then table.insert(awk, {skill:gsub('@$', ','), isSkill = true}) end
end end
if awk[1] then
table.sort(awk, function(a, b) return a[1] < b[1] end)
local fake_parent = {
getTitle = function() return currentTitle end,
args = {'table', mode = 'awaken'}
}
function frame.getParent() return fake_parent end
local r, wide_tab = result:_'\n==Ability Awakening==',
'width:200%%;margin-right:-99vh;%1"%2 mw-collapsible mw-collapsed" data-expandtext="Show table (hidden on testcase pages only due to width)"\n|+'
for k, name in ipairs(awk) do
result, fake_parent.args.page, fake_parent.args.skill =
setmetatable({}, {__index = r}),
select(name.isSkill and 1 or 2, invokePage, name[1])
awk, fake_parent.args[1] = k== 1 and
p.item(frame)
:gsub('!Name', '!style="width:5em"|Unit/Skill!%1', 1)
:gsub(currentTitle:find'testcases/' and 'width:100%%([^"]*" class=)(wikitable)' or '^$',
wide_tab,
1
)
or p.item(frame)
:gsub('(colspan=)(%d+)', function(a,b)return a..b+1 end, 1)--future maintenance proof
r:_'\n':_(awk:gsub(
'(%|%[%[.-%]%] %+)',
'|rowspan=' .. select(2, awk:gsub('[^|]%[%[([^%]|]+)%]%] ?%+1', '')) * 3 + 2 .. '|'
.. (name.isSkill and
'{{:' .. name[1] .. '|mode=fetch|ICON}}'
or '{{sprite|' .. name[1] .. '}}'
) .. '<br>'.. link(name[1]) ..'|%1',
1
))
for conditional in awk:gmatch'[^|]%[%[([^%]|]+)%]%] ?%+1' do
local m = ''
for n in awk:gmatch('%[%[' .. conditional .. '%]%] ?%+%s') do m = m < n and n or m end
r:_'\n':_(frame
:expandTemplate{title = ':' .. conditional, args = {
mode = 'awaken',
skill = args.name,
max_plus = m
}}
:gsub('undefined', '%1 at ' .. link(conditional))
)
end
end
result = r:_'\n|}'
end
end
local categories = {''}
if args.type then
if p.ability[args.type] then
table.insert(categories, 'Module:Data Ability')
if flags.isItem or args.trust or args.obtain then
table.insert(categories, 'Items')
table.insert(categories, 'Ability Materia')
elseif args.esper or args.equip then table.insert(categories, 'Ability Materia') end
if p.ability[args.type] == 1 then
table.insert(categories, ('%s (%s)'):format(
p.ability._class[p.ability[args.type]]:sub(1, -2) .. 'ies',
args.type
))
else
table.insert(categories, 'Magic')
table.insert(categories, args.type .. ' Magic')
table.insert(categories, args.type .. ' Magic Level ' .. args.mag_lv)
end
else
table.insert(categories, 'Items')
if p.equipment[args.type] then
table.insert(categories, 'Equipment')
if args.type == 'Accessory' then
table.insert(categories, 'Accessories')
else
table.insert(categories, p.equipment._class[p.equipment[args.type]] .. 's')
table.insert(categories, p.equipment._plural[args.type] or args.type .. 's')
end
else
if args.usage or args.awk_mat then table.insert(categories, 'Materials') end
end
end
end
if (args.recipe or args.reward or ''):find(p.patterns.event) then table.insert(categories, 'Event Items') end
for _, k in ipairs{
--{arg key, category name}, if key is not nil, put in cat
{'recipe', 'Crafting Recipes'},
{'buy_gil', 'Purchasables'},
{'trust', 'Trust Master Rewards'},
{hasExclusiveFX and 'effect' or 'used_by', 'Unit Exclusive Items'},
{'awk_mat', 'Awakening Materials'},
{'usage', 'Crafting Materials'},
{'quest', 'Quest Items'},
{'equip', 'Equipment-given Abilities'},
{'esper', 'Esper-given Abilities'}
} do
if args[k[1]] then table.insert(categories, k[2]) end
end
result
:_((namespace ~= 0 and --escape catagories if not on main namespace
table.concat(categories, ']]\n[[:Category:'):gsub('%[C', '[:C')
or table.concat(categories, ']]\n[[Category:')
):sub(3, -1))
:_']]'
end
return frame:preprocess(table.concat(result))
end
function p.wrap(frame)
if frame.args.mode == 'shop' then
result
:_'{|class=wikitable'
for k, v in ipairs(frame.args) do
local name = k==1 and frame.args.name or frame.args['name'..k] or ''
result
:_'\n|-\n!colspan=4| '
:_(name)
:_'\n|-\n!Name!!'
:_((name == 'Item Shop' or name == 'Ability Shop') and
'colspan=2| '
or 'Type!!'
)
:_'Description!!Price'
:_(v)
end
result:_'\n|}'
end
return frame:preprocess(table.concat(result))
end
function p.find(frame)
local data, bad, title, result, this = {}, {}, mw.title.getCurrentTitle().fullText
this = mw.text.decode(frame:preprocess('{{msgnw::' .. (frame.args[1] or mw.title.getCurrentTitle().fullText) .. '}}'))
if title:find'User:' or not title:find':' and not title:find'/' then
for m, p, l in this:gmatch'|%s*%[(%b[])%] *(.)(%d?)' do
m = m:sub(2, -2):match'^[^|]+'
if not (m:find':[^ _]' or m:find'#') and (p ~= '+' or l ~= '2') then
local page = mw.text.decode(frame:preprocess('{{msgnw::' .. m .. '}}')):gsub('<!%-%b--%->', '')
if page:lower():find'<onlyinclude>%s*{{#invoke:data|item' and (not title:find'Abilit' or page:find'Ability_%d+%.png') then
if this:sub(1, 99):find'Unit Infobox' then
table.insert(page:find(title) and data or bad, p == '+' and tonumber(l) and m .. '|mode=awaken' or m)
else
if title == 'Ability Awakening' then
for awk in page:gmatch'|%s*([^\n]-)%+1%s*=' do
if not this:find(m .. '|'.. awk, 1, 1) then
local rowspan = this:match(
'rowspan%s*=%s*["\']?(%d+)[^\n]+'
.. awk .. '[^\n]+\n|%s*%[%[' .. m
)
table.insert(data, m .. '|' .. awk
.. (rowspan and '|' .. rowspan or ''))
end
end
else
local rowspan
if title:find'Abilit' and page:find'mag_lv%s*=%s*%d' then
rowspan = this:match('rowspan=["\']?(%d+)[^\n]+\n|[^\n]+|' .. m)
end
table.insert(data, rowspan and
m .. '|rowspan=' .. rowspan
or m
)
end
end
end
end
end
end
if data[1] then
result = '{{Kupo2|Kupo! The following '
.. (data[2] and 'are [[Module:Data]] pages' or 'is a [[Module:Data]] page')
.. ':\n<pre>{{:'
.. table.concat(data, '}}\n{{:')
.. '}}</pre>\nPlease replace where appropriate. Thanks!\n\nThis message only appears if links to such pages are found.\n}}'
end
if bad[1] then
result = (result or '')
.. '{{Kupo2|The following '
.. (bad[2] and '[[Module:Data]] abilites do' or '[[Module:Data]] ability does')
.. ' not include this unit in {{param|learn}}:\n\n[['
.. table.concat(bad, ']], [[')
.. ']]\n\nPlease add this unit to '
.. (bad[2] and 'those pages' or 'that page')
.. '. Thanks, Kupo!}}'
end
local count = #data
if bad[1] then count = '*'
elseif #data > 9 then count = mw.ustring.char(('A'):byte() + #data - 10) end
return result and frame:preprocess(result) .. (not this:find'{{Unreleased}}' and '[[Category:Pages needing a Module:Data transclusion|' .. count.. ']]' or '')
--following script can be used on pages like Special Abilities Passive in edit mode
--javascript:for(i=0,m=document.querySelector('div>pre').innerHTML.match(/[^{}:][^{}\n]+?(?=\}\})/g);m[i];i++)wpTextbox1.value=wpTextbox1.value.replace(new RegExp('\\n\\|\\-.*?\\n?.*?\n?.*?\\[\\[('+m[i].replace(/([^\w\s])/g, "\\$1")+')(\]\]|\\|)[\\s\\S]*?(?=\\n(\\|(\\-|\\})|\\{\\{:))'), "\n{{:$1}}");
end
return p