Avarush / index.html
offerpk3's picture
Update index.html
6f90d62 verified
<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="UTF-8">
<meta name="viewport" content="width=device-width, initial-scale=1.0">
<title>AvaRush - Adventure Match Game</title>
<style>
* {
margin: 0;
padding: 0;
box-sizing: border-box;
}
body {
font-family: 'Arial', sans-serif;
background: linear-gradient(135deg, #667eea 0%, #764ba2 100%);
min-height: 100vh;
overflow-x: hidden;
}
.game-container {
max-width: 1200px;
margin: 0 auto;
padding: 10px;
}
.header {
display: flex;
justify-content: space-between;
align-items: center;
background: rgba(255, 255, 255, 0.1);
backdrop-filter: blur(10px);
padding: 15px 20px;
border-radius: 15px;
margin-bottom: 10px;
}
.logo {
font-size: 2.5em;
font-weight: bold;
background: linear-gradient(45deg, #ff6b6b, #4ecdc4);
-webkit-background-clip: text;
-webkit-text-fill-color: transparent;
text-shadow: 2px 2px 4px rgba(0,0,0,0.3);
}
.nav-buttons {
display: flex;
gap: 10px;
}
.nav-btn {
padding: 10px 20px;
background: linear-gradient(45deg, #ff6b6b, #ee5a52);
color: white;
border: none;
border-radius: 25px;
cursor: pointer;
font-weight: bold;
transition: all 0.3s ease;
}
.nav-btn:hover {
transform: translateY(-2px);
box-shadow: 0 5px 15px rgba(0,0,0,0.3);
}
.game-area {
display: flex;
gap: 20px;
height: 600px;
}
.left-panel, .right-panel {
width: 200px;
background: rgba(255, 255, 255, 0.1);
backdrop-filter: blur(10px);
border-radius: 15px;
padding: 20px;
color: white;
}
.game-board {
flex: 1;
background: rgba(255, 255, 255, 0.1);
backdrop-filter: blur(10px);
border-radius: 15px;
padding: 20px;
display: flex;
flex-direction: column;
align-items: center;
}
.score-info {
text-align: right;
margin-bottom: 20px;
}
.score-item {
background: rgba(255, 255, 255, 0.2);
padding: 10px;
border-radius: 10px;
margin-bottom: 10px;
}
.moves-info {
text-align: left;
margin-bottom: 20px;
}
.canvas-container {
position: relative;
border-radius: 15px;
overflow: hidden;
box-shadow: 0 10px 30px rgba(0,0,0,0.3);
}
canvas {
display: block;
background: #2c3e50;
}
.game-controls {
display: flex;
gap: 10px;
margin-top: 20px;
}
.control-btn {
padding: 15px 30px;
font-size: 18px;
border: none;
border-radius: 25px;
cursor: pointer;
font-weight: bold;
transition: all 0.3s ease;
}
.play-btn {
background: linear-gradient(45deg, #4ecdc4, #44a08d);
color: white;
}
.pause-btn {
background: linear-gradient(45deg, #ffa726, #ff7043);
color: white;
}
.control-btn:hover {
transform: scale(1.05);
}
.objective-info {
background: rgba(255, 255, 255, 0.2);
padding: 15px;
border-radius: 10px;
text-align: center;
color: white;
font-weight: bold;
margin-bottom: 20px;
}
.level-info {
text-align: center;
margin: 20px 0;
}
.modal {
display: none;
position: fixed;
top: 0;
left: 0;
width: 100%;
height: 100%;
background: rgba(0,0,0,0.8);
z-index: 1000;
}
.modal-content {
position: absolute;
top: 50%;
left: 50%;
transform: translate(-50%, -50%);
background: linear-gradient(135deg, #667eea 0%, #764ba2 100%);
padding: 30px;
border-radius: 20px;
color: white;
text-align: center;
min-width: 300px;
}
.toast {
position: fixed;
top: 20px;
right: 20px;
background: linear-gradient(45deg, #4ecdc4, #44a08d);
color: white;
padding: 15px 25px;
border-radius: 10px;
z-index: 1001;
transform: translateX(400px);
transition: transform 0.3s ease;
}
.toast.show {
transform: translateX(0);
}
.gem {
width: 40px;
height: 40px;
border-radius: 8px;
display: inline-block;
margin: 2px;
cursor: pointer;
transition: all 0.2s ease;
}
.gem:hover {
transform: scale(1.1);
}
.gem-red { background: linear-gradient(45deg, #ff6b6b, #ee5a52); }
.gem-blue { background: linear-gradient(45deg, #4ecdc4, #44a08d); }
.gem-green { background: linear-gradient(45deg, #a8e6cf, #88d8a3); }
.gem-yellow { background: linear-gradient(45deg, #ffd93d, #ffb74d); }
.gem-purple { background: linear-gradient(45deg, #b19cd9, #9b59b6); }
.gem-ice { background: linear-gradient(45deg, #e3f2fd, #bbdefb); border: 2px solid #2196f3; }
.modal-buttons {
display: flex;
gap: 15px;
justify-content: center;
margin-top: 20px;
}
.modal-btn {
padding: 10px 20px;
border: none;
border-radius: 20px;
cursor: pointer;
font-weight: bold;
transition: all 0.3s ease;
}
.close-btn {
background: #e74c3c;
color: white;
}
.continue-btn {
background: #27ae60;
color: white;
}
</style>
</head>
<body>
<div class="game-container">
<div class="header">
<div class="logo">AvaRush</div>
<div class="nav-buttons">
<button class="nav-btn" onclick="showModal('shop')">Shop</button>
<button class="nav-btn" onclick="showModal('equip')">Equip</button>
<button class="nav-btn" onclick="showModal('friends')">Friends</button>
<button class="nav-btn" onclick="showModal('tasks')">Tasks</button>
<button class="nav-btn" onclick="showModal('rating')">Rating</button>
<button class="nav-btn" onclick="showModal('boosters')">Boosters</button>
<button class="nav-btn" onclick="showModal('skins')">Skins</button>
</div>
</div>
<div class="game-area">
<div class="left-panel">
<div class="moves-info">
<h3>Moves</h3>
<div class="score-item">
<div style="font-size: 2em; color: #4ecdc4;" id="moves-count">25</div>
</div>
</div>
<div class="objective-info">
<div>Crush Ice</div>
<div style="font-size: 1.5em; color: #4ecdc4;" id="ice-count">0/28</div>
</div>
<div class="level-info">
<h3>Level</h3>
<div style="font-size: 2em; color: #ffd93d;" id="player-level">1</div>
<div style="font-size: 0.9em; margin-top: 5px;" id="map-name">Forest Valley</div>
</div>
</div>
<div class="game-board">
<div class="canvas-container">
<canvas id="gameCanvas" width="480" height="480"></canvas>
</div>
<div class="game-controls">
<button class="control-btn pause-btn" onclick="pauseGame()" id="pauseBtn">Pause</button>
<button class="control-btn play-btn" onclick="playGame()" id="playBtn" style="display: none;">Play</button>
</div>
</div>
<div class="right-panel">
<div class="score-info">
<h3>Score</h3>
<div class="score-item">
<div style="font-size: 2em; color: #ff6b6b;" id="score">0</div>
</div>
<div class="score-item">
<div>High Score</div>
<div style="color: #ffd93d;" id="high-score">1250</div>
</div>
<div class="score-item">
<div>Level Progress</div>
<div style="color: #4ecdc4;" id="level-progress">Level 1/30</div>
</div>
</div>
</div>
</div>
</div>
<!-- Modals -->
<div id="modal" class="modal">
<div class="modal-content">
<div id="modal-title"></div>
<div id="modal-body"></div>
<div class="modal-buttons">
<button class="modal-btn close-btn" onclick="closeModal()">Close</button>
</div>
</div>
</div>
<!-- Toast Notification -->
<div id="toast" class="toast"></div>
<script>
// Game state
let gameState = {
score: 0,
moves: 25,
level: 1,
iceCount: 0,
iceTarget: 28,
isPaused: false,
currentMap: 'forest',
gems: [],
selectedGem: null,
animations: [],
fallingGems: [],
isAnimating: false
};
// Audio context for sound effects
let audioContext;
function initAudio() {
try {
audioContext = new (window.AudioContext || window.webkitAudioContext)();
} catch (e) {
console.log('Audio not supported');
}
}
function playSound(frequency, duration, type = 'sine') {
if (!audioContext) return;
const oscillator = audioContext.createOscillator();
const gainNode = audioContext.createGain();
oscillator.connect(gainNode);
gainNode.connect(audioContext.destination);
oscillator.frequency.setValueAtTime(frequency, audioContext.currentTime);
oscillator.type = type;
gainNode.gain.setValueAtTime(0.1, audioContext.currentTime);
gainNode.gain.exponentialRampToValueAtTime(0.001, audioContext.currentTime + duration);
oscillator.start(audioContext.currentTime);
oscillator.stop(audioContext.currentTime + duration);
}
function playMatchSound() {
// Pleasant chime sound for matches
playSound(523.25, 0.2); // C5
setTimeout(() => playSound(659.25, 0.2), 100); // E5
setTimeout(() => playSound(783.99, 0.3), 200); // G5
}
function playDropSound() {
// Soft drop sound
playSound(220, 0.15, 'triangle');
}
function playIceBreakSound() {
// Crystal break sound
playSound(1000, 0.1, 'square');
setTimeout(() => playSound(800, 0.1, 'square'), 50);
setTimeout(() => playSound(600, 0.1, 'square'), 100);
}
// Game maps with different backgrounds
const maps = {
forest: { name: 'Forest Valley', bg: '#2d5016', levels: [1,2,3,4,5,6,7,8,9,10] },
desert: { name: 'Desert Oasis', bg: '#8b4513', levels: [11,12,13,14,15,16,17,18,19,20] },
skylands: { name: 'Sky Realm', bg: '#4169e1', levels: [21,22,23,24,25,26,27,28,29,30] }
};
// Canvas setup
const canvas = document.getElementById('gameCanvas');
const ctx = canvas.getContext('2d');
const gridSize = 8;
const gemSize = 60;
// Game elements (natural themed)
const gemTypes = ['wood', 'water', 'snake', 'bee', 'whale', 'fish'];
const gemColors = {
wood: '#8B4513',
water: '#4682B4',
snake: '#228B22',
bee: '#FFD700',
whale: '#4169E1',
fish: '#FF6347'
};
// Initialize game
function initGame() {
createGemGrid();
updateUI();
updateMapTheme();
gameLoop();
}
function createGemGrid() {
gameState.gems = [];
for (let row = 0; row < gridSize; row++) {
gameState.gems[row] = [];
for (let col = 0; col < gridSize; col++) {
gameState.gems[row][col] = {
type: gemTypes[Math.floor(Math.random() * gemTypes.length)],
x: col * gemSize,
y: row * gemSize,
isIce: Math.random() < 0.1 // 10% chance for ice blocks
};
}
}
// Add some ice gems for the objective
addIceGems();
}
function addIceGems() {
let iceAdded = 0;
while (iceAdded < gameState.iceTarget && iceAdded < 15) {
const row = Math.floor(Math.random() * gridSize);
const col = Math.floor(Math.random() * gridSize);
if (!gameState.gems[row][col].isIce) {
gameState.gems[row][col].isIce = true;
iceAdded++;
}
}
}
function drawGame() {
// Clear canvas with map-specific background
const currentMapData = Object.values(maps).find(map =>
map.levels.includes(gameState.level)
) || maps.forest;
ctx.fillStyle = currentMapData.bg;
ctx.fillRect(0, 0, canvas.width, canvas.height);
// Draw grid background
ctx.strokeStyle = 'rgba(255,255,255,0.1)';
ctx.lineWidth = 1;
for (let i = 0; i <= gridSize; i++) {
ctx.beginPath();
ctx.moveTo(i * gemSize, 0);
ctx.lineTo(i * gemSize, canvas.height);
ctx.stroke();
ctx.beginPath();
ctx.moveTo(0, i * gemSize);
ctx.lineTo(canvas.width, i * gemSize);
ctx.stroke();
}
// Draw gems (including falling ones)
for (let row = 0; row < gridSize; row++) {
for (let col = 0; col < gridSize; col++) {
const gem = gameState.gems[row][col];
if (gem && !gem.isMatched) {
drawGem(gem, col * gemSize, row * gemSize);
}
}
}
// Draw falling gems with animation
gameState.fallingGems.forEach(fallingGem => {
drawGem(fallingGem.gem, fallingGem.x, fallingGem.y);
});
// Draw match animations
gameState.animations.forEach(animation => {
drawMatchAnimation(animation);
});
// Highlight selected gem
if (gameState.selectedGem && !gameState.isAnimating) {
const { row, col } = gameState.selectedGem;
ctx.strokeStyle = '#fff';
ctx.lineWidth = 3;
ctx.strokeRect(col * gemSize + 2, row * gemSize + 2, gemSize - 4, gemSize - 4);
}
}
function drawMatchAnimation(animation) {
const progress = (Date.now() - animation.startTime) / animation.duration;
if (progress >= 1) return;
const alpha = 1 - progress;
const scale = 1 + progress * 0.5;
ctx.save();
ctx.globalAlpha = alpha;
ctx.translate(animation.x + gemSize/2, animation.y + gemSize/2);
ctx.scale(scale, scale);
ctx.translate(-gemSize/2, -gemSize/2);
// Draw sparkle effect
ctx.fillStyle = '#FFD700';
for (let i = 0; i < 8; i++) {
const angle = (i / 8) * Math.PI * 2;
const x = Math.cos(angle) * 20 * progress;
const y = Math.sin(angle) * 20 * progress;
ctx.beginPath();
ctx.arc(gemSize/2 + x, gemSize/2 + y, 3, 0, Math.PI * 2);
ctx.fill();
}
ctx.restore();
}
function drawGem(gem, x, y) {
const padding = 4;
const size = gemSize - padding * 2;
const centerX = x + padding + size/2;
const centerY = y + padding + size/2;
ctx.save();
// Draw different shapes based on gem type
switch(gem.type) {
case 'wood':
drawWood(centerX, centerY, size);
break;
case 'water':
drawWaterDrop(centerX, centerY, size);
break;
case 'snake':
drawSnake(centerX, centerY, size);
break;
case 'bee':
drawBee(centerX, centerY, size);
break;
case 'whale':
drawWhale(centerX, centerY, size);
break;
case 'fish':
drawFish(centerX, centerY, size);
break;
}
// Draw ice overlay if applicable
if (gem.isIce) {
ctx.strokeStyle = '#87CEEB';
ctx.lineWidth = 3;
ctx.strokeRect(x + padding, y + padding, size, size);
// Ice crystal pattern
ctx.strokeStyle = 'rgba(135, 206, 235, 0.7)';
ctx.lineWidth = 2;
ctx.beginPath();
ctx.moveTo(centerX, y + padding);
ctx.lineTo(centerX, y + padding + size);
ctx.moveTo(x + padding, centerY);
ctx.lineTo(x + padding + size, centerY);
ctx.moveTo(x + padding + size/4, y + padding + size/4);
ctx.lineTo(x + padding + 3*size/4, y + padding + 3*size/4);
ctx.moveTo(x + padding + 3*size/4, y + padding + size/4);
ctx.lineTo(x + padding + size/4, y + padding + 3*size/4);
ctx.stroke();
}
ctx.restore();
}
function drawWood(centerX, centerY, size) {
const radius = size * 0.4;
// Wood background
const gradient = ctx.createRadialGradient(centerX, centerY, 0, centerX, centerY, radius);
gradient.addColorStop(0, '#D2691E');
gradient.addColorStop(1, '#8B4513');
ctx.fillStyle = gradient;
ctx.beginPath();
ctx.arc(centerX, centerY, radius, 0, Math.PI * 2);
ctx.fill();
// Wood rings
ctx.strokeStyle = '#654321';
ctx.lineWidth = 2;
for(let i = 1; i <= 3; i++) {
ctx.beginPath();
ctx.arc(centerX, centerY, radius * 0.3 * i, 0, Math.PI * 2);
ctx.stroke();
}
}
function drawWaterDrop(centerX, centerY, size) {
const radius = size * 0.4;
// Water drop shape
const gradient = ctx.createRadialGradient(centerX, centerY, 0, centerX, centerY, radius);
gradient.addColorStop(0, '#87CEEB');
gradient.addColorStop(1, '#4682B4');
ctx.fillStyle = gradient;
ctx.beginPath();
ctx.arc(centerX, centerY + radius * 0.2, radius * 0.8, 0, Math.PI * 2);
ctx.moveTo(centerX, centerY - radius);
ctx.quadraticCurveTo(centerX - radius * 0.5, centerY, centerX, centerY + radius * 0.2);
ctx.quadraticCurveTo(centerX + radius * 0.5, centerY, centerX, centerY - radius);
ctx.fill();
// Highlight
ctx.fillStyle = 'rgba(255, 255, 255, 0.5)';
ctx.beginPath();
ctx.arc(centerX - radius * 0.3, centerY - radius * 0.3, radius * 0.2, 0, Math.PI * 2);
ctx.fill();
}
function drawSnake(centerX, centerY, size) {
const radius = size * 0.15;
// Snake body (S-curve)
ctx.strokeStyle = '#228B22';
ctx.lineWidth = radius;
ctx.lineCap = 'round';
ctx.beginPath();
ctx.moveTo(centerX - size * 0.3, centerY - size * 0.2);
ctx.quadraticCurveTo(centerX + size * 0.2, centerY - size * 0.1, centerX, centerY);
ctx.quadraticCurveTo(centerX - size * 0.2, centerY + size * 0.1, centerX + size * 0.3, centerY + size * 0.2);
ctx.stroke();
// Snake head
ctx.fillStyle = '#32CD32';
ctx.beginPath();
ctx.arc(centerX + size * 0.3, centerY + size * 0.2, radius * 1.2, 0, Math.PI * 2);
ctx.fill();
// Eyes
ctx.fillStyle = '#000';
ctx.beginPath();
ctx.arc(centerX + size * 0.25, centerY + size * 0.15, 2, 0, Math.PI * 2);
ctx.arc(centerX + size * 0.35, centerY + size * 0.15, 2, 0, Math.PI * 2);
ctx.fill();
}
function drawBee(centerX, centerY, size) {
const bodyWidth = size * 0.6;
const bodyHeight = size * 0.3;
// Bee body
ctx.fillStyle = '#FFD700';
ctx.beginPath();
ctx.ellipse(centerX, centerY, bodyWidth/2, bodyHeight/2, 0, 0, Math.PI * 2);
ctx.fill();
// Black stripes
ctx.fillStyle = '#000';
for(let i = 0; i < 3; i++) {
ctx.fillRect(centerX - bodyWidth/2 + i * bodyWidth/3, centerY - bodyHeight/2, bodyWidth/6, bodyHeight);
}
// Wings
ctx.fillStyle = 'rgba(255, 255, 255, 0.7)';
ctx.beginPath();
ctx.ellipse(centerX - bodyWidth/4, centerY - bodyHeight/2, bodyWidth/3, bodyHeight/3, -Math.PI/6, 0, Math.PI * 2);
ctx.ellipse(centerX + bodyWidth/4, centerY - bodyHeight/2, bodyWidth/3, bodyHeight/3, Math.PI/6, 0, Math.PI * 2);
ctx.fill();
// Head
ctx.fillStyle = '#FFD700';
ctx.beginPath();
ctx.arc(centerX, centerY - bodyHeight/2, bodyHeight/3, 0, Math.PI * 2);
ctx.fill();
}
function drawWhale(centerX, centerY, size) {
const bodyWidth = size * 0.7;
const bodyHeight = size * 0.4;
// Whale body
const gradient = ctx.createLinearGradient(centerX - bodyWidth/2, centerY, centerX + bodyWidth/2, centerY);
gradient.addColorStop(0, '#4169E1');
gradient.addColorStop(1, '#191970');
ctx.fillStyle = gradient;
ctx.beginPath();
ctx.ellipse(centerX, centerY, bodyWidth/2, bodyHeight/2, 0, 0, Math.PI * 2);
ctx.fill();
// Tail
ctx.beginPath();
ctx.moveTo(centerX + bodyWidth/2, centerY);
ctx.lineTo(centerX + bodyWidth/2 + size * 0.2, centerY - size * 0.15);
ctx.lineTo(centerX + bodyWidth/2 + size * 0.2, centerY + size * 0.15);
ctx.closePath();
ctx.fill();
// Eye
ctx.fillStyle = '#FFF';
ctx.beginPath();
ctx.arc(centerX - bodyWidth/4, centerY - bodyHeight/4, 4, 0, Math.PI * 2);
ctx.fill();
ctx.fillStyle = '#000';
ctx.beginPath();
ctx.arc(centerX - bodyWidth/4, centerY - bodyHeight/4, 2, 0, Math.PI * 2);
ctx.fill();
// Water spout
ctx.strokeStyle = '#87CEEB';
ctx.lineWidth = 3;
ctx.beginPath();
ctx.moveTo(centerX, centerY - bodyHeight/2);
ctx.lineTo(centerX, centerY - bodyHeight/2 - size * 0.2);
ctx.stroke();
}
function drawFish(centerX, centerY, size) {
const bodyWidth = size * 0.6;
const bodyHeight = size * 0.4;
// Fish body
const gradient = ctx.createRadialGradient(centerX, centerY, 0, centerX, centerY, bodyWidth/2);
gradient.addColorStop(0, '#FFA500');
gradient.addColorStop(1, '#FF6347');
ctx.fillStyle = gradient;
ctx.beginPath();
ctx.ellipse(centerX, centerY, bodyWidth/2, bodyHeight/2, 0, 0, Math.PI * 2);
ctx.fill();
// Tail
ctx.beginPath();
ctx.moveTo(centerX + bodyWidth/2, centerY);
ctx.lineTo(centerX + bodyWidth/2 + size * 0.25, centerY - size * 0.2);
ctx.lineTo(centerX + bodyWidth/2 + size * 0.15, centerY);
ctx.lineTo(centerX + bodyWidth/2 + size * 0.25, centerY + size * 0.2);
ctx.closePath();
ctx.fill();
// Fins
ctx.beginPath();
ctx.moveTo(centerX - bodyWidth/4, centerY + bodyHeight/2);
ctx.lineTo(centerX - bodyWidth/4 - size * 0.1, centerY + bodyHeight/2 + size * 0.15);
ctx.lineTo(centerX, centerY + bodyHeight/2);
ctx.closePath();
ctx.fill();
// Eye
ctx.fillStyle = '#FFF';
ctx.beginPath();
ctx.arc(centerX - bodyWidth/4, centerY - bodyHeight/6, 5, 0, Math.PI * 2);
ctx.fill();
ctx.fillStyle = '#000';
ctx.beginPath();
ctx.arc(centerX - bodyWidth/4, centerY - bodyHeight/6, 3, 0, Math.PI * 2);
ctx.fill();
// Scales pattern
ctx.strokeStyle = 'rgba(255, 255, 255, 0.3)';
ctx.lineWidth = 1;
for(let i = 0; i < 3; i++) {
ctx.beginPath();
ctx.arc(centerX - bodyWidth/4 + i * bodyWidth/6, centerY, bodyWidth/8, 0, Math.PI * 2);
ctx.stroke();
}
}
function darkenColor(color, amount) {
const num = parseInt(color.replace("#", ""), 16);
const amt = Math.round(2.55 * amount * 100);
const R = (num >> 16) - amt;
const G = (num >> 8 & 0x00FF) - amt;
const B = (num & 0x0000FF) - amt;
return "#" + (0x1000000 + (R < 255 ? R < 1 ? 0 : R : 255) * 0x10000 +
(G < 255 ? G < 1 ? 0 : G : 255) * 0x100 +
(B < 255 ? B < 1 ? 0 : B : 255)).toString(16).slice(1);
}
// Game loop
function gameLoop() {
if (!gameState.isPaused) {
updateAnimations();
drawGame();
}
requestAnimationFrame(gameLoop);
}
function updateAnimations() {
// Update falling gems
gameState.fallingGems = gameState.fallingGems.filter(fallingGem => {
fallingGem.y += fallingGem.speed;
fallingGem.speed += 0.5; // Gravity effect
const targetY = fallingGem.targetRow * gemSize;
if (fallingGem.y >= targetY) {
fallingGem.y = targetY;
gameState.gems[fallingGem.targetRow][fallingGem.col] = fallingGem.gem;
playDropSound();
return false; // Remove from falling gems array
}
return true;
});
// Update match animations
gameState.animations = gameState.animations.filter(animation => {
return (Date.now() - animation.startTime) < animation.duration;
});
// Check if all animations are done
if (gameState.fallingGems.length === 0 && gameState.animations.length === 0 && gameState.isAnimating) {
gameState.isAnimating = false;
// Check for new matches after gems have fallen
setTimeout(() => {
const newMatches = findMatches();
if (newMatches.length > 0) {
processMatches(newMatches);
}
}, 200);
}
}
// Mouse handling
canvas.addEventListener('click', function(e) {
if (gameState.isPaused) return;
const rect = canvas.getBoundingClientRect();
const x = e.clientX - rect.left;
const y = e.clientY - rect.top;
const col = Math.floor(x / gemSize);
const row = Math.floor(y / gemSize);
if (row >= 0 && row < gridSize && col >= 0 && col < gridSize) {
handleGemClick(row, col);
}
});
function handleGemClick(row, col) {
if (gameState.isAnimating) return; // Don't allow clicks during animations
if (!gameState.selectedGem) {
gameState.selectedGem = { row, col };
} else {
const selected = gameState.selectedGem;
if (selected.row === row && selected.col === col) {
gameState.selectedGem = null;
} else if (isAdjacent(selected, { row, col })) {
swapGems(selected, { row, col });
gameState.selectedGem = null;
} else {
gameState.selectedGem = { row, col };
}
}
}
function isAdjacent(gem1, gem2) {
const rowDiff = Math.abs(gem1.row - gem2.row);
const colDiff = Math.abs(gem1.col - gem2.col);
return (rowDiff === 1 && colDiff === 0) || (rowDiff === 0 && colDiff === 1);
}
function swapGems(gem1, gem2) {
const temp = gameState.gems[gem1.row][gem1.col];
gameState.gems[gem1.row][gem1.col] = gameState.gems[gem2.row][gem2.col];
gameState.gems[gem2.row][gem2.col] = temp;
const matches = findMatches();
if (matches.length > 0) {
gameState.moves--;
processMatches(matches);
updateUI();
showToast('Great match!');
} else {
// Swap back if no matches
const temp = gameState.gems[gem1.row][gem1.col];
gameState.gems[gem1.row][gem1.col] = gameState.gems[gem2.row][gem2.col];
gameState.gems[gem2.row][gem2.col] = temp;
showToast('No matches found!');
}
}
function findMatches() {
const matches = [];
// Check horizontal matches
for (let row = 0; row < gridSize; row++) {
let count = 1;
let currentType = gameState.gems[row][0].type;
for (let col = 1; col < gridSize; col++) {
if (gameState.gems[row][col].type === currentType) {
count++;
} else {
if (count >= 3) {
for (let i = col - count; i < col; i++) {
matches.push({ row, col: i });
}
}
count = 1;
currentType = gameState.gems[row][col].type;
}
}
if (count >= 3) {
for (let i = gridSize - count; i < gridSize; i++) {
matches.push({ row, col: i });
}
}
}
// Check vertical matches
for (let col = 0; col < gridSize; col++) {
let count = 1;
let currentType = gameState.gems[0][col].type;
for (let row = 1; row < gridSize; row++) {
if (gameState.gems[row][col].type === currentType) {
count++;
} else {
if (count >= 3) {
for (let i = row - count; i < row; i++) {
matches.push({ row: i, col });
}
}
count = 1;
currentType = gameState.gems[row][col].type;
}
}
if (count >= 3) {
for (let i = gridSize - count; i < gridSize; i++) {
matches.push({ row: i, col });
}
}
}
return matches;
}
function processMatches(matches) {
let iceDestroyed = 0;
gameState.isAnimating = true;
// Mark matched gems and create animations
matches.forEach(match => {
const gem = gameState.gems[match.row][match.col];
if (gem.isIce) {
iceDestroyed++;
playIceBreakSound();
}
// Create match animation
gameState.animations.push({
x: match.col * gemSize,
y: match.row * gemSize,
startTime: Date.now(),
duration: 500
});
// Mark gem as matched (will be replaced)
gameState.gems[match.row][match.col].isMatched = true;
});
// Play match sound
playMatchSound();
// Update score and ice count
gameState.iceCount += iceDestroyed;
gameState.score += matches.length * 100 + iceDestroyed * 200;
// Start dropping animation after a brief delay
setTimeout(() => {
applyGravity();
fillEmptySpaces();
}, 300);
if (gameState.iceCount >= gameState.iceTarget) {
setTimeout(() => {
levelComplete();
}, 1000);
}
}
function applyGravity() {
// Make gems fall down to fill empty spaces
for (let col = 0; col < gridSize; col++) {
const column = [];
// Collect non-matched gems from bottom to top
for (let row = gridSize - 1; row >= 0; row--) {
if (!gameState.gems[row][col].isMatched) {
column.push(gameState.gems[row][col]);
}
}
// Clear the column
for (let row = 0; row < gridSize; row++) {
gameState.gems[row][col] = null;
}
// Create falling animations for existing gems
column.forEach((gem, index) => {
const newRow = gridSize - 1 - index;
const currentRow = findGemCurrentRow(gem, col);
if (currentRow !== newRow && currentRow !== -1) {
gameState.fallingGems.push({
gem: gem,
x: col * gemSize,
y: currentRow * gemSize,
targetRow: newRow,
col: col,
speed: 2
});
} else {
gameState.gems[newRow][col] = gem;
}
});
}
}
function findGemCurrentRow(targetGem, col) {
for (let row = 0; row < gridSize; row++) {
if (gameState.gems[row][col] === targetGem) {
return row;
}
}
return -1;
}
function fillEmptySpaces() {
// Fill empty spaces with new gems
for (let col = 0; col < gridSize; col++) {
for (let row = 0; row < gridSize; row++) {
if (!gameState.gems[row][col]) {
const newGem = {
type: gemTypes[Math.floor(Math.random() * gemTypes.length)],
isIce: false,
isMatched: false
};
// Create falling animation for new gem
gameState.fallingGems.push({
gem: newGem,
x: col * gemSize,
y: -gemSize * (gridSize - row),
targetRow: row,
col: col,
speed: 2
});
}
}
}
}
function levelComplete() {
showToast('Level Complete!');
gameState.level++;
if (gameState.level > 30) {
showToast('Congratulations! Game Complete!');
gameState.level = 30;
} else {
setTimeout(() => {
initializeNewLevel();
}, 2000);
}
}
function initializeNewLevel() {
gameState.moves = 25;
gameState.iceCount = 0;
gameState.iceTarget = Math.min(28 + gameState.level * 2, 50);
updateMapTheme();
createGemGrid();
updateUI();
}
function updateMapTheme() {
let currentMap = 'forest';
if (gameState.level >= 11 && gameState.level <= 20) {
currentMap = 'desert';
} else if (gameState.level >= 21) {
currentMap = 'skylands';
}
gameState.currentMap = currentMap;
document.getElementById('map-name').textContent = maps[currentMap].name;
}
// UI Updates
function updateUI() {
document.getElementById('score').textContent = gameState.score;
document.getElementById('moves-count').textContent = gameState.moves;
document.getElementById('ice-count').textContent = `${gameState.iceCount}/${gameState.iceTarget}`;
document.getElementById('player-level').textContent = gameState.level;
document.getElementById('level-progress').textContent = `Level ${gameState.level}/30`;
}
// Game controls
function pauseGame() {
gameState.isPaused = true;
document.getElementById('pauseBtn').style.display = 'none';
document.getElementById('playBtn').style.display = 'block';
showToast('Game Paused');
}
function playGame() {
gameState.isPaused = false;
document.getElementById('pauseBtn').style.display = 'block';
document.getElementById('playBtn').style.display = 'none';
showToast('Game Resumed');
}
// Modal system
function showModal(type) {
const modal = document.getElementById('modal');
const title = document.getElementById('modal-title');
const body = document.getElementById('modal-body');
const modalContent = {
shop: {
title: 'πŸ›οΈ Shop',
body: '<p>Buy power-ups and boosters!</p><div style="margin: 20px 0;"><div>πŸ’Ž Gems: 150</div><div>⚑ Energy Boost - 50 gems</div><div>πŸ”₯ Fire Boost - 75 gems</div><div>❄️ Ice Breaker - 100 gems</div></div>'
},
equip: {
title: 'βš”οΈ Equipment',
body: '<p>Manage your power-ups and equipment!</p><div style="margin: 20px 0;"><div>πŸ›‘οΈ Equipped: Basic Hammer</div><div>⚑ Energy Boost: Ready</div><div>πŸ”₯ Fire Power: Cooldown 2 moves</div></div>'
},
friends: {
title: 'πŸ‘₯ Friends',
body: '<p>Connect with friends and send lives!</p><div style="margin: 20px 0;"><div>🟒 Alex_Gamer - Online</div><div>🟑 Sarah_123 - 5 min ago</div><div>πŸ”΄ Mike_Pro - 1 hour ago</div><button style="margin-top: 10px; padding: 5px 15px; background: #4ecdc4; border: none; border-radius: 15px; color: white;">Invite Friends</button></div>'
},
tasks: {
title: 'πŸ“‹ Daily Tasks',
body: '<p>Complete tasks for rewards!</p><div style="margin: 20px 0;"><div>βœ… Play 3 levels - Completed</div><div>⏳ Crush 50 ice blocks - 28/50</div><div>⏳ Score 5000 points - 0/5000</div><div>⏳ Use 5 power-ups - 0/5</div></div>'
},
rating: {
title: 'πŸ† Leaderboard',
body: '<p>Global Rankings</p><div style="margin: 20px 0;"><div>πŸ₯‡ ProGamer99 - 45,230</div><div>πŸ₯ˆ MatchMaster - 42,100</div><div>πŸ₯‰ GemCrusher - 38,950</div><div style="color: #4ecdc4;">πŸ… You - 0 (Rank: 15,432)</div></div>'
},
boosters: {
title: 'πŸš€ Boosters',
body: '<p>Activate powerful boosters!</p><div style="margin: 20px 0;"><div>⚑ Color Bomb - 3 left</div><div>πŸŒͺ️ Line Blast - 2 left</div><div>❄️ Ice Breaker - 1 left</div><div>πŸ”₯ Fire Storm - 0 left</div></div>'
},
skins: {
title: '🎨 Skins & Themes',
body: '<p>Customize your game appearance!</p><div style="margin: 20px 0;"><div>🌲 Forest Theme - Active</div><div>🏜️ Desert Theme - Unlocked</div><div>☁️ Sky Theme - Locked</div><div>🌟 Galaxy Theme - Locked</div></div>'
}
};
const content = modalContent[type];
title.innerHTML = `<h2>${content.title}</h2>`;
body.innerHTML = content.body;
modal.style.display = 'block';
}
function closeModal() {
document.getElementById('modal').style.display = 'none';
}
// Toast notifications
function showToast(message) {
const toast = document.getElementById('toast');
toast.textContent = message;
toast.classList.add('show');
setTimeout(() => {
toast.classList.remove('show');
}, 3000);
}
// Close modal when clicking outside
window.onclick = function(event) {
const modal = document.getElementById('modal');
if (event.target === modal) {
closeModal();
}
}
// Initialize the game
initGame();
initAudio();
showToast('Welcome to AvaRush!');
</script>
</body>
</html>