/**** 
* Classes
****/ 
// Ball class to represent the game balls
var Ball = Container.expand(function (type) {
	var self = Container.call(this);
	var assetId = 'ball' + type;
	var ballGraphics = self.attachAsset(assetId, {
		anchorX: 0.5,
		anchorY: 0.5
	});
	self.type = type;
	// Initialize velocity property for gravity effect
	self.velocity = {
		x: 0,
		y: 0
	};
	self.upgrade = function () {
		var nextType;
		switch (self.type) {
			case '1':
				nextType = '2';
				break;
			case '2':
				nextType = '3';
				break;
			case '3':
				nextType = '4';
				break;
			case '4':
				nextType = '5';
				break;
			case '5':
				nextType = '6';
				break;
			case '6':
				nextType = '7';
				break;
			case '7':
				nextType = '8';
				break;
			case '8':
				nextType = '9';
				break;
			case '9':
				// Already at largest size, no upgrade
				return;
		}
		// Replace current asset with the next upgrade
		self.removeChild(ballGraphics);
		assetId = 'ball' + nextType;
		ballGraphics = self.attachAsset(assetId, {
			anchorX: 0.5,
			anchorY: 0.5
		});
		self.type = nextType;
		// Increase the score when balls merge
		LK.setScore(LK.getScore() + 1);
	};
});
// Class to display the next ball type in the top left corner
var NextBallDisplay = Container.expand(function (type) {
	var self = Container.call(this);
	self.nextBallGraphic = self.attachAsset('ball' + type, {
		anchorX: 0.5,
		anchorY: 0.5,
		x: 100,
		// Position x-coordinate
		y: 100,
		// Position y-coordinate
		width: 100,
		// Set width to 100
		height: 100 // Set height to 100
	});
	self.updateNextBallType = function (type) {
		self.removeChild(self.nextBallGraphic);
		self.nextBallGraphic = self.attachAsset('ball' + type, {
			anchorX: 0.5,
			anchorY: 0.5,
			x: 100,
			// Position x-coordinate
			y: 100,
			// Position y-coordinate
			width: 100,
			// Set width to 100
			height: 100 // Set height to 100
		});
	};
});
var Score = Container.expand(function () {
	var self = Container.call(this);
	var scoreText = new Text2('0', {
		size: 150,
		fill: "#ffffff"
	});
	self.addChild(scoreText);
	self.value = 0;
	self.updateScore = function () {
		self.value = balls.reduce(function (score, ball) {
			return score + Math.pow(2, parseBallType(ball.type) - 1);
		}, 0);
		scoreText.setText(self.value.toString());
	};
});
/**** 
* Initialize Game
****/ 
var game = new LK.Game({
	backgroundColor: 0x000000 // Init game with black background
});
/**** 
* Game Code
****/ 
// Initialize an array to keep track of all balls
// Define ball assets with increasing sizes and colors for each upgrade level
function calculateNextBallType(ballCount) {
	var ballType = '1';
	if (ballCount > 50) {
		var rand = Math.random();
		if (rand < 0.1) {
			ballType = '4';
		} else if (rand < 0.4) {
			ballType = '3';
		} else if (rand < 0.9) {
			ballType = '2';
		} else {
			ballType = '1';
		}
	} else if (ballCount > 25) {
		var rand = Math.random();
		if (rand < 0.3) {
			ballType = '2';
		} else if (rand < 0.6) {
			ballType = '3';
		}
	} else if (ballCount > 5 && Math.random() < 0.3) {
		ballType = '2';
	}
	return ballType;
}
var nextBallDisplay = new NextBallDisplay(nextBallType);
LK.gui.topLeft.addChild(nextBallDisplay);
function parseBallType(type) {
	return Number(type);
}
var score = new Score();
LK.gui.top.addChild(score);
var balls = [];
// Function to check for collisions and upgrade balls
function checkCollisions() {
	for (var i = 0; i < balls.length; i++) {
		for (var j = i + 1; j < balls.length; j++) {
			if (balls[i].intersects(balls[j]) && balls[i].type === balls[j].type) {
				balls[i].upgrade();
				balls[j].destroy();
				balls.splice(j, 1);
				// Adjust index to continue checking without skipping a ball
				j--;
			}
		}
	}
}
// Event listener for spawning balls on touch
var ballCount = 0;
var canThrowBall = true;
var delayEnabled = true; // Clause to enable or disable the delay on spawning balls
var nextBallType = '1'; // Pre-calculate the next ball type
game.on('down', function (x, y, obj) {
	if (canThrowBall) {
		var ballTypesToString = function ballTypesToString(ballsArray) {
			var counts = {};
			ballsArray.forEach(function (ball) {
				counts[ball.type] = (counts[ball.type] || 0) + 1;
			});
			return Object.keys(counts).map(function (type) {
				return 'Type ' + type + ': ' + counts[type];
			}).join(', ');
		};
		canThrowBall = false;
		var event = obj;
		var pos = game.toLocal(event.global);
		var ballType = nextBallType; // Use the precalculated ball type
		var newBall = new Ball(ballType);
		newBall.x = pos.x + (Math.random() * 20 - 10);
		newBall.y = 300 + (Math.random() * 20 - 10);
		// Update the next ball type display
		nextBallDisplay.updateNextBallType(ballType);
		balls.push(newBall);
		game.addChild(newBall);
		ballCount++;
		console.log('Ball count: ' + ballCount + ', Ball types: ' + ballTypesToString(balls));
		if (delayEnabled) {
			LK.setTimeout(function () {
				canThrowBall = true;
				// Calculate the next ball type for the upcoming throw
				nextBallType = calculateNextBallType(ballCount);
				nextBallDisplay.updateNextBallType(nextBallType); // Update the display with the new next ball type
			}, 1000);
		} else {
			canThrowBall = true;
			// Calculate the next ball type for the upcoming throw
			nextBallType = calculateNextBallType(ballCount);
			nextBallDisplay.updateNextBallType(nextBallType); // Update the display with the new next ball type
		}
	}
});
// Main game update loop
var gameOverTimer = null;
var flashInterval = null;
function startGameOverTimer() {
	if (gameOverTimer) {
		return;
	} // Timer already running
	gameOverTimer = LK.setTimeout(function () {
		var objectAboveZero = balls.some(function (ball) {
			return ball.y < 0;
		});
		if (objectAboveZero) {
			LK.showGameOver();
		} else {
			// Continue the game
			LK.clearTimeout(gameOverTimer);
			LK.clearInterval(flashInterval);
			gameOverTimer = null;
			flashInterval = null;
		}
	}, 3000);
	flashInterval = LK.setInterval(function () {
		LK.effects.flashScreen(0xff0000, 500);
	}, 1000);
}
LK.on('tick', function () {
	// Check if any object is above y=0
	var objectAboveZero = balls.some(function (ball) {
		return ball.y < 0;
	});
	if (objectAboveZero) {
		startGameOverTimer();
	}
	score.updateScore();
	// Check if any object is above y=0
	var objectAboveZero = balls.some(function (ball) {
		return ball.y < 0;
	});
	if (objectAboveZero) {
		startGameOverTimer();
	}
	// Apply gravity to each ball
	for (var i = 0; i < balls.length; i++) {
		balls[i].velocity.y += 0.5; // Increased gravity acceleration
		if (balls[i].y + balls[i].velocity.y > 2732 - balls[i].height / 2) {
			balls[i].velocity.y *= -0.5; // Reverse direction with damping
			balls[i].y = 2732 - balls[i].height / 2; // Position at the bottom
		} else {
			balls[i].y += balls[i].velocity.y;
		}
		// Check if part of the ball is offscreen and roll it back on screen
		if (balls[i].x - balls[i].width / 2 < 0) {
			balls[i].x = balls[i].width / 2;
			balls[i].velocity.x = Math.abs(balls[i].velocity.x);
		} else if (balls[i].x + balls[i].width / 2 > 2048) {
			balls[i].x = 2048 - balls[i].width / 2;
			balls[i].velocity.x = -Math.abs(balls[i].velocity.x);
		}
		balls[i].velocity.x *= 0.95; // Apply roll resistance
		balls[i].x += balls[i].velocity.x;
		// Adjusted collision response to prevent constant movement and clipping
		for (var j = 0; j < balls.length; j++) {
			if (i != j && balls[i].intersects(balls[j])) {
				var dx = balls[j].x - balls[i].x;
				var dy = balls[j].y - balls[i].y;
				var distance = Math.sqrt(dx * dx + dy * dy);
				var overlap = balls[i].width / 2 + balls[j].width / 2 - distance;
				if (overlap > 0) {
					var angle = Math.atan2(dy, dx);
					// Apply a small force to separate the balls
					var separationForce = 0.03 * overlap;
					balls[i].velocity.x -= separationForce * Math.cos(angle);
					balls[i].velocity.y -= separationForce * Math.sin(angle);
					balls[j].velocity.x += separationForce * Math.cos(angle);
					balls[j].velocity.y += separationForce * Math.sin(angle);
					// Adjust positions to ensure balls are no longer intersecting
					var correctionFactor = 0.5 * overlap / distance;
					balls[i].x -= correctionFactor * dx;
					balls[i].y -= correctionFactor * dy;
					balls[j].x += correctionFactor * dx;
					balls[j].y += correctionFactor * dy;
				}
			}
		}
	}
	checkCollisions();
}); /**** 
* Classes
****/ 
// Ball class to represent the game balls
var Ball = Container.expand(function (type) {
	var self = Container.call(this);
	var assetId = 'ball' + type;
	var ballGraphics = self.attachAsset(assetId, {
		anchorX: 0.5,
		anchorY: 0.5
	});
	self.type = type;
	// Initialize velocity property for gravity effect
	self.velocity = {
		x: 0,
		y: 0
	};
	self.upgrade = function () {
		var nextType;
		switch (self.type) {
			case '1':
				nextType = '2';
				break;
			case '2':
				nextType = '3';
				break;
			case '3':
				nextType = '4';
				break;
			case '4':
				nextType = '5';
				break;
			case '5':
				nextType = '6';
				break;
			case '6':
				nextType = '7';
				break;
			case '7':
				nextType = '8';
				break;
			case '8':
				nextType = '9';
				break;
			case '9':
				// Already at largest size, no upgrade
				return;
		}
		// Replace current asset with the next upgrade
		self.removeChild(ballGraphics);
		assetId = 'ball' + nextType;
		ballGraphics = self.attachAsset(assetId, {
			anchorX: 0.5,
			anchorY: 0.5
		});
		self.type = nextType;
		// Increase the score when balls merge
		LK.setScore(LK.getScore() + 1);
	};
});
// Class to display the next ball type in the top left corner
var NextBallDisplay = Container.expand(function (type) {
	var self = Container.call(this);
	self.nextBallGraphic = self.attachAsset('ball' + type, {
		anchorX: 0.5,
		anchorY: 0.5,
		x: 100,
		// Position x-coordinate
		y: 100,
		// Position y-coordinate
		width: 100,
		// Set width to 100
		height: 100 // Set height to 100
	});
	self.updateNextBallType = function (type) {
		self.removeChild(self.nextBallGraphic);
		self.nextBallGraphic = self.attachAsset('ball' + type, {
			anchorX: 0.5,
			anchorY: 0.5,
			x: 100,
			// Position x-coordinate
			y: 100,
			// Position y-coordinate
			width: 100,
			// Set width to 100
			height: 100 // Set height to 100
		});
	};
});
var Score = Container.expand(function () {
	var self = Container.call(this);
	var scoreText = new Text2('0', {
		size: 150,
		fill: "#ffffff"
	});
	self.addChild(scoreText);
	self.value = 0;
	self.updateScore = function () {
		self.value = balls.reduce(function (score, ball) {
			return score + Math.pow(2, parseBallType(ball.type) - 1);
		}, 0);
		scoreText.setText(self.value.toString());
	};
});
/**** 
* Initialize Game
****/ 
var game = new LK.Game({
	backgroundColor: 0x000000 // Init game with black background
});
/**** 
* Game Code
****/ 
// Initialize an array to keep track of all balls
// Define ball assets with increasing sizes and colors for each upgrade level
function calculateNextBallType(ballCount) {
	var ballType = '1';
	if (ballCount > 50) {
		var rand = Math.random();
		if (rand < 0.1) {
			ballType = '4';
		} else if (rand < 0.4) {
			ballType = '3';
		} else if (rand < 0.9) {
			ballType = '2';
		} else {
			ballType = '1';
		}
	} else if (ballCount > 25) {
		var rand = Math.random();
		if (rand < 0.3) {
			ballType = '2';
		} else if (rand < 0.6) {
			ballType = '3';
		}
	} else if (ballCount > 5 && Math.random() < 0.3) {
		ballType = '2';
	}
	return ballType;
}
var nextBallDisplay = new NextBallDisplay(nextBallType);
LK.gui.topLeft.addChild(nextBallDisplay);
function parseBallType(type) {
	return Number(type);
}
var score = new Score();
LK.gui.top.addChild(score);
var balls = [];
// Function to check for collisions and upgrade balls
function checkCollisions() {
	for (var i = 0; i < balls.length; i++) {
		for (var j = i + 1; j < balls.length; j++) {
			if (balls[i].intersects(balls[j]) && balls[i].type === balls[j].type) {
				balls[i].upgrade();
				balls[j].destroy();
				balls.splice(j, 1);
				// Adjust index to continue checking without skipping a ball
				j--;
			}
		}
	}
}
// Event listener for spawning balls on touch
var ballCount = 0;
var canThrowBall = true;
var delayEnabled = true; // Clause to enable or disable the delay on spawning balls
var nextBallType = '1'; // Pre-calculate the next ball type
game.on('down', function (x, y, obj) {
	if (canThrowBall) {
		var ballTypesToString = function ballTypesToString(ballsArray) {
			var counts = {};
			ballsArray.forEach(function (ball) {
				counts[ball.type] = (counts[ball.type] || 0) + 1;
			});
			return Object.keys(counts).map(function (type) {
				return 'Type ' + type + ': ' + counts[type];
			}).join(', ');
		};
		canThrowBall = false;
		var event = obj;
		var pos = game.toLocal(event.global);
		var ballType = nextBallType; // Use the precalculated ball type
		var newBall = new Ball(ballType);
		newBall.x = pos.x + (Math.random() * 20 - 10);
		newBall.y = 300 + (Math.random() * 20 - 10);
		// Update the next ball type display
		nextBallDisplay.updateNextBallType(ballType);
		balls.push(newBall);
		game.addChild(newBall);
		ballCount++;
		console.log('Ball count: ' + ballCount + ', Ball types: ' + ballTypesToString(balls));
		if (delayEnabled) {
			LK.setTimeout(function () {
				canThrowBall = true;
				// Calculate the next ball type for the upcoming throw
				nextBallType = calculateNextBallType(ballCount);
				nextBallDisplay.updateNextBallType(nextBallType); // Update the display with the new next ball type
			}, 1000);
		} else {
			canThrowBall = true;
			// Calculate the next ball type for the upcoming throw
			nextBallType = calculateNextBallType(ballCount);
			nextBallDisplay.updateNextBallType(nextBallType); // Update the display with the new next ball type
		}
	}
});
// Main game update loop
var gameOverTimer = null;
var flashInterval = null;
function startGameOverTimer() {
	if (gameOverTimer) {
		return;
	} // Timer already running
	gameOverTimer = LK.setTimeout(function () {
		var objectAboveZero = balls.some(function (ball) {
			return ball.y < 0;
		});
		if (objectAboveZero) {
			LK.showGameOver();
		} else {
			// Continue the game
			LK.clearTimeout(gameOverTimer);
			LK.clearInterval(flashInterval);
			gameOverTimer = null;
			flashInterval = null;
		}
	}, 3000);
	flashInterval = LK.setInterval(function () {
		LK.effects.flashScreen(0xff0000, 500);
	}, 1000);
}
LK.on('tick', function () {
	// Check if any object is above y=0
	var objectAboveZero = balls.some(function (ball) {
		return ball.y < 0;
	});
	if (objectAboveZero) {
		startGameOverTimer();
	}
	score.updateScore();
	// Check if any object is above y=0
	var objectAboveZero = balls.some(function (ball) {
		return ball.y < 0;
	});
	if (objectAboveZero) {
		startGameOverTimer();
	}
	// Apply gravity to each ball
	for (var i = 0; i < balls.length; i++) {
		balls[i].velocity.y += 0.5; // Increased gravity acceleration
		if (balls[i].y + balls[i].velocity.y > 2732 - balls[i].height / 2) {
			balls[i].velocity.y *= -0.5; // Reverse direction with damping
			balls[i].y = 2732 - balls[i].height / 2; // Position at the bottom
		} else {
			balls[i].y += balls[i].velocity.y;
		}
		// Check if part of the ball is offscreen and roll it back on screen
		if (balls[i].x - balls[i].width / 2 < 0) {
			balls[i].x = balls[i].width / 2;
			balls[i].velocity.x = Math.abs(balls[i].velocity.x);
		} else if (balls[i].x + balls[i].width / 2 > 2048) {
			balls[i].x = 2048 - balls[i].width / 2;
			balls[i].velocity.x = -Math.abs(balls[i].velocity.x);
		}
		balls[i].velocity.x *= 0.95; // Apply roll resistance
		balls[i].x += balls[i].velocity.x;
		// Adjusted collision response to prevent constant movement and clipping
		for (var j = 0; j < balls.length; j++) {
			if (i != j && balls[i].intersects(balls[j])) {
				var dx = balls[j].x - balls[i].x;
				var dy = balls[j].y - balls[i].y;
				var distance = Math.sqrt(dx * dx + dy * dy);
				var overlap = balls[i].width / 2 + balls[j].width / 2 - distance;
				if (overlap > 0) {
					var angle = Math.atan2(dy, dx);
					// Apply a small force to separate the balls
					var separationForce = 0.03 * overlap;
					balls[i].velocity.x -= separationForce * Math.cos(angle);
					balls[i].velocity.y -= separationForce * Math.sin(angle);
					balls[j].velocity.x += separationForce * Math.cos(angle);
					balls[j].velocity.y += separationForce * Math.sin(angle);
					// Adjust positions to ensure balls are no longer intersecting
					var correctionFactor = 0.5 * overlap / distance;
					balls[i].x -= correctionFactor * dx;
					balls[i].y -= correctionFactor * dy;
					balls[j].x += correctionFactor * dx;
					balls[j].y += correctionFactor * dy;
				}
			}
		}
	}
	checkCollisions();
});