/**** 
* Plugins
****/ 
var tween = LK.import("@upit/tween.v1");
/**** 
* Classes
****/ 
// --- Win Condition (Optional: e.g. score 30) ---
/*
if (score >= 30) {
		LK.showYouWin();
}
*/
// --- End of File ---
// Monster: Enemy advancing from the top
var Monster = Container.expand(function () {
	var self = Container.call(this);
	// Attach monster asset (box/ellipse)
	var monsterAsset = self.attachAsset('monster', {
		anchorX: 0.5,
		anchorY: 0.5,
		width: self.monsterSize,
		height: self.monsterSize
	});
	// Health points
	self.hp = self.maxHp;
	// Called every tick
	self.update = function () {
		// Monsters only move forward if not destroyed
		if (!self.destroyed) {
			// Move toward hero using direction vector if set
			if (typeof self.dirX === "number" && typeof self.dirY === "number") {
				self.x += self.dirX * self.speed;
				self.y += self.dirY * self.speed;
			} else {
				// fallback: move down
				self.y += self.speed;
			}
		}
	};
	// --- Flying effect: gentle up/down hover using tween ---
	function startFlyingEffect() {
		// Reset to default before starting
		self.yOffset = 0;
		// Animate up
		tween(self, {
			yOffset: -18
		}, {
			duration: 420 + Math.random() * 120,
			easing: tween.easeInOut,
			onUpdate: function onUpdate() {
				// Apply yOffset to monster position
				self.y += self.yOffset - (self._lastYOffset || 0);
				self._lastYOffset = self.yOffset;
			},
			onFinish: function onFinish() {
				// Animate down
				tween(self, {
					yOffset: 18
				}, {
					duration: 420 + Math.random() * 120,
					easing: tween.easeInOut,
					onUpdate: function onUpdate() {
						self.y += self.yOffset - (self._lastYOffset || 0);
						self._lastYOffset = self.yOffset;
					},
					onFinish: function onFinish() {
						startFlyingEffect();
					}
				});
			}
		});
	}
	startFlyingEffect();
	// Take damage
	self.hit = function () {
		self.hp -= 1;
		if (self.hp <= 0) {
			self.destroyed = true;
			// Play monster dead sound
			LK.getSound('monsterdead').play();
			// Animate scale up and fade out for death effect
			tween(self, {
				alpha: 0,
				scaleX: 1.7,
				scaleY: 1.7
			}, {
				duration: 220,
				onFinish: function onFinish() {
					self.destroy();
				}
			});
		} else {
			// Flash red
			tween(monsterAsset, {
				tint: 0xff4444
			}, {
				duration: 80,
				onFinish: function onFinish() {
					tween(monsterAsset, {
						tint: self.baseColor
					}, {
						duration: 120
					});
				}
			});
		}
	};
	return self;
});
// Monster2: Funky Groove special monster
var Monster2 = Container.expand(function () {
	var self = Container.call(this);
	// Attach monster2 asset
	var monsterAsset = self.attachAsset('monster2', {
		anchorX: 0.5,
		anchorY: 0.5,
		width: self.monsterSize,
		height: self.monsterSize
	});
	// Health points
	self.hp = self.maxHp;
	// Called every tick
	self.update = function () {
		if (!self.destroyed) {
			if (typeof self.dirX === "number" && typeof self.dirY === "number") {
				self.x += self.dirX * self.speed;
				self.y += self.dirY * self.speed;
			} else {
				self.y += self.speed;
			}
		}
	};
	// --- Flying effect: gentle up/down hover using tween ---
	function startFlyingEffect() {
		self.yOffset = 0;
		tween(self, {
			yOffset: -18
		}, {
			duration: 420 + Math.random() * 120,
			easing: tween.easeInOut,
			onUpdate: function onUpdate() {
				self.y += self.yOffset - (self._lastYOffset || 0);
				self._lastYOffset = self.yOffset;
			},
			onFinish: function onFinish() {
				tween(self, {
					yOffset: 18
				}, {
					duration: 420 + Math.random() * 120,
					easing: tween.easeInOut,
					onUpdate: function onUpdate() {
						self.y += self.yOffset - (self._lastYOffset || 0);
						self._lastYOffset = self.yOffset;
					},
					onFinish: function onFinish() {
						startFlyingEffect();
					}
				});
			}
		});
	}
	startFlyingEffect();
	// Take damage
	self.hit = function () {
		self.hp -= 1;
		if (self.hp <= 0) {
			self.destroyed = true;
			// Play monsterdead2 sound for Funky Groove monsters
			LK.getSound('monsterdead2').play();
			tween(self, {
				alpha: 0,
				scaleX: 1.7,
				scaleY: 1.7
			}, {
				duration: 220,
				onFinish: function onFinish() {
					self.destroy();
				}
			});
		} else {
			// Flash red
			tween(monsterAsset, {
				tint: 0xff4444
			}, {
				duration: 80,
				onFinish: function onFinish() {
					tween(monsterAsset, {
						tint: self.baseColor
					}, {
						duration: 120
					});
				}
			});
		}
	};
	return self;
});
// Monster3: Majestic Mountains special monster
var Monster3 = Container.expand(function () {
	var self = Container.call(this);
	// Attach monster3 asset
	var monsterAsset = self.attachAsset('monster3', {
		anchorX: 0.5,
		anchorY: 0.5,
		width: self.monsterSize,
		height: self.monsterSize
	});
	// Health points
	self.hp = self.maxHp;
	// Called every tick
	self.update = function () {
		if (!self.destroyed) {
			if (typeof self.dirX === "number" && typeof self.dirY === "number") {
				self.x += self.dirX * self.speed;
				self.y += self.dirY * self.speed;
			} else {
				self.y += self.speed;
			}
		}
	};
	// --- Flying effect: gentle up/down hover using tween ---
	function startFlyingEffect() {
		self.yOffset = 0;
		tween(self, {
			yOffset: -18
		}, {
			duration: 420 + Math.random() * 120,
			easing: tween.easeInOut,
			onUpdate: function onUpdate() {
				self.y += self.yOffset - (self._lastYOffset || 0);
				self._lastYOffset = self.yOffset;
			},
			onFinish: function onFinish() {
				tween(self, {
					yOffset: 18
				}, {
					duration: 420 + Math.random() * 120,
					easing: tween.easeInOut,
					onUpdate: function onUpdate() {
						self.y += self.yOffset - (self._lastYOffset || 0);
						self._lastYOffset = self.yOffset;
					},
					onFinish: function onFinish() {
						startFlyingEffect();
					}
				});
			}
		});
	}
	startFlyingEffect();
	// Take damage
	self.hit = function () {
		self.hp -= 1;
		if (self.hp <= 0) {
			self.destroyed = true;
			// Play monsterdead3 sound for Majestic Mountains monsters
			LK.getSound('monsterdead3').play();
			tween(self, {
				alpha: 0,
				scaleX: 1.7,
				scaleY: 1.7
			}, {
				duration: 220,
				onFinish: function onFinish() {
					self.destroy();
				}
			});
		} else {
			// Flash red
			tween(monsterAsset, {
				tint: 0xff4444
			}, {
				duration: 80,
				onFinish: function onFinish() {
					tween(monsterAsset, {
						tint: self.baseColor
					}, {
						duration: 120
					});
				}
			});
		}
	};
	return self;
});
// Note: Falling note that must be hit in time
var Note = Container.expand(function () {
	var self = Container.call(this);
	// Pick a random note asset for this note
	var noteAssetId = 'note' + (1 + Math.floor(Math.random() * 4));
	self.noteAssetId = noteAssetId;
	var noteAsset = self.attachAsset(noteAssetId, {
		anchorX: 0.5,
		anchorY: 0.5,
		width: self.noteSize,
		height: self.noteSize
	});
	// Index of the key this note targets
	self.keyIndex = typeof self.keyIndex !== "undefined" ? self.keyIndex : self.index;
	// Used for hit/miss detection
	self.active = true;
	// Called every tick
	self.update = function () {
		// Notes always fall straight down toward their assigned key
		self.y += self.speed;
		// Find the key this note is assigned to
		var key = typeof self.keyIndex !== "undefined" && self.keyIndex >= 0 && self.keyIndex < NUM_KEYS ? pianoKeys[self.keyIndex] : null;
		if (key) {
			var missY = key.y + KEY_HEIGHT + self.noteSize / 2;
			// If note crosses the bottom boundary and is still active, mark as miss and destroy
			if (self.y > missY && self.active) {
				self.active = false;
				// Register miss
				missCount += 1;
				missTxt.setText('Misses: ' + missCount);
				LK.effects.flashObject(hero, 0xff4444, 200);
				checkGameOver();
				self.destroy();
			}
		} else {
			// Defensive: If key is missing, just destroy the note
			self.destroy();
		}
	};
	return self;
});
// PianoKey: Represents a single piano key at the bottom
var PianoKey = Container.expand(function () {
	var self = Container.call(this);
	// Defensive: Set defaults if not set
	if (typeof self.assetId === "undefined") {
		self.assetId = 'key_piano';
	}
	if (typeof self.keyWidth === "undefined") {
		self.keyWidth = KEY_WIDTH;
	}
	if (typeof self.keyHeight === "undefined") {
		self.keyHeight = KEY_HEIGHT;
	}
	if (typeof self.baseColor === "undefined") {
		self.baseColor = 0xffffff;
	}
	if (typeof self.index === "undefined") {
		self.index = 0;
	}
	// Attach key asset (always key_piano)
	var keyAsset = self.attachAsset(self.assetId, {
		anchorX: 0.5,
		anchorY: 0,
		width: self.keyWidth,
		height: self.keyHeight
	});
	// Store index for reference
	self.keyIndex = self.index;
	// Set initial dim state
	keyAsset.alpha = 0.45;
	// Visual feedback for press
	self.flash = function () {
		// Light up key
		tween(keyAsset, {
			alpha: 1
		}, {
			duration: 60,
			onFinish: function onFinish() {
				// Return to dim after a short time
				tween(keyAsset, {
					alpha: 0.45
				}, {
					duration: 120
				});
			}
		});
	};
	return self;
});
// Projectile: Fired by hero toward a monster
var Projectile = Container.expand(function () {
	var self = Container.call(this);
	// Defensive: Set defaults if not set
	if (typeof self.size === "undefined") {
		self.size = PROJECTILE_SIZE;
	}
	if (typeof self.speed === "undefined") {
		self.speed = PROJECTILE_SPEED;
	}
	// Pick a random bullet asset for this projectile
	var bulletAssetIds = ['bullet', 'bullet2', 'bullet3', 'bullet4'];
	var chosenBulletAsset = bulletAssetIds[Math.floor(Math.random() * bulletAssetIds.length)];
	// Attach bullet asset
	var projAsset = self.attachAsset(chosenBulletAsset, {
		anchorX: 0.5,
		anchorY: 0.5,
		width: self.size,
		height: self.size
	});
	// Target monster (set externally)
	self.target = null;
	// Called every tick
	self.update = function () {
		// If no target or target destroyed, fade out and destroy
		if (!self.target || self.target.destroyed || !self.target.parent) {
			tween(self, {
				alpha: 0,
				scaleX: 1.5,
				scaleY: 1.5
			}, {
				duration: 120,
				onFinish: function onFinish() {
					self.destroy();
				}
			});
			return;
		}
		// Move toward target
		var dx = self.target.x - self.x;
		var dy = self.target.y - self.y;
		var dist = Math.sqrt(dx * dx + dy * dy);
		if (dist < self.speed) {
			// Arrived at target: hit!
			if (typeof self.target.hit === "function") {
				self.target.hit();
			}
			// Impact effect
			tween(self, {
				alpha: 0,
				scaleX: 1.7,
				scaleY: 1.7
			}, {
				duration: 120,
				onFinish: function onFinish() {
					self.destroy();
				}
			});
			return;
		}
		// Move toward target
		self.x += dx / dist * self.speed;
		self.y += dy / dist * self.speed;
	};
	return self;
});
/**** 
* Initialize Game
****/ 
var game = new LK.Game({
	backgroundColor: 0x181830
});
/**** 
* Game Code
****/ 
// Create splash background asset (full screen, custom color or image)
// --- SPLASH SCREEN LOGIC ---
// Funky Groove top background (separate from splash and other screens)
var splashBg = LK.getAsset('entry_bg', {
	anchorX: 0,
	anchorY: 0,
	x: 0,
	y: 0,
	width: 2048,
	height: 2732
});
game.addChild(splashBg);
// Title text
var splashTitle = new Text2("Melody Mayhem", {
	size: 210,
	fill: 0xFFE600,
	font: "'Impact','GillSans-Bold','Arial Black',Tahoma,sans-serif",
	stroke: "#222",
	strokeThickness: 16,
	dropShadow: true,
	dropShadowColor: "#000",
	dropShadowDistance: 8,
	dropShadowAngle: Math.PI / 2,
	dropShadowBlur: 8
});
// Move splash title and buttons to the bottom of the screen
splashTitle.anchor.set(0.5, 1);
splashTitle.x = 2048 / 2;
splashTitle.y = 2732 - 420;
game.addChild(splashTitle);
// "Choose The Music" button
var chooseMusicBtn = new Container();
var chooseMusicBg = LK.getAsset('centerCircle', {
	anchorX: 0.5,
	anchorY: 0.5,
	width: 700,
	height: 180,
	x: 0,
	y: 0
});
chooseMusicBtn.addChild(chooseMusicBg);
var chooseMusicTxt = new Text2("Choose The Music", {
	size: 82,
	fill: ["#FF5F6D", "#FFC371", "#43E97B", "#38F9D7"],
	// gradient-like array for color pop
	font: "'Comic Sans MS','Luckiest Guy','Impact','GillSans-Bold','Arial Black',Tahoma,sans-serif",
	stroke: "#fff",
	strokeThickness: 7,
	dropShadow: true,
	dropShadowColor: "#222",
	dropShadowDistance: 3,
	dropShadowAngle: Math.PI / 2,
	dropShadowBlur: 7
});
chooseMusicTxt.anchor.set(0.5, 0.5);
chooseMusicTxt.x = 0;
chooseMusicTxt.y = 0;
chooseMusicBtn.addChild(chooseMusicTxt);
// "How to Play" button
var howToPlayBtn = new Container();
var howToPlayBg = LK.getAsset('centerCircle', {
	anchorX: 0.5,
	anchorY: 0.5,
	width: 700,
	height: 180,
	x: 0,
	y: 0
});
howToPlayBtn.addChild(howToPlayBg);
var howToPlayTxt = new Text2("How to Play", {
	size: 82,
	fill: ["#43E97B", "#38F9D7", "#FF5F6D", "#FFC371"],
	// gradient-like array for color pop
	font: "'Comic Sans MS','Luckiest Guy','Impact','GillSans-Bold','Arial Black',Tahoma,sans-serif",
	stroke: "#fff",
	strokeThickness: 7,
	dropShadow: true,
	dropShadowColor: "#222",
	dropShadowDistance: 3,
	dropShadowAngle: Math.PI / 2,
	dropShadowBlur: 7
});
howToPlayTxt.anchor.set(0.5, 0.5);
howToPlayTxt.x = 0;
howToPlayTxt.y = 0;
howToPlayBtn.addChild(howToPlayTxt);
// Position both buttons side by side, centered horizontally at the bottom
var buttonSpacing = 80; // space between buttons
var buttonY = 2732 - 180; // bottom margin, same for both
var buttonTotalWidth = 700 * 2 + buttonSpacing;
var leftBtnX = 2048 / 2 - (700 / 2 + buttonSpacing / 2);
var rightBtnX = 2048 / 2 + (700 / 2 + buttonSpacing / 2);
chooseMusicBtn.x = leftBtnX;
chooseMusicBtn.y = buttonY;
howToPlayBtn.x = rightBtnX;
howToPlayBtn.y = buttonY;
game.addChild(chooseMusicBtn);
game.addChild(howToPlayBtn);
// Music selection menu (hidden by default)
var musicMenu = new Container();
musicMenu.visible = false;
musicMenu.x = 2048 / 2;
musicMenu.y = 1200;
var musicNames = [{
	id: "gamemusic",
	label: "Cyber : 2099",
	fill: ["#00F0FF", "#FF00C8", "#00FF85"] // Vibrant neon
}, {
	id: "gamemusic2",
	label: "Welcome to Hell",
	fill: ["#FF2D00", "#FFB800", "#FF00A8"] // Hot, fiery
}, {
	id: "gamemusic3",
	label: "Majestic Mountains",
	fill: ["#00FFB2", "#00B2FF", "#FFFA00"] // Lively, fresh
}];
var musicBtns = [];
for (var i = 0; i < musicNames.length; i++) {
	var btn = new Container();
	var btnBg = LK.getAsset('centerCircle', {
		anchorX: 0.5,
		anchorY: 0.5,
		width: 820,
		// wider for long names
		height: 150,
		// slightly taller for better fit
		x: 0,
		y: 0
	});
	btn.addChild(btnBg);
	var btnTxt = new Text2(musicNames[i].label, {
		size: 66,
		// smaller font to fit long names
		fill: musicNames[i].fill,
		font: "'Comic Sans MS','Luckiest Guy','Impact','GillSans-Bold','Arial Black',Tahoma,sans-serif",
		stroke: "#fff",
		strokeThickness: 8,
		dropShadow: true,
		dropShadowColor: "#000",
		dropShadowDistance: 4,
		dropShadowAngle: Math.PI / 2,
		dropShadowBlur: 8
	});
	btnTxt.anchor.set(0.5, 0.5);
	btnTxt.x = 0;
	btnTxt.y = 0;
	btn.addChild(btnTxt);
	btn.x = 0;
	btn.y = i * 180;
	btn.musicId = musicNames[i].id;
	musicBtns.push(btn);
	musicMenu.addChild(btn);
}
// Add a back button to the music menu
var backBtn = new Container();
var backBtnBg = LK.getAsset('centerCircle', {
	anchorX: 0.5,
	anchorY: 0.5,
	width: 500,
	height: 120,
	x: 0,
	y: 0
});
backBtn.addChild(backBtnBg);
var backBtnTxt = new Text2("Back", {
	size: 70,
	fill: ["#FF5F6D", "#43E97B"],
	font: "'Comic Sans MS','Luckiest Guy','Impact','GillSans-Bold','Arial Black',Tahoma,sans-serif",
	stroke: "#fff",
	strokeThickness: 7,
	dropShadow: true,
	dropShadowColor: "#222",
	dropShadowDistance: 3,
	dropShadowAngle: Math.PI / 2,
	dropShadowBlur: 7
});
backBtnTxt.anchor.set(0.5, 0.5);
backBtnTxt.x = 0;
backBtnTxt.y = 0;
backBtn.addChild(backBtnTxt);
// Position back button below music buttons
backBtn.x = 0;
backBtn.y = musicNames.length * 180 + 80;
musicMenu.addChild(backBtn);
game.addChild(musicMenu);
// How to Play popup (hidden by default)
var howToPlayPopup = new Container();
howToPlayPopup.visible = false;
howToPlayPopup.x = 2048 / 2;
howToPlayPopup.y = 1200;
var popupBg = LK.getAsset('centerCircle', {
	anchorX: 0.5,
	anchorY: 0.5,
	width: 1400,
	height: 900,
	x: 0,
	y: 0
});
howToPlayPopup.addChild(popupBg);
var howToPlayText = new Text2("Tap the falling notes or the correct piano key at the right time to shoot monsters!\n\n" + "- Hit notes before they reach the bottom.\n" + "- Each hit fires a projectile at a monster.\n" + "- Don't let monsters reach you or miss too many notes!\n\n" + "Good luck!", {
	size: 60,
	fill: "#222",
	align: "center",
	wordWrap: true,
	wordWrapWidth: 1200
});
howToPlayText.anchor.set(0.5, 0.5);
howToPlayText.x = 0;
howToPlayText.y = -80;
howToPlayPopup.addChild(howToPlayText);
// Close button for popup
var closePopupBtn = new Container();
var closePopupBg = LK.getAsset('centerCircle', {
	anchorX: 0.5,
	anchorY: 0.5,
	width: 400,
	height: 120,
	x: 0,
	y: 0
});
closePopupBtn.addChild(closePopupBg);
var closePopupTxt = new Text2("Close", {
	size: 70,
	fill: "#222"
});
closePopupTxt.anchor.set(0.5, 0.5);
closePopupTxt.x = 0;
closePopupTxt.y = 0;
closePopupBtn.addChild(closePopupTxt);
closePopupBtn.x = 0;
closePopupBtn.y = 320;
howToPlayPopup.addChild(closePopupBtn);
game.addChild(howToPlayPopup);
// --- Splash screen input handling ---
var splashActive = true;
game.down = function (x, y, obj) {
	if (!splashActive) return;
	// Convert to local coordinates for splash elements
	var localX = x,
		localY = y;
	// Check Choose Music button
	if (localX >= chooseMusicBtn.x - 350 && localX <= chooseMusicBtn.x + 350 && localY >= chooseMusicBtn.y - 90 && localY <= chooseMusicBtn.y + 90) {
		// Show music menu
		musicMenu.visible = true;
		chooseMusicBtn.visible = false;
		howToPlayBtn.visible = false;
		return;
	}
	// Check How to Play button
	if (localX >= howToPlayBtn.x - 350 && localX <= howToPlayBtn.x + 350 && localY >= howToPlayBtn.y - 90 && localY <= howToPlayBtn.y + 90) {
		// Show how to play popup
		howToPlayPopup.visible = true;
		chooseMusicBtn.visible = false;
		howToPlayBtn.visible = false;
		return;
	}
	// Check music menu buttons
	if (musicMenu.visible) {
		// Check music selection buttons
		for (var i = 0; i < musicBtns.length; i++) {
			var btn = musicBtns[i];
			var btnTop = musicMenu.y + btn.y - 70;
			var btnBottom = musicMenu.y + btn.y + 70;
			var btnLeft = musicMenu.x - 300;
			var btnRight = musicMenu.x + 300;
			if (localX >= btnLeft && localX <= btnRight && localY >= btnTop && localY <= btnBottom) {
				// Start game with selected music
				LK.playMusic(btn.musicId);
				// Track which music was selected
				selectedMusicId = btn.musicId;
				// Hide splash elements
				splashBg.visible = false;
				splashTitle.visible = false;
				chooseMusicBtn.visible = false;
				howToPlayBtn.visible = false;
				musicMenu.visible = false;
				howToPlayPopup.visible = false;
				splashActive = false;
				// Show correct background for selected music
				showMainGameBg();
				// Enable main game input
				game.down = mainGameDownHandler;
				return;
			}
		}
		// Check back button
		var backBtnTop = musicMenu.y + musicMenu.children[musicMenu.children.length - 1].y - 60;
		var backBtnBottom = musicMenu.y + musicMenu.children[musicMenu.children.length - 1].y + 60;
		var backBtnLeft = musicMenu.x - 250;
		var backBtnRight = musicMenu.x + 250;
		if (localX >= backBtnLeft && localX <= backBtnRight && localY >= backBtnTop && localY <= backBtnBottom) {
			// Hide music menu, show splash buttons again
			musicMenu.visible = false;
			chooseMusicBtn.visible = true;
			howToPlayBtn.visible = true;
			return;
		}
	}
	// Check close button on how to play popup
	if (howToPlayPopup.visible) {
		var closeBtnTop = howToPlayPopup.y + closePopupBtn.y - 60;
		var closeBtnBottom = howToPlayPopup.y + closePopupBtn.y + 60;
		var closeBtnLeft = howToPlayPopup.x - 200;
		var closeBtnRight = howToPlayPopup.x + 200;
		if (localX >= closeBtnLeft && localX <= closeBtnRight && localY >= closeBtnTop && localY <= closeBtnBottom) {
			howToPlayPopup.visible = false;
			chooseMusicBtn.visible = true;
			howToPlayBtn.visible = true;
			return;
		}
	}
};
// Save the original main game input handler
var mainGameDownHandler = function mainGameDownHandler(x, y, obj) {
	// (Original game.down code will be inserted here by the next block)
};
// --- Add top background asset for main game (hidden until splash is gone) ---
// Default background (Classical Adventure)
var topBg = LK.getAsset('top_bg', {
	anchorX: 0,
	anchorY: 0,
	x: 0,
	y: 0,
	width: 2048,
	height: 1366 // Top half of the screen
});
game.addChild(topBg);
topBg.visible = false;
// Funky Groove background (new asset, must be defined in Assets section)
var funkyBg = LK.getAsset('funky_top_bg', {
	anchorX: 0,
	anchorY: 0,
	x: 0,
	y: 0,
	width: 2048,
	height: 1366
});
game.addChild(funkyBg);
funkyBg.visible = false;
// Epic Battle background (new asset, must be defined in Assets section)
var epicBattleBg = LK.getAsset('epic_battle_bg', {
	anchorX: 0,
	anchorY: 0,
	x: 0,
	y: 0,
	width: 2048,
	height: 1366
});
game.addChild(epicBattleBg);
epicBattleBg.visible = false;
// Track which music is selected
var selectedMusicId = null;
// When splash is dismissed, show main game background
var showMainGameBg = function showMainGameBg() {
	// Show only the correct background
	if (selectedMusicId === "gamemusic2") {
		funkyBg.visible = true;
		topBg.visible = false;
		epicBattleBg.visible = false;
		updateHeroPositionForMusic();
	} else if (selectedMusicId === "gamemusic3") {
		epicBattleBg.visible = true;
		topBg.visible = false;
		funkyBg.visible = false;
		updateHeroPositionForMusic();
	} else {
		topBg.visible = true;
		funkyBg.visible = false;
		epicBattleBg.visible = false;
		updateHeroPositionForMusic();
	}
};
// --- Constants ---
// Tween plugin for note/monster animations
// Bullet asset for weapon fire
// 5 separate heart assets for health (can be different colors for each)
var NUM_KEYS = 5;
// --- Piano and Layout Constants ---
var KEY_WIDTH = Math.floor(2048 / NUM_KEYS); // Each key fills 1/5 of width
var KEY_HEIGHT = Math.floor(2732 / 2); // Keys fill bottom half
var KEY_GAP = 0; // No gap, keys are flush
var KEY_BOTTOM_MARGIN = 0; // No margin, keys reach bottom
var NOTE_SIZE = 210;
var NOTE_BASE_SPEED = 7; // Start slower
var NOTE_MAX_SPEED = 18; // Cap speed (increased for more challenge)
var NOTE_SPEED = NOTE_BASE_SPEED; // Will be updated dynamically
var NOTE_SPAWN_INTERVAL = 60; // frames
var NOTE_SPEEDUP_INTERVAL = 600; // Every 10 seconds at 60fps
var NOTE_SPEEDUP_AMOUNT = 1.2; // Increase by this amount each interval
var MONSTER_SIZE = 180;
var MONSTER_SPEED = 2.5;
var MONSTER_HP = 2;
var MONSTER_SPAWN_INTERVAL = 180; // frames
var PROJECTILE_SIZE = 60;
var PROJECTILE_SPEED = 40;
var MAX_MISSES = 8;
// --- Note density (how many notes at once) ---
var DENSITY_INCREASE_INTERVAL = 1200; // every 20 seconds at 60fps
var MAX_NOTE_DENSITY = Math.min(NUM_KEYS, 4); // never more than number of keys
if (typeof noteDensity === "undefined") {
	var noteDensity = 1;
}
// --- Asset Initialization ---
// --- Game State ---
var pianoKeys = [];
var notes = [];
var monsters = [];
var projectiles = [];
var missCount = 0;
var score = 0;
var lastNoteSpawn = 0;
var lastMonsterSpawn = 0;
// --- Layout Calculations ---
var pianoWidth = NUM_KEYS * KEY_WIDTH + (NUM_KEYS - 1) * KEY_GAP;
var pianoLeft = 0; // Keys start at left edge
var pianoTop = 2732 / 2; // Keys start at vertical center
// --- No divider line: screen is visually split by content only ---
// --- Hero (player) ---
// --- Breathing effect for hero and weapon (in sync) ---
// Move hero and weapon slightly lower only for Funky Groove map
var heroYDefault = 770;
var heroYFunky = 920; // Move down by 150px for Funky Groove
// Move hero and weapon even higher for Funky Groove (very slightly up)
var funkyGrooveYOffset = 18; // move up by 18px more (previously was -80px, now -98px)
var hero = game.addChild(LK.getAsset('hero', {
	anchorX: 0.5,
	anchorY: 0.5,
	x: 400,
	y: heroYDefault
}));
// Add a weapon to hero's lap (bigger and centered for lap position)
var weapon = LK.getAsset('projectile', {
	anchorX: 0.5,
	anchorY: 0.85,
	width: 230,
	height: 120,
	x: hero.x,
	y: hero.y + 90
});
game.addChild(weapon);
// Helper to update hero/weapon Y for Funky Groove
function updateHeroPositionForMusic() {
	if (selectedMusicId === "gamemusic2") {
		hero.y = heroYFunky - 98; // Move up by 98px for Funky Groove (was 80px, now even higher)
		weapon.y = hero.y + 90;
	} else if (selectedMusicId === "gamemusic3") {
		hero.y = heroYDefault - 134; // Move hero up by 4px more for Epic Battle
		weapon.y = hero.y + 90;
	} else {
		hero.y = heroYDefault;
		weapon.y = hero.y + 90;
	}
}
// Call on music select and in game.update to ensure correct position
function startHeroBreathing() {
	// Reset scale to default before starting
	hero.scaleX = 1;
	hero.scaleY = 1;
	weapon.scaleX = 1;
	weapon.scaleY = 1;
	// Helper to tween both hero and weapon together
	function inhale() {
		tween(hero, {
			scaleX: 1.07,
			scaleY: 0.93
		}, {
			duration: 900,
			easing: tween.easeInOut,
			onFinish: function onFinish() {
				tween(hero, {
					scaleX: 1,
					scaleY: 1
				}, {
					duration: 900,
					easing: tween.easeInOut,
					onFinish: inhale
				});
			}
		});
		tween(weapon, {
			scaleX: 1.07,
			scaleY: 0.93
		}, {
			duration: 900,
			easing: tween.easeInOut,
			onFinish: function onFinish() {
				tween(weapon, {
					scaleX: 1,
					scaleY: 1
				}, {
					duration: 900,
					easing: tween.easeInOut
				});
			}
		});
	}
	inhale();
}
startHeroBreathing();
// Keep weapon attached to hero's lap
game.updateWeapon = function () {
	weapon.x = hero.x;
	weapon.y = hero.y + 90;
};
// --- Score Display ---
var scoreTxt = new Text2('0', {
	size: 120,
	fill: "#fff"
});
scoreTxt.anchor.set(0.5, 0);
LK.gui.top.addChild(scoreTxt);
// --- Misses Display ---
var missTxt = new Text2('Misses: 0', {
	size: 70,
	fill: 0xFF6666
});
missTxt.anchor.set(0.5, 0);
LK.gui.top.addChild(missTxt);
missTxt.y = 120;
// --- Piano Keys ---
for (var i = 0; i < NUM_KEYS; i++) {
	var key = new PianoKey();
	key.index = i;
	key.keyWidth = KEY_WIDTH;
	key.keyHeight = KEY_HEIGHT;
	key.assetId = 'key_piano'; // Use key_piano asset for all keys
	key.baseColor = 0xffffff;
	key.x = pianoLeft + i * (KEY_WIDTH + KEY_GAP) + KEY_WIDTH / 2;
	key.y = 2732 - KEY_HEIGHT; // Place keys at the very bottom of the screen
	key.width = KEY_WIDTH;
	key.height = KEY_HEIGHT;
	game.addChild(key);
	pianoKeys.push(key);
}
// --- Input Handling ---
mainGameDownHandler = function mainGameDownHandler(x, y, obj) {
	// Check if a key was pressed
	var keyPressed = false;
	for (var i = 0; i < pianoKeys.length; i++) {
		var key = pianoKeys[i];
		// Key bounds
		var left = key.x - KEY_WIDTH / 2;
		var right = key.x + KEY_WIDTH / 2;
		var top = key.y;
		var bottom = key.y + KEY_HEIGHT;
		if (x >= left && x <= right && y >= top && y <= bottom) {
			key.flash();
			handleKeyPress(i);
			keyPressed = true;
			break;
		}
	}
	// If not on a key, check if a note was tapped
	if (!keyPressed) {
		for (var n = 0; n < notes.length; n++) {
			var note = notes[n];
			if (!note.active) {
				continue;
			}
			// Note bounds
			var noteLeft = note.x - note.noteSize / 2;
			var noteRight = note.x + note.noteSize / 2;
			var noteTop = note.y - note.noteSize / 2;
			var noteBottom = note.y + note.noteSize / 2;
			if (x >= noteLeft && x <= noteRight && y >= noteTop && y <= noteBottom) {
				// Only allow firing if note is above the bottom of its assigned key (not missed yet)
				var key = typeof note.keyIndex !== "undefined" && note.keyIndex >= 0 && note.keyIndex < pianoKeys.length ? pianoKeys[note.keyIndex] : null;
				if (key) {
					var missY = key.y + KEY_HEIGHT + NOTE_SIZE / 2;
					if (note.y < missY) {
						// Fire projectile at nearest monster, scale speed by timing accuracy
						var target = findNearestMonster();
						if (target) {
							// Calculate accuracy: closer to center line = more accurate
							var centerLine = 2732 / 2;
							var maxDist = pianoTop - centerLine;
							var distFromCenter = Math.abs(note.y - centerLine);
							var accuracy = 1 - Math.min(distFromCenter / maxDist, 1); // 1 = perfect, 0 = worst
							var proj = new Projectile();
							proj.size = PROJECTILE_SIZE;
							proj.x = weapon.x;
							proj.y = weapon.y;
							// Scale projectile speed: min 60, max 120
							proj.speed = PROJECTILE_SPEED + Math.floor(accuracy * 60);
							proj.monster = target;
							proj.target = target;
							projectiles.push(proj);
							game.addChild(proj);
							// Animate hero and weapon for shooting
							tween(hero, {
								scaleX: 1.15,
								scaleY: 0.92
							}, {
								duration: 80,
								yoyo: true,
								repeat: 1,
								onFinish: function onFinish() {
									// Restart breathing effect after shooting
									startHeroBreathing();
								}
							});
							// Rotate weapon to point toward the enemy
							var angleToTarget = Math.atan2(target.y - weapon.y, target.x - weapon.x);
							tween(weapon, {
								rotation: angleToTarget
							}, {
								duration: 80,
								yoyo: true,
								repeat: 1
							});
						}
						// Animate note
						note.active = false;
						tween(note, {
							alpha: 0,
							scaleX: 1.5,
							scaleY: 1.5
						}, {
							duration: 120,
							onFinish: function onFinish() {
								note.destroy();
							}
						});
						break;
					}
				}
			}
		}
	}
};
// --- Key Press Logic ---
function handleKeyPress(keyIndex) {
	// Find the first active note for this key that is still in the air (not missed yet)
	var hit = false;
	for (var n = 0; n < notes.length; n++) {
		var note = notes[n];
		if (!note.active) {
			continue;
		}
		if (note.keyIndex !== keyIndex) {
			continue;
		}
		var key = pianoKeys[keyIndex];
		// Only allow hit if note is inside the key bounds (not just above the key)
		var keyTop = key.y;
		var keyBottom = key.y + KEY_HEIGHT;
		var noteTop = note.y - note.noteSize / 2;
		var noteBottom = note.y + note.noteSize / 2;
		// Check if note is at least partially inside the key area
		var insideKey = !(noteBottom < keyTop || noteTop > keyBottom);
		// Rhythm mechanic: Only allow hit if note is visible (not missed, not below key)
		var missY = key.y + KEY_HEIGHT + note.noteSize / 2;
		if (note.y >= missY || !note.active) {
			// Note is no longer visible, or already inactive, so pressing now is a miss
			break;
		}
		if (insideKey) {
			// Play key1 sound when any key is pressed
			LK.getSound('key1').play();
			// Only allow hit if note is still active (not destroyed/missed)
			if (!note.active) {
				continue;
			}
			// Hit!
			note.active = false;
			hit = true;
			score += 1;
			scoreTxt.setText(score);
			// Fire projectile at nearest monster, scale speed by timing accuracy
			var target = findNearestMonster();
			if (target) {
				// Calculate accuracy: closer to center line = more accurate
				var centerLine = 2732 / 2;
				var maxDist = pianoTop - centerLine;
				var distFromCenter = Math.abs(note.y - centerLine);
				var accuracy = 1 - Math.min(distFromCenter / maxDist, 1); // 1 = perfect, 0 = worst
				var proj = new Projectile();
				proj.size = PROJECTILE_SIZE;
				proj.x = weapon.x;
				proj.y = weapon.y;
				// Scale projectile speed: min 60, max 120
				proj.speed = PROJECTILE_SPEED + Math.floor(accuracy * 60);
				proj.monster = target;
				proj.target = target;
				projectiles.push(proj);
				game.addChild(proj);
				// Animate hero and weapon for shooting
				tween(hero, {
					scaleX: 1.15,
					scaleY: 0.92
				}, {
					duration: 80,
					yoyo: true,
					repeat: 1,
					onFinish: function onFinish() {
						// Restart breathing effect after shooting
						startHeroBreathing();
					}
				});
				// Rotate weapon to point toward the enemy
				var angleToTarget = Math.atan2(target.y - weapon.y, target.x - weapon.x);
				tween(weapon, {
					rotation: angleToTarget
				}, {
					duration: 80,
					yoyo: true,
					repeat: 1
				});
			}
			// Animate note
			tween(note, {
				alpha: 0,
				scaleX: 1.5,
				scaleY: 1.5
			}, {
				duration: 120,
				onFinish: function onFinish() {
					note.destroy();
				}
			});
			break;
		}
	}
	if (!hit) {
		// Missed (pressed wrong key, or note is not visible, or note was already destroyed/missed)
		missCount += 1;
		missTxt.setText('Misses: ' + missCount);
		LK.effects.flashObject(hero, 0xff4444, 200);
		checkGameOver();
	}
}
// --- Find Nearest Monster ---
function findNearestMonster() {
	var minDist = 99999;
	var nearest = null;
	for (var i = 0; i < monsters.length; i++) {
		var m = monsters[i];
		if (m.destroyed) {
			continue;
		}
		// Distance from hero to monster
		var dx = m.x - hero.x;
		var dy = m.y - hero.y;
		var dist = Math.sqrt(dx * dx + dy * dy);
		if (dist < minDist) {
			minDist = dist;
			nearest = m;
		}
	}
	return nearest;
}
// --- Game Update Loop ---
game.update = function () {
	// If splash screen is active, hide all main game elements and skip game logic
	if (typeof splashActive !== "undefined" && splashActive) {
		// Hide main game elements
		if (typeof topBg !== "undefined") topBg.visible = false;
		if (typeof hero !== "undefined") hero.visible = false;
		if (typeof weapon !== "undefined") weapon.visible = false;
		if (typeof healthBar !== "undefined" && healthBar) healthBar.visible = false;
		for (var i = 0; i < pianoKeys.length; i++) {
			if (pianoKeys[i]) pianoKeys[i].visible = false;
		}
		for (var i = 0; i < notes.length; i++) {
			if (notes[i]) notes[i].visible = false;
		}
		for (var i = 0; i < monsters.length; i++) {
			if (monsters[i]) monsters[i].visible = false;
		}
		for (var i = 0; i < projectiles.length; i++) {
			if (projectiles[i]) projectiles[i].visible = false;
		}
		if (typeof scoreTxt !== "undefined") scoreTxt.visible = false;
		if (typeof missTxt !== "undefined") missTxt.visible = false;
		return;
	} else {
		// Show main game elements when splash is gone
		if (typeof showMainGameBg === "function") showMainGameBg();
		if (typeof hero !== "undefined") hero.visible = true;
		if (typeof weapon !== "undefined") weapon.visible = true;
		if (typeof healthBar !== "undefined" && healthBar) healthBar.visible = true;
		for (var i = 0; i < pianoKeys.length; i++) {
			if (pianoKeys[i]) pianoKeys[i].visible = true;
		}
		for (var i = 0; i < notes.length; i++) {
			if (notes[i]) notes[i].visible = true;
		}
		for (var i = 0; i < monsters.length; i++) {
			if (monsters[i]) monsters[i].visible = true;
		}
		for (var i = 0; i < projectiles.length; i++) {
			if (projectiles[i]) projectiles[i].visible = true;
		}
		if (typeof scoreTxt !== "undefined") scoreTxt.visible = true;
		if (typeof missTxt !== "undefined") missTxt.visible = true;
	}
	// Gradually speed up notes and monsters every NOTE_SPEEDUP_INTERVAL frames, up to max
	if (LK.ticks % NOTE_SPEEDUP_INTERVAL === 0 && LK.ticks > 0) {
		NOTE_SPEED = Math.min(NOTE_MAX_SPEED, NOTE_SPEED + NOTE_SPEEDUP_AMOUNT);
		// Cap monster speed at a separate, reasonable maximum
		var MONSTER_MAX_SPEED = 8; // Set a reasonable cap for monster speed
		// Also increase speed of all future monsters (and update current monsters to match)
		for (var i = 0; i < notes.length; i++) {
			notes[i].speed = NOTE_SPEED;
		}
		for (var j = 0; j < monsters.length; j++) {
			// Only update monsters that are not in attack range (so they don't "jump" while attacking)
			if (!monsters[j].destroyed && typeof monsters[j].dirX === "number" && typeof monsters[j].dirY === "number") {
				monsters[j].speed = Math.min(MONSTER_MAX_SPEED, NOTE_SPEED);
			}
		}
	}
	// --- DENSITY CONTROL ---
	// Difficulty variables
	if (typeof noteDensity === "undefined") noteDensity = 1;
	if (typeof noteScatter === "undefined") noteScatter = 0;
	if (typeof noteScatterMax === "undefined") noteScatterMax = 120; // max px scatter
	if (typeof noteScatterStep === "undefined") noteScatterStep = 12; // how much scatter increases per interval
	// Gradually increase note density and scatter, but very slowly
	if (LK.ticks % (DENSITY_INCREASE_INTERVAL * 2) === 0 && LK.ticks > 0) {
		// Only increase density if not at max, and only after a long time
		if (noteDensity < MAX_NOTE_DENSITY) {
			noteDensity += 1;
		} else if (noteScatter < noteScatterMax) {
			noteScatter = Math.min(noteScatterMax, noteScatter + noteScatterStep);
		}
	}
	// Spawn notes and corresponding monsters (enemies) in sync
	if (LK.ticks - lastNoteSpawn >= NOTE_SPAWN_INTERVAL) {
		lastNoteSpawn = LK.ticks;
		// Decide how many notes to spawn: mostly 1, but as density increases, sometimes more
		var spawnCount = 1;
		if (noteDensity > 1) {
			// As density increases, increase chance to spawn more than 1 note
			var chance = Math.random();
			if (chance < 0.25 * (noteDensity - 1)) spawnCount = 2;
			if (noteDensity > 2 && chance < 0.10 * (noteDensity - 1)) spawnCount = 3;
			if (noteDensity > 3 && chance < 0.04 * (noteDensity - 1)) spawnCount = 4;
			spawnCount = Math.min(noteDensity, spawnCount);
		}
		// Pick random keys to spawn notes on, never duplicate keys in one spawn
		var availableKeys = [];
		for (var i = 0; i < NUM_KEYS; i++) {
			availableKeys.push(i);
		}
		// Shuffle availableKeys
		for (var i = availableKeys.length - 1; i > 0; i--) {
			var j = Math.floor(Math.random() * (i + 1));
			var temp = availableKeys[i];
			availableKeys[i] = availableKeys[j];
			availableKeys[j] = temp;
		}
		for (var d = 0; d < spawnCount; d++) {
			if (availableKeys.length === 0) break;
			var keyIdx = availableKeys.pop();
			// Create note
			var note = new Note();
			note.index = keyIdx;
			note.noteSize = NOTE_SIZE;
			// Assign note to a random key
			var key = pianoKeys[note.index];
			note.keyIndex = note.index;
			// Start notes at the center line, horizontally aligned with their key
			note.x = key.x;
			// Add scatter as difficulty increases (notes start at slightly different Y)
			var scatterY = 0;
			if (noteScatter > 0) {
				scatterY = Math.floor((Math.random() - 0.5) * noteScatter);
			}
			note.y = 2732 / 2 - NOTE_SIZE / 2 + scatterY;
			note.speed = NOTE_SPEED;
			note.active = true;
			notes.push(note);
			game.addChild(note);
			// Create corresponding monster (enemy) for this note
			var monster;
			if (selectedMusicId === "gamemusic2") {
				monster = new Monster2();
			} else if (selectedMusicId === "gamemusic3") {
				monster = new Monster3();
			} else {
				monster = new Monster();
			}
			monster.monsterSize = MONSTER_SIZE;
			// Spawn at the top right of the upper half of the screen
			monster.x = 2048 - MONSTER_SIZE / 2 - 40; // right margin, with a little padding
			monster.y = 220 + Math.random() * (2732 / 2 - 220 - MONSTER_SIZE); // random Y in upper half, not below center
			// Monster speed matches note speed, but is capped
			var MONSTER_MAX_SPEED = 8;
			monster.speed = Math.min(MONSTER_MAX_SPEED, note.speed);
			monster.maxHp = MONSTER_HP;
			monster.hp = MONSTER_HP;
			monster.baseColor = 0x8e44ad;
			monster.destroyed = false;
			// Calculate direction vector: from spawn point toward hero
			var dx = hero.x - monster.x;
			var dy = hero.y - monster.y;
			var dist = Math.sqrt(dx * dx + dy * dy);
			monster.dirX = dx / dist;
			monster.dirY = dy / dist;
			// Link monster to note and note to monster for removal
			note.linkedMonster = monster;
			monster.linkedNote = note;
			monsters.push(monster);
			game.addChild(monster);
		}
	}
	// Update notes
	for (var i = notes.length - 1; i >= 0; i--) {
		var note = notes[i];
		if (note && typeof note.update === "function") {
			note.update();
		}
		// Remove destroyed/inactive notes
		if (!note || !note.active || !note.parent || note.alpha === 0) {
			if (note && typeof note.destroy === "function" && note.parent) {
				note.destroy();
			}
			notes.splice(i, 1);
		} else if (typeof note.keyIndex === "undefined" || note.keyIndex < 0 || note.keyIndex >= pianoKeys.length) {
			if (note && typeof note.destroy === "function" && note.parent) {
				note.destroy();
			}
			notes.splice(i, 1);
		}
	}
	// Update projectiles
	for (var i = projectiles.length - 1; i >= 0; i--) {
		var p = projectiles[i];
		if (p && typeof p.update === "function") {
			p.update();
		}
		if (!p || !p.parent || p.alpha === 0) {
			if (p && typeof p.destroy === "function" && p.parent) {
				p.destroy();
			}
			projectiles.splice(i, 1);
		}
	}
	// Update monsters and clean up destroyed ones
	for (var i = monsters.length - 1; i >= 0; i--) {
		var m = monsters[i];
		if (m && typeof m.update === "function") {
			m.update();
		}
		if (!m || m.destroyed && (!m.parent || m.alpha === 0)) {
			if (m && typeof m.destroy === "function" && m.parent) {
				m.destroy();
			}
			monsters.splice(i, 1);
		}
	}
	// Defensive: Full cleanup for any orphaned/destroyed objects (extra safety, every 120 frames)
	if (LK.ticks % 120 === 0) {
		for (var i = notes.length - 1; i >= 0; i--) {
			var note = notes[i];
			if (!note || !note.parent || note.alpha === 0) {
				if (note && typeof note.destroy === "function" && note.parent) {
					note.destroy();
				}
				notes.splice(i, 1);
			}
		}
		for (var i = monsters.length - 1; i >= 0; i--) {
			var m = monsters[i];
			if (!m || !m.parent || m.alpha === 0) {
				if (m && typeof m.destroy === "function" && m.parent) {
					m.destroy();
				}
				monsters.splice(i, 1);
			}
		}
		for (var i = projectiles.length - 1; i >= 0; i--) {
			var p = projectiles[i];
			if (!p || !p.parent || p.alpha === 0) {
				if (p && typeof p.destroy === "function" && p.parent) {
					p.destroy();
				}
				projectiles.splice(i, 1);
			}
		}
	}
	// (Hero health and monster attack logic removed)
	// Update weapon position to follow hero
	if (typeof updateHeroPositionForMusic === "function") {
		updateHeroPositionForMusic();
	}
	if (typeof game.updateWeapon === "function") {
		game.updateWeapon();
	}
};
// --- Game Over Check ---
function checkGameOver() {
	if (missCount >= MAX_MISSES) {
		LK.effects.flashScreen(0xff0000, 800);
		LK.showGameOver();
		// Clean up all notes, monsters, and projectiles to prevent buildup
		for (var i = notes.length - 1; i >= 0; i--) {
			if (notes[i] && typeof notes[i].destroy === "function" && notes[i].parent) {
				notes[i].destroy();
			}
			notes.splice(i, 1);
		}
		for (var i = monsters.length - 1; i >= 0; i--) {
			if (monsters[i] && typeof monsters[i].destroy === "function" && monsters[i].parent) {
				monsters[i].destroy();
			}
			monsters.splice(i, 1);
		}
		for (var i = projectiles.length - 1; i >= 0; i--) {
			if (projectiles[i] && typeof projectiles[i].destroy === "function" && projectiles[i].parent) {
				projectiles[i].destroy();
			}
			projectiles.splice(i, 1);
		}
		// Defensive: Reset arrays to empty to ensure no lingering references
		notes = [];
		monsters = [];
		projectiles = [];
	}
} /**** 
* Plugins
****/ 
var tween = LK.import("@upit/tween.v1");
/**** 
* Classes
****/ 
// --- Win Condition (Optional: e.g. score 30) ---
/*
if (score >= 30) {
		LK.showYouWin();
}
*/
// --- End of File ---
// Monster: Enemy advancing from the top
var Monster = Container.expand(function () {
	var self = Container.call(this);
	// Attach monster asset (box/ellipse)
	var monsterAsset = self.attachAsset('monster', {
		anchorX: 0.5,
		anchorY: 0.5,
		width: self.monsterSize,
		height: self.monsterSize
	});
	// Health points
	self.hp = self.maxHp;
	// Called every tick
	self.update = function () {
		// Monsters only move forward if not destroyed
		if (!self.destroyed) {
			// Move toward hero using direction vector if set
			if (typeof self.dirX === "number" && typeof self.dirY === "number") {
				self.x += self.dirX * self.speed;
				self.y += self.dirY * self.speed;
			} else {
				// fallback: move down
				self.y += self.speed;
			}
		}
	};
	// --- Flying effect: gentle up/down hover using tween ---
	function startFlyingEffect() {
		// Reset to default before starting
		self.yOffset = 0;
		// Animate up
		tween(self, {
			yOffset: -18
		}, {
			duration: 420 + Math.random() * 120,
			easing: tween.easeInOut,
			onUpdate: function onUpdate() {
				// Apply yOffset to monster position
				self.y += self.yOffset - (self._lastYOffset || 0);
				self._lastYOffset = self.yOffset;
			},
			onFinish: function onFinish() {
				// Animate down
				tween(self, {
					yOffset: 18
				}, {
					duration: 420 + Math.random() * 120,
					easing: tween.easeInOut,
					onUpdate: function onUpdate() {
						self.y += self.yOffset - (self._lastYOffset || 0);
						self._lastYOffset = self.yOffset;
					},
					onFinish: function onFinish() {
						startFlyingEffect();
					}
				});
			}
		});
	}
	startFlyingEffect();
	// Take damage
	self.hit = function () {
		self.hp -= 1;
		if (self.hp <= 0) {
			self.destroyed = true;
			// Play monster dead sound
			LK.getSound('monsterdead').play();
			// Animate scale up and fade out for death effect
			tween(self, {
				alpha: 0,
				scaleX: 1.7,
				scaleY: 1.7
			}, {
				duration: 220,
				onFinish: function onFinish() {
					self.destroy();
				}
			});
		} else {
			// Flash red
			tween(monsterAsset, {
				tint: 0xff4444
			}, {
				duration: 80,
				onFinish: function onFinish() {
					tween(monsterAsset, {
						tint: self.baseColor
					}, {
						duration: 120
					});
				}
			});
		}
	};
	return self;
});
// Monster2: Funky Groove special monster
var Monster2 = Container.expand(function () {
	var self = Container.call(this);
	// Attach monster2 asset
	var monsterAsset = self.attachAsset('monster2', {
		anchorX: 0.5,
		anchorY: 0.5,
		width: self.monsterSize,
		height: self.monsterSize
	});
	// Health points
	self.hp = self.maxHp;
	// Called every tick
	self.update = function () {
		if (!self.destroyed) {
			if (typeof self.dirX === "number" && typeof self.dirY === "number") {
				self.x += self.dirX * self.speed;
				self.y += self.dirY * self.speed;
			} else {
				self.y += self.speed;
			}
		}
	};
	// --- Flying effect: gentle up/down hover using tween ---
	function startFlyingEffect() {
		self.yOffset = 0;
		tween(self, {
			yOffset: -18
		}, {
			duration: 420 + Math.random() * 120,
			easing: tween.easeInOut,
			onUpdate: function onUpdate() {
				self.y += self.yOffset - (self._lastYOffset || 0);
				self._lastYOffset = self.yOffset;
			},
			onFinish: function onFinish() {
				tween(self, {
					yOffset: 18
				}, {
					duration: 420 + Math.random() * 120,
					easing: tween.easeInOut,
					onUpdate: function onUpdate() {
						self.y += self.yOffset - (self._lastYOffset || 0);
						self._lastYOffset = self.yOffset;
					},
					onFinish: function onFinish() {
						startFlyingEffect();
					}
				});
			}
		});
	}
	startFlyingEffect();
	// Take damage
	self.hit = function () {
		self.hp -= 1;
		if (self.hp <= 0) {
			self.destroyed = true;
			// Play monsterdead2 sound for Funky Groove monsters
			LK.getSound('monsterdead2').play();
			tween(self, {
				alpha: 0,
				scaleX: 1.7,
				scaleY: 1.7
			}, {
				duration: 220,
				onFinish: function onFinish() {
					self.destroy();
				}
			});
		} else {
			// Flash red
			tween(monsterAsset, {
				tint: 0xff4444
			}, {
				duration: 80,
				onFinish: function onFinish() {
					tween(monsterAsset, {
						tint: self.baseColor
					}, {
						duration: 120
					});
				}
			});
		}
	};
	return self;
});
// Monster3: Majestic Mountains special monster
var Monster3 = Container.expand(function () {
	var self = Container.call(this);
	// Attach monster3 asset
	var monsterAsset = self.attachAsset('monster3', {
		anchorX: 0.5,
		anchorY: 0.5,
		width: self.monsterSize,
		height: self.monsterSize
	});
	// Health points
	self.hp = self.maxHp;
	// Called every tick
	self.update = function () {
		if (!self.destroyed) {
			if (typeof self.dirX === "number" && typeof self.dirY === "number") {
				self.x += self.dirX * self.speed;
				self.y += self.dirY * self.speed;
			} else {
				self.y += self.speed;
			}
		}
	};
	// --- Flying effect: gentle up/down hover using tween ---
	function startFlyingEffect() {
		self.yOffset = 0;
		tween(self, {
			yOffset: -18
		}, {
			duration: 420 + Math.random() * 120,
			easing: tween.easeInOut,
			onUpdate: function onUpdate() {
				self.y += self.yOffset - (self._lastYOffset || 0);
				self._lastYOffset = self.yOffset;
			},
			onFinish: function onFinish() {
				tween(self, {
					yOffset: 18
				}, {
					duration: 420 + Math.random() * 120,
					easing: tween.easeInOut,
					onUpdate: function onUpdate() {
						self.y += self.yOffset - (self._lastYOffset || 0);
						self._lastYOffset = self.yOffset;
					},
					onFinish: function onFinish() {
						startFlyingEffect();
					}
				});
			}
		});
	}
	startFlyingEffect();
	// Take damage
	self.hit = function () {
		self.hp -= 1;
		if (self.hp <= 0) {
			self.destroyed = true;
			// Play monsterdead3 sound for Majestic Mountains monsters
			LK.getSound('monsterdead3').play();
			tween(self, {
				alpha: 0,
				scaleX: 1.7,
				scaleY: 1.7
			}, {
				duration: 220,
				onFinish: function onFinish() {
					self.destroy();
				}
			});
		} else {
			// Flash red
			tween(monsterAsset, {
				tint: 0xff4444
			}, {
				duration: 80,
				onFinish: function onFinish() {
					tween(monsterAsset, {
						tint: self.baseColor
					}, {
						duration: 120
					});
				}
			});
		}
	};
	return self;
});
// Note: Falling note that must be hit in time
var Note = Container.expand(function () {
	var self = Container.call(this);
	// Pick a random note asset for this note
	var noteAssetId = 'note' + (1 + Math.floor(Math.random() * 4));
	self.noteAssetId = noteAssetId;
	var noteAsset = self.attachAsset(noteAssetId, {
		anchorX: 0.5,
		anchorY: 0.5,
		width: self.noteSize,
		height: self.noteSize
	});
	// Index of the key this note targets
	self.keyIndex = typeof self.keyIndex !== "undefined" ? self.keyIndex : self.index;
	// Used for hit/miss detection
	self.active = true;
	// Called every tick
	self.update = function () {
		// Notes always fall straight down toward their assigned key
		self.y += self.speed;
		// Find the key this note is assigned to
		var key = typeof self.keyIndex !== "undefined" && self.keyIndex >= 0 && self.keyIndex < NUM_KEYS ? pianoKeys[self.keyIndex] : null;
		if (key) {
			var missY = key.y + KEY_HEIGHT + self.noteSize / 2;
			// If note crosses the bottom boundary and is still active, mark as miss and destroy
			if (self.y > missY && self.active) {
				self.active = false;
				// Register miss
				missCount += 1;
				missTxt.setText('Misses: ' + missCount);
				LK.effects.flashObject(hero, 0xff4444, 200);
				checkGameOver();
				self.destroy();
			}
		} else {
			// Defensive: If key is missing, just destroy the note
			self.destroy();
		}
	};
	return self;
});
// PianoKey: Represents a single piano key at the bottom
var PianoKey = Container.expand(function () {
	var self = Container.call(this);
	// Defensive: Set defaults if not set
	if (typeof self.assetId === "undefined") {
		self.assetId = 'key_piano';
	}
	if (typeof self.keyWidth === "undefined") {
		self.keyWidth = KEY_WIDTH;
	}
	if (typeof self.keyHeight === "undefined") {
		self.keyHeight = KEY_HEIGHT;
	}
	if (typeof self.baseColor === "undefined") {
		self.baseColor = 0xffffff;
	}
	if (typeof self.index === "undefined") {
		self.index = 0;
	}
	// Attach key asset (always key_piano)
	var keyAsset = self.attachAsset(self.assetId, {
		anchorX: 0.5,
		anchorY: 0,
		width: self.keyWidth,
		height: self.keyHeight
	});
	// Store index for reference
	self.keyIndex = self.index;
	// Set initial dim state
	keyAsset.alpha = 0.45;
	// Visual feedback for press
	self.flash = function () {
		// Light up key
		tween(keyAsset, {
			alpha: 1
		}, {
			duration: 60,
			onFinish: function onFinish() {
				// Return to dim after a short time
				tween(keyAsset, {
					alpha: 0.45
				}, {
					duration: 120
				});
			}
		});
	};
	return self;
});
// Projectile: Fired by hero toward a monster
var Projectile = Container.expand(function () {
	var self = Container.call(this);
	// Defensive: Set defaults if not set
	if (typeof self.size === "undefined") {
		self.size = PROJECTILE_SIZE;
	}
	if (typeof self.speed === "undefined") {
		self.speed = PROJECTILE_SPEED;
	}
	// Pick a random bullet asset for this projectile
	var bulletAssetIds = ['bullet', 'bullet2', 'bullet3', 'bullet4'];
	var chosenBulletAsset = bulletAssetIds[Math.floor(Math.random() * bulletAssetIds.length)];
	// Attach bullet asset
	var projAsset = self.attachAsset(chosenBulletAsset, {
		anchorX: 0.5,
		anchorY: 0.5,
		width: self.size,
		height: self.size
	});
	// Target monster (set externally)
	self.target = null;
	// Called every tick
	self.update = function () {
		// If no target or target destroyed, fade out and destroy
		if (!self.target || self.target.destroyed || !self.target.parent) {
			tween(self, {
				alpha: 0,
				scaleX: 1.5,
				scaleY: 1.5
			}, {
				duration: 120,
				onFinish: function onFinish() {
					self.destroy();
				}
			});
			return;
		}
		// Move toward target
		var dx = self.target.x - self.x;
		var dy = self.target.y - self.y;
		var dist = Math.sqrt(dx * dx + dy * dy);
		if (dist < self.speed) {
			// Arrived at target: hit!
			if (typeof self.target.hit === "function") {
				self.target.hit();
			}
			// Impact effect
			tween(self, {
				alpha: 0,
				scaleX: 1.7,
				scaleY: 1.7
			}, {
				duration: 120,
				onFinish: function onFinish() {
					self.destroy();
				}
			});
			return;
		}
		// Move toward target
		self.x += dx / dist * self.speed;
		self.y += dy / dist * self.speed;
	};
	return self;
});
/**** 
* Initialize Game
****/ 
var game = new LK.Game({
	backgroundColor: 0x181830
});
/**** 
* Game Code
****/ 
// Create splash background asset (full screen, custom color or image)
// --- SPLASH SCREEN LOGIC ---
// Funky Groove top background (separate from splash and other screens)
var splashBg = LK.getAsset('entry_bg', {
	anchorX: 0,
	anchorY: 0,
	x: 0,
	y: 0,
	width: 2048,
	height: 2732
});
game.addChild(splashBg);
// Title text
var splashTitle = new Text2("Melody Mayhem", {
	size: 210,
	fill: 0xFFE600,
	font: "'Impact','GillSans-Bold','Arial Black',Tahoma,sans-serif",
	stroke: "#222",
	strokeThickness: 16,
	dropShadow: true,
	dropShadowColor: "#000",
	dropShadowDistance: 8,
	dropShadowAngle: Math.PI / 2,
	dropShadowBlur: 8
});
// Move splash title and buttons to the bottom of the screen
splashTitle.anchor.set(0.5, 1);
splashTitle.x = 2048 / 2;
splashTitle.y = 2732 - 420;
game.addChild(splashTitle);
// "Choose The Music" button
var chooseMusicBtn = new Container();
var chooseMusicBg = LK.getAsset('centerCircle', {
	anchorX: 0.5,
	anchorY: 0.5,
	width: 700,
	height: 180,
	x: 0,
	y: 0
});
chooseMusicBtn.addChild(chooseMusicBg);
var chooseMusicTxt = new Text2("Choose The Music", {
	size: 82,
	fill: ["#FF5F6D", "#FFC371", "#43E97B", "#38F9D7"],
	// gradient-like array for color pop
	font: "'Comic Sans MS','Luckiest Guy','Impact','GillSans-Bold','Arial Black',Tahoma,sans-serif",
	stroke: "#fff",
	strokeThickness: 7,
	dropShadow: true,
	dropShadowColor: "#222",
	dropShadowDistance: 3,
	dropShadowAngle: Math.PI / 2,
	dropShadowBlur: 7
});
chooseMusicTxt.anchor.set(0.5, 0.5);
chooseMusicTxt.x = 0;
chooseMusicTxt.y = 0;
chooseMusicBtn.addChild(chooseMusicTxt);
// "How to Play" button
var howToPlayBtn = new Container();
var howToPlayBg = LK.getAsset('centerCircle', {
	anchorX: 0.5,
	anchorY: 0.5,
	width: 700,
	height: 180,
	x: 0,
	y: 0
});
howToPlayBtn.addChild(howToPlayBg);
var howToPlayTxt = new Text2("How to Play", {
	size: 82,
	fill: ["#43E97B", "#38F9D7", "#FF5F6D", "#FFC371"],
	// gradient-like array for color pop
	font: "'Comic Sans MS','Luckiest Guy','Impact','GillSans-Bold','Arial Black',Tahoma,sans-serif",
	stroke: "#fff",
	strokeThickness: 7,
	dropShadow: true,
	dropShadowColor: "#222",
	dropShadowDistance: 3,
	dropShadowAngle: Math.PI / 2,
	dropShadowBlur: 7
});
howToPlayTxt.anchor.set(0.5, 0.5);
howToPlayTxt.x = 0;
howToPlayTxt.y = 0;
howToPlayBtn.addChild(howToPlayTxt);
// Position both buttons side by side, centered horizontally at the bottom
var buttonSpacing = 80; // space between buttons
var buttonY = 2732 - 180; // bottom margin, same for both
var buttonTotalWidth = 700 * 2 + buttonSpacing;
var leftBtnX = 2048 / 2 - (700 / 2 + buttonSpacing / 2);
var rightBtnX = 2048 / 2 + (700 / 2 + buttonSpacing / 2);
chooseMusicBtn.x = leftBtnX;
chooseMusicBtn.y = buttonY;
howToPlayBtn.x = rightBtnX;
howToPlayBtn.y = buttonY;
game.addChild(chooseMusicBtn);
game.addChild(howToPlayBtn);
// Music selection menu (hidden by default)
var musicMenu = new Container();
musicMenu.visible = false;
musicMenu.x = 2048 / 2;
musicMenu.y = 1200;
var musicNames = [{
	id: "gamemusic",
	label: "Cyber : 2099",
	fill: ["#00F0FF", "#FF00C8", "#00FF85"] // Vibrant neon
}, {
	id: "gamemusic2",
	label: "Welcome to Hell",
	fill: ["#FF2D00", "#FFB800", "#FF00A8"] // Hot, fiery
}, {
	id: "gamemusic3",
	label: "Majestic Mountains",
	fill: ["#00FFB2", "#00B2FF", "#FFFA00"] // Lively, fresh
}];
var musicBtns = [];
for (var i = 0; i < musicNames.length; i++) {
	var btn = new Container();
	var btnBg = LK.getAsset('centerCircle', {
		anchorX: 0.5,
		anchorY: 0.5,
		width: 820,
		// wider for long names
		height: 150,
		// slightly taller for better fit
		x: 0,
		y: 0
	});
	btn.addChild(btnBg);
	var btnTxt = new Text2(musicNames[i].label, {
		size: 66,
		// smaller font to fit long names
		fill: musicNames[i].fill,
		font: "'Comic Sans MS','Luckiest Guy','Impact','GillSans-Bold','Arial Black',Tahoma,sans-serif",
		stroke: "#fff",
		strokeThickness: 8,
		dropShadow: true,
		dropShadowColor: "#000",
		dropShadowDistance: 4,
		dropShadowAngle: Math.PI / 2,
		dropShadowBlur: 8
	});
	btnTxt.anchor.set(0.5, 0.5);
	btnTxt.x = 0;
	btnTxt.y = 0;
	btn.addChild(btnTxt);
	btn.x = 0;
	btn.y = i * 180;
	btn.musicId = musicNames[i].id;
	musicBtns.push(btn);
	musicMenu.addChild(btn);
}
// Add a back button to the music menu
var backBtn = new Container();
var backBtnBg = LK.getAsset('centerCircle', {
	anchorX: 0.5,
	anchorY: 0.5,
	width: 500,
	height: 120,
	x: 0,
	y: 0
});
backBtn.addChild(backBtnBg);
var backBtnTxt = new Text2("Back", {
	size: 70,
	fill: ["#FF5F6D", "#43E97B"],
	font: "'Comic Sans MS','Luckiest Guy','Impact','GillSans-Bold','Arial Black',Tahoma,sans-serif",
	stroke: "#fff",
	strokeThickness: 7,
	dropShadow: true,
	dropShadowColor: "#222",
	dropShadowDistance: 3,
	dropShadowAngle: Math.PI / 2,
	dropShadowBlur: 7
});
backBtnTxt.anchor.set(0.5, 0.5);
backBtnTxt.x = 0;
backBtnTxt.y = 0;
backBtn.addChild(backBtnTxt);
// Position back button below music buttons
backBtn.x = 0;
backBtn.y = musicNames.length * 180 + 80;
musicMenu.addChild(backBtn);
game.addChild(musicMenu);
// How to Play popup (hidden by default)
var howToPlayPopup = new Container();
howToPlayPopup.visible = false;
howToPlayPopup.x = 2048 / 2;
howToPlayPopup.y = 1200;
var popupBg = LK.getAsset('centerCircle', {
	anchorX: 0.5,
	anchorY: 0.5,
	width: 1400,
	height: 900,
	x: 0,
	y: 0
});
howToPlayPopup.addChild(popupBg);
var howToPlayText = new Text2("Tap the falling notes or the correct piano key at the right time to shoot monsters!\n\n" + "- Hit notes before they reach the bottom.\n" + "- Each hit fires a projectile at a monster.\n" + "- Don't let monsters reach you or miss too many notes!\n\n" + "Good luck!", {
	size: 60,
	fill: "#222",
	align: "center",
	wordWrap: true,
	wordWrapWidth: 1200
});
howToPlayText.anchor.set(0.5, 0.5);
howToPlayText.x = 0;
howToPlayText.y = -80;
howToPlayPopup.addChild(howToPlayText);
// Close button for popup
var closePopupBtn = new Container();
var closePopupBg = LK.getAsset('centerCircle', {
	anchorX: 0.5,
	anchorY: 0.5,
	width: 400,
	height: 120,
	x: 0,
	y: 0
});
closePopupBtn.addChild(closePopupBg);
var closePopupTxt = new Text2("Close", {
	size: 70,
	fill: "#222"
});
closePopupTxt.anchor.set(0.5, 0.5);
closePopupTxt.x = 0;
closePopupTxt.y = 0;
closePopupBtn.addChild(closePopupTxt);
closePopupBtn.x = 0;
closePopupBtn.y = 320;
howToPlayPopup.addChild(closePopupBtn);
game.addChild(howToPlayPopup);
// --- Splash screen input handling ---
var splashActive = true;
game.down = function (x, y, obj) {
	if (!splashActive) return;
	// Convert to local coordinates for splash elements
	var localX = x,
		localY = y;
	// Check Choose Music button
	if (localX >= chooseMusicBtn.x - 350 && localX <= chooseMusicBtn.x + 350 && localY >= chooseMusicBtn.y - 90 && localY <= chooseMusicBtn.y + 90) {
		// Show music menu
		musicMenu.visible = true;
		chooseMusicBtn.visible = false;
		howToPlayBtn.visible = false;
		return;
	}
	// Check How to Play button
	if (localX >= howToPlayBtn.x - 350 && localX <= howToPlayBtn.x + 350 && localY >= howToPlayBtn.y - 90 && localY <= howToPlayBtn.y + 90) {
		// Show how to play popup
		howToPlayPopup.visible = true;
		chooseMusicBtn.visible = false;
		howToPlayBtn.visible = false;
		return;
	}
	// Check music menu buttons
	if (musicMenu.visible) {
		// Check music selection buttons
		for (var i = 0; i < musicBtns.length; i++) {
			var btn = musicBtns[i];
			var btnTop = musicMenu.y + btn.y - 70;
			var btnBottom = musicMenu.y + btn.y + 70;
			var btnLeft = musicMenu.x - 300;
			var btnRight = musicMenu.x + 300;
			if (localX >= btnLeft && localX <= btnRight && localY >= btnTop && localY <= btnBottom) {
				// Start game with selected music
				LK.playMusic(btn.musicId);
				// Track which music was selected
				selectedMusicId = btn.musicId;
				// Hide splash elements
				splashBg.visible = false;
				splashTitle.visible = false;
				chooseMusicBtn.visible = false;
				howToPlayBtn.visible = false;
				musicMenu.visible = false;
				howToPlayPopup.visible = false;
				splashActive = false;
				// Show correct background for selected music
				showMainGameBg();
				// Enable main game input
				game.down = mainGameDownHandler;
				return;
			}
		}
		// Check back button
		var backBtnTop = musicMenu.y + musicMenu.children[musicMenu.children.length - 1].y - 60;
		var backBtnBottom = musicMenu.y + musicMenu.children[musicMenu.children.length - 1].y + 60;
		var backBtnLeft = musicMenu.x - 250;
		var backBtnRight = musicMenu.x + 250;
		if (localX >= backBtnLeft && localX <= backBtnRight && localY >= backBtnTop && localY <= backBtnBottom) {
			// Hide music menu, show splash buttons again
			musicMenu.visible = false;
			chooseMusicBtn.visible = true;
			howToPlayBtn.visible = true;
			return;
		}
	}
	// Check close button on how to play popup
	if (howToPlayPopup.visible) {
		var closeBtnTop = howToPlayPopup.y + closePopupBtn.y - 60;
		var closeBtnBottom = howToPlayPopup.y + closePopupBtn.y + 60;
		var closeBtnLeft = howToPlayPopup.x - 200;
		var closeBtnRight = howToPlayPopup.x + 200;
		if (localX >= closeBtnLeft && localX <= closeBtnRight && localY >= closeBtnTop && localY <= closeBtnBottom) {
			howToPlayPopup.visible = false;
			chooseMusicBtn.visible = true;
			howToPlayBtn.visible = true;
			return;
		}
	}
};
// Save the original main game input handler
var mainGameDownHandler = function mainGameDownHandler(x, y, obj) {
	// (Original game.down code will be inserted here by the next block)
};
// --- Add top background asset for main game (hidden until splash is gone) ---
// Default background (Classical Adventure)
var topBg = LK.getAsset('top_bg', {
	anchorX: 0,
	anchorY: 0,
	x: 0,
	y: 0,
	width: 2048,
	height: 1366 // Top half of the screen
});
game.addChild(topBg);
topBg.visible = false;
// Funky Groove background (new asset, must be defined in Assets section)
var funkyBg = LK.getAsset('funky_top_bg', {
	anchorX: 0,
	anchorY: 0,
	x: 0,
	y: 0,
	width: 2048,
	height: 1366
});
game.addChild(funkyBg);
funkyBg.visible = false;
// Epic Battle background (new asset, must be defined in Assets section)
var epicBattleBg = LK.getAsset('epic_battle_bg', {
	anchorX: 0,
	anchorY: 0,
	x: 0,
	y: 0,
	width: 2048,
	height: 1366
});
game.addChild(epicBattleBg);
epicBattleBg.visible = false;
// Track which music is selected
var selectedMusicId = null;
// When splash is dismissed, show main game background
var showMainGameBg = function showMainGameBg() {
	// Show only the correct background
	if (selectedMusicId === "gamemusic2") {
		funkyBg.visible = true;
		topBg.visible = false;
		epicBattleBg.visible = false;
		updateHeroPositionForMusic();
	} else if (selectedMusicId === "gamemusic3") {
		epicBattleBg.visible = true;
		topBg.visible = false;
		funkyBg.visible = false;
		updateHeroPositionForMusic();
	} else {
		topBg.visible = true;
		funkyBg.visible = false;
		epicBattleBg.visible = false;
		updateHeroPositionForMusic();
	}
};
// --- Constants ---
// Tween plugin for note/monster animations
// Bullet asset for weapon fire
// 5 separate heart assets for health (can be different colors for each)
var NUM_KEYS = 5;
// --- Piano and Layout Constants ---
var KEY_WIDTH = Math.floor(2048 / NUM_KEYS); // Each key fills 1/5 of width
var KEY_HEIGHT = Math.floor(2732 / 2); // Keys fill bottom half
var KEY_GAP = 0; // No gap, keys are flush
var KEY_BOTTOM_MARGIN = 0; // No margin, keys reach bottom
var NOTE_SIZE = 210;
var NOTE_BASE_SPEED = 7; // Start slower
var NOTE_MAX_SPEED = 18; // Cap speed (increased for more challenge)
var NOTE_SPEED = NOTE_BASE_SPEED; // Will be updated dynamically
var NOTE_SPAWN_INTERVAL = 60; // frames
var NOTE_SPEEDUP_INTERVAL = 600; // Every 10 seconds at 60fps
var NOTE_SPEEDUP_AMOUNT = 1.2; // Increase by this amount each interval
var MONSTER_SIZE = 180;
var MONSTER_SPEED = 2.5;
var MONSTER_HP = 2;
var MONSTER_SPAWN_INTERVAL = 180; // frames
var PROJECTILE_SIZE = 60;
var PROJECTILE_SPEED = 40;
var MAX_MISSES = 8;
// --- Note density (how many notes at once) ---
var DENSITY_INCREASE_INTERVAL = 1200; // every 20 seconds at 60fps
var MAX_NOTE_DENSITY = Math.min(NUM_KEYS, 4); // never more than number of keys
if (typeof noteDensity === "undefined") {
	var noteDensity = 1;
}
// --- Asset Initialization ---
// --- Game State ---
var pianoKeys = [];
var notes = [];
var monsters = [];
var projectiles = [];
var missCount = 0;
var score = 0;
var lastNoteSpawn = 0;
var lastMonsterSpawn = 0;
// --- Layout Calculations ---
var pianoWidth = NUM_KEYS * KEY_WIDTH + (NUM_KEYS - 1) * KEY_GAP;
var pianoLeft = 0; // Keys start at left edge
var pianoTop = 2732 / 2; // Keys start at vertical center
// --- No divider line: screen is visually split by content only ---
// --- Hero (player) ---
// --- Breathing effect for hero and weapon (in sync) ---
// Move hero and weapon slightly lower only for Funky Groove map
var heroYDefault = 770;
var heroYFunky = 920; // Move down by 150px for Funky Groove
// Move hero and weapon even higher for Funky Groove (very slightly up)
var funkyGrooveYOffset = 18; // move up by 18px more (previously was -80px, now -98px)
var hero = game.addChild(LK.getAsset('hero', {
	anchorX: 0.5,
	anchorY: 0.5,
	x: 400,
	y: heroYDefault
}));
// Add a weapon to hero's lap (bigger and centered for lap position)
var weapon = LK.getAsset('projectile', {
	anchorX: 0.5,
	anchorY: 0.85,
	width: 230,
	height: 120,
	x: hero.x,
	y: hero.y + 90
});
game.addChild(weapon);
// Helper to update hero/weapon Y for Funky Groove
function updateHeroPositionForMusic() {
	if (selectedMusicId === "gamemusic2") {
		hero.y = heroYFunky - 98; // Move up by 98px for Funky Groove (was 80px, now even higher)
		weapon.y = hero.y + 90;
	} else if (selectedMusicId === "gamemusic3") {
		hero.y = heroYDefault - 134; // Move hero up by 4px more for Epic Battle
		weapon.y = hero.y + 90;
	} else {
		hero.y = heroYDefault;
		weapon.y = hero.y + 90;
	}
}
// Call on music select and in game.update to ensure correct position
function startHeroBreathing() {
	// Reset scale to default before starting
	hero.scaleX = 1;
	hero.scaleY = 1;
	weapon.scaleX = 1;
	weapon.scaleY = 1;
	// Helper to tween both hero and weapon together
	function inhale() {
		tween(hero, {
			scaleX: 1.07,
			scaleY: 0.93
		}, {
			duration: 900,
			easing: tween.easeInOut,
			onFinish: function onFinish() {
				tween(hero, {
					scaleX: 1,
					scaleY: 1
				}, {
					duration: 900,
					easing: tween.easeInOut,
					onFinish: inhale
				});
			}
		});
		tween(weapon, {
			scaleX: 1.07,
			scaleY: 0.93
		}, {
			duration: 900,
			easing: tween.easeInOut,
			onFinish: function onFinish() {
				tween(weapon, {
					scaleX: 1,
					scaleY: 1
				}, {
					duration: 900,
					easing: tween.easeInOut
				});
			}
		});
	}
	inhale();
}
startHeroBreathing();
// Keep weapon attached to hero's lap
game.updateWeapon = function () {
	weapon.x = hero.x;
	weapon.y = hero.y + 90;
};
// --- Score Display ---
var scoreTxt = new Text2('0', {
	size: 120,
	fill: "#fff"
});
scoreTxt.anchor.set(0.5, 0);
LK.gui.top.addChild(scoreTxt);
// --- Misses Display ---
var missTxt = new Text2('Misses: 0', {
	size: 70,
	fill: 0xFF6666
});
missTxt.anchor.set(0.5, 0);
LK.gui.top.addChild(missTxt);
missTxt.y = 120;
// --- Piano Keys ---
for (var i = 0; i < NUM_KEYS; i++) {
	var key = new PianoKey();
	key.index = i;
	key.keyWidth = KEY_WIDTH;
	key.keyHeight = KEY_HEIGHT;
	key.assetId = 'key_piano'; // Use key_piano asset for all keys
	key.baseColor = 0xffffff;
	key.x = pianoLeft + i * (KEY_WIDTH + KEY_GAP) + KEY_WIDTH / 2;
	key.y = 2732 - KEY_HEIGHT; // Place keys at the very bottom of the screen
	key.width = KEY_WIDTH;
	key.height = KEY_HEIGHT;
	game.addChild(key);
	pianoKeys.push(key);
}
// --- Input Handling ---
mainGameDownHandler = function mainGameDownHandler(x, y, obj) {
	// Check if a key was pressed
	var keyPressed = false;
	for (var i = 0; i < pianoKeys.length; i++) {
		var key = pianoKeys[i];
		// Key bounds
		var left = key.x - KEY_WIDTH / 2;
		var right = key.x + KEY_WIDTH / 2;
		var top = key.y;
		var bottom = key.y + KEY_HEIGHT;
		if (x >= left && x <= right && y >= top && y <= bottom) {
			key.flash();
			handleKeyPress(i);
			keyPressed = true;
			break;
		}
	}
	// If not on a key, check if a note was tapped
	if (!keyPressed) {
		for (var n = 0; n < notes.length; n++) {
			var note = notes[n];
			if (!note.active) {
				continue;
			}
			// Note bounds
			var noteLeft = note.x - note.noteSize / 2;
			var noteRight = note.x + note.noteSize / 2;
			var noteTop = note.y - note.noteSize / 2;
			var noteBottom = note.y + note.noteSize / 2;
			if (x >= noteLeft && x <= noteRight && y >= noteTop && y <= noteBottom) {
				// Only allow firing if note is above the bottom of its assigned key (not missed yet)
				var key = typeof note.keyIndex !== "undefined" && note.keyIndex >= 0 && note.keyIndex < pianoKeys.length ? pianoKeys[note.keyIndex] : null;
				if (key) {
					var missY = key.y + KEY_HEIGHT + NOTE_SIZE / 2;
					if (note.y < missY) {
						// Fire projectile at nearest monster, scale speed by timing accuracy
						var target = findNearestMonster();
						if (target) {
							// Calculate accuracy: closer to center line = more accurate
							var centerLine = 2732 / 2;
							var maxDist = pianoTop - centerLine;
							var distFromCenter = Math.abs(note.y - centerLine);
							var accuracy = 1 - Math.min(distFromCenter / maxDist, 1); // 1 = perfect, 0 = worst
							var proj = new Projectile();
							proj.size = PROJECTILE_SIZE;
							proj.x = weapon.x;
							proj.y = weapon.y;
							// Scale projectile speed: min 60, max 120
							proj.speed = PROJECTILE_SPEED + Math.floor(accuracy * 60);
							proj.monster = target;
							proj.target = target;
							projectiles.push(proj);
							game.addChild(proj);
							// Animate hero and weapon for shooting
							tween(hero, {
								scaleX: 1.15,
								scaleY: 0.92
							}, {
								duration: 80,
								yoyo: true,
								repeat: 1,
								onFinish: function onFinish() {
									// Restart breathing effect after shooting
									startHeroBreathing();
								}
							});
							// Rotate weapon to point toward the enemy
							var angleToTarget = Math.atan2(target.y - weapon.y, target.x - weapon.x);
							tween(weapon, {
								rotation: angleToTarget
							}, {
								duration: 80,
								yoyo: true,
								repeat: 1
							});
						}
						// Animate note
						note.active = false;
						tween(note, {
							alpha: 0,
							scaleX: 1.5,
							scaleY: 1.5
						}, {
							duration: 120,
							onFinish: function onFinish() {
								note.destroy();
							}
						});
						break;
					}
				}
			}
		}
	}
};
// --- Key Press Logic ---
function handleKeyPress(keyIndex) {
	// Find the first active note for this key that is still in the air (not missed yet)
	var hit = false;
	for (var n = 0; n < notes.length; n++) {
		var note = notes[n];
		if (!note.active) {
			continue;
		}
		if (note.keyIndex !== keyIndex) {
			continue;
		}
		var key = pianoKeys[keyIndex];
		// Only allow hit if note is inside the key bounds (not just above the key)
		var keyTop = key.y;
		var keyBottom = key.y + KEY_HEIGHT;
		var noteTop = note.y - note.noteSize / 2;
		var noteBottom = note.y + note.noteSize / 2;
		// Check if note is at least partially inside the key area
		var insideKey = !(noteBottom < keyTop || noteTop > keyBottom);
		// Rhythm mechanic: Only allow hit if note is visible (not missed, not below key)
		var missY = key.y + KEY_HEIGHT + note.noteSize / 2;
		if (note.y >= missY || !note.active) {
			// Note is no longer visible, or already inactive, so pressing now is a miss
			break;
		}
		if (insideKey) {
			// Play key1 sound when any key is pressed
			LK.getSound('key1').play();
			// Only allow hit if note is still active (not destroyed/missed)
			if (!note.active) {
				continue;
			}
			// Hit!
			note.active = false;
			hit = true;
			score += 1;
			scoreTxt.setText(score);
			// Fire projectile at nearest monster, scale speed by timing accuracy
			var target = findNearestMonster();
			if (target) {
				// Calculate accuracy: closer to center line = more accurate
				var centerLine = 2732 / 2;
				var maxDist = pianoTop - centerLine;
				var distFromCenter = Math.abs(note.y - centerLine);
				var accuracy = 1 - Math.min(distFromCenter / maxDist, 1); // 1 = perfect, 0 = worst
				var proj = new Projectile();
				proj.size = PROJECTILE_SIZE;
				proj.x = weapon.x;
				proj.y = weapon.y;
				// Scale projectile speed: min 60, max 120
				proj.speed = PROJECTILE_SPEED + Math.floor(accuracy * 60);
				proj.monster = target;
				proj.target = target;
				projectiles.push(proj);
				game.addChild(proj);
				// Animate hero and weapon for shooting
				tween(hero, {
					scaleX: 1.15,
					scaleY: 0.92
				}, {
					duration: 80,
					yoyo: true,
					repeat: 1,
					onFinish: function onFinish() {
						// Restart breathing effect after shooting
						startHeroBreathing();
					}
				});
				// Rotate weapon to point toward the enemy
				var angleToTarget = Math.atan2(target.y - weapon.y, target.x - weapon.x);
				tween(weapon, {
					rotation: angleToTarget
				}, {
					duration: 80,
					yoyo: true,
					repeat: 1
				});
			}
			// Animate note
			tween(note, {
				alpha: 0,
				scaleX: 1.5,
				scaleY: 1.5
			}, {
				duration: 120,
				onFinish: function onFinish() {
					note.destroy();
				}
			});
			break;
		}
	}
	if (!hit) {
		// Missed (pressed wrong key, or note is not visible, or note was already destroyed/missed)
		missCount += 1;
		missTxt.setText('Misses: ' + missCount);
		LK.effects.flashObject(hero, 0xff4444, 200);
		checkGameOver();
	}
}
// --- Find Nearest Monster ---
function findNearestMonster() {
	var minDist = 99999;
	var nearest = null;
	for (var i = 0; i < monsters.length; i++) {
		var m = monsters[i];
		if (m.destroyed) {
			continue;
		}
		// Distance from hero to monster
		var dx = m.x - hero.x;
		var dy = m.y - hero.y;
		var dist = Math.sqrt(dx * dx + dy * dy);
		if (dist < minDist) {
			minDist = dist;
			nearest = m;
		}
	}
	return nearest;
}
// --- Game Update Loop ---
game.update = function () {
	// If splash screen is active, hide all main game elements and skip game logic
	if (typeof splashActive !== "undefined" && splashActive) {
		// Hide main game elements
		if (typeof topBg !== "undefined") topBg.visible = false;
		if (typeof hero !== "undefined") hero.visible = false;
		if (typeof weapon !== "undefined") weapon.visible = false;
		if (typeof healthBar !== "undefined" && healthBar) healthBar.visible = false;
		for (var i = 0; i < pianoKeys.length; i++) {
			if (pianoKeys[i]) pianoKeys[i].visible = false;
		}
		for (var i = 0; i < notes.length; i++) {
			if (notes[i]) notes[i].visible = false;
		}
		for (var i = 0; i < monsters.length; i++) {
			if (monsters[i]) monsters[i].visible = false;
		}
		for (var i = 0; i < projectiles.length; i++) {
			if (projectiles[i]) projectiles[i].visible = false;
		}
		if (typeof scoreTxt !== "undefined") scoreTxt.visible = false;
		if (typeof missTxt !== "undefined") missTxt.visible = false;
		return;
	} else {
		// Show main game elements when splash is gone
		if (typeof showMainGameBg === "function") showMainGameBg();
		if (typeof hero !== "undefined") hero.visible = true;
		if (typeof weapon !== "undefined") weapon.visible = true;
		if (typeof healthBar !== "undefined" && healthBar) healthBar.visible = true;
		for (var i = 0; i < pianoKeys.length; i++) {
			if (pianoKeys[i]) pianoKeys[i].visible = true;
		}
		for (var i = 0; i < notes.length; i++) {
			if (notes[i]) notes[i].visible = true;
		}
		for (var i = 0; i < monsters.length; i++) {
			if (monsters[i]) monsters[i].visible = true;
		}
		for (var i = 0; i < projectiles.length; i++) {
			if (projectiles[i]) projectiles[i].visible = true;
		}
		if (typeof scoreTxt !== "undefined") scoreTxt.visible = true;
		if (typeof missTxt !== "undefined") missTxt.visible = true;
	}
	// Gradually speed up notes and monsters every NOTE_SPEEDUP_INTERVAL frames, up to max
	if (LK.ticks % NOTE_SPEEDUP_INTERVAL === 0 && LK.ticks > 0) {
		NOTE_SPEED = Math.min(NOTE_MAX_SPEED, NOTE_SPEED + NOTE_SPEEDUP_AMOUNT);
		// Cap monster speed at a separate, reasonable maximum
		var MONSTER_MAX_SPEED = 8; // Set a reasonable cap for monster speed
		// Also increase speed of all future monsters (and update current monsters to match)
		for (var i = 0; i < notes.length; i++) {
			notes[i].speed = NOTE_SPEED;
		}
		for (var j = 0; j < monsters.length; j++) {
			// Only update monsters that are not in attack range (so they don't "jump" while attacking)
			if (!monsters[j].destroyed && typeof monsters[j].dirX === "number" && typeof monsters[j].dirY === "number") {
				monsters[j].speed = Math.min(MONSTER_MAX_SPEED, NOTE_SPEED);
			}
		}
	}
	// --- DENSITY CONTROL ---
	// Difficulty variables
	if (typeof noteDensity === "undefined") noteDensity = 1;
	if (typeof noteScatter === "undefined") noteScatter = 0;
	if (typeof noteScatterMax === "undefined") noteScatterMax = 120; // max px scatter
	if (typeof noteScatterStep === "undefined") noteScatterStep = 12; // how much scatter increases per interval
	// Gradually increase note density and scatter, but very slowly
	if (LK.ticks % (DENSITY_INCREASE_INTERVAL * 2) === 0 && LK.ticks > 0) {
		// Only increase density if not at max, and only after a long time
		if (noteDensity < MAX_NOTE_DENSITY) {
			noteDensity += 1;
		} else if (noteScatter < noteScatterMax) {
			noteScatter = Math.min(noteScatterMax, noteScatter + noteScatterStep);
		}
	}
	// Spawn notes and corresponding monsters (enemies) in sync
	if (LK.ticks - lastNoteSpawn >= NOTE_SPAWN_INTERVAL) {
		lastNoteSpawn = LK.ticks;
		// Decide how many notes to spawn: mostly 1, but as density increases, sometimes more
		var spawnCount = 1;
		if (noteDensity > 1) {
			// As density increases, increase chance to spawn more than 1 note
			var chance = Math.random();
			if (chance < 0.25 * (noteDensity - 1)) spawnCount = 2;
			if (noteDensity > 2 && chance < 0.10 * (noteDensity - 1)) spawnCount = 3;
			if (noteDensity > 3 && chance < 0.04 * (noteDensity - 1)) spawnCount = 4;
			spawnCount = Math.min(noteDensity, spawnCount);
		}
		// Pick random keys to spawn notes on, never duplicate keys in one spawn
		var availableKeys = [];
		for (var i = 0; i < NUM_KEYS; i++) {
			availableKeys.push(i);
		}
		// Shuffle availableKeys
		for (var i = availableKeys.length - 1; i > 0; i--) {
			var j = Math.floor(Math.random() * (i + 1));
			var temp = availableKeys[i];
			availableKeys[i] = availableKeys[j];
			availableKeys[j] = temp;
		}
		for (var d = 0; d < spawnCount; d++) {
			if (availableKeys.length === 0) break;
			var keyIdx = availableKeys.pop();
			// Create note
			var note = new Note();
			note.index = keyIdx;
			note.noteSize = NOTE_SIZE;
			// Assign note to a random key
			var key = pianoKeys[note.index];
			note.keyIndex = note.index;
			// Start notes at the center line, horizontally aligned with their key
			note.x = key.x;
			// Add scatter as difficulty increases (notes start at slightly different Y)
			var scatterY = 0;
			if (noteScatter > 0) {
				scatterY = Math.floor((Math.random() - 0.5) * noteScatter);
			}
			note.y = 2732 / 2 - NOTE_SIZE / 2 + scatterY;
			note.speed = NOTE_SPEED;
			note.active = true;
			notes.push(note);
			game.addChild(note);
			// Create corresponding monster (enemy) for this note
			var monster;
			if (selectedMusicId === "gamemusic2") {
				monster = new Monster2();
			} else if (selectedMusicId === "gamemusic3") {
				monster = new Monster3();
			} else {
				monster = new Monster();
			}
			monster.monsterSize = MONSTER_SIZE;
			// Spawn at the top right of the upper half of the screen
			monster.x = 2048 - MONSTER_SIZE / 2 - 40; // right margin, with a little padding
			monster.y = 220 + Math.random() * (2732 / 2 - 220 - MONSTER_SIZE); // random Y in upper half, not below center
			// Monster speed matches note speed, but is capped
			var MONSTER_MAX_SPEED = 8;
			monster.speed = Math.min(MONSTER_MAX_SPEED, note.speed);
			monster.maxHp = MONSTER_HP;
			monster.hp = MONSTER_HP;
			monster.baseColor = 0x8e44ad;
			monster.destroyed = false;
			// Calculate direction vector: from spawn point toward hero
			var dx = hero.x - monster.x;
			var dy = hero.y - monster.y;
			var dist = Math.sqrt(dx * dx + dy * dy);
			monster.dirX = dx / dist;
			monster.dirY = dy / dist;
			// Link monster to note and note to monster for removal
			note.linkedMonster = monster;
			monster.linkedNote = note;
			monsters.push(monster);
			game.addChild(monster);
		}
	}
	// Update notes
	for (var i = notes.length - 1; i >= 0; i--) {
		var note = notes[i];
		if (note && typeof note.update === "function") {
			note.update();
		}
		// Remove destroyed/inactive notes
		if (!note || !note.active || !note.parent || note.alpha === 0) {
			if (note && typeof note.destroy === "function" && note.parent) {
				note.destroy();
			}
			notes.splice(i, 1);
		} else if (typeof note.keyIndex === "undefined" || note.keyIndex < 0 || note.keyIndex >= pianoKeys.length) {
			if (note && typeof note.destroy === "function" && note.parent) {
				note.destroy();
			}
			notes.splice(i, 1);
		}
	}
	// Update projectiles
	for (var i = projectiles.length - 1; i >= 0; i--) {
		var p = projectiles[i];
		if (p && typeof p.update === "function") {
			p.update();
		}
		if (!p || !p.parent || p.alpha === 0) {
			if (p && typeof p.destroy === "function" && p.parent) {
				p.destroy();
			}
			projectiles.splice(i, 1);
		}
	}
	// Update monsters and clean up destroyed ones
	for (var i = monsters.length - 1; i >= 0; i--) {
		var m = monsters[i];
		if (m && typeof m.update === "function") {
			m.update();
		}
		if (!m || m.destroyed && (!m.parent || m.alpha === 0)) {
			if (m && typeof m.destroy === "function" && m.parent) {
				m.destroy();
			}
			monsters.splice(i, 1);
		}
	}
	// Defensive: Full cleanup for any orphaned/destroyed objects (extra safety, every 120 frames)
	if (LK.ticks % 120 === 0) {
		for (var i = notes.length - 1; i >= 0; i--) {
			var note = notes[i];
			if (!note || !note.parent || note.alpha === 0) {
				if (note && typeof note.destroy === "function" && note.parent) {
					note.destroy();
				}
				notes.splice(i, 1);
			}
		}
		for (var i = monsters.length - 1; i >= 0; i--) {
			var m = monsters[i];
			if (!m || !m.parent || m.alpha === 0) {
				if (m && typeof m.destroy === "function" && m.parent) {
					m.destroy();
				}
				monsters.splice(i, 1);
			}
		}
		for (var i = projectiles.length - 1; i >= 0; i--) {
			var p = projectiles[i];
			if (!p || !p.parent || p.alpha === 0) {
				if (p && typeof p.destroy === "function" && p.parent) {
					p.destroy();
				}
				projectiles.splice(i, 1);
			}
		}
	}
	// (Hero health and monster attack logic removed)
	// Update weapon position to follow hero
	if (typeof updateHeroPositionForMusic === "function") {
		updateHeroPositionForMusic();
	}
	if (typeof game.updateWeapon === "function") {
		game.updateWeapon();
	}
};
// --- Game Over Check ---
function checkGameOver() {
	if (missCount >= MAX_MISSES) {
		LK.effects.flashScreen(0xff0000, 800);
		LK.showGameOver();
		// Clean up all notes, monsters, and projectiles to prevent buildup
		for (var i = notes.length - 1; i >= 0; i--) {
			if (notes[i] && typeof notes[i].destroy === "function" && notes[i].parent) {
				notes[i].destroy();
			}
			notes.splice(i, 1);
		}
		for (var i = monsters.length - 1; i >= 0; i--) {
			if (monsters[i] && typeof monsters[i].destroy === "function" && monsters[i].parent) {
				monsters[i].destroy();
			}
			monsters.splice(i, 1);
		}
		for (var i = projectiles.length - 1; i >= 0; i--) {
			if (projectiles[i] && typeof projectiles[i].destroy === "function" && projectiles[i].parent) {
				projectiles[i].destroy();
			}
			projectiles.splice(i, 1);
		}
		// Defensive: Reset arrays to empty to ensure no lingering references
		notes = [];
		monsters = [];
		projectiles = [];
	}
}
:quality(85)/https://cdn.frvr.ai/6839a1918aa1a737f2faf0e3.png%3F3) 
 :quality(85)/https://cdn.frvr.ai/6839a3048aa1a737f2faf0eb.png%3F3) 
 :quality(85)/https://cdn.frvr.ai/6839a4128aa1a737f2faf0f0.png%3F3) 
 :quality(85)/https://cdn.frvr.ai/6839a6438cebd6b6e7ef6d4d.png%3F3) 
 :quality(85)/https://cdn.frvr.ai/6839a76e19472c7e9599b71b.png%3F3) 
 shine yellow color music note. No background. Transparent background. Blank background. No shadows. 2d. In-Game asset. flat
:quality(85)/https://cdn.frvr.ai/6839e17f6e1ee1a9f6d4eb42.png%3F3) 
 :quality(85)/https://cdn.frvr.ai/683c3f1d5715f4c9136ea1b5.png%3F3) 
 :quality(85)/https://cdn.frvr.ai/683c42235715f4c9136ea1c3.png%3F3) 
 :quality(85)/https://cdn.frvr.ai/683c45fcb0c2fbb7d6293eb0.png%3F3) 
 robotic monster. No background. Transparent background. Blank background. No shadows. 2d. In-Game asset. flat
:quality(85)/https://cdn.frvr.ai/683c4805b0c2fbb7d6293eba.png%3F3) 
 blue shiny music note. No background. Transparent background. Blank background. No shadows. 2d. In-Game asset. flat
:quality(85)/https://cdn.frvr.ai/683e338debe79108d1f156f2.png%3F3) 
 :quality(85)/https://cdn.frvr.ai/683e353bebe79108d1f156f4.png%3F3) 
 :quality(85)/https://cdn.frvr.ai/683e3724ebe79108d1f156f8.png%3F3) 
 :quality(85)/https://cdn.frvr.ai/683e3a6cebe79108d1f156fa.png%3F3) 
 :quality(85)/https://cdn.frvr.ai/683e3c19ebe79108d1f156fe.png%3F3) 
 :quality(85)/https://cdn.frvr.ai/68443045935510c7f8bf1d13.png%3F3) 
 :quality(85)/https://cdn.frvr.ai/68443167935510c7f8bf1d15.png%3F3)