🌟 | 現在、 鉄壁ヘッドショットには対応済みです。 鉄壁HSは通常HSと同じダメージになります。LMG及びDMR、チャージライフル、ハンマーポイント弾を除き、すべてのダメージ値が一致していることを確認しています。 |
「モジュール:DamageTable」の版間の差分
ナビゲーションに移動
検索に移動
(不要な記述の削除) |
(2次的なダメージ使用時にスカルピアサーライフリングを含めた表が生成できない不具合の修正) |
||
(同じ利用者による、間の137版が非表示) | |||
1行目: | 1行目: | ||
require('Module:Utility/mw.html Extensions') | |||
local p = {} | local p = {} | ||
local table = require('Module:TableExtensions') | |||
local aw = require('Module:Utility/Library') | |||
local apex = require('Module:Utility/ApexLibrary') | |||
local Color = require('Module:Color') | |||
local STKCalculator = require('Module:Apex/STKCalculator') | |||
local getArgs -- lazily initialized | local getArgs -- lazily initialized | ||
local function | local function getShotCount(part, health, shield, info, gunshield) | ||
return | local damages = apex.calcShotCount(info.damage, part, info.mul, health, shield, gunshield or 0, info.opts) | ||
return #damages, damages | |||
end | |||
local function renderHeader(tbl, mul, colspan, shields, res) | |||
tbl:tag('tr') | |||
:tag('th') | |||
:attr('colspan', colspan) | |||
:attr('rowspan', 2) | |||
:wikitextIf( | |||
mul == 1, | |||
res.targets.caption, | |||
function() | |||
return string.format(res.targets.caption_format, mul) | |||
end) | |||
:done() | |||
:tag('th') | |||
:attr('rowspan', 2) | |||
:wikitext(res.damages.caption) | |||
:done() | |||
:tag('th') | |||
:attr('colspan', #shields) | |||
:wikitext(res.shotstokill) | |||
local row = tbl:tag('tr') | |||
for _, shield in ipairs(shields) do | |||
row:tag('th') | |||
:attrIf( | |||
shield.tooltip ~= nil, | |||
{ ['data-tooltip'] = shield.tooltip }) | |||
:wikitext(shield.label) | |||
end | |||
end | end | ||
local function | local function renderCell(row, part, health, shield, info, gunshield, rowspan) | ||
local row = table: | local shotCount, damages = getShotCount(part, health, shield, info, gunshield) | ||
local cell = row:tag('th') | local ratio = (shotCount - info.minCount) / info.diffCount | ||
:attr('colspan', | local tooltip = { aw.stringifyRepeatingArray(damages, '→') } | ||
:attr('rowspan', | if info.ttkCalculator then | ||
if | local template = '<tr><th>%s </th><td class="cell-type-number" style="font-weight:bold">%d</td><td> ミリ秒</td></tr>' | ||
cell:wikitext(' | local ttkc = info.ttkCalculator | ||
local ttk0 = aw.round(1000 * ttkc:getAsLevel(shotCount, 0)) | |||
local ttk1 = aw.round(1000 * ttkc:getAsLevel(shotCount, 1)) | |||
elseif mul == | local ttk2 = aw.round(1000 * ttkc:getAsLevel(shotCount, 2)) | ||
local ttk3 = aw.round(1000 * ttkc:getAsLevel(shotCount, 3)) | |||
if ttk2 ~= ttk3 then | |||
table.insert(tooltip, '<br><br>キルタイム:<table class="condensedtable listtable">') | |||
if ttk0 == ttk1 then | |||
table.insert(tooltip, string.format(template, 'なし・Lv.1', ttk0)) | |||
table.insert(tooltip, string.format(template, 'Lv.2', ttk2)) | |||
else | |||
table.insert(tooltip, string.format(template, 'なし', ttk0)) | |||
table.insert(tooltip, string.format(template, 'Lv.1', ttk1)) | |||
table.insert(tooltip, string.format(template, 'Lv.2', ttk2)) | |||
end | |||
table.insert(tooltip, string.format(template, 'Lv.3', ttk3)) | |||
table.insert(tooltip, '</table>') | |||
elseif ttk1 ~= ttk2 then | |||
table.insert(tooltip, '<br><br>キルタイム:<table class="condensedtable listtable">') | |||
if ttk0 == ttk1 then | |||
table.insert(tooltip, string.format(template, 'なし・Lv.1', ttk0)) | |||
else | |||
table.insert(tooltip, string.format(template, 'なし', ttk0)) | |||
table.insert(tooltip, string.format(template, 'Lv.1', ttk1)) | |||
end | |||
table.insert(tooltip, string.format(template, 'Lv.2, 3', ttk2)) | |||
table.insert(tooltip, '</table>') | |||
elseif ttk0 ~= ttk1 then | |||
table.insert(tooltip, '<br><br>キルタイム:<table class="condensedtable listtable">') | |||
table.insert(tooltip, string.format(template, 'なし', ttk0)) | |||
table.insert(tooltip, string.format(template, 'Lv.1, 2, 3', ttk1)) | |||
table.insert(tooltip, '</table>') | |||
else | |||
table.insert(tooltip, string.format('<br>キルタイム: <span class="text-style-number" style="font-weight:bold">%d</span> ミリ秒', ttk0)) | |||
end | |||
end | |||
local hue = (info.diffCount < 5 and 0.65 or 0.85) * ratio | |||
local color = Color.HSL(hue, 0.91, 0.89):toRGB() | |||
row:tag('td') | |||
:attrIf(rowspan > 1, { rowspan = rowspan }) | |||
:attr('data-tooltip', table.concat(tooltip)) | |||
:css('background-color', tostring(color)) | |||
:wikitext(shotCount) | |||
end | |||
local function renderHeaderCell(row, name, tooltip, rowinfo) | |||
for i = 1, #rowinfo do | |||
local cellinfo = rowinfo[i] | |||
local colspan = cellinfo.colspan or 1 | |||
local rowspan = cellinfo.rowspan or 1 | |||
local cell = row:tag('th') | |||
if colspan > 1 then | |||
cell:attr('colspan', colspan) | |||
end | |||
if rowspan > 1 then | |||
cell:attr('rowspan', rowspan) | |||
end | |||
if cellinfo.breaktop then | |||
cell:css('border-top', '0 none transparent') | |||
end | |||
if cellinfo.breakbottom then | |||
cell:css('border-bottom', '0 none transparent') | |||
end | |||
--if cellinfo.showbottom then | |||
-- cell:css({ | |||
-- ['border-bottom-style'] = 'solid', | |||
-- ['border-bottom-width'] = '1px', | |||
-- }) | |||
--end | |||
if cellinfo.verticalAlign then | |||
cell:css('vertical-align', cellinfo.verticalAlign) | |||
end | |||
if i == #rowinfo then | |||
if tooltip ~= nil then | |||
cell:attr('data-tooltip', tooltip) | |||
end | |||
cell:wikitext(name) | |||
elseif cellinfo.content then | |||
if cellinfo.vertical then | |||
cell:addClass('vertical-cell') | |||
:tag('span') | |||
:wikitext(cellinfo.content) | |||
else | |||
cell:wikitext(cellinfo.content) | |||
end | |||
else | |||
cell:wikitext(' ') | |||
end | |||
end | |||
end | |||
local function renderRow(tbl, name, tooltip, part, weaponinfo, rowinfo, res, gunshield) | |||
local row = tbl:tag('tr') | |||
renderHeaderCell(row, name, tooltip, rowinfo) | |||
local damage | |||
local opts2 = aw.shallowCopy(weaponinfo.opts) | |||
table.removeKey(opts2, 'beamdamage') | |||
table.removeKey(opts2, 'beamticks') | |||
if gunshield then | |||
table.removeKey(opts2, 'disruptorRounds') | |||
table.removeKey(opts2, 'hammerpointRounds') | |||
damage = apex.calcDamage(weaponinfo.damage, 1, 1, opts2) | |||
else | |||
damage = apex.calcDamage(weaponinfo.damage, part, weaponinfo.mul, opts2) | |||
end | |||
local text | |||
if not gunshield and weaponinfo.opts.disruptorRounds > 1 then | |||
local optsD = aw.shallowCopy(weaponinfo.opts) | |||
table.removeKey(optsD, 'disruptorRounds') | |||
local defaultDamage = apex.calcDamage(weaponinfo.damage, part, weaponinfo.mul, optsD) | |||
if weaponinfo.opts.pellets > 1 then | |||
text = string.format( | |||
res.damages.pelletsWithDisruptor, | |||
damage * weaponinfo.opts.pellets, | |||
damage, | |||
weaponinfo.opts.pellets, | |||
defaultDamage * weaponinfo.opts.pellets) | |||
else | |||
text = string.format(res.damages.disruptor, damage, defaultDamage) | |||
end | |||
elseif not gunshield and weaponinfo.opts.hammerpointRounds > 1 then | |||
local optsH = aw.shallowCopy(weaponinfo.opts) | |||
table.removeKey(optsH, 'hammerpointRounds') | |||
local defaultDamage = apex.calcDamage(weaponinfo.damage, part, weaponinfo.mul, optsH) | |||
if weaponinfo.opts.pellets > 1 then | |||
text = string.format( | |||
res.damages.pelletsWithHammerpoint, | |||
defaultDamage * weaponinfo.opts.pellets, | |||
damage * weaponinfo.opts.pellets, | |||
damage, | |||
weaponinfo.opts.pellets) | |||
else | |||
text = string.format(res.damages.hammerpoint, defaultDamage, damage) | |||
end | |||
elseif weaponinfo.opts.pellets > 1 then | |||
text = string.format( | |||
res.damages.pellets, | |||
damage * weaponinfo.opts.pellets, | |||
damage, | |||
weaponinfo.opts.pellets) | |||
elseif weaponinfo.opts.beamticks > 1 then | |||
local beamdamage = apex.calcDamageFromPartAndPassive(weaponinfo.opts.beamdamage, part, weaponinfo.mul, opts2) | |||
local alldamage = beamdamage * weaponinfo.opts.beamticks + damage | |||
text = string.format( | |||
res.damages.ticks, | |||
alldamage, | |||
beamdamage, | |||
weaponinfo.opts.beamticks, | |||
damage) | |||
else | else | ||
text = tostring(damage) | |||
end | end | ||
row:tag(' | row:tag('td'):wikitext(text) | ||
for _, shield in ipairs(weaponinfo.shields) do | |||
renderCell(row, part, shield.health, shield.shield, weaponinfo, gunshield, 1) | |||
end | |||
end | end | ||
local function | local function getTTKCalculator(args) | ||
if args.rps <= 0 then | |||
return nil | |||
end | |||
local | -- 射撃レート | ||
local firerate | |||
if args.rpsratio1 > 1 then | |||
if args.rpsratio2 > args.rpsratio1 then | |||
if args.rpsratio3 > args.rpsratio2 then | |||
firerate = { | |||
args.rps, | |||
args.rpsratio1 * args.rps, | |||
args.rpsratio2 * args.rps, | |||
args.rpsratio3 * args.rps, | |||
} | |||
else | |||
local rps2 = args.rpsratio2 * args.rps | |||
firerate = { | |||
args.rps, | |||
args.rpsratio1 * args.rps, | |||
rps2, | |||
rps2, | |||
} | |||
end | |||
else | |||
local rps1 = args.rpsratio1 * args.rps | |||
firerate = { | |||
args.rps, | |||
rps1, | |||
rps1, | |||
rps1, | |||
} | |||
end | |||
else | |||
firerate = args.rps | |||
end | |||
-- 装填数 | |||
local magazine | |||
if args.extmag0 > 0 then | |||
if args.extmag1 > args.extmag0 then | |||
if args.extmag2 > args.extmag1 then | |||
if args.extmag3 > args.extmag2 then | |||
magazine = { args.extmag0, args.extmag1, args.extmag2, args.extmag3 } | |||
else | |||
magazine = { args.extmag0, args.extmag1, args.extmag2, args.extmag2 } | |||
end | |||
else | |||
magazine = { args.extmag0, args.extmag1, args.extmag1, args.extmag1 } | |||
end | |||
else | |||
magazine = args.extmag0 | |||
end | |||
else | |||
magazine = math.huge | |||
end | |||
-- リロード時間 | |||
local reload | |||
if args.reloadratio2 > 0 and args.reloadratio2 < 1 then | |||
if args.reloadratio3 > 0 and args.reloadratio3 < args.reloadratio2 then | |||
if args.reloadratio1 > 0 and args.reloadratio1 < 1 and args.reloadratio1 > args.reloadratio2 then | |||
reload = { | |||
args.reload, | |||
args.reloadratio1 * args.reload, | |||
args.reloadratio2 * args.reload, | |||
args.reloadratio3 * args.reload | |||
} | |||
else | |||
reload = { | |||
args.reload, | |||
args.reload, | |||
args.reloadratio2 * args.reload, | |||
args.reloadratio3 * args.reload | |||
} | |||
end | |||
else | |||
local reload2 = args.reloadratio2 * args.reload | |||
reload = { | |||
args.reload, | |||
args.reload, | |||
reload2, | |||
reload2 | |||
} | |||
end | |||
else | |||
reload = args.reload | |||
end | |||
local ttkc = require('Module:Apex/TTKCalculator').new(firerate, magazine, reload, { | |||
raiseTime = args.raise, | |||
}) | |||
return ttkc | |||
end | end | ||
local function | local function getContentLanguage(lang) | ||
local language = lang or mw.language.getContentLanguage().code | |||
return language == 'en' and 'en' or 'ja' | |||
end | |||
-- Calc all base damages | |||
local function calcBaseDamages(damage, headScale, legsScale, helmets, opts) | |||
local headLv1Scale = helmets.level1.func(headScale) | |||
local headLv2Scale = helmets.level2.func(headScale) | |||
local headLv3Scale = helmets.level3.func(headScale) | |||
local ret = { | |||
scale_hed0 = headScale, | |||
scale_hed1 = headLv1Scale, | |||
scale_hed2 = headLv2Scale, | |||
scale_hed3 = headLv3Scale, | |||
scale_body = 1, | |||
scale_legs = legsScale, | |||
} | |||
if opts.beamdamage > 0 then | |||
ret.dschrg_hed0 = aw.round(headScale * opts.beamdamage) | |||
ret.dschrg_hed1 = aw.round(headLv1Scale * opts.beamdamage) | |||
ret.dschrg_hed2 = aw.round(headLv2Scale * opts.beamdamage) | |||
ret.dschrg_hed3 = aw.round(headLv3Scale * opts.beamdamage) | |||
ret.dschrg_body = opts.beamdamage | |||
if legsScale < 1 then | |||
ret.dschrg_legs = aw.round(legsScale * opts.beamdamage) | |||
else | |||
ret.dschrg_legs = opts.beamdamage | |||
end | |||
end | |||
-- Amped Cover | |||
if opts.ampedCover then | |||
damage = aw.round(1.2 * damage) | |||
end | |||
-- Additional Scale | |||
if opts.charged > 1 then | |||
damage = aw.round(opts.charged * damage) | |||
end | |||
-- Unshield Scale | |||
if opts.hammerpointRounds > 1 then | |||
local shieldDamage = damage | |||
local unshldDamage = apex.calcHammerpointDamage(damage, opts.hammerpointRounds) | |||
-- Passthrough | |||
if opts.passthrough < 1 then | |||
shieldDamage = apex.calcPassthroughDamage(shieldDamage, opts.passthrough) | |||
unshldDamage = apex.calcPassthroughDamage(unshldDamage, opts.passthrough) | |||
end | |||
local shieldLegs, unshldLegs | |||
if legsScale < 1 then | |||
shieldLegs = aw.round(legsScale * shieldDamage) | |||
unshldLegs = aw.round(legsScale * unshldDamage) | |||
else | |||
shieldLegs = shieldDamage | |||
unshldLegs = unshldDamage | |||
end | |||
ret.shield_hed0 = aw.round(headScale * shieldDamage) | |||
ret.shield_hed1 = aw.round(headLv1Scale * shieldDamage) | |||
ret.shield_hed2 = aw.round(headLv2Scale * shieldDamage) | |||
ret.shield_hed3 = aw.round(headLv3Scale * shieldDamage) | |||
ret.shield_body = shieldDamage | |||
ret.shield_legs = shieldLegs | |||
ret.unshld_hed0 = aw.round(headScale * unshldDamage) | |||
ret.unshld_hed1 = aw.round(headLv1Scale * unshldDamage) | |||
ret.unshld_hed2 = aw.round(headLv2Scale * unshldDamage) | |||
ret.unshld_hed3 = aw.round(headLv3Scale * unshldDamage) | |||
ret.unshld_body = unshldDamage | |||
ret.unshld_legs = unshldLegs | |||
-- Other | |||
else | |||
-- Passthrough | |||
if opts.passthrough < 1 then | |||
damage = apex.calcPassthroughDamage(damage, opts.passthrough) | |||
end | |||
local legs | |||
if legsScale < 1 then | |||
legs = aw.round(legsScale * damage) | |||
else | |||
legs = damage | |||
end | |||
ret.shield_hed0 = aw.round(headScale * damage) | |||
ret.shield_hed1 = aw.round(headLv1Scale * damage) | |||
ret.shield_hed2 = aw.round(headLv2Scale * damage) | |||
ret.shield_hed3 = aw.round(headLv3Scale * damage) | |||
ret.shield_body = damage | |||
ret.shield_legs = legs | |||
ret.unshld_hed0 = ret.shield_hed0 | |||
ret.unshld_hed1 = ret.shield_hed1 | |||
ret.unshld_hed2 = ret.shield_hed2 | |||
ret.unshld_hed3 = ret.shield_hed3 | |||
ret.unshld_body = ret.shield_body | |||
ret.unshld_legs = ret.shield_legs | |||
end | |||
local | return ret | ||
end | |||
-- Apply perk/shield scale to damages | |||
local function applyPerkAndShieldScaleToDamages(damages, perkScale, ignorePerkScaleForHS, opts) | |||
if perkScale ~= 1 then | |||
elseif | if opts.disruptorRounds > 1 then | ||
return table.map(damages, function(key, val) | |||
if ignorePerkScaleForHS and (aw.stringstarts(key, 'shield_hed') or aw.stringstarts(key, 'unshld_hed') or aw.stringstarts(key, 'dschrg_hed')) then | |||
if aw.stringstarts(key, 'shield_') then | |||
return apex.calcDisruptorDamage(val, opts.disruptorRounds) | |||
else | |||
return val | |||
end | |||
elseif aw.stringstarts(key, 'shield_') or aw.stringstarts(key, 'unshld_') or aw.stringstarts(key, 'dschrg_') then | |||
local perkedDamage = apex.calcPassiveDamage(val, perkScale, { round = opts.round }) | |||
if aw.stringstarts(key, 'shield_') then | |||
return apex.calcDisruptorDamage(perkedDamage, opts.disruptorRounds) | |||
else | |||
return perkedDamage | |||
end | |||
else | |||
return val | |||
end | |||
end) | |||
else | |||
return table.map(damages, function(key, val) | |||
if ignorePerkScaleForHS and (aw.stringstarts(key, 'shield_hed') or aw.stringstarts(key, 'unshld_hed') or aw.stringstarts(key, 'dschrg_hed')) then | |||
return val | |||
elseif aw.stringstarts(key, 'shield_') or aw.stringstarts(key, 'unshld_') or aw.stringstarts(key, 'dschrg_') then | |||
return apex.calcPassiveDamage(val, perkScale, { round = opts.round }) | |||
else | |||
return val | |||
end | |||
end) | |||
end | |||
elseif opts.disruptorRounds > 1 then | |||
return table.map(damages, function(key, val) | |||
if aw.stringstarts(key, 'shield_') then | |||
return apex.calcDisruptorDamage(val, opts.disruptorRounds) | |||
else | |||
return val | |||
end | |||
end) | |||
else | else | ||
return damages | |||
end | end | ||
if | end | ||
-- Compare damage | |||
local function equalPartDamage(damages, part0, part1) | |||
if damages['dschrg_' .. part0] and damages['dschrg_' .. part1] then | |||
return damages['shield_' .. part0] == damages['shield_' .. part1] and damages['unshld_' .. part0] == damages['unshld_' .. part1] and damages['dschrg_' .. part0] == damages['dschrg_' .. part1] | |||
else | else | ||
return damages['shield_' .. part0] == damages['shield_' .. part1] and damages['unshld_' .. part0] == damages['unshld_' .. part1] | |||
end | end | ||
end | end | ||
local function | -- Render the damage row | ||
local | local function renderRow2(tbl, name, tooltip, damages, partname, weaponinfo, rowinfo, res, rowspan, gunshield) | ||
rowspan = rowspan or 1 | |||
local scale = damages['scale_' .. partname] | |||
local shieldDamage = damages['shield_' .. partname] | |||
row:tag(' | local unshldDamage = damages['unshld_' .. partname] | ||
local dschrgDamage = damages['dschrg_' .. partname] | |||
local row = tbl:tag('tr') | |||
renderHeaderCell(row, name, tooltip, rowinfo) | |||
local | local text | ||
if | if shieldDamage > unshldDamage then | ||
if weaponinfo.opts.pellets > 1 then | |||
text = string.format( | |||
res.damages.pelletsWithDisruptor, | |||
shieldDamage * weaponinfo.opts.pellets, | |||
shieldDamage, | |||
weaponinfo.opts.pellets, | |||
unshldDamage * weaponinfo.opts.pellets) | |||
else | |||
text = string.format(res.damages.disruptor, shieldDamage, unshldDamage) | |||
end | |||
elseif shieldDamage < unshldDamage then | |||
if weaponinfo.opts.pellets > 1 then | |||
text = string.format( | |||
res.damages.pelletsWithHammerpoint, | |||
shieldDamage * weaponinfo.opts.pellets, | |||
unshldDamage * weaponinfo.opts.pellets, | |||
unshldDamage, | |||
weaponinfo.opts.pellets) | |||
else | |||
text = string.format(res.damages.hammerpoint, shieldDamage, unshldDamage) | |||
end | |||
elseif dschrgDamage and weaponinfo.opts.beamticks >= 1 then | |||
text = string.format( | |||
res.damages.ticks, | |||
dschrgDamage * weaponinfo.opts.beamticks + shieldDamage, | |||
dschrgDamage, | |||
weaponinfo.opts.beamticks, | |||
shieldDamage) | |||
else | else | ||
row:tag('td'):attr(' | if weaponinfo.opts.pellets > 1 then | ||
text = string.format( | |||
res.damages.pellets, | |||
shieldDamage * weaponinfo.opts.pellets, | |||
shieldDamage, | |||
weaponinfo.opts.pellets) | |||
else | |||
text = tostring(shieldDamage) | |||
end | |||
end | |||
row:tag('td') | |||
:attr('rowspan', rowspan) | |||
:wikitext(text) | |||
for _, shield in ipairs(weaponinfo.shields) do | |||
renderCell(row, scale, shield.health, shield.shield, weaponinfo, gunshield, rowspan) | |||
end | end | ||
end | |||
-- Render the helmet damage | |||
local function renderHelmetSection(tbl, damages, res, weaponinfo, helmets, info) | |||
local skipLvl1 = false | |||
local skipLvl2 = false | |||
local hed1Label = string.format(res.targets.helmet1, damages.scale_hed1) | |||
local hed2Label = string.format(res.targets.helmet2, damages.scale_hed2) | |||
local hed3Label = string.format(res.targets.helmet3, damages.scale_hed3) | |||
local hed1Tooltip = string.format(helmets.level1.text, damages.scale_hed0) | |||
local hed2Tooltip = string.format(helmets.level2.text, damages.scale_hed0) | |||
local hed3Tooltip = string.format(helmets.level3.text, damages.scale_hed0) | |||
if not helmets.level0.disabled then | |||
local hed0Rowspan | |||
if equalPartDamage(damages, 'hed0', 'hed1') then | |||
if equalPartDamage(damages, 'hed0', 'hed2') then | |||
if equalPartDamage(damages, 'hed0', 'hed3') then | |||
hed0Rowspan = 4 | |||
else | |||
hed0Rowspan = 3 | |||
end | |||
else | |||
hed0Rowspan = 2 | |||
end | |||
else | |||
hed0Rowspan = 1 | |||
end | |||
local hed0Label = string.format(res.targets.head_format, damages.scale_hed0) | |||
renderRow2(tbl, hed0Label, nil, damages, 'hed0', weaponinfo, info.level1top, res, hed0Rowspan) | |||
if hed0Rowspan >= 4 then | |||
renderHeaderCell(tbl:tag('tr'), hed1Label, hed1Tooltip, info.level2first) | |||
renderHeaderCell(tbl:tag('tr'), hed2Label, hed2Tooltip, info.level2) | |||
renderHeaderCell(tbl:tag('tr'), hed3Label, hed3Tooltip, info.level2) | |||
return | |||
elseif hed0Rowspan == 3 then | |||
renderHeaderCell(tbl:tag('tr'), hed1Label, hed1Tooltip, info.level2first) | |||
renderHeaderCell(tbl:tag('tr'), hed2Label, hed2Tooltip, info.level2) | |||
skipLvl1 = true | |||
skipLvl2 = true | |||
elseif hed0Rowspan == 2 then | |||
renderHeaderCell(tbl:tag('tr'), hed1Label, hed1Tooltip, info.level2first) | |||
skipLvl1 = true | |||
end | |||
end | |||
-- Lvl 1 | |||
if not skipLvl1 then | |||
local hed1Rowspan | |||
if equalPartDamage(damages, 'hed1', 'hed2') then | |||
if equalPartDamage(damages, 'hed1', 'hed3') then | |||
hed1Rowspan = 3 | |||
else | |||
hed1Rowspan = 2 | |||
end | |||
else | |||
hed1Rowspan = 1 | |||
end | |||
renderRow2(tbl, hed1Label, hed1Tooltip, damages, 'hed1', weaponinfo, info.level2first, res, hed1Rowspan) | |||
if hed1Rowspan >= 3 then | |||
renderHeaderCell(tbl:tag('tr'), hed2Label, hed2Tooltip, info.level2) | |||
renderHeaderCell(tbl:tag('tr'), hed3Label, hed3Tooltip, info.level2) | |||
return | |||
elseif hed1Rowspan == 2 then | |||
renderHeaderCell(tbl:tag('tr'), hed2Label, hed2Tooltip, info.level2) | |||
skipLvl2 = true | |||
end | |||
end | |||
-- Lvl 2 | |||
if not skipLvl2 then | |||
local hed2Rowspan | |||
if equalPartDamage(damages, 'hed2', 'hed3') then | |||
hed2Rowspan = 2 | |||
else | |||
hed2Rowspan = 1 | |||
end | |||
renderRow2(tbl, hed2Label, hed2Tooltip, damages, 'hed2', weaponinfo, info.level2, res, hed2Rowspan) | |||
if hed2Rowspan >= 2 then | |||
renderHeaderCell(tbl:tag('tr'), hed3Label, hed3Tooltip, info.level2) | |||
return | |||
end | |||
end | |||
-- Lvl 3 | |||
renderRow2(tbl, hed3Label, hed3Tooltip, damages, 'hed3', weaponinfo, info.level2, res, 1) | |||
end | end | ||
local function renderTable(args) | local function renderTable(args) | ||
local | local lang = getContentLanguage(args.lang) | ||
local res = mw.loadData('Module:DamageTable/configuration')[lang] | |||
local shieldinfo = args.shieldinfo or require('Module:Stat/Shield')[args.shieldpreset] | |||
local skullpiercer = args.skullpiercer or 1 | |||
local headMul = args.head or 2 | |||
local hideNoHelmets = shieldinfo.helmets.level0.disabled | |||
local minHead | |||
if hideNoHelmets then | |||
minHead = shieldinfo.helmets.level1.func(args.headmax) | |||
else | else | ||
minHead = args.headmax | |||
end | |||
if shieldinfo.sameHeadshotDamageToNormalOnFortified then | |||
args.mul2 = shieldinfo.fortified | |||
end | |||
local hasSecond = args.mul2 > 0 and args.mul2 ~= 1 | |||
local noLegsShot = args.leg < 0 or args.leg >= 1 or (shieldinfo.legAsBodyOnLowProfile and args.mul > 1) | |||
local noLegsShot2 = args.leg < 0 or args.leg >= 1 or (shieldinfo.legAsBodyOnLowProfile and args.mul2 > 1) | |||
-- Get/calc min count | |||
local minCount | |||
if args.mincount > 0 then | |||
minCount = args.mincount | |||
else | |||
minCount, _ = getShotCount( | |||
minHead, | |||
100, | |||
0, | |||
{ | |||
damage = math.max(args.damage, args.damagemax), | |||
mul = math.max(args.mul, args.mulmax), | |||
opts = { | |||
ampedCover = true, | |||
beamdamage = math.max(args.beamdamage, args.beamdamagemax), | |||
beamticks = math.max(args.ticks, args.ticksmax), | |||
charged = math.max(args.charged, args.chargedmax), | |||
disruptorRounds = math.max(args.disruptor, args.disruptorsup), | |||
gunshieldBleedthrough = shieldinfo.gunshieldBleedthrough, | |||
hammerpointRounds = math.max(args.hammerpoint, args.hammerpointsup), | |||
ignorePassiveForHeadshot = shieldinfo.sameHeadshotDamageToNormalOnFortified, | |||
passthrough = 1, | |||
pellets = math.max(args.pellet, args.pelletmax), | |||
round = args.round, | |||
} | |||
}) | |||
end | end | ||
local | -- Get/calc max count | ||
local mul = args.mul | local maxCount | ||
if args.maxcount < 250 then | |||
local | maxCount = args.maxcount | ||
local | else | ||
local damagemin = math.min(args.damage, args.damagemin) | |||
local mininfo = { | |||
damage = damagemin, | |||
mul = math.min(args.mul, args.mulmin), | |||
opts = { | |||
ampedCover = false, | |||
beamdamage = math.min(args.beamdamage, args.beamdamagemin), | |||
beamticks = math.min(args.ticks, args.ticksmin), | |||
charged = 1, | |||
disruptorRounds = 1, | |||
gunshieldBleedthrough = shieldinfo.gunshieldBleedthrough, | |||
hammerpointRounds = 1, | |||
ignorePassiveForHeadshot = shieldinfo.sameHeadshotDamageToNormalOnFortified, | |||
passthrough = math.min(args.passthrough, args.passthroughsup), | |||
pellets = math.min(args.pellet, args.pelletmin), | |||
round = args.round, | |||
} | |||
} | |||
local maxshield = shieldinfo.shields[#shieldinfo.shields] | |||
local legCount, _ = getShotCount(math.min(args.leg, args.legmin), maxshield.health, maxshield.shield, mininfo) | |||
local bodyWithGunSheild, _ = getShotCount(1, maxshield.health, maxshield.shield, mininfo, shieldinfo.gunshield) | |||
maxCount = math.max(legCount, bodyWithGunSheild) | |||
end | |||
local ttkCalculator = getTTKCalculator(args) | |||
-- Define weapon info | |||
local weaponinfo = { | |||
damage = args.damage, | |||
mul = args.mul, | |||
minCount = minCount, | |||
diffCount = maxCount - minCount, | |||
shields = shieldinfo.shields, | |||
helmets = shieldinfo.helmets, | |||
ttkCalculator = ttkCalculator, | |||
opts = { | |||
ampedCover = args.amped, | |||
beamdamage = args.beamdamage, | |||
beamticks = args.ticks, | |||
charged = args.charged, | |||
disruptorRounds = args.disruptor, | |||
gunshieldBleedthrough = shieldinfo.gunshieldBleedthrough, | |||
hammerpointRounds = args.hammerpoint, | |||
ignorePassiveForHeadshot = shieldinfo.sameHeadshotDamageToNormalOnFortified, | |||
passthrough = args.passthrough, | |||
pellets = args.pellet, | |||
round = args.round, | |||
}, | |||
} | |||
local colspan, info | |||
if skullpiercer > 1 then | |||
colspan = 3 | |||
info = { | |||
level1 = { | |||
{ breaktop = false, breakbottom = false, colspan = 3 }, | |||
}, | |||
level1top = { | |||
{ breaktop = true, breakbottom = true, colspan = 3 }, | |||
}, | |||
level1gunshiled = { | |||
{ breaktop = false, breakbottom = true, colspan = 3 }, | |||
}, | |||
level2 = { | |||
{ breaktop = true, breakbottom = false, colspan = 2 }, | |||
}, | |||
level2gunshiled = { | |||
{ breaktop = true, breakbottom = false }, | |||
{ breaktop = false, breakbottom = false, colspan = 2 }, | |||
}, | |||
level3 = { | |||
{ breaktop = false, breakbottom = true }, | |||
{ breaktop = false, breakbottom = false, showbottom = true }, | |||
}, | |||
level3first = { | |||
hideNoHelmets and { breaktop = false, breakbottom = false, rowspan = 6, content = res.targets.head, vertical = res.targets.head_vertical, verticalAlign = res.targets.head_verticalalign } or { breaktop = true, breakbottom = false, rowspan = 6 }, | |||
{ breaktop = false, breakbottom = true }, | |||
{ breaktop = false, breakbottom = false, showbottom = true }, | |||
}, | |||
level3top = { | |||
{ breaktop = false, breakbottom = true, colspan = 2 }, | |||
{ breaktop = false, breakbottom = false, showbottom = true }, | |||
}, | |||
} | |||
info.level2first = info.level2 | |||
if hasSecond and not noLegsShot2 then | |||
info.level1gunshiled = nil | |||
info.level2gunshiled = { | |||
{ breaktop = false, breakbottom = false, rowspan = 3, content = res.targets.fortified, vertical = res.targets.fortified_vertical, verticalAlign = res.targets.fortified_verticalalign }, | |||
{ breaktop = false, breakbottom = true, colspan = 2 }, | |||
} | |||
info.level3gunshiled = { | |||
{ breaktop = true, breakbottom = false }, | |||
{ breaktop = false, breakbottom = false }, | |||
} | |||
end | |||
elseif hasSecond and not noLegsShot2 then | |||
colspan = 3 | |||
info = { | |||
level1 = { | |||
{ breaktop = false, breakbottom = false, colspan = 3 }, | |||
}, | |||
level1top = { | |||
{ breaktop = false, breakbottom = true, colspan = 3 }, | |||
}, | |||
level2 = { | |||
{ breaktop = false, breakbottom = false, colspan = 2 }, | |||
}, | |||
level2first = { | |||
hideNoHelmets and { breaktop = false, breakbottom = false, rowspan = 3, content = res.targets.head, vertical = res.targets.head_vertical, verticalAlign = res.targets.head_verticalalign } or { breaktop = true, breakbottom = false, rowspan = 3 }, | |||
{ breaktop = false, breakbottom = false, colspan = 2 }, | |||
}, | |||
level2gunshiled = { | |||
{ breaktop = false, breakbottom = false, rowspan = 3, content = res.targets.fortified, vertical = res.targets.fortified_vertical, verticalAlign = res.targets.fortified_verticalalign }, | |||
{ breaktop = false, breakbottom = true, colspan = 2 }, | |||
}, | |||
level3 = { | |||
{ breaktop = false, breakbottom = false }, | |||
}, | |||
level3gunshiled = { | |||
{ breaktop = true, breakbottom = false }, | |||
{ breaktop = false, breakbottom = false }, | |||
}, | |||
} | |||
else | |||
colspan = 2 | |||
info = { | |||
level1 = { | |||
{ breaktop = false, breakbottom = false, colspan = 2 }, | |||
}, | |||
level1gunshiled = { | |||
{ breaktop = false, breakbottom = true, colspan = 2 }, | |||
}, | |||
level2 = { | |||
{ breaktop = false, breakbottom = false }, | |||
}, | |||
level2first = { | |||
hideNoHelmets and { breaktop = false, breakbottom = false, rowspan = 3, content = res.targets.head, vertical = res.targets.head_vertical, verticalAlign = res.targets.head_verticalalign } or { breaktop = true, breakbottom = false, rowspan = 3 }, | |||
{ breaktop = false, breakbottom = false }, | |||
}, | |||
level2gunshiled = { | |||
{ breaktop = true, breakbottom = false }, | |||
{ breaktop = false, breakbottom = false }, | |||
}, | |||
} | |||
info.level1top = info.level1gunshiled | |||
end | |||
local table = mw.html.create('table') | local table = mw.html.create('table') | ||
:addClass('wikitable') | :addClass('wikitable') | ||
:addClass('numbertable') | |||
:addClass('damagetable') | |||
table | if args.caption ~= nil then | ||
table:tag('caption') | |||
:wikitext(args.caption) | |||
end | |||
local | local baseDamages = calcBaseDamages(weaponinfo.damage, headMul, args.leg, weaponinfo.helmets, weaponinfo.opts) | ||
local perkedDamages = applyPerkAndShieldScaleToDamages(baseDamages, weaponinfo.mul, shieldinfo.sameHeadshotDamageToNormalOnFortified, weaponinfo.opts) | |||
renderHeader(table, args.mul, colspan, shieldinfo.shields, res) | |||
local | -- Headshot damage | ||
if headMul > 1 then | |||
-- w/Skullpiercer Rifling | |||
if skullpiercer > 1 then | |||
if not hideNoHelmets then | |||
renderRow( | |||
table, | |||
string.format(res.targets.skullpiercer0, args.skullpiercerrarity, skullpiercer), | |||
nil, | |||
skullpiercer, weaponinfo, info.level3top, res) | |||
renderRow2( | |||
table, | |||
string.format(res.targets.head_format, perkedDamages.scale_hed0), | |||
nil, | |||
perkedDamages, | |||
'hed0', | |||
weaponinfo, info.level1top, res) | |||
end | |||
local skullpiercerLv1Mul = shieldinfo.helmets.level1.func(skullpiercer) | |||
renderRow( | |||
table, | |||
string.format(res.targets.skullpiercer1, args.skullpiercerrarity, skullpiercerLv1Mul), | |||
string.format(shieldinfo.helmets.level1.text, skullpiercer), | |||
skullpiercerLv1Mul, weaponinfo, info.level3first, res) | |||
renderRow2( | |||
table, | |||
string.format(res.targets.helmet1, perkedDamages.scale_hed1), | |||
string.format(shieldinfo.helmets.level1.text, headMul), | |||
perkedDamages, | |||
'hed1', | |||
weaponinfo, info.level2first, res) | |||
local skullpiercerLv2Mul = shieldinfo.helmets.level2.func(skullpiercer) | |||
renderRow( | |||
table, | |||
string.format(res.targets.skullpiercer2, args.skullpiercerrarity, skullpiercerLv2Mul), | |||
string.format(shieldinfo.helmets.level2.text, skullpiercer), | |||
skullpiercerLv2Mul, weaponinfo, info.level3, res) | |||
renderRow2( | |||
table, | |||
string.format(res.targets.helmet2, perkedDamages.scale_hed2), | |||
string.format(shieldinfo.helmets.level2.text, headMul), | |||
perkedDamages, | |||
'hed2', | |||
weaponinfo, info.level2, res) | |||
local skullpiercerLv3Mul = shieldinfo.helmets.level3.func(skullpiercer) | |||
renderRow( | |||
table, | |||
string.format(res.targets.skullpiercer3, args.skullpiercerrarity, skullpiercerLv3Mul), | |||
string.format(shieldinfo.helmets.level3.text, skullpiercer), | |||
skullpiercerLv3Mul, weaponinfo, info.level3, res) | |||
renderRow2( | |||
table, | |||
string.format(res.targets.helmet3, perkedDamages.scale_hed3), | |||
string.format(shieldinfo.helmets.level3.text, headMul), | |||
perkedDamages, | |||
'hed3', | |||
weaponinfo, info.level2, res) | |||
-- w/o Skullpiercer Rifling | |||
else | |||
renderHelmetSection(table, perkedDamages, res, weaponinfo, shieldinfo.helmets, info) | |||
end | |||
end | |||
-- Body shot damage | |||
local label | |||
if headMul <= 1 then | |||
if noLegsShot then | |||
label = res.targets.all | |||
else | |||
label = res.targets.headbody | |||
end | |||
elseif noLegsShot then | |||
label = res.targets.bodylegs | |||
else | |||
label = res.targets.body | |||
end | |||
if args.mul < 1 or args.forcegunshield then | |||
renderRow2(table, label, nil, perkedDamages, 'body', weaponinfo, info.level1gunshiled, res) | |||
renderRow( | |||
table, | |||
res.targets.gunshield, | |||
shieldinfo.gunshieldLabel, | |||
1, weaponinfo, info.level2gunshiled, res, shieldinfo.gunshield) | |||
else | |||
renderRow2(table, label, nil, perkedDamages, 'body', weaponinfo, info.level1, res) | |||
end | |||
-- Legs shot damage | |||
if not noLegsShot then | |||
local legsLabel = string.format(res.targets.legs, args.leg) | |||
renderRow2(table, legsLabel, nil, perkedDamages, 'legs', weaponinfo, info.level1, res) | |||
end | |||
-- the 2nd place of damages | |||
if | if hasSecond then | ||
if | local rowinfoSecondTop, rowinfoSecondGunShield, label2 | ||
if not noLegsShot2 then | |||
rowinfoSecondTop = info.level2gunshiled | |||
rowinfoSecondGunShield = info.level3gunshiled | |||
label2 = label | |||
elseif args.mul2 < 1 then | |||
rowinfoSecondTop = info.level1gunshiled | |||
rowinfoSecondGunShield = info.level2gunshiled | |||
label2 = string.format(res.targets.fortified_prefix, args.mul2, label) | |||
else | else | ||
rowinfoSecondTop = info.level1 | |||
rowinfoSecondGunShield = nil | |||
label2 = string.format(res.targets.fortified_prefix, args.mul2, label) | |||
end | end | ||
local | local weaponinfo2 = aw.shallowCopy(weaponinfo) | ||
weaponinfo2.mul = args.mul2 | |||
local perkedDamages2 = applyPerkAndShieldScaleToDamages(baseDamages, weaponinfo2.mul, shieldinfo.sameHeadshotDamageToNormalOnFortified, weaponinfo2.opts) | |||
if args.mul2 < 1 then | |||
renderRow2(table, label2, nil, perkedDamages2, 'body', weaponinfo2, rowinfoSecondTop, res) | |||
renderRow( | |||
renderRow(table, | table, | ||
res.targets.gunshield, | |||
shieldinfo.gunshieldLabel, | |||
1, weaponinfo2, rowinfoSecondGunShield, res, shieldinfo.gunshield) | |||
else | else | ||
renderRow2(table, label2, nil, perkedDamages2, 'body', weaponinfo2, info.level2, res) | |||
end | |||
-- Legs shot damage | |||
if not noLegsShot2 then | |||
local legsLabel = string.format(res.targets.legs, args.leg) | |||
renderRow2(table, legsLabel, nil, perkedDamages2, 'legs', weaponinfo2, info.level2, res) | |||
end | end | ||
end | end | ||
164行目: | 985行目: | ||
end | end | ||
function p._main(args) | function p._main(args, frame) | ||
-- init value | |||
local initValues = { | |||
mincount = 0, | |||
maxcount = 250, | |||
damage = 20, | |||
damagemin = 1000, | |||
damagemax = 0, | |||
beamdamage = 0, | |||
beamdamagemin = 0, | |||
beamdamagemax = 0, | |||
ticks = 0, | |||
ticksmin = math.huge, | |||
ticksmax = 0, | |||
pellet = 1, | |||
pelletmin = 0, | |||
pelletmax = 0, | |||
head = 2, | |||
headmax = -1, | |||
leg = 0.8, | |||
legmin = 0, | |||
mul = 1, | |||
mul2 = 0, | |||
mulmin = 0.85, | |||
mulmax = 1, | |||
charged = 1, | |||
chargedmax = 1, | |||
skullpiercer = 1, | |||
disruptor = 1, | |||
disruptorsup = 1, | |||
hammerpoint = 1, | |||
hammerpointsup = 1, | |||
passthrough = 1, | |||
passthroughsup = 1, | |||
rps = 0, | |||
rpsratio1 = 0, | |||
rpsratio2 = 0, | |||
rpsratio3 = 0, | |||
raise = 0, | |||
reload = 0, | |||
reloadratio1 = 0.963, | |||
reloadratio2 = 0.933, | |||
reloadratio3 = 0.9, | |||
extmag0 = 0, | |||
extmag1 = 0, | |||
extmag2 = 0, | |||
extmag3 = 0, | |||
} | |||
-- fix arguments | |||
for key, value in pairs(initValues) do | |||
args[key] = aw.getAsNumber(args[key], value) | |||
end | |||
if args.pelletmin == 0 then | |||
args.pelletmin = args.pellet | |||
end | |||
if args.pelletmax == 0 then | |||
args.pelletmax = args.pellet | |||
end | |||
if args.headmax == -1 then | |||
args.headmax = math.max(args.head, args.skullpiercer) | |||
end | |||
if args.legmin == 0 then | |||
args.legmin = args.leg | |||
end | |||
if args.beamdamagemin == 0 then | |||
args.beamdamagemin = args.beamdamage | |||
end | |||
if args.beamdamagemax == 0 then | |||
args.beamdamagemax = args.beamdamage | |||
end | |||
args.round = aw.getAsBoolean(args.round, false) | |||
args.amped = aw.getAsBoolean(args.amped, false) | |||
args.forcegunshield = aw.getAsBoolean(args.forcegunshield, false) | |||
args.rarity = args.rarity or 'epic' | |||
args.skullpiercerrarity = args.skullpiercerrarity or 'legendary' | |||
args.shieldpreset = args.shieldpreset or 'reinforcehelmets' | |||
return tostring(renderTable(args)) | return tostring(renderTable(args)) | ||
end | end | ||
174行目: | 1,072行目: | ||
args = getArgs(frame) | args = getArgs(frame) | ||
return p._main(args, frame) | |||
return p._main(args) | |||
end | end | ||
return p | return p |
2022年8月10日 (水) 12:59時点における最新版
このモジュールについての説明文ページを モジュール:DamageTable/doc に作成できます
require('Module:Utility/mw.html Extensions') local p = {} local table = require('Module:TableExtensions') local aw = require('Module:Utility/Library') local apex = require('Module:Utility/ApexLibrary') local Color = require('Module:Color') local STKCalculator = require('Module:Apex/STKCalculator') local getArgs -- lazily initialized local function getShotCount(part, health, shield, info, gunshield) local damages = apex.calcShotCount(info.damage, part, info.mul, health, shield, gunshield or 0, info.opts) return #damages, damages end local function renderHeader(tbl, mul, colspan, shields, res) tbl:tag('tr') :tag('th') :attr('colspan', colspan) :attr('rowspan', 2) :wikitextIf( mul == 1, res.targets.caption, function() return string.format(res.targets.caption_format, mul) end) :done() :tag('th') :attr('rowspan', 2) :wikitext(res.damages.caption) :done() :tag('th') :attr('colspan', #shields) :wikitext(res.shotstokill) local row = tbl:tag('tr') for _, shield in ipairs(shields) do row:tag('th') :attrIf( shield.tooltip ~= nil, { ['data-tooltip'] = shield.tooltip }) :wikitext(shield.label) end end local function renderCell(row, part, health, shield, info, gunshield, rowspan) local shotCount, damages = getShotCount(part, health, shield, info, gunshield) local ratio = (shotCount - info.minCount) / info.diffCount local tooltip = { aw.stringifyRepeatingArray(damages, '→') } if info.ttkCalculator then local template = '<tr><th>%s </th><td class="cell-type-number" style="font-weight:bold">%d</td><td> ミリ秒</td></tr>' local ttkc = info.ttkCalculator local ttk0 = aw.round(1000 * ttkc:getAsLevel(shotCount, 0)) local ttk1 = aw.round(1000 * ttkc:getAsLevel(shotCount, 1)) local ttk2 = aw.round(1000 * ttkc:getAsLevel(shotCount, 2)) local ttk3 = aw.round(1000 * ttkc:getAsLevel(shotCount, 3)) if ttk2 ~= ttk3 then table.insert(tooltip, '<br><br>キルタイム:<table class="condensedtable listtable">') if ttk0 == ttk1 then table.insert(tooltip, string.format(template, 'なし・Lv.1', ttk0)) table.insert(tooltip, string.format(template, 'Lv.2', ttk2)) else table.insert(tooltip, string.format(template, 'なし', ttk0)) table.insert(tooltip, string.format(template, 'Lv.1', ttk1)) table.insert(tooltip, string.format(template, 'Lv.2', ttk2)) end table.insert(tooltip, string.format(template, 'Lv.3', ttk3)) table.insert(tooltip, '</table>') elseif ttk1 ~= ttk2 then table.insert(tooltip, '<br><br>キルタイム:<table class="condensedtable listtable">') if ttk0 == ttk1 then table.insert(tooltip, string.format(template, 'なし・Lv.1', ttk0)) else table.insert(tooltip, string.format(template, 'なし', ttk0)) table.insert(tooltip, string.format(template, 'Lv.1', ttk1)) end table.insert(tooltip, string.format(template, 'Lv.2, 3', ttk2)) table.insert(tooltip, '</table>') elseif ttk0 ~= ttk1 then table.insert(tooltip, '<br><br>キルタイム:<table class="condensedtable listtable">') table.insert(tooltip, string.format(template, 'なし', ttk0)) table.insert(tooltip, string.format(template, 'Lv.1, 2, 3', ttk1)) table.insert(tooltip, '</table>') else table.insert(tooltip, string.format('<br>キルタイム: <span class="text-style-number" style="font-weight:bold">%d</span> ミリ秒', ttk0)) end end local hue = (info.diffCount < 5 and 0.65 or 0.85) * ratio local color = Color.HSL(hue, 0.91, 0.89):toRGB() row:tag('td') :attrIf(rowspan > 1, { rowspan = rowspan }) :attr('data-tooltip', table.concat(tooltip)) :css('background-color', tostring(color)) :wikitext(shotCount) end local function renderHeaderCell(row, name, tooltip, rowinfo) for i = 1, #rowinfo do local cellinfo = rowinfo[i] local colspan = cellinfo.colspan or 1 local rowspan = cellinfo.rowspan or 1 local cell = row:tag('th') if colspan > 1 then cell:attr('colspan', colspan) end if rowspan > 1 then cell:attr('rowspan', rowspan) end if cellinfo.breaktop then cell:css('border-top', '0 none transparent') end if cellinfo.breakbottom then cell:css('border-bottom', '0 none transparent') end --if cellinfo.showbottom then -- cell:css({ -- ['border-bottom-style'] = 'solid', -- ['border-bottom-width'] = '1px', -- }) --end if cellinfo.verticalAlign then cell:css('vertical-align', cellinfo.verticalAlign) end if i == #rowinfo then if tooltip ~= nil then cell:attr('data-tooltip', tooltip) end cell:wikitext(name) elseif cellinfo.content then if cellinfo.vertical then cell:addClass('vertical-cell') :tag('span') :wikitext(cellinfo.content) else cell:wikitext(cellinfo.content) end else cell:wikitext(' ') end end end local function renderRow(tbl, name, tooltip, part, weaponinfo, rowinfo, res, gunshield) local row = tbl:tag('tr') renderHeaderCell(row, name, tooltip, rowinfo) local damage local opts2 = aw.shallowCopy(weaponinfo.opts) table.removeKey(opts2, 'beamdamage') table.removeKey(opts2, 'beamticks') if gunshield then table.removeKey(opts2, 'disruptorRounds') table.removeKey(opts2, 'hammerpointRounds') damage = apex.calcDamage(weaponinfo.damage, 1, 1, opts2) else damage = apex.calcDamage(weaponinfo.damage, part, weaponinfo.mul, opts2) end local text if not gunshield and weaponinfo.opts.disruptorRounds > 1 then local optsD = aw.shallowCopy(weaponinfo.opts) table.removeKey(optsD, 'disruptorRounds') local defaultDamage = apex.calcDamage(weaponinfo.damage, part, weaponinfo.mul, optsD) if weaponinfo.opts.pellets > 1 then text = string.format( res.damages.pelletsWithDisruptor, damage * weaponinfo.opts.pellets, damage, weaponinfo.opts.pellets, defaultDamage * weaponinfo.opts.pellets) else text = string.format(res.damages.disruptor, damage, defaultDamage) end elseif not gunshield and weaponinfo.opts.hammerpointRounds > 1 then local optsH = aw.shallowCopy(weaponinfo.opts) table.removeKey(optsH, 'hammerpointRounds') local defaultDamage = apex.calcDamage(weaponinfo.damage, part, weaponinfo.mul, optsH) if weaponinfo.opts.pellets > 1 then text = string.format( res.damages.pelletsWithHammerpoint, defaultDamage * weaponinfo.opts.pellets, damage * weaponinfo.opts.pellets, damage, weaponinfo.opts.pellets) else text = string.format(res.damages.hammerpoint, defaultDamage, damage) end elseif weaponinfo.opts.pellets > 1 then text = string.format( res.damages.pellets, damage * weaponinfo.opts.pellets, damage, weaponinfo.opts.pellets) elseif weaponinfo.opts.beamticks > 1 then local beamdamage = apex.calcDamageFromPartAndPassive(weaponinfo.opts.beamdamage, part, weaponinfo.mul, opts2) local alldamage = beamdamage * weaponinfo.opts.beamticks + damage text = string.format( res.damages.ticks, alldamage, beamdamage, weaponinfo.opts.beamticks, damage) else text = tostring(damage) end row:tag('td'):wikitext(text) for _, shield in ipairs(weaponinfo.shields) do renderCell(row, part, shield.health, shield.shield, weaponinfo, gunshield, 1) end end local function getTTKCalculator(args) if args.rps <= 0 then return nil end -- 射撃レート local firerate if args.rpsratio1 > 1 then if args.rpsratio2 > args.rpsratio1 then if args.rpsratio3 > args.rpsratio2 then firerate = { args.rps, args.rpsratio1 * args.rps, args.rpsratio2 * args.rps, args.rpsratio3 * args.rps, } else local rps2 = args.rpsratio2 * args.rps firerate = { args.rps, args.rpsratio1 * args.rps, rps2, rps2, } end else local rps1 = args.rpsratio1 * args.rps firerate = { args.rps, rps1, rps1, rps1, } end else firerate = args.rps end -- 装填数 local magazine if args.extmag0 > 0 then if args.extmag1 > args.extmag0 then if args.extmag2 > args.extmag1 then if args.extmag3 > args.extmag2 then magazine = { args.extmag0, args.extmag1, args.extmag2, args.extmag3 } else magazine = { args.extmag0, args.extmag1, args.extmag2, args.extmag2 } end else magazine = { args.extmag0, args.extmag1, args.extmag1, args.extmag1 } end else magazine = args.extmag0 end else magazine = math.huge end -- リロード時間 local reload if args.reloadratio2 > 0 and args.reloadratio2 < 1 then if args.reloadratio3 > 0 and args.reloadratio3 < args.reloadratio2 then if args.reloadratio1 > 0 and args.reloadratio1 < 1 and args.reloadratio1 > args.reloadratio2 then reload = { args.reload, args.reloadratio1 * args.reload, args.reloadratio2 * args.reload, args.reloadratio3 * args.reload } else reload = { args.reload, args.reload, args.reloadratio2 * args.reload, args.reloadratio3 * args.reload } end else local reload2 = args.reloadratio2 * args.reload reload = { args.reload, args.reload, reload2, reload2 } end else reload = args.reload end local ttkc = require('Module:Apex/TTKCalculator').new(firerate, magazine, reload, { raiseTime = args.raise, }) return ttkc end local function getContentLanguage(lang) local language = lang or mw.language.getContentLanguage().code return language == 'en' and 'en' or 'ja' end -- Calc all base damages local function calcBaseDamages(damage, headScale, legsScale, helmets, opts) local headLv1Scale = helmets.level1.func(headScale) local headLv2Scale = helmets.level2.func(headScale) local headLv3Scale = helmets.level3.func(headScale) local ret = { scale_hed0 = headScale, scale_hed1 = headLv1Scale, scale_hed2 = headLv2Scale, scale_hed3 = headLv3Scale, scale_body = 1, scale_legs = legsScale, } if opts.beamdamage > 0 then ret.dschrg_hed0 = aw.round(headScale * opts.beamdamage) ret.dschrg_hed1 = aw.round(headLv1Scale * opts.beamdamage) ret.dschrg_hed2 = aw.round(headLv2Scale * opts.beamdamage) ret.dschrg_hed3 = aw.round(headLv3Scale * opts.beamdamage) ret.dschrg_body = opts.beamdamage if legsScale < 1 then ret.dschrg_legs = aw.round(legsScale * opts.beamdamage) else ret.dschrg_legs = opts.beamdamage end end -- Amped Cover if opts.ampedCover then damage = aw.round(1.2 * damage) end -- Additional Scale if opts.charged > 1 then damage = aw.round(opts.charged * damage) end -- Unshield Scale if opts.hammerpointRounds > 1 then local shieldDamage = damage local unshldDamage = apex.calcHammerpointDamage(damage, opts.hammerpointRounds) -- Passthrough if opts.passthrough < 1 then shieldDamage = apex.calcPassthroughDamage(shieldDamage, opts.passthrough) unshldDamage = apex.calcPassthroughDamage(unshldDamage, opts.passthrough) end local shieldLegs, unshldLegs if legsScale < 1 then shieldLegs = aw.round(legsScale * shieldDamage) unshldLegs = aw.round(legsScale * unshldDamage) else shieldLegs = shieldDamage unshldLegs = unshldDamage end ret.shield_hed0 = aw.round(headScale * shieldDamage) ret.shield_hed1 = aw.round(headLv1Scale * shieldDamage) ret.shield_hed2 = aw.round(headLv2Scale * shieldDamage) ret.shield_hed3 = aw.round(headLv3Scale * shieldDamage) ret.shield_body = shieldDamage ret.shield_legs = shieldLegs ret.unshld_hed0 = aw.round(headScale * unshldDamage) ret.unshld_hed1 = aw.round(headLv1Scale * unshldDamage) ret.unshld_hed2 = aw.round(headLv2Scale * unshldDamage) ret.unshld_hed3 = aw.round(headLv3Scale * unshldDamage) ret.unshld_body = unshldDamage ret.unshld_legs = unshldLegs -- Other else -- Passthrough if opts.passthrough < 1 then damage = apex.calcPassthroughDamage(damage, opts.passthrough) end local legs if legsScale < 1 then legs = aw.round(legsScale * damage) else legs = damage end ret.shield_hed0 = aw.round(headScale * damage) ret.shield_hed1 = aw.round(headLv1Scale * damage) ret.shield_hed2 = aw.round(headLv2Scale * damage) ret.shield_hed3 = aw.round(headLv3Scale * damage) ret.shield_body = damage ret.shield_legs = legs ret.unshld_hed0 = ret.shield_hed0 ret.unshld_hed1 = ret.shield_hed1 ret.unshld_hed2 = ret.shield_hed2 ret.unshld_hed3 = ret.shield_hed3 ret.unshld_body = ret.shield_body ret.unshld_legs = ret.shield_legs end return ret end -- Apply perk/shield scale to damages local function applyPerkAndShieldScaleToDamages(damages, perkScale, ignorePerkScaleForHS, opts) if perkScale ~= 1 then if opts.disruptorRounds > 1 then return table.map(damages, function(key, val) if ignorePerkScaleForHS and (aw.stringstarts(key, 'shield_hed') or aw.stringstarts(key, 'unshld_hed') or aw.stringstarts(key, 'dschrg_hed')) then if aw.stringstarts(key, 'shield_') then return apex.calcDisruptorDamage(val, opts.disruptorRounds) else return val end elseif aw.stringstarts(key, 'shield_') or aw.stringstarts(key, 'unshld_') or aw.stringstarts(key, 'dschrg_') then local perkedDamage = apex.calcPassiveDamage(val, perkScale, { round = opts.round }) if aw.stringstarts(key, 'shield_') then return apex.calcDisruptorDamage(perkedDamage, opts.disruptorRounds) else return perkedDamage end else return val end end) else return table.map(damages, function(key, val) if ignorePerkScaleForHS and (aw.stringstarts(key, 'shield_hed') or aw.stringstarts(key, 'unshld_hed') or aw.stringstarts(key, 'dschrg_hed')) then return val elseif aw.stringstarts(key, 'shield_') or aw.stringstarts(key, 'unshld_') or aw.stringstarts(key, 'dschrg_') then return apex.calcPassiveDamage(val, perkScale, { round = opts.round }) else return val end end) end elseif opts.disruptorRounds > 1 then return table.map(damages, function(key, val) if aw.stringstarts(key, 'shield_') then return apex.calcDisruptorDamage(val, opts.disruptorRounds) else return val end end) else return damages end end -- Compare damage local function equalPartDamage(damages, part0, part1) if damages['dschrg_' .. part0] and damages['dschrg_' .. part1] then return damages['shield_' .. part0] == damages['shield_' .. part1] and damages['unshld_' .. part0] == damages['unshld_' .. part1] and damages['dschrg_' .. part0] == damages['dschrg_' .. part1] else return damages['shield_' .. part0] == damages['shield_' .. part1] and damages['unshld_' .. part0] == damages['unshld_' .. part1] end end -- Render the damage row local function renderRow2(tbl, name, tooltip, damages, partname, weaponinfo, rowinfo, res, rowspan, gunshield) rowspan = rowspan or 1 local scale = damages['scale_' .. partname] local shieldDamage = damages['shield_' .. partname] local unshldDamage = damages['unshld_' .. partname] local dschrgDamage = damages['dschrg_' .. partname] local row = tbl:tag('tr') renderHeaderCell(row, name, tooltip, rowinfo) local text if shieldDamage > unshldDamage then if weaponinfo.opts.pellets > 1 then text = string.format( res.damages.pelletsWithDisruptor, shieldDamage * weaponinfo.opts.pellets, shieldDamage, weaponinfo.opts.pellets, unshldDamage * weaponinfo.opts.pellets) else text = string.format(res.damages.disruptor, shieldDamage, unshldDamage) end elseif shieldDamage < unshldDamage then if weaponinfo.opts.pellets > 1 then text = string.format( res.damages.pelletsWithHammerpoint, shieldDamage * weaponinfo.opts.pellets, unshldDamage * weaponinfo.opts.pellets, unshldDamage, weaponinfo.opts.pellets) else text = string.format(res.damages.hammerpoint, shieldDamage, unshldDamage) end elseif dschrgDamage and weaponinfo.opts.beamticks >= 1 then text = string.format( res.damages.ticks, dschrgDamage * weaponinfo.opts.beamticks + shieldDamage, dschrgDamage, weaponinfo.opts.beamticks, shieldDamage) else if weaponinfo.opts.pellets > 1 then text = string.format( res.damages.pellets, shieldDamage * weaponinfo.opts.pellets, shieldDamage, weaponinfo.opts.pellets) else text = tostring(shieldDamage) end end row:tag('td') :attr('rowspan', rowspan) :wikitext(text) for _, shield in ipairs(weaponinfo.shields) do renderCell(row, scale, shield.health, shield.shield, weaponinfo, gunshield, rowspan) end end -- Render the helmet damage local function renderHelmetSection(tbl, damages, res, weaponinfo, helmets, info) local skipLvl1 = false local skipLvl2 = false local hed1Label = string.format(res.targets.helmet1, damages.scale_hed1) local hed2Label = string.format(res.targets.helmet2, damages.scale_hed2) local hed3Label = string.format(res.targets.helmet3, damages.scale_hed3) local hed1Tooltip = string.format(helmets.level1.text, damages.scale_hed0) local hed2Tooltip = string.format(helmets.level2.text, damages.scale_hed0) local hed3Tooltip = string.format(helmets.level3.text, damages.scale_hed0) if not helmets.level0.disabled then local hed0Rowspan if equalPartDamage(damages, 'hed0', 'hed1') then if equalPartDamage(damages, 'hed0', 'hed2') then if equalPartDamage(damages, 'hed0', 'hed3') then hed0Rowspan = 4 else hed0Rowspan = 3 end else hed0Rowspan = 2 end else hed0Rowspan = 1 end local hed0Label = string.format(res.targets.head_format, damages.scale_hed0) renderRow2(tbl, hed0Label, nil, damages, 'hed0', weaponinfo, info.level1top, res, hed0Rowspan) if hed0Rowspan >= 4 then renderHeaderCell(tbl:tag('tr'), hed1Label, hed1Tooltip, info.level2first) renderHeaderCell(tbl:tag('tr'), hed2Label, hed2Tooltip, info.level2) renderHeaderCell(tbl:tag('tr'), hed3Label, hed3Tooltip, info.level2) return elseif hed0Rowspan == 3 then renderHeaderCell(tbl:tag('tr'), hed1Label, hed1Tooltip, info.level2first) renderHeaderCell(tbl:tag('tr'), hed2Label, hed2Tooltip, info.level2) skipLvl1 = true skipLvl2 = true elseif hed0Rowspan == 2 then renderHeaderCell(tbl:tag('tr'), hed1Label, hed1Tooltip, info.level2first) skipLvl1 = true end end -- Lvl 1 if not skipLvl1 then local hed1Rowspan if equalPartDamage(damages, 'hed1', 'hed2') then if equalPartDamage(damages, 'hed1', 'hed3') then hed1Rowspan = 3 else hed1Rowspan = 2 end else hed1Rowspan = 1 end renderRow2(tbl, hed1Label, hed1Tooltip, damages, 'hed1', weaponinfo, info.level2first, res, hed1Rowspan) if hed1Rowspan >= 3 then renderHeaderCell(tbl:tag('tr'), hed2Label, hed2Tooltip, info.level2) renderHeaderCell(tbl:tag('tr'), hed3Label, hed3Tooltip, info.level2) return elseif hed1Rowspan == 2 then renderHeaderCell(tbl:tag('tr'), hed2Label, hed2Tooltip, info.level2) skipLvl2 = true end end -- Lvl 2 if not skipLvl2 then local hed2Rowspan if equalPartDamage(damages, 'hed2', 'hed3') then hed2Rowspan = 2 else hed2Rowspan = 1 end renderRow2(tbl, hed2Label, hed2Tooltip, damages, 'hed2', weaponinfo, info.level2, res, hed2Rowspan) if hed2Rowspan >= 2 then renderHeaderCell(tbl:tag('tr'), hed3Label, hed3Tooltip, info.level2) return end end -- Lvl 3 renderRow2(tbl, hed3Label, hed3Tooltip, damages, 'hed3', weaponinfo, info.level2, res, 1) end local function renderTable(args) local lang = getContentLanguage(args.lang) local res = mw.loadData('Module:DamageTable/configuration')[lang] local shieldinfo = args.shieldinfo or require('Module:Stat/Shield')[args.shieldpreset] local skullpiercer = args.skullpiercer or 1 local headMul = args.head or 2 local hideNoHelmets = shieldinfo.helmets.level0.disabled local minHead if hideNoHelmets then minHead = shieldinfo.helmets.level1.func(args.headmax) else minHead = args.headmax end if shieldinfo.sameHeadshotDamageToNormalOnFortified then args.mul2 = shieldinfo.fortified end local hasSecond = args.mul2 > 0 and args.mul2 ~= 1 local noLegsShot = args.leg < 0 or args.leg >= 1 or (shieldinfo.legAsBodyOnLowProfile and args.mul > 1) local noLegsShot2 = args.leg < 0 or args.leg >= 1 or (shieldinfo.legAsBodyOnLowProfile and args.mul2 > 1) -- Get/calc min count local minCount if args.mincount > 0 then minCount = args.mincount else minCount, _ = getShotCount( minHead, 100, 0, { damage = math.max(args.damage, args.damagemax), mul = math.max(args.mul, args.mulmax), opts = { ampedCover = true, beamdamage = math.max(args.beamdamage, args.beamdamagemax), beamticks = math.max(args.ticks, args.ticksmax), charged = math.max(args.charged, args.chargedmax), disruptorRounds = math.max(args.disruptor, args.disruptorsup), gunshieldBleedthrough = shieldinfo.gunshieldBleedthrough, hammerpointRounds = math.max(args.hammerpoint, args.hammerpointsup), ignorePassiveForHeadshot = shieldinfo.sameHeadshotDamageToNormalOnFortified, passthrough = 1, pellets = math.max(args.pellet, args.pelletmax), round = args.round, } }) end -- Get/calc max count local maxCount if args.maxcount < 250 then maxCount = args.maxcount else local damagemin = math.min(args.damage, args.damagemin) local mininfo = { damage = damagemin, mul = math.min(args.mul, args.mulmin), opts = { ampedCover = false, beamdamage = math.min(args.beamdamage, args.beamdamagemin), beamticks = math.min(args.ticks, args.ticksmin), charged = 1, disruptorRounds = 1, gunshieldBleedthrough = shieldinfo.gunshieldBleedthrough, hammerpointRounds = 1, ignorePassiveForHeadshot = shieldinfo.sameHeadshotDamageToNormalOnFortified, passthrough = math.min(args.passthrough, args.passthroughsup), pellets = math.min(args.pellet, args.pelletmin), round = args.round, } } local maxshield = shieldinfo.shields[#shieldinfo.shields] local legCount, _ = getShotCount(math.min(args.leg, args.legmin), maxshield.health, maxshield.shield, mininfo) local bodyWithGunSheild, _ = getShotCount(1, maxshield.health, maxshield.shield, mininfo, shieldinfo.gunshield) maxCount = math.max(legCount, bodyWithGunSheild) end local ttkCalculator = getTTKCalculator(args) -- Define weapon info local weaponinfo = { damage = args.damage, mul = args.mul, minCount = minCount, diffCount = maxCount - minCount, shields = shieldinfo.shields, helmets = shieldinfo.helmets, ttkCalculator = ttkCalculator, opts = { ampedCover = args.amped, beamdamage = args.beamdamage, beamticks = args.ticks, charged = args.charged, disruptorRounds = args.disruptor, gunshieldBleedthrough = shieldinfo.gunshieldBleedthrough, hammerpointRounds = args.hammerpoint, ignorePassiveForHeadshot = shieldinfo.sameHeadshotDamageToNormalOnFortified, passthrough = args.passthrough, pellets = args.pellet, round = args.round, }, } local colspan, info if skullpiercer > 1 then colspan = 3 info = { level1 = { { breaktop = false, breakbottom = false, colspan = 3 }, }, level1top = { { breaktop = true, breakbottom = true, colspan = 3 }, }, level1gunshiled = { { breaktop = false, breakbottom = true, colspan = 3 }, }, level2 = { { breaktop = true, breakbottom = false, colspan = 2 }, }, level2gunshiled = { { breaktop = true, breakbottom = false }, { breaktop = false, breakbottom = false, colspan = 2 }, }, level3 = { { breaktop = false, breakbottom = true }, { breaktop = false, breakbottom = false, showbottom = true }, }, level3first = { hideNoHelmets and { breaktop = false, breakbottom = false, rowspan = 6, content = res.targets.head, vertical = res.targets.head_vertical, verticalAlign = res.targets.head_verticalalign } or { breaktop = true, breakbottom = false, rowspan = 6 }, { breaktop = false, breakbottom = true }, { breaktop = false, breakbottom = false, showbottom = true }, }, level3top = { { breaktop = false, breakbottom = true, colspan = 2 }, { breaktop = false, breakbottom = false, showbottom = true }, }, } info.level2first = info.level2 if hasSecond and not noLegsShot2 then info.level1gunshiled = nil info.level2gunshiled = { { breaktop = false, breakbottom = false, rowspan = 3, content = res.targets.fortified, vertical = res.targets.fortified_vertical, verticalAlign = res.targets.fortified_verticalalign }, { breaktop = false, breakbottom = true, colspan = 2 }, } info.level3gunshiled = { { breaktop = true, breakbottom = false }, { breaktop = false, breakbottom = false }, } end elseif hasSecond and not noLegsShot2 then colspan = 3 info = { level1 = { { breaktop = false, breakbottom = false, colspan = 3 }, }, level1top = { { breaktop = false, breakbottom = true, colspan = 3 }, }, level2 = { { breaktop = false, breakbottom = false, colspan = 2 }, }, level2first = { hideNoHelmets and { breaktop = false, breakbottom = false, rowspan = 3, content = res.targets.head, vertical = res.targets.head_vertical, verticalAlign = res.targets.head_verticalalign } or { breaktop = true, breakbottom = false, rowspan = 3 }, { breaktop = false, breakbottom = false, colspan = 2 }, }, level2gunshiled = { { breaktop = false, breakbottom = false, rowspan = 3, content = res.targets.fortified, vertical = res.targets.fortified_vertical, verticalAlign = res.targets.fortified_verticalalign }, { breaktop = false, breakbottom = true, colspan = 2 }, }, level3 = { { breaktop = false, breakbottom = false }, }, level3gunshiled = { { breaktop = true, breakbottom = false }, { breaktop = false, breakbottom = false }, }, } else colspan = 2 info = { level1 = { { breaktop = false, breakbottom = false, colspan = 2 }, }, level1gunshiled = { { breaktop = false, breakbottom = true, colspan = 2 }, }, level2 = { { breaktop = false, breakbottom = false }, }, level2first = { hideNoHelmets and { breaktop = false, breakbottom = false, rowspan = 3, content = res.targets.head, vertical = res.targets.head_vertical, verticalAlign = res.targets.head_verticalalign } or { breaktop = true, breakbottom = false, rowspan = 3 }, { breaktop = false, breakbottom = false }, }, level2gunshiled = { { breaktop = true, breakbottom = false }, { breaktop = false, breakbottom = false }, }, } info.level1top = info.level1gunshiled end local table = mw.html.create('table') :addClass('wikitable') :addClass('numbertable') :addClass('damagetable') if args.caption ~= nil then table:tag('caption') :wikitext(args.caption) end local baseDamages = calcBaseDamages(weaponinfo.damage, headMul, args.leg, weaponinfo.helmets, weaponinfo.opts) local perkedDamages = applyPerkAndShieldScaleToDamages(baseDamages, weaponinfo.mul, shieldinfo.sameHeadshotDamageToNormalOnFortified, weaponinfo.opts) renderHeader(table, args.mul, colspan, shieldinfo.shields, res) -- Headshot damage if headMul > 1 then -- w/Skullpiercer Rifling if skullpiercer > 1 then if not hideNoHelmets then renderRow( table, string.format(res.targets.skullpiercer0, args.skullpiercerrarity, skullpiercer), nil, skullpiercer, weaponinfo, info.level3top, res) renderRow2( table, string.format(res.targets.head_format, perkedDamages.scale_hed0), nil, perkedDamages, 'hed0', weaponinfo, info.level1top, res) end local skullpiercerLv1Mul = shieldinfo.helmets.level1.func(skullpiercer) renderRow( table, string.format(res.targets.skullpiercer1, args.skullpiercerrarity, skullpiercerLv1Mul), string.format(shieldinfo.helmets.level1.text, skullpiercer), skullpiercerLv1Mul, weaponinfo, info.level3first, res) renderRow2( table, string.format(res.targets.helmet1, perkedDamages.scale_hed1), string.format(shieldinfo.helmets.level1.text, headMul), perkedDamages, 'hed1', weaponinfo, info.level2first, res) local skullpiercerLv2Mul = shieldinfo.helmets.level2.func(skullpiercer) renderRow( table, string.format(res.targets.skullpiercer2, args.skullpiercerrarity, skullpiercerLv2Mul), string.format(shieldinfo.helmets.level2.text, skullpiercer), skullpiercerLv2Mul, weaponinfo, info.level3, res) renderRow2( table, string.format(res.targets.helmet2, perkedDamages.scale_hed2), string.format(shieldinfo.helmets.level2.text, headMul), perkedDamages, 'hed2', weaponinfo, info.level2, res) local skullpiercerLv3Mul = shieldinfo.helmets.level3.func(skullpiercer) renderRow( table, string.format(res.targets.skullpiercer3, args.skullpiercerrarity, skullpiercerLv3Mul), string.format(shieldinfo.helmets.level3.text, skullpiercer), skullpiercerLv3Mul, weaponinfo, info.level3, res) renderRow2( table, string.format(res.targets.helmet3, perkedDamages.scale_hed3), string.format(shieldinfo.helmets.level3.text, headMul), perkedDamages, 'hed3', weaponinfo, info.level2, res) -- w/o Skullpiercer Rifling else renderHelmetSection(table, perkedDamages, res, weaponinfo, shieldinfo.helmets, info) end end -- Body shot damage local label if headMul <= 1 then if noLegsShot then label = res.targets.all else label = res.targets.headbody end elseif noLegsShot then label = res.targets.bodylegs else label = res.targets.body end if args.mul < 1 or args.forcegunshield then renderRow2(table, label, nil, perkedDamages, 'body', weaponinfo, info.level1gunshiled, res) renderRow( table, res.targets.gunshield, shieldinfo.gunshieldLabel, 1, weaponinfo, info.level2gunshiled, res, shieldinfo.gunshield) else renderRow2(table, label, nil, perkedDamages, 'body', weaponinfo, info.level1, res) end -- Legs shot damage if not noLegsShot then local legsLabel = string.format(res.targets.legs, args.leg) renderRow2(table, legsLabel, nil, perkedDamages, 'legs', weaponinfo, info.level1, res) end -- the 2nd place of damages if hasSecond then local rowinfoSecondTop, rowinfoSecondGunShield, label2 if not noLegsShot2 then rowinfoSecondTop = info.level2gunshiled rowinfoSecondGunShield = info.level3gunshiled label2 = label elseif args.mul2 < 1 then rowinfoSecondTop = info.level1gunshiled rowinfoSecondGunShield = info.level2gunshiled label2 = string.format(res.targets.fortified_prefix, args.mul2, label) else rowinfoSecondTop = info.level1 rowinfoSecondGunShield = nil label2 = string.format(res.targets.fortified_prefix, args.mul2, label) end local weaponinfo2 = aw.shallowCopy(weaponinfo) weaponinfo2.mul = args.mul2 local perkedDamages2 = applyPerkAndShieldScaleToDamages(baseDamages, weaponinfo2.mul, shieldinfo.sameHeadshotDamageToNormalOnFortified, weaponinfo2.opts) if args.mul2 < 1 then renderRow2(table, label2, nil, perkedDamages2, 'body', weaponinfo2, rowinfoSecondTop, res) renderRow( table, res.targets.gunshield, shieldinfo.gunshieldLabel, 1, weaponinfo2, rowinfoSecondGunShield, res, shieldinfo.gunshield) else renderRow2(table, label2, nil, perkedDamages2, 'body', weaponinfo2, info.level2, res) end -- Legs shot damage if not noLegsShot2 then local legsLabel = string.format(res.targets.legs, args.leg) renderRow2(table, legsLabel, nil, perkedDamages2, 'legs', weaponinfo2, info.level2, res) end end return table end function p._main(args, frame) -- init value local initValues = { mincount = 0, maxcount = 250, damage = 20, damagemin = 1000, damagemax = 0, beamdamage = 0, beamdamagemin = 0, beamdamagemax = 0, ticks = 0, ticksmin = math.huge, ticksmax = 0, pellet = 1, pelletmin = 0, pelletmax = 0, head = 2, headmax = -1, leg = 0.8, legmin = 0, mul = 1, mul2 = 0, mulmin = 0.85, mulmax = 1, charged = 1, chargedmax = 1, skullpiercer = 1, disruptor = 1, disruptorsup = 1, hammerpoint = 1, hammerpointsup = 1, passthrough = 1, passthroughsup = 1, rps = 0, rpsratio1 = 0, rpsratio2 = 0, rpsratio3 = 0, raise = 0, reload = 0, reloadratio1 = 0.963, reloadratio2 = 0.933, reloadratio3 = 0.9, extmag0 = 0, extmag1 = 0, extmag2 = 0, extmag3 = 0, } -- fix arguments for key, value in pairs(initValues) do args[key] = aw.getAsNumber(args[key], value) end if args.pelletmin == 0 then args.pelletmin = args.pellet end if args.pelletmax == 0 then args.pelletmax = args.pellet end if args.headmax == -1 then args.headmax = math.max(args.head, args.skullpiercer) end if args.legmin == 0 then args.legmin = args.leg end if args.beamdamagemin == 0 then args.beamdamagemin = args.beamdamage end if args.beamdamagemax == 0 then args.beamdamagemax = args.beamdamage end args.round = aw.getAsBoolean(args.round, false) args.amped = aw.getAsBoolean(args.amped, false) args.forcegunshield = aw.getAsBoolean(args.forcegunshield, false) args.rarity = args.rarity or 'epic' args.skullpiercerrarity = args.skullpiercerrarity or 'legendary' args.shieldpreset = args.shieldpreset or 'reinforcehelmets' return tostring(renderTable(args)) end function p.main(frame) if not getArgs then getArgs = require('Module:Arguments').getArgs end args = getArgs(frame) return p._main(args, frame) end return p