Module:Ability stat

local mArguments -- lazy load local cargo = require("Module:Cargo") local cargo_store = cargo.store local mm = require("Module:Math") local yesno = require('Module:Yesno')

local p = {}

local BLACK = mw.ustring.char(0x2605) local WHITE = mw.ustring.char(0x2606) local NAMESPACE = mw.title.getCurrentTitle.namespace local FULLPAGENAME = mw.title.getCurrentTitle.fullText

local multis = {1.0, 1.1, 1.2, 1.3, 1.4, 1.7, 2.0, 2.3, 2.6, 3.0} local cooldowns = {8, 7, 6, 5, 4, 3, 2, 2, 1, 1}

local i18n = { categories = { -- Tracking categories non_support_with_no_atk = "Non-support abilities with no attack", non_support_with_no_brk = "Non-support abilities with no break power", non_support_with_fixed_atk = "Non-support abilities with fixed attack", non_support_with_fixed_brk = "Non-support abilities with fixed break power", non_support_with_cooldown = "Non-support abilities with cooldown", support_with_varied_atk = "Support abilities with attack", support_with_varied_brk = "Support abilities with break power", support_with_fixed_atk = "Support abilities with fixed attack", support_with_fixed_brk = "Support abilities with fixed break power", support_with_no_cooldown = "Support abilities with no cooldown", },	errors = { rarity_empty = "No rarity specified.", rarity_not_a_number = "Rarity is not a number: %q", rarity_out_of_bounds = "Rarity is outside the range of 1-5: %d", } }

local function number_to_stars(n) local n = tonumber(n) or 0 return string.rep(WHITE, n / 10) .. string.rep(BLACK, n % 10) end

local function parse_number(s) return tonumber(s) or 0 end

local function parse_stars(s) local s = tostring(s) :gsub("&#9733;", BLACK) :gsub("&#x2605;", BLACK) :gsub("&starf;", BLACK) :gsub("&#9734;", WHITE) :gsub("&#x2606;", WHITE) :gsub("&star;",  WHITE) local pattern = "^%s*(["..BLACK..WHITE.."]*)%s*x?%s*(%d*)%s*$" local stars, digit = mw.ustring.match(s, pattern) if digit == "" and stars == "" then mw.log(string.format("Count not find stars or numbers: %q", s)) return 0 elseif digit == "" and stars ~= "" then local _, bcount, wcount _, bcount = string.gsub(stars, BLACK, "") _, wcount = string.gsub(stars, WHITE, "") return bcount + wcount * 10 elseif digit ~= "" and (stars == "" or stars == BLACK) then return tonumber(digit) elseif digit ~= "" and stars ~= "" then mw.log(string.format("Number and multiple stars specified: %q", s)) -- Stars were specified multiple times AND digits also follow. return 0 end end

function p.get_levels(args) local rarity = tostring(args.rarity or '') if mw.text.trim(rarity) == '' then error(i18n.errors.rarity_empty) end local jobtype = tostring(args.jobtype):lower local is_support = jobtype == 'support' or jobtype == 'healer'

local rarities = {} local is_fast for digit, plus in rarity:gmatch('(%d+)(%+?)') do		digit = tonumber(digit) if digit 5 then error(i18n.errors.rarity_out_of_bounds:format(digit)) end rarities[#rarities+1] = digit is_fast = is_fast or plus == '+' end if #rarity == 0 then error(i18n.errors.rarity_not_a_number:format(rarity)) end local min_rarity = mm._min(unpack(rarities)) local max_rarity = mm._max(unpack(rarities)) local m, c	if is_support then m, c = 1, 1 else m, c = 2, 0 end local start = 1 local stop = m * max_rarity + c	local step = 1 if is_fast then start = m * min_rarity + c		step = m	end local levels = {} for x=start, stop, step do		levels[#levels+1] = x	end return levels end

function p._main(args) -- Load args into locals local jobtype = tostring(args.jobtype):lower local base_atk = parse_number(args.atk or args.attack) local base_brk = parse_number(args.brk or args.break_power or args.breakpower) local base_crt = parse_stars(args.crt or args.crit_chance or args.critchance)

local is_fixed_atk = yesno(args.const_atk or args.const_attack) local is_fixed_brk = yesno(args.const_brk or args.const_breakpower) local is_support = jobtype == 'support' local has_cooldown = args.has_cooldown if has_cooldown == nil then -- If there is a support with no-cooldown, then this would be "false" has_cooldown = is_support else has_cooldown = yesno(has_cooldown) end

local lvls = p.get_levels(args) local atks = {} local brks = {} local crts = {} local cds = {} -- Handle fixed and varying stats. for i=1,10 do		local atk if is_fixed_atk then atk = base_atk else local atk_i = args['atk'..i] or args['attack'..i]			local atk_m = base_atk * multis[i] atk = atk_i or atk_m end atks[i] = mm._round(atk) local brk if is_fixed_brk then brk = base_brk else local brk_i = args['brk'..i] or args['breakpower'..i] or args['break_power'..i]			local brk_m = base_brk * multis[i] brk = brk_i or brk_m end brks[i] = mm._round(brk) crts[i] = base_crt if has_cooldown then cds[i] = args['cd'..i] or args['cooldown'..i] or cooldowns[i] end end

-- If the stat set contains only one value, then it is a fixed stat. local atk_set = {} local atk_len = 0 local brk_set = {} local brk_len = 0 -- We're only checking the values at each level. for i,lvl in ipairs(lvls) do -- Before insert, check if it's already defined. local k = atks[lvl] if not atk_set[k] then atk_len = atk_len + 1 atk_set[k] = true end k = brks[lvl] if not brk_set[k] then brk_len = brk_len + 1 brk_set[k] = true end end -- no value, or the only value is "0". local has_no_atk = atk_len == 0 or (atk_len == 1 and atk_set[0]) local has_no_brk = atk_len == 0 or (atk_len == 1 and atk_set[0]) -- If only one value, and is not "0". local has_fixed_atk = atk_len == 1 and not atk_set[0] local has_fixed_brk = brk_len == 1 and not brk_set[0] -- If there are 2 or more different values. -- Is "0" a valid value? local has_varied_atk = atk_len > 1 and not atk_set[0] local has_varied_brk = brk_len > 1 and not brk_set[0] -- Create data rows for storage and display. local data_rows = {} for i,lvl in ipairs(lvls) do		local data_row = { level = lvl, attack = atks[lvl], break_power = brks[lvl], crit_chance = crts[lvl], cooldown = cds[lvl], }		data_rows[#data_rows+1] = data_row end -- Storage if NAMESPACE == 0 or args.demospace == "main" then local abilities = mw.ext.cargo.query("abilities", "_pageName", {			where = string.format("_pageName = %q", FULLPAGENAME),		}) if #abilities > 0 then for i,data_row in ipairs(data_rows) do				cargo.store("ability_stats", data_row) end end end -- Display local root = mw.html.create("table") root:addClass("wikitable") local header = root:tag("tr") header:tag("th"):wikitext("ALv."):done header:tag("th"):wikitext("Attack"):done header:tag("th"):wikitext("Break Power"):done header:tag("th"):wikitext("Crit Chance"):done header:tag("th"):wikitext("Cooldown"):done for i,data_row in ipairs(data_rows) do		local lvl = data_row.level local atk = data_row.attack or 0 local brk = data_row.break_power or 0 local crt = data_row.crit_chance local stars = number_to_stars(crt) crt = string.format("%s (%d%%)", stars, crt * 5) local cd = data_row.cooldown or 0

local tbl_row = root:tag('tr') tbl_row:tag("td"):wikitext(lvl):done tbl_row:tag("td"):wikitext(atk):done tbl_row:tag("td"):wikitext(brk):done tbl_row:tag("td"):wikitext(crt):done tbl_row:tag("td"):wikitext(cd):done end -- Categories local cats = {} if NAMESPACE == 0 or args.demospace == "main" then if is_support then if has_fixed_atk then cats[#cats+1] = i18n.categories.support_with_fixed_atk elseif has_varied_atk then cats[#cats+1] = i18n.categories.support_with_varied_atk end if has_fixed_brk then cats[#cats+1] = i18n.categories.support_with_fixed_brk elseif has_varied_brk then cats[#cats+1] = i18n.categories.support_with_varied_brk end if not has_cooldown then cats[#cats+1] = i18n.categories.support_with_no_cooldown end else if has_no_atk then cats[#cats+1] = i18n.categories.non_support_with_no_atk elseif has_fixed_atk then cats[#cats+1] = i18n.categories.non_support_with_fixed_atk end if has_no_brk then cats[#cats+1] = i18n.categories.non_support_with_no_brk elseif has_fixed_brk then cats[#cats+1] = i18n.categories.non_support_with_fixed_brk end if has_cooldown then cats[#cats+1] = i18n.categories.non_support_with_cooldown end end end for i,cat in ipairs(cats) do		cats[i] = string.format('', cat) end -- Output return tostring(root) .. table.concat(cats) end

function p.main(frame) mArguments = require("Module:Arguments") local args = mArguments.getArgs(frame) return p._main(args) end

return p