Skip to content

Instantly share code, notes, and snippets.

@opparco
Last active February 25, 2025 14:42
Show Gist options
  • Save opparco/21ce5bc98ce4e1453d164d6302de42b1 to your computer and use it in GitHub Desktop.
Save opparco/21ce5bc98ce4e1453d164d6302de42b1 to your computer and use it in GitHub Desktop.
Dungeon Hack generated by Claude 3.7 Sonnet lang:ja
<!DOCTYPE html>
<html lang="ja">
<head>
<meta charset="UTF-8">
<meta name="viewport" content="width=device-width, initial-scale=1.0">
<title>ダンジョンハック</title>
<style>
body {
font-family: 'Helvetica Neue', Arial, sans-serif;
background-color: #1a1a2e;
color: #e6e6ff;
margin: 0;
padding: 20px;
display: flex;
flex-direction: column;
align-items: center;
min-height: 100vh;
}
.container {
max-width: 800px;
width: 100%;
}
h1 {
color: #4db8ff;
text-align: center;
text-shadow: 0 0 10px rgba(77, 184, 255, 0.5);
}
.game-area {
background-color: #252547;
border-radius: 10px;
padding: 20px;
margin-bottom: 20px;
box-shadow: 0 0 15px rgba(77, 184, 255, 0.3);
}
.character-sheet {
display: grid;
grid-template-columns: 1fr 1fr;
gap: 10px;
margin-bottom: 20px;
}
.status-section, .skills-section {
background-color: #333366;
padding: 15px;
border-radius: 8px;
}
.dungeon-area {
position: relative;
min-height: 200px;
background-color: #333366;
padding: 15px;
border-radius: 8px;
margin-bottom: 20px;
}
.action-buttons {
display: grid;
grid-template-columns: 1fr 1fr;
gap: 10px;
margin-bottom: 20px;
}
button {
background-color: #4d4dff;
color: white;
border: none;
padding: 10px;
border-radius: 5px;
cursor: pointer;
transition: background-color 0.3s;
}
button:hover {
background-color: #3333cc;
}
button:disabled {
background-color: #666699;
cursor: not-allowed;
}
.log-area {
background-color: #1a1a2e;
padding: 15px;
border-radius: 8px;
height: 150px;
overflow-y: auto;
border: 1px solid #4d4dff;
}
.log-entry {
margin-bottom: 5px;
border-bottom: 1px solid #333366;
padding-bottom: 5px;
}
.success {
color: #66ff66;
}
.failure {
color: #ff6666;
}
.critical {
color: #ffcc00;
font-weight: bold;
}
.skill-item {
display: flex;
justify-content: space-between;
margin-bottom: 5px;
}
.stat-item {
display: flex;
justify-content: space-between;
margin-bottom: 8px;
}
.hp-mp {
display: flex;
justify-content: space-between;
margin-bottom: 15px;
}
.hp-mp div {
flex: 1;
text-align: center;
}
.progress {
height: 20px;
background-color: #1a1a2e;
border-radius: 5px;
margin-top: 5px;
}
.progress-fill-hp {
height: 100%;
background-color: #ff5050;
border-radius: 5px;
transition: width 0.3s;
}
.progress-fill-mp {
height: 100%;
background-color: #5050ff;
border-radius: 5px;
transition: width 0.3s;
}
.monster {
margin-bottom: 15px;
padding: 10px;
background-color: #3d3d5c;
border-radius: 5px;
}
.monster-stats {
display: flex;
justify-content: space-between;
}
.monster-hp {
margin-top: 5px;
}
.treasure {
background-color: #665600;
color: #ffdd00;
padding: 10px;
border-radius: 5px;
margin-bottom: 15px;
text-align: center;
}
.level-display {
text-align: center;
margin-bottom: 15px;
font-size: 1.2em;
color: #4db8ff;
}
.game-over {
text-align: center;
color: #ff5050;
font-size: 1.5em;
font-weight: bold;
margin: 20px 0;
}
.levelup-container button {
margin: 5px;
}
</style>
</head>
<body>
<div class="container">
<h1>ダンジョンハック</h1>
<div class="game-area">
<div class="level-display">ダンジョン階層: <span id="level">1</span></div>
<div class="character-sheet">
<div class="status-section">
<h3>ステータス</h3>
<div class="hp-mp">
<div>
<div>HP: <span id="current-hp">30</span>/<span id="max-hp">30</span></div>
<div class="progress">
<div id="hp-bar" class="progress-fill-hp" style="width: 100%"></div>
</div>
</div>
<div>
<div>MP: <span id="current-mp">20</span>/<span id="max-mp">20</span></div>
<div class="progress">
<div id="mp-bar" class="progress-fill-mp" style="width: 100%"></div>
</div>
</div>
</div>
<div class="stat-item">
<div>筋力(STR):</div>
<div id="str">3</div>
</div>
<div class="stat-item">
<div>敏捷(DEX):</div>
<div id="dex">3</div>
</div>
<div class="stat-item">
<div>知力(INT):</div>
<div id="int">3</div>
</div>
<div class="stat-item">
<div>精神(MND):</div>
<div id="mnd">3</div>
</div>
</div>
<div class="skills-section">
<h3>特技</h3>
<div class="skill-item">
<div>剣術:</div>
<div id="sword-skill">1</div>
</div>
<div class="skill-item">
<div>魔法:</div>
<div id="magic-skill">1</div>
</div>
<div class="skill-item">
<div>罠回避:</div>
<div id="trap-skill">1</div>
</div>
<div class="skill-item">
<div>探索:</div>
<div id="search-skill">1</div>
</div>
<div class="skill-item">
<div>交渉:</div>
<div id="negotiation-skill">1</div>
</div>
<div>
<div>経験値: <span id="xp">0</span></div>
<div>レベル: <span id="char-level">1</span></div>
</div>
</div>
</div>
<div class="dungeon-area" id="dungeon-content">
ダンジョンに入る準備はできましたか?
</div>
<div class="action-buttons">
<button id="explore-btn">探索する</button>
<button id="rest-btn">休憩する</button>
<button id="attack-btn" disabled>攻撃</button>
<button id="magic-btn" disabled>魔法</button>
<button id="negotiate-btn" disabled>交渉</button>
<button id="next-level-btn" disabled>次の階層へ</button>
</div>
<div class="log-area" id="log">
<div class="log-entry">ゲーム開始!ダンジョンの探索を始めましょう。</div>
</div>
</div>
</div>
<script>
// ゲームの状態
const gameState = {
character: {
hp: 125,
maxHp: 125,
mp: 50,
maxMp: 50,
stats: {
str: 5,
dex: 1,
int: 1,
mnd: 3
},
skills: {
sword: 2,
magic: 1,
trap: 1,
search: 2,
negotiation: 2
},
xp: 0,
level: 1,
statPoints: 0,
skillPoints: 0
},
dungeon: {
level: 1,
enemyPresent: false,
treasurePresent: false,
currentEnemy: null,
clearedRooms: 0,
roomsToNextLevel: 5
}
};
// モンスターのテンプレート
const monsterTemplates = [
{ name: "ゴブリン", hp: 15, attack: 3, defense: 1, xp: 5 },
{ name: "スケルトン", hp: 20, attack: 4, defense: 2, xp: 8 },
{ name: "オーク", hp: 30, attack: 5, defense: 3, xp: 12 },
{ name: "リザードマン", hp: 25, attack: 6, defense: 2, xp: 10 },
{ name: "ウィスプ", hp: 15, attack: 7, defense: 1, xp: 7 },
{ name: "ダークエルフ", hp: 22, attack: 5, defense: 3, xp: 15 },
{ name: "ミミック", hp: 35, attack: 8, defense: 4, xp: 20 },
{ name: "シャドウ", hp: 28, attack: 6, defense: 2, xp: 18 },
{ name: "ゴーレム", hp: 50, attack: 10, defense: 5, xp: 25 },
{ name: "ワイバーン", hp: 40, attack: 12, defense: 3, xp: 30 }
];
// イベントのテンプレート
const eventTemplates = [
{ type: "trap", name: "落とし穴", difficulty: 10, damage: 5 },
{ type: "trap", name: "毒矢の罠", difficulty: 12, damage: 8 },
{ type: "trap", name: "爆発の魔法陣", difficulty: 15, damage: 10 },
{ type: "treasure", name: "宝箱", contents: "回復薬", effect: "HP +10" },
{ type: "treasure", name: "魔法の泉", contents: "魔力回復", effect: "MP +10" },
{ type: "treasure", name: "古代の遺物", contents: "経験値", effect: "XP +15" }
];
// DOM要素
const dungeonContent = document.getElementById('dungeon-content');
const logArea = document.getElementById('log');
const exploreBtn = document.getElementById('explore-btn');
const restBtn = document.getElementById('rest-btn');
const attackBtn = document.getElementById('attack-btn');
const magicBtn = document.getElementById('magic-btn');
const negotiateBtn = document.getElementById('negotiate-btn');
const nextLevelBtn = document.getElementById('next-level-btn');
// ステータス表示の更新
function updateStats() {
document.getElementById('current-hp').textContent = gameState.character.hp;
document.getElementById('max-hp').textContent = gameState.character.maxHp;
document.getElementById('current-mp').textContent = gameState.character.mp;
document.getElementById('max-mp').textContent = gameState.character.maxMp;
document.getElementById('hp-bar').style.width =
`${(gameState.character.hp / gameState.character.maxHp) * 100}%`;
document.getElementById('mp-bar').style.width =
`${(gameState.character.mp / gameState.character.maxMp) * 100}%`;
document.getElementById('str').textContent = gameState.character.stats.str;
document.getElementById('dex').textContent = gameState.character.stats.dex;
document.getElementById('int').textContent = gameState.character.stats.int;
document.getElementById('mnd').textContent = gameState.character.stats.mnd;
document.getElementById('sword-skill').textContent = gameState.character.skills.sword;
document.getElementById('magic-skill').textContent = gameState.character.skills.magic;
document.getElementById('trap-skill').textContent = gameState.character.skills.trap;
document.getElementById('search-skill').textContent = gameState.character.skills.search;
document.getElementById('negotiation-skill').textContent = gameState.character.skills.negotiation;
document.getElementById('xp').textContent = gameState.character.xp;
document.getElementById('char-level').textContent = gameState.character.level;
document.getElementById('level').textContent = gameState.dungeon.level;
}
// ログにエントリを追加
function addLog(text, className = '') {
const entry = document.createElement('div');
entry.className = `log-entry ${className}`;
entry.textContent = text;
logArea.appendChild(entry);
logArea.scrollTop = logArea.scrollHeight;
}
// ダイスロール
function rollDice(sides = 10) {
return Math.floor(Math.random() * sides) + 1;
}
// 判定ロール
function checkRoll(stat, skill, difficulty) {
const roll = rollDice();
const total = stat + skill + roll;
return {
success: total >= difficulty,
critical: roll === 10,
fumble: roll === 1,
roll: roll,
total: total
};
}
// モンスターの生成
function generateMonster() {
const level = gameState.dungeon.level;
let template = monsterTemplates[Math.floor(Math.random() * monsterTemplates.length)];
// ダンジョンレベルに応じて強化
const monster = {
name: template.name,
hp: template.hp + (level - 1) * 5,
maxHp: template.hp + (level - 1) * 5,
attack: template.attack + Math.floor((level - 1) / 2),
defense: template.defense + Math.floor((level - 1) / 3),
xp: template.xp + (level - 1) * 3
};
return monster;
}
// 敵の表示
function showEnemy() {
const enemy = gameState.dungeon.currentEnemy;
dungeonContent.innerHTML = `
<div class="monster">
<h3>${enemy.name}が現れた!</h3>
<div class="monster-stats">
<div>攻撃力: ${enemy.attack}</div>
<div>防御力: ${enemy.defense}</div>
</div>
<div class="monster-hp">
HP: ${enemy.hp}/${enemy.maxHp}
<div class="progress">
<div class="progress-fill-hp" style="width: ${(enemy.hp / enemy.maxHp) * 100}%"></div>
</div>
</div>
</div>
<p>どうする?</p>
`;
exploreBtn.disabled = true;
restBtn.disabled = true;
attackBtn.disabled = false;
magicBtn.disabled = false;
negotiateBtn.disabled = false;
nextLevelBtn.disabled = true;
}
// 宝物の表示
function showTreasure() {
const treasureIndex = Math.floor(Math.random() * 3);
let treasure;
switch (treasureIndex) {
case 0:
treasure = { name: "回復薬", effect: "HPが10回復した!" };
gameState.character.hp = Math.min(gameState.character.hp + 10, gameState.character.maxHp);
break;
case 1:
treasure = { name: "魔力の結晶", effect: "MPが10回復した!" };
gameState.character.mp = Math.min(gameState.character.mp + 10, gameState.character.maxMp);
break;
case 2:
const xpGain = 5 + gameState.dungeon.level * 2;
treasure = { name: "古代の遺物", effect: `${xpGain}の経験値を獲得した!` };
gainXP(xpGain);
break;
}
dungeonContent.innerHTML = `
<div class="treasure">
<h3>${treasure.name}を見つけた!</h3>
<p>${treasure.effect}</p>
</div>
`;
addLog(`${treasure.name}を見つけました!${treasure.effect}`, 'critical');
gameState.dungeon.treasurePresent = false;
gameState.dungeon.clearedRooms += 1;
exploreBtn.disabled = false;
restBtn.disabled = false;
attackBtn.disabled = true;
magicBtn.disabled = true;
negotiateBtn.disabled = true;
nextLevelBtn.disabled = gameState.dungeon.clearedRooms < gameState.dungeon.roomsToNextLevel;
updateStats();
}
// 部屋の表示
function showRoom() {
if (gameState.dungeon.enemyPresent) {
showEnemy();
} else if (gameState.dungeon.treasurePresent) {
showTreasure();
} else {
dungeonContent.innerHTML = `
<p>あなたは暗い部屋に立っています。先に進むか、休むか選択してください。</p>
`;
exploreBtn.disabled = false;
restBtn.disabled = false;
attackBtn.disabled = true;
magicBtn.disabled = true;
negotiateBtn.disabled = true;
nextLevelBtn.disabled = gameState.dungeon.clearedRooms < gameState.dungeon.roomsToNextLevel;
}
}
// キャラクターのレベルアップ
function levelUp() {
gameState.character.level += 1;
gameState.character.maxHp += 5;
gameState.character.hp = gameState.character.maxHp;
gameState.character.maxMp += 3;
gameState.character.mp = gameState.character.maxMp;
gameState.character.statPoints += 1;
gameState.character.skillPoints += 2;
addLog(`レベルアップ!レベル${gameState.character.level}になりました!`, 'critical');
// レベルアップメニューを表示
showLevelUpMenu();
}
// レベルアップメニューを表示
function showLevelUpMenu() {
dungeonContent.innerHTML = `
<h3>レベルアップ</h3>
<p>ステータスポイント: ${gameState.character.statPoints}</p>
<div class="levelup-container">
<button onclick="increaseStat('str')">筋力+</button>
<button onclick="increaseStat('dex')">敏捷+</button>
<button onclick="increaseStat('int')">知力+</button>
<button onclick="increaseStat('mnd')">精神+</button>
</div>
<p>特技ポイント: ${gameState.character.skillPoints}</p>
<div class="levelup-container">
<button onclick="increaseSkill('sword')">剣術+</button>
<button onclick="increaseSkill('magic')">魔法+</button>
<button onclick="increaseSkill('trap')">罠回避+</button>
<button onclick="increaseSkill('search')">探索+</button>
<button onclick="increaseSkill('negotiation')">交渉+</button>
</div>
<button onclick="finishLevelUp()">完了</button>
`;
exploreBtn.disabled = true;
restBtn.disabled = true;
attackBtn.disabled = true;
magicBtn.disabled = true;
negotiateBtn.disabled = true;
nextLevelBtn.disabled = true;
}
// ステータスを上げる
window.increaseStat = function(stat) {
if (gameState.character.statPoints > 0) {
gameState.character.stats[stat] += 1;
gameState.character.statPoints -= 1;
showLevelUpMenu();
updateStats();
}
}
// 特技を上げる
window.increaseSkill = function(skill) {
if (gameState.character.skillPoints > 0) {
gameState.character.skills[skill] += 1;
gameState.character.skillPoints -= 1;
showLevelUpMenu();
updateStats();
}
}
// レベルアップ完了
window.finishLevelUp = function() {
addLog("レベルアップが完了しました!探索を続けましょう。");
showRoom();
}
// 経験値の獲得
function gainXP(amount) {
gameState.character.xp += amount;
addLog(`${amount}の経験値を獲得しました!`, 'success');
// レベルアップの条件
const xpNeeded = gameState.character.level * 20;
if (gameState.character.xp >= xpNeeded) {
gameState.character.xp -= xpNeeded;
levelUp();
}
updateStats();
}
// 敵を倒した時の処理
function defeatEnemy() {
const enemy = gameState.dungeon.currentEnemy;
addLog(`${enemy.name}を倒した!`, 'critical');
// 経験値獲得
gainXP(enemy.xp);
// 部屋クリア
gameState.dungeon.enemyPresent = false;
gameState.dungeon.currentEnemy = null;
gameState.dungeon.clearedRooms += 1;
// 次の階層への進行チェック
checkNextLevel();
// 部屋表示更新
showRoom();
}
// 次の階層への進行チェック
function checkNextLevel() {
if (gameState.dungeon.clearedRooms >= gameState.dungeon.roomsToNextLevel) {
nextLevelBtn.disabled = false;
addLog("次の階層に進むことができます!", 'success');
}
}
// ゲームオーバー処理
function gameOver() {
dungeonContent.innerHTML = `
<div class="game-over">ゲームオーバー</div>
<p>あなたは冒険の途中で倒れました。最終ダンジョン階層: ${gameState.dungeon.level}</p>
<button onclick="resetGame()">もう一度挑戦する</button>
`;
exploreBtn.disabled = true;
restBtn.disabled = true;
attackBtn.disabled = true;
magicBtn.disabled = true;
negotiateBtn.disabled = true;
nextLevelBtn.disabled = true;
addLog("ゲームオーバー...", 'failure');
}
// ゲームリセット
window.resetGame = function() {
gameState.character = {
hp: 30,
maxHp: 30,
mp: 20,
maxMp: 20,
stats: {
str: 3,
dex: 3,
int: 3,
mnd: 3
},
skills: {
sword: 1,
magic: 1,
trap: 1,
search: 1,
negotiation: 1
},
xp: 0,
level: 1,
statPoints: 0,
skillPoints: 0
};
gameState.dungeon = {
level: 1,
enemyPresent: false,
treasurePresent: false,
currentEnemy: null,
clearedRooms: 0,
roomsToNextLevel: 5
};
updateStats();
showRoom();
// ログをクリア
logArea.innerHTML = '';
addLog("ゲーム開始!ダンジョンの探索を始めましょう。");
}
// 特殊イベント - レアモンスター
function spawnRareMonster() {
const rareMonster = {
name: "古代のガーディアン",
hp: 100 + gameState.dungeon.level * 10,
maxHp: 100 + gameState.dungeon.level * 10,
attack: 15 + gameState.dungeon.level,
defense: 8 + Math.floor(gameState.dungeon.level / 2),
xp: 50 + gameState.dungeon.level * 5
};
gameState.dungeon.enemyPresent = true;
gameState.dungeon.currentEnemy = rareMonster;
addLog("床が振動し、壁から光が漏れ出す...", 'critical');
addLog("強大なエネルギーを感じる!", 'critical');
addLog(`${rareMonster.name}が現れた!`, 'critical');
showEnemy();
}
// 特殊イベント - 祝福の泉
function blessingFountain() {
dungeonContent.innerHTML = `
<div class="treasure">
<h3>祝福の泉を見つけた!</h3>
<p>神秘的な力があなたを包み込む...</p>
<div class="levelup-container">
<button onclick="chooseFountainEffect('hp')">体力強化</button>
<button onclick="chooseFountainEffect('mp')">魔力強化</button>
<button onclick="chooseFountainEffect('stat')">能力強化</button>
</div>
</div>
`;
exploreBtn.disabled = true;
restBtn.disabled = true;
attackBtn.disabled = true;
magicBtn.disabled = true;
negotiateBtn.disabled = true;
nextLevelBtn.disabled = true;
addLog("祝福の泉を見つけました!特別な力を得ることができます。", 'critical');
}
// 祝福の泉の効果選択
window.chooseFountainEffect = function(effect) {
switch (effect) {
case 'hp':
gameState.character.maxHp += 10;
gameState.character.hp = gameState.character.maxHp;
addLog("体力が強化されました!最大HPが10増加し、HPが全回復しました。", 'success');
break;
case 'mp':
gameState.character.maxMp += 8;
gameState.character.mp = gameState.character.maxMp;
addLog("魔力が強化されました!最大MPが8増加し、MPが全回復しました。", 'success');
break;
case 'stat':
// すべての能力値を+1
gameState.character.stats.str += 1;
gameState.character.stats.dex += 1;
gameState.character.stats.int += 1;
gameState.character.stats.mnd += 1;
addLog("能力が強化されました!すべての能力値が1増加しました。", 'success');
break;
}
updateStats();
gameState.dungeon.clearedRooms += 1;
showRoom();
}
// 5%の確率で特殊イベントを発生させる関数
function checkSpecialEvent() {
if (Math.random() < 0.05) {
// 特殊イベントの種類をランダムに選ぶ
const eventType = Math.random();
if (eventType < 0.5) {
spawnRareMonster();
} else {
blessingFountain();
}
return true;
}
return false;
}
// 攻撃ボタンの処理
attackBtn.addEventListener('click', function() {
if (!gameState.dungeon.enemyPresent) return;
const enemy = gameState.dungeon.currentEnemy;
// プレイヤーの攻撃
const attackResult = checkRoll(
gameState.character.stats.str,
gameState.character.skills.sword,
10
);
if (attackResult.critical) {
const damage = gameState.character.stats.str * 2 + gameState.character.skills.sword * 2 - enemy.defense;
enemy.hp = Math.max(0, enemy.hp - damage);
addLog(`クリティカルヒット!${enemy.name}に${damage}ダメージ!`, 'critical');
} else if (attackResult.success) {
const damage = Math.max(1, gameState.character.stats.str + gameState.character.skills.sword - enemy.defense);
enemy.hp = Math.max(0, enemy.hp - damage);
addLog(`攻撃成功!${enemy.name}に${damage}ダメージ!`, 'success');
} else if (attackResult.fumble) {
addLog(`ファンブル!攻撃が大きく外れた!`, 'failure');
} else {
addLog(`攻撃が外れた!`, 'failure');
}
// 敵の反撃(敵がまだ生きていれば)
if (enemy.hp > 0) {
const defenseResult = checkRoll(
gameState.character.stats.dex,
gameState.character.skills.sword,
10
);
if (defenseResult.success) {
addLog(`${enemy.name}の攻撃を回避した!`, 'success');
} else {
const damage = Math.max(1, enemy.attack - Math.floor(gameState.character.stats.str / 2));
gameState.character.hp = Math.max(0, gameState.character.hp - damage);
addLog(`${enemy.name}の攻撃で${damage}ダメージを受けた!`, 'failure');
if (gameState.character.hp <= 0) {
gameOver();
return;
}
}
} else {
// 敵を倒した
defeatEnemy();
return;
}
updateStats();
showEnemy();
});
// 魔法ボタンの処理
magicBtn.addEventListener('click', function() {
if (!gameState.dungeon.enemyPresent) return;
const mpCost = 5;
if (gameState.character.mp < mpCost) {
addLog("MPが足りません!", 'failure');
return;
}
gameState.character.mp -= mpCost;
const enemy = gameState.dungeon.currentEnemy;
// 魔法攻撃
const magicResult = checkRoll(
gameState.character.stats.int,
gameState.character.skills.magic,
10
);
if (magicResult.critical) {
const damage = gameState.character.stats.int * 2 + gameState.character.skills.magic * 2;
enemy.hp = Math.max(0, enemy.hp - damage);
addLog(`クリティカル魔法!${enemy.name}に${damage}ダメージ!`, 'critical');
} else if (magicResult.success) {
const damage = gameState.character.stats.int + gameState.character.skills.magic;
enemy.hp = Math.max(0, enemy.hp - damage);
addLog(`魔法攻撃が命中!${enemy.name}に${damage}ダメージ!`, 'success');
} else if (magicResult.fumble) {
const damage = Math.floor(gameState.character.stats.int / 2);
gameState.character.hp = Math.max(0, gameState.character.hp - damage);
addLog(`ファンブル!魔法が暴走して自分に${damage}ダメージ!`, 'failure');
if (gameState.character.hp <= 0) {
gameOver();
return;
}
} else {
addLog(`魔法が失敗した!`, 'failure');
}
// 敵の反撃(敵がまだ生きていれば)
if (enemy.hp > 0) {
const defenseResult = checkRoll(
gameState.character.stats.dex,
gameState.character.skills.trap,
10
);
if (defenseResult.success) {
addLog(`${enemy.name}の攻撃を回避した!`, 'success');
} else {
const damage = Math.max(1, enemy.attack - Math.floor(gameState.character.stats.int / 3));
gameState.character.hp = Math.max(0, gameState.character.hp - damage);
addLog(`${enemy.name}の攻撃で${damage}ダメージを受けた!`, 'failure');
if (gameState.character.hp <= 0) {
gameOver();
return;
}
}
} else {
// 敵を倒した
defeatEnemy();
return;
}
updateStats();
showEnemy();
});
// 交渉ボタンの処理
negotiateBtn.addEventListener('click', function() {
if (!gameState.dungeon.enemyPresent) return;
const enemy = gameState.dungeon.currentEnemy;
// 交渉判定
const negotiationResult = checkRoll(
gameState.character.stats.mnd,
gameState.character.skills.negotiation,
10 + Math.floor(enemy.attack / 2)
);
if (negotiationResult.critical) {
// 完全成功
addLog(`クリティカル交渉!${enemy.name}が味方になった!`, 'critical');
// ボーナス経験値
gainXP(enemy.xp / 2);
// 部屋クリア
gameState.dungeon.enemyPresent = false;
gameState.dungeon.currentEnemy = null;
gameState.dungeon.clearedRooms += 1;
// 次の階層への進行チェック
checkNextLevel();
// 部屋表示更新
showRoom();
} else if (negotiationResult.success) {
// 成功
addLog(`交渉成功!${enemy.name}は去っていった。`, 'success');
// 少しだけ経験値
gainXP(Math.floor(enemy.xp / 4));
// 部屋クリア
gameState.dungeon.enemyPresent = false;
gameState.dungeon.currentEnemy = null;
gameState.dungeon.clearedRooms += 1;
// 次の階層への進行チェック
checkNextLevel();
// 部屋表示更新
showRoom();
} else {
// 失敗
addLog(`交渉失敗!${enemy.name}は怒っている!`, 'failure');
// 敵の攻撃
const damage = Math.max(1, enemy.attack - Math.floor(gameState.character.stats.mnd / 3));
gameState.character.hp = Math.max(0, gameState.character.hp - damage);
addLog(`${enemy.name}の攻撃で${damage}ダメージを受けた!`, 'failure');
if (gameState.character.hp <= 0) {
gameOver();
return;
}
updateStats();
showEnemy();
}
});
// 探索ボタンの処理
exploreBtn.addEventListener('click', function() {
// 特殊イベントのチェック
if (checkSpecialEvent()) {
return;
}
// 罠のチェック
const trapCheck = Math.random() < 0.2;
if (trapCheck) {
const trapIndex = Math.floor(Math.random() * 3);
let trap;
switch (trapIndex) {
case 0:
trap = { name: "落とし穴", difficulty: 8 + gameState.dungeon.level, damage: 3 + gameState.dungeon.level };
break;
case 1:
trap = { name: "毒矢の罠", difficulty: 10 + gameState.dungeon.level, damage: 5 + gameState.dungeon.level };
break;
case 2:
trap = { name: "爆発の魔法陣", difficulty: 12 + gameState.dungeon.level, damage: 8 + gameState.dungeon.level };
break;
}
addLog(`${trap.name}を発見しました!罠回避の判定が必要です。`);
const result = checkRoll(
gameState.character.stats.dex,
gameState.character.skills.trap,
trap.difficulty
);
if (result.success) {
addLog(`罠回避判定成功!罠を回避しました。(${result.roll}を出して合計${result.total})`, 'success');
} else {
const damage = trap.damage;
gameState.character.hp = Math.max(0, gameState.character.hp - damage);
addLog(`罠回避判定失敗!${damage}ダメージを受けました。(${result.roll}を出して合計${result.total})`, 'failure');
if (gameState.character.hp <= 0) {
gameOver();
return;
}
}
updateStats();
}
// 部屋の内容を決定
const roomType = Math.random();
if (roomType < 0.6) { // 60%の確率で敵
gameState.dungeon.enemyPresent = true;
gameState.dungeon.currentEnemy = generateMonster();
addLog(`${gameState.dungeon.currentEnemy.name}が現れた!`);
showEnemy();
} else if (roomType < 0.9) { // 30%の確率で宝物
gameState.dungeon.treasurePresent = true;
showTreasure();
} else { // 10%の確率で何もなし
addLog("何もない部屋だった。");
gameState.dungeon.clearedRooms += 1;
showRoom();
}
// 次の階層への進行チェック
checkNextLevel();
});
// 休憩ボタンの処理
restBtn.addEventListener('click', function() {
const hpRecover = Math.floor(gameState.character.maxHp * 0.2);
const mpRecover = Math.floor(gameState.character.maxMp * 0.2);
gameState.character.hp = Math.min(gameState.character.hp + hpRecover, gameState.character.maxHp);
gameState.character.mp = Math.min(gameState.character.mp + mpRecover, gameState.character.maxMp);
addLog(`休憩しました。HPが${hpRecover}、MPが${mpRecover}回復しました。`, 'success');
updateStats();
// 休憩中に敵が現れる確率
if (Math.random() < 0.3) {
gameState.dungeon.enemyPresent = true;
gameState.dungeon.currentEnemy = generateMonster();
addLog(`休憩中に${gameState.dungeon.currentEnemy.name}に襲われた!`, 'failure');
showEnemy();
}
});
// 次の階層へボタンの処理
nextLevelBtn.addEventListener('click', function() {
gameState.dungeon.level += 1;
gameState.dungeon.clearedRooms = 0;
gameState.dungeon.roomsToNextLevel = 5 + gameState.dungeon.level;
gameState.dungeon.enemyPresent = false;
gameState.dungeon.treasurePresent = false;
addLog(`ダンジョン階層${gameState.dungeon.level}に到達しました!`, 'critical');
updateStats();
showRoom();
});
// ゲーム初期化
updateStats();
showRoom();
</script>
</body>
</html>
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment