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

モジュール:MultipleStatTable

提供:Apex Data
2021年2月25日 (木) 16:27時点におけるMntone (トーク | 投稿記録)による版 (ページの作成:「require('Module:Utility/mw.html Extensions') local p = {} local aw = require('Module:Utility/Library') local apex = require('Module:Utility/ApexLibrary') local iu = req…」)
(差分) ← 古い版 | 最新版 (差分) | 新しい版 → (差分)
ナビゲーションに移動 検索に移動

このモジュールについての説明文ページを モジュール: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 formatter -- lazily initialized
local getArgs -- lazily initialized

-- [[ リソース キャッシュ ]]
local cache = {}
local function getModdedLoader()
	if cache.moddedLoader then
		return cache.moddedLoader
	end
	
	cache.moddedLoader = formatter:hopup('改造ローダー') .. ' <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 getHammerpointRounds()
	if cache.hammerpointRounds then
		return cache.hammerpointRounds
	end
	
	cache.hammerpointRounds = iu.hopup('ハンマーポイント弾') .. ' ' .. formatter:epic('ハンマーポイント弾', 'text-desktoponly')
	return cache.hammerpointRounds
end

local function getAnvilReceiver()
	if cache.anvilReceiver then
		return cache.anvilReceiver
	end
	
	cache.anvilReceiver = iu.hopup('アンビルレシーバー') .. ' ' .. formatter:legendary('アンビルレシーバー', 'text-desktoponly')
	return cache.anvilReceiver
end

local function getMagazineLabel(ammo, level, force)
	if not force and level == 0 then
		return ''
	end
	
	if not cache[ammo] then
		cache[ammo] = {}
	end
	if cache[ammo] and cache[ammo][1 + level] then
		return cache[ammo][1 + level]
	end
	
	local footer
	if level == 0 then
		footer = 'なし'
	else
		footer = ' - レベル' .. level
	end
	
	if ammo == 'shotgun' then
		cache[ammo][1 + level] = iu.attachment(nu.bolt('ja'), level) .. ' ' .. formatter:level(level, nu.bolt() .. footer, 'text-desktoponly')
	else
		cache[ammo][1 + level] = iu.attachment(nu.extmag(ammo, 'ja'), level) .. ' ' .. formatter:level(level, nu.extmag(ammo) .. footer, 'text-desktoponly')
	end
	return cache[ammo][1 + level]
end

-- [[ テーブル生成 ]]
local function createRow(tbl, text)
	return tbl:tag('tr')
		:tag('th')
			:wikitext(text)
			:done()
		:tag('td')
			:tag('ul')
				:addClass('tpl-navbox-list')
end

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('wikitable')
			:addClass('graphtable')
			:addClass('numbertable')
			:addClass('stattable')
			:addClass('sortable')
	local header = tbl:tag('tr')
		:tag('th')
			:addClass('stattable-cell-header')
			:addClass('stattable-cell-header-name')
			:attrIf(slots > 1, { colspan = slots })
			:wikitext('武器名')
			:done()
	for _, item in ipairs(headers) do
		header:tag('th')
			:addClass('graphtable-cell-header')
			:addClass('graphtable-cell-header-both')
			:addClass('stattable-cell-header')
			:addClass('stattable-cell-header-value')
			:wikitext(item)
	end
	
	local rank = 1
	local max
	if isdesc then
		for i = 1, #data do
			local value = data[i].values[1]
			if value ~= math.huge then
				max = value
				break
			end
		end
	else
		for i = #data, 1, -1 do
			local value = data[i].values[1]
			if value ~= math.huge then
				max = value
				break
			end
		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
				row:tag('td')
					:addClass('stattable-cell')
					:addClassIf(i == 1, 'stattable-cell-name')
					:addClassIf(i > 1, 'stattable-cell-attachment')
					:addClassIf(i == slots, 'stattable-cell-attachment-last')
					:wikitext(obj[i])
					:attr('align', 'left')
			end
		else
			row:tag('td')
				:addClass('stattable-cell')
				:addClass('stattable-cell-name')
				: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('graphtable-cell')
				:addClass('graphtable-cell-both')
				:addClass('stattable-cell')
				:addClass('stattable-cell-value')
				: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 getTTKs(stat, mode, opts, health, shield, STKCalculator, TTKCalculator)
	local stkc = STKCalculator.newFromStat(stat, opts)
	stkc:calcShotToKill(health, shield, 0, 1)
	local stkNormal = stkc:get()
	stkc:reset()
	stkc:calcShotToKill(health, shield, 0, 1.05)
	local stkLowProfile = stkc:get()
	stkc:reset()
	stkc:calcShotToKill(health, shield, 0, 0.85)
	local stkFortified = stkc:get()
	
	local ttkc = TTKCalculator.newFromStat(stat, mode)
	return {
		{
			ttkc:getAsLevel(stkNormal, 0),
			ttkc:getAsLevel(stkNormal, 1),
			ttkc:getAsLevel(stkNormal, 2),
			ttkc:getAsLevel(stkNormal, 3),
		},
		{
			ttkc:getAsLevel(stkLowProfile, 0),
			ttkc:getAsLevel(stkLowProfile, 1),
			ttkc:getAsLevel(stkLowProfile, 2),
			ttkc:getAsLevel(stkLowProfile, 3),
		},
		{
			ttkc:getAsLevel(stkFortified, 0),
			ttkc:getAsLevel(stkFortified, 1),
			ttkc:getAsLevel(stkFortified, 2),
			ttkc:getAsLevel(stkFortified, 3),
		},
	}
end

local function repackTTKs(ttks, level)
	return {
		ttks[1][level],
		ttks[2][level],
		ttks[3][level],
	}
end

local function addFromTTKs(ammo, data, basename, hopup, ttks)
	if ttks[1][3] ~= ttks[1][4] or ttks[2][3] ~= ttks[2][4] or ttks[3][3] ~= ttks[3][4] then
		add(data, { basename, getMagazineLabel(ammo, 3), hopup }, repackTTKs(ttks, 4))
		add(data, { basename, getMagazineLabel(ammo, 2), hopup }, repackTTKs(ttks, 3))
		if ttks[1][1] ~= ttks[1][2] or ttks[2][1] ~= ttks[2][2] or ttks[3][1] ~= ttks[3][2] then
			add(data, { basename, getMagazineLabel(ammo, 1), hopup }, repackTTKs(ttks, 2))
			add(data, { basename, getMagazineLabel(ammo, 0, true), hopup }, repackTTKs(ttks, 1))
		else
			add(data, { basename, getMagazineLabel(ammo, 0, true) .. '<br>' .. getMagazineLabel(ammo, 1), hopup }, repackTTKs(ttks, 1))
		end
	elseif ttks[1][2] ~= ttks[1][3] or ttks[2][2] ~= ttks[2][3] or ttks[3][2] ~= ttks[3][3] then
		add(data, { basename, getMagazineLabel(ammo, 2) .. '<br>' .. getMagazineLabel(ammo, 3), hopup }, repackTTKs(ttks, 3))
		if ttks[1][1] ~= ttks[1][2] or ttks[2][1] ~= ttks[2][2] or ttks[3][1] ~= ttks[3][2] then
			add(data, { basename, getMagazineLabel(ammo, 1), hopup }, repackTTKs(ttks, 2))
			add(data, { basename, getMagazineLabel(ammo, 0, true), hopup }, repackTTKs(ttks, 1))
		else
			add(data, { basename, getMagazineLabel(ammo, 0, true) .. '<br>' .. getMagazineLabel(ammo, 1), hopup }, repackTTKs(ttks, 1))
		end
	elseif ttks[1][1] ~= ttks[1][2] or ttks[2][1] ~= ttks[2][2] or ttks[3][1] ~= ttks[3][2] then
		add(data, { basename, getMagazineLabel(ammo, 1) .. '<br>' .. getMagazineLabel(ammo, 2) .. '<br>' .. getMagazineLabel(ammo, 3), hopup }, repackTTKs(ttks, 2))
		add(data, { basename, getMagazineLabel(ammo, 0, true), hopup }, repackTTKs(ttks, 1))
	else
		add(data, { basename, '', hopup }, repackTTKs(ttks, 1))
	end
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 STKCalculator = require('Module:Apex/STKCalculator')
	local TTKCalculator = require('Module:Apex/TTKCalculator')
	
	local tbl = createStatTable('キルタイム [s]', 3, { '通常', '小柄', '鉄壁' }, function(data, name, stat)
		if type(stat.damage.base) == 'table' or stat.time == nil or stat.time.reload == nil or name == 'ディヴォーションLMG' then
			return
		end
		
		local ammo = stat.ammo
		local basename = iu.ammo(ammo, { size = 20 }) .. ' [[' .. name .. ']]'
		if stat.mode.burst > 1 then
			if stat.mode.auto then
				local ttks = getTTKs(stat, TTKCalculator.AUTO, {}, args.health, args.shield, STKCalculator, TTKCalculator)
				addFromTTKs(ammo, data, basename .. ' (オート)', '', ttks)
			else
				local ttks = getTTKs(stat, TTKCalculator.SINGLE, {}, args.health, args.shield, STKCalculator, TTKCalculator)
				addFromTTKs(ammo, data, basename .. ' (単発)', '', ttks)
			end
			
			local ttks = getTTKs(stat, TTKCalculator.BURST, {}, args.health, args.shield, STKCalculator, TTKCalculator)
			addFromTTKs(ammo, data, basename .. ' (バースト)', '', ttks)
		else
			local mode = stat.mode.auto and TTKCalculator.AUTO or TTKCalculator.SINGLE
			local ttks = getTTKs(stat, mode, {}, args.health, args.shield, STKCalculator, TTKCalculator)
			addFromTTKs(ammo, data, basename, '', ttks)
			
			-- センチネルの増幅モード
			if aw.isNumber(stat.damage.amped) then
				local ttks = getTTKs(stat, TTKCalculator.SINGLE, { useAmpedMode = true }, args.health, args.shield, STKCalculator, TTKCalculator)
				addFromTTKs(ammo, data, basename, getAmpedMode(), ttks)
			end
			
			-- ハンマーポイント弾
			if aw.isNumber(stat.damage.hammerpoint_rounds) and stat.damage.hammerpoint_rounds > 1 then
				local ttks = getTTKs(stat, TTKCalculator.SINGLE, { useHammerpointRounds = true }, args.health, args.shield, STKCalculator, TTKCalculator)
				addFromTTKs(ammo, data, basename, getHammerpointRounds(), ttks)
			end
			
			-- アンビルレシーバー
			if stat.damage.anvil_receiver then
				local ttks = getTTKs(stat, TTKCalculator.SINGLE_ANVIL_RECEIVER, { useAnvilReceiver = true }, args.health, args.shield, STKCalculator, TTKCalculator)
				addFromTTKs(ammo, data, basename, getAnvilReceiver(), ttks)
			end
		end
	end, function(num)
		return 0.001 * aw.round(1000 * num)
	end, false, -0.1)
	return tostring(tbl)
end

return p