🌟 | 現在、 鉄壁ヘッドショットには対応済みです。 鉄壁HSは通常HSと同じダメージになります。LMG及びDMR、チャージライフル、ハンマーポイント弾を除き、すべてのダメージ値が一致していることを確認しています。 |
「モジュール:MultipleStatTable」の版間の差分
ナビゲーションに移動
検索に移動
(ホップアップデータ構造の変更に対応) |
(可変レート武器における最高速スタートのTTKが表示されていない不具合の修正) |
||
(同じ利用者による、間の6版が非表示) | |||
8行目: | 8行目: | ||
local nu = require('Module:Utility/Name') | local nu = require('Module:Utility/Name') | ||
local inu = require('Module:Utility/ImageWithName') | 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 | ||
45行目: | 48行目: | ||
end | end | ||
cache.disruptorRounds = | cache.disruptorRounds = inu.hopup('disruptor_rounds', { desktopOnly = true }) | ||
return cache.disruptorRounds | return cache.disruptorRounds | ||
end | end | ||
54行目: | 57行目: | ||
end | end | ||
cache.hammerpointRounds = | cache.hammerpointRounds = inu.hopup('hammerpoint_rounds', { desktopOnly = true }) | ||
return cache.hammerpointRounds | return cache.hammerpointRounds | ||
end | end | ||
63行目: | 66行目: | ||
end | end | ||
cache.shatterCaps = | cache.shatterCaps = inu.hopup('shatter_caps', { desktopOnly = true }) | ||
return cache.shatterCaps | return cache.shatterCaps | ||
end | end | ||
72行目: | 75行目: | ||
end | end | ||
cache.deadeyesTempo = | cache.deadeyesTempo = inu.hopup('deadeyes_tempo', { desktopOnly = true }) | ||
return cache.deadeyesTempo | return cache.deadeyesTempo | ||
end | end | ||
81行目: | 84行目: | ||
end | end | ||
cache.anvilReceiver = | cache.anvilReceiver = inu.hopup('anvil_receiver', { desktopOnly = true }) | ||
return cache.anvilReceiver | return cache.anvilReceiver | ||
end | end | ||
90行目: | 93行目: | ||
end | end | ||
cache.turbocharger = | cache.turbocharger = inu.hopup('turbocharger', { desktopOnly = true }) | ||
return cache.turbocharger | return cache.turbocharger | ||
end | end | ||
99行目: | 102行目: | ||
end | end | ||
cache.boostedLoader = | cache.boostedLoader = inu.hopup('boosted_loader', { desktopOnly = true }) | ||
return cache.boostedLoader | return cache.boostedLoader | ||
end | end | ||
192行目: | 195行目: | ||
local tbl = mw.html.create('table') | local tbl = mw.html.create('table') | ||
:addClass('numbertable') | :addClass('numbertable') | ||
:addClass(' | :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(' | :addClass('st-desktop') | ||
: | :css('width', '36px') | ||
:done() | :done() | ||
:tag('th') | :tag('th') | ||
:addClass(' | :addClass('st-mobile-first') | ||
:attrIf(slots > 2, { colspan = slots - 1 }) | :attrIf(slots > 2, { colspan = slots - 1 }) | ||
:wikitext('武器名') | :wikitext('武器名') | ||
211行目: | 211行目: | ||
for _, item in ipairs(headers) do | for _, item in ipairs(headers) do | ||
header:tag('th') | header:tag('th') | ||
: | :css('min-width', '60px') | ||
:wikitext(item) | :wikitext(item) | ||
end | end | ||
234行目: | 231行目: | ||
local classname | local classname | ||
if i == 1 then | if i == 1 then | ||
classname = ' | classname = 'st-desktop' | ||
elseif i == 2 then | elseif i == 2 then | ||
classname = ' | 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 | else | ||
classname = ' | classname = 'st-dashed-both st-mobile-none-both st-mobile-padding0-both' | ||
end | end | ||
row:tag('td') | row:tag('td') | ||
:addClass(classname) | :addClass(classname) | ||
: | :attrIf(i == 1, { align = 'center' }) | ||
:wikitext(obj[i]) | :wikitext(obj[i]) | ||
:attr('align', 'left') | :attr('align', 'left') | ||
250行目: | 248行目: | ||
else | else | ||
row:tag('td') | row:tag('td') | ||
:wikitext(obj.name) | :wikitext(obj.name) | ||
:attr('align', 'left') | :attr('align', 'left') | ||
260行目: | 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(' | :addClass('st-graph') | ||
:addClass(' | :addClass('st-textshadow') | ||
:addClass(' | :addClass('st-line') | ||
:addClass(' | :addClass('st-line-h12') | ||
:attr('align', 'right') | :attr('align', 'right') | ||
:css('background-image', graph .. ' !important') | :css('background-image', graph .. ' !important') | ||
302行目: | 298行目: | ||
end | end | ||
local function getTTKs(stat, stks | local function getTTKs(stat, stks, opts, TTKCalculator) | ||
local ttkc = TTKCalculator.newFromStat(stat | local ttkc = TTKCalculator.newFromStat(stat, opts) | ||
local ret = {} | local ret = {} | ||
for _, stk in ipairs(stks) do | for _, stk in ipairs(stks) do | ||
445行目: | 441行目: | ||
local STKCalculator = require('Module:Apex/STKCalculator') | local STKCalculator = require('Module:Apex/STKCalculator') | ||
local TTKCalculator = require('Module:Apex/TTKCalculator') | local TTKCalculator = require('Module:Apex/TTKCalculator') | ||
local tbl = createStatTable('キルタイム [s]', 4, columns, function(data, name, stat) | local tbl = createStatTable('キルタイム [s]', 4, columns, function(data, name, stat) | ||
457行目: | 452行目: | ||
local special = aw.stringstarts(ammo, 'special_') | local special = aw.stringstarts(ammo, 'special_') | ||
local stks = getSTKs(stat, opts, args.health, args.shield, STKCalculator) | local stks = getSTKs(stat, opts, args.health, args.shield, STKCalculator) | ||
if stat. | local ttks = getTTKs(stat, stks, opts, TTKCalculator) | ||
if stat. | if not stat.attachments.disruptor_rounds_only then | ||
addFromTTKs(ammo, data, ammoname, basename, '', ttks) | |||
addFromTTKs(ammo, data, ammoname, basename | 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 | ||
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 | end | ||
local | local altopts = aw.shallowCopy(opts) | ||
addFromTTKs(ammo, data, ammoname, | altopts.useAltfire = true | ||
local ttks = getTTKs(stat, stks, altopts, TTKCalculator) | |||
addFromTTKs(ammo, data, ammoname, altname, '', ttks) | |||
-- ブーステッドローダー (ヘムロックバーストAR) | -- ブーステッドローダー (ヘムロックバーストAR) | ||
if Hopup.boosted_loader.enabled and stat.boosted_loader and type(stat.boosted_loader.magazine) == 'table' then | 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) | |||
local burstttks2 = getTTKs(stat, stks, | addFromTTKs(ammo, data, ammoname, altname, getBoostedLoader(), burstttks2) | ||
addFromTTKs(ammo, data, ammoname, | |||
end | 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 | if stat.category == 'light_machine_gun' then | ||
local | local opts3 = aw.shallowCopy(opts2) | ||
opts3.useModdedLoader = true | |||
local | local ttks3 = getTTKs(stat, stks, opts3, TTKCalculator) | ||
if not compareTTKs( | if not compareTTKs(ttksmax, ttks3) then | ||
addFromTTKs(ammo, data, ammoname, | 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 Hopup.deadeyes_tempo.enabled and stat.deadeyes_tempo then | |||
if | opts2.useDeadeyesTempo = true | ||
local ttksTempo = getTTKs(stat, stksAmped, opts2, TTKCalculator) | |||
if not compareTTKs(ttksAmped, ttksTempo) then | |||
addFromTTKs(ammo, data, ampedammoname, ampedname, getDeadeyesTempo(), ttksTempo) | |||
end | |||
addFromTTKs(ammo, data, | |||
if stat. | -- 最高速 | ||
local | if aw.isNumberAndGreaterThanOrEqualToX(stat.deadeyes_tempo.firerate_maximum_count, 1) then | ||
local ampedmaxname = string.format('%s (最高速・%s)', basename, getAmpedMode()) | |||
local | 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) | |||
-- | -- デッドアイズテンポ | ||
if | 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) | |||
local | |||
-- | -- 最高速 | ||
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 | ||
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 | |||
if aw.isNumberAndGreaterThanZero(stat. | |||
local chargedname = basename .. ' (最大溜め)' | local chargedname = basename .. ' (最大溜め)' | ||
opts2.useCharged = true | opts2.useCharged = true | ||
local | local stks3 = getSTKs(stat, opts2, args.health, args.shield, STKCalculator) | ||
local | local ttks3 = getTTKs(stat, stks3, opts2, TTKCalculator) | ||
addFromTTKs(ammo, data, ammoname, chargedname, | addFromTTKs(ammo, data, ammoname, chargedname, label, ttks3) | ||
-- デッドアイズテンポ | -- デッドアイズテンポ (ボセックコンパウンドボウ) | ||
if Hopup.deadeyes_tempo.enabled and stat.deadeyes_tempo then | if Hopup.deadeyes_tempo.enabled and stat.deadeyes_tempo then | ||
label = label .. '<br>' .. getDeadeyesTempo() | |||
opts2.useDeadeyesTempo = true | opts2.useDeadeyesTempo = true | ||
local ttksTempo = getTTKs(stat, | local ttksTempo = getTTKs(stat, stks3, opts2, TTKCalculator) | ||
addFromTTKs(ammo, data, ammoname, chargedname, | addFromTTKs(ammo, data, ammoname, chargedname, label, ttksTempo) | ||
-- 最高速 | -- 最高速 | ||
if aw.isNumberAndGreaterThanOrEqualToX(stat.deadeyes_tempo. | if aw.isNumberAndGreaterThanOrEqualToX(stat.deadeyes_tempo.firerate_maximum_count, 1) then | ||
local chargedmaxname = basename .. ' (最高速・最大溜め)' | local chargedmaxname = basename .. ' (最高速・最大溜め)' | ||
opts2.startMaximum = true | opts2.startMaximum = true | ||
local stksTempoMax = getSTKs(stat, opts2, args.health, args.shield, STKCalculator) | local stksTempoMax = getSTKs(stat, opts2, args.health, args.shield, STKCalculator) | ||
local ttksTempoMax = getTTKs(stat, stksTempoMax | local ttksTempoMax = getTTKs(stat, stksTempoMax, opts2, TTKCalculator) | ||
addFromTTKs(ammo, data, ammoname, chargedmaxname, | addFromTTKs(ammo, data, ammoname, chargedmaxname, label, ttksTempoMax) | ||
end | end | ||
end | 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) | |||
addFromTTKs(ammo, data, ammoname, basename, | if not compareTTKs(ttks, ttksTempo) then | ||
addFromTTKs(ammo, data, ammoname, basename, getDeadeyesTempo(), ttksTempo) | |||
end | end | ||
-- | -- 最高速 | ||
if | if aw.isNumberAndGreaterThanOrEqualToX(stat.deadeyes_tempo.firerate_maximum_count, 1) then | ||
local | local maxname = basename .. ' (最高速)' | ||
opts2. | opts2.startMaximum = true | ||
local | local stksTempoMax = getSTKs(stat, opts2, args.health, args.shield, STKCalculator) | ||
local | local ttksTempoMax = getTTKs(stat, stksTempoMax, opts2, TTKCalculator) | ||
addFromTTKs(ammo, data, ammoname, | 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) | |||
-- | -- 最高速から | ||
if | if aw.isNumberAndGreaterThanZero(stat.turbocharger.firerate_maximum_duration) then | ||
local maxname = basename .. ' (最高速)' | |||
local opts3 = aw.shallowCopy(opts2) | |||
opts3.startMaximum = true | |||
local | local ttks3 = getTTKs(stat, stks, opts3, TTKCalculator) | ||
if ttksmax ~= nil and not compareTTKs(ttksmax, ttks3) then | |||
addFromTTKs(ammo, data, ammoname, maxname, getTurbocharger(), ttks3) | |||
end | |||
local | |||
local | |||
if | if stat.category == 'light_machine_gun' then | ||
local | local opts4 = aw.shallowCopy(opts3) | ||
opts4.useModdedLoader = true | |||
local | local ttks4 = getTTKs(stat, stks, opts4, TTKCalculator) | ||
if not compareTTKs(ttks3, ttks4) then | |||
addFromTTKs(ammo, data, ammoname, maxname, getTurbocharger() .. '<br>' .. getModdedLoader(), ttks4) | |||
addFromTTKs(ammo, data, ammoname, | |||
end | end | ||
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