Files
nanocode/happy-games/games/guandan/ui.js
T
Ubuntu 32b43f85bd a
2026-07-03 16:58:28 +08:00

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);
}
}