Module:AttackBox

local module = {} local format = string.format

local function getVal(args, name) return args.help and '' or args[name] end

local function getVals(args, name, cols) local vals = {} local val = args[name] if val and #val > 0 then local pos = 1 for start, stop in string.gmatch(val, ';%s*') do        vals[#vals+1] = string.sub(val, pos, start - 1) pos = stop end vals[#vals+1] = string.sub(val, pos) elseif cols then for i = 1, cols do        vals[i] = args[name .. i]     end else for i = 1, math.huge do        val = args[name .. i]        if not val then break end vals[i] = val end end return vals end

local function addHeader(icon, title, frame, out) out[#out+1] = format('|-\n! class="body" | %s %s\n',     icon and frame:expandTemplate{title=icon, args={size='x20'}} or '', title) end

local function addRow(title, name, args, rows, style) local val = args[name] if val then rows[#rows+1] = format('%s| %s\n| %s\n', style or '', title, val) end end

function module.player(frame) local args = frame.args if args.parent then args = frame:getParent.args end

local power = getVals(args, 'power') if #power == 0 then power = { 0, 5, 10, 15, 20, 25 } end local ranks = #power local minrank = tonumber(args.rank) or 1 if minrank > ranks then minrank = ranks elseif minrank < 1 then minrank = 1 end

local out = { '{| class="player ranks"\n' }

local image = getVal(args, 'image') if image then out[#out+1] = format('|-\n| colspan="%d" | %s\n', ranks+1, image) end

local rows = {} addRow('Attack Icon', 'weaponicon', args, rows, 'style="padding:none" ') addRow('Rank Available', 'rank', args, rows) for i = 1, #rows do     out[#out+1] = format('|-\n! class="body" colspan="%d" %s', ranks, rows[i]) end

out[#out+1] = '|-\n! class="body" | Rank\n' for i = 1, ranks do out[#out+1] = format('! %d\n', i) end

local damage = getVals(args, 'damage', ranks) local mindmg = tonumber(args['mindmg']) or 0 local maxdmg = tonumber(args['maxdmg']) or 0 local numattacks = tonumber(args['numattacks']) numattacks = numattacks and format(' (x%s)', numattacks) or '' local damagetype = string.lower(args['damagetype'] or '') if    damagetype == 'cold'      then damagetype = 'ColdDamage' elseif damagetype == 'crushing' then damagetype = 'Crushing' elseif damagetype == 'explosive' then damagetype = 'Explosive' elseif damagetype == 'fire'     then damagetype = 'Fire' elseif damagetype == 'piercing' then damagetype = 'Piercing' else damagetype = 'Power' end addHeader(damagetype, 'Damage', frame, out) for i = 1, minrank-1 do out[#out+1] = '| -\n' end for i = minrank, ranks do     local mult = 1 + (tonumber(power[i]) or 0) * 0.02 local min = math.floor(mindmg * mult) local max = math.floor(maxdmg * mult) out[#out+1] = damage[i] and format('| %s\n', damage[i]) or        format('| %d-%d%s\n', min, max, numattacks) damage[i] = (min + max) / 2 end

local dottype = string.lower(args['dottype'] or '') local dotduration = tonumber(args['dotduration']) or 0 local dot = getVals(args, 'dot', ranks) local dotmult = 1 if    dottype == 'poison' then dottype = 'PoisonDOT' elseif dottype == 'fire'  then dottype = 'FireDOT'; dotmult = 0.5 elseif dottype == 'napalm' then dottype = 'FireDOT'; dotmult = 0.5; dotduration = 0 else dottype = nil end if dottype then addHeader(dottype, 'DoT', frame, out) for i = 1, minrank-1 do out[#out+1] = '| -\n' end for i = minrank, ranks do        local dotdmg = damage[i] * dotmult out[#out+1] = dot[i] and format('| %s\n', dot[i]) or dotduration <= 1 and format('| %.0f\n', dotdmg) or format('| %.0f&rarr;%.0f\n', dotdmg, dotdmg / dotduration) end end

local baseoffense = tonumber(args['baseoffense']) or 0 local accuracy = getVals(args, 'accuracy', ranks) addHeader('Offense', 'Offense', frame, out) for i = 1, minrank-1 do out[#out+1] = '| -\n' end for i = minrank, ranks do     out[#out+1] = format('| %d\n', baseoffense + (tonumber(accuracy[i]) or 5*i-5)) end

local basecrit = tonumber(args['basecrit']) or 0 local critmod = getVals(args, 'critmod', ranks) local maxcritmod = 0 for i = minrank, ranks do      critmod[i] = tonumber(critmod[i]) or 0 if critmod[i] > maxcritmod then maxcritmod = critmod[i] end end if maxcritmod > 0 then addHeader('CriticalBonus', 'Crit', frame, out) for i = 1, minrank-1 do out[#out+1] = '| -\n' end for i = minrank, ranks do        out[#out+1] = format('| %d%%\n', basecrit + critmod[i]) end local critbonus = getVals(args, 'critbonus') -- no ranks! for j = 1, #critbonus do        local cat, val = string.match(critbonus[j] or '', '^(.-)%s*([-+]?%d+)%s*$') val = tonumber(val) if val then out[#out+1] = format('|-\n| align="left" | vs. %s\n', cat) for i = 1, minrank-1 do out[#out+1] = '| -\n' end for i = minrank, ranks do              out[#out+1] = format('| %d%%\n', basecrit + val + critmod[i]) end end end end

out[#out+1] = '|}' return table.concat(out) end

return module