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

「モジュール:DamageTable」の版間の差分

提供:Apex Data
ナビゲーションに移動 検索に移動
(ホップアップのレアリティー情報が正しく反映されなかった問題の修正)
(データ構造変更による実装の変更)
353行目: 353行目:


local function renderTable(args)
local function renderTable(args)
local shields = require('Module:Stat/Shield')[args.shieldpreset]
local shieldinfo = require('Module:Stat/Shield')[args.shieldpreset]
local skullpiercer = args.skullpiercer or 1
local skullpiercer = args.skullpiercer or 1
local headMul = args.head or 2
local headMul = args.head or 2
376行目: 376行目:
hammerpoint = 1,
hammerpoint = 1,
}
}
local shieldinfo = shields[#shields]
local maxshield = shieldinfo.shields[#shieldinfo.shields]
local legCount, _ = getShotCount(math.min(args.leg, args.legmin), shieldinfo.health, shieldinfo.shield, mininfo)
local legCount, _ = getShotCount(math.min(args.leg, args.legmin), maxshield.health, maxshield.shield, mininfo)
local bodyWithGunSheild, _ = getShotCount(1, shieldinfo.health, shieldinfo.shield, mininfo, args.gunshield)
local bodyWithGunSheild, _ = getShotCount(1, maxshield.health, maxshield.shield, mininfo)
local maxCount = math.max(legCount, bodyWithGunSheild)
local maxCount = math.max(legCount, bodyWithGunSheild)
local weaponinfo = {
local weaponinfo = {
389行目: 389行目:
minCount = minCount,
minCount = minCount,
maxCount = maxCount,
maxCount = maxCount,
shields = shields,
shields = shieldinfo.shields,
}
}
453行目: 453行目:
end
end
renderHeader(table, args.mul, colspan, shields)
renderHeader(table, args.mul, colspan, shieldinfo.shields)
if skullpiercer > 1 then
if skullpiercer > 1 then
520行目: 520行目:
if args.mul < 1 or args.forcegunshield then
if args.mul < 1 or args.forcegunshield then
renderRow(table, "胴・脚",        nil, 1,    weaponinfo, info.level1gunshiled)
renderRow(table, "胴・脚",        nil, 1,    weaponinfo, info.level1gunshiled)
renderRow(table, '+ガンシールド', nil, 1,    weaponinfo, info.level2gunshiled, args.gunshield)
renderRow(table, '+ガンシールド', nil, 1,    weaponinfo, info.level2gunshiled, shieldinfo.gunshield)
else
else
renderRow(table, "胴・脚", nil, 1, weaponinfo, info.level1)
renderRow(table, "胴・脚", nil, 1, weaponinfo, info.level1)
530行目: 530行目:
if args.mul < 1 or args.forcegunshield then
if args.mul < 1 or args.forcegunshield then
renderRow(table, "胴",            nil, 1, weaponinfo, info.level1gunshiled)
renderRow(table, "胴",            nil, 1, weaponinfo, info.level1gunshiled)
renderRow(table, '+ガンシールド', nil, 1, weaponinfo, info.level2gunshiled, args.gunshield)
renderRow(table, '+ガンシールド', nil, 1, weaponinfo, info.level2gunshiled, shieldinfo.gunshield)
else
else
renderRow(table, "胴", nil, 1, weaponinfo, info.level1)
renderRow(table, "胴", nil, 1, weaponinfo, info.level1)
559行目: 559行目:
hammerpoint = 1,
hammerpoint = 1,
hammerpointsup = 1,
hammerpointsup = 1,
gunshield = 50,
}
}

2021年2月6日 (土) 18:29時点における版

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

local p = {}

local aw = require('Module:Utility/Library')
local formatter -- lazily initialized
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 = math.floor(info.hammerpoint * damage)
	end
	
	-- 部位倍率
	if part ~= 1 then
		damage = aw.round(part * damage)
	end
	
	-- 小柄・鉄壁
	if info.mul == 1.05 then
		if info.amped then
			damage = aw.roundover(info.mul * damage)
		else
			damage = aw.selectiveRound(info.mul * damage, info.useRound)
		end
	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 then
		if info.amped then
			damage = aw.roundover(info.mul * damage)
		else
			damage = aw.selectiveRound(info.mul * damage, info.useRound)
		end
	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, gunshield)
	local gunshieldinfo = aw.shallowCopy(info)
	gunshieldinfo.mul = 1
	gunshieldinfo.hammerpoint = 1
	
	local damage = getDamage(1, gunshieldinfo)
	return _getShotCount(damage, gunshield, gunshieldinfo)
end

local function _getShotCountForDefault(part, health, info, gunshield)
	local damage = getDamage(part, info)
	if gunshield > 0 then
		local gunshieldcount, damages = _getShotCountForGunShield(info, gunshield)
		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 > 0 then
		count, damages = _getShotCountForGunShield(info, gunshield)
	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(math.floor(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 0
	
	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, shields)
	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', #shields)
		:wikitext('確殺数')
	
	row = table:tag('tr')
	for _, shield in ipairs(shields) do
		local cell = row:tag('th')
		if shield.tooltip ~= nil then
			cell:attr('data-tooltip', shield.tooltip)
		end
		cell:wikitext(shield.label)
	end
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, tooltip, 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
			if tooltip ~= nil then
				cell:attr('data-tooltip', tooltip)
			end
			cell:wikitext(name)
		else
			cell:wikitext('&nbsp;&nbsp;')
		end
	end
end

local function renderRow(table, name, tooltip, part, weaponinfo, rowinfo, gunshield)
	local row = table:tag('tr')
	renderHeaderCell(row, name, tooltip, 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
	
	for _, shield in ipairs(weaponinfo.shields) do
		renderCell(row, part, shield.health, shield.shield, weaponinfo, gunshield)
	end
end

local function renderTable(args)
	local shieldinfo = require('Module:Stat/Shield')[args.shieldpreset]
	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 = math.max(args.mul, args.mulmax),
			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 = math.min(args.mul, args.mulmin),
		pellet = args.pellet,
		amped = false,
		hammerpoint = 1,
	}
	local maxshield = shieldinfo.shields[#shieldinfo.shields]
	local legCount, _ = getShotCount(math.min(args.leg, args.legmin), maxshield.health, maxshield.shield, mininfo)
	local bodyWithGunSheild, _ = getShotCount(1, maxshield.health, maxshield.shield, mininfo)
	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,
		shields = shieldinfo.shields,
	}
	
	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 skullpiercerPrefix = formatter:hopup('スカルピアサーライフリング', { rariry = args.skullpiercerrariry })
	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, shieldinfo.shields)
	
	if skullpiercer > 1 then
		renderRow(
			table,
			skullpiercerPrefix .. '(x' .. skullpiercer .. ')',
			nil,
			skullpiercer, weaponinfo, info.level3top)
	end
	
	renderRow(
		table,
		"頭 (x" .. headMul .. ")",
		nil,
		headMul, weaponinfo, info.level1top)
	
	if skullpiercer > 1 then
		local skullpiercerLv1Mul = 0.2 + 0.8 * skullpiercer
		renderRow(
			table,
			skullpiercerPrefix .. formatter:common('(x' .. skullpiercerLv1Mul .. ')'),
			'0.2 + 0.8 × ' .. skullpiercer,
			skullpiercerLv1Mul, weaponinfo, info.level3)
	end
	
	local hlmLv1Mul = 0.2 + 0.8 * headMul
	renderRow(
		table,
		formatter:common('Lv.1 (x' .. hlmLv1Mul .. ')'),
		'0.2 + 0.8 × ' .. headMul,
		hlmLv1Mul, weaponinfo, info.level2)
	
	if skullpiercer > 1 then
		local skullpiercerLv2Mul = 0.4 + 0.6 * skullpiercer
		renderRow(
			table,
			skullpiercerPrefix .. formatter:rare('(x' .. skullpiercerLv2Mul .. ')'),
			'0.4 + 0.6 × ' .. skullpiercer,
			skullpiercerLv2Mul, weaponinfo, info.level3)
	end
	
	local hlmLv2Mul = 0.4 + 0.6 * headMul
	renderRow(
		table,
		formatter:rare('Lv.2 (x' .. hlmLv2Mul .. ')'),
		'0.4 + 0.6 × ' .. headMul,
		hlmLv2Mul, weaponinfo, info.level2)
	
	if skullpiercer > 1 then
		local skullpiercerLv3Mul = 0.5 + 0.5 * skullpiercer
		renderRow(
			table,
			skullpiercerPrefix .. formatter:epic('(x' .. skullpiercerLv3Mul .. ')'),
			'0.5 + 0.5 × ' .. skullpiercer,
			skullpiercerLv3Mul, weaponinfo, info.level3)
	end
	
	local hlmLv3Mul = 0.5 + 0.5 * headMul
	renderRow(
		table,
		formatter:epic('Lv.3') .. '/' .. formatter:legendary('4') .. ' ' .. formatter:epic('(x' .. hlmLv3Mul .. ')'),
		'0.5 + 0.5 × ' .. headMul,
		hlmLv3Mul, weaponinfo, info.level2)
	
	if args.leg == 1 then
		if args.mul < 1 or args.forcegunshield then
			renderRow(table, "胴・脚",        nil, 1,     weaponinfo, info.level1gunshiled)
			renderRow(table, '+ガンシールド', nil, 1,     weaponinfo, info.level2gunshiled, shieldinfo.gunshield)
		else
			renderRow(table, "胴・脚", nil, 1, weaponinfo, info.level1)
		end
	else
		if args.mul == 1.05 then
			renderRow(table, "胴・脚", nil, 1, weaponinfo, info.level1)
		else
			if args.mul < 1 or args.forcegunshield then
				renderRow(table, "胴",            nil, 1, weaponinfo, info.level1gunshiled)
				renderRow(table, '+ガンシールド', nil, 1, weaponinfo, info.level2gunshiled, shieldinfo.gunshield)
			else
				renderRow(table, "胴", nil, 1, weaponinfo, info.level1)
			end
			renderRow(table, "脚 (x" .. args.leg .. ")", nil, args.leg, weaponinfo, info.level1)
		end
	end
	
	return table
end

function p._main(args, frame)
	formatter = require('Module:Utility/Formatter').new(frame)
	
	-- init value
	local initValues = {
		damage = 20,
		damagemin = 1000,
		damagemax = 0,
		pellet = 1,
		head = 2,
		leg = 0.8,
		legmin = 0,
		mul = 1,
		mulmin = 0.85,
		mulmax = 1.05,
		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)
	args.forcegunshield = aw.getAsBoolean(args.forcegunshield, false)
	args.skullpiercerrariry = args.skullpiercerrariry or 'legendary'
	args.shieldpreset = args.shieldpreset or 'evoshieldonly'
	
	return tostring(renderTable(args))
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