Documentation for this module may be created at Module:Autoability/doc
-- ----------------------------------------------------------------------------
-- Imports
-- ----------------------------------------------------------------------------
local getArgs = require("Module:Arguments").getArgs
local yesno = require("Module:Yesno")
local quote = require("Module:Quote")._quote
local cargo = require("Module:Cargo")
local p = {}
local lang = mw.language.new('en')
-- -------------------------------------------------------------------------
-- Strings
-- -------------------------------------------------------------------------
local i18n = {
CELR = "Cumulative effect limit reached.",
inf = "∞",
icons = {
red = "File:Icon Auto-Abilities Red.png",
blue = "File:Icon Auto-Abilities Blue.png",
green = "File:Icon Auto-Abilities Green.png",
yellow = "File:Icon Auto-Abilities Yellow.png",
},
-- Called "Category" ingame. Refer to skill card filter in deck editor.
categories = {
red = "Multi-Skill",
blue = "Auto-Skill",
green = "Enhance/Resist",
yellow = "Attributes",
},
errors = {
minimum_not_numeric = "Provided minimum value is not a number (%s)",
minimum_not_unique = "Provided minimum value is not unique (%s)",
}
}
local styles = {
clear = {
["clear"] = "both",
["height"] = "5px",
},
infobox = {
["float"] = "right",
["position"] = "relative",
["width"] = "250px",
["background"] = "#FFF",
["font-size"] = ".923em",
["border"] = "1px solid #AAA",
["margin"] = "0 0 1em 1em",
["padding"] = "0",
},
heading = {
["font-weight"] = "700",
["text-align"] = "center",
["border"] = "1px solid rgba(0,0,0,0.25)",
["border-bottom-width"] = "0",
["position"] = "relative",
["z-index"] = "1",
["margin"] = "-1px -1px 5px!important",
["font-size"] = "1.417em!important",
["color"] = "#fff!important",
["background-color"] = "#444",
["text-shadow"] = "rgba(0,0,0,0.75) 0 0 .25em",
["line-height"] = "1.176em",
["font-size-adjust"] = ".43",
["padding"] = ".5em!important",
},
wrapper = {
["clear"] = "both",
["padding"] = "0",
},
dt = {
["float"] = "left",
["text-align"] = "right",
["width"] = "78px",
["line-height"] = "1em",
["font-weight"] = "700",
["clear"] = "left",
["border-right"] = "2px solid #999",
["margin"] = "0 -2px 0 0",
["padding"] = "2px 8px 2px 3px",
["line-height"] = "1.667em",
},
dd = {
["float"] = "left",
["width"] = "125px",
["font-weight"] = "400",
["border-left"] = "2px solid #999",
["margin"] = "0",
["padding"] = "2px 7px",
["line-height"] = "1.667em",
},
}
function p.parse_min_infos(info, minimum, maximum)
local infos = info or ""
if infos == "" then
infos = {}
elseif type(infos) == "string" then
infos = mw.text.split(infos, "%s*;%s*")
end
for i=#infos,1,-1 do
if infos[i] ~= "" then break end
infos[i] = nil
end
local mins = minimum or ""
if mins == "" then
mins = {}
elseif type(mins) == "string" then
mins = mw.text.split(mins, "%s*;%s*")
end
for i=#mins,1,-1 do
if mins[i] ~= "" then break end
mins[i] = nil
end
if #mins == 0 and #infos == 0 then
return {}
elseif #mins == #infos then
local keys = {}
local items = {}
for i,min in ipairs(mins) do
local key = tonumber(min)
if not key then
error(string.format(i18n.errors.minimum_not_numeric, min))
end
if key <= maximum then
keys[#keys+1] = key
-- Ensure that all keys are unique.
if items[key] then
error(string.format(i18n.errors.minimum_not_unique, min))
end
items[key] = infos[i]
end
end
table.sort(keys)
local min_infos = {}
for i=1,#keys do
local from = keys[i]
local to = keys[i+1]
if to then
to = to - 1
else
to = maximum
end
local v = mw.text.trim(items[from])
if v:sub(-#i18n.CELR) == i18n.CELR then -- v:endswith(i18n.CELR)
v = mw.text.trim(v:sub(1, -#i18n.CELR - 1))
end
if from == maximum then
v = v.." "..i18n.CELR
end
min_infos[i] = {info=mw.text.trim(v), from=from, to=to}
end
return min_infos
elseif #mins == 0 then
-- Minimum is empty, assume that infos is sorted.
-- "", "A;B;C" = [A,B,C].
-- "", "A;C;B" = [A,C,B].
local min_infos = {}
for i,v in ipairs(infos) do
min_infos[#min_infos+1] = {info=v}
end
return min_infos
elseif #infos == 0 then
-- No description provided. What to do?
return {}
elseif #mins < #infos then
-- There are not enough minimums provided. What to do?
return {}
elseif #infos < #mins then
-- There are not enough descriptions provided. What to do?
return {}
end
end
-- Implements {{autoability}}
function p.infobox(frame)
local args = getArgs(frame)
local name = args.name or mw.title.getCurrentTitle().fullText
local id = (args.id or name):lower():gsub("%W+", "_")
local color = args.color or ""
local icon = i18n.icons[color:lower()]
local category = i18n.categories[color:lower()]
local category_icon = icon and ("[["..icon.."|link=|16px]] "..category)
local is_rewards_based = yesno(args.rewards_based, false)
local value_type = (args.value_type or ""):lower()
local is_value_hidden = yesno(args.hide_value, false)
local info = args.info or args.description or ""
local minimum = args.minimum or ""
local maximum = tonumber(args.maximum) or math.huge
local min_infos = p.parse_min_infos(info, minimum, maximum)
-- Build view
local content = mw.html.create("div")
content
:addClass("infobox auto-ability"):addClass(color)
:css(styles.infobox)
:tag("p")
:addClass("heading")
:css(styles.heading)
:wikitext(name)
:done()
:tag("div")
:addClass("wrapper")
:css(styles.wrapper)
:tag("dl")
:tag("dt")
:css(styles.dt)
:wikitext("Value type")
:done()
:tag("dd")
:css(styles.dd)
:wikitext(lang:ucfirst(value_type))
:done()
:tag("dt")
:css(styles.dt)
:wikitext("Hidden value")
:done()
:tag("dd")
:css(styles.dd)
:wikitext(is_value_hidden and "Yes" or "No")
:done()
:tag("dt")
:css(styles.dt)
:wikitext("Category")
:done()
:tag("dd")
:css(styles.dd)
:wikitext(category_icon)
:done()
:tag("dt")
:css(styles.dt)
:wikitext("Main only")
:done()
:tag("dd")
:css(styles.dd)
:wikitext(is_rewards_based and "Yes" or "No")
:done()
:tag("dt")
:css(styles.dt)
:wikitext("Maximum")
:done()
:tag("dd")
:css(styles.dd)
:wikitext(maximum == math.huge and i18n.inf or maximum)
:done()
:done()
:tag("div")
:addClass("clear")
:css(styles.clear)
:done()
:done()
local quotation = mw.html.create("")
for _,row in ipairs(min_infos) do
local from = row.from
local to = row.to
if to and from == to then
to = nil
end
if to and to == math.huge then
to = "∞"
end
local interval = table.concat({from, to}, "~")
if interval ~= "" then
interval = mw.html.create("small")
:wikitext("'''["..interval.."]:''' ")
:done()
else
interval = nil
end
local info = row.info
quotation
:tag("p")
:node(interval)
:wikitext(info)
:done():newline()
end
local description_box = quote{
text = tostring(quotation),
source = "In-game description",
}
mw.logObject(quotation)
local infobox = mw.html.create("")
:node(content)
:node(description_box)
local out = tostring(infobox)
-- ------------------------------------------------------------------------
-- Category handling
-- ------------------------------------------------------------------------
local cats = {}
if category then
cats[#cats+1] = lang:ucfirst(category:lower()) .. " auto-abilities"
end
if is_rewards_based then
cats[#cats+1] = "Rewards-based auto-abilities"
end
if maximum and maximum < math.huge then
cats[#cats+1] = "Auto-abilities with cumulative effect limits"
end
for i, cat in ipairs(cats) do
cats[i] = string.format("[[Category:%s]]", cat)
end
out = out..table.concat(cats)
-- ------------------------------------------------------------------------
-- Store cargo data
-- ------------------------------------------------------------------------
--[[cargo.store("autoabilities", {
id = id,
name = name,
color = color,
icon = icon,
category = category,
is_rewards_based = is_rewards_based and 1 or 0,
value_type = value_type,
is_value_hidden = is_value_hidden and 1 or 0,
maximum = maximum,
})]]
for _,row in ipairs(min_infos) do
local from = row.from
local to = row.to or maximum
to = math.min(to + 1, maximum)
local info = row.info
--[[cargo.attach("autoabilities_min_infos", {
from = from,
to = to,
info = info,
})]]
mw.log(from, to, info)
end
--mw.log(out)
return out
end
function p.test()
p.infobox{
name = "Crystal Seeker",
description = [[Ever so slightly raises the chance to obtain crystals as drops.;
Slightly raises the chance to obtain crystals as drops.;
Raises the chance to obtain crystals as drops.;]],
minimum = [[5; 15; 40]],
value_type = "number",
hide_value = "n",
color = "blue",
}
p.infobox{
name = "Crystal Seeker",
description = [[Ever so slightly raises the chance to obtain crystals as drops.;
Slightly raises the chance to obtain crystals as drops.;
Raises the chance to obtain crystals as drops.;]],
minimum = [[5; 15; 40]],
maximum = 100,
value_type = "number",
hide_value = "n",
color = "blue",
}
p.infobox{
name = "Job Change Recast",
description = [[
Job Change recast: 4 turns. ;
Job Change recast: 3 turns. ;
Job Change recast: 2 turns. Cumulative effect limit reached. ;]],
minimum = [[0; 1; 2]],
--maximum = "2",
value_type = "number",
hide_value = "y",
color = "blue",
}
p.infobox{
name = "Job Change Recast",
description = [[
Job Change recast: 4 turns. ;
Job Change recast: 3 turns. ;
Job Change recast: 2 turns. ;]],
minimum = [[0; 1; 2]],
maximum = "2",
value_type = "number",
hide_value = "y",
color = "blue",
}
end
return p