| 🌟 | 現在、 鉄壁HSは通常HSと同じダメージになります。LMG及びDMR、チャージライフル、ハンマーポイント弾を除き、すべてのダメージ値が一致していることを確認しています。  | 
「モジュール:DamageTable」の版間の差分
		
		
		
		
		
		ナビゲーションに移動
		検索に移動
		
				
		
		
	
 (増幅バリケードを経由する場合の丸め演算が間違っていた問題の修正)  | 
				 (ハンマーポイント弾の正式な計算を実装)  | 
				||
| 1行目: | 1行目: | ||
local p = {}  | local p = {}  | ||
local aw = require('Module:Utility/Library')  | |||
local getArgs -- lazily initialized  | local getArgs -- lazily initialized  | ||
local function round(num)  | local function round(num)  | ||
	return math.floor(tonumber(string.format("%.  | 	return math.floor(tonumber(string.format("%.4f", num)) + 0.5)  | ||
end  | end  | ||
local function roundover(num)  | local function roundover(num)  | ||
	return math.ceil(tonumber(string.format("%.  | 	return math.ceil(tonumber(string.format("%.4f", num)) - 0.5)  | ||
end  | end  | ||
| 63行目: | 64行目: | ||
end  | end  | ||
local function   | local function getDamage(part, info)  | ||
	return math.  | 	local damage = info.damage  | ||
	-- 増幅バリケード  | |||
	if info.amped then  | |||
		damage = round(1.2 * damage)  | |||
	end  | |||
	-- ハンマーポイント弾  | |||
	if info.hammerpoint > 1 then  | |||
		damage = round(info.hammerpoint * damage)  | |||
	end  | |||
	-- 部位倍率  | |||
	if part ~= 1 then  | |||
		damage = round(part * damage)  | |||
	end  | |||
	-- 小柄・鉄壁  | |||
	if info.mul == 1.05 and not info.amped then  | |||
		damage = selectiveRound(info.mul * damage, info.useRound)  | |||
	elseif info.mul ~= 1 then  | |||
		damage = round(info.mul * damage)  | |||
	end  | |||
	return damage  | |||
end  | |||
local function getDamageForPartAndPassive(damage, part, info)  | |||
	-- 部位倍率  | |||
	if part ~= 1 then  | |||
		damage = round(part * damage)  | |||
	end  | |||
	-- 小柄・鉄壁  | |||
	if info.mul == 1.05 and not info.amped then  | |||
		damage = selectiveRound(info.mul * damage, info.useRound)  | |||
	elseif info.mul ~= 1 then  | |||
		damage = 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(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 = 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  | end  | ||
| 93行目: | 299行目: | ||
end  | end  | ||
local function renderCell(row,   | local function renderCell(row, part, health, shield, info, gunshield)  | ||
	local shotCount = getShotCount(  | 	local shotCount, damages = getShotCount(part, health, shield, info, gunshield)  | ||
	local ratio = (shotCount   | 	local ratio = (shotCount - info.minCount) / (info.maxCount - info.minCount)  | ||
	row:tag('td')  | 	row:tag('td')  | ||
		:attr('align', 'right')  | 		:attr('align', 'right')  | ||
		:attr('title', arrangeArray(damages, '→'))  | |||
		:css('background-color', getColorAsString(0.85 * ratio))  | 		:css('background-color', getColorAsString(0.85 * ratio))  | ||
		:wikitext(  | 		:wikitext(shotCount)  | ||
end  | end  | ||
| 137行目: | 332行目: | ||
end  | end  | ||
local function renderRow(table, name,   | local function renderRow(table, name, part, weaponinfo, rowinfo, gunshield)  | ||
	local row = table:tag('tr')  | 	local row = table:tag('tr')  | ||
	renderHeaderCell(row, name, rowinfo)  | 	renderHeaderCell(row, name, rowinfo)  | ||
	if pellet > 1 then  | 	local damage  | ||
		row:tag('td'):attr('align', 'right'):wikitext((damage * pellet) .. ' <span style="white-space:nowrap"><small>(' .. damage .. ' × ' .. pellet .. ')</small></span>')     | 	if gunshield then  | ||
		if weaponinfo.amped then  | |||
			damage = round(1.2 * weaponinfo.damage)  | |||
		else  | |||
			damage = weaponinfo.damage  | |||
		end  | |||
	else  | |||
		damage = getDamage(part, weaponinfo)  | |||
	end  | |||
	if weaponinfo.pellet > 1 then  | |||
		row:tag('td'):attr('align', 'right'):wikitext((damage * weaponinfo.pellet) .. ' <span style="white-space:nowrap"><small>(' .. damage .. ' × ' .. weaponinfo.pellet .. ')</small></span>')     | |||
	else  | 	else  | ||
		row:tag('td'):attr('align', 'right'):wikitext(damage)  | 		row:tag('td'):attr('align', 'right'):wikitext(damage)  | ||
	end  | 	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  | end  | ||
local function renderTable(args, frame)  | local function renderTable(args, frame)  | ||
	local skullpiercer = args.skullpiercer or 1  | 	local skullpiercer = args.skullpiercer or 1  | ||
	local headMul = args.head or 2  | 	local headMul = args.head or 2  | ||
	local minCount = getShotCount(  | 	local minCount, _ = getShotCount(  | ||
	local   | 		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(args.leg, 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,  | |||
		minCount = minCount,  | |||
		maxCount = maxCount,  | |||
	}  | |||
	local colspan, info  | 	local colspan, info  | ||
	if skullpiercer > 1 then  | 	if skullpiercer > 1 then  | ||
| 268行目: | 463行目: | ||
	end  | 	end  | ||
	renderHeader(table, mul, colspan)  | 	renderHeader(table, args.mul, colspan)  | ||
	if skullpiercer > 1 then  | 	if skullpiercer > 1 then  | ||
| 274行目: | 469行目: | ||
			table,  | 			table,  | ||
			skullpiercerHtml .. '(x' .. skullpiercer .. ')',  | 			skullpiercerHtml .. '(x' .. skullpiercer .. ')',  | ||
			skullpiercer, weaponinfo, info.level3top)  | |||
	end  | 	end  | ||
| 281行目: | 475行目: | ||
		table,  | 		table,  | ||
		"頭 (x" .. headMul .. ")",  | 		"頭 (x" .. headMul .. ")",  | ||
		headMul, weaponinfo, info.level1top)  | |||
	if skullpiercer > 1 then  | 	if skullpiercer > 1 then  | ||
| 289行目: | 482行目: | ||
			table,  | 			table,  | ||
			skullpiercerHtml .. '<span class="text-rarity text-rarity-common">(x' .. skullpiercerLv1Mul .. ')</span>',  | 			skullpiercerHtml .. '<span class="text-rarity text-rarity-common">(x' .. skullpiercerLv1Mul .. ')</span>',  | ||
			skullpiercerLv1Mul, weaponinfo, info.level3)  | |||
	end  | 	end  | ||
| 297行目: | 489行目: | ||
		table,  | 		table,  | ||
		'<span class="text-rarity text-rarity-common">Lv.1 (x' .. hlmLv1Mul .. ')</span>',  | 		'<span class="text-rarity text-rarity-common">Lv.1 (x' .. hlmLv1Mul .. ')</span>',  | ||
		hlmLv1Mul, weaponinfo, info.level2)  | |||
	if skullpiercer > 1 then  | 	if skullpiercer > 1 then  | ||
| 305行目: | 496行目: | ||
			table,  | 			table,  | ||
			skullpiercerHtml .. '<span class="text-rarity text-rarity-rare">(x' .. skullpiercerLv2Mul .. ')</span>',  | 			skullpiercerHtml .. '<span class="text-rarity text-rarity-rare">(x' .. skullpiercerLv2Mul .. ')</span>',  | ||
			skullpiercerLv2Mul, weaponinfo, info.level3)  | |||
	end  | 	end  | ||
| 313行目: | 503行目: | ||
		table,  | 		table,  | ||
		'<span class="text-rarity text-rarity-rare">Lv.2 (x' .. hlmLv2Mul .. ')</span>',  | 		'<span class="text-rarity text-rarity-rare">Lv.2 (x' .. hlmLv2Mul .. ')</span>',  | ||
		hlmLv2Mul, weaponinfo, info.level2)  | |||
	if skullpiercer > 1 then  | 	if skullpiercer > 1 then  | ||
| 321行目: | 510行目: | ||
			table,  | 			table,  | ||
			skullpiercerHtml .. '<span class="text-rarity text-rarity-epic">(x' .. skullpiercerLv3Mul .. ')</span>',  | 			skullpiercerHtml .. '<span class="text-rarity text-rarity-epic">(x' .. skullpiercerLv3Mul .. ')</span>',  | ||
			skullpiercerLv3Mul, weaponinfo, info.level3)  | |||
	end  | 	end  | ||
| 329行目: | 517行目: | ||
		table,  | 		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>',  | 		'<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 legMul == 1 then  | 	if legMul == 1 then  | ||
		if mul == 0.85 then  | 		if args.mul == 0.85 then  | ||
			renderRow(table, "胴・脚",   | 			renderRow(table, "胴・脚",        1,     weaponinfo, info.level1gunshiled)  | ||
			renderRow(table, '+ガンシールド', 1,     weaponinfo, info.level2gunshiled, true)  | |||
		else  | 		else  | ||
			renderRow(table, "胴・脚",   | 			renderRow(table, "胴・脚", 1, weaponinfo, info.level1)  | ||
		end  | 		end  | ||
	else  | 	else  | ||
		if mul == 1.05 then  | 		if args.mul == 1.05 then  | ||
			renderRow(table, "胴・脚",   | 			renderRow(table, "胴・脚", 1, weaponinfo, info.level1)  | ||
		else  | 		else  | ||
			if mul == 0.85 then  | 			if args.mul == 0.85 then  | ||
				renderRow(table, "胴",   | 				renderRow(table, "胴",            1, weaponinfo, info.level1gunshiled)  | ||
				renderRow(table, '+ガンシールド', 1, weaponinfo, info.level2gunshiled, true)  | |||
			else  | 			else  | ||
				renderRow(table, "胴",   | 				renderRow(table, "胴", 1, weaponinfo, info.level1)  | ||
			end  | 			end  | ||
			renderRow(  | 			renderRow(table, "脚 (x" .. args.leg .. ")", args.leg, weaponinfo, info.level1)  | ||
		end  | 		end  | ||
	end  | 	end  | ||
| 361行目: | 544行目: | ||
function p._main(args, frame)  | function p._main(args, frame)  | ||
	-- init value  | |||
	local initValues = {  | |||
		damage = 20,  | |||
		damagemin = 1000,  | |||
		damagemax = 0,  | |||
		pellet = 1,  | |||
		head = 2,  | |||
		leg = 0.8,  | |||
		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  | |||
	args.round = aw.getAsBoolean(args.round, false)  | |||
	args.amped = aw.getAsBoolean(args.amped, false)  | |||
	return tostring(renderTable(args, frame))  | 	return tostring(renderTable(args, frame))  | ||
end  | end  | ||
| 369行目: | 573行目: | ||
	end  | 	end  | ||
	args = getArgs(frame)  | 	args = getArgs(frame)  | ||
	return p._main(args, frame)  | 	return p._main(args, frame)  | ||
2021年2月1日 (月) 18:05時点における版
このモジュールについての説明文ページを モジュール:DamageTable/doc に作成できます
local p = {}
local aw = require('Module:Utility/Library')
local getArgs -- lazily initialized
local function round(num)
	return math.floor(tonumber(string.format("%.4f", num)) + 0.5)
end
local function roundover(num)
	return math.ceil(tonumber(string.format("%.4f", num)) - 0.5)
end
local function selectiveRound(num, useRound)
	useRound = useRound or false
	if useRound then
		return round(num)
	else
		return roundover(num)
	end
end
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 = round(1.2 * damage)
	end
	
	-- ハンマーポイント弾
	if info.hammerpoint > 1 then
		damage = round(info.hammerpoint * damage)
	end
	
	-- 部位倍率
	if part ~= 1 then
		damage = round(part * damage)
	end
	
	-- 小柄・鉄壁
	if info.mul == 1.05 and not info.amped then
		damage = selectiveRound(info.mul * damage, info.useRound)
	elseif info.mul ~= 1 then
		damage = round(info.mul * damage)
	end
	
	return damage
end
local function getDamageForPartAndPassive(damage, part, info)
	-- 部位倍率
	if part ~= 1 then
		damage = round(part * damage)
	end
	
	-- 小柄・鉄壁
	if info.mul == 1.05 and not info.amped then
		damage = selectiveRound(info.mul * damage, info.useRound)
	elseif info.mul ~= 1 then
		damage = 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(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 = 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'):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('align', 'right')
		:attr('title', 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('  ')
		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 = round(1.2 * weaponinfo.damage)
		else
			damage = weaponinfo.damage
		end
	else
		damage = getDamage(part, weaponinfo)
	end
	if weaponinfo.pellet > 1 then
		row:tag('td'):attr('align', 'right'):wikitext((damage * weaponinfo.pellet) .. ' <span style="white-space:nowrap"><small>(' .. damage .. ' × ' .. weaponinfo.pellet .. ')</small></span>')  
	else
		row:tag('td'):attr('align', 'right'):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(args.leg, 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,
		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 legMul == 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,
		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
	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