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

モジュール:WeaponInfobox/Firerate

提供:Apex Data
< モジュール:WeaponInfobox
2022年5月23日 (月) 13:03時点におけるMntone (トーク | 投稿記録)による版 (EVA-8オートのダブルタップトリガーの判定を自動化)
(差分) ← 古い版 | 最新版 (差分) | 新しい版 → (差分)
ナビゲーションに移動 検索に移動

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

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

local p = {}
local cfg = mw.loadData('Module:WeaponInfobox/configuration')

local aw    = require('Module:Utility/Library')
local apex  = require('Module:Utility/ApexLibrary')
local iu    = require('Module:Utility/Image')
local proto = require('Module:Utility/Prototypes')
local Hopup = mw.loadData('Module:Stat/Hopup')

-- Protos
local MultipleNumberProto = {
	proto.NumberRange(0),
	proto.NumberRange(0),
	proto.NumberRange(0),
	proto.NumberRange(0),
}
local Eva8AutoProto = {
	firerate = MultipleNumberProto,
	double_tap_trigger = {
		burst_count = proto.NumberRange(2),
		burst_delay = MultipleNumberProto,
		firerate    = proto.NumberRange(0),
	},
}
local PeacekeeperProto = {
	firerate  = proto.NumberRange(0),
	rechamber = MultipleNumberProto,
}
local AltfireProto = {
	firerate     = proto.NumberRange(0),
}
local SelectfireReceiverProto = {
	firerate = proto.NumberRange(0),
}
local DevotionProto = {
	firerate         = proto.NumberRange(0),
	firerate_maximum = proto.NumberRange(0),
}
local AnvilReceiverProto = {
	firerate = proto.NumberRange(0),
}
local DoubleTapTrigggerProto = {
	burst_count = proto.NumberRange(2),
	burst_delay = proto.NumberRange(0),
	firerate    = proto.NumberRange(0),
}
local DeadeyesTempoWithChargeProto = {
	charge = proto.NumberRange(0),
}
local DeadeyesTempoWithRechamberProto = {
	rechamber = proto.NumberRange(0),
}

local function renderFormatRow(tbl, name, default, common, rare, epic, opts)
	opts = opts or {}
	opts.separator = opts.separator or '&nbsp;-&nbsp;'
	local row = tbl:tag('tr')
		:addClassIf(type(opts.class)  == 'string', opts.class)
		:addClassIf(type(opts.rarity) == 'string', 'row-rarity-one disp-rarity-' .. (opts.rarity or 'common'))
	
	if name ~= nil then
		row:tag('th')
			:attrIf(opts.headerAlign and type(opts.headerAlign) == 'string', { align = opts.headerAlign })
			:wikitext(name)
	end

	row
		:tag('td')
			:addClass('cell-type-number')
			:attrIf(opts.align and type(opts.align) == 'string', { align = opts.align })
			:wikitext(default)
			:done()
		:tag('td'):wikitext(opts.separator):done()
		:tag('td')
			:addClass('cell-type-number')
			:attrIf(opts.align and type(opts.align) == 'string', { align = opts.align })
			:tag('span')
				:addClass('text-rarity')
				:addClass('text-rarity-common')
				:wikitext(common)
				:done()
			:done()
		:tag('td'):wikitext(opts.separator):done()
		:tag('td')
			:addClass('cell-type-number')
			:attrIf(opts.align and type(opts.align) == 'string', { align = opts.align })
			:tag('span')
				:addClass('text-rarity')
				:addClass('text-rarity-rare')
				:wikitext(rare)
				:done()
			:done()
		:tag('td'):wikitext(opts.separator):done()
		:tag('td')
			:addClass('cell-type-number')
			:attrIf(opts.align and type(opts.align) == 'string', { align = opts.align })
			:tag('span')
				:addClass('text-rarity')
				:addClass('text-rarity-epic')
				:wikitext(epic)
				:done()
			:done()
		:tag('td')
			:attr('align', 'left')
			:wikitext(opts.footer)
	return row
end

-- Render variable firerate
local function renderVariableFirerateRow(intbl, name, cfg, rps1, rps2, opts)
	opts = opts or {}
	intbl
		:tag('tr')
			:addClassIf(type(opts.rarity) == 'string', 'row-rarity-first disp-rarity-' .. (opts.rarity or 'common'))
			:addClassIf(type(opts.class) == 'string',  opts.class)
			:tag('th')
				:wikitext(name)
				:done()
			:tag('td')
				:addClass('cell-type-number')
				:attr('align', 'right')
				:wikitext(string.format(cfg.rps.format, rps1))
				:done()
			:tag('td')
				:wikitext('&nbsp;→&nbsp;')
				:done()
			:tag('td')
				:addClass('cell-type-number')
				:attr('align', 'right')
				:wikitext(string.format(cfg.rps.format, rps2))
				:done()
			:tag('td')
				:wikitext(cfg.rps.unit)
				:done()
			:done()
		:tag('tr')
			:addClassIf(type(opts.rarity) == 'string', 'row-rarity-last disp-rarity-' .. (opts.rarity or 'common'))
			:addClass('no-list-style')
			:addClass('text-secondary')
			:addClass('text-smaller')
			:tag('th')
				:attr('align', 'right')
				:wikitext(cfg.rpm.name)
				:done()
			:tag('td')
				:addClass('cell-type-number')
				:wikitext(aw.comma(aw.roundx(60 * rps1, 1)))
				:done()
			:tag('td')
				:wikitext('&nbsp;→&nbsp;')
				:done()
			:tag('td')
				:addClass('cell-type-number')
				:wikitext(aw.comma(aw.roundx(60 * rps2, 1)))
				:done()
			:tag('td')
				:wikitext(cfg.rpm.unit)
end

-- Render multiple firerates in table
local function renderMultipleFirerateRow(intbl, name, cfg, rps, opts)
	opts = opts or {}
	renderFormatRow(
		intbl,
		name .. cfg.rps.name,
		string.format(cfg.rps.format, aw.roundx(rps[1], 2)),
		string.format(cfg.rps.format, aw.roundx(rps[2], 2)),
		string.format(cfg.rps.format, aw.roundx(rps[3], 2)),
		string.format(cfg.rps.format, aw.roundx(rps[4], 2)),
		{ class = opts.rpsClass or '', separator = cfg.rps.separator, footer = cfg.rps.unit })
	renderFormatRow(
		intbl,
		cfg.rpm.name,
		string.format(cfg.rpm.format, aw.comma(aw.roundx(60 * rps[1], 1))),
		string.format(cfg.rpm.format, aw.comma(aw.roundx(60 * rps[2], 1))),
		string.format(cfg.rpm.format, aw.comma(aw.roundx(60 * rps[3], 1))),
		string.format(cfg.rpm.format, aw.comma(aw.roundx(60 * rps[4], 1))),
		{ class = opts.rpmClass and 'text-secondary text-smaller ' .. opts.rpmClass or 'text-secondary text-smaller', headerAlign = 'right', separator = cfg.rpm.separator, footer = cfg.rpm.unit })
end

-- Render a firerate in table
local function renderFirerateRow(intbl, name, cfg, rps, opts)
	opts = opts or {}
	local row = intbl:tag('tr')
		:addClassIf(opts.class and type(opts.class) == 'string', opts.class)
	if type(opts.rarity) == 'string' then
		row:addClass(string.format('row-rarity-%s disp-rarity-%s', opts.rarityRowStyle or 'one', opts.rarity))
	end
	
	row
		:tag('th')
			:wikitext(name)
			:done()
		:tag('td')
			:addClass('cell-type-number')
			:attr('align', 'right')
			:wikitext(string.format(cfg.rps.format, rps))
			:done()
		:tag('td')
			:wikitext(cfg.rps.unit)
			:done()
		:tag('td')
			:addClass('text-secondary')
			:addClass('text-smaller')
			:wikitext(cfg.rpm.name)
			:done()
		:tag('td')
			:addClass('cell-type-number')
			:addClass('text-secondary')
			:addClass('text-smaller')
			:attr('align', 'right')
			:wikitext(aw.comma(aw.roundx(60 * rps, 1)))
			:done()
		:tag('td')
			:addClass('text-secondary')
			:addClass('text-smaller')
			:wikitext(cfg.rpm.unit)
end

-- Render a firerate
local function renderFirerateText(name, cfg, rps)
	return string.format(
		'%s<span class="text-type-number">' .. cfg.rps.format .. '</span>' .. cfg.rps.unit .. '<span class="text-secondary text-smaller">(<span class="text-type-number">%s</span>' .. cfg.rpm.unit .. '</span>',
		name,
		rps,
		aw.comma(aw.roundx(60 * rps, 1)))
end

-- Render
function p.renderFirerate(stat, lang)
	local isSpecial = aw.stringstarts(stat.ammo, "special_")
	local cfg2 = cfg[lang].firerate
	local tbl = mw.html.create('table'):addClass('condensedtable')
	
	-- ディヴォーションLMG
	if proto.validateTypes(stat, DevotionProto) then
		renderVariableFirerateRow(tbl, '', cfg2, stat.firerate, stat.firerate_maximum)
		
		if stat.turbocharger and aw.isNumberAndGreaterThanZero(stat.turbocharger.firerate) then
			tbl:addClass('raritytable')
			renderVariableFirerateRow(
				tbl,
				iu.hopup('turbocharger') .. '&nbsp;',
				cfg2,
				stat.turbocharger.firerate         or stat.firerate,
				stat.turbocharger.firerate_maximum or stat.firerate_maximum,
				{ rarity = Hopup.turbocharger.rarity })
		end
	
	-- ショットガン
	elseif stat.ammo == 'shotgun' then
		-- EVA-8オート
		if (Hopup.double_tap_trigger.enabled or isSpecial) and proto.validateTypes(stat, Eva8AutoProto) then
			renderMultipleFirerateRow(tbl, '', cfg2, stat.firerate)
			
			local burstAverage = {
				apex.calcBurstAverageFirerate(stat.double_tap_trigger.burst_count, stat.double_tap_trigger.burst_delay[1], stat.double_tap_trigger.firerate),
				apex.calcBurstAverageFirerate(stat.double_tap_trigger.burst_count, stat.double_tap_trigger.burst_delay[2], stat.double_tap_trigger.firerate),
				apex.calcBurstAverageFirerate(stat.double_tap_trigger.burst_count, stat.double_tap_trigger.burst_delay[3], stat.double_tap_trigger.firerate),
				apex.calcBurstAverageFirerate(stat.double_tap_trigger.burst_count, stat.double_tap_trigger.burst_delay[4], stat.double_tap_trigger.firerate),
			}
			local label = string.format('%s %s&nbsp;', iu.hopup('double_tap_trigger'), cfg2.burst_average)
			tbl:addClass('raritytable')
			renderMultipleFirerateRow(tbl, label, cfg2, burstAverage, {
				rpsClass = 'row-rarity-first disp-rarity-epic',
				rpmClass = 'row-rarity-last disp-rarity-epic',
			})
			return tbl, true
		
		-- ピースキーパー
		elseif proto.validateTypes(stat, PeacekeeperProto) then
			local calcRPS = {
				apex.calcRechamberFirerate(stat.firerate, stat.rechamber[1]),
				apex.calcRechamberFirerate(stat.firerate, stat.rechamber[2]),
				apex.calcRechamberFirerate(stat.firerate, stat.rechamber[3]),
				apex.calcRechamberFirerate(stat.firerate, stat.rechamber[4]),
			}
			renderMultipleFirerateRow(tbl, '', cfg2, calcRPS)
		
		-- マスティフショットガン・モザンビークショットガン
		elseif proto.validateTypes(stat.firerate, MultipleNumberProto) then
			renderMultipleFirerateRow(tbl, '', cfg2, stat.firerate)
		end
	
	-- mode: Burst
	elseif aw.isNumberAndGreaterThanOrEqualToX(stat.burst_count, 2) then
		local average = apex.calcBurstAverageFirerate(stat.burst_count, stat.burst_delay, stat.firerate)
		
		-- w/Altfire
		if proto.validateTypes(stat.altfire, AltfireProto) then
			tbl:addClass('listtable')
			renderFirerateRow(tbl, cfg2.burst,         cfg2, stat.firerate)
			renderFirerateRow(tbl, cfg2.burst_average, cfg2, average, { class = 'no-list-style' })
			
			local label = (stat.altfire.is_semi_auto == true or stat.is_semi_auto) and cfg2.single or cfg2.auto
			renderFirerateRow(tbl, label,              cfg2, stat.altfire.firerate)
			return tbl, true
		
		-- w/o Altfire
		else
			renderFirerateRow(tbl, '',                 cfg2, stat.firerate)
			renderFirerateRow(tbl, cfg2.burst_average, cfg2, average)
			
			-- プラウラーバーストPDW
			if (Hopup.selectfire_receiver.enabled or isSpecial) and proto.validateTypes(stat.selectfire_receiver, SelectfireReceiverProto) then
				tbl:addClass('raritytable')
				
				local label = iu.hopup('selectfire_receiver') .. '&nbsp;'
				renderFirerateRow(tbl, label, cfg2, stat.selectfire_receiver.firerate, { rarity = Hopup.selectfire_receiver.rarity })
			end
		end
	
	-- w/charge
	elseif aw.isNumberAndGreaterThanZero(stat.charge) then
		local minimum, maximum
		if aw.isNumberAndGreaterThanZero(stat.charge_minimum) then
			minimum = apex.calcRechamberFirerate(stat.firerate, stat.charge_minimum)
			maximum = apex.calcRechamberFirerate(stat.firerate, stat.charge)
		elseif aw.isNumberAndGreaterThanZero(stat.rechamber) then
			minimum = apex.calcRechamberFirerate(stat.firerate, stat.rechamber)
			maximum = apex.calcRechamberFirerate(stat.firerate, stat.rechamber + stat.charge)
		else
			minimum = stat.firerate
			maximum = apex.calcRechamberFirerate(stat.firerate, stat.charge)
		end
		
		renderVariableFirerateRow(tbl, '', cfg2, minimum, maximum)
		
		if (Hopup.deadeyes_tempo.enabled or isSpecial) and proto.validateTypes(stat.deadeyes_tempo, DeadeyesTempoWithChargeProto) then
			tbl:addClass('raritytable')
			
			local mintempo = apex.calcRechamberFirerate(stat.firerate, aw.getAsNumber(stat.deadeyes_tempo.charge_minimum, 0))
			local maxtempo = apex.calcRechamberFirerate(stat.firerate, stat.deadeyes_tempo.charge)
			local label = iu.hopup('deadeyes_tempo') .. '&nbsp;'
			renderVariableFirerateRow(tbl, label, cfg2, mintempo, maxtempo, { rarity = Hopup.deadeyes_tempo.rarity })
		end
	
	-- mode: Auto/Single
	else
		local isRarity            = false
		local hasRevvedUp         = aw.isNumberAndGreaterThanZero(stat.firerate_revvedup)
		local hasAnvilReceiver    = (Hopup.anvil_receiver.enabled     or isSpecial) and proto.validateTypes(stat.anvil_receiver, AnvilReceiverProto)
		local hasDoubleTapTrigger = (Hopup.double_tap_trigger.enabled or isSpecial) and proto.validateTypes(stat.double_tap_trigger, DoubleTapTrigggerProto)
		local hasDeadeyesTempo    = (Hopup.deadeyes_tempo.enabled     or isSpecial) and proto.validateTypes(stat.deadeyes_tempo, DeadeyesTempoWithRechamberProto)
		
		-- w/Altfire
		if proto.validateTypes(stat.altfire, AltfireProto) and stat.firerate ~= stat.altfire.firerate then
			renderFirerateRow(tbl, cfg2.auto, cfg2, calcFirerate)
			
			if aw.isNumberAndGreaterThanZero(stat.rechamber) then
				local calcFirerate = apex.calcRechamberFirerate(stat.firerate, stat.rechamber)
				renderFirerateRow(tbl, cfg2.single, cfg2, calcFirerate)
			else
				renderFirerateRow(tbl, cfg2.single, cfg2, stat.altfire.firerate)
			end
			
		-- single w/o Altfire
		elseif stat.is_semi_auto and aw.isNumberAndGreaterThanZero(stat.rechamber) then
			local calcFirerate = apex.calcRechamberFirerate(stat.firerate, stat.rechamber)
			renderFirerateRow(tbl, '', cfg2, calcFirerate)
		
		-- auto w/o Altfire
		else
			if hasRevvedUp or hasAnvilReceiver or hasDoubleTapTrigger or hasDeadeyesTempo then
				renderFirerateRow(tbl, '', cfg2, stat.firerate)
			else
				return renderFirerateText('', cfg2, stat.firerate), false
			end
		end
		
		-- Revved Up
		if hasRevvedUp then
			if not isRarity then
				tbl:addClass('raritytable')
			end
			
			local label = iu.grenade('テルミットグレネード') .. '&nbsp;'
			renderFirerateRow(tbl, label, cfg2, stat.firerate_revvedup)
		end
		
		-- Anvil Receiver
		if hasAnvilReceiver then
			if not isRarity then
				tbl:addClass('raritytable')
			end
			
			local label = iu.hopup('anvil_receiver') .. '&nbsp;'
			renderFirerateRow(tbl, label, cfg2, stat.anvil_receiver.firerate, { rarity = Hopup.anvil_receiver.rarity })
		end
		
		-- Double Tap Trigger
		if hasDoubleTapTrigger then
			if not isRarity then
				tbl:addClass('raritytable')
			end
			
			local average = apex.calcBurstAverageFirerate(stat.double_tap_trigger.burst_count, stat.double_tap_trigger.burst_delay, stat.double_tap_trigger.firerate)
			local label = iu.hopup('double_tap_trigger') .. '&nbsp;'
			renderFirerateRow(tbl, label,              cfg2, stat.double_tap_trigger.firerate, { rarity = Hopup.double_tap_trigger.rarity, rarityRowStyle = 'first' })
			renderFirerateRow(tbl, cfg2.burst_average, cfg2, average                         , { rarity = Hopup.double_tap_trigger.rarity, rarityRowStyle = 'last' })
		end
		
		-- Deadeyes Tempo
		if hasDeadeyesTempo then
			if not isRarity then
				tbl:addClass('raritytable')
			end
			
			local label = iu.hopup('deadeyes_tempo') .. '&nbsp;'
			local calcFirerate = apex.calcRechamberFirerate(stat.firerate, stat.deadeyes_tempo.rechamber)
			renderFirerateRow(tbl, label, cfg2, calcFirerate, { rarity = Hopup.deadeyes_tempo.rarity })
		end
	end
	
	return tbl, false
end

function p._main(name, lang)
	lang = lang or 'ja'
	
	stats = {
		['VK-47フラットライン'] = {
			ammo = "heavy",
			firerate = 10,
			is_semi_auto = false,
			altfire = {
				is_semi_auto = true,
			},
			anvil_receiver = {
				firerate = 2.9,
				is_semi_auto = true,
			},
		},
		['ヘムロックバーストAR'] = {
			ammo = "heavy",
			burst_count = 3,
			burst_delay = 0.28,
			firerate = 15.5,
			is_semi_auto = true,
			altfire = {
				burst_count = 0,
				burst_delay = 0,
				firerate    = 6.4,
			},
		},
		['30-30リピーター'] = {
			ammo = "heavy",
			charge = 0.35,
			firerate = 3.85,
			is_semi_auto = true,
			rechamber = 0.685,
		},
		['ボセックコンパウンドボウ'] = {
			ammo = "arrows",
			charge = 0.56,
			charge_minimum = 0.084,
			firerate = 3,
			is_semi_auto = true,
			deadeyes_tempo = {
				charge = 0.38,
				charge_minimum = 0.057,
			},
		},
		['R-99 SMG'] = {
			ammo = "light",
			firerate = 18,
			is_semi_auto = false,
		},
		['プラウラーバーストPDW'] = {
			ammo = "heavy",
			burst_count = 5,
			burst_delay = 0.24,
			firerate = 21,
			is_semi_auto = true,
			selectfire_receiver = {
				burst_count = 0,
				burst_delay = 0,
				firerate = 13.25,
				is_semi_auto = false,
			},
		},
		['ディヴォーションLMG'] = {
			ammo = "energy",
			firerate                  = 5,
			firerate_maximum          = 15,
			firerate_maximum_duration = 1.75,
			firerate_maximum_count    = 17,
			is_semi_auto = false,
			turbocharger = {
				firerate                  = 6.8,
				firerate_maximum_duration = 0.85,
				firerate_maximum_count    = 9,
			},
		},
		['センチネル'] = {
			ammo = "sniper",
			firerate = 3.1,
			is_semi_auto = true,
			rechamber = 1.6,
			deadeyes_tempo = {
				rechamber = 1.25,
			},	
		},
		['ピースキーパー'] = {
			ammo = "shotgun",
			firerate = 4,
			is_semi_auto = true,
			rechamber = { 1.1, 1.0175, 0.957, 0.924 },
		},
		['EVA-8オート'] = {
			ammo = "shotgun",
			firerate = { 2.1, 2.31, 2.415, 2.52 },
			is_semi_auto = false,
			double_tap_trigger = {
				burst_count = 2,
				burst_delay = { 0.8, 0.74, 0.7, 0.66 },
				firerate    = 6,
			},
		},
	}
	local builder = require('Module:Utility/StringBuilder').new()
	for name, stat in pairs(stats) do
		local cell = mw.html.create('div')
			:addClass('tpl-infobox-right')
			:addClass('tpl-weapon')
			:addClass('tpl-weapon-' .. stat.ammo)
			:tag('div')
				:addClass('tpl-weapon-header')
				:wikitext(name .. iu.ammo(stat.ammo, { size = 40 }))
				:done()
			:tag('table')
				:tag('tr')
					:tag('th'):wikitext(cfg[lang].firerate.name):done()
					:tag('td')
		local node, newcell = p.renderFirerate(stat, lang)
		if newcell then
			cell = cell:done():done():tag('tr'):tag('td'):attr('colspan', 2)
		end
		cell:node(node)
		builder:append(tostring(cell:allDone()))
	end
	return tostring(builder)
end

return p