Module:Damage: Difference between revisions
From Elwiki
No edit summary |
No edit summary Tag: Reverted |
||
Line 2: | Line 2: | ||
require('Module:CommonFunctions'); | require('Module:CommonFunctions'); | ||
local getArgs = require('Module:Arguments').getArgs | local getArgs = require('Module:Arguments').getArgs | ||
local p = {} | local p = {} | ||
Line 8: | Line 7: | ||
function p.main(frame) | function p.main(frame) | ||
local args = getArgs(frame) | local args = getArgs(frame) | ||
function inArgs(key) | function inArgs(key) | ||
Line 16: | Line 14: | ||
end | end | ||
local | -- Collect data from the input | ||
local data = {} | |||
local data_types = { | |||
'dmg', | |||
'awk_dmg', | |||
'hits', | |||
'avg_hits', | |||
'awk_hits', | |||
'avg_awk_hits', | |||
'hits_useful', | |||
'avg_hits_useful', | |||
'awk_hits_useful', | |||
'avg_awk_hits_useful', | |||
'perm_buff' | |||
} | |||
-- | -- Handle the PvP split values | ||
for k, v in spairs(data_types) do | |||
for | table.insert(data_types, 'pvp_' .. v) | ||
end | end | ||
for k, v in spairs(data_types) do | |||
for | local i = 1 | ||
if inArgs(v) then | |||
for k2, v2 in spairs(split(args[v])) do | |||
-- Check for operators. If detected, evaluate. | |||
if string.find(v2, '*') or string.find(v2, '+') then | |||
v2 = frame:preprocess('{{#expr:' .. v2 .. '}}') | |||
end | |||
-- Check if proper hit count values provided. If empty string detected, inherit from 'hits'. | |||
if string.find(v, 'avg_') and string.find(v, '_hits') and v2 == '' then | |||
data[v .. i] = data['avg_hits' .. i] | |||
elseif string.find(v, 'hits') and v2 == '' then | |||
data[v .. i] = data['hits' .. i] | |||
elseif string.find(v, 'awk_dmg') and v2 == '' then | |||
if string.find(v, 'pvp') then | |||
data[v .. i] = data['pvp_dmg' .. i] | |||
else | |||
data[v .. i] = data['dmg' .. i] | |||
end | |||
else | |||
data[v .. i] = v2 | |||
end | |||
i = i + 1 | |||
end | |||
end | end | ||
end | end | ||
function | -- For weird skills | ||
for | function inheritMissing(keyTable, inheritTable) | ||
local n = 1; -- counter for the func. argument loop | |||
local i; | |||
for k_key, v_key in spairs(keyTable) do | |||
if inArgs(inheritTable[n]) and not inArgs(v_key) then | |||
i = 1 | |||
for k, v in spairs(split(args.dmg)) do | |||
data[v_key .. i] = data[inheritTable[n] .. i] | |||
i = i + 1 | |||
end | |||
end | |||
n = n + 1 | |||
end | end | ||
end | end | ||
inheritMissing({'awk_dmg', 'pvp_awk_dmg', 'awk_hits', 'avg_awk_hits'}, {'dmg', 'pvp_dmg', 'hits', 'avg_hits'}) | |||
-- Laziness | |||
if args.hits and args.awk_dmg and not args.awk_hits then | |||
data.awk_hits = args.hits | |||
end | |||
if args.awk_dmg and args.avg_hits and not args.avg_awk_hits then | |||
data.avg_awk_hits = args.avg_hits | |||
end | end | ||
if args.awk_dmg and args.avg_hits_useful and not args.avg_awk_hits_useful then | |||
data.avg_awk_hits_useful = args.avg_hits_useful | |||
end | |||
-- | -- Handle trait table | ||
local | local traits = {} | ||
if inArgs('heavy') then | |||
traits.heavy = 1.44 | |||
end | |||
if inArgs('enhanced') then | |||
traits.enhanced = 0.8 | |||
end | end | ||
-- | -- Customizable for empowered, it had to be special lol. | ||
if inArgs('empowered') then | |||
if (args.empowered == 'true') then | |||
traits.empowered = 1.2 | |||
else | |||
traits.empowered = args.empowered | |||
end | |||
end | |||
if args.useful == 'true' then | |||
args.useful = 0.7 | |||
end | |||
if args.useful_penalty == 'true' then | |||
args.useful_penalty = 0.7 | |||
end | |||
-- Output passives if provided | |||
local passives = {} | |||
for i = 1, 3 do | |||
if inArgs('passive' .. i) then | |||
passives[i] = args['passive' .. i] | |||
passives[i] = split(frame:preprocess('{{:' .. passives[i] .. '}}{{#arrayprint:' .. passives[i] .. '}}')) | |||
end | end | ||
end | end | ||
-- | function list(ispvp) | ||
if | -- Define tables that hold the subsequent damage values. | ||
-- I know this isn't the best, but I don't want to work with nested tables in this language. | |||
local fvals = {} | |||
local tvals = {} | |||
local pvals = { | |||
[1] = {}, | |||
[2] = {}, | |||
[3] = {}, | |||
[12] = {}, | |||
[13] = {}, | |||
[23] = {}, | |||
[123] = {} | |||
} | |||
-- Check the specified mode and define the prefixes/suffixes first. | |||
local pr = '' | |||
local su = '' | |||
local p_index = 1 | |||
if ispvp then | |||
p_index = 2 | |||
end | end | ||
if | |||
if (ispvp) then | |||
pr = 'pvp_' | |||
su = '_pvp' | |||
end | end | ||
-- Define total/average damage calculation based on damage per hit and hit amount. | |||
function getTotal(dmg, hits, fval, count) | |||
-- Handle PvP prefixes/suffixes | |||
if | if inArgs(pr .. dmg) then | ||
dmg = pr .. dmg | |||
end | |||
if inArgs(pr .. hits) then | |||
hits = pr .. hits | |||
end | end | ||
if not | |||
if dmg == 'awk_dmg' and ispvp and not inArgs(pr .. 'awk_dmg') then | |||
dmg = pr .. 'dmg' | |||
end | end | ||
fval = fval .. su | |||
local i = 1 | |||
fvals[fval] = 0 | |||
for k, v in spairs(split(args.dmg)) do | |||
if -- If 'hits' defined, but 'avg_hits' not defined, inherit from 'hits'. | |||
(data[hits .. i] == nil and data['hits' .. i] ~= nil and hits == 'avg_hits') then | |||
data[hits .. i] = data['hits' .. i] | |||
elseif -- If 'hits' undefined, assume they're equal to 1. | |||
(data[hits .. i] == nil) then | |||
data[hits .. i] = 1 | |||
end | |||
-- Proceed to combine | |||
fvals[fval] = fvals[fval] + data[dmg .. i] * data[hits .. i] * (data[pr .. 'perm_buff' .. i] or data['perm_buff' .. i] or 1) | |||
i = i + 1 | |||
end | |||
-- For skills with multiple same parts, ex. Clementine, Enough Mineral | |||
if count == true then | |||
fvals[fval] = fvals[fval] * args.count | |||
if inArgs('count_extra' .. su) then | |||
if args.count_extra_hits == nil then | |||
args.count_extra_hits = 1 | |||
end | |||
if not string.find(fval, "each_") then | |||
fvals[fval] = fvals[fval] + (args['count_extra' .. su] * args['count_extra_hits']) | |||
end | end | ||
end | end | ||
end | |||
-- Apply Useful modifier. | |||
if string.find(fval, 'useful') then | |||
fvals[fval] = fvals[fval] * (args.useful_penalty or args.useful) | |||
end | end | ||
end | end | ||
-- Actually generate the values depending on arguments provided. | |||
if inArgs(pr .. 'dmg') then | |||
if (inArgs('count')) then | |||
getTotal('dmg', 'hits', 'each_damage') | |||
getTotal('dmg', 'hits', 'total_damage', true) | |||
else | |||
getTotal(pr .. 'dmg', 'hits', 'total_damage') | |||
end | |||
if inArgs('avg_hits') then | |||
getTotal('dmg', 'avg_hits', 'avg_damage') | |||
end | |||
end | |||
if inArgs(pr .. 'awk_dmg') or inArrayStarts(pr .. 'awk_dmg', data) then | |||
getTotal('awk_dmg', 'awk_hits', 'total_damage_awk') | |||
if (inArgs('avg_hits') and (inArgs('awk_dmg') or inArgs('awk_hits'))) or inArgs('avg_awk_hits') then | |||
getTotal('awk_dmg', 'avg_awk_hits', 'avg_damage_awk') | |||
end | |||
end | end | ||
-- Handling traits | |||
-- Useful handled separately | |||
if inArgs('useful_penalty') or inArgs('useful') then | |||
getTotal(pr .. 'dmg', 'hits_useful', 'total_damage_useful') | |||
if inArgs('avg_hits_useful') then | |||
getTotal('dmg', 'avg_hits_useful', 'avg_damage_useful') | |||
end | |||
if inArgs(pr .. 'awk_dmg') and inArgs('awk_hits_useful') then | |||
getTotal('awk_dmg', 'awk_hits_useful', 'total_damage_awk_useful') | |||
end | |||
if inArgs(pr .. 'avg_awk_hits') and inArgs('avg_awk_hits_useful') then | |||
getTotal('awk_dmg', 'avg_awk_hits_useful', 'avg_damage_awk_useful') | |||
end | |||
end | |||
-- Multiply all values with traits and store them in another table. | |||
if | for k, v in spairs(fvals) do | ||
if not string.find(k, 'useful') then | |||
for kt, vt in spairs(traits) do | |||
if inArgs(kt) then | |||
local dmg_name = k .. '_' .. kt | |||
if ispvp then | |||
dmg_name = dmg_name:gsub(su, '') .. su | |||
end | |||
local dmg_formula = v * vt | |||
tvals[dmg_name] = dmg_formula | |||
end | end | ||
end | |||
end | |||
end | |||
-- Get a table of merged base & trait values | |||
local ftvals = fvals | |||
tableMerge(ftvals, tvals) | |||
function addPassive(num, loop_table) | |||
local pval_index | |||
if loop_table == nil then | |||
pval_index = num | |||
loop_table = ftvals | |||
else | |||
pval_index = tonumber(loop_table .. num) | |||
loop_table = pvals[loop_table] | |||
end | |||
for k, v in spairs(loop_table) do | |||
local dmg_name = k .. '_passive' .. num | |||
if ispvp then | |||
dmg_name = dmg_name:gsub(su, '') .. su | |||
end | end | ||
local dmg_formula = v * passives[num][p_index] | |||
pvals[pval_index][dmg_name] = dmg_formula | |||
end | |||
end | |||
-- Add passives and combine them. | |||
if inArgs('passive2') then | |||
addPassive(2) | |||
if inArgs('passive3') then | |||
addPassive(3, 2) | |||
end | end | ||
end | end | ||
if inArgs('passive1') then | |||
addPassive(1) | |||
if inArgs('passive2') then | |||
addPassive(2, 1) | |||
if inArgs('passive3') then | |||
addPassive(3, 12) | |||
end | end | ||
end | |||
if inArgs('passive3') then | |||
addPassive(3, 1) | |||
end | end | ||
end | end | ||
if inArgs('passive3') then | |||
addPassive(3) | |||
end | |||
-- Merge all tables into one. | |||
tableMerge(fvals, tvals) | |||
for k, v in spairs(pvals) do | |||
for | tableMerge(fvals, v) | ||
end | |||
return fvals | |||
end | |||
local out = list(false) | |||
local out_pvp = list(true) | |||
-- Merge the output to a unified table. | |||
tableMerge(out, out_pvp) | |||
-- Function wrapper for vardefine syntax in MW. | |||
function var(name, dmg, prefix) | |||
if prefix == nil then | |||
prefix = '' | |||
else | |||
prefix = prefix .. '_' | |||
end | |||
if dmg == 0 then | |||
dmg = 'N/A' | |||
else | |||
dmg = round(dmg) | |||
end | |||
if (args.format == 'false' or dmg == 'N/A') then | |||
return '{{#vardefine:' .. prefix .. name .. '|' .. dmg .. '}}' | |||
else | |||
return '{{#vardefine:' .. prefix .. name .. '|{{formatnum:' .. dmg .. '}}%}}' | |||
end | |||
end | |||
-- Apply ranges. | |||
function getRangeCount(arg) | |||
if inArgs(arg) then | |||
data[arg] = split(args[arg]) | |||
if data[arg][2] == nil then | |||
data[arg][2] = data[arg][1] | |||
end | end | ||
end | end | ||
end | end | ||
getRangeCount('range_min_count'); | |||
getRangeCount('range_max_count') | |||
function determineRange(minmax) | |||
function | if inArgs('range_' .. minmax) then | ||
data['range_' .. minmax] = split(args['range_' .. minmax]) | |||
if data['range_' .. minmax][2] == nil then | |||
data['range_' .. minmax][2] = data['range_' .. minmax][1] | |||
if | end | ||
if inArgs('range_' .. minmax .. '_count') then | |||
local i = 1; | |||
for k, v in spairs(data['range_' .. minmax]) do | |||
data['range_' .. minmax][i] = 1 + (-1 + data['range_' .. minmax][i]) * | |||
data['range_' .. minmax .. '_count'][i] | |||
i = i + 1 | |||
end | end | ||
end | end | ||
end | end | ||
end | end | ||
determineRange('min'); | |||
determineRange('max'); | |||
-- If maximum range is specified, but not minimum, and minimum count is specified. | |||
-- By default, it would just do the same as with max, don't want that. | |||
if inArgs('range_max') and not inArgs('range_min') then | |||
data['range_min'] = {1, 1} | |||
if inArgs('range_min_count') then | |||
local range_max_arg = split(args.range_max); | |||
if range_max_arg[2] == nil then | |||
range_max_arg[2] = range_max_arg[1] | |||
end | end | ||
data['range_min'] = {1 + range_max_arg[1] * data['range_min_count'][1], | |||
1 + range_max_arg[2] * data['range_min_count'][2]} | |||
end | end | ||
end | end | ||
local out_min = {} | |||
local out_max = {} | |||
function applyRange(minmax) | |||
function | local temp_tab = {}; | ||
if minmax == 'min' then | |||
for | temp_tab = out_min | ||
else | |||
temp_tab = out_max | |||
if | end | ||
if inArgs('range_max') then | |||
for k, v in spairs(out) do | |||
if not (string.starts(k, 'min_') or string.starts(k, 'max_')) then | |||
if (string.find(k, '_pvp')) then | |||
temp_tab[minmax .. '_' .. k] = v * data['range_' .. minmax][2]; | |||
else | |||
temp_tab[minmax .. '_' .. k] = v * data['range_' .. minmax][1]; | |||
end | end | ||
end | end | ||
end | end | ||
end | end | ||
tableMerge(out, temp_tab) | |||
end | end | ||
applyRange('min'); | |||
applyRange('max'); | |||
-- Get the actual variables with MW syntax. | |||
local vars = {} | |||
for k, v in spairs(out) do | |||
table.insert(vars, var(k, v, args.prefix)) | |||
end | end | ||
local | -- Transform ranges to variables. | ||
local vars_range = {} | |||
if (inArgs('range_max')) then | |||
for | for k, v in spairs(out) do | ||
if not (string.starts(k, 'min_') or string.starts(k, 'max_')) then | |||
local prefix = '' | |||
if args.prefix ~= nil then | |||
prefix = args.prefix .. '_' | |||
end | end | ||
table.insert(vars_range, | |||
'{{#vardefine: ' .. prefix .. 'range_' .. k .. '|{{formatnum:' .. round(out_min['min_' .. k]) .. | |||
'}}% ~ {{formatnum:' .. round(out_max['max_' .. k]) .. '}}%}}'); | |||
end | end | ||
end | end | ||
indexTableMerge(vars, vars_range); | |||
end | |||
-- Dump all values if wanted. | |||
if args.dump == 'true' then | |||
local ret = {} | |||
for k, v in spairs(out) do | |||
table.insert(ret, k .. ': ' .. v) | |||
end | |||
return frame:preprocess(table.concat(ret, "<br/>")) | |||
end | end | ||
-- Parse all variables | |||
local parsed = frame:preprocess('{{ ' .. table.concat(vars) .. 'trim2}}') | |||
local | if args[1] ~= 'true' and args.table ~= 'true' then | ||
return parsed | |||
end | |||
local char = args.char or args[2] or 'Elsword' | |||
-- Generate the table | |||
local tbl = mw.html.create('table'):attr({ | |||
['cellpadding'] = 5, | |||
['border'] = 1, | |||
['style'] = 'border-collapse: collapse; text-align: center', | |||
['class'] = 'colortable-' .. char | |||
}) | |||
-- For rowspan, colspan shenanigans | |||
function increaseSpace(el, type, num) | |||
if type == 'row' then | |||
type = 'rowspan' | |||
elseif type == 'col' then | |||
type = 'colspan' | |||
end | |||
num = num or 1 | |||
return el:attr(type, tonumber(el:getAttr(type) or 1) + num) | |||
end | |||
function multiplySpace(el, type, m) | |||
if not el then | |||
return false | |||
end | |||
if type == 'row' then | |||
type = 'rowspan' | |||
else | |||
type = 'colspan' | |||
end | |||
if m == nil then | |||
m = 2 | |||
end | end | ||
local span = el:getAttr(type) or 1 | |||
return el:attr(type, tonumber(span) * m) | |||
end | end | ||
local combine = split(args.combine) | |||
local combine_suffix = args.combine_suffix | |||
local append = split(args.append)[1] | |||
local append_alias = split(args.append)[2] | |||
local tbl_order = {'extra', 'passives_normal', 'passives_switch', 'awk', 'traits', 'hit_count'} | |||
local STR = { | |||
BASE = 'Base', | |||
MODE = 'Mode', | |||
REGULAR = 'Regular', | |||
NORMAL = 'Normal', | |||
AWK = 'Awakening Mode', | |||
AVG = 'Average', | |||
MAX = 'Max', | |||
TRAIT = {'Enhanced', 'Empowered', 'Useful', 'Heavy'}, | |||
PER = 'Per', | |||
INSTANCE = 'Instance' | |||
} | |||
local trait_args = {} | |||
for k, v in ipairs(STR.TRAIT) do | |||
table.insert(trait_args, string.lower(v)) | |||
end | |||
local trait_count = 0 | |||
for k, v in ipairs(trait_args) do | |||
if inArrayHas(v, out) then | |||
trait_count = trait_count + 1 | |||
end | |||
end | |||
local | local tbl_content = { | ||
extra = { | |||
mode = STR.MODE, | |||
long = STR.AVG | |||
}, | |||
passives_normal = { | |||
mode = STR.MODE, | |||
base = STR.BASE, | |||
combined = {}, | |||
aliases = {args.alias1 or false, args.alias2 or false, args.alias3 or false}, | |||
suffixes = {args.suffix1 or false, args.suffix2 or false, args.suffix3 or false} | |||
}, | }, | ||
passives_switch = { | |||
normal = STR.NORMAL, | |||
hide = true | |||
}, | |||
awk = { | |||
normal = STR.REGULAR, | |||
awk_link = '[[' .. STR.AWK .. ']]', | |||
hide = true | |||
}, | |||
traits = { | |||
normal = STR.NORMAL, | |||
hide = true | |||
}, | |||
hit_count = { | |||
avg = STR.AVG, | |||
max = STR.MAX, | |||
hide = true | |||
} | } | ||
} | } | ||
local | local count_name = args.count_name or STR.INSTANCE | ||
if inArgs('count') and not args.use_avg then | |||
tbl_content.hit_count.avg = table.concat({STR.PER, count_name}, ' ') | |||
end | |||
function getRowIndex(row) | |||
for k, v in ipairs(tbl_order) do | |||
if row == v then | |||
return k | |||
end | end | ||
end | end | ||
end | end | ||
for passive_i = 1, 3 do | |||
repeat | |||
-- Add normal passives to the first row. | |||
local passive_name = '' | |||
-- Alias for appended passives. | |||
if (inArgs('passive' .. passive_i)) then | |||
passive_name = args['passive' .. passive_i] | |||
end | |||
if indexOf(tostring(passive_i), combine) ~= nil then | |||
-- Add combined passives. | |||
tbl_content.passives_normal.combined[passive_i] = passive_name | |||
elseif tostring(passive_i) == append then | |||
-- Add switch passives. | |||
tbl_content.passives_switch[passive_i] = passive_name | |||
tbl_content.passives_switch.hide = false | |||
if append_alias ~= nil then | |||
tbl_content.passives_switch.display_name = append_alias | |||
end | |||
elseif (inArgs('passive' .. passive_i)) then | |||
-- Add regular passives to the first row. | |||
tbl_content.passives_normal[passive_i] = passive_name | |||
end | |||
until true | |||
end | |||
local | local ret = '' | ||
-- | for trait_order, trait_arg in ipairs(trait_args) do | ||
-- Add traits if exist. | |||
if (inArgs(trait_arg)) then | |||
tbl_content.traits[trait_arg] = args[trait_arg] | |||
tbl_content.traits.hide = false | |||
end | end | ||
end | |||
-- Add Useful trait. | |||
if inArgs('hits_useful') or inArgs('avg_hits_useful') then | |||
tbl_content.traits.useful = 'true' | |||
tbl_content.traits.hide = false | |||
end | |||
if inArgs('avg_hits') or inArgs('count') then | |||
-- Enable average/max if needed. | |||
tbl_content.hit_count.hide = false | |||
end | |||
if inArrayHas('awk_', args) then | |||
-- Enable Awakening if needed. | |||
tbl_content.awk.hide = false | |||
end | |||
local loop_factor, mode_th; | |||
local cells = {} | |||
local passive_normal_count = 0; | |||
local passive_switch_count = 0; | |||
function hidden(level) | |||
return tbl_content[level].hide | |||
return | |||
end | end | ||
local hit_count_table = {'total'} | |||
local awk_table = {''} | |||
local levels_exist = | |||
(next(passives) or args.append or args.awk_hits or args.awk_dmg or args.count) | |||
local no_max = args.no_max == 'true' | |||
function makePassiveLink(passive, alias, suffix, nil_cond) | |||
if | if nil_cond == nil then | ||
nil_cond = true | |||
end | end | ||
if nil_cond and alias ~= nil and alias ~= false then | |||
alias = '|' .. alias | |||
else | |||
alias = '' | |||
end | |||
suffix = suffix or '' | |||
passive = '[[' .. passive .. alias .. ']]' .. suffix | |||
return passive | |||
end | |||
-- Begin the main loop. | |||
for k, type in ipairs(tbl_order) do | |||
repeat | |||
local tr = tbl:tag('tr') | |||
local data = tbl_content[type]; | |||
local hide = data.hide; | |||
cells[type] = {} | |||
function new(wikitext, normal) | |||
local th = tr:tag('th'):wikitext(wikitext) | |||
if type | if normal == true then | ||
table.insert(cells[type].normal_th, th) | |||
elseif normal == false then | |||
table.insert(cells[type].th, th) | |||
else | else | ||
return | return th | ||
end | end | ||
end | end | ||
function multiplySpaceAll(level, num) | |||
if cells[level] == nil then | |||
return false | |||
end | end | ||
num = num or 2 | |||
for k, v in ipairs(cells[level].th) do | |||
multiplySpace(v, 'col', num) | |||
end | end | ||
for k, v in ipairs(cells[level].normal_th) do | |||
multiplySpace(v, 'col', num) | |||
end | end | ||
end | |||
end | |||
function reverseMultiplySpace(num, increase_mode) | |||
local i = #tbl_order; | |||
num = num or 2 | |||
local fix_for_no_max = 0 | |||
if no_max and not levels_exist then | |||
fix_for_no_max = -1 | |||
end | end | ||
while (i > 1) do | |||
multiplySpaceAll(tbl_order[i - 1 + fix_for_no_max], num) | |||
i = i - 1 | |||
end | end | ||
if increase_mode ~= false then | |||
increaseSpace(mode_th, 'row') | |||
end | end | ||
end | |||
end | |||
cells[type].normal_th = {} | |||
cells[type].th = {} | |||
if (type == 'extra' and no_max) then | |||
mode_th = new(data.mode) | |||
new(data.long, true) | |||
end | |||
if (type == 'passives_normal') then | |||
if not no_max then | |||
mode_th = new(data.mode) | |||
else | |||
reverseMultiplySpace(nil, false); | |||
end | |||
if (no_max and levels_exist) or not no_max then | |||
new(data.base, true) | |||
end | |||
for i = 1, 3, 1 do | |||
local passive_link = data[i] | |||
if (passive_link ~= nil) then | |||
local suffix = '' | |||
if | if next(data.suffixes) and data.suffixes[i] ~= false then | ||
suffix = ' ' .. data.suffixes[i] | |||
end | end | ||
passive_link = makePassiveLink(passive_link, data.aliases[i], suffix, next(data.aliases)) | |||
new(passive_link, false) | |||
passive_normal_count = passive_normal_count + 1 | |||
end | end | ||
end | |||
for | -- Handle combining passives. | ||
if next(data.combined) then | |||
local combined_str = '' | |||
for k, v in spairs(data.combined) do | |||
combined_str = combined_str .. makePassiveLink(v, data.aliases[k], data.suffixes[k]) .. '/' | |||
end | |||
combined_str = combined_str:gsub('/$', '') | |||
if combine_suffix then | |||
combined_str = combined_str .. ' ' .. combine_suffix | |||
end | |||
new(combined_str, false) | |||
passive_normal_count = passive_normal_count + 1 | |||
end | |||
end | |||
if (type == 'passives_switch') then | |||
if not hidden(type) then | |||
multiplySpaceAll('passives_normal') | |||
-- For some reason, whenever appending is active, it misses a 1 in rowspan of this cell. | |||
increaseSpace(mode_th, 'row') | |||
end | |||
-- Passives that appear in the second row | |||
loop_factor = (passive_normal_count + 1) | |||
for ix = 1, loop_factor, 1 do | |||
for i = 1, 3, 1 do | |||
if (data[i] ~= nil) then | |||
new(data.normal, true); | |||
local suffix = '' | |||
if next(tbl_content.passives_normal.suffixes) and tbl_content.passives_normal.suffixes[i] ~= false then | |||
suffix = ' ' .. tbl_content.passives_normal.suffixes[i] | |||
end | end | ||
local passive_link = data[i] | |||
passive_link = makePassiveLink(passive_link, data.display_name, suffix) | |||
new(passive_link, false) | |||
if (ix == 1) then | |||
-- Count switch passives. Only one iteration. | |||
passive_switch_count = passive_switch_count + 1 | |||
end | |||
end | end | ||
end | end | ||
end | end | ||
end | |||
if (type == 'awk' and not hide) then | |||
reverseMultiplySpace(); | |||
table.insert(awk_table, 'awk') | |||
loop_factor = loop_factor * (passive_switch_count + 1) | |||
for i = 1, loop_factor, 1 do | |||
new(data.normal, true) | |||
new(data.awk_link, false) | |||
end | end | ||
end | end | ||
if (type == 'traits' and not hide) then | |||
if trait_count == 2 then | |||
reverseMultiplySpace(3); | |||
if | |||
else | else | ||
reverseMultiplySpace(); | |||
end | |||
-- Manually fix certain situations. | |||
local has_awk = 1 | |||
if not hidden('awk') then | |||
has_awk = 2 | |||
end | end | ||
local extra = 1 | |||
if hidden('awk') and not hidden('passives_switch') then | |||
extra = 2 | |||
end | |||
loop_factor = loop_factor * has_awk | |||
for i = 1, loop_factor * extra, 1 do | |||
local ix = 1 | |||
new(data.normal, true) | |||
for k, trait_name in ipairs(trait_args) do | |||
if data[trait_name] ~= nil then | |||
new(STR.TRAIT[ix], false) | |||
end | |||
ix = ix + 1 | |||
end | |||
end | |||
end | |||
if (type == 'hit_count' and not hide) then | |||
if no_max and levels_exist then | |||
increaseSpace(mode_th, 'row') | |||
elseif levels_exist or (args.avg_hits and args.hits) then | |||
reverseMultiplySpace(); | |||
else | |||
reverseMultiplySpace(nil, false); | |||
end | |||
local avg_or_each = 'avg' | |||
if inArgs('count') and not args.use_avg then | |||
avg_or_each = 'each' | |||
end | |||
table.insert(hit_count_table, 1, avg_or_each) | |||
-- Some things are breaking here, so I needed to implement conditional patches. | |||
if hidden('awk') then | |||
loop_factor = loop_factor * (passive_switch_count + 1) | |||
end | |||
if hidden('passives_switch') then | |||
if | loop_factor = passive_normal_count + 1 | ||
end | end | ||
if (hidden('traits') and not hidden('awk')) or (not hidden('awk') and hidden('passives_switch')) then | |||
loop_factor = loop_factor * 2 | |||
end | end | ||
loop_factor = loop_factor * (trait_count + 1) | |||
for i = 1, | |||
if not no_max then | |||
for i = 1, loop_factor, 1 do | |||
new(data.avg, true) | |||
new(data.max, false) | |||
end | end | ||
end | end | ||
end | end | ||
end | |||
until true | |||
end | |||
if no_max and args.avg_hits then | |||
hit_count_table[2] = nil | |||
end | end | ||
function concat(tbl) | |||
local returned_str = '' | |||
for k, v in ipairs(tbl) do | |||
local delimiter = '_' | |||
if returned_str == '' then | |||
delimiter = '' | |||
end | |||
if v ~= '' then | |||
returned_str = returned_str .. delimiter .. v | |||
end | |||
end | end | ||
return | return returned_str | ||
end | end | ||
function | function makeValueRows(mode_flag) | ||
local | local mode_cell = 'PvE' | ||
if mode_flag == true then | |||
mode_flag = '_pvp' | |||
mode_cell = 'PvP' | |||
else | |||
mode_flag = '' | |||
end | |||
local value_row = tbl:tag('tr') | |||
function display(name, range_flag) | |||
local range_factor; | |||
local cell_content = {} | |||
if range_flag == true then | |||
range_factor = 2 | |||
else | |||
range_factor = 1 | |||
end | |||
for i = 1, range_factor, 1 do | |||
local range_prefix = ''; | |||
if range_flag == true then | |||
if i == 1 then | |||
range_prefix = 'min_' | |||
else | |||
range_prefix = 'max_' | |||
end | |||
end | |||
local value = out[range_prefix .. name]; | |||
if (value ~= nil) then | |||
if (args.dump_names == 'true') then | |||
table.insert(cell_content, name) | |||
elseif value ~= 0 then | |||
table.insert(cell_content, formatnum(math.round(value, 2)) .. '%') | |||
else | |||
table.insert(cell_content, 'N/A') | |||
end | |||
end | end | ||
end | |||
if next(cell_content) then | |||
return value_row:tag('td'):wikitext(table.concat(cell_content, '<span style="white-space:nowrap"> ~</span> ')); | |||
else | else | ||
if args.dump_names == 'true' then | |||
return value_row:tag('td'):wikitext(name) | |||
end | |||
return value_row:tag('td'):wikitext(frame:expandTemplate{ | |||
title = 'color', | |||
args = {'red', '#ERROR'} | |||
}) | |||
end | |||
end | |||
local ret2 = '' | |||
value_row:tag('td'):wikitext(frame:expandTemplate{ | |||
title = mode_cell | |||
}) | |||
for passive_normal_i = 0, 3, 1 do | |||
local combine_now = tostring(passive_normal_i) == combine[1] | |||
if tbl_content.passives_normal[passive_normal_i] or combine_now or passive_normal_i == 0 then | |||
local passive_normal_str = 'passive' .. passive_normal_i | |||
if combine_now then | |||
for k, v in ipairs(combine) do | |||
if k ~= 1 then | |||
passive_normal_str = passive_normal_str .. '_passive' .. v | |||
end | |||
end | |||
end | |||
if passive_normal_i == 0 then | |||
passive_normal_str = '' | |||
end | |||
for passive_switch_i = 0, 3, 1 do | |||
local current_switch = tbl_content.passives_switch[passive_switch_i] | |||
if current_switch or passive_switch_i == 0 then | |||
local passive_switch_str = 'passive' .. passive_switch_i | |||
if passive_switch_i == 0 then | |||
passive_switch_str = '' | |||
end | |||
for _, awk_str in ipairs(awk_table) do | |||
for trait_i = 0, #trait_args do | |||
repeat | |||
for hit_i, hit_v in ipairs(hit_count_table) do | |||
local trait_str = trait_args[trait_i] or '' | |||
local str_tbl = {'damage'} | |||
local passive_tbl = {} | |||
table.insert(str_tbl, awk_str) | |||
if tbl_content.traits[trait_str] then | |||
table.insert(str_tbl, trait_str) | |||
elseif trait_i > 0 then | |||
do | |||
break | |||
end | |||
end | |||
table.insert(str_tbl, 1, hit_v) | |||
table.insert(passive_tbl, passive_switch_str) | |||
table.insert(passive_tbl, passive_normal_str) | |||
table.sort(passive_tbl) | |||
for k, v in ipairs(passive_tbl) do | |||
table.insert(str_tbl, v) | |||
end | |||
if inArgs('range_max') then | |||
display(concat(str_tbl) .. mode_flag, true) | |||
else | |||
display(concat(str_tbl) .. mode_flag) | |||
end | |||
end | |||
until true | |||
end | |||
end | |||
end | |||
end | |||
end | end | ||
end | end | ||
end | end | ||
-- For debugging purposes | |||
if (args.debug == 'true') then | |||
ret = '' | |||
for i = 1, #tbl_order, 1 do | |||
ret = ret .. "'''" .. tbl_order[i] .. "''': <br/>" | |||
for k2, v2 in pairs(tbl_content[tbl_order[i]]) do | |||
if (v2 == true) then | |||
v2 = 'true' | |||
end | |||
local output = tostring(v2) | |||
if (type(v2) == 'table') then | |||
output = '' | |||
output = output .. '<br/>--<br/>' | |||
for k3, v3 in pairs(v2) do | |||
output = output .. k3 .. ': ' .. tostring(v3) .. '<br/>' | |||
end | |||
output = output .. '--' | |||
end | |||
ret = ret .. k2 .. ': ' .. output .. '<br/>' | |||
end | |||
ret = ret .. '<br/>' | |||
end | |||
return ret | |||
end | end | ||
makeValueRows(); | |||
makeValueRows(true); | |||
local bug = '' | local bug = '' | ||
if | if args.bug == 'true' then | ||
bug = frame:expandTemplate { | bug = frame:expandTemplate{ | ||
title = 'SkillText', | title = 'SkillText', | ||
args = { 'FreeTraining' } | args = {'FreeTraining'} | ||
} | } | ||
end | end | ||
return parsed .. bug .. tostring(tbl) | |||
end | end | ||
return p | return p | ||
-- pyend | -- pyend |
Revision as of 23:34, 4 January 2024
Documentation for this module may be created at Module:Damage/doc
-- pystart
require('Module:CommonFunctions');
local getArgs = require('Module:Arguments').getArgs
local p = {}
-- Main process
function p.main(frame)
local args = getArgs(frame)
function inArgs(key)
if args[key] ~= nil then
return true
end
end
-- Collect data from the input
local data = {}
local data_types = {
'dmg',
'awk_dmg',
'hits',
'avg_hits',
'awk_hits',
'avg_awk_hits',
'hits_useful',
'avg_hits_useful',
'awk_hits_useful',
'avg_awk_hits_useful',
'perm_buff'
}
-- Handle the PvP split values
for k, v in spairs(data_types) do
table.insert(data_types, 'pvp_' .. v)
end
for k, v in spairs(data_types) do
local i = 1
if inArgs(v) then
for k2, v2 in spairs(split(args[v])) do
-- Check for operators. If detected, evaluate.
if string.find(v2, '*') or string.find(v2, '+') then
v2 = frame:preprocess('{{#expr:' .. v2 .. '}}')
end
-- Check if proper hit count values provided. If empty string detected, inherit from 'hits'.
if string.find(v, 'avg_') and string.find(v, '_hits') and v2 == '' then
data[v .. i] = data['avg_hits' .. i]
elseif string.find(v, 'hits') and v2 == '' then
data[v .. i] = data['hits' .. i]
elseif string.find(v, 'awk_dmg') and v2 == '' then
if string.find(v, 'pvp') then
data[v .. i] = data['pvp_dmg' .. i]
else
data[v .. i] = data['dmg' .. i]
end
else
data[v .. i] = v2
end
i = i + 1
end
end
end
-- For weird skills
function inheritMissing(keyTable, inheritTable)
local n = 1; -- counter for the func. argument loop
local i;
for k_key, v_key in spairs(keyTable) do
if inArgs(inheritTable[n]) and not inArgs(v_key) then
i = 1
for k, v in spairs(split(args.dmg)) do
data[v_key .. i] = data[inheritTable[n] .. i]
i = i + 1
end
end
n = n + 1
end
end
inheritMissing({'awk_dmg', 'pvp_awk_dmg', 'awk_hits', 'avg_awk_hits'}, {'dmg', 'pvp_dmg', 'hits', 'avg_hits'})
-- Laziness
if args.hits and args.awk_dmg and not args.awk_hits then
data.awk_hits = args.hits
end
if args.awk_dmg and args.avg_hits and not args.avg_awk_hits then
data.avg_awk_hits = args.avg_hits
end
if args.awk_dmg and args.avg_hits_useful and not args.avg_awk_hits_useful then
data.avg_awk_hits_useful = args.avg_hits_useful
end
-- Handle trait table
local traits = {}
if inArgs('heavy') then
traits.heavy = 1.44
end
if inArgs('enhanced') then
traits.enhanced = 0.8
end
-- Customizable for empowered, it had to be special lol.
if inArgs('empowered') then
if (args.empowered == 'true') then
traits.empowered = 1.2
else
traits.empowered = args.empowered
end
end
if args.useful == 'true' then
args.useful = 0.7
end
if args.useful_penalty == 'true' then
args.useful_penalty = 0.7
end
-- Output passives if provided
local passives = {}
for i = 1, 3 do
if inArgs('passive' .. i) then
passives[i] = args['passive' .. i]
passives[i] = split(frame:preprocess('{{:' .. passives[i] .. '}}{{#arrayprint:' .. passives[i] .. '}}'))
end
end
function list(ispvp)
-- Define tables that hold the subsequent damage values.
-- I know this isn't the best, but I don't want to work with nested tables in this language.
local fvals = {}
local tvals = {}
local pvals = {
[1] = {},
[2] = {},
[3] = {},
[12] = {},
[13] = {},
[23] = {},
[123] = {}
}
-- Check the specified mode and define the prefixes/suffixes first.
local pr = ''
local su = ''
local p_index = 1
if ispvp then
p_index = 2
end
if (ispvp) then
pr = 'pvp_'
su = '_pvp'
end
-- Define total/average damage calculation based on damage per hit and hit amount.
function getTotal(dmg, hits, fval, count)
-- Handle PvP prefixes/suffixes
if inArgs(pr .. dmg) then
dmg = pr .. dmg
end
if inArgs(pr .. hits) then
hits = pr .. hits
end
if dmg == 'awk_dmg' and ispvp and not inArgs(pr .. 'awk_dmg') then
dmg = pr .. 'dmg'
end
fval = fval .. su
local i = 1
fvals[fval] = 0
for k, v in spairs(split(args.dmg)) do
if -- If 'hits' defined, but 'avg_hits' not defined, inherit from 'hits'.
(data[hits .. i] == nil and data['hits' .. i] ~= nil and hits == 'avg_hits') then
data[hits .. i] = data['hits' .. i]
elseif -- If 'hits' undefined, assume they're equal to 1.
(data[hits .. i] == nil) then
data[hits .. i] = 1
end
-- Proceed to combine
fvals[fval] = fvals[fval] + data[dmg .. i] * data[hits .. i] * (data[pr .. 'perm_buff' .. i] or data['perm_buff' .. i] or 1)
i = i + 1
end
-- For skills with multiple same parts, ex. Clementine, Enough Mineral
if count == true then
fvals[fval] = fvals[fval] * args.count
if inArgs('count_extra' .. su) then
if args.count_extra_hits == nil then
args.count_extra_hits = 1
end
if not string.find(fval, "each_") then
fvals[fval] = fvals[fval] + (args['count_extra' .. su] * args['count_extra_hits'])
end
end
end
-- Apply Useful modifier.
if string.find(fval, 'useful') then
fvals[fval] = fvals[fval] * (args.useful_penalty or args.useful)
end
end
-- Actually generate the values depending on arguments provided.
if inArgs(pr .. 'dmg') then
if (inArgs('count')) then
getTotal('dmg', 'hits', 'each_damage')
getTotal('dmg', 'hits', 'total_damage', true)
else
getTotal(pr .. 'dmg', 'hits', 'total_damage')
end
if inArgs('avg_hits') then
getTotal('dmg', 'avg_hits', 'avg_damage')
end
end
if inArgs(pr .. 'awk_dmg') or inArrayStarts(pr .. 'awk_dmg', data) then
getTotal('awk_dmg', 'awk_hits', 'total_damage_awk')
if (inArgs('avg_hits') and (inArgs('awk_dmg') or inArgs('awk_hits'))) or inArgs('avg_awk_hits') then
getTotal('awk_dmg', 'avg_awk_hits', 'avg_damage_awk')
end
end
-- Handling traits
-- Useful handled separately
if inArgs('useful_penalty') or inArgs('useful') then
getTotal(pr .. 'dmg', 'hits_useful', 'total_damage_useful')
if inArgs('avg_hits_useful') then
getTotal('dmg', 'avg_hits_useful', 'avg_damage_useful')
end
if inArgs(pr .. 'awk_dmg') and inArgs('awk_hits_useful') then
getTotal('awk_dmg', 'awk_hits_useful', 'total_damage_awk_useful')
end
if inArgs(pr .. 'avg_awk_hits') and inArgs('avg_awk_hits_useful') then
getTotal('awk_dmg', 'avg_awk_hits_useful', 'avg_damage_awk_useful')
end
end
-- Multiply all values with traits and store them in another table.
for k, v in spairs(fvals) do
if not string.find(k, 'useful') then
for kt, vt in spairs(traits) do
if inArgs(kt) then
local dmg_name = k .. '_' .. kt
if ispvp then
dmg_name = dmg_name:gsub(su, '') .. su
end
local dmg_formula = v * vt
tvals[dmg_name] = dmg_formula
end
end
end
end
-- Get a table of merged base & trait values
local ftvals = fvals
tableMerge(ftvals, tvals)
function addPassive(num, loop_table)
local pval_index
if loop_table == nil then
pval_index = num
loop_table = ftvals
else
pval_index = tonumber(loop_table .. num)
loop_table = pvals[loop_table]
end
for k, v in spairs(loop_table) do
local dmg_name = k .. '_passive' .. num
if ispvp then
dmg_name = dmg_name:gsub(su, '') .. su
end
local dmg_formula = v * passives[num][p_index]
pvals[pval_index][dmg_name] = dmg_formula
end
end
-- Add passives and combine them.
if inArgs('passive2') then
addPassive(2)
if inArgs('passive3') then
addPassive(3, 2)
end
end
if inArgs('passive1') then
addPassive(1)
if inArgs('passive2') then
addPassive(2, 1)
if inArgs('passive3') then
addPassive(3, 12)
end
end
if inArgs('passive3') then
addPassive(3, 1)
end
end
if inArgs('passive3') then
addPassive(3)
end
-- Merge all tables into one.
tableMerge(fvals, tvals)
for k, v in spairs(pvals) do
tableMerge(fvals, v)
end
return fvals
end
local out = list(false)
local out_pvp = list(true)
-- Merge the output to a unified table.
tableMerge(out, out_pvp)
-- Function wrapper for vardefine syntax in MW.
function var(name, dmg, prefix)
if prefix == nil then
prefix = ''
else
prefix = prefix .. '_'
end
if dmg == 0 then
dmg = 'N/A'
else
dmg = round(dmg)
end
if (args.format == 'false' or dmg == 'N/A') then
return '{{#vardefine:' .. prefix .. name .. '|' .. dmg .. '}}'
else
return '{{#vardefine:' .. prefix .. name .. '|{{formatnum:' .. dmg .. '}}%}}'
end
end
-- Apply ranges.
function getRangeCount(arg)
if inArgs(arg) then
data[arg] = split(args[arg])
if data[arg][2] == nil then
data[arg][2] = data[arg][1]
end
end
end
getRangeCount('range_min_count');
getRangeCount('range_max_count')
function determineRange(minmax)
if inArgs('range_' .. minmax) then
data['range_' .. minmax] = split(args['range_' .. minmax])
if data['range_' .. minmax][2] == nil then
data['range_' .. minmax][2] = data['range_' .. minmax][1]
end
if inArgs('range_' .. minmax .. '_count') then
local i = 1;
for k, v in spairs(data['range_' .. minmax]) do
data['range_' .. minmax][i] = 1 + (-1 + data['range_' .. minmax][i]) *
data['range_' .. minmax .. '_count'][i]
i = i + 1
end
end
end
end
determineRange('min');
determineRange('max');
-- If maximum range is specified, but not minimum, and minimum count is specified.
-- By default, it would just do the same as with max, don't want that.
if inArgs('range_max') and not inArgs('range_min') then
data['range_min'] = {1, 1}
if inArgs('range_min_count') then
local range_max_arg = split(args.range_max);
if range_max_arg[2] == nil then
range_max_arg[2] = range_max_arg[1]
end
data['range_min'] = {1 + range_max_arg[1] * data['range_min_count'][1],
1 + range_max_arg[2] * data['range_min_count'][2]}
end
end
local out_min = {}
local out_max = {}
function applyRange(minmax)
local temp_tab = {};
if minmax == 'min' then
temp_tab = out_min
else
temp_tab = out_max
end
if inArgs('range_max') then
for k, v in spairs(out) do
if not (string.starts(k, 'min_') or string.starts(k, 'max_')) then
if (string.find(k, '_pvp')) then
temp_tab[minmax .. '_' .. k] = v * data['range_' .. minmax][2];
else
temp_tab[minmax .. '_' .. k] = v * data['range_' .. minmax][1];
end
end
end
end
tableMerge(out, temp_tab)
end
applyRange('min');
applyRange('max');
-- Get the actual variables with MW syntax.
local vars = {}
for k, v in spairs(out) do
table.insert(vars, var(k, v, args.prefix))
end
-- Transform ranges to variables.
local vars_range = {}
if (inArgs('range_max')) then
for k, v in spairs(out) do
if not (string.starts(k, 'min_') or string.starts(k, 'max_')) then
local prefix = ''
if args.prefix ~= nil then
prefix = args.prefix .. '_'
end
table.insert(vars_range,
'{{#vardefine: ' .. prefix .. 'range_' .. k .. '|{{formatnum:' .. round(out_min['min_' .. k]) ..
'}}% ~ {{formatnum:' .. round(out_max['max_' .. k]) .. '}}%}}');
end
end
indexTableMerge(vars, vars_range);
end
-- Dump all values if wanted.
if args.dump == 'true' then
local ret = {}
for k, v in spairs(out) do
table.insert(ret, k .. ': ' .. v)
end
return frame:preprocess(table.concat(ret, "<br/>"))
end
-- Parse all variables
local parsed = frame:preprocess('{{ ' .. table.concat(vars) .. 'trim2}}')
if args[1] ~= 'true' and args.table ~= 'true' then
return parsed
end
local char = args.char or args[2] or 'Elsword'
-- Generate the table
local tbl = mw.html.create('table'):attr({
['cellpadding'] = 5,
['border'] = 1,
['style'] = 'border-collapse: collapse; text-align: center',
['class'] = 'colortable-' .. char
})
-- For rowspan, colspan shenanigans
function increaseSpace(el, type, num)
if type == 'row' then
type = 'rowspan'
elseif type == 'col' then
type = 'colspan'
end
num = num or 1
return el:attr(type, tonumber(el:getAttr(type) or 1) + num)
end
function multiplySpace(el, type, m)
if not el then
return false
end
if type == 'row' then
type = 'rowspan'
else
type = 'colspan'
end
if m == nil then
m = 2
end
local span = el:getAttr(type) or 1
return el:attr(type, tonumber(span) * m)
end
local combine = split(args.combine)
local combine_suffix = args.combine_suffix
local append = split(args.append)[1]
local append_alias = split(args.append)[2]
local tbl_order = {'extra', 'passives_normal', 'passives_switch', 'awk', 'traits', 'hit_count'}
local STR = {
BASE = 'Base',
MODE = 'Mode',
REGULAR = 'Regular',
NORMAL = 'Normal',
AWK = 'Awakening Mode',
AVG = 'Average',
MAX = 'Max',
TRAIT = {'Enhanced', 'Empowered', 'Useful', 'Heavy'},
PER = 'Per',
INSTANCE = 'Instance'
}
local trait_args = {}
for k, v in ipairs(STR.TRAIT) do
table.insert(trait_args, string.lower(v))
end
local trait_count = 0
for k, v in ipairs(trait_args) do
if inArrayHas(v, out) then
trait_count = trait_count + 1
end
end
local tbl_content = {
extra = {
mode = STR.MODE,
long = STR.AVG
},
passives_normal = {
mode = STR.MODE,
base = STR.BASE,
combined = {},
aliases = {args.alias1 or false, args.alias2 or false, args.alias3 or false},
suffixes = {args.suffix1 or false, args.suffix2 or false, args.suffix3 or false}
},
passives_switch = {
normal = STR.NORMAL,
hide = true
},
awk = {
normal = STR.REGULAR,
awk_link = '[[' .. STR.AWK .. ']]',
hide = true
},
traits = {
normal = STR.NORMAL,
hide = true
},
hit_count = {
avg = STR.AVG,
max = STR.MAX,
hide = true
}
}
local count_name = args.count_name or STR.INSTANCE
if inArgs('count') and not args.use_avg then
tbl_content.hit_count.avg = table.concat({STR.PER, count_name}, ' ')
end
function getRowIndex(row)
for k, v in ipairs(tbl_order) do
if row == v then
return k
end
end
end
for passive_i = 1, 3 do
repeat
-- Add normal passives to the first row.
local passive_name = ''
-- Alias for appended passives.
if (inArgs('passive' .. passive_i)) then
passive_name = args['passive' .. passive_i]
end
if indexOf(tostring(passive_i), combine) ~= nil then
-- Add combined passives.
tbl_content.passives_normal.combined[passive_i] = passive_name
elseif tostring(passive_i) == append then
-- Add switch passives.
tbl_content.passives_switch[passive_i] = passive_name
tbl_content.passives_switch.hide = false
if append_alias ~= nil then
tbl_content.passives_switch.display_name = append_alias
end
elseif (inArgs('passive' .. passive_i)) then
-- Add regular passives to the first row.
tbl_content.passives_normal[passive_i] = passive_name
end
until true
end
local ret = ''
for trait_order, trait_arg in ipairs(trait_args) do
-- Add traits if exist.
if (inArgs(trait_arg)) then
tbl_content.traits[trait_arg] = args[trait_arg]
tbl_content.traits.hide = false
end
end
-- Add Useful trait.
if inArgs('hits_useful') or inArgs('avg_hits_useful') then
tbl_content.traits.useful = 'true'
tbl_content.traits.hide = false
end
if inArgs('avg_hits') or inArgs('count') then
-- Enable average/max if needed.
tbl_content.hit_count.hide = false
end
if inArrayHas('awk_', args) then
-- Enable Awakening if needed.
tbl_content.awk.hide = false
end
local loop_factor, mode_th;
local cells = {}
local passive_normal_count = 0;
local passive_switch_count = 0;
function hidden(level)
return tbl_content[level].hide
end
local hit_count_table = {'total'}
local awk_table = {''}
local levels_exist =
(next(passives) or args.append or args.awk_hits or args.awk_dmg or args.count)
local no_max = args.no_max == 'true'
function makePassiveLink(passive, alias, suffix, nil_cond)
if nil_cond == nil then
nil_cond = true
end
if nil_cond and alias ~= nil and alias ~= false then
alias = '|' .. alias
else
alias = ''
end
suffix = suffix or ''
passive = '[[' .. passive .. alias .. ']]' .. suffix
return passive
end
-- Begin the main loop.
for k, type in ipairs(tbl_order) do
repeat
local tr = tbl:tag('tr')
local data = tbl_content[type];
local hide = data.hide;
cells[type] = {}
function new(wikitext, normal)
local th = tr:tag('th'):wikitext(wikitext)
if normal == true then
table.insert(cells[type].normal_th, th)
elseif normal == false then
table.insert(cells[type].th, th)
else
return th
end
end
function multiplySpaceAll(level, num)
if cells[level] == nil then
return false
end
num = num or 2
for k, v in ipairs(cells[level].th) do
multiplySpace(v, 'col', num)
end
for k, v in ipairs(cells[level].normal_th) do
multiplySpace(v, 'col', num)
end
end
function reverseMultiplySpace(num, increase_mode)
local i = #tbl_order;
num = num or 2
local fix_for_no_max = 0
if no_max and not levels_exist then
fix_for_no_max = -1
end
while (i > 1) do
multiplySpaceAll(tbl_order[i - 1 + fix_for_no_max], num)
i = i - 1
end
if increase_mode ~= false then
increaseSpace(mode_th, 'row')
end
end
cells[type].normal_th = {}
cells[type].th = {}
if (type == 'extra' and no_max) then
mode_th = new(data.mode)
new(data.long, true)
end
if (type == 'passives_normal') then
if not no_max then
mode_th = new(data.mode)
else
reverseMultiplySpace(nil, false);
end
if (no_max and levels_exist) or not no_max then
new(data.base, true)
end
for i = 1, 3, 1 do
local passive_link = data[i]
if (passive_link ~= nil) then
local suffix = ''
if next(data.suffixes) and data.suffixes[i] ~= false then
suffix = ' ' .. data.suffixes[i]
end
passive_link = makePassiveLink(passive_link, data.aliases[i], suffix, next(data.aliases))
new(passive_link, false)
passive_normal_count = passive_normal_count + 1
end
end
-- Handle combining passives.
if next(data.combined) then
local combined_str = ''
for k, v in spairs(data.combined) do
combined_str = combined_str .. makePassiveLink(v, data.aliases[k], data.suffixes[k]) .. '/'
end
combined_str = combined_str:gsub('/$', '')
if combine_suffix then
combined_str = combined_str .. ' ' .. combine_suffix
end
new(combined_str, false)
passive_normal_count = passive_normal_count + 1
end
end
if (type == 'passives_switch') then
if not hidden(type) then
multiplySpaceAll('passives_normal')
-- For some reason, whenever appending is active, it misses a 1 in rowspan of this cell.
increaseSpace(mode_th, 'row')
end
-- Passives that appear in the second row
loop_factor = (passive_normal_count + 1)
for ix = 1, loop_factor, 1 do
for i = 1, 3, 1 do
if (data[i] ~= nil) then
new(data.normal, true);
local suffix = ''
if next(tbl_content.passives_normal.suffixes) and tbl_content.passives_normal.suffixes[i] ~= false then
suffix = ' ' .. tbl_content.passives_normal.suffixes[i]
end
local passive_link = data[i]
passive_link = makePassiveLink(passive_link, data.display_name, suffix)
new(passive_link, false)
if (ix == 1) then
-- Count switch passives. Only one iteration.
passive_switch_count = passive_switch_count + 1
end
end
end
end
end
if (type == 'awk' and not hide) then
reverseMultiplySpace();
table.insert(awk_table, 'awk')
loop_factor = loop_factor * (passive_switch_count + 1)
for i = 1, loop_factor, 1 do
new(data.normal, true)
new(data.awk_link, false)
end
end
if (type == 'traits' and not hide) then
if trait_count == 2 then
reverseMultiplySpace(3);
else
reverseMultiplySpace();
end
-- Manually fix certain situations.
local has_awk = 1
if not hidden('awk') then
has_awk = 2
end
local extra = 1
if hidden('awk') and not hidden('passives_switch') then
extra = 2
end
loop_factor = loop_factor * has_awk
for i = 1, loop_factor * extra, 1 do
local ix = 1
new(data.normal, true)
for k, trait_name in ipairs(trait_args) do
if data[trait_name] ~= nil then
new(STR.TRAIT[ix], false)
end
ix = ix + 1
end
end
end
if (type == 'hit_count' and not hide) then
if no_max and levels_exist then
increaseSpace(mode_th, 'row')
elseif levels_exist or (args.avg_hits and args.hits) then
reverseMultiplySpace();
else
reverseMultiplySpace(nil, false);
end
local avg_or_each = 'avg'
if inArgs('count') and not args.use_avg then
avg_or_each = 'each'
end
table.insert(hit_count_table, 1, avg_or_each)
-- Some things are breaking here, so I needed to implement conditional patches.
if hidden('awk') then
loop_factor = loop_factor * (passive_switch_count + 1)
end
if hidden('passives_switch') then
loop_factor = passive_normal_count + 1
end
if (hidden('traits') and not hidden('awk')) or (not hidden('awk') and hidden('passives_switch')) then
loop_factor = loop_factor * 2
end
loop_factor = loop_factor * (trait_count + 1)
if not no_max then
for i = 1, loop_factor, 1 do
new(data.avg, true)
new(data.max, false)
end
end
end
until true
end
if no_max and args.avg_hits then
hit_count_table[2] = nil
end
function concat(tbl)
local returned_str = ''
for k, v in ipairs(tbl) do
local delimiter = '_'
if returned_str == '' then
delimiter = ''
end
if v ~= '' then
returned_str = returned_str .. delimiter .. v
end
end
return returned_str
end
function makeValueRows(mode_flag)
local mode_cell = 'PvE'
if mode_flag == true then
mode_flag = '_pvp'
mode_cell = 'PvP'
else
mode_flag = ''
end
local value_row = tbl:tag('tr')
function display(name, range_flag)
local range_factor;
local cell_content = {}
if range_flag == true then
range_factor = 2
else
range_factor = 1
end
for i = 1, range_factor, 1 do
local range_prefix = '';
if range_flag == true then
if i == 1 then
range_prefix = 'min_'
else
range_prefix = 'max_'
end
end
local value = out[range_prefix .. name];
if (value ~= nil) then
if (args.dump_names == 'true') then
table.insert(cell_content, name)
elseif value ~= 0 then
table.insert(cell_content, formatnum(math.round(value, 2)) .. '%')
else
table.insert(cell_content, 'N/A')
end
end
end
if next(cell_content) then
return value_row:tag('td'):wikitext(table.concat(cell_content, '<span style="white-space:nowrap"> ~</span> '));
else
if args.dump_names == 'true' then
return value_row:tag('td'):wikitext(name)
end
return value_row:tag('td'):wikitext(frame:expandTemplate{
title = 'color',
args = {'red', '#ERROR'}
})
end
end
local ret2 = ''
value_row:tag('td'):wikitext(frame:expandTemplate{
title = mode_cell
})
for passive_normal_i = 0, 3, 1 do
local combine_now = tostring(passive_normal_i) == combine[1]
if tbl_content.passives_normal[passive_normal_i] or combine_now or passive_normal_i == 0 then
local passive_normal_str = 'passive' .. passive_normal_i
if combine_now then
for k, v in ipairs(combine) do
if k ~= 1 then
passive_normal_str = passive_normal_str .. '_passive' .. v
end
end
end
if passive_normal_i == 0 then
passive_normal_str = ''
end
for passive_switch_i = 0, 3, 1 do
local current_switch = tbl_content.passives_switch[passive_switch_i]
if current_switch or passive_switch_i == 0 then
local passive_switch_str = 'passive' .. passive_switch_i
if passive_switch_i == 0 then
passive_switch_str = ''
end
for _, awk_str in ipairs(awk_table) do
for trait_i = 0, #trait_args do
repeat
for hit_i, hit_v in ipairs(hit_count_table) do
local trait_str = trait_args[trait_i] or ''
local str_tbl = {'damage'}
local passive_tbl = {}
table.insert(str_tbl, awk_str)
if tbl_content.traits[trait_str] then
table.insert(str_tbl, trait_str)
elseif trait_i > 0 then
do
break
end
end
table.insert(str_tbl, 1, hit_v)
table.insert(passive_tbl, passive_switch_str)
table.insert(passive_tbl, passive_normal_str)
table.sort(passive_tbl)
for k, v in ipairs(passive_tbl) do
table.insert(str_tbl, v)
end
if inArgs('range_max') then
display(concat(str_tbl) .. mode_flag, true)
else
display(concat(str_tbl) .. mode_flag)
end
end
until true
end
end
end
end
end
end
end
-- For debugging purposes
if (args.debug == 'true') then
ret = ''
for i = 1, #tbl_order, 1 do
ret = ret .. "'''" .. tbl_order[i] .. "''': <br/>"
for k2, v2 in pairs(tbl_content[tbl_order[i]]) do
if (v2 == true) then
v2 = 'true'
end
local output = tostring(v2)
if (type(v2) == 'table') then
output = ''
output = output .. '<br/>--<br/>'
for k3, v3 in pairs(v2) do
output = output .. k3 .. ': ' .. tostring(v3) .. '<br/>'
end
output = output .. '--'
end
ret = ret .. k2 .. ': ' .. output .. '<br/>'
end
ret = ret .. '<br/>'
end
return ret
end
makeValueRows();
makeValueRows(true);
local bug = ''
if args.bug == 'true' then
bug = frame:expandTemplate{
title = 'SkillText',
args = {'FreeTraining'}
}
end
return parsed .. bug .. tostring(tbl)
end
return p
-- pyend