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

モジュール:DPSTable

提供:Apex Data
2022年5月22日 (日) 22:37時点におけるMntone (トーク | 投稿記録)による版 (ショットガンボルトの片方の値しか持たない場合に対応)
(差分) ← 古い版 | 最新版 (差分) | 新しい版 → (差分)
ナビゲーションに移動 検索に移動

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

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

local p = {}
local cfg    = mw.loadData('Module:DPSTable/configuration')
local aw     = require('Module:Utility/Library')
local apex   = require('Module:Utility/ApexLibrary')
local iu     = require('Module:Utility/Image')
local Shield = require('Module:Stat/Shield')
local table  = require('Module:TableExtensions')
local getArgs -- lazily initialized

-- Define values
local fromtoValues = {
	damage   = 20,
	firerate = 10,
	pellets  = 1,
	head     = 2,
	legs     = 0.75,
	ratio1   = -1,
	ratio2   = -1,
	ratio3   = -1,
}
local fromtoStringValues = {
	shieldpreset = 'reinforcehelmets',
}

local booleanValues = {
	round = false,
}
local stringValues = {
	lang = 'ja',
}

-- Calc the scales
local function calcScales(opts)
	local ret = {
		hed0_fm = opts.args.head_from,
		hed1_fm = opts.shld_fm.helmets.level1.func(opts.args.head_from),
		hed2_fm = opts.shld_fm.helmets.level2.func(opts.args.head_from),
		hed3_fm = opts.shld_fm.helmets.level3.func(opts.args.head_from),
		body_fm = 1,
		legs_fm = opts.args.legs_from,
		
		hed0_to = opts.args.head_to,
		hed1_to = opts.shld_to.helmets.level1.func(opts.args.head_to),
		hed2_to = opts.shld_to.helmets.level2.func(opts.args.head_to),
		hed3_to = opts.shld_to.helmets.level3.func(opts.args.head_to),
		body_to = 1,
		legs_to = opts.args.legs_to,
	}
	return ret
end

-- Calc the damages
local function calcBaseDamages(scales, opts)
	local ret = {
		hed0_fm = apex.calcPartDamage(opts.args.damage_from, scales.hed0_fm),
		hed1_fm = apex.calcPartDamage(opts.args.damage_from, scales.hed1_fm),
		hed2_fm = apex.calcPartDamage(opts.args.damage_from, scales.hed2_fm),
		hed3_fm = apex.calcPartDamage(opts.args.damage_from, scales.hed3_fm),
		body_fm = opts.args.damage_from,
		legs_fm = apex.calcPartDamage(opts.args.damage_from, scales.legs_fm),
		
		hed0_to = apex.calcPartDamage(opts.args.damage_to, scales.hed0_to),
		hed1_to = apex.calcPartDamage(opts.args.damage_to, scales.hed1_to),
		hed2_to = apex.calcPartDamage(opts.args.damage_to, scales.hed2_to),
		hed3_to = apex.calcPartDamage(opts.args.damage_to, scales.hed3_to),
		body_to = opts.args.damage_to,
		legs_to = apex.calcPartDamage(opts.args.damage_to, scales.legs_to),
	}
	return ret
end

-- Apply perk scale to base damage as DPS
local function applyPerkToDamages(damages, fmperk, toperk, opts)
	if fmperk ~= 1 then
		if toperk ~= 1 then
			return table.map(damages, function(key, damage)
				if aw.stringends(key, '_to') then
					if opts.shld_to.sameHeadshotDamageToNormalOnFortified and aw.stringstarts(key, 'hed') then
						return damage
					else
						return apex.calcPassiveDamage(damage, toperk, { round = opts.args.round })
					end
				else
					if opts.shld_fm.sameHeadshotDamageToNormalOnFortified and aw.stringstarts(key, 'hed') then
						return damage
					else
						return apex.calcPassiveDamage(damage, fmperk, { round = opts.args.round })
					end
				end
			end)
		else
			return table.map(damages, function(key, damage)
				if aw.stringends(key, '_to') then
					return damage
				else
					if opts.shld_fm.sameHeadshotDamageToNormalOnFortified and aw.stringstarts(key, 'hed') then
						return damage
					else
						return apex.calcPassiveDamage(damage, fmperk, { round = opts.args.round })
					end
				end
			end)
		end
	elseif toperk ~= 1 then
		return table.map(damages, function(key, damage)
			if aw.stringends(key, '_to') then
				if opts.shld_to.sameHeadshotDamageToNormalOnFortified and aw.stringstarts(key, 'hed') then
					return damage
				else
					return apex.calcPassiveDamage(damage, toperk, { round = opts.args.round })
				end
			else
				return damage
			end
		end)
	else
		return damages
	end
end

-- Calc DPSs
local function calcDPSs(damages, fmratio, toratio, opts)
	return table.map(damages, function(key, damage)
		if aw.stringends(key, '_to') then
			return damage * toratio * opts.args.firerate_to   * opts.args.pellets_to
		else
			return damage * fmratio * opts.args.firerate_from * opts.args.pellets_from
		end
	end)
end

-- Render the cell node base
local function getRenderCellFunction(tag, prefix)
	return function(row, suffix, fmval, toval, opts, colspan)
		colspan = colspan or 1
		
		local text
		if fmval ~= toval then
			if fmval <= 0 then
				local key = string.format('%s_ft%s_lastonly', prefix, suffix)
				text = string.format(opts.cfg[key], toval)
			elseif toval <= 0 then
				local key = string.format('%s_ft%s_firstonly', prefix, suffix)
				text = string.format(opts.cfg[key], fmval)
			else
				local key = string.format('%s_ft%s', prefix, suffix)
				text = string.format(opts.cfg[key], fmval, toval)
			end
		else
			local key = prefix .. suffix
			text = string.format(opts.cfg[key], fmval)
		end
		
		local cell = row:tag(tag)
		if colspan > 1 then
			cell:attr('colspan', colspan)
		end
		cell:wikitext(text)
	end
end

-- Render the header cell node
local renderHeaderCell = getRenderCellFunction('th', 'part')

-- Render the header node
local function renderHeaderRow(tbl, scales, opts)
	local header = tbl:tag('tr')
		:tag('th')
			:attrIf(opts.colspan > 1, { colspan = opts.colspan })
			:wikitext('DPS')
			:done()
		
	if not opts.shld_fm.helmets.level0.disabled or not opts.shld_to.helmets.level0.disabled then
		renderHeaderCell(header, '_head', scales.hed0_fm, scales.hed0_to, opts)
	end
	
	renderHeaderCell(header, '_head_lvl1', scales.hed1_fm, scales.hed1_to, opts)
	renderHeaderCell(header, '_head_lvl2', scales.hed2_fm, scales.hed2_to, opts)
	renderHeaderCell(header, '_head_lvl3', scales.hed3_fm, scales.hed3_to, opts)
	if opts.nolegs then
		header:tag('th'):wikitext(opts.cfg.part_bodylegs)
	else
		header:tag('th'):wikitext(opts.cfg.part_body)
		renderHeaderCell(header, '_legs', scales.legs_fm, scales.legs_to, opts)
	end
end

-- Render the cell node
local renderCell = getRenderCellFunction('td', 'format')

-- Render the row node
local function renderRow(tbl, name, suffix, perkDamages, fmratio, toratio, opts)
	local dps = calcDPSs(perkDamages, fmratio, toratio, opts)
	
	local row = tbl:tag('tr')
	
	if aw.isNumberAndGreaterThanZero(opts.coloffset) then
		row:tag('th')
			:attrIf(opts.coloffset > 1, { colspan = opts.coloffset })
			:css({
				['border-top']   = '0 none transparent',
				['border-bottom'] = '0 none transparent',
			})
			:wikitext('&nbsp;')
	end
	
	row:tag('th')
		:attrIf(opts.colspan > 1, { colspan = opts.colspan })
		:cssIf( opts.colspan > 1, { ['border-bottom'] = '0 none transparent' })
		:wikitext(name)
		
	if opts.shld_fm.helmets.level0.disabled then
		if not opts.shld_to.helmets.level0.disabled then
			renderCell(row, '', -1, dps.hed0_to, opts)
		end
	elseif opts.shld_to.helmets.level0.disabled then
		renderCell(row, '', dps.hed0_fm, -1, opts)
	else
		renderCell(row, '', dps.hed0_fm, dps.hed0_to, opts)
	end
	
	renderCell(row, '_head_lvl1', dps.hed1_fm, dps.hed1_to, opts)
	renderCell(row, '_head_lvl2', dps.hed2_fm, dps.hed2_to, opts)
	renderCell(row, '_head_lvl3', dps.hed3_fm, dps.hed3_to, opts)
	
	if opts.nolegs then
		renderCell(row, '', dps.body_fm, dps.body_to, opts)
	elseif dps.body_fm == dps.legs_fm and dps.body_to == dps.legs_to then
		renderCell(row, '', dps.body_fm, dps.body_to, opts, 2)
	else
		renderCell(row, '', dps.body_fm, dps.body_to, opts)
		renderCell(row, '', dps.legs_fm, dps.legs_to, opts)
	end
end

-- Render the rows node
local function renderRows(tbl, suffix, damages, fmperk, toperk, opts)
	local name
	if fmperk ~= toperk then
		local key = string.format('perk_ft%s', suffix)
		name = string.format(opts.cfg[key], 100 * (fmperk - 1), 100 * (toperk - 1))
	else
		local key = string.format('perk%s', suffix)
		name = string.format(opts.cfg[key], 100 * (fmperk - 1))
	end
	
	local perkDamages = applyPerkToDamages(damages, fmperk, toperk, opts)
	if fmperk > 1 and opts.shld_fm.legAsBodyOnLowProfile then
		perkDamages.legs_fm = perkDamages.body_fm
	end
	if toperk > 1 and opts.shld_to.legAsBodyOnLowProfile then
		perkDamages.legs_to = perkDamages.body_to
	end
	
	-- Default
	renderRow(tbl, name, suffix, perkDamages, 1, 1, opts)
	
	-- Shotgun bolt
	if opts.colspan == 2 then
		local opts2 = aw.shallowCopy(opts)
		opts2.coloffset = 1
		opts2.colspan   = 1
		
		-- Shotgun bolt lvl1
		if opts.args.ratio1_from ~= opts.args.ratio1_to then
			if opts.args.ratio1_from <= 0 then
				name = string.format(opts.cfg.ratio_ft_shotgun1_lastonly, opts.args.ratio1_to)
			elseif opts.args.ratio1_to <= 0 then
				name = string.format(opts.cfg.ratio_ft_shotgun1_firstonly, opts.args.ratio1_from)
			else
				name = string.format(opts.cfg.ratio_ft_shotgun1, opts.args.ratio1_from, opts.args.ratio1_to)
			end
		else
			name = string.format(opts.cfg.ratio_shotgun1, opts.args.ratio1_from)
		end
		renderRow(tbl, name, suffix, perkDamages, opts.args.ratio1_from, opts.args.ratio1_to, opts2)
		
		-- Shotgun bolt lvl2
		if aw.isNumberAndGreaterThanX(opts.args.ratio2_from, 1) or aw.isNumberAndGreaterThanX(opts.args.ratio2_to, 1) then
			if opts.args.ratio2_from ~= opts.args.ratio2_to then
				if opts.args.ratio2_from <= 0 then
					name = string.format(opts.cfg.ratio_ft_shotgun2_lastonly, opts.args.ratio2_to)
				elseif opts.args.ratio2_to <= 0 then
					name = string.format(opts.cfg.ratio_ft_shotgun2_firstonly, opts.args.ratio2_from)
				else
					name = string.format(opts.cfg.ratio_ft_shotgun2, opts.args.ratio2_from, opts.args.ratio2_to)
				end
			else
				name = string.format(opts.cfg.ratio_shotgun2, opts.args.ratio2_from)
			end
			renderRow(tbl, name, suffix, perkDamages, opts.args.ratio2_from, opts.args.ratio2_to, opts2)
			
			-- Shotgun bolt lvl3
			if aw.isNumberAndGreaterThanX(opts.args.ratio3_from, 1) or aw.isNumberAndGreaterThanX(opts.args.ratio3_to, 1) then
				if opts.args.ratio3_from ~= opts.args.ratio3_to then
					if opts.args.ratio3_from <= 0 then
						name = string.format(opts.cfg.ratio_ft_shotgun3_lastonly, opts.args.ratio3_to)
					elseif opts.args.ratio3_to <= 0 then
						name = string.format(opts.cfg.ratio_ft_shotgun3_firstonly, opts.args.ratio3_from)
					else
						name = string.format(opts.cfg.ratio_ft_shotgun3, opts.args.ratio3_from, opts.args.ratio3_to)
					end
				else
					name = string.format(opts.cfg.ratio_shotgun3, opts.args.ratio3_from)
				end
				renderRow(tbl, name, suffix, perkDamages, opts.args.ratio3_from, opts.args.ratio3_to, opts2)
			end
		end
	end
end

-- Render the table
function p.renderTable(opts)
	local scales  = calcScales(opts)
	local damages = calcBaseDamages(scales, opts)
	
	local tbl = mw.html.create('table')
		:addClass('numbertable')
		:addClass('patchnotetable')
		:addClass('wikitable')
	
	-- Header
	renderHeaderRow(tbl, scales, opts)
	
	-- Normal
	renderRows(tbl, '_normal', damages, 1, 1, opts)
	
	-- Low Profile
	if opts.shld_fm.lowprofile > 1 or opts.shld_to.lowprofile > 1 then
		renderRows(tbl, '_lowprofile', damages, opts.shld_fm.lowprofile, opts.shld_to.lowprofile, opts)
	end
	
	-- Fortified
	if opts.shld_fm.fortified < 1 or opts.shld_to.fortified < 1 then
		renderRows(tbl, '_fortified', damages, opts.shld_fm.fortified, opts.shld_to.fortified, opts)
	end
	
	return tbl
end

function p._main(args)
	args = args or {}
	
	-- Fix arguments
	for key, value in pairs(fromtoValues) do
		local fromKey = key .. '_from'
		args[fromKey] = aw.getAsNumber(args[fromKey], aw.getAsNumber(args[key], value))
		
		local toKey = key .. '_to'
		args[toKey] = aw.getAsNumber(args[toKey], aw.getAsNumber(args[key], value))
	end
	for key, value in pairs(fromtoStringValues) do
		local fromKey = key .. '_from'
		args[fromKey] = args[fromKey] or args[key] or value
		
		local toKey = key .. '_to'
		args[toKey] = args[toKey] or args[key] or value
	end
	
	for key, value in pairs(booleanValues) do
		args[key] = aw.getAsBoolean(args[key], value)
	end
	for key, value in pairs(stringValues) do
		args[key] = args[key] or value
	end
	
	-- Load data
	local opts = {
		args    = args,
		cfg     = cfg[args.lang],
		colspan = (aw.isNumberAndGreaterThanX(args.ratio1_from, 1) or aw.isNumberAndGreaterThanX(args.ratio1_to, 1)) and 2 or 1,
		shld_fm = Shield[args.shieldpreset_from],
		shld_to = Shield[args.shieldpreset_to],
		nolegs  = (args.legs_from < 0 or args.legs_from >= 1) and (args.legs_to < 0 or args.legs_to >= 1),
	}
	
	-- Render the table node
	local node = p.renderTable(opts)
	return tostring(node)
end

function p.main(frame)
	if not getArgs then
		getArgs = require('Module:Arguments').getArgs
	end
	args = getArgs(frame)
	
	return p._main(args, frame)
end

return p