/**** 
* Plugins
****/ 
var tween = LK.import("@upit/tween.v1");
var storage = LK.import("@upit/storage.v1", {
	highScore: 0
});
/**** 
* Classes
****/ 
var Bullet = Container.expand(function () {
	var self = Container.call(this);
	var bulletGraphics = self.attachAsset('bullet', {
		anchorX: 0.5,
		anchorY: 0.5
	});
	self.speedX = 0;
	self.speedY = 0;
	self.rotation = 0;
	self.rotationSpeed = 0;
	self.update = function () {
		self.x += self.speedX;
		self.y += self.speedY;
		// Rotate bullet if it has rotation speed
		if (self.rotationSpeed !== 0) {
			bulletGraphics.rotation += self.rotationSpeed;
		}
		// Check if bullet is off-screen with padding
		if (self.x < -50 || self.x > 2048 + 50 || self.y < -50 || self.y > 2732 + 50) {
			return true; // Return true to indicate it should be removed
		}
		return false;
	};
	return self;
});
var Ghost = Container.expand(function () {
	var self = Container.call(this);
	var ghostGraphics = self.attachAsset('ghost', {
		anchorX: 0.5,
		anchorY: 0.5,
		alpha: 0.8
	});
	// Trail effect using small ghost shapes
	self.trail = [];
	self.trailMax = 5;
	self.trailInterval = 3;
	self.trailCounter = 0;
	self.invulnerable = false;
	self.invulnerableTime = 0;
	self.blinkInterval = 5;
	self.update = function () {
		// Handle trail effect
		self.trailCounter++;
		if (self.trailCounter >= self.trailInterval) {
			self.trailCounter = 0;
			// Add new trail element
			if (self.trail.length >= self.trailMax) {
				var oldest = self.trail.shift();
				oldest.destroy();
			}
			var trail = LK.getAsset('ghost', {
				anchorX: 0.5,
				anchorY: 0.5,
				alpha: 0.3,
				scaleX: 0.7,
				scaleY: 0.7,
				x: self.x,
				y: self.y
			});
			game.addChildAt(trail, 0);
			self.trail.push(trail);
			// Fade out trail elements
			for (var i = 0; i < self.trail.length; i++) {
				var trailElement = self.trail[i];
				tween(trailElement, {
					alpha: 0
				}, {
					duration: 300,
					onFinish: function onFinish() {
						// Cleanup happens in the shift above
					}
				});
			}
		}
		// Handle invulnerability blinking
		if (self.invulnerable) {
			self.invulnerableTime--;
			if (self.invulnerableTime <= 0) {
				self.invulnerable = false;
				ghostGraphics.alpha = 0.8;
			} else {
				// Set transparency only during invulnerability
				ghostGraphics.alpha = 0.3;
				// Blink effect
				if (self.invulnerableTime % self.blinkInterval === 0) {
					ghostGraphics.alpha = ghostGraphics.alpha < 0.4 ? 0.8 : 0.3;
				}
			}
		}
	};
	self.makeInvulnerable = function (time) {
		self.invulnerable = true;
		self.invulnerableTime = time;
	};
	return self;
});
var WaveIndicator = Container.expand(function () {
	var self = Container.call(this);
	var indicatorGraphic = self.attachAsset('wave_indicator', {
		anchorX: 0.5,
		anchorY: 0.5
	});
	self.active = false;
	self.setActive = function (isActive) {
		self.active = isActive;
		if (isActive) {
			tween(indicatorGraphic, {
				alpha: 1,
				scaleX: 1.2,
				scaleY: 1.2
			}, {
				duration: 300,
				onFinish: function onFinish() {
					tween(indicatorGraphic, {
						scaleX: 1,
						scaleY: 1
					}, {
						duration: 200
					});
				}
			});
		} else {
			indicatorGraphic.alpha = 0.4;
			indicatorGraphic.scaleX = 1;
			indicatorGraphic.scaleY = 1;
		}
	};
	return self;
});
/**** 
* Initialize Game
****/ 
var game = new LK.Game({
	backgroundColor: 0x000033
});
/**** 
* Game Code
****/ 
// Background
var background = LK.getAsset('background', {
	anchorX: 0,
	anchorY: 0,
	x: 0,
	y: 0
});
game.addChild(background);
// Game state
var state = {
	score: 0,
	wave: 1,
	waveTimer: 0,
	difficulty: 1,
	isGameOver: false,
	isPaused: false,
	highScore: storage.highScore || 0
};
// Player
var ghost = new Ghost();
ghost.x = 2048 / 2;
ghost.y = 2732 / 2;
game.addChild(ghost);
// Add wave indicators
var waveIndicators = [];
var indicatorSpacing = 30;
var totalIndicators = 5;
var indicatorStartX = (2048 - (totalIndicators - 1) * indicatorSpacing) / 2;
for (var i = 0; i < totalIndicators; i++) {
	var indicator = new WaveIndicator();
	indicator.x = indicatorStartX + i * indicatorSpacing;
	indicator.y = 50;
	indicator.setActive(i === 0); // Set first one active
	waveIndicators.push(indicator);
	LK.gui.top.addChild(indicator);
}
// Bullet management
var bullets = [];
var patterns = {
	// Wave patterns
	circle: function circle(centerX, centerY, count, speed, size) {
		var angleStep = Math.PI * 2 / count;
		for (var i = 0; i < count; i++) {
			var angle = i * angleStep;
			createBullet(centerX, centerY, Math.cos(angle) * speed, Math.sin(angle) * speed, size);
		}
	},
	spiral: function spiral(centerX, centerY, count, speed, size) {
		var timeout = 0;
		var angleStep = Math.PI * 2 / count;
		for (var i = 0; i < count; i++) {
			(function (index) {
				LK.setTimeout(function () {
					var angle = index * angleStep;
					createBullet(centerX, centerY, Math.cos(angle) * speed, Math.sin(angle) * speed, size);
				}, timeout);
				timeout += 100;
			})(i);
		}
	},
	random: function random(count, speed, size) {
		for (var i = 0; i < count; i++) {
			var side = Math.floor(Math.random() * 4); // 0:top, 1:right, 2:bottom, 3:left
			var startX, startY;
			var targetX = ghost.x + (Math.random() * 100 - 50);
			var targetY = ghost.y + (Math.random() * 100 - 50);
			switch (side) {
				case 0:
					// Top
					startX = Math.random() * 2048;
					startY = -50;
					break;
				case 1:
					// Right
					startX = 2048 + 50;
					startY = Math.random() * 2732;
					break;
				case 2:
					// Bottom
					startX = Math.random() * 2048;
					startY = 2732 + 50;
					break;
				case 3:
					// Left
					startX = -50;
					startY = Math.random() * 2732;
					break;
			}
			var angle = Math.atan2(targetY - startY, targetX - startX);
			createBullet(startX, startY, Math.cos(angle) * speed, Math.sin(angle) * speed, size, 0.05);
		}
	},
	aimed: function aimed(count, speed, size) {
		var angleSpread = Math.PI / 4; // 45 degree spread
		for (var i = 0; i < count; i++) {
			var side = Math.floor(Math.random() * 4);
			var startX, startY;
			switch (side) {
				case 0:
					// Top
					startX = Math.random() * 2048;
					startY = -50;
					break;
				case 1:
					// Right
					startX = 2048 + 50;
					startY = Math.random() * 2732;
					break;
				case 2:
					// Bottom
					startX = Math.random() * 2048;
					startY = 2732 + 50;
					break;
				case 3:
					// Left
					startX = -50;
					startY = Math.random() * 2732;
					break;
			}
			var baseAngle = Math.atan2(ghost.y - startY, ghost.x - startX);
			var angleOffset = angleSpread * (Math.random() - 0.5);
			var angle = baseAngle + angleOffset;
			createBullet(startX, startY, Math.cos(angle) * speed, Math.sin(angle) * speed, size);
		}
	}
};
function createBullet(x, y, speedX, speedY, scale, rotationSpeed) {
	var bullet = new Bullet();
	bullet.x = x;
	bullet.y = y;
	bullet.speedX = speedX;
	bullet.speedY = speedY;
	bullet.rotationSpeed = rotationSpeed || 0;
	if (scale) {
		bullet.scale.set(scale);
	}
	bullets.push(bullet);
	game.addChild(bullet);
	return bullet;
}
function spawnWave() {
	var baseCount = 10;
	var baseSpeed = 3;
	// Update wave indicators
	var currentWaveIndex = (state.wave - 1) % totalIndicators;
	for (var i = 0; i < waveIndicators.length; i++) {
		waveIndicators[i].setActive(i === currentWaveIndex);
	}
	// Increase difficulty with each wave
	var count = Math.floor(baseCount * Math.sqrt(state.difficulty));
	var speed = baseSpeed * (1 + (state.difficulty - 1) * 0.1);
	// Play wave complete sound if not the first wave
	if (state.wave > 1) {
		LK.getSound('wave_complete').play();
	}
	// Choose pattern based on wave
	switch ((state.wave - 1) % 4) {
		case 0:
			patterns.circle(2048 / 2, 2732 / 2, count, speed, 1);
			break;
		case 1:
			patterns.spiral(2048 / 2, 2732 / 2, count, speed, 1);
			break;
		case 2:
			patterns.random(count, speed, 1);
			break;
		case 3:
			patterns.aimed(count, speed, 1);
			break;
	}
	// Make player briefly invulnerable after a new wave
	ghost.makeInvulnerable(60);
	// Increment difficulty
	state.difficulty += 0.2;
	// Set timer for next wave
	state.waveTimer = Math.max(180, 300 - state.wave * 10); // Decrease time between waves
}
// Initialize scoreboard
var scoreTxt = new Text2('Score: 0', {
	size: 50,
	fill: 0xFFFFFF
});
scoreTxt.anchor.set(1, 0); // Anchor to top-right
LK.gui.topRight.addChild(scoreTxt);
// Wave indicator text
var waveTxt = new Text2('Wave: 1', {
	size: 50,
	fill: 0xFFFFFF
});
waveTxt.anchor.set(0, 0); // Anchor to top-left
LK.gui.top.addChild(waveTxt);
// Allow dragging of the ghost
var isDragging = false;
// Handle input
game.down = function (x, y) {
	if (!state.isPaused && !state.isGameOver) {
		// Teleport ghost to mouse position
		ghost.x = x;
		ghost.y = y;
		// Make ghost invulnerable and semi-transparent for 1 second
		ghost.makeInvulnerable(60);
	}
};
game.move = function (x, y) {
	if (!state.isPaused && !state.isGameOver) {
		// Continuously update ghost position to follow the mouse
		ghost.x = x;
		ghost.y = y;
	}
};
game.up = function () {
	// Removed dragging state reset
};
// Main game update function
game.update = function () {
	if (state.isGameOver) {
		return;
	}
	// Increment score
	state.score++;
	scoreTxt.setText('Score: ' + state.score);
	waveTxt.setText('Wave: ' + state.wave);
	// Wave timer logic
	if (state.waveTimer > 0) {
		state.waveTimer--;
		if (state.waveTimer === 0 || bullets.length === 0) {
			state.wave++;
			spawnWave();
		}
	}
	// Update bullets
	for (var i = bullets.length - 1; i >= 0; i--) {
		var bullet = bullets[i];
		if (bullet.update()) {
			// Bullet is off-screen, remove it
			bullet.destroy();
			bullets.splice(i, 1);
			continue;
		}
		// Check collision with ghost
		if (!ghost.invulnerable && bullet.intersects(ghost)) {
			// Handle collision
			LK.getSound('hit').play();
			// Flash screen
			LK.effects.flashScreen(0xff0000, 500);
			// Game over
			state.isGameOver = true;
			// Update high score
			if (state.score > state.highScore) {
				state.highScore = state.score;
				storage.highScore = state.score;
			}
			// Play game over sound
			LK.getSound('game_over').play();
			// Show game over screen after a short delay
			LK.setTimeout(function () {
				LK.showGameOver();
			}, 1000);
			break;
		}
	}
};
// Start first wave
spawnWave();
// Play background music
LK.playMusic('game_music', {
	fade: {
		start: 0,
		end: 0.4,
		duration: 1000
	}
}); /**** 
* Plugins
****/ 
var tween = LK.import("@upit/tween.v1");
var storage = LK.import("@upit/storage.v1", {
	highScore: 0
});
/**** 
* Classes
****/ 
var Bullet = Container.expand(function () {
	var self = Container.call(this);
	var bulletGraphics = self.attachAsset('bullet', {
		anchorX: 0.5,
		anchorY: 0.5
	});
	self.speedX = 0;
	self.speedY = 0;
	self.rotation = 0;
	self.rotationSpeed = 0;
	self.update = function () {
		self.x += self.speedX;
		self.y += self.speedY;
		// Rotate bullet if it has rotation speed
		if (self.rotationSpeed !== 0) {
			bulletGraphics.rotation += self.rotationSpeed;
		}
		// Check if bullet is off-screen with padding
		if (self.x < -50 || self.x > 2048 + 50 || self.y < -50 || self.y > 2732 + 50) {
			return true; // Return true to indicate it should be removed
		}
		return false;
	};
	return self;
});
var Ghost = Container.expand(function () {
	var self = Container.call(this);
	var ghostGraphics = self.attachAsset('ghost', {
		anchorX: 0.5,
		anchorY: 0.5,
		alpha: 0.8
	});
	// Trail effect using small ghost shapes
	self.trail = [];
	self.trailMax = 5;
	self.trailInterval = 3;
	self.trailCounter = 0;
	self.invulnerable = false;
	self.invulnerableTime = 0;
	self.blinkInterval = 5;
	self.update = function () {
		// Handle trail effect
		self.trailCounter++;
		if (self.trailCounter >= self.trailInterval) {
			self.trailCounter = 0;
			// Add new trail element
			if (self.trail.length >= self.trailMax) {
				var oldest = self.trail.shift();
				oldest.destroy();
			}
			var trail = LK.getAsset('ghost', {
				anchorX: 0.5,
				anchorY: 0.5,
				alpha: 0.3,
				scaleX: 0.7,
				scaleY: 0.7,
				x: self.x,
				y: self.y
			});
			game.addChildAt(trail, 0);
			self.trail.push(trail);
			// Fade out trail elements
			for (var i = 0; i < self.trail.length; i++) {
				var trailElement = self.trail[i];
				tween(trailElement, {
					alpha: 0
				}, {
					duration: 300,
					onFinish: function onFinish() {
						// Cleanup happens in the shift above
					}
				});
			}
		}
		// Handle invulnerability blinking
		if (self.invulnerable) {
			self.invulnerableTime--;
			if (self.invulnerableTime <= 0) {
				self.invulnerable = false;
				ghostGraphics.alpha = 0.8;
			} else {
				// Set transparency only during invulnerability
				ghostGraphics.alpha = 0.3;
				// Blink effect
				if (self.invulnerableTime % self.blinkInterval === 0) {
					ghostGraphics.alpha = ghostGraphics.alpha < 0.4 ? 0.8 : 0.3;
				}
			}
		}
	};
	self.makeInvulnerable = function (time) {
		self.invulnerable = true;
		self.invulnerableTime = time;
	};
	return self;
});
var WaveIndicator = Container.expand(function () {
	var self = Container.call(this);
	var indicatorGraphic = self.attachAsset('wave_indicator', {
		anchorX: 0.5,
		anchorY: 0.5
	});
	self.active = false;
	self.setActive = function (isActive) {
		self.active = isActive;
		if (isActive) {
			tween(indicatorGraphic, {
				alpha: 1,
				scaleX: 1.2,
				scaleY: 1.2
			}, {
				duration: 300,
				onFinish: function onFinish() {
					tween(indicatorGraphic, {
						scaleX: 1,
						scaleY: 1
					}, {
						duration: 200
					});
				}
			});
		} else {
			indicatorGraphic.alpha = 0.4;
			indicatorGraphic.scaleX = 1;
			indicatorGraphic.scaleY = 1;
		}
	};
	return self;
});
/**** 
* Initialize Game
****/ 
var game = new LK.Game({
	backgroundColor: 0x000033
});
/**** 
* Game Code
****/ 
// Background
var background = LK.getAsset('background', {
	anchorX: 0,
	anchorY: 0,
	x: 0,
	y: 0
});
game.addChild(background);
// Game state
var state = {
	score: 0,
	wave: 1,
	waveTimer: 0,
	difficulty: 1,
	isGameOver: false,
	isPaused: false,
	highScore: storage.highScore || 0
};
// Player
var ghost = new Ghost();
ghost.x = 2048 / 2;
ghost.y = 2732 / 2;
game.addChild(ghost);
// Add wave indicators
var waveIndicators = [];
var indicatorSpacing = 30;
var totalIndicators = 5;
var indicatorStartX = (2048 - (totalIndicators - 1) * indicatorSpacing) / 2;
for (var i = 0; i < totalIndicators; i++) {
	var indicator = new WaveIndicator();
	indicator.x = indicatorStartX + i * indicatorSpacing;
	indicator.y = 50;
	indicator.setActive(i === 0); // Set first one active
	waveIndicators.push(indicator);
	LK.gui.top.addChild(indicator);
}
// Bullet management
var bullets = [];
var patterns = {
	// Wave patterns
	circle: function circle(centerX, centerY, count, speed, size) {
		var angleStep = Math.PI * 2 / count;
		for (var i = 0; i < count; i++) {
			var angle = i * angleStep;
			createBullet(centerX, centerY, Math.cos(angle) * speed, Math.sin(angle) * speed, size);
		}
	},
	spiral: function spiral(centerX, centerY, count, speed, size) {
		var timeout = 0;
		var angleStep = Math.PI * 2 / count;
		for (var i = 0; i < count; i++) {
			(function (index) {
				LK.setTimeout(function () {
					var angle = index * angleStep;
					createBullet(centerX, centerY, Math.cos(angle) * speed, Math.sin(angle) * speed, size);
				}, timeout);
				timeout += 100;
			})(i);
		}
	},
	random: function random(count, speed, size) {
		for (var i = 0; i < count; i++) {
			var side = Math.floor(Math.random() * 4); // 0:top, 1:right, 2:bottom, 3:left
			var startX, startY;
			var targetX = ghost.x + (Math.random() * 100 - 50);
			var targetY = ghost.y + (Math.random() * 100 - 50);
			switch (side) {
				case 0:
					// Top
					startX = Math.random() * 2048;
					startY = -50;
					break;
				case 1:
					// Right
					startX = 2048 + 50;
					startY = Math.random() * 2732;
					break;
				case 2:
					// Bottom
					startX = Math.random() * 2048;
					startY = 2732 + 50;
					break;
				case 3:
					// Left
					startX = -50;
					startY = Math.random() * 2732;
					break;
			}
			var angle = Math.atan2(targetY - startY, targetX - startX);
			createBullet(startX, startY, Math.cos(angle) * speed, Math.sin(angle) * speed, size, 0.05);
		}
	},
	aimed: function aimed(count, speed, size) {
		var angleSpread = Math.PI / 4; // 45 degree spread
		for (var i = 0; i < count; i++) {
			var side = Math.floor(Math.random() * 4);
			var startX, startY;
			switch (side) {
				case 0:
					// Top
					startX = Math.random() * 2048;
					startY = -50;
					break;
				case 1:
					// Right
					startX = 2048 + 50;
					startY = Math.random() * 2732;
					break;
				case 2:
					// Bottom
					startX = Math.random() * 2048;
					startY = 2732 + 50;
					break;
				case 3:
					// Left
					startX = -50;
					startY = Math.random() * 2732;
					break;
			}
			var baseAngle = Math.atan2(ghost.y - startY, ghost.x - startX);
			var angleOffset = angleSpread * (Math.random() - 0.5);
			var angle = baseAngle + angleOffset;
			createBullet(startX, startY, Math.cos(angle) * speed, Math.sin(angle) * speed, size);
		}
	}
};
function createBullet(x, y, speedX, speedY, scale, rotationSpeed) {
	var bullet = new Bullet();
	bullet.x = x;
	bullet.y = y;
	bullet.speedX = speedX;
	bullet.speedY = speedY;
	bullet.rotationSpeed = rotationSpeed || 0;
	if (scale) {
		bullet.scale.set(scale);
	}
	bullets.push(bullet);
	game.addChild(bullet);
	return bullet;
}
function spawnWave() {
	var baseCount = 10;
	var baseSpeed = 3;
	// Update wave indicators
	var currentWaveIndex = (state.wave - 1) % totalIndicators;
	for (var i = 0; i < waveIndicators.length; i++) {
		waveIndicators[i].setActive(i === currentWaveIndex);
	}
	// Increase difficulty with each wave
	var count = Math.floor(baseCount * Math.sqrt(state.difficulty));
	var speed = baseSpeed * (1 + (state.difficulty - 1) * 0.1);
	// Play wave complete sound if not the first wave
	if (state.wave > 1) {
		LK.getSound('wave_complete').play();
	}
	// Choose pattern based on wave
	switch ((state.wave - 1) % 4) {
		case 0:
			patterns.circle(2048 / 2, 2732 / 2, count, speed, 1);
			break;
		case 1:
			patterns.spiral(2048 / 2, 2732 / 2, count, speed, 1);
			break;
		case 2:
			patterns.random(count, speed, 1);
			break;
		case 3:
			patterns.aimed(count, speed, 1);
			break;
	}
	// Make player briefly invulnerable after a new wave
	ghost.makeInvulnerable(60);
	// Increment difficulty
	state.difficulty += 0.2;
	// Set timer for next wave
	state.waveTimer = Math.max(180, 300 - state.wave * 10); // Decrease time between waves
}
// Initialize scoreboard
var scoreTxt = new Text2('Score: 0', {
	size: 50,
	fill: 0xFFFFFF
});
scoreTxt.anchor.set(1, 0); // Anchor to top-right
LK.gui.topRight.addChild(scoreTxt);
// Wave indicator text
var waveTxt = new Text2('Wave: 1', {
	size: 50,
	fill: 0xFFFFFF
});
waveTxt.anchor.set(0, 0); // Anchor to top-left
LK.gui.top.addChild(waveTxt);
// Allow dragging of the ghost
var isDragging = false;
// Handle input
game.down = function (x, y) {
	if (!state.isPaused && !state.isGameOver) {
		// Teleport ghost to mouse position
		ghost.x = x;
		ghost.y = y;
		// Make ghost invulnerable and semi-transparent for 1 second
		ghost.makeInvulnerable(60);
	}
};
game.move = function (x, y) {
	if (!state.isPaused && !state.isGameOver) {
		// Continuously update ghost position to follow the mouse
		ghost.x = x;
		ghost.y = y;
	}
};
game.up = function () {
	// Removed dragging state reset
};
// Main game update function
game.update = function () {
	if (state.isGameOver) {
		return;
	}
	// Increment score
	state.score++;
	scoreTxt.setText('Score: ' + state.score);
	waveTxt.setText('Wave: ' + state.wave);
	// Wave timer logic
	if (state.waveTimer > 0) {
		state.waveTimer--;
		if (state.waveTimer === 0 || bullets.length === 0) {
			state.wave++;
			spawnWave();
		}
	}
	// Update bullets
	for (var i = bullets.length - 1; i >= 0; i--) {
		var bullet = bullets[i];
		if (bullet.update()) {
			// Bullet is off-screen, remove it
			bullet.destroy();
			bullets.splice(i, 1);
			continue;
		}
		// Check collision with ghost
		if (!ghost.invulnerable && bullet.intersects(ghost)) {
			// Handle collision
			LK.getSound('hit').play();
			// Flash screen
			LK.effects.flashScreen(0xff0000, 500);
			// Game over
			state.isGameOver = true;
			// Update high score
			if (state.score > state.highScore) {
				state.highScore = state.score;
				storage.highScore = state.score;
			}
			// Play game over sound
			LK.getSound('game_over').play();
			// Show game over screen after a short delay
			LK.setTimeout(function () {
				LK.showGameOver();
			}, 1000);
			break;
		}
	}
};
// Start first wave
spawnWave();
// Play background music
LK.playMusic('game_music', {
	fade: {
		start: 0,
		end: 0.4,
		duration: 1000
	}
});