<!DOCTYPE html>
<html lang="ja">
<head>
<meta charset="UTF-8">
<title>遮断ダメージ計算ツール</title>
<style>
body { font-family: sans-serif; padding: 20px; }
label { display: block; margin-top: 10px; }
input { width: 220px; }
button {
margin-top: 20px;
font-size: 20px;
padding: 12px 30px;
background-color: #007BFF;
color: white;
border: none;
border-radius: 8px;
cursor: pointer;
transition: background-color 0.3s ease;
}
button:hover {
background-color: #0056b3;
}
#result, #formula {
margin-top: 20px;
white-space: pre-line;
background: #f9f9f9;
padding: 10px;
border-radius: 5px;
border: 1px solid #ccc;
}
</style>
</head>
<body>
<h2>遮断ダメージ計算ツール</h2>
<label>最大HP: <input type="text" id="hp" value="0"></label>
<label>受けるダメージ: <input type="text" id="damage" value="0"></label>
<label>被ダメージ減少(%カット): <input type="text" id="reduction" value="0"></label>
<label>遮断ライン(HPの何%を超えた分に遮断適用): <input type="text" id="aPercent" value="0"></label>
<label>遮断率(超過部分のダメージを何%遮断): <input type="text" id="blockRate" value="0"></label>
<button onclick="calculate()">計算</button>
<div id="result"></div>
<div id="formula"></div>
<script>
function parseMixedNumber(input) {
const units = { '億': 100000000, '万': 10000 };
let total = 0;
let matched = false;
for (let unit in units) {
const regex = new RegExp('(\\d+(?:\\.\\d+)?)' + unit);
const match = input.match(regex);
if (match) {
total += parseFloat(match[1]) * units[unit];
input = input.replace(match[0], '');
matched = true;
}
}
if (input.match(/[一二三四五六七八九〇十百千万億]/)) {
total += kanjiToNumber(input);
matched = true;
} else if (input
.trim().length
> 0) { total += parseFloat(input);
matched = true;
}
return matched ? total : NaN;
}
function kanjiToNumber(kanji) {
const nums = { '〇': 0, '一': 1, '二': 2, '三': 3, '四': 4, '五': 5, '六': 6, '七': 7, '八': 8, '九': 9 };
const units = { '十': 10, '百': 100, '千': 1000 };
const bigUnits = { '万': 10000, '億': 100000000 };
let total = 0;
const parseSection = (str) => {
let n = 0, temp = 0;
for (let c of str) {
if (nums[c] !== undefined) {
temp = nums[c];
} else if (units[c]) {
n += (temp || 1) * units[c];
temp = 0;
}
}
return n + temp;
};
let tmp = kanji;
for (let unit in bigUnits) {
const idx = tmp.indexOf(unit);
if (idx !== -1) {
const left = tmp.slice(0, idx);
total += parseSection(left) * bigUnits[unit];
tmp = tmp.slice(idx + 1);
}
}
total += parseSection(tmp);
return total;
}
function formatNumber(num) {
if (num >= 100000000) return (num / 100000000).toFixed(2).replace(/\.00$/, '') + "億";
if (num >= 10000) return (num / 10000).toFixed(2).replace(/\.00$/, '') + "万";
return num.toLocaleString();
}
function calculate() {
const hp = parseMixedNumber(document.getElementById("hp").value);
let damage = parseMixedNumber(document.getElementById("damage").value);
const originalDamage = damage;
const reductionRate = parseFloat(document.getElementById("reduction").value) / 100 || 0;
const aPercent = parseFloat(document.getElementById("aPercent").value) / 100 || 0;
const blockRate = parseFloat(document.getElementById("blockRate").value) / 100 || 0;
if (isNaN(hp) || isNaN(damage)) {
document.getElementById("result").innerText = "HPまたはダメージが無効です。";
document.getElementById("formula").innerText = "";
return;
}
damage = damage * (1 - reductionRate);
const threshold = hp * aPercent;
const excess
= Math
.max(0, damage
- threshold
); const blockedDamage = excess * (1 - blockRate);
const nonBlockedDamage = damage - excess;
const totalDamage = nonBlockedDamage + blockedDamage;
const resultHP = hp - totalDamage;
const attackCount = totalDamage > 0 ? (hp / totalDamage) : Infinity;
const attackCountDisplay = attackCount === Infinity ? "∞" : attackCount.toFixed(3);
const finalBlockRate = (1 - (totalDamage / originalDamage)) * 100;
const finalBlockRateDisplay = isFinite(finalBlockRate) ? finalBlockRate.toFixed(2) + "%" : "0%";
document.getElementById("result").innerText =
`受けたダメージ: ${formatNumber(totalDamage)}\n残りHP: ${formatNumber(resultHP)}\n` +
`最終遮断率: ${finalBlockRateDisplay}\n` +
`このダメージでHPを0以下にするには 約 ${attackCountDisplay} 回攻撃が必要`;
document.getElementById("formula").innerText =
`計算詳細:
最大HP: ${formatNumber(hp)}
受けるダメージ(初期): ${formatNumber(originalDamage)}
被ダメージ減少: ${(reductionRate * 100).toFixed(1)}% → ${formatNumber(damage)}
遮断発動ライン: ${formatNumber(threshold)}(${(aPercent * 100).toFixed(1)}%)
超過ダメージ: ${formatNumber(excess)}
遮断率: ${(blockRate * 100).toFixed(1)}%
遮断後の超過ダメージ: ${formatNumber(blockedDamage)}
非遮断ダメージ: ${formatNumber(nonBlockedDamage)}
合計ダメージ: ${formatNumber(totalDamage)}
最終遮断率(元のダメージと比較): ${finalBlockRateDisplay}
残りHP: ${formatNumber(hp)} - ${formatNumber(totalDamage)} = ${formatNumber(resultHP)}
HPを0以下にするのに必要な攻撃回数: 約 ${attackCountDisplay} 回`;
}
</script>
</body>
</html>