459 lines
14 KiB
JavaScript
459 lines
14 KiB
JavaScript
/**
|
|
* 掼蛋游戏UI交互
|
|
*/
|
|
|
|
// 游戏实例
|
|
let game = null;
|
|
let selectedCards = new Set();
|
|
|
|
// 初始化
|
|
document.addEventListener('DOMContentLoaded', () => {
|
|
initEventListeners();
|
|
});
|
|
|
|
function initEventListeners() {
|
|
// 开始游戏
|
|
document.getElementById('btn-start').addEventListener('click', startGame);
|
|
|
|
// 出牌按钮
|
|
document.getElementById('btn-play').addEventListener('click', playSelectedCards);
|
|
document.getElementById('btn-pass').addEventListener('click', passTurn);
|
|
document.getElementById('btn-hint').addEventListener('click', showHint);
|
|
|
|
// 下一局
|
|
document.getElementById('btn-next-round').addEventListener('click', nextRound);
|
|
}
|
|
|
|
// 开始游戏
|
|
function startGame() {
|
|
game = new GuandanGame();
|
|
const result = game.startGame();
|
|
|
|
if (result.success) {
|
|
document.getElementById('start-screen').style.display = 'none';
|
|
document.getElementById('game-over-modal').style.display = 'none';
|
|
document.getElementById('game-status').style.display = 'none';
|
|
|
|
// 显示规则
|
|
showRules();
|
|
|
|
// 更新UI
|
|
updateGameInfo();
|
|
renderHandCards();
|
|
updatePlayerStatus();
|
|
|
|
// 清除提示
|
|
document.getElementById('played-by').textContent = '等待出牌...';
|
|
document.getElementById('played-cards').innerHTML = '';
|
|
|
|
// 显示当前玩家
|
|
showTurnIndicator();
|
|
|
|
// 如果AI先手
|
|
if (game.currentPlayer !== 0) {
|
|
setTimeout(() => processAITurn(), 1000);
|
|
}
|
|
}
|
|
}
|
|
|
|
// 显示规则
|
|
function showRules() {
|
|
document.getElementById('rule-level').textContent = game.currentLevel;
|
|
document.getElementById('rule-wild').textContent = game.currentLevel;
|
|
document.getElementById('rules-modal').style.display = 'flex';
|
|
|
|
setTimeout(() => {
|
|
document.getElementById('rules-modal').style.display = 'none';
|
|
}, 3000);
|
|
}
|
|
|
|
// 更新游戏信息
|
|
function updateGameInfo() {
|
|
document.getElementById('current-level').textContent = game.currentLevel;
|
|
document.getElementById('team-a-level').textContent = game.teamLevels[0];
|
|
document.getElementById('team-b-level').textContent = game.teamLevels[1];
|
|
}
|
|
|
|
// 渲染手牌
|
|
function renderHandCards() {
|
|
const container = document.getElementById('hand-cards');
|
|
container.innerHTML = '';
|
|
|
|
const player = game.players[0];
|
|
selectedCards.clear();
|
|
updatePlayButton();
|
|
|
|
player.cards.forEach((card, index) => {
|
|
const cardEl = createCardElement(card, index);
|
|
container.appendChild(cardEl);
|
|
});
|
|
|
|
document.getElementById('my-card-count').textContent = `${player.cards.length}张`;
|
|
}
|
|
|
|
// 创建牌元素
|
|
function createCardElement(card, index) {
|
|
const el = document.createElement('div');
|
|
el.className = 'card';
|
|
el.dataset.cardId = card.id;
|
|
|
|
const isRed = card.suit === '♥' || card.suit === '♦';
|
|
const colorClass = isRed ? 'red' : 'black';
|
|
const isWild = game.isWildCard(card);
|
|
|
|
if (isWild) {
|
|
el.classList.add('wild');
|
|
}
|
|
|
|
// 王牌的显示
|
|
let displayRank = card.rank;
|
|
let displaySuit = card.suit;
|
|
|
|
if (card.isJoker) {
|
|
displaySuit = '🃏';
|
|
displayRank = card.rank === '大王' ? '大' : '小';
|
|
}
|
|
|
|
el.innerHTML = `
|
|
<div class="card-top">
|
|
<span class="rank ${colorClass}">${displayRank}</span>
|
|
<span class="suit ${colorClass}">${displaySuit}</span>
|
|
</div>
|
|
<div class="card-center ${colorClass}">${displaySuit}</div>
|
|
`;
|
|
|
|
el.addEventListener('click', () => toggleCardSelection(card.id, el));
|
|
|
|
return el;
|
|
}
|
|
|
|
// 切换牌选择
|
|
function toggleCardSelection(cardId, el) {
|
|
if (selectedCards.has(cardId)) {
|
|
selectedCards.delete(cardId);
|
|
el.classList.remove('selected');
|
|
} else {
|
|
selectedCards.add(cardId);
|
|
el.classList.add('selected');
|
|
}
|
|
updatePlayButton();
|
|
}
|
|
|
|
// 更新出牌按钮状态
|
|
function updatePlayButton() {
|
|
const hasSelection = selectedCards.size > 0;
|
|
const isMyTurn = game && game.currentPlayer === 0 && game.gameState === 'playing';
|
|
|
|
document.getElementById('btn-play').disabled = !hasSelection || !isMyTurn;
|
|
document.getElementById('btn-pass').disabled = !isMyTurn;
|
|
document.getElementById('btn-hint').disabled = !isMyTurn;
|
|
}
|
|
|
|
// 出牌
|
|
function playSelectedCards() {
|
|
if (!game || game.currentPlayer !== 0) return;
|
|
|
|
const cardIds = Array.from(selectedCards);
|
|
const result = game.playCards(0, cardIds);
|
|
|
|
if (result.success) {
|
|
// 显示出的牌
|
|
showPlayedCards(result.cards, 0, result.cardType.type);
|
|
|
|
// 更新手牌
|
|
renderHandCards();
|
|
|
|
// 更新玩家状态
|
|
updatePlayerStatus();
|
|
|
|
// 清空选中
|
|
selectedCards.clear();
|
|
|
|
// 检查是否出完
|
|
if (result.isFinished) {
|
|
showGameStatus(`${game.players[0].name} 出完啦!排名第${game.players[0].rank}`);
|
|
}
|
|
|
|
// 检查游戏是否结束
|
|
if (game.gameState === 'ended') {
|
|
showGameOver();
|
|
} else {
|
|
// AI回合
|
|
setTimeout(() => processAITurn(), 800);
|
|
}
|
|
} else {
|
|
showGameStatus(result.message, true);
|
|
}
|
|
}
|
|
|
|
// 不出
|
|
function passTurn() {
|
|
if (!game || game.currentPlayer !== 0) return;
|
|
|
|
const result = game.pass(0);
|
|
|
|
if (result.success) {
|
|
showGameStatus('你选择了不出');
|
|
|
|
if (result.roundEnd) {
|
|
showGameStatus('本轮结束,重新开始');
|
|
document.getElementById('played-cards').innerHTML = '';
|
|
document.getElementById('played-by').textContent = '等待出牌...';
|
|
}
|
|
|
|
updatePlayButton();
|
|
setTimeout(() => processAITurn(), 800);
|
|
} else {
|
|
showGameStatus(result.message, true);
|
|
}
|
|
}
|
|
|
|
// 提示
|
|
function showHint() {
|
|
// 简化提示:选择最小的几张牌
|
|
const player = game.players[0];
|
|
if (player.cards.length > 0) {
|
|
// 清除之前的选择
|
|
selectedCards.clear();
|
|
document.querySelectorAll('.card.selected').forEach(el => el.classList.remove('selected'));
|
|
|
|
// 选择最小的牌(简化处理)
|
|
const card = player.cards[player.cards.length - 1];
|
|
selectedCards.add(card.id);
|
|
|
|
const el = document.querySelector(`[data-card-id="${card.id}"]`);
|
|
if (el) el.classList.add('selected');
|
|
|
|
updatePlayButton();
|
|
showGameStatus('提示:已选择一张较小的牌');
|
|
}
|
|
}
|
|
|
|
// AI回合处理
|
|
function processAITurn() {
|
|
if (!game || game.gameState === 'ended') return;
|
|
|
|
const playerId = game.currentPlayer;
|
|
if (playerId === 0) return; // 回到玩家回合
|
|
|
|
const player = game.players[playerId];
|
|
const decision = game.makeAIDecision(playerId);
|
|
|
|
if (decision.action === 'play') {
|
|
const cardIds = decision.cards.map(c => c.id);
|
|
const result = game.playCards(playerId, cardIds);
|
|
|
|
if (result.success) {
|
|
showPlayedCards(result.cards, playerId, result.cardType.type);
|
|
updatePlayerStatus();
|
|
|
|
if (result.isFinished) {
|
|
showGameStatus(`${player.name} 出完啦!排名第${player.rank}`);
|
|
}
|
|
|
|
if (game.gameState === 'ended') {
|
|
showGameOver();
|
|
return;
|
|
}
|
|
}
|
|
} else {
|
|
// 不出
|
|
game.pass(playerId);
|
|
showGameStatus(`${player.name} 不出`);
|
|
}
|
|
|
|
showTurnIndicator();
|
|
updatePlayButton();
|
|
|
|
// 继续AI回合或等待玩家
|
|
if (game.currentPlayer !== 0 && game.gameState !== 'ended') {
|
|
setTimeout(() => processAITurn(), 800);
|
|
}
|
|
}
|
|
|
|
// 显示出的牌
|
|
function showPlayedCards(cards, playerId, cardType) {
|
|
const container = document.getElementById('played-cards');
|
|
const player = game.players[playerId];
|
|
|
|
container.innerHTML = '';
|
|
|
|
cards.forEach(card => {
|
|
const el = document.createElement('div');
|
|
el.className = 'card small';
|
|
|
|
const isRed = card.suit === '♥' || card.suit === '♦';
|
|
const colorClass = isRed ? 'red' : 'black';
|
|
const isWild = game.isWildCard(card);
|
|
|
|
if (isWild) el.classList.add('wild');
|
|
|
|
// 王牌的显示
|
|
let displayRank = card.rank;
|
|
let displaySuit = card.suit;
|
|
|
|
if (card.isJoker) {
|
|
displaySuit = '🃏';
|
|
displayRank = card.rank === '大王' ? '大' : '小';
|
|
}
|
|
|
|
el.innerHTML = `
|
|
<div class="card-top">
|
|
<span class="rank ${colorClass}">${displayRank}</span>
|
|
<span class="suit ${colorClass}">${displaySuit}</span>
|
|
</div>
|
|
<div class="card-center ${colorClass}">${displaySuit}</div>
|
|
`;
|
|
|
|
container.appendChild(el);
|
|
});
|
|
|
|
// 更新谁出的
|
|
const typeNames = {
|
|
'single': '单张', 'pair': '对子', 'triple': '三张',
|
|
'triple_pair': '三带二', 'straight': '顺子',
|
|
'consecutive_pairs': '三连对', 'steel_plate': '钢板',
|
|
'bomb4': '炸弹(4)', 'bomb5': '炸弹(5)', 'bomb6': '炸弹(6)',
|
|
'bomb7': '炸弹(7)', 'bomb8': '炸弹(8)', 'joker_bomb': '天王炸'
|
|
};
|
|
|
|
document.getElementById('played-by').innerHTML =
|
|
`<span class="player-name-${player.team === 0 ? 'ally' : 'enemy'}">${player.name}</span> 出了 ${typeNames[cardType] || cardType}`;
|
|
|
|
// 更新玩家剩余牌数
|
|
updateCardCount(playerId);
|
|
}
|
|
|
|
// 更新玩家状态
|
|
function updatePlayerStatus() {
|
|
// 更新剩余牌数显示
|
|
for (let i = 0; i < 4; i++) {
|
|
updateCardCount(i);
|
|
}
|
|
}
|
|
|
|
// 更新某玩家牌数
|
|
function updateCardCount(playerId) {
|
|
const player = game.players[playerId];
|
|
const count = player.cards.length;
|
|
|
|
let selector;
|
|
if (playerId === 0) {
|
|
selector = '#my-card-count';
|
|
} else if (playerId === 1) {
|
|
selector = '#player-left .card-count';
|
|
} else if (playerId === 2) {
|
|
selector = '#player-top .card-count';
|
|
} else {
|
|
selector = '#player-right .card-count';
|
|
}
|
|
|
|
const el = document.querySelector(selector);
|
|
if (el) el.textContent = `${count}张`;
|
|
}
|
|
|
|
// 显示回合指示
|
|
function showTurnIndicator() {
|
|
if (!game) return;
|
|
|
|
const player = game.players[game.currentPlayer];
|
|
|
|
// 更新出牌提示文字
|
|
const playedBy = document.getElementById('played-by');
|
|
if (playedBy && playedBy.textContent === '等待出牌...') {
|
|
playedBy.innerHTML = `<span class="turn-text">轮到 ${player.name} 出牌</span>`;
|
|
}
|
|
|
|
// 高亮当前玩家
|
|
document.querySelectorAll('.player, .player-self').forEach(el => {
|
|
el.classList.remove('active-turn');
|
|
});
|
|
|
|
const playerEl = document.getElementById(
|
|
game.currentPlayer === 0 ? 'player-self' :
|
|
game.currentPlayer === 1 ? 'player-left' :
|
|
game.currentPlayer === 2 ? 'player-top' : 'player-right'
|
|
);
|
|
if (playerEl) playerEl.classList.add('active-turn');
|
|
}
|
|
|
|
// 显示游戏状态提示
|
|
function showGameStatus(message, isError = false) {
|
|
const el = document.getElementById('game-status');
|
|
el.textContent = message;
|
|
el.className = isError ? 'game-status error' : 'game-status';
|
|
el.style.display = 'block';
|
|
|
|
setTimeout(() => {
|
|
el.style.display = 'none';
|
|
}, 2000);
|
|
}
|
|
|
|
// 显示游戏结束
|
|
function showGameOver() {
|
|
const result = game.endGame();
|
|
|
|
document.getElementById('game-result-title').textContent =
|
|
result.winner === 0 ? '我方胜利!' : '对方胜利!';
|
|
|
|
// 排名列表
|
|
const rankList = document.getElementById('rank-list');
|
|
rankList.innerHTML = '';
|
|
|
|
result.ranks.sort((a, b) => a.rank - b.rank).forEach(r => {
|
|
const div = document.createElement('div');
|
|
div.className = 'rank-item';
|
|
div.innerHTML = `
|
|
<span class="rank-num">第${r.rank}名</span>
|
|
<span class="rank-name ${r.team === 0 ? 'ally' : 'enemy'}">${r.name}</span>
|
|
`;
|
|
rankList.appendChild(div);
|
|
});
|
|
|
|
// 升级信息
|
|
const upgradeInfo = document.getElementById('upgrade-info');
|
|
const levelNames = { 1: '险胜(+1)', 2: '单上(+2)', 3: '双上(+3)' };
|
|
upgradeInfo.innerHTML = `
|
|
<p>获胜方升 ${result.upgrade} 级</p>
|
|
<p>我方:${game.teamLevels[0]} → ${result.winner === 0 ? getNextLevel(game.teamLevels[0], result.upgrade) : game.teamLevels[0]}</p>
|
|
`;
|
|
|
|
document.getElementById('game-over-modal').style.display = 'flex';
|
|
}
|
|
|
|
// 获取下一级
|
|
function getNextLevel(current, upgrade) {
|
|
const levels = ['2', '3', '4', '5', '6', '7', '8', '9', '10', 'J', 'Q', 'K', 'A'];
|
|
const idx = levels.indexOf(current);
|
|
return levels[Math.min(idx + upgrade, levels.length - 1)];
|
|
}
|
|
|
|
// 下一局
|
|
function nextRound() {
|
|
if (!game) return;
|
|
|
|
const result = game.endGame();
|
|
const nextResult = game.nextRound(result.winner, result.upgrade);
|
|
|
|
if (nextResult.gameOver) {
|
|
showGameStatus(nextResult.finalWinner === 0 ? '恭喜!你们赢得了整场比赛!' : '对方赢得了整场比赛!');
|
|
document.getElementById('start-screen').style.display = 'flex';
|
|
document.getElementById('game-over-modal').style.display = 'none';
|
|
return;
|
|
}
|
|
|
|
// 重置UI
|
|
document.getElementById('game-over-modal').style.display = 'none';
|
|
document.getElementById('played-cards').innerHTML = '';
|
|
document.getElementById('played-by').textContent = '等待出牌...';
|
|
|
|
updateGameInfo();
|
|
renderHandCards();
|
|
updatePlayerStatus();
|
|
showTurnIndicator();
|
|
|
|
if (game.currentPlayer !== 0) {
|
|
setTimeout(() => processAITurn(), 1000);
|
|
}
|
|
}
|