🌟現在、鉄壁 鉄壁ヘッドショットには対応済みです。
鉄壁HSは通常HSと同じダメージになります。LMG及びDMR、チャージライフル、ハンマーポイント弾を除き、すべてのダメージ値が一致していることを確認しています。

「モジュール:MultipleStatTable」の版間の差分

提供:Apex Data
ナビゲーションに移動 検索に移動
(武器リンクの空文字判定の改善)
(可変レート武器における最高速スタートのTTKが表示されていない不具合の修正)
 
(同じ利用者による、間の38版が非表示)
7行目: 7行目:
local iu = require('Module:Utility/Image')
local iu = require('Module:Utility/Image')
local nu = require('Module:Utility/Name')
local nu = require('Module:Utility/Name')
local inu = require('Module:Utility/ImageWithName')
local Hopup = mw.loadData('Module:Stat/Hopup')
local formatter -- lazily initialized
local formatter -- lazily initialized
local getArgs -- lazily initialized
local getArgs -- lazily initialized
17行目: 21行目:
end
end
cache.moddedLoader = formatter:hopup('改造ローダー') .. ' <span class="text-desktoponly">改造ローダー</span>'
cache.moddedLoader = iu.passive('modded_loader') .. ' <span class="text-desktoponly">改造ローダー</span>'
return cache.moddedLoader
return cache.moddedLoader
end
end
28行目: 32行目:
cache.ampedMode = iu.item('シールドセル') .. ' <span class="text-desktoponly">増幅モード</span>'
cache.ampedMode = iu.item('シールドセル') .. ' <span class="text-desktoponly">増幅モード</span>'
return cache.ampedMode
return cache.ampedMode
end
local function getRevvedUpMode()
if cache.revvedUpMode then
return cache.revvedUpMode
end
cache.revvedUpMode = iu.grenade('テルミットグレネード') .. ' <span class="text-desktoponly">連射速度上昇モード</span>'
return cache.revvedUpMode
end
local function getDisruptorRounds()
if cache.disruptorRounds then
return cache.disruptorRounds
end
cache.disruptorRounds = inu.hopup('disruptor_rounds', { desktopOnly = true })
return cache.disruptorRounds
end
end


35行目: 57行目:
end
end
cache.hammerpointRounds = iu.hopup('ハンマーポイント弾') .. ' [[ホップアップによる武器一覧#ハンマーポイント弾|' .. formatter:epic('ハンマーポイント弾', 'text-desktoponly') .. ']]'
cache.hammerpointRounds = inu.hopup('hammerpoint_rounds', { desktopOnly = true })
return cache.hammerpointRounds
return cache.hammerpointRounds
end
local function getShatterCaps()
if cache.shatterCaps then
return cache.shatterCaps
end
cache.shatterCaps = inu.hopup('shatter_caps', { desktopOnly = true })
return cache.shatterCaps
end
local function getDeadeyesTempo()
if cache.deadeyesTempo then
return cache.deadeyesTempo
end
cache.deadeyesTempo = inu.hopup('deadeyes_tempo', { desktopOnly = true })
return cache.deadeyesTempo
end
end


44行目: 84行目:
end
end
cache.anvilReceiver = iu.hopup('アンビルレシーバー') .. ' [[ホップアップによる武器一覧#アンビルレシーバー|' .. formatter:legendary('アンビルレシーバー', 'text-desktoponly') .. ']]'
cache.anvilReceiver = inu.hopup('anvil_receiver', { desktopOnly = true })
return cache.anvilReceiver
return cache.anvilReceiver
end
end
53行目: 93行目:
end
end
cache.turbocharger = iu.hopup('ターボチャージャー') .. ' [[ホップアップによる武器一覧#ターボチャージャー|' .. formatter:legendary('ターボチャージャー', 'text-desktoponly') .. ']]'
cache.turbocharger = inu.hopup('turbocharger', { desktopOnly = true })
return cache.turbocharger
return cache.turbocharger
end
end


local function getCharged()
local function getBoostedLoader()
if cache.charged then
if cache.boostedLoader then
return cache.charged
return cache.boostedLoader
end
end
cache.charged = iu.scope('スロット') .. ' <span class="text-desktoponly">フルチャージ</span>'
cache.boostedLoader = inu.hopup('boosted_loader', { desktopOnly = true })
return cache.charged
return cache.boostedLoader
end
end


69行目: 109行目:
if not force and level == 0 then
if not force and level == 0 then
return ''
return ''
end
if aw.stringstarts(ammo, 'special_') then
ammo = string.sub(ammo, 9)
end
end
76行目: 120行目:
if cache[ammo] and cache[ammo][1 + level] then
if cache[ammo] and cache[ammo][1 + level] then
return cache[ammo][1 + level]
return cache[ammo][1 + level]
end
local footer
if level == 0 then
footer = 'なし'
else
footer = ' - レベル' .. level
end
end
if ammo == 'shotgun' then
if ammo == 'shotgun' then
cache[ammo][1 + level] = iu.attachment(nu.bolt('ja'), level) .. ' ' .. formatter:level(level, nu.bolt() .. footer, 'text-desktoponly')
cache[ammo][1 + level] = inu.bolt(level, { desktopOnly = true })
else
else
cache[ammo][1 + level] = iu.attachment(nu.extmag(ammo, 'ja'), level) .. ' ' .. formatter:level(level, nu.extmag(ammo) .. footer, 'text-desktoponly')
cache[ammo][1 + level] = inu.extmag(ammo, level, { desktopOnly = true })
end
end
return cache[ammo][1 + level]
return cache[ammo][1 + level]
end
end


local getEmphasizableText = aw.getEmphasizableTextFunc('%s', '<span class="text-desktoponly">%s</span>', '<span class="text-desktoponly">%s</span>')
local function getWeaponLink(name, ammo, shortname)
local function getWeaponLink(name, ammo, shortname)
local classSuffix = aw.stringstarts(ammo, 'special_') and 'special' or ammo
local classSuffix = aw.stringstarts(ammo, 'special_') and 'special' or ammo
local suitableName = string.gsub(
local suitableName = getEmphasizableText(name, shortname)
name,
'(.*)' .. string.gsub(shortname, '-', '%%-')  .. '(.*)',
function(prefix, suffix)
if prefix ~= '' then
if suffix ~= '' then
return string.format('<span class="text-desktoponly">%s</span>%s<span class="text-desktoponly">%s</span>', prefix, shortname, suffix)
else
return string.format('<span class="text-desktoponly">%s</span>%s', prefix, shortname)
end
else
if suffix ~= '' then
return string.format('%s<span class="text-desktoponly">%s</span>', shortname, suffix)
else
return shortname
end
end
end)
return string.format('[[%s|<span class="text-ammo-%s">%s</span>]]', name, classSuffix, suitableName)
return string.format('[[%s|<span class="text-ammo-%s">%s</span>]]', name, classSuffix, suitableName)
end
end
-- [[ 設定 ]]
local columns = { '通常', '鉄壁', '+ガンシールド' }
local columnCount = #columns
local config = {
-- 通常
{
gunshield = 0,
passive = 1,
},
-- 小柄
--{
-- gunshield = 0,
-- passive = 1.05,
--},
-- 鉄壁
{
gunshield = 0,
passive = 0.85,
},
-- +ガンシールド
{
gunshield = 50,
passive = 0.85,
},
}


-- [[ テーブル生成 ]]
-- [[ テーブル生成 ]]
145行目: 195行目:
local tbl = mw.html.create('table')
local tbl = mw.html.create('table')
:addClass('wikitable')
:addClass('graphtable')
:addClass('numbertable')
:addClass('numbertable')
:addClass('stattable')
:addClass('st')
:addClass('sortable')
:addClass('sortable')
local header = tbl:tag('tr')
local header = tbl:tag('tr')
:addClass('row-sticky')
:addClass('row-sticky')
:tag('th')
:tag('th')
:addClass('stattable-cell-header')
:addClass('st-desktop')
:addClass('stattable-cell-header-ammo')
:css('width', '36px')
:done()
:done()
:tag('th')
:tag('th')
:addClass('stattable-cell-header')
:addClass('st-mobile-first')
:addClass('stattable-cell-header-name')
:attrIf(slots > 2, { colspan = slots - 1 })
:attrIf(slots > 2, { colspan = slots - 1 })
:wikitext('武器名')
:wikitext('武器名')
164行目: 211行目:
for _, item in ipairs(headers) do
for _, item in ipairs(headers) do
header:tag('th')
header:tag('th')
:addClass('graphtable-cell-header')
:css('min-width', '60px')
:addClass('graphtable-cell-header-both')
:addClass('stattable-cell-header')
:addClass('stattable-cell-header-value')
:wikitext(item)
:wikitext(item)
end
end
185行目: 229行目:
if slots > 1 then
if slots > 1 then
for i = 1, slots do
for i = 1, slots do
local classname
if i == 1 then
classname = 'st-desktop'
elseif i == 2 then
classname = 'st-mobile-first st-dashed-right st-mobile-none-right st-mobile-padding0-right'
elseif i == slots then
classname = 'st-dashed-left st-mobile-none-left st-mobile-padding0-both'
else
classname = 'st-dashed-both st-mobile-none-both st-mobile-padding0-both'
end
row:tag('td')
row:tag('td')
:addClass('stattable-cell')
:addClass(classname)
:addClassIf(i == 1, 'stattable-cell-name')
:attrIf(i == 1, { align = 'center' })
:addClassIf(i > 1, 'stattable-cell-attachment')
:addClassIf(i == slots, 'stattable-cell-attachment-last')
:wikitext(obj[i])
:wikitext(obj[i])
:attr('align', 'left')
:attr('align', 'left')
195行目: 248行目:
else
else
row:tag('td')
row:tag('td')
:addClass('stattable-cell')
:addClass('stattable-cell-name')
:wikitext(obj.name)
:wikitext(obj.name)
:attr('align', 'left')
:attr('align', 'left')
205行目: 256行目:
local graph = string.format('linear-gradient(to right, #A7D7F9 %s%%, transparent %s%%)', percentage, percentage)
local graph = string.format('linear-gradient(to right, #A7D7F9 %s%%, transparent %s%%)', percentage, percentage)
row:tag('td')
row:tag('td')
:addClass('graphtable-cell')
:addClass('st-graph')
:addClass('graphtable-cell-both')
:addClass('st-textshadow')
:addClass('stattable-cell')
:addClass('st-line')
:addClass('stattable-cell-value')
:addClass('st-line-h12')
:attr('align', 'right')
:attr('align', 'right')
:css('background-image', graph .. ' !important')
:css('background-image', graph .. ' !important')
235行目: 286行目:


-- [[ キルタイム ]]
-- [[ キルタイム ]]
local function getTTKs(stat, mode, opts, health, shield, STKCalculator, TTKCalculator)
local function getSTKs(stat, opts, health, shield, STKCalculator)
local ret = {}
local stkc = STKCalculator.newFromStat(stat, opts)
local stkc = STKCalculator.newFromStat(stat, opts)
stkc:calcShotToKill(health, shield, 0, 1)
for passive = 1, #config do
local stkNormal = stkc:get()
local c = config[passive]
stkc:reset()
stkc:calcShotToKill(health, shield, c.gunshield, c.passive)
stkc:calcShotToKill(health, shield, 0, 1.05)
table.insert(ret, stkc:get())
local stkLowProfile = stkc:get()
stkc:reset()
stkc:reset()
end
stkc:calcShotToKill(health, shield, 0, 0.85)
return ret
local stkFortified = stkc:get()
end
 
local ttkc = TTKCalculator.newFromStat(stat, mode, opts)
local function getTTKs(stat, stks, opts, TTKCalculator)
return {
local ttkc = TTKCalculator.newFromStat(stat, opts)
{
local ret = {}
ttkc:getAsLevel(stkNormal, 0),
for _, stk in ipairs(stks) do
ttkc:getAsLevel(stkNormal, 1),
local obj = {
ttkc:getAsLevel(stkNormal, 2),
ttkc:getAsLevel(stk, 0),
ttkc:getAsLevel(stkNormal, 3),
ttkc:getAsLevel(stk, 1),
},
ttkc:getAsLevel(stk, 2),
{
ttkc:getAsLevel(stk, 3),
ttkc:getAsLevel(stkLowProfile, 0),
}
ttkc:getAsLevel(stkLowProfile, 1),
table.insert(ret, obj)
ttkc:getAsLevel(stkLowProfile, 2),
end
ttkc:getAsLevel(stkLowProfile, 3),
return ret
},
{
ttkc:getAsLevel(stkFortified, 0),
ttkc:getAsLevel(stkFortified, 1),
ttkc:getAsLevel(stkFortified, 2),
ttkc:getAsLevel(stkFortified, 3),
},
}
end
end


local function isDiffTTKs(ttks, a, b)
local function isDiffTTKs(ttks, a, b)
return 0.0001 * aw.round(10000 * ttks[1][a]) ~= 0.0001 * aw.round(10000 * ttks[1][b])
for passive = 1, columnCount do
or 0.0001 * aw.round(10000 * ttks[2][a]) ~= 0.0001 * aw.round(10000 * ttks[2][b])
if 0.0001 * aw.round(10000 * ttks[passive][a]) ~= 0.0001 * aw.round(10000 * ttks[passive][b]) then
or 0.0001 * aw.round(10000 * ttks[3][a]) ~= 0.0001 * aw.round(10000 * ttks[3][b])
return true
end
end
return false
end
end


local function compareTTKs(ttks1, ttks2)
local function compareTTKs(ttks1, ttks2)
for passive = 1, 3 do
for passive = 1, columnCount do
for level = 1, 4 do
for level = 1, 4 do
local ttk1 = 0.0001 * aw.round(10000 * ttks1[passive][level])
local ttk1 = 0.0001 * aw.round(10000 * ttks1[passive][level])
289行目: 336行目:


local function repackTTKs(ttks, level)
local function repackTTKs(ttks, level)
return {
local ret = {}
ttks[1][level],
for _, ttk in ipairs(ttks) do
ttks[2][level],
table.insert(ret, ttk[level])
ttks[3][level],
end
}
return ret
end
end


395行目: 442行目:
local TTKCalculator = require('Module:Apex/TTKCalculator')
local TTKCalculator = require('Module:Apex/TTKCalculator')
local tbl = createStatTable('キルタイム [s]', 4, { '通常', '小柄', '鉄壁' }, function(data, name, stat)
local tbl = createStatTable('キルタイム [s]', 4, columns, function(data, name, stat)
if stat.time == nil or stat.time.reload == nil then
if stat.time == nil or (not aw.isNumber(stat.time.reloadempty or stat.time.reload)) then
return
return
end
end
403行目: 450行目:
local ammoname = iu.ammo(ammo, { size = 20 })
local ammoname = iu.ammo(ammo, { size = 20 })
local basename = getWeaponLink(name, ammo, stat.localization['Japanese_Short'])
local basename = getWeaponLink(name, ammo, stat.localization['Japanese_Short'])
if stat.mode.burst > 1 then
local special  = aw.stringstarts(ammo, 'special_')
if stat.mode.auto then
local stks = getSTKs(stat, opts, args.health, args.shield, STKCalculator)
local ttks = getTTKs(stat, TTKCalculator.AUTO, opts, args.health, args.shield, STKCalculator, TTKCalculator)
local ttks = getTTKs(stat, stks, opts, TTKCalculator)
addFromTTKs(ammo, data, ammoname, basename .. ' (オート)', '', ttks)
if not stat.attachments.disruptor_rounds_only then
addFromTTKs(ammo, data, ammoname, basename, '', ttks)
end
-- ライトマシンガン (ディヴォーションLMG・M600スピットファイア・L-スターEMG)
if stat.category == 'light_machine_gun' then
local opts2 = aw.shallowCopy(opts)
opts2.useModdedLoader = true
local ttks2 = getTTKs(stat, stks, opts2, TTKCalculator)
if not compareTTKs(ttks, ttks2) then
addFromTTKs(ammo, data, ammoname, basename, getModdedLoader(), ttks2)
end
end
if stat.altfire and aw.isNumber(stat.altfire.firerate) and stat.altfire.firerate ~= stat.firerate then
local altname
if stat.altfire.is_semi_auto or stat.is_semi_auto then
altname = basename .. ' (単発)'
else
else
local ttks = getTTKs(stat, TTKCalculator.SINGLE, opts, args.health, args.shield, STKCalculator, TTKCalculator)
altname = basename .. ' (オート)'
addFromTTKs(ammo, data, ammoname, basename .. ' (単発)', '', ttks)
end
end
local ttks = getTTKs(stat, TTKCalculator.BURST, opts, args.health, args.shield, STKCalculator, TTKCalculator)
local altopts = aw.shallowCopy(opts)
addFromTTKs(ammo, data, ammoname, basename .. ' (バースト)', '', ttks)
altopts.useAltfire = true
else
local mode = stat.mode.auto and TTKCalculator.AUTO or TTKCalculator.SINGLE
local ttks = getTTKs(stat, stks, altopts, TTKCalculator)
local ttks = getTTKs(stat, mode, opts, args.health, args.shield, STKCalculator, TTKCalculator)
addFromTTKs(ammo, data, ammoname, altname, '', ttks)
addFromTTKs(ammo, data, ammoname, basename, '', ttks)
-- ブーステッドローダー (ヘムロックバーストAR)
if Hopup.boosted_loader.enabled and stat.boosted_loader and type(stat.boosted_loader.magazine) == 'table' then
altopts.useBoostedLoader = true
local burstttks2 = getTTKs(stat, stks, altopts, TTKCalculator)
addFromTTKs(ammo, data, ammoname, altname, getBoostedLoader(), burstttks2)
end
end
-- 最高速から
local ttksmax = nil
if aw.isNumberAndGreaterThanZero(stat.firerate_maximum_duration) then
local maxname = basename .. ' (最高速)'
local opts2 = aw.shallowCopy(opts)
opts2.startMaximum = true
ttksmax = getTTKs(stat, stks, opts2, TTKCalculator)
addFromTTKs(ammo, data, ammoname, maxname, '', ttksmax)
-- ライトマシンガン (ディヴォーションLMG・M600スピットファイア・L-スターEMG)
if stat.category == 'light_machine_gun' then
if stat.category == 'light_machine_gun' then
local opts2 = aw.shallowCopy(opts)
local opts3 = aw.shallowCopy(opts2)
opts2.useModdedLoader = true
opts3.useModdedLoader = true
local ttks2 = getTTKs(stat, TTKCalculator.AUTO, opts2, args.health, args.shield, STKCalculator, TTKCalculator)
local ttks3 = getTTKs(stat, stks, opts3, TTKCalculator)
if not compareTTKs(ttks, ttks2) then
if not compareTTKs(ttksmax, ttks3) then
addFromTTKs(ammo, data, ammoname, basename, getModdedLoader(), ttks2)
addFromTTKs(ammo, data, ammoname, maxname, getModdedLoader(), ttks3)
end
end
end
end
-- センチネルの増幅モード
if aw.isNumberAndGreaterThanZero(stat.damage.amped) then
local ampedammoname = iu.ammo(ammo .. '_amped', { size = 20 })
local ampedname = string.format('%s (%s)', basename, getAmpedMode())
local opts2 = aw.shallowCopy(opts)
opts2.useAmpedMode = true
local stksAmped = getSTKs(stat, opts2, args.health, args.shield, STKCalculator)
local ttksAmped = getTTKs(stat, stksAmped, opts2, TTKCalculator)
if not compareTTKs(ttks, ttksAmped) then
addFromTTKs(ammo, data, ampedammoname, ampedname, '', ttksAmped)
end
end
-- センチネルの増幅モード
-- デッドアイズテンポ
if aw.isNumberAndGreaterThanZero(stat.damage.amped) then
if Hopup.deadeyes_tempo.enabled and stat.deadeyes_tempo then
local opts2 = aw.shallowCopy(opts)
opts2.useDeadeyesTempo = true
opts2.useAmpedMode = true
local ttksTempo = getTTKs(stat, stksAmped, opts2, TTKCalculator)
local ttks2 = getTTKs(stat, TTKCalculator.SINGLE, opts2, args.health, args.shield, STKCalculator, TTKCalculator)
if not compareTTKs(ttksAmped, ttksTempo) then
if not compareTTKs(ttks, ttks2) then
addFromTTKs(ammo, data, ampedammoname, ampedname, getDeadeyesTempo(), ttksTempo)
addFromTTKs(ammo, data, ammoname, basename, getAmpedMode(), ttks2)
end
-- 最高速
if aw.isNumberAndGreaterThanOrEqualToX(stat.deadeyes_tempo.firerate_maximum_count, 1) then
local ampedmaxname = string.format('%s (最高速・%s)', basename, getAmpedMode())
opts2.startMaximum = true
local stksTempoMax = getSTKs(stat, opts2, args.health, args.shield, STKCalculator)
local ttksTempoMax = getTTKs(stat, stksTempoMax, opts2, TTKCalculator)
addFromTTKs(ammo, data, ampedammoname, ampedmaxname, getDeadeyesTempo(), ttksTempoMax)
end
end
end
end
end
-- ランページの連射速度上昇モード
if aw.isNumberAndGreaterThanZero(stat.firerate_revvedup) then
local revvedupammoname = iu.ammo(ammo .. '_revved_up', { size = 20 })
local revvedupname = string.format('%s (%s)', basename, getRevvedUpMode())
local opts2 = aw.shallowCopy(opts)
opts2.useRevvedUpMode = true
local ttksRevvedUp = getTTKs(stat, stks, opts2, TTKCalculator)
addFromTTKs(ammo, data, revvedupammoname, revvedupname, '', ttksRevvedUp)
end
-- フルチャージ (30-30リピーター・ボセックコンパウンドボウ)
if aw.isNumberAndGreaterThanZero(stat.damage.charged) then
local chargedname = basename .. ' (最大溜め)'
local opts2 = aw.shallowCopy(opts)
opts2.useCharged = true
local stks2 = getSTKs(stat, opts2, args.health, args.shield, STKCalculator)
local ttks2 = getTTKs(stat, stks2, opts2, TTKCalculator)
addFromTTKs(ammo, data, ammoname, chargedname, '', ttks2)
-- 30-30リピーターのフルチャージ
-- デッドアイズテンポ
if aw.isNumberAndGreaterThanZero(stat.damage.charged) then
if Hopup.deadeyes_tempo.enabled and stat.deadeyes_tempo then
local opts2 = aw.shallowCopy(opts)
opts2.useDeadeyesTempo = true
opts2.useAmpedMode = true
local ttksTempo = getTTKs(stat, stks2, opts2, TTKCalculator)
local ttks2 = getTTKs(stat, TTKCalculator.SINGLE, opts2, args.health, args.shield, STKCalculator, TTKCalculator)
addFromTTKs(ammo, data, ammoname, chargedname, getDeadeyesTempo(), ttksTempo)
addFromTTKs(ammo, data, ammoname, basename, getCharged(), ttks2)
-- 最高速
if aw.isNumberAndGreaterThanOrEqualToX(stat.deadeyes_tempo.firerate_maximum_count, 1) then
local chargedmaxname = basename .. ' (最高速・最大溜め)'
opts2.startMaximum = true
local stksTempoMax = getSTKs(stat, opts2, args.health, args.shield, STKCalculator)
local ttksTempoMax = getTTKs(stat, stksTempoMax, opts2, TTKCalculator)
addFromTTKs(ammo, data, ammoname, chargedmaxname, getDeadeyesTempo(), ttksTempoMax)
end
end
end
end
-- ディスラプター弾 (オルタネーターSMG・RE-45オート)
if (Hopup.disruptor_rounds.enabled or special) and aw.isNumber(stat.damage.disruptor_rounds) and stat.damage.disruptor_rounds > 1 then
local opts2 = aw.shallowCopy(opts)
opts2.useDisruptorRounds  = true
local stks2 = getSTKs(stat, opts2, args.health, args.shield, STKCalculator)
local ttks2 = getTTKs(stat, stks2, opts2, TTKCalculator)
addFromTTKs(ammo, data, ammoname, basename, getDisruptorRounds(), ttks2)
end
-- ハンマーポイント弾 (モザンビーク・P2020)
if Hopup.hammerpoint_rounds.enabled and aw.isNumber(stat.damage.hammerpoint_rounds) and stat.damage.hammerpoint_rounds > 1 then
local opts2 = aw.shallowCopy(opts)
opts2.useHammerpointRounds = true
local stks2 = getSTKs(stat, opts2, args.health, args.shield, STKCalculator)
local ttks2 = getTTKs(stat, stks2, opts2, TTKCalculator)
addFromTTKs(ammo, data, ammoname, basename, getHammerpointRounds(), ttks2)
end
-- アンビルレシーバー (VK-47フラットライン・R-301カービン)
if Hopup.anvil_receiver.enabled and stat.anvil_receiver then
local opts2 = aw.shallowCopy(opts)
opts2.useAnvilReceiver = true
local stks2 = getSTKs(stat, opts2, args.health, args.shield, STKCalculator)
local ttks2 = getTTKs(stat, stks2, opts2, TTKCalculator)
addFromTTKs(ammo, data, ammoname, basename, getAnvilReceiver(), ttks2)
end
-- ブーステッドローダー (ヘムロックバーストAR・ウィングマン)
if Hopup.boosted_loader.enabled and stat.boosted_loader and type(stat.boosted_loader.magazine) == 'table' then
local opts2 = aw.shallowCopy(opts)
opts2.useBoostedLoader = true
local ttks2 = getTTKs(stat, stks, opts2, TTKCalculator)
addFromTTKs(ammo, data, ammoname, basename, getBoostedLoader(), ttks2)
end
-- シャッターキャップ (30-30リピーター・ボセックコンポウンドボウ)
if Hopup.shatter_caps.enabled and stat.shatter_caps then
local label = getShatterCaps()
local opts2 = aw.shallowCopy(opts)
opts2.useShatterCaps = true
local stks2 = getSTKs(stat, opts2, args.health, args.shield, STKCalculator)
local ttks2 = getTTKs(stat, stks2, opts2, TTKCalculator)
addFromTTKs(ammo, data, ammoname, basename, label, ttks2)
-- ハンマーポイント弾 (モザンビーク・P2020)
if aw.isNumberAndGreaterThanZero(stat.shatter_caps.damage.charged) then
if aw.isNumber(stat.damage.hammerpoint_rounds) and stat.damage.hammerpoint_rounds > 1 then
local chargedname = basename .. ' (最大溜め)'
local opts2 = aw.shallowCopy(opts)
opts2.useCharged = true
opts2.useHammerpointRounds = true
local stks3 = getSTKs(stat, opts2, args.health, args.shield, STKCalculator)
local ttks = getTTKs(stat, TTKCalculator.SINGLE, opts2, args.health, args.shield, STKCalculator, TTKCalculator)
local ttks3 = getTTKs(stat, stks3, opts2, TTKCalculator)
addFromTTKs(ammo, data, ammoname, basename, getHammerpointRounds(), ttks)
addFromTTKs(ammo, data, ammoname, chargedname, label, ttks3)
-- デッドアイズテンポ (ボセックコンパウンドボウ)
if Hopup.deadeyes_tempo.enabled and stat.deadeyes_tempo then
label = label .. '<br>' .. getDeadeyesTempo()
opts2.useDeadeyesTempo = true
local ttksTempo = getTTKs(stat, stks3, opts2, TTKCalculator)
addFromTTKs(ammo, data, ammoname, chargedname, label, ttksTempo)
-- 最高速
if aw.isNumberAndGreaterThanOrEqualToX(stat.deadeyes_tempo.firerate_maximum_count, 1) then
local chargedmaxname = basename .. ' (最高速・最大溜め)'
opts2.startMaximum = true
local stksTempoMax = getSTKs(stat, opts2, args.health, args.shield, STKCalculator)
local ttksTempoMax = getTTKs(stat, stksTempoMax, opts2, TTKCalculator)
addFromTTKs(ammo, data, ammoname, chargedmaxname, label, ttksTempoMax)
end
end
end
end
end
-- アンビルレシーバー (VK-47フラットライン・R-301カービン)
if stat.damage.anvil_receiver then
-- デッドアイズテンポ (センチネル)
local opts2 = aw.shallowCopy(opts)
if Hopup.deadeyes_tempo.enabled and stat.deadeyes_tempo and (not aw.isNumberAndGreaterThanZero(stat.damage.charged)) then
opts2.useAnvilReceiver = true
local opts2 = aw.shallowCopy(opts)
local ttks = getTTKs(stat, TTKCalculator.SINGLE_ANVIL_RECEIVER, opts2, args.health, args.shield, STKCalculator, TTKCalculator)
opts2.useDeadeyesTempo = true
addFromTTKs(ammo, data, ammoname, basename, getAnvilReceiver(), ttks)
local ttksTempo = getTTKs(stat, stks, opts2, TTKCalculator)
if not compareTTKs(ttks, ttksTempo) then
addFromTTKs(ammo, data, ammoname, basename, getDeadeyesTempo(), ttksTempo)
end
-- 最高速
if aw.isNumberAndGreaterThanOrEqualToX(stat.deadeyes_tempo.firerate_maximum_count, 1) then
local maxname = basename .. ' (最高速)'
opts2.startMaximum = true
local stksTempoMax = getSTKs(stat, opts2, args.health, args.shield, STKCalculator)
local ttksTempoMax = getTTKs(stat, stksTempoMax, opts2, TTKCalculator)
addFromTTKs(ammo, data, ammoname, maxname, getDeadeyesTempo(), ttksTempoMax)
end
end
end
-- ターボチャージャー (ハボックライフル・ディヴォーションLMG)
if stat.turbocharger then
local opts2 = aw.shallowCopy(opts)
opts2.useTurbocharger = true
local ttks2 = getTTKs(stat, stks, opts2, TTKCalculator)
addFromTTKs(ammo, data, ammoname, basename, getTurbocharger(), ttks2)
-- ターボチャージャー (ハボックライフル・ディヴォーションLMG)
-- 最高速から
if aw.isNumberAndGreaterThanOrEqualToZero(stat.firerate.auto_raise_turbocharger)
if aw.isNumberAndGreaterThanZero(stat.turbocharger.firerate_maximum_duration) then
or aw.isNumberAndGreaterThanOrEqualToZero(stat.firerate.auto_start_turbocharger) then
local maxname = basename .. ' (最高速)'
local opts2 = aw.shallowCopy(opts)
local opts3 = aw.shallowCopy(opts2)
opts2.useTurbocharger = true
opts3.startMaximum = true
local ttks2 = getTTKs(stat, TTKCalculator.AUTO, opts2, args.health, args.shield, STKCalculator, TTKCalculator)
local ttks3 = getTTKs(stat, stks, opts3, TTKCalculator)
addFromTTKs(ammo, data, ammoname, basename, getTurbocharger(), ttks2)
if ttksmax ~= nil and not compareTTKs(ttksmax, ttks3) then
addFromTTKs(ammo, data, ammoname, maxname, getTurbocharger(), ttks3)
end
-- ライトマシンガン (ディヴォーションLMG)
if stat.category == 'light_machine_gun' then
if stat.category == 'light_machine_gun' then
local opts3 = aw.shallowCopy(opts2)
local opts4 = aw.shallowCopy(opts3)
opts3.useModdedLoader = true
opts4.useModdedLoader = true
local ttks3 = getTTKs(stat, TTKCalculator.AUTO, opts3, args.health, args.shield, STKCalculator, TTKCalculator)
local ttks4 = getTTKs(stat, stks, opts4, TTKCalculator)
if not compareTTKs(ttks2, ttks3) then
if not compareTTKs(ttks3, ttks4) then
addFromTTKs(ammo, data, ammoname, basename, getTurbocharger() .. '<br>' .. getModdedLoader(), ttks3)
addFromTTKs(ammo, data, ammoname, maxname, getTurbocharger() .. '<br>' .. getModdedLoader(), ttks4)
end
end
end
end
-- ライトマシンガン (ディヴォーションLMG)
if stat.category == 'light_machine_gun' then
local opts3 = aw.shallowCopy(opts2)
opts3.useModdedLoader = true
local ttks3 = getTTKs(stat, stks, opts3, TTKCalculator)
if not compareTTKs(ttks2, ttks3) then
addFromTTKs(ammo, data, ammoname, basename, getTurbocharger() .. '<br>' .. getModdedLoader(), ttks3)
end
end
end
end

2022年4月24日 (日) 15:02時点における最新版

このモジュールについての説明文ページを モジュール:MultipleStatTable/doc に作成できます

require('Module:Utility/mw.html Extensions')

local p = {}

local aw = require('Module:Utility/Library')
local apex = require('Module:Utility/ApexLibrary')
local iu = require('Module:Utility/Image')
local nu = require('Module:Utility/Name')
local inu = require('Module:Utility/ImageWithName')

local Hopup = mw.loadData('Module:Stat/Hopup')

local formatter -- lazily initialized
local getArgs -- lazily initialized

-- [[ リソース キャッシュ ]]
local cache = {}
local function getModdedLoader()
	if cache.moddedLoader then
		return cache.moddedLoader
	end
	
	cache.moddedLoader = iu.passive('modded_loader') .. ' <span class="text-desktoponly">改造ローダー</span>'
	return cache.moddedLoader
end

local function getAmpedMode()
	if cache.ampedMode then
		return cache.ampedMode
	end
	
	cache.ampedMode = iu.item('シールドセル') .. ' <span class="text-desktoponly">増幅モード</span>'
	return cache.ampedMode
end

local function getRevvedUpMode()
	if cache.revvedUpMode then
		return cache.revvedUpMode
	end
	
	cache.revvedUpMode = iu.grenade('テルミットグレネード') .. ' <span class="text-desktoponly">連射速度上昇モード</span>'
	return cache.revvedUpMode
end

local function getDisruptorRounds()
	if cache.disruptorRounds then
		return cache.disruptorRounds
	end
	
	cache.disruptorRounds = inu.hopup('disruptor_rounds', { desktopOnly = true })
	return cache.disruptorRounds
end

local function getHammerpointRounds()
	if cache.hammerpointRounds then
		return cache.hammerpointRounds
	end
	
	cache.hammerpointRounds = inu.hopup('hammerpoint_rounds', { desktopOnly = true })
	return cache.hammerpointRounds
end

local function getShatterCaps()
	if cache.shatterCaps then
		return cache.shatterCaps
	end
	
	cache.shatterCaps = inu.hopup('shatter_caps', { desktopOnly = true })
	return cache.shatterCaps
end

local function getDeadeyesTempo()
	if cache.deadeyesTempo then
		return cache.deadeyesTempo
	end
	
	cache.deadeyesTempo = inu.hopup('deadeyes_tempo', { desktopOnly = true })
	return cache.deadeyesTempo
end

local function getAnvilReceiver()
	if cache.anvilReceiver then
		return cache.anvilReceiver
	end
	
	cache.anvilReceiver = inu.hopup('anvil_receiver', { desktopOnly = true })
	return cache.anvilReceiver
end

local function getTurbocharger()
	if cache.turbocharger then
		return cache.turbocharger
	end
	
	cache.turbocharger = inu.hopup('turbocharger', { desktopOnly = true })
	return cache.turbocharger
end

local function getBoostedLoader()
	if cache.boostedLoader then
		return cache.boostedLoader
	end
	
	cache.boostedLoader = inu.hopup('boosted_loader', { desktopOnly = true })
	return cache.boostedLoader
end

local function getMagazineLabel(ammo, level, force)
	if not force and level == 0 then
		return ''
	end
	
	if aw.stringstarts(ammo, 'special_') then
		ammo = string.sub(ammo, 9)
	end
	
	if not cache[ammo] then
		cache[ammo] = {}
	end
	if cache[ammo] and cache[ammo][1 + level] then
		return cache[ammo][1 + level]
	end
	
	if ammo == 'shotgun' then
		cache[ammo][1 + level] = inu.bolt(level, { desktopOnly = true })
	else
		cache[ammo][1 + level] = inu.extmag(ammo, level, { desktopOnly = true })
	end
	return cache[ammo][1 + level]
end

local getEmphasizableText = aw.getEmphasizableTextFunc('%s', '<span class="text-desktoponly">%s</span>', '<span class="text-desktoponly">%s</span>')
local function getWeaponLink(name, ammo, shortname)
	local classSuffix = aw.stringstarts(ammo, 'special_') and 'special' or ammo
	local suitableName = getEmphasizableText(name, shortname)
	return string.format('[[%s|<span class="text-ammo-%s">%s</span>]]', name, classSuffix, suitableName)
end

-- [[ 設定 ]]
local columns = { '通常', '鉄壁', '+ガンシールド' }
local columnCount = #columns
local config = {
	-- 通常
	{
		gunshield = 0,
		passive = 1,
	},

	-- 小柄
	--{
	--	gunshield = 0,
	--	passive = 1.05,
	--},
	
	-- 鉄壁
	{
		gunshield = 0,
		passive = 0.85,
	},

	-- +ガンシールド
	{
		gunshield = 50,
		passive = 0.85,
	},
}

-- [[ テーブル生成 ]]
local function passthrough(num)
	return num
end

local function createStatTable(itemname, slots, headers, fn, numformat, isdesc, zero)
	numformat = numformat or passthrough
	if isdesc == nil then
		isdesc = true
	end
	zero = zero or 0
	
	local stat = mw.loadData('Module:Stat/Weapon')
	
	local data = {}
	for key, value in pairs(stat) do
		fn(data, key, value)
	end
	if isdesc then
		table.sort(data, function(a, b)
			return a.values[1] > b.values[1]
		end)
	else
		table.sort(data, function(a, b)
			return a.values[1] < b.values[1]
		end)
	end
	
	local tbl = mw.html.create('table')
			:addClass('numbertable')
			:addClass('st')
			:addClass('sortable')
	local header = tbl:tag('tr')
		:addClass('row-sticky')
		:tag('th')
			:addClass('st-desktop')
			:css('width', '36px')
			:done()
		:tag('th')
			:addClass('st-mobile-first')
			:attrIf(slots > 2, { colspan = slots - 1 })
			:wikitext('武器名')
			:done()
	for _, item in ipairs(headers) do
		header:tag('th')
			:css('min-width', '60px')
			:wikitext(item)
	end
	
	local rank = 1
	local max = 0
	for i = 1, #data do
		local value = math.max(unpack(data[i].values))
		if value ~= math.huge then
			max = math.max(max, value)
		end
	end
	
	local current = max
	for i, obj in ipairs(data) do
		local row = tbl:tag('tr')
		if slots > 1 then
			for i = 1, slots do
				local classname
				if i == 1 then
					classname = 'st-desktop'
				elseif i == 2 then
					classname = 'st-mobile-first st-dashed-right st-mobile-none-right st-mobile-padding0-right'
				elseif i == slots then
					classname = 'st-dashed-left st-mobile-none-left st-mobile-padding0-both'
				else
					classname = 'st-dashed-both st-mobile-none-both st-mobile-padding0-both'
				end
				
				row:tag('td')
					:addClass(classname)
					:attrIf(i == 1, { align = 'center' })
					:wikitext(obj[i])
					:attr('align', 'left')
			end
		else
			row:tag('td')
				:wikitext(obj.name)
				:attr('align', 'left')
		end
		
		for _, value in ipairs(obj.values) do
			local percentage = 0.001 * aw.round(100000 * (value - zero) / (1.05 * max - zero))
			local graph = string.format('linear-gradient(to right, #A7D7F9 %s%%, transparent %s%%)', percentage, percentage)
			row:tag('td')
				:addClass('st-graph')
				:addClass('st-textshadow')
				:addClass('st-line')
				:addClass('st-line-h12')
				:attr('align', 'right')
				:css('background-image', graph .. ' !important')
				:wikitext(numformat(value))
		end
	end
	return tbl
end

local function add(data, name, values)
	if values == nil or type(values) == 'number' then
		error(string.format('The "%s" value is nil or number', name))
	end
	
	if type(name) == 'table' then
		name.values = values
		table.insert(data, name)
	else
		local obj = {
			name = name,
			values = values,
		}
		table.insert(data, obj)
	end
end

-- [[ キルタイム ]]
local function getSTKs(stat, opts, health, shield, STKCalculator)
	local ret = {}
	local stkc = STKCalculator.newFromStat(stat, opts)
	for passive = 1, #config do
		local c = config[passive]
		stkc:calcShotToKill(health, shield, c.gunshield, c.passive)
		table.insert(ret, stkc:get())
		stkc:reset()
	end
	return ret
end

local function getTTKs(stat, stks, opts, TTKCalculator)
	local ttkc = TTKCalculator.newFromStat(stat, opts)
	local ret = {}
	for _, stk in ipairs(stks) do
		local obj = {
			ttkc:getAsLevel(stk, 0),
			ttkc:getAsLevel(stk, 1),
			ttkc:getAsLevel(stk, 2),
			ttkc:getAsLevel(stk, 3),
		}
		table.insert(ret, obj)
	end
	return ret
end

local function isDiffTTKs(ttks, a, b)
	for passive = 1, columnCount do
		if 0.0001 * aw.round(10000 * ttks[passive][a]) ~= 0.0001 * aw.round(10000 * ttks[passive][b]) then
			return true
		end
	end
	return false
end

local function compareTTKs(ttks1, ttks2)
	for passive = 1, columnCount do
		for level = 1, 4 do
			local ttk1 = 0.0001 * aw.round(10000 * ttks1[passive][level])
			local ttk2 = 0.0001 * aw.round(10000 * ttks2[passive][level])
			if ttk1 ~= ttk2 then
				return false
			end
		end
	end
	return true
end

local function repackTTKs(ttks, level)
	local ret = {}
	for _, ttk in ipairs(ttks) do
		table.insert(ret, ttk[level])
	end
	return ret
end

local function addFromTTKs(ammo, data, ammoname, basename, hopup, ttks)
	if isDiffTTKs(ttks, 3, 4) then
		add(data, { ammoname, basename, getMagazineLabel(ammo, 3), hopup }, repackTTKs(ttks, 4))
		add(data, { ammoname, basename, getMagazineLabel(ammo, 2), hopup }, repackTTKs(ttks, 3))
		if isDiffTTKs(ttks, 1, 2) then
			add(data, { ammoname, basename, getMagazineLabel(ammo, 1), hopup }, repackTTKs(ttks, 2))
			add(data, { ammoname, basename, getMagazineLabel(ammo, 0, true), hopup }, repackTTKs(ttks, 1))
		else
			add(data, { ammoname, basename, getMagazineLabel(ammo, 0, true) .. '<br>' .. getMagazineLabel(ammo, 1), hopup }, repackTTKs(ttks, 1))
		end
	elseif isDiffTTKs(ttks, 2, 3) then
		add(data, { ammoname, basename, getMagazineLabel(ammo, 2) .. '<br>' .. getMagazineLabel(ammo, 3), hopup }, repackTTKs(ttks, 3))
		if isDiffTTKs(ttks, 1, 2) then
			add(data, { ammoname, basename, getMagazineLabel(ammo, 1), hopup }, repackTTKs(ttks, 2))
			add(data, { ammoname, basename, getMagazineLabel(ammo, 0, true), hopup }, repackTTKs(ttks, 1))
		else
			add(data, { ammoname, basename, getMagazineLabel(ammo, 0, true) .. '<br>' .. getMagazineLabel(ammo, 1), hopup }, repackTTKs(ttks, 1))
		end
	elseif isDiffTTKs(ttks, 1, 2) then
		add(data, { ammoname, basename, getMagazineLabel(ammo, 1) .. '<br>' .. getMagazineLabel(ammo, 2) .. '<br>' .. getMagazineLabel(ammo, 3), hopup }, repackTTKs(ttks, 2))
		add(data, { ammoname, basename, getMagazineLabel(ammo, 0, true), hopup }, repackTTKs(ttks, 1))
	else
		add(data, { ammoname, basename, '', hopup }, repackTTKs(ttks, 1))
	end
end

local function parsePattern(str)
	local type = type(str)
	if type == 'table' then
		return str
	elseif str == nil or type ~= 'string' then
		return nil
	end
	
	local pattern = {}
	local head = false
	for i = 1, #str do
		local c = string.sub(str, i, i)
		local cont = false
		if head then
			head = false
			if c == '1' then
				table.insert(pattern, apex.HEAD_HLMLV1)
				cont = true
			elseif c == '2' then
				table.insert(pattern, apex.HEAD_HLMLV2)
				cont = true
			elseif c == '3' then
				table.insert(pattern, apex.HEAD_HLMLV3)
				cont = true
			elseif c == '0' then
				table.insert(pattern, apex.HEAD_NOHLM)
				cont = true
			else
				table.insert(pattern, apex.HEAD_NOHLM)
			end
		end
		
		if not cont then
			if c == 'H' then
				head = true
			elseif c == 'L' then
				table.insert(pattern, apex.LEGS)
			elseif c == 'S' then
				table.insert(pattern, apex.SKY)
			elseif c == ',' or c == ' ' then
				if head then
					head = false
					table.insert(pattern, apex.HEAD_NOHLM)
				end
			else
				table.insert(pattern, apex.BODY)
			end
		end
	end
	if head then
		table.insert(pattern, apex.HEAD_NOHLM)
	end
	return pattern
end

function p.bytimetokill(frame, args)
	formatter = require('Module:Utility/Formatter').new(frame)
	if not getArgs then
		getArgs = require('Module:Arguments').getArgs
	end
	args = args or getArgs(frame)
	args.health = aw.getAsNumber(args.health, 100)
	args.shield = aw.getAsNumber(args.shield, 125)
	
	local opts = {
		pattern = {
			first = parsePattern(args.firstPattern),
			loop  = parsePattern(args.loopPattern),
		},
	}
	local STKCalculator = require('Module:Apex/STKCalculator')
	local TTKCalculator = require('Module:Apex/TTKCalculator')
	
	local tbl = createStatTable('キルタイム [s]', 4, columns, function(data, name, stat)
		if stat.time == nil or (not aw.isNumber(stat.time.reloadempty or stat.time.reload)) then
			return
		end
		
		local ammo = stat.ammo
		local ammoname = iu.ammo(ammo, { size = 20 })
		local basename = getWeaponLink(name, ammo, stat.localization['Japanese_Short'])
		local special  = aw.stringstarts(ammo, 'special_')
		local stks = getSTKs(stat, opts, args.health, args.shield, STKCalculator)
		local ttks = getTTKs(stat, stks, opts, TTKCalculator)
		if not stat.attachments.disruptor_rounds_only then
			addFromTTKs(ammo, data, ammoname, basename, '', ttks)
		end
		
		-- ライトマシンガン (ディヴォーションLMG・M600スピットファイア・L-スターEMG)
		if stat.category == 'light_machine_gun' then
			local opts2 = aw.shallowCopy(opts)
			opts2.useModdedLoader = true
			local ttks2 = getTTKs(stat, stks, opts2, TTKCalculator)
			if not compareTTKs(ttks, ttks2) then
				addFromTTKs(ammo, data, ammoname, basename, getModdedLoader(), ttks2)
			end
		end
		
		if stat.altfire and aw.isNumber(stat.altfire.firerate) and stat.altfire.firerate ~= stat.firerate then
			local altname
			if stat.altfire.is_semi_auto or stat.is_semi_auto then
				altname = basename .. ' (単発)'
			else
				altname = basename .. ' (オート)'
			end
			
			local altopts = aw.shallowCopy(opts)
			altopts.useAltfire = true
			
			local ttks = getTTKs(stat, stks, altopts, TTKCalculator)
			addFromTTKs(ammo, data, ammoname, altname, '', ttks)
			
			-- ブーステッドローダー (ヘムロックバーストAR)
			if Hopup.boosted_loader.enabled and stat.boosted_loader and type(stat.boosted_loader.magazine) == 'table' then
				altopts.useBoostedLoader = true
				local burstttks2 = getTTKs(stat, stks, altopts, TTKCalculator)
				addFromTTKs(ammo, data, ammoname, altname, getBoostedLoader(), burstttks2)
			end
		end
		
		-- 最高速から
		local ttksmax = nil
		if aw.isNumberAndGreaterThanZero(stat.firerate_maximum_duration) then
			local maxname = basename .. ' (最高速)'
			local opts2 = aw.shallowCopy(opts)
			opts2.startMaximum = true
			ttksmax = getTTKs(stat, stks, opts2, TTKCalculator)
			addFromTTKs(ammo, data, ammoname, maxname, '', ttksmax)
			
			if stat.category == 'light_machine_gun' then
				local opts3 = aw.shallowCopy(opts2)
				opts3.useModdedLoader = true
				local ttks3 = getTTKs(stat, stks, opts3, TTKCalculator)
				if not compareTTKs(ttksmax, ttks3) then
					addFromTTKs(ammo, data, ammoname, maxname, getModdedLoader(), ttks3)
				end
			end
		end
		
		-- センチネルの増幅モード
		if aw.isNumberAndGreaterThanZero(stat.damage.amped) then
			local ampedammoname = iu.ammo(ammo .. '_amped', { size = 20 })
			local ampedname = string.format('%s (%s)', basename, getAmpedMode())
			local opts2 = aw.shallowCopy(opts)
			opts2.useAmpedMode = true
			local stksAmped = getSTKs(stat, opts2, args.health, args.shield, STKCalculator)
			local ttksAmped = getTTKs(stat, stksAmped, opts2, TTKCalculator)
			if not compareTTKs(ttks, ttksAmped) then
				addFromTTKs(ammo, data, ampedammoname, ampedname, '', ttksAmped)
			end
			
			-- デッドアイズテンポ
			if Hopup.deadeyes_tempo.enabled and stat.deadeyes_tempo then
				opts2.useDeadeyesTempo = true
				local ttksTempo = getTTKs(stat, stksAmped, opts2, TTKCalculator)
				if not compareTTKs(ttksAmped, ttksTempo) then
					addFromTTKs(ammo, data, ampedammoname, ampedname, getDeadeyesTempo(), ttksTempo)
				end
				
				-- 最高速
				if aw.isNumberAndGreaterThanOrEqualToX(stat.deadeyes_tempo.firerate_maximum_count, 1) then
					local ampedmaxname = string.format('%s (最高速・%s)', basename, getAmpedMode())
					opts2.startMaximum = true
					local stksTempoMax = getSTKs(stat, opts2, args.health, args.shield, STKCalculator)
					local ttksTempoMax = getTTKs(stat, stksTempoMax, opts2, TTKCalculator)
					addFromTTKs(ammo, data, ampedammoname, ampedmaxname, getDeadeyesTempo(), ttksTempoMax)
				end
			end
		end
		
		-- ランページの連射速度上昇モード
		if aw.isNumberAndGreaterThanZero(stat.firerate_revvedup) then
			local revvedupammoname = iu.ammo(ammo .. '_revved_up', { size = 20 })
			local revvedupname = string.format('%s (%s)', basename, getRevvedUpMode())
			local opts2 = aw.shallowCopy(opts)
			opts2.useRevvedUpMode = true
			local ttksRevvedUp = getTTKs(stat, stks, opts2, TTKCalculator)
			addFromTTKs(ammo, data, revvedupammoname, revvedupname, '', ttksRevvedUp)
		end
		
		-- フルチャージ (30-30リピーター・ボセックコンパウンドボウ)
		if aw.isNumberAndGreaterThanZero(stat.damage.charged) then
			local chargedname = basename .. ' (最大溜め)'
			local opts2 = aw.shallowCopy(opts)
			opts2.useCharged = true
			local stks2 = getSTKs(stat, opts2, args.health, args.shield, STKCalculator)
			local ttks2 = getTTKs(stat, stks2, opts2, TTKCalculator)
			addFromTTKs(ammo, data, ammoname, chargedname, '', ttks2)
			
			-- デッドアイズテンポ
			if Hopup.deadeyes_tempo.enabled and stat.deadeyes_tempo then
				opts2.useDeadeyesTempo = true
				local ttksTempo = getTTKs(stat, stks2, opts2, TTKCalculator)
				addFromTTKs(ammo, data, ammoname, chargedname, getDeadeyesTempo(), ttksTempo)
				
				-- 最高速
				if aw.isNumberAndGreaterThanOrEqualToX(stat.deadeyes_tempo.firerate_maximum_count, 1) then
					local chargedmaxname = basename .. ' (最高速・最大溜め)'
					opts2.startMaximum = true
					local stksTempoMax = getSTKs(stat, opts2, args.health, args.shield, STKCalculator)
					local ttksTempoMax = getTTKs(stat, stksTempoMax, opts2, TTKCalculator)
					addFromTTKs(ammo, data, ammoname, chargedmaxname, getDeadeyesTempo(), ttksTempoMax)
				end
			end
		end
		
		-- ディスラプター弾 (オルタネーターSMG・RE-45オート)
		if (Hopup.disruptor_rounds.enabled or special) and aw.isNumber(stat.damage.disruptor_rounds) and stat.damage.disruptor_rounds > 1 then
			local opts2 = aw.shallowCopy(opts)
			opts2.useDisruptorRounds  = true
			local stks2 = getSTKs(stat, opts2, args.health, args.shield, STKCalculator)
			local ttks2 = getTTKs(stat, stks2, opts2, TTKCalculator)
			addFromTTKs(ammo, data, ammoname, basename, getDisruptorRounds(), ttks2)
		end
		
		-- ハンマーポイント弾 (モザンビーク・P2020)
		if Hopup.hammerpoint_rounds.enabled and aw.isNumber(stat.damage.hammerpoint_rounds) and stat.damage.hammerpoint_rounds > 1 then
			local opts2 = aw.shallowCopy(opts)
			opts2.useHammerpointRounds = true
			local stks2 = getSTKs(stat, opts2, args.health, args.shield, STKCalculator)
			local ttks2 = getTTKs(stat, stks2, opts2, TTKCalculator)
			addFromTTKs(ammo, data, ammoname, basename, getHammerpointRounds(), ttks2)
		end
		
		-- アンビルレシーバー (VK-47フラットライン・R-301カービン)
		if Hopup.anvil_receiver.enabled and stat.anvil_receiver then
			local opts2 = aw.shallowCopy(opts)
			opts2.useAnvilReceiver = true
			local stks2 = getSTKs(stat, opts2, args.health, args.shield, STKCalculator)
			local ttks2 = getTTKs(stat, stks2, opts2, TTKCalculator)
			addFromTTKs(ammo, data, ammoname, basename, getAnvilReceiver(), ttks2)
		end
		
		-- ブーステッドローダー (ヘムロックバーストAR・ウィングマン)
		if Hopup.boosted_loader.enabled and stat.boosted_loader and type(stat.boosted_loader.magazine) == 'table' then
			local opts2 = aw.shallowCopy(opts)
			opts2.useBoostedLoader = true
			local ttks2 = getTTKs(stat, stks, opts2, TTKCalculator)
			addFromTTKs(ammo, data, ammoname, basename, getBoostedLoader(), ttks2)
		end
		
		-- シャッターキャップ (30-30リピーター・ボセックコンポウンドボウ)
		if Hopup.shatter_caps.enabled and stat.shatter_caps then
			local label = getShatterCaps()
			local opts2 = aw.shallowCopy(opts)
			opts2.useShatterCaps = true
			local stks2 = getSTKs(stat, opts2, args.health, args.shield, STKCalculator)
			local ttks2 = getTTKs(stat, stks2, opts2, TTKCalculator)
			addFromTTKs(ammo, data, ammoname, basename, label, ttks2)
			
			if aw.isNumberAndGreaterThanZero(stat.shatter_caps.damage.charged) then
				local chargedname = basename .. ' (最大溜め)'
				opts2.useCharged = true
				local stks3 = getSTKs(stat, opts2, args.health, args.shield, STKCalculator)
				local ttks3 = getTTKs(stat, stks3, opts2, TTKCalculator)
				addFromTTKs(ammo, data, ammoname, chargedname, label, ttks3)
				
				-- デッドアイズテンポ (ボセックコンパウンドボウ)
				if Hopup.deadeyes_tempo.enabled and stat.deadeyes_tempo then
					label = label .. '<br>' .. getDeadeyesTempo()
					opts2.useDeadeyesTempo = true
					local ttksTempo = getTTKs(stat, stks3, opts2, TTKCalculator)
					addFromTTKs(ammo, data, ammoname, chargedname, label, ttksTempo)
				
					-- 最高速
					if aw.isNumberAndGreaterThanOrEqualToX(stat.deadeyes_tempo.firerate_maximum_count, 1) then
						local chargedmaxname = basename .. ' (最高速・最大溜め)'
						opts2.startMaximum = true
						local stksTempoMax = getSTKs(stat, opts2, args.health, args.shield, STKCalculator)
						local ttksTempoMax = getTTKs(stat, stksTempoMax, opts2, TTKCalculator)
						addFromTTKs(ammo, data, ammoname, chargedmaxname, label, ttksTempoMax)
					end
				end
			end
		end
		
		-- デッドアイズテンポ (センチネル)
		if Hopup.deadeyes_tempo.enabled and stat.deadeyes_tempo and (not aw.isNumberAndGreaterThanZero(stat.damage.charged)) then
			local opts2 = aw.shallowCopy(opts)
			opts2.useDeadeyesTempo = true
			local ttksTempo = getTTKs(stat, stks, opts2, TTKCalculator)
			if not compareTTKs(ttks, ttksTempo) then
				addFromTTKs(ammo, data, ammoname, basename, getDeadeyesTempo(), ttksTempo)
			end
				
			-- 最高速
			if aw.isNumberAndGreaterThanOrEqualToX(stat.deadeyes_tempo.firerate_maximum_count, 1) then
				local maxname = basename .. ' (最高速)'
				opts2.startMaximum = true
				local stksTempoMax = getSTKs(stat, opts2, args.health, args.shield, STKCalculator)
				local ttksTempoMax = getTTKs(stat, stksTempoMax, opts2, TTKCalculator)
				addFromTTKs(ammo, data, ammoname, maxname, getDeadeyesTempo(), ttksTempoMax)
			end
		end
		
		-- ターボチャージャー (ハボックライフル・ディヴォーションLMG)
		if stat.turbocharger then
			local opts2 = aw.shallowCopy(opts)
			opts2.useTurbocharger = true
			local ttks2 = getTTKs(stat, stks, opts2, TTKCalculator)
			addFromTTKs(ammo, data, ammoname, basename, getTurbocharger(), ttks2)
			
			-- 最高速から
			if aw.isNumberAndGreaterThanZero(stat.turbocharger.firerate_maximum_duration) then
				local maxname = basename .. ' (最高速)'
				local opts3 = aw.shallowCopy(opts2)
				opts3.startMaximum = true
				local ttks3 = getTTKs(stat, stks, opts3, TTKCalculator)
				if ttksmax ~= nil and not compareTTKs(ttksmax, ttks3) then
					addFromTTKs(ammo, data, ammoname, maxname, getTurbocharger(), ttks3)
				end
				
				if stat.category == 'light_machine_gun' then
					local opts4 = aw.shallowCopy(opts3)
					opts4.useModdedLoader = true
					local ttks4 = getTTKs(stat, stks, opts4, TTKCalculator)
					if not compareTTKs(ttks3, ttks4) then
						addFromTTKs(ammo, data, ammoname, maxname, getTurbocharger() .. '<br>' .. getModdedLoader(), ttks4)
					end
				end
			end
			
			-- ライトマシンガン (ディヴォーションLMG)
			if stat.category == 'light_machine_gun' then
				local opts3 = aw.shallowCopy(opts2)
				opts3.useModdedLoader = true
				local ttks3 = getTTKs(stat, stks, opts3, TTKCalculator)
				if not compareTTKs(ttks2, ttks3) then
					addFromTTKs(ammo, data, ammoname, basename, getTurbocharger() .. '<br>' .. getModdedLoader(), ttks3)
				end
			end
		end
	end, function(num)
		return 0.001 * aw.round(1000 * num)
	end, false, -0.1)
	return tostring(tbl)
end

return p