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

モジュール:DamageTable

提供:Apex Data
2021年2月4日 (木) 00:01時点におけるMntone (トーク | 投稿記録)による版 (round情報を渡していなかった不具合の修正)
ナビゲーションに移動 検索に移動

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

local p = {}

local aw = require('Module:Utility/Library')
local getArgs -- lazily initialized

local function convertHslToRgb(hue, saturation, lightness)
	hue = math.max(0, math.min(1, hue))
	saturation = math.max(0, math.min(1, saturation))
	lightness = math.max(0, math.min(1, lightness))
	
	if saturation == 0 then
		return lightness, lightness, lightness
	else
		local function to(p, q, t)
			if t < 0 then t = t + 1 end
			if t > 1 then t = t - 1 end
			
			if t < 1/6 then
				return p + (q - p) * 6 * t
			elseif t < 3/6 then
				return q
			elseif t < 4/6 then
				return p + (q - p) * (2/3 - t) * 6
			else
				return p
			end
		end
		
		local q
		if lightness < 0.5 then
			q = lightness * (1 + saturation)
		else
			q = lightness + saturation - lightness * saturation
		end
		
		local p = 2 * lightness - q
		return to(p, q, hue + 1/3), to(p, q, hue), to(p, q, hue - 1/3)
	end
end

local function getColorAsString(hue)
	local r, g, b = convertHslToRgb(hue, 0.91, 0.89)
	return '#'
		.. string.format('%02X', 255 * r)
		.. string.format('%02X', 255 * g)
		.. string.format('%02X', 255 * b)
end

local function getDamage(part, info)
	local damage = info.damage
	
	-- 増幅バリケード
	if info.amped then
		damage = aw.round(1.2 * damage)
	end
	
	-- ハンマーポイント弾
	if info.hammerpoint > 1 then
		damage = aw.round(info.hammerpoint * damage)
	end
	
	-- 部位倍率
	if part ~= 1 then
		damage = aw.round(part * damage)
	end
	
	-- 小柄・鉄壁
	if info.mul == 1.05 and not info.amped then
		damage = aw.selectiveRound(info.mul * damage, info.useRound)
	elseif info.mul ~= 1 then
		damage = aw.round(info.mul * damage)
	end
	
	return damage
end

local function getDamageForPartAndPassive(damage, part, info)
	-- 部位倍率
	if part ~= 1 then
		damage = aw.round(part * damage)
	end
	
	-- 小柄・鉄壁
	if info.mul == 1.05 and not info.amped then
		damage = aw.selectiveRound(info.mul * damage, info.useRound)
	elseif info.mul ~= 1 then
		damage = aw.round(info.mul * damage)
	end
	
	return damage
end

local function _getShotCount(damage, health, info)
	local count = 0
	local damages = {}
	local damageStack = 0
	local pelletCount = info.pellet
	
	while health > 0 do
		pelletCount = pelletCount - 1
		health = health - damage
		damageStack = damageStack + damage
		
		if pelletCount == 0 then
			count = count + 1
			pelletCount = info.pellet
			table.insert(damages, damageStack)
			damageStack = 0
		end
	end
	if damageStack > 0 then
		count = count + 1
		table.insert(damages, damageStack)
	end
	return count, damages
end

local function _getShotCountForGunShield(info)
	local gunshieldinfo = aw.shallowCopy(info)
	gunshieldinfo.mul = 1
	gunshieldinfo.hammerpoint = 1
	
	local damage = getDamage(1, gunshieldinfo)
	return _getShotCount(damage, 50, gunshieldinfo)
end

local function _getShotCountForDefault(part, health, info, gunshield)
	local damage = getDamage(part, info)
	if gunshield then
		local gunshieldcount, damages = _getShotCountForGunShield(info)
		local count, damages2 = _getShotCount(damage, health, info)
		for _, value in ipairs(damages2) do
			table.insert(damages, value)
		end
		return gunshieldcount + count, damages
	else
		return _getShotCount(damage, health, info)
	end
end

local function _getShotCountForHammerpointRounds(ampedDamage, part, health, shield, info, gunshield)
	local count = 0
	local damages = {}
	local damageStack = 0
	local pelletCount = info.pellet
	
	if gunshield then
		count, damages = _getShotCountForGunShield(info)
	end
	
	local shieldDamage = getDamageForPartAndPassive(ampedDamage, part, info)
	while shield >= shieldDamage do
		pelletCount = pelletCount - 1
		shield = shield - shieldDamage
		damageStack = damageStack + shieldDamage
		
		if pelletCount == 0 then
			count = count + 1
			pelletCount = info.pellet
			table.insert(damages, damageStack)
			damageStack = 0
		end
	end
	
	if shield > 0 then
		local mergedDamage
		if shield < ampedDamage then
			mergedDamage = getDamageForPartAndPassive(shield + math.floor(info.hammerpoint * (ampedDamage - shield)), part, info)
		else
			mergedDamage = shieldDamage
		end
		pelletCount = pelletCount - 1
		health = health - (mergedDamage - shield)
		damageStack = damageStack + mergedDamage
	end
	if pelletCount == 0 then
		count = count + 1
		pelletCount = info.pellet
		table.insert(damages, damageStack)
		damageStack = 0
	end
	
	local healthDamage = getDamageForPartAndPassive(aw.round(info.hammerpoint * ampedDamage), part, info)
	while health > 0 do
		pelletCount = pelletCount - 1
		health = health - healthDamage
		damageStack = damageStack + healthDamage
		
		if pelletCount == 0 then
			count = count + 1
			pelletCount = info.pellet
			table.insert(damages, damageStack)
			damageStack = 0
		end
	end
	
	if pelletCount > 0 and pelletCount < info.pellet then
		count = count + 1
		pelletCount = info.pellet
		table.insert(damages, damageStack)
	end
	
	return count, damages
end

local function getShotCount(part, health, shield, info, gunshield)
	gunshield = gunshield or false
	
	if info.hammerpoint > 1 then
		local damage
		if info.amped then
			damage = aw.round(1.2 * info.damage)
		else
			damage = info.damage
		end
		return _getShotCountForHammerpointRounds(damage, part, health, shield, info, gunshield)
	else
		return _getShotCountForDefault(part, health + shield, info, gunshield)
	end
end

local function _arrangeArray(cache, count)
	if count > 1 then
		return cache .. '×' .. count
	else
		return cache
	end
end

local function arrangeArray(array, separator)
	local cache = array[1]
	local count = 0
	local output = nil
	for _, damage in ipairs(array) do
		if cache == damage then
			count = count + 1
		else
			local text = _arrangeArray(cache, count)
			if output ~= nil then
				output = output .. separator .. text
			else
				output = text
			end
			cache = damage
			count = 1
		end
	end
	
	local text = _arrangeArray(cache, count)
	if output ~= nil then
		output = output .. separator .. text
	else
		output = text
	end
	return output
end

local function renderHeader(table, mul, colspan)
	local row = table:tag('tr')
	local cell = row:tag('th')
		:attr('colspan', colspan)
		:attr('rowspan', 2)
	if mul == 1 then
		cell:wikitext('部位')
	else
		cell:wikitext('部位 (x' .. mul .. ')')
	end
	row:tag('th')
		:attr('rowspan', 2)
		:wikitext('ダメージ')
	row:tag('th')
		:attr('colspan', 6)
		:wikitext('確殺数')
	
	row = table:tag('tr')
	row:tag('th'):wikitext('100<small> HP</small>')
	row:tag('th')
		:attr('data-tooltip', '金バックパック蘇生')
		:wikitext('<span class="text-rarity text-rarity-legendary">120<small> HP</small></span>')
	row:tag('th'):wikitext('<span class="text-rarity text-rarity-common">150<small> HP</small></span>')
	row:tag('th'):wikitext('<span class="text-rarity text-rarity-rare">175<small> HP</small></span>')
	row:tag('th'):wikitext('<span class="text-rarity text-rarity-epic">200<small> HP</small></span>')
	row:tag('th'):wikitext('<span class="text-rarity text-rarity-heirloom">225<small> HP</small></span>')
end

local function renderCell(row, part, health, shield, info, gunshield)
	local shotCount, damages = getShotCount(part, health, shield, info, gunshield)
	local ratio = (shotCount - info.minCount) / (info.maxCount - info.minCount)
	row:tag('td')
		:attr('data-tooltip', arrangeArray(damages, '→'))
		:css('background-color', getColorAsString(0.85 * ratio))
		:wikitext(shotCount)
end

local function renderHeaderCell(row, name, rowinfo)
	for i = 1, #rowinfo do
		local cellinfo = rowinfo[i]
		local colspan = cellinfo.colspan or 1
		
		local cell = row:tag('th')
		if colspan > 1 then
			cell:attr('colspan', colspan)
		end
		if cellinfo.breaktop then
			cell:css('border-top', '0 none')
		end
		if cellinfo.breakbottom then
			cell:css('border-bottom', '0 none')
		end
		if i == #rowinfo then
			cell:wikitext(name)
		else
			cell:wikitext('&nbsp;&nbsp;')
		end
	end
end

local function renderRow(table, name, part, weaponinfo, rowinfo, gunshield)
	local row = table:tag('tr')
	renderHeaderCell(row, name, rowinfo)
	
	local damage
	if gunshield then
		if weaponinfo.amped then
			damage = aw.round(1.2 * weaponinfo.damage)
		else
			damage = weaponinfo.damage
		end
	else
		damage = getDamage(part, weaponinfo)
	end
	if weaponinfo.pellet > 1 then
		row:tag('td'):wikitext((damage * weaponinfo.pellet) .. ' <span style="white-space:nowrap"><small>(' .. damage .. ' × ' .. weaponinfo.pellet .. ')</small></span>')  
	else
		row:tag('td'):wikitext(damage)
	end
	
	renderCell(row, part, 100,   0, weaponinfo, gunshield)
	renderCell(row, part,  70,  50, weaponinfo, gunshield)
	renderCell(row, part, 100,  50, weaponinfo, gunshield)
	renderCell(row, part, 100,  75, weaponinfo, gunshield)
	renderCell(row, part, 100, 100, weaponinfo, gunshield)
	renderCell(row, part, 100, 125, weaponinfo, gunshield)
end

local function renderTable(args, frame)
	local skullpiercer = args.skullpiercer or 1
	local headMul = args.head or 2
	
	local minCount, _ = getShotCount(
		math.max(headMul, skullpiercer),
		100,
		0,
		{
			damage = math.max(args.damage, args.damagemax),
			mul = 1.05,
			pellet = args.pellet,
			amped = true,
			hammerpoint = math.max(args.hammerpoint, args.hammerpointsup),
		})
	local damagemin = math.min(args.damage, args.damagemin)
	local mininfo = {
		damage = damagemin,
		mul = 0.85,
		pellet = args.pellet,
		amped = false,
		hammerpoint = 1,
	}
	local legCount, _ = getShotCount(math.min(args.leg, args.legmin), 100, 125, mininfo)
	local bodyWithGunSheild, _ = getShotCount(1, 100, 125, mininfo, true)
	local maxCount = math.max(legCount, bodyWithGunSheild)
	local weaponinfo = {
		damage = args.damage,
		mul = args.mul,
		pellet = args.pellet,
		amped = args.amped,
		hammerpoint = args.hammerpoint,
		useRound = args.round,
		minCount = minCount,
		maxCount = maxCount,
	}
	
	local colspan, info
	if skullpiercer > 1 then
		colspan = 3
		info = {
			level1 = {
				{ breaktop = false, breakbottom = false, colspan = 3 },
			},
			level1top = {
				{ breaktop = true, breakbottom = true, colspan = 3 },
			},
			level1gunshiled = {
				{ breaktop = false, breakbottom = true, colspan = 3 },
			},
			level2 = {
				{ breaktop = true, breakbottom = true },
				{ breaktop = true, breakbottom = false, colspan = 2 },
			},
			level2gunshiled = {
				{ breaktop = true, breakbottom = false },
				{ breaktop = false, breakbottom = false, colspan = 2 },
			},
			level3 = {
				{ breaktop = true, breakbottom = true },
				{ breaktop = false, breakbottom = true },
				{ breaktop = false, breakbottom = false },
			},
			level3top = {
				{ breaktop = false, breakbottom = true, colspan = 2 },
				{ breaktop = false, breakbottom = false },
			},
		}
	else
		colspan = 2
		info = {
			level1 = {
				{ breaktop = false, breakbottom = true, colspan = 2 },
			},
			level1gunshiled = {
				{ breaktop = false, breakbottom = true, colspan = 2 },
			},
			level2 = {
				{ breaktop = true, breakbottom = true },
				{ breaktop = false, breakbottom = false },
			},
			level2gunshiled = {
				{ breaktop = true, breakbottom = false },
				{ breaktop = false, breakbottom = false },
			},
		}
		info.level1top = info.level1
	end
	
	local skullpiercerHtml
	if frame ~= nil then
		skullpiercerHtml = frame:expandTemplate { title = 'Hopup', args = { "スカルピアサーライフリング" }} .. ' '
	else
		skullpiercerHtml = ''
	end
	
	local table = mw.html.create('table')
		:addClass('wikitable')
		:addClass('numbertable')
	if args.caption ~= nil then
		table:tag('caption')
			:wikitext(args.caption)
	end
	
	renderHeader(table, args.mul, colspan)
	
	if skullpiercer > 1 then
		renderRow(
			table,
			skullpiercerHtml .. '(x' .. skullpiercer .. ')',
			skullpiercer, weaponinfo, info.level3top)
	end
	
	renderRow(
		table,
		"頭 (x" .. headMul .. ")",
		headMul, weaponinfo, info.level1top)
	
	if skullpiercer > 1 then
		local skullpiercerLv1Mul = 0.2 + 0.8 * skullpiercer
		renderRow(
			table,
			skullpiercerHtml .. '<span class="text-rarity text-rarity-common">(x' .. skullpiercerLv1Mul .. ')</span>',
			skullpiercerLv1Mul, weaponinfo, info.level3)
	end
	
	local hlmLv1Mul = 0.2 + 0.8 * headMul
	renderRow(
		table,
		'<span class="text-rarity text-rarity-common">Lv.1 (x' .. hlmLv1Mul .. ')</span>',
		hlmLv1Mul, weaponinfo, info.level2)
	
	if skullpiercer > 1 then
		local skullpiercerLv2Mul = 0.4 + 0.6 * skullpiercer
		renderRow(
			table,
			skullpiercerHtml .. '<span class="text-rarity text-rarity-rare">(x' .. skullpiercerLv2Mul .. ')</span>',
			skullpiercerLv2Mul, weaponinfo, info.level3)
	end
	
	local hlmLv2Mul = 0.4 + 0.6 * headMul
	renderRow(
		table,
		'<span class="text-rarity text-rarity-rare">Lv.2 (x' .. hlmLv2Mul .. ')</span>',
		hlmLv2Mul, weaponinfo, info.level2)
	
	if skullpiercer > 1 then
		local skullpiercerLv3Mul = 0.5 + 0.5 * skullpiercer
		renderRow(
			table,
			skullpiercerHtml .. '<span class="text-rarity text-rarity-epic">(x' .. skullpiercerLv3Mul .. ')</span>',
			skullpiercerLv3Mul, weaponinfo, info.level3)
	end
	
	local hlmLv3Mul = 0.5 + 0.5 * headMul
	renderRow(
		table,
		'<span class="text-rarity text-rarity-epic">Lv.3</span>/<span class="text-rarity text-rarity-legendary">4</span> <span class="text-rarity text-rarity-epic">(x' .. hlmLv3Mul .. ')</span>',
		hlmLv3Mul, weaponinfo, info.level2)
	
	if args.leg == 1 then
		if args.mul == 0.85 then
			renderRow(table, "胴・脚",        1,     weaponinfo, info.level1gunshiled)
			renderRow(table, '+ガンシールド', 1,     weaponinfo, info.level2gunshiled, true)
		else
			renderRow(table, "胴・脚", 1, weaponinfo, info.level1)
		end
	else
		if args.mul == 1.05 then
			renderRow(table, "胴・脚", 1, weaponinfo, info.level1)
		else
			if args.mul == 0.85 then
				renderRow(table, "胴",            1, weaponinfo, info.level1gunshiled)
				renderRow(table, '+ガンシールド', 1, weaponinfo, info.level2gunshiled, true)
			else
				renderRow(table, "胴", 1, weaponinfo, info.level1)
			end
			renderRow(table, "脚 (x" .. args.leg .. ")", args.leg, weaponinfo, info.level1)
		end
	end
	
	return table
end

function p._main(args, frame)
	-- init value
	local initValues = {
		damage = 20,
		damagemin = 1000,
		damagemax = 0,
		pellet = 1,
		head = 2,
		leg = 0.8,
		legmin = 0,
		mul = 1,
		skullpiercer = 1,
		hammerpoint = 1,
		hammerpointsup = 1,
	}
	
	-- fix arguments
	for key, value in pairs(initValues) do
		args[key] = aw.getAsNumber(args[key], value)
	end
	if args.legmin == 0 then
		args.legmin = args.leg
	end
	args.round = aw.getAsBoolean(args.round, false)
	args.amped = aw.getAsBoolean(args.amped, false)
	
	return tostring(renderTable(args, frame))
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