Module:Damage
From Elwiki
Documentation for this module may be created at Module:Damage/doc
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', 'pvp_dmg', 'awk_dmg', 'pvp_awk_dmg', 'hits', 'avg_hits', 'awk_hits', 'avg_awk_hits',
'hits_useful', 'avg_hits_useful', 'awk_hits_useful', 'avg_awk_hits_useful'}
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 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('awk_hits') 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'}, {'dmg', 'pvp_dmg'})
-- 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
-- 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)
local i = 1
fvals[fval] = 0
for k, v in spairs(split(args.dmg)) do
-- If 'hits' undefined, assume they're equal to 1.
if (data[hits .. i] == nil) then
data[hits .. i] = 1
end
-- Proceed to combine
fvals[fval] = fvals[fval] + data[dmg .. i] * data[hits .. i]
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
fvals[fval] = fvals[fval] + (args['count_extra' .. su] * args['count_extra_hits'])
end
end
-- Apply Useful modifier.
if string.find(fval, 'useful') then
fvals[fval] = fvals[fval] * args.useful_penalty
end
-- Undefined cases
if fvals[fval] == 0 then
fvals[fval] = '-'
end
end
-- Actually generate the values depending on arguments provided.
if inArgs(pr .. 'dmg') then
if (inArgs('count')) then
getTotal(pr .. 'dmg', 'hits', 'each_damage' .. su)
getTotal(pr .. 'dmg', 'hits', 'total_damage' .. su, true)
else
getTotal(pr .. 'dmg', 'hits', 'total_damage' .. su)
end
if inArgs('avg_hits') then
getTotal(pr .. 'dmg', 'avg_hits', 'avg_damage' .. su)
end
end
if inArgs(pr .. 'awk_dmg') or inArrayStarts(pr .. 'awk_dmg', data) then
getTotal(pr .. 'awk_dmg', 'awk_hits', 'total_damage_awk' .. su)
if inArgs('avg_awk_hits') then
getTotal(pr .. 'awk_dmg', 'avg_awk_hits', 'avg_damage_awk' .. su)
end
end
-- Handling traits
-- Useful handled separately
if inArgs('useful_penalty') then
getTotal(pr .. 'dmg', 'hits_useful', 'total_damage_useful' .. su)
if inArgs('avg_hits_useful') then
getTotal(pr .. 'dmg', 'avg_hits_useful', 'avg_damage_useful' .. su)
end
if inArgs(pr .. 'awk_dmg') and inArgs('awk_hits_useful') then
getTotal(pr .. 'awk_dmg', 'awk_hits_useful', 'total_damage_awk_useful' .. su)
end
if inArgs('avg_awk_hits') and inArgs('avg_awk_hits_useful') then
getTotal(pr .. 'awk_dmg', 'avg_awk_hits_useful', 'avg_damage_awk_useful' .. su)
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 (args.format == 'false') then
return '{{#vardefine:' .. prefix .. name .. '|' .. round(dmg) .. '}}'
else
return '{{#vardefine:' .. prefix .. name .. '|{{formatnum:' .. round(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 + 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/>"))
else
-- Parse all variables - end point
return frame:preprocess('{{ ' .. table.concat(vars) .. 'trim2}}')
end
end
return p