User prompt
add a global isPlaying
User prompt
log the entry in showScore
Code edit (1 edits merged)
Please save this source code
User prompt
fix : dragon still comes after showScore call !!
User prompt
in showscore stop the dragon
User prompt
Please fix the bug: 'Timeout.tick error: Cannot set properties of null (setting 'visible')' in or related to this line: 'gem.visible = false;' Line Number: 1606
User prompt
in showScore, stop every thing : dragon, falling gems, hints...
User prompt
in showScore, stop timer and hide all gems
Code edit (3 edits merged)
Please save this source code
User prompt
Ajoute une nouvelle fonction ShowScore
User prompt
play wrong sound when wrong move
Code edit (1 edits merged)
Please save this source code
User prompt
add a global loopBgMusicInterval and un function loopBgMusic function where you check loopBgMusicInterval is defined, if not define the interval and play bgMusic in it
User prompt
play happyWitch sound when objective is reached
Code edit (2 edits merged)
Please save this source code
User prompt
play batRoad when the dragon takes a gem
User prompt
play gemMatch sound when gems are matched
Code edit (1 edits merged)
Please save this source code
User prompt
Please fix the bug: 'Timeout.tick error: Cannot read properties of undefined (reading 'dx')' in or related to this line: 'hintOverlay.x = move.gemStartPosition.x + moveDirection.dx * moveDistance * waveProgress;' Line Number: 167
User prompt
Migrate to the latest version of LK
Remix started
Copy Dragon Match: New Years
/**** 
* Classes
****/ 
// Board class
var Board = Container.expand(function () {
	var self = Container.call(this);
	// Function to shuffle gems around randomly
	Board.prototype.shuffleGems = function () {
		console.log("shuffleGems");
		self.isShuffling = true;
		// Removed usage of Set for compatibility
		for (var i = this.gems.length - 1; i > 0; i--) {
			this.gems[i].newPosition = false;
		}
		for (var i = this.gems.length - 1; i > 0; i--) {
			var j = Math.floor(Math.random() * (i + 1));
			// Swap the gems
			var tempNewPosition = this.gems[i].newPosition || {
				x: this.gems[i].x,
				y: this.gems[i].y
			};
			this.gems[i].newPosition = this.gems[j].newPosition || {
				x: this.gems[j].x,
				y: this.gems[j].y
			};
			this.gems[j].newPosition = tempNewPosition;
		}
		// The rest of your method remains unchanged
		function animateGemToPosition(gem, x, y) {
			var animationDuration = 1000; // Duration of the animation in milliseconds
			var startX = gem.x;
			var startY = gem.y;
			var deltaX = x - startX;
			var deltaY = y - startY;
			var startTime = Date.now();
			var animate = function animate() {
				var now = Date.now();
				var progress = Math.min(1, (now - startTime) / animationDuration);
				gem.x = startX + deltaX * progress;
				gem.y = startY + deltaY * progress;
				if (progress < 1) {
					LK.setTimeout(animate, 16); // Aim for roughly 60fps
				} else {
					gem.x = x;
					gem.y = y;
					self.isShuffling = false;
				}
			};
			LK.setTimeout(animate, 16);
		}
		// Update the positions of the shuffled gems and ensure they have the correct new position in the gems array
		var newGemsArray = new Array(this.gems.length);
		this.gems.forEach(function (gem, index) {
			if (gem.newPosition) {
				var newPositionIndex = this.gems.findIndex(function (g) {
					return g.x === gem.newPosition.x && g.y === gem.newPosition.y;
				});
				var aNewPosition = this.snapToGrid(gem.newPosition.x, gem.newPosition.y);
				animateGemToPosition(gem, aNewPosition.x, aNewPosition.y);
				newGemsArray[newPositionIndex] = gem;
			}
		}.bind(this));
		this.gems = newGemsArray.filter(function (g) {
			return g !== undefined;
		});
		LK.setTimeout(self.checkForMatches, 1000);
	};
	// Method to round or snap any position to the nearest position in the grid made by the 6x8 gems
	this.snapToGrid = function (x, y) {
		// Ensure there is at least one gem in the array before accessing its properties
		var margin = 10;
		var boardWidth = game.width * .9;
		var boardHeight = game.height * .9;
		var gemsPerRow = 6;
		var gemsPerColumn = 8;
		var totalMarginWidth = margin * (gemsPerRow + 1);
		var totalMarginHeight = margin * (gemsPerColumn + 1);
		var availableWidth = boardWidth - totalMarginWidth;
		var availableHeight = boardHeight - totalMarginHeight;
		var scaledGemSize = Math.min(availableWidth / gemsPerRow, availableHeight / gemsPerColumn);
		var xOffset = (game.width - boardWidth) / 2 + scaledGemSize / 2;
		var yOffset = (game.height - boardHeight) / 2 + scaledGemSize / 2 + 80;
		var columnWidth = (boardWidth - margin) / 6;
		var rowHeight = (boardHeight - margin) / 8;
		var snappedX = Math.round((x - xOffset) / columnWidth) * columnWidth + xOffset;
		var snappedY = Math.round((y - yOffset) / rowHeight) * rowHeight + yOffset;
		return {
			x: snappedX,
			y: snappedY
		};
	};
	// Method to show a hint for a possible match
	this.showHint = function () {
		console.log('showHint function started');
		var possibleMatches = this.checkIfAnyMoveCausesMatch();
		if (possibleMatches.length > 0) {
			var animateMove = function animateMove(repeatCount) {
				if (move.gem.isUsed) {
					// Start fade-out effect for hint overlay
					var fadeOutDuration = 500; // Fade out over 500ms
					var startTime = Date.now();
					var fadeStep = function fadeStep() {
						var currentTime = Date.now();
						var progress = (currentTime - startTime) / fadeOutDuration;
						hintOverlay.alpha = 1 - progress; // Fade out effect
						if (progress < 1) {
							LK.setTimeout(fadeStep, 16); // Continue fading
						} else {
							hintOverlay.destroy(); // Destroy after faded out
						}
					};
					fadeStep();
					return;
				}
				var totalDuration = 1000; // Half a second for each back and forth movement
				var repeatLimit = 1; // Repeat the animation three times
				var animationCount = 0;
				var startTime = Date.now();
				var animateStep = function animateStep() {
					if (move.gem.isUsed || !hintOverlay) {
						if (hintOverlay) {
							hintOverlay.destroy();
						}
						return;
					}
					var currentTime = Date.now();
					var progress = (currentTime - startTime) / totalDuration;
					var waveProgress = (Math.sin(progress * Math.PI * 2) + 1) / 2; // Adjusted to ensure it never goes below zero
					hintOverlay.x = move.gemStartPosition.x + moveDirection.dx * moveDistance * waveProgress;
					hintOverlay.y = move.gemStartPosition.y + moveDirection.dy * moveDistance * waveProgress;
					if (progress >= 1) {
						animationCount++;
						if (animationCount < repeatLimit) {
							startTime = Date.now(); // Reset start time for the next cycle
							animateStep(); // Continue animation
						} else {
							hintOverlay.destroy();
						}
					} else {
						LK.setTimeout(animateStep, 16); // Continue animation
					}
				};
				animateStep();
			};
			console.log('Possible matches:', possibleMatches);
			var move = possibleMatches[0];
			var hintOverlay = LK.getAsset('hintOverlay', {});
			self.lastHintOverlay = hintOverlay;
			hintOverlay.anchor.set(0, 0);
			self.addChild(hintOverlay);
			hintOverlay.x = move.gem.x;
			hintOverlay.y = move.gem.y;
			move.gemStartPosition = {
				x: move.gem.x,
				y: move.gem.y
			}; // Track starting position for animation
			var moveDirection = move.move || {
				dx: 0,
				dy: 0
			};
			var moveDistance = move.gem.spacing; // Distance to move back and forth
			var moveDuration = 500; // Duration of each move
			animateMove();
		} else {
			console.log("no possible matches");
			if (!self.fillingEmptySpaces && !self.gemsFalling && !self.isShuffling && !isDragoning) {
				triggerDragon();
			}
		}
	};
	// Method to find possible matches on the board
	// Method to find possible matches on the board
	// Method to find possible matches on the board
	this.findPossibleMatches = function () {
		var matches = [];
		var width = 6; // Board width
		var height = 8; // Board height
		for (var i = 0; i < height; i++) {
			for (var j = 0; j < width; j++) {
				var currentGem = this.gems[i * width + j];
				// Check right and down for potential matches
				var directions = [{
					dx: 1,
					dy: 0
				},
				// Right
				{
					dx: 0,
					dy: 1
				} // Down
				];
				directions.forEach(function (dir) {
					var match = [currentGem];
					for (var k = 1; k < 3; k++) {
						var nextGemX = j + dir.dx * k;
						var nextGemY = i + dir.dy * k;
						if (nextGemX < width && nextGemY < height) {
							var nextGem = this.gems[nextGemY * width + nextGemX];
							if (nextGem && currentGem && nextGem.color === currentGem.color) {
								match.push(nextGem);
							} else {
								break;
							}
						}
					}
					if (match.length >= 3) {
						// Allows for matches longer than 3
						matches.push(match);
					}
				}, this);
			}
		}
		return matches;
	};
	// Method to check if moving any gem results in a match
	this.checkIfAnyMoveCausesMatch = function () {
		var matches = [];
		var width = 6; // Board width
		var height = 8; // Board height
		// Simulate moving each gem in all four directions and check for matches
		for (var i = 0; i < height; i++) {
			for (var j = 0; j < width; j++) {
				var currentGem = this.gems[i * width + j];
				if (!currentGem) {
					continue;
				}
				// Possible moves: up, down, left, right
				var moves = [{
					dx: -1,
					dy: 0
				}, {
					dx: 1,
					dy: 0
				}, {
					dx: 0,
					dy: -1
				}, {
					dx: 0,
					dy: 1
				}];
				moves.forEach(function (move) {
					var newX = j + move.dx;
					var newY = i + move.dy;
					// Check if the new position is within the board
					if (newX >= 0 && newX < width && newY >= 0 && newY < height) {
						var targetGem = this.findGemByPosition(currentGem.x + currentGem.spacing * move.dx, currentGem.y + currentGem.spacing * move.dy);
						if (targetGem && this.wouldSwapResultInMatch(currentGem, targetGem)) {
							matches.push({
								gem: currentGem,
								move: move
							});
						}
					}
				}, this);
			}
		}
		return matches;
	};
	// Check if swapping two gems would result in a match
	this.wouldSwapResultInMatch = function (gemA, gemB) {
		var gemAIndex = this.gems.indexOf(gemA);
		var gemBIndex = this.gems.indexOf(gemB);
		this.gems[gemAIndex] = gemB;
		this.gems[gemBIndex] = gemA;
		// Check for matches
		var matchFound = false;
		var matchedGems = [];
		// Check for horizontal matches
		for (var i = 0; i < 8; i++) {
			for (var j = 0; j < 6; j++) {
				// Adjust to allow checks across all columns
				var gem1 = this.gems[i * 6 + j];
				var nowMatchingGems = [];
				for (var k = j; k < 6; k++) {
					var nextGem = this.gems[i * 6 + k];
					if (nextGem && nextGem.color === gem1.color) {
						nowMatchingGems.push(nextGem);
					} else {
						break;
					}
				}
				if (nowMatchingGems.length >= 3) {
					matchFound = true;
					matchedGems = matchedGems.concat(nowMatchingGems.filter(function (gem) {
						return matchedGems.indexOf(gem) === -1;
					}));
				}
			}
		}
		// Check for vertical matches
		for (var i = 0; i < 6; i++) {
			for (var j = 0; j < 8; j++) {
				// Adjust to allow checks across all rows
				var gem1 = this.gems[j * 6 + i];
				var nowMatchingGems = [];
				for (var k = j; k < 8; k++) {
					var nextGem = this.gems[k * 6 + i];
					if (nextGem && nextGem.color === gem1.color) {
						nowMatchingGems.push(nextGem);
					} else {
						break;
					}
				}
				if (nowMatchingGems.length >= 3) {
					matchFound = true;
					matchedGems = matchedGems.concat(nowMatchingGems.filter(function (gem) {
						return matchedGems.indexOf(gem) === -1;
					}));
				}
			}
		}
		// Swap back
		this.gems[gemAIndex] = gemA;
		this.gems[gemBIndex] = gemB;
		return matchFound;
	};
	this.swapGems = function (gem1, gem2) {
		var gem1Index = this.gems.indexOf(gem1);
		var gem2Index = this.gems.indexOf(gem2);
		if (gem1Index !== -1 && gem2Index !== -1) {
			// Animate swap positions with easing
			var swapDuration = 150; // Duration in milliseconds
			var gem1StartPos = {
				x: gem1.x,
				y: gem1.y
			};
			if (!gem2) {
				return;
			} // Prevent TypeError if gem2 is null
			var gem2StartPos = {
				x: gem2.x,
				y: gem2.y
			};
			gem1.isUsed = true;
			gem2.isUsed = true;
			gem1.alpha = 1;
			gem2.alpha = 1;
			var startTime = Date.now();
			var animateSwap = function animateSwap() {
				var currentTime = Date.now();
				var progress = Math.min(1, (currentTime - startTime) / swapDuration);
				var easeInOut = progress < 0.5 ? 2 * progress * progress : -1 + (4 - 2 * progress) * progress;
				gem1.x = gem1StartPos.x + (gem2StartPos.x - gem1StartPos.x) * easeInOut;
				gem1.y = gem1StartPos.y + (gem2StartPos.y - gem1StartPos.y) * easeInOut;
				gem2.x = gem2StartPos.x + (gem1StartPos.x - gem2StartPos.x) * easeInOut;
				gem2.y = gem2StartPos.y + (gem1StartPos.y - gem2StartPos.y) * easeInOut;
				if (progress < 1) {
					LK.setTimeout(animateSwap, 16); // Aim for roughly 60fps
				} else {
					gem1.isUsed = false;
					gem2.isUsed = false;
					var snappedOne = self.snapToGrid(gem1.x, gem1.y);
					gem1.x = snappedOne.x;
					gem1.y = snappedOne.y;
					var snappedOne = self.snapToGrid(gem2.x, gem2.y);
					gem2.x = snappedOne.x;
					gem2.y = snappedOne.y;
					self.checkForMatches();
				}
			};
			animateSwap();
			// Swap in gems array
			this.gems[gem1Index] = gem2;
			this.gems[gem2Index] = gem1;
			// Check for matches after swap
		}
	};
	this.faintSwapGems = function (gem1, gem2, firstFaint) {
		var gem1Index = this.gems.indexOf(gem1);
		var gem2Index = this.gems.indexOf(gem2);
		if (gem1Index !== -1 && gem2Index !== -1) {
			// Animate swap positions with easing
			var swapDuration = 150; // Duration in milliseconds
			var gem1StartPos = {
				x: gem1.x,
				y: gem1.y
			};
			var gem2StartPos = {
				x: gem2.x,
				y: gem2.y
			};
			var startTime = Date.now();
			var animateSwap = function animateSwap() {
				var currentTime = Date.now();
				var progress = Math.min(1, (currentTime - startTime) / swapDuration);
				var easeInOut = progress < 0.5 ? 2 * progress * progress : -1 + (4 - 2 * progress) * progress;
				gem1.x = gem1StartPos.x + (gem2StartPos.x - gem1StartPos.x) * easeInOut;
				gem1.y = gem1StartPos.y + (gem2StartPos.y - gem1StartPos.y) * easeInOut;
				gem2.x = gem2StartPos.x + (gem1StartPos.x - gem2StartPos.x) * easeInOut;
				gem2.y = gem2StartPos.y + (gem1StartPos.y - gem2StartPos.y) * easeInOut;
				if (progress < 1) {
					LK.setTimeout(animateSwap, 16); // Aim for roughly 60fps
				} else if (firstFaint) {
					self.faintSwapGems(gem1, gem2);
				}
			};
			animateSwap();
			// Swap in gems array
			this.gems[gem1Index] = gem2;
			this.gems[gem2Index] = gem1;
		}
	};
	// Find a gem by its position
	this.findGemByPosition = function (x, y, exceptThisGem) {
		for (var i = 0; i < this.gems.length; i++) {
			var gem = this.gems[i];
			if (gem == exceptThisGem) {
				continue;
			}
			if (gem) {
				var tolerance = gem.spacing / 2; // Tolerance in pixels for approximate position
				if (Math.abs(x - gem.x) < tolerance && Math.abs(y - gem.y) < tolerance) {
					return gem;
				}
			}
		}
		return null;
	};
	this.fillEmptySpaces = function () {
		self.fillingEmptySpaces = true;
		var _animateGemDown = function animateGemDown(newGem, finalY, initialY) {
			var snappedOne = self.snapToGrid(newGem.x, finalY);
			finalY = snappedOne.y;
			var animationDuration = 250; // Duration in milliseconds
			var startTime = Date.now();
			var animate = function animate() {
				var currentTime = Date.now();
				var progress = Math.min(1, (currentTime - startTime) / animationDuration);
				// Apply easing for smoother animation
				var easedProgress = Math.sin(progress * Math.PI / 2);
				if (progress < 1) {
					newGem.y = initialY + (finalY - initialY) * easedProgress;
					LK.setTimeout(animate, 16); // Aim for roughly 60fps
				} else {
					newGem.y = finalY; // Ensure final position is accurate
					self.fillingEmptySpaces = false;
				}
			};
			animate();
		};
		for (var i = 0; i < 8; i++) {
			for (var j = 0; j < 6; j++) {
				var index = i * 6 + j;
				if (!self.gems[index]) {
					var possibleColors = ['gemBlue', 'gemGreen', 'gemRed', 'gemPurple', 'gemYellow', 'gemOrange', 'gemCyan'];
					// Filter colors to ensure at least one possible match
					var colors = possibleColors.filter(function (color) {
						return true;
					}, this);
					var color = colors.length > 0 ? colors[Math.floor(Math.random() * colors.length)] : possibleColors[Math.floor(Math.random() * possibleColors.length)];
					var newGem = new Gem(color);
					// Calculate x and y position for new gems when there are no existing gems to reference
					var gemSize = 100;
					var margin = 10;
					var boardWidth = 1800; // Assuming the board width is known
					var boardHeight = 2400; // Assuming the board height is known
					var gemsPerRow = 6;
					var gemsPerColumn = 8;
					var totalMarginWidth = margin * (gemsPerRow + 1);
					var totalMarginHeight = margin * (gemsPerColumn + 1);
					var availableWidth = boardWidth - totalMarginWidth;
					var availableHeight = boardHeight - totalMarginHeight;
					var scaledGemSize = Math.min(availableWidth / gemsPerRow, availableHeight / gemsPerColumn);
					var xOffset = (2048 - boardWidth) / 2 + scaledGemSize / 2; // Assuming game width is 2048
					var yOffset = (2732 - boardHeight) / 2 + scaledGemSize / 2; // Assuming game height is 2732
					var snapped = self.snapToGrid(xOffset + (scaledGemSize + margin) * j, yOffset + (scaledGemSize + margin) * i);
					newGem.x = snapped.x;
					// Calculate initial y position for animation start
					// Calculate initial y position for animation start
					var initialY = -gemSize; // Start above the screen to simulate falling into place
					newGem.y = initialY;
					// Animate gem to its final position
					var finalY = snapped.y;
					_animateGemDown(newGem, finalY, initialY);
					newGem.spacing = scaledGemSize + margin;
					newGem.scale.set(scaledGemSize / gemSize);
					newGem.baseScale = scaledGemSize / gemSize;
					self.addChild(newGem);
					self.gems[index] = newGem;
					self.handleGemClick(newGem);
				}
			}
		}
	};
	self.gems = [];
	this.handleFallingGems = function () {
		console.log("handle Falling gems");
		var didFall = false;
		for (var i = 0; i < 6; i++) {
			for (var j = 7; j >= 0; j--) {
				var index = j * 6 + i;
				if (index >= 0 && index < self.gems.length && !self.gems[index]) {
					var emptySpaces = 1;
					for (var k = j - 1; k >= 0; k--) {
						var aboveIndex = k * 6 + i;
						if (!self.gems[aboveIndex]) {
							emptySpaces++;
						} else {
							var gemAbove = self.gems[aboveIndex];
							var targetIndex = (k + emptySpaces) * 6 + i;
							self.gems[targetIndex] = gemAbove;
							self.gems[aboveIndex] = null;
							// Calculate the new Y position based on the number of empty spaces
							var margin = 10;
							var snapped = self.snapToGrid(gemAbove.x, gemAbove.y + gemAbove.spacing * emptySpaces);
							var newY = snapped.y;
							// Animate the gem moving to the new position
							gemAbove.alpha = 1;
							animateGemToPosition(gemAbove, gemAbove.x, newY);
							didFall = true;
							break;
						}
					}
				}
			}
		}
		if (didFall) {
			self.gemsFalling = true;
			LK.setTimeout(function () {
				self.fillEmptySpaces();
				LK.setTimeout(function () {
					self.gemsFalling = false;
					self.checkForMatches();
				}, 250);
			}, 250);
		} else {
			// Trigger fillEmptySpaces even if no gems fell to ensure no gaps are left
			self.fillEmptySpaces();
			LK.setTimeout(function () {
				self.checkForMatches();
			}, 250);
		}
	};
	function animateGemToPosition(gem, newX, newY) {
		var fallDuration = 500; // Duration for the gem to fall to its new position
		var bounceDuration = 300; // Duration for the bounce effect, slightly longer for realism
		var scaleDuration = 150; // Duration for the scale effect after bouncing
		var startTime = Date.now();
		var animateStep = function animateStep() {
			var currentTime = Date.now();
			var elapsedTime = currentTime - startTime;
			var progress = elapsedTime / fallDuration;
			// First, handle the falling animation with a linear or ease-in effect
			if (progress < 1) {
				var fallProgress = Math.min(1, progress); // Ensure progress doesn't exceed 1
				// Simple linear interpolation for falling
				gem.y = gem.y + (newY - gem.y) * fallProgress;
				if (fallProgress < 1) {
					LK.setTimeout(animateStep, 16); // Continue the fall animation
				} else {
					gem.y = newY;
					gem.isUsed = false;
				}
			}
		};
		animateStep(); // Start the animation with the fall
	}
	this.handleGemMatched = function (gem) {
		if (gem.color == goalGemType) {
			matchedGemCount++;
			goalTxt.setText(matchedGemCount + "/" + goalGemCount);
			if (matchedGemCount >= goalGemCount) {
				LK.getSound('happyWitch').play();
				game.timer += 10;
				timerTxt.setText(game.timer.toString());
				stopTimer();
				if (isDragoning) {
					isDragoning = false;
					if (dragonSpawnTimer) {
						LK.clearTimeout(dragonSpawnTimer);
					}
				}
				// Show modal pop-up for 10 more seconds
				var modalContainer = new Container();
				LK.gui.center.addChild(modalContainer);
				var modalBackground = LK.getAsset('goalCompleteBg', {});
				modalBackground.anchor.set(.5, .5);
				modalBackground.alpha = .75;
				modalContainer.addChild(modalBackground);
				// Animate scale of the modal container for excitement
				var scaleStartTime = Date.now();
				var scaleDuration = 500; // Scale animation duration in milliseconds
				var animateScale = function animateScale() {
					var currentTime = Date.now();
					var progress = (currentTime - scaleStartTime) / scaleDuration;
					var scale = 1 + 0.1 * Math.sin(progress * Math.PI * 2); // Oscillate scale between 1 and 1.1
					modalContainer.scale.set(scale);
					if (progress < 1) {
						LK.setTimeout(animateScale, 16);
					}
				};
				animateScale();
				// Trigger lots of confetti balls on mission complete
				for (var i = 0; i < 100; i++) {
					var confetti = new ConfettiParticle();
					confetti.init(Math.random() * game.width, Math.random() * game.height);
					game.addChild(confetti);
				}
				showPastGoalSprite = LK.getAsset(goalGemType, {
					// Align with the timer's top margin
					anchorX: .5,
					// Anchor right for right alignment
					anchorY: .5 // Anchor top for top alignment
				});
				goalGemType = false;
				// Add hourglass sprite next to the timer
				var pastGoalBackground = LK.getAsset('newSpriteId', {});
				pastGoalBackground.y = 0;
				pastGoalBackground.x = -100;
				pastGoalBackground.anchor.set(0.5, 0.5); // Align with the timer's top margin
				modalContainer.addChild(pastGoalBackground);
				pastGoalBackground.alpha = .75;
				showPastGoalSprite.y = pastGoalBackground.y;
				showPastGoalSprite.x = pastGoalBackground.x;
				showPastGoalSprite.anchor.set(.5, 0.5); // Align with the timer's top margin
				modalContainer.addChild(showPastGoalSprite);
				showPastGoalSprite.rotation = -.2;
				var showPastGoalText = new Text2(matchedGemCount + "/" + goalGemCount, {
					size: 100,
					weight: 600,
					fill: "#ffffff",
					x: 1024,
					y: 1366,
					anchorX: 0.5,
					anchorY: 0.5,
					dropShadow: true,
					dropShadowColor: '#000000',
					dropShadowBlur: 8,
					dropShadowOffsetX: 4,
					dropShadowOffsetY: 4,
					stroke: true,
					strokeColor: '#000000',
					strokeThickness: 4
				});
				showPastGoalText.y = pastGoalBackground.y;
				showPastGoalText.x = 0;
				showPastGoalText.anchor.set(0, 0.5); // Align with the timer's top margin
				modalContainer.addChild(showPastGoalText);
				var modalInfoText = new Text2('MISSION COMPLETE:', {
					size: 50,
					weight: 600,
					fill: "#ffffff",
					x: 1024,
					y: 1366,
					anchorX: 0.5,
					anchorY: 0.5,
					dropShadow: true,
					dropShadowColor: '#000000',
					dropShadowBlur: 8,
					dropShadowOffsetX: 4,
					dropShadowOffsetY: 4,
					stroke: true,
					strokeColor: '#000000',
					strokeThickness: 2
				});
				modalInfoText.anchor.set(.5);
				modalInfoText.y = -100;
				modalContainer.addChild(modalInfoText);
				var modalText = new Text2('+10 seconds!', {
					size: 100,
					weight: 600,
					fill: "#ffffff",
					x: 1024 + 70,
					// Adjust x position to make space for the hourglass sprite
					y: 1366,
					anchorX: 0.5,
					anchorY: 0.5,
					dropShadow: true,
					dropShadowColor: '#000000',
					dropShadowBlur: 8,
					dropShadowOffsetX: 4,
					dropShadowOffsetY: 4,
					stroke: true,
					strokeColor: '#000000',
					strokeThickness: 2
				});
				modalText.anchor.set(.5);
				modalText.y = 100;
				modalContainer.addChild(modalText);
				// Add hourglass sprite next to the '+10 seconds!' text
				var hourglassSpriteModal = LK.getAsset('hourglass', {
					anchorX: .5,
					anchorY: .5
				});
				hourglassSpriteModal.x = 1024 - 70; // Position hourglass to the left of the text
				hourglassSpriteModal.y = 1366;
				modalContainer.addChild(hourglassSpriteModal);
				var thumbUpSprite = LK.getAsset('thumbUp', {
					// Align with the timer's top margin
					anchorX: .5,
					// Anchor right for right alignment
					anchorY: .5 // Anchor top for top alignment
				});
				thumbUpSprite.y = 0;
				thumbUpSprite.x = -500;
				thumbUpSprite.anchor.set(.5, 0.5); // Align with the timer's top margin
				modalContainer.addChild(thumbUpSprite);
				var thumbUpSprite2 = LK.getAsset('woodLockAcid', {
					// Align with the timer's top margin
					anchorX: .5,
					// Anchor right for right alignment
					anchorY: .5 // Anchor top for top alignment
				});
				thumbUpSprite2.y = 0;
				thumbUpSprite2.x = 500;
				thumbUpSprite2.anchor.set(.5, 0.5); // Align with the timer's top margin
				modalContainer.addChild(thumbUpSprite2);
				var modalText = new Text2('+', {
					size: 120,
					weight: 600,
					fill: "#ffffff",
					x: 1024 + 70,
					// Adjust x position to make space for the hourglass sprite
					y: 1366,
					anchorX: 0.5,
					anchorY: 0.5,
					dropShadow: true,
					dropShadowColor: '#000000',
					dropShadowBlur: 8,
					dropShadowOffsetX: 4,
					dropShadowOffsetY: 4,
					stroke: true,
					strokeColor: '#000000',
					strokeThickness: 2
				});
				modalText.anchor.set(.5);
				modalText.x = 400;
				modalText.y = 0;
				modalContainer.addChild(modalText);
				// Automatically remove the modal and background after 2 seconds
				// Start animation for modal elements
				var duration = 2000; // 3 seconds for the animation
				LK.setTimeout(function () {
					var startTime = Date.now();
					var simpleCountdownInterval = LK.setInterval(function () {
						var currentTime = Date.now();
						var progress = (currentTime - startTime) / duration;
						var moveDistance = 2048; // Move to the right side off-screen
						modalContainer.x += moveDistance * progress;
						if (progress >= 1) {
							LK.clearInterval(simpleCountdownInterval);
							modalContainer.destroy();
							startTimer();
						}
					}, 16);
				}, 2000);
				goalLevel++;
				updateBackground();
				setRandomGoalGemType();
			}
		}
	};
	this.checkForMatches = function (matchFoundPreviously) {
		var matchFound = false;
		var matchedGems = [];
		// Check for horizontal matches
		for (var i = 0; i < 8; i++) {
			for (var j = 0; j < 6; j++) {
				// Adjust to allow checks across all columns
				if (!this.gems || !this.gems[i * 6 + j] || typeof this.gems[i * 6 + j] === 'undefined') {
					continue;
				}
				var gem1 = this.gems[i * 6 + j];
				if (!gem1) {
					continue;
				}
				var gem1 = this.gems[i * 6 + j];
				var nowMatchingGems = [];
				for (var k = j; k < 6; k++) {
					var nextGem = this.gems[i * 6 + k];
					if (nextGem && nextGem.color === gem1.color) {
						nowMatchingGems.push(nextGem);
					} else {
						break;
					}
				}
				if (nowMatchingGems.length >= 3) {
					matchFound = true;
					matchedGems = matchedGems.concat(nowMatchingGems.filter(function (gem) {
						return matchedGems.indexOf(gem) === -1;
					}));
				}
			}
		}
		// Check for vertical matches
		for (var i = 0; i < 6; i++) {
			for (var j = 0; j < 8; j++) {
				// Adjust to allow checks across all rows
				if (!this.gems || !this.gems[j * 6 + i]) {
					continue;
				}
				var gem1 = this.gems[j * 6 + i];
				var nowMatchingGems = [];
				for (var k = j; k < 8; k++) {
					var nextGem = this.gems[k * 6 + i];
					if (nextGem && nextGem.color === gem1.color) {
						nowMatchingGems.push(nextGem);
					} else {
						break;
					}
				}
				if (nowMatchingGems.length >= 3) {
					matchFound = true;
					matchedGems = matchedGems.concat(nowMatchingGems.filter(function (gem) {
						return matchedGems.indexOf(gem) === -1;
					}));
				}
			}
		}
		var matchesHandled = 0;
		matchedGems.forEach(function (gem) {
			// Play gemMatch sound when gems are matched
			LK.getSound('gemMatch').play();
			if (gem.color == goalGemType) {
				self.handleGemMatched(gem);
				// Move gem to the goalGemSprite instead of destroying it
				matchesHandled++;
				game.addChild(gem);
				var moveGemToGoal = function moveGemToGoal(gem) {
					LK.setTimeout(function () {
						var goalGemSpriteX = currentGoalGemSprite ? currentGoalGemSprite.x + (currentGoalGemSprite.parent ? currentGoalGemSprite.parent.x : 0) : 0;
						var goalGemSpriteY = currentGoalGemSprite ? currentGoalGemSprite.y + (currentGoalGemSprite.parent ? currentGoalGemSprite.parent.y : 0) : 0;
						if (currentGoalGemSprite) {
							var goalGemSpriteScale = currentGoalGemSprite.scale.x;
						}
						var moveDuration = 500 + matchesHandled * 100; // Duration in milliseconds
						var startTime = Date.now();
						var animateMove = function animateMove() {
							var currentTime = Date.now();
							var progress = Math.min(1, (currentTime - startTime) / moveDuration);
							var newX = gem.x + (goalGemSpriteX - gem.x) * progress;
							var newY = gem.y + (goalGemSpriteY - gem.y) * progress;
							var newScale = gem.scale.x + (goalGemSpriteScale - gem.scale.x) * progress;
							gem.x = newX;
							gem.y = newY;
							gem.scale.set(newScale);
							if (progress < 1) {
								LK.setTimeout(animateMove, 16); // Aim for roughly 60fps
							} else {
								gem.destroy(); // Destroy gem after reaching the goal
							}
						};
						animateMove();
					}, matchesHandled * 100);
				};
				moveGemToGoal(gem);
			} else {
				self.handleGemMatched(gem);
				gem.scaleUpAndDisappear();
				// Trigger glowing particles effect at the gem's position
				var glowingParticles = new GlowingParticles();
				glowingParticles.init(gem.x, gem.y);
				self.addChild(glowingParticles);
			}
			var index = self.gems.indexOf(gem);
			if (index > -1) {
				self.gems[index] = false;
				// Increase score based on combo multiplier
				var pointsAwarded = 10 * self.comboMultiplier;
				score += pointsAwarded; // Update score with points awarded based on combo multiplier
				LK.setScore(score);
				// Display points at the gem's location with animation
				var pointsText = new Text2("+" + pointsAwarded.toString(), {
					size: 80,
					weight: 600,
					fill: "#ffffff",
					anchorX: 0.5,
					anchorY: 0.5,
					dropShadow: true,
					dropShadowColor: '#000000',
					dropShadowBlur: 8,
					dropShadowOffsetX: 4,
					dropShadowOffsetY: 4,
					outline: true,
					outlineColor: '#000000',
					outlineThickness: 5
				});
				pointsText.y -= 20; // Make it a little bit higher
				pointsText.anchor.set(.5);
				pointsText.x = gem.x;
				pointsText.y = gem.y;
				game.addChild(pointsText);
				// Animate points text: scale up and fade out
				var scaleUpDuration = 500; // Duration to scale up in milliseconds
				var fadeOutDuration = 500; // Duration to fade out in milliseconds
				var maxScale = 1.5; // Maximum scale factor
				var originalScale = 1; // Original scale
				var startTime = Date.now();
				var animate = function animate() {
					var currentTime = Date.now();
					var progress = Math.min(1, (currentTime - startTime) / scaleUpDuration);
					pointsText.scale.set(originalScale + (maxScale - originalScale) * progress);
					pointsText.alpha = 1 - progress; // Fade out
					if (progress < 1) {
						LK.setTimeout(animate, 16); // Aim for roughly 60fps
					} else {
						pointsText.destroy(); // Destroy text after animation
					}
				};
				animate();
				// Increase combo multiplier for each consecutive match
				self.comboMultiplier++;
				scoreTxt.setText(score.toString()); // Update score display
			}
		});
		if (matchFound) {
			// If no match was found previously and it's not the first check, reset the combo multiplier
			if (!matchFoundPreviously && matchFound) {
				self.comboMultiplier = 1;
			} else if (matchFound) {
				// Increase combo multiplier for each consecutive match
				self.comboMultiplier++;
			}
			self.checkForMatches(true);
		} else if (matchFoundPreviously) {
			LK.setTimeout(function () {
				this.handleFallingGems();
			}.bind(this), 200);
		}
		return matchFound;
	};
	self.handleGemClick = function (gem) {
		gem.on('down', function (x, y, obj) {
			self.dragStartGem = gem;
			self.dragStartGemStartPosition = {
				x: gem.x,
				y: gem.y
			};
			var currentPos = game.toLocal(obj.global);
			self.dragStartPos = {
				x: currentPos.x,
				y: currentPos.y
			};
			// Highlight the drag start gem
			self.dragStartGem.alpha = 0.5;
			self.dragStartGem.scale.set(self.dragStartGem.baseScale * 1.1);
		});
		gem.on('move', function (x, y, obj) {
			if (!self.dragStartGem) {
				return;
			}
			var currentPos = game.toLocal(obj.global);
			//self.dragStartGem.x = self.dragStartGemStartPosition.x + currentPos.x - self.dragStartPos.x;
			//self.dragStartGem.y = self.dragStartGemStartPosition.y + currentPos.y - self.dragStartPos.y;
			var dx = currentPos.x - self.dragStartPos.x;
			var dy = currentPos.y - self.dragStartPos.y;
			if (Math.abs(dx) > gem.spacing / 2 || Math.abs(dy) > gem.spacing / 2) {
				var directionX = dx > 0 ? 1 : -1;
				var directionY = dy > 0 ? 1 : -1;
				// Correctly identify if we should swap horizontally or vertically
				if (Math.abs(dx) > Math.abs(dy)) {
					// Swap horizontally
					var swapGem = self.findGemByPosition(self.dragStartGem.x + gem.spacing * directionX, self.dragStartGem.y, self.dragStartGem);
				} else {
					// Swap vertically
					var swapGem = self.findGemByPosition(self.dragStartGem.x, self.dragStartGem.y + gem.spacing * directionY, self.dragStartGem);
				}
				if (self.lastHintOverlay) {
					self.lastHintOverlay.destroy();
				}
				if (swapGem && self.wouldSwapResultInMatch(self.dragStartGem, swapGem)) {
					self.swapGems(self.dragStartGem, swapGem);
				} else {
					self.faintSwapGems(self.dragStartGem, swapGem, true);
					// Play wrong sound when a wrong move is made
					LK.getSound('wrong').play();
				}
				self.dragStartGem.alpha = 1;
				self.dragStartGem.scale.set(self.dragStartGem.baseScale * 1);
				self.dragStartGem = null;
				self.dragStartPos = null;
			}
		});
		gem.on('up', function () {
			if (self.dragStartGem) {
				self.dragStartGem.alpha = 1; // Reset alpha to unhighlight the gem
				self.dragStartGem.scale.set(self.dragStartGem.baseScale * 1);
			}
			self.dragStartGem = null;
			self.dragStartPos = null;
		});
	};
	self.initBoard = function () {
		var colors = game.timer > 60 ? ['gemBlue', 'gemGreen', 'gemRed', 'gemPurple', 'gemYellow', 'gemOrange', 'gemCyan'] : ['gemBlue', 'gemGreen', 'gemRed', 'gemPurple', 'gemYellow', 'gemOrange'];
		for (var i = 0; i < 8; i++) {
			for (var j = 0; j < 6; j++) {
				var color = colors[Math.floor(Math.random() * colors.length)];
				var gem = new Gem(color);
				var gem = new Gem(color);
				var gemSize = 100;
				var margin = 10;
				var boardWidth = game.width * .9;
				var boardHeight = game.height * .9;
				var gemsPerRow = 6;
				var gemsPerColumn = 8;
				var totalMarginWidth = margin * (gemsPerRow + 1);
				var totalMarginHeight = margin * (gemsPerColumn + 1);
				var availableWidth = boardWidth - totalMarginWidth;
				var availableHeight = boardHeight - totalMarginHeight;
				var scaledGemSize = Math.min(availableWidth / gemsPerRow, availableHeight / gemsPerColumn);
				var xOffset = (game.width - boardWidth) / 2 + scaledGemSize / 2;
				var yOffset = (game.height - boardHeight) / 2 + scaledGemSize / 2;
				gem.spacing = scaledGemSize + margin;
				self.spacing = gem.spacing;
				var snappedPos = self.snapToGrid(xOffset + (scaledGemSize + margin) * j, yOffset + (scaledGemSize + margin) * i);
				gem.x = snappedPos.x;
				gem.y = snappedPos.y;
				gem.scale.set(scaledGemSize / gemSize);
				gem.scale.set(scaledGemSize / gemSize);
				gem.baseScale = scaledGemSize / gemSize;
				self.addChild(gem);
				self.gems.push(gem);
				self.handleGemClick(gem);
			}
		}
		self.comboMultiplier = 1; // Initialize combo multiplier
		self.checkForMatches();
	};
});
// ChineseRedEnvelope class
var ChineseRedEnvelope = Container.expand(function () {
	var self = Container.call(this);
	var envelopeGraphics = self.attachAsset('redEnvelope', {
		anchorX: 0.5,
		anchorY: 0.5
	});
	self.init = function (x, y) {
		self.x = x;
		self.y = y;
		var scaleAnimation = function scaleAnimation() {
			var scaleUp = true;
			var scaleValue = 1;
			LK.setInterval(function () {
				if (scaleUp) {
					scaleValue += 0.01;
				} else {
					scaleValue -= 0.01;
				}
				if (scaleValue >= 1.1) {
					scaleUp = false;
				}
				if (scaleValue <= 1) {
					scaleUp = true;
				}
				self.scale.set(scaleValue * 2.0); // Make the envelope significantly larger
			}, 100);
		};
		scaleAnimation();
		self.on('down', function () {
			var targetX = timerTxt.x;
			var targetY = timerTxt.y;
			var moveDuration = 1000; // Duration in milliseconds
			var startTime = Date.now();
			var animateMove = function animateMove() {
				var currentTime = Date.now();
				var progress = Math.min(1, (currentTime - startTime) / moveDuration);
				// Apply a quadratic easing for a smooth curve
				var curveProgress = Math.pow(progress, 2);
				self.x = self.x + (targetX - self.x) * curveProgress;
				self.y = self.y - 75 * Math.sin(Math.PI * progress) + (targetY - self.y) * curveProgress; // Add a sine wave pattern for vertical movement
				if (progress < 1) {
					LK.setTimeout(animateMove, 16);
				} else {
					game.timer += 5; // Grant 5 more seconds
					timerTxt.setText(game.timer.toString()); // Update timer display
					self.destroy(); // Remove the envelope after reaching the timer
				}
			};
			animateMove();
		});
		// Initiate continuous glowing effect
		function glowEffect() {
			var glowParticle = new GlowingParticlesForRedEnvelopes(.3);
			glowParticle.init(0, 0);
			self.addChildAt(glowParticle, 0);
		}
		;
		glowEffect();
		//	LK.setInterval(glowEffect, 500); // Add a glowing particle effect every 500ms
	};
});
// ConfettiParticle class
var ConfettiParticle = Container.expand(function () {
	var self = Container.call(this);
	var confettiColors = ['confettiRed', 'confettiBlue', 'confettiGreen', 'confettiYellow', 'confettiPurple'];
	var randomColor = confettiColors[Math.floor(Math.random() * confettiColors.length)];
	var confettiGraphics = self.attachAsset(randomColor, {
		anchorX: 0.5,
		anchorY: 0.5
	});
	self.init = function (x, y) {
		self.x = x;
		self.y = y;
		var angle = Math.random() * Math.PI * 2;
		var speed = 0.5 + Math.random(); // Reduced speed for smoother appearance
		var duration = 1500 + Math.random() * 2500; // Extended duration for smoother fade
		var startTime = Date.now();
		var floatGravity = 1 + 20 * Math.random();
		var animate = function animate() {
			var currentTime = Date.now();
			var progress = (currentTime - startTime) / duration;
			self.x += Math.cos(angle) * speed;
			self.y -= Math.sin(angle) * speed;
			self.y -= floatGravity; // Apply upward gravity to make confetti float upwards
			self.alpha = Math.sin(progress * Math.PI); // Smooth in and out fading effect
			if (progress < 1) {
				LK.setTimeout(animate, 16);
			} else {
				self.destroy();
			}
		};
		animate();
	};
});
// Dragon class
var Dragon = Container.expand(function (gem) {
	var self = Container.call(this);
	var dragonGraphics = self.attachAsset('dragon', {
		anchorX: 0.5,
		anchorY: 0.5
	});
	dragonGraphics.anchor.set(1, .7);
	self.speed = 5;
	var hasTakenGem = false;
	self._move_migrated = function () {
		var endX = 2048 + self.width; // Ensure dragon ends off-screen to the right
		var startX = -self.width; // Start off-screen to the left
		var travelDistance = endX - startX;
		var travelTime = 3000; // Time in milliseconds for the dragon to cross the screen
		var startTime = Date.now();
		var particleParts = [];
		function animate() {
			var currentTime = Date.now();
			var elapsedTime = currentTime - startTime;
			var progress = elapsedTime / travelTime;
			self.x = startX + travelDistance * progress;
			if (self.x > gem.x && !hasTakenGem) {
				hasTakenGem = true;
				self.addChild(gem);
				LK.getSound('batRoar').play();
				// Animate gem scale upon grabbing
				var scaleAnimationDuration = 300; // Duration of the scale animation in milliseconds
				var scaleAnimationStartTime = Date.now();
				var animateGemScale = function animateGemScale() {
					var currentTime = Date.now();
					var progress = Math.min(1, (currentTime - scaleAnimationStartTime) / scaleAnimationDuration);
					gem.scale.set(gem.baseScale * (.8 + .2 * Math.sin(progress * Math.PI * 2))); // Animate scale
					if (progress < 1) {
						LK.setTimeout(animateGemScale, 16);
					} else {
						gem.scale.set(gem.baseScale * .8);
					}
				};
				animateGemScale();
				gem.x = 50;
				gem.y = 0;
				var index = board.gems.indexOf(gem);
				if (index > -1) {
					if (board.gems[index] == gem) {
						board.gems[index] = false;
					}
				}
				LK.setTimeout(function () {
					board.handleFallingGems();
				}, 200);
			}
			if (hasTakenGem) {
				self.addChild(gem);
				//gem.scale.set(gem.baseScale * .8);
				gem.x = 50;
				gem.y = 0;
			}
			// Generate particle trail
			if (progress < 1) {
				LK.setTimeout(animate, 16); // Aim for roughly 60fps
			} else {
				var fadeoutparticle = function fadeoutparticle(particle) {
					// Start fade out effect
					var fadeOutDuration = 500; // Duration for the fade out in milliseconds
					var fadeStartTime = Date.now();
					var fadeStep = function fadeStep() {
						var currentTime = Date.now();
						var progress = (currentTime - fadeStartTime) / fadeOutDuration;
						particle.alpha = 1 - progress; // Fade out
						if (progress < 1) {
							LK.setTimeout(fadeStep, 16);
						} else {
							particle.destroy(); // Destroy particle after fade out
						}
					};
					fadeStep();
				};
				;
				// Spawn a red envelope at a random position
				//var envelope = new ChineseRedEnvelope();
				//envelope.init(Math.random() * game.width, self.y);
				//game.addChild(envelope);
				// Destroy the dragon instance once it crosses the screen
				isDragoning = false;
				particleParts.forEach(function (particle) {
					fadeoutparticle(particle);
				});
				self.destroy();
			}
		}
		animate();
	};
});
var FireworkEffect = Container.expand(function (x, y, numParticles, color) {
	var self = Container.call(this);
	self.x = x;
	self.y = y;
	for (var i = 0; i < numParticles; i++) {
		var angle = i / numParticles * 2 * Math.PI;
		var speed = 5 + Math.random() * 5; // Random speed between 5 and 10
		var expansionSize = 0.5 + Math.random() * 1.5; // Variable size of expansion between 0.5 and 2
		var particle = new FireworkParticle();
		particle.init(self.x, self.y, angle, speed, color);
		self.addChild(particle);
	}
});
// FireworkParticle class
var FireworkParticle = Container.expand(function () {
	var self = Container.call(this);
	var particleGraphics = self.attachAsset('fireworkParticle', {
		anchorX: 0.5,
		anchorY: 0.5
	});
	self.init = function (x, y, angle, speed, color) {
		particleGraphics.tint = color;
		particleGraphics.scale.set(.5 + Math.random() * 1);
		particleGraphics.rotation = Math.PI * 2 * Math.random();
		self.x = x;
		self.y = y;
		self.angle = angle;
		self.speed = speed;
		self.alpha = 1;
		var decay = 0.95;
		var gravity = 0.05;
		self._move_migrated = function () {
			var decay = 0.95;
			var gravity = 0.05;
			self.x += Math.cos(self.angle) * self.speed;
			self.y += Math.sin(self.angle) * self.speed;
			self.speed *= decay;
			self.y += gravity;
			self.alpha *= decay;
			if (self.alpha < 0.05) {
				self.destroy();
			}
		};
		LK.on('tick', function () {
			self._move_migrated();
		});
	};
});
// Gem class
var Gem = Container.expand(function (color) {
	var self = Container.call(this);
	self.scaleUpAndDown = function (delay) {
		LK.setTimeout(function () {
			var scaleUpDuration = 150; // Duration to scale up in milliseconds
			var scaleDownDuration = 150; // Duration to scale down in milliseconds
			var maxScale = self.baseScale * 1.3; // Maximum scale factor
			var originalScale = self.baseScale; // Remember the original scale
			var scaleUp = function scaleUp() {
				var startTime = Date.now();
				var scaleStep = function scaleStep() {
					var currentTime = Date.now();
					var progress = Math.min(1, (currentTime - startTime) / scaleUpDuration);
					self.scale.set(originalScale + (maxScale - originalScale) * progress);
					if (progress < 1) {
						LK.setTimeout(scaleStep, 16);
					} else {
						scaleDown();
					}
				};
				scaleStep();
			};
			var scaleDown = function scaleDown() {
				var startTime = Date.now();
				var scaleStep = function scaleStep() {
					var currentTime = Date.now();
					var progress = Math.min(1, (currentTime - startTime) / scaleDownDuration);
					self.scale.set(maxScale - (maxScale - originalScale) * progress);
					if (progress < 1) {
						LK.setTimeout(scaleStep, 16);
					}
				};
				scaleStep();
			};
			scaleUp();
		}, delay);
	};
	self.scaleUpAndDisappear = function scaleUpAndDisappear() {
		var scaleUpDuration = 100; // Duration to scale up in milliseconds
		var scaleDownDuration = 200; // Duration to scale down to zero
		var maxScale = self.baseScale * 1.2; // Maximum scale factor
		var disappearScale = 0; // Scale factor to disappear
		var originalScale = self.baseScale; // Remember the original scale
		// Animate scale up
		// Start scale up
		var scaleUpDuration = 100; // Duration to scale up in milliseconds
		var disappearDuration = 200; // Duration to scale down to zero
		var maxScale = self.baseScale * 1.2; // Maximum scale factor
		var disappearScale = 0; // Scale factor to disappear
		var originalScale = self.baseScale; // Remember the original scale
		// Animate scale up
		var startTime = Date.now();
		var _scaleStep2 = function _scaleStep() {
			var currentTime = Date.now();
			var progress = Math.min(1, (currentTime - startTime) / scaleUpDuration);
			self.scale.set(originalScale + (maxScale - originalScale) * progress);
			if (progress < 1) {
				LK.setTimeout(_scaleStep2, 16);
			} else {
				// Once scaled up, start disappearing
				startTime = Date.now();
				_scaleStep2 = function scaleStep() {
					var currentTime = Date.now();
					var progress = Math.min(1, (currentTime - startTime) / disappearDuration);
					self.scale.set(maxScale - (maxScale - disappearScale) * progress);
					if (progress < 1) {
						LK.setTimeout(_scaleStep2, 16);
					} else {
						self.destroy();
					}
				};
				_scaleStep2();
			}
		};
		_scaleStep2();
	};
	var gemGraphics = self.attachAsset(color, {
		anchorX: 0.5,
		anchorY: 0.5
	});
	self.color = color;
	self.isSelected = false;
	self.toggleSelect = function () {
		self.isSelected = !self.isSelected;
		if (self.isSelected) {
			gemGraphics.alpha = 0.5;
			self.scale.set(self.baseScale * 1.1);
		} else {
			gemGraphics.alpha = 1;
			self.scale.set(self.baseScale);
		}
	};
});
// GlowingParticles class enhancement
var GlowingParticles = Container.expand(function () {
	var self = Container.call(this);
	scaleMultiplier = 1;
	var _animateParticle = function animateParticle(particle) {
		var currentTime = Date.now();
		var elapsedTime = currentTime - particle.startTime;
		var progress = elapsedTime / particle.duration;
		if (progress < 1) {
			particle.x += Math.cos(particle.angle) * particle.speed;
			particle.y += Math.sin(particle.angle) * particle.speed;
			particle.alpha = Math.cos(progress * Math.PI); // Smooth in and out fading effect
			particle.rotation += particle.rotationVelocity; // Add rotation to each particle
			LK.setTimeout(function () {
				_animateParticle(particle);
			}, 16);
		} else {
			particle.destroy();
		}
	};
	self.init = function (x, y) {
		for (var i = 0; i < 50; i++) {
			var particle = self.attachAsset('glowEffect', {
				x: x,
				y: y,
				anchorX: 0.5,
				anchorY: 0.5
			});
			particle.blendMode = 1;
			particle.angle = Math.random() * Math.PI * 2; // Random angle for direction
			particle.speed = 1 + Math.random() * 2.5; // Adjusted speed for varied particle movement
			particle.duration = 500 + Math.random() * 1000; // Keeping the duration dynamic
			// Introduce gravity effect to some particles
			for (var i = 0; i < 50; i++) {
				var particle = self.attachAsset('glowEffect', {
					x: x,
					y: y,
					anchorX: 0.5,
					anchorY: 0.5
				});
				particle.blendMode = 1;
				particle.angle = Math.random() * Math.PI * 2; // Random angle for direction
				particle.speed = 1 + Math.random() * 2.5; // Adjusted speed for varied particle movement
				particle.duration = 500 + Math.random() * 1000; // Keeping the duration dynamic
				particle.gravity = Math.random() > 0.5 ? 0.01 : 0; // Half the particles have a gravity effect
				particle.targetScale = 0.5 + Math.random() * 1.5; // Varied scale for more visual variety
				particle.scale.set(particle.targetScale * scaleMultiplier); // Initial scale set based on the random scale variable
				particle.startTime = Date.now();
				particle.rotationVelocity = -0.1 + Math.random() * .2;
				particle.x += Math.cos(particle.angle) * Math.random() * 80;
				particle.y += Math.sin(particle.angle) * Math.random() * 80;
				_animateParticle(particle);
			}
			particle.targetScale = 0.5 + Math.random() * 1.5; // Varied scale for more visual variety
			particle.scale.set(particle.targetScale * scaleMultiplier); // Initial scale set based on the random scale variable
			particle.startTime = Date.now();
			particle.rotationVelocity = -0.1 + Math.random() * .2;
			particle.x += Math.cos(particle.angle) * Math.random() * 80;
			particle.y += Math.sin(particle.angle) * Math.random() * 80;
			_animateParticle(particle);
		}
	};
});
// Define the GlowingParticlesForRedEnvelope class
var GlowingParticlesForRedEnvelope = Container.expand(function (scaleMultiplier) {
	var self = Container.call(this);
	var _animateParticle = function animateParticle(particle) {
		var currentTime = Date.now();
		var elapsedTime = currentTime - particle.startTime;
		var progress = elapsedTime / particle.duration;
		if (progress < 1) {
			// Update particle properties for movement, fading, and rotation
			particle.x += Math.cos(particle.angle) * particle.speed;
			particle.y += Math.sin(particle.angle) * particle.speed;
			particle.alpha = Math.cos(progress * Math.PI); // Fading effect
			particle.rotation += particle.rotationVelocity;
		} else {
			// Reset particle to create a continuous effect
			particle.startTime = Date.now(); // Reset start time
			// Optionally, re-randomize properties for varied continuous effect
			particle.angle = Math.random() * Math.PI * 2;
			particle.speed = 1 + Math.random() * 1.5;
			particle.duration = 500 + Math.random() * 1000;
			particle.rotationVelocity = -0.1 + Math.random() * 0.2;
			particle.x = particle.initialX + Math.cos(particle.angle) * Math.random() * 50;
			particle.y = particle.initialY + Math.sin(particle.angle) * Math.random() * 50;
		}
		LK.setTimeout(function () {
			_animateParticle(particle);
		}, 16); // Continue animation loop
	};
	self.init = function (x, y) {
		for (var i = 0; i < 50; i++) {
			var particle = self.attachAsset('glowEffect', {
				x: x,
				y: y,
				anchorX: 0.5,
				anchorY: 0.5
			});
			particle.blendMode = 1;
			particle.alpha = 0;
			particle.initialX = x; // Store initial position
			particle.initialY = y;
			particle.angle = Math.random() * Math.PI * 2;
			particle.speed = 1 + Math.random() * 1.5;
			particle.duration = 500 + Math.random() * 1000;
			particle.targetScale = 0.5 + Math.random() * 1.5;
			particle.scale.set(particle.targetScale * scaleMultiplier);
			particle.startTime = Date.now();
			particle.rotationVelocity = -0.1 + Math.random() * 0.2;
			particle.x += Math.cos(particle.angle) * Math.random() * 70;
			particle.y += Math.sin(particle.angle) * Math.random() * 70;
			_animateParticle(particle);
		}
	};
});
var GlowingParticlesForRedEnvelopes = Container.expand(function (scaleMultiplier) {
	var self = Container.call(this);
	var _animateParticle = function animateParticle(particle) {
		var currentTime = Date.now();
		var elapsedTime = currentTime - particle.startTime;
		var progress = elapsedTime / particle.duration;
		if (progress < 1) {
			// Update particle properties for movement, fading, and rotation
			particle.x += Math.cos(particle.angle) * particle.speed;
			particle.y += Math.sin(particle.angle) * particle.speed;
			particle.alpha = Math.cos(progress * Math.PI); // Fading effect
			particle.rotation += particle.rotationVelocity;
		} else {
			// Reset particle to create a continuous effect
			particle.startTime = Date.now(); // Reset start time
			// Optionally, re-randomize properties for varied continuous effect
			particle.angle = Math.random() * Math.PI * 2;
			particle.speed = 1 + Math.random() * 1.5;
			particle.duration = 500 + Math.random() * 1000;
			particle.rotationVelocity = -0.1 + Math.random() * 0.2;
			particle.x = particle.initialX + Math.cos(particle.angle) * Math.random() * 50;
			particle.y = particle.initialY + Math.sin(particle.angle) * Math.random() * 50;
		}
		LK.setTimeout(function () {
			_animateParticle(particle);
		}, 16); // Continue animation loop
	};
	self.init = function (x, y) {
		for (var i = 0; i < 50; i++) {
			var particle = self.attachAsset('glowEffect', {
				x: x,
				y: y,
				anchorX: 0.5,
				anchorY: 0.5
			});
			particle.blendMode = 1;
			particle.alpha = 0;
			particle.initialX = x; // Store initial position
			particle.initialY = y;
			particle.angle = Math.random() * Math.PI * 2;
			particle.speed = 1 + Math.random() * 1.5;
			particle.duration = 500 + Math.random() * 1000;
			particle.targetScale = 0.5 + Math.random() * 1.5;
			particle.scale.set(particle.targetScale * scaleMultiplier);
			particle.startTime = Date.now();
			particle.rotationVelocity = -0.1 + Math.random() * 0.2;
			particle.x += Math.cos(particle.angle) * Math.random() * 70;
			particle.y += Math.sin(particle.angle) * Math.random() * 70;
			_animateParticle(particle);
		}
	};
});
// LineSprite class
var LineSprite = Container.expand(function () {
	var self = Container.call(this);
	self.updateLine = function (startX, startY, endX, endY) {
		var dx = endX - startX;
		var dy = endY - startY;
		var distance = Math.sqrt(dx * dx + dy * dy);
		self.width = distance;
		self.height = 5; // Fixed height for the line
		self.rotation = Math.atan2(dy, dx);
		self.x = startX + dx / 2;
		self.y = startY + dy / 2;
		self.anchorX = 0.5;
		self.anchorY = 0.5;
	};
});
// RowBlasterGem class
var RowBlasterGem = Container.expand(function (color) {
	var self = Container.call(this);
	var gemGraphics = self.attachAsset(color, {
		anchorX: 0.5,
		anchorY: 0.5
	});
	self.color = color;
	// Unique behavior for RowBlasterGem
	self.activate = function () {
		// Logic to blast the entire row
		console.log('Blasting row...');
	};
});
/**** 
* Initialize Game
****/ 
var game = new LK.Game({
	backgroundColor: 0x000000 // Init game with black background
});
/**** 
* Game Code
****/ 
// Function to show the current score
function showScore() {
	stopTimer();
	if (isDragoning) {
		isDragoning = false;
		if (dragonSpawnTimer) {
			LK.clearTimeout(dragonSpawnTimer);
		}
	}
	board.gems.forEach(function (gem) {
		if (gem) {
			gem.visible = false;
		}
	});
	board.fillingEmptySpaces = false;
	board.gemsFalling = false;
	if (hintTimer) {
		LK.clearTimeout(hintTimer);
	}
	var scoreContainer = new Container();
	LK.gui.center.addChild(scoreContainer);
	var scoreBackground = LK.getAsset('scoreBg', {
		anchorX: 0.5,
		anchorY: 0.5
	});
	scoreContainer.addChild(scoreBackground);
	//LK.showGameOver('Final Score: ' + score);
	var scoreText = new Text2(score.toString(), {
		size: 150,
		fill: "#ffffff",
		anchorX: 0.5,
		anchorY: 0.5
	});
	scoreContainer.addChild(scoreText);
	scoreContainer.x = game.width / 2;
	scoreContainer.y = game.height / 2;
	// Animate the score display
	var startTime = Date.now();
	var duration = 2000; // 2 seconds
	var animate = function animate() {
		var currentTime = Date.now();
		var progress = (currentTime - startTime) / duration;
		scoreContainer.alpha = 1 - progress; // Fade out effect
		if (progress < 1) {
			LK.setTimeout(animate, 16); // Continue animation
		} else {
			scoreContainer.destroy(); // Remove the score display after animation
		}
	};
	animate();
}
// Function to loop background music
function loopBgMusic() {
	if (!loopBgMusicInterval) {
		// Play the background music immediately
		LK.getSound('bgMusic').play();
		// Set an interval to loop the background music
		loopBgMusicInterval = LK.setInterval(function () {
			LK.getSound('bgMusic').play();
		}, 6030); // Assuming the background music duration is 60 seconds
	}
}
// Global variable to store the interval ID for looping background music
var loopBgMusicInterval;
// Start looping background music
loopBgMusic();
// Initialize a timer for showing hints
// Initialize 2-minute timer
// Initialize score
// Initialize large countdown at the beginning of the game
// Goal gem type and count
// Dragon spawn timer
// SagaMap class
// SagaMap class
// FireworkEffect class
function _typeof3(o) {
	"@babel/helpers - typeof";
	return _typeof3 = "function" == typeof Symbol && "symbol" == typeof Symbol.iterator ? function (o) {
		return typeof o;
	} : function (o) {
		return o && "function" == typeof Symbol && o.constructor === Symbol && o !== Symbol.prototype ? "symbol" : typeof o;
	}, _typeof3(o);
}
function __defineProperties(target, props) {
	for (var i = 0; i < props.length; i++) {
		var descriptor = props[i];
		descriptor.enumerable = descriptor.enumerable || false;
		descriptor.configurable = true;
		if ("value" in descriptor) {
			descriptor.writable = true;
		}
		Object.defineProperty(target, _toPropertyKey3(descriptor.key), descriptor);
	}
}
function _createClass2(Constructor, protoProps, staticProps) {
	if (protoProps) {
		__defineProperties(Constructor.prototype, protoProps);
	}
	if (staticProps) {
		__defineProperties(Constructor, staticProps);
	}
	Object.defineProperty(Constructor, "prototype", {
		writable: false
	});
	return Constructor;
}
function _toPropertyKey3(t) {
	var i = _toPrimitive3(t, "string");
	return "symbol" == _typeof3(i) ? i : String(i);
}
function _toPrimitive3(t, r) {
	if ("object" != _typeof3(t) || !t) {
		return t;
	}
	var e = t[Symbol.toPrimitive];
	if (void 0 !== e) {
		var i = e.call(t, r || "default");
		if ("object" != _typeof3(i)) {
			return i;
		}
		throw new TypeError("@@toPrimitive must return a primitive value.");
	}
	return ("string" === r ? String : Number)(t);
}
function _classCallCheck2(instance, Constructor) {
	if (!(instance instanceof Constructor)) {
		throw new TypeError("Cannot call a class as a function");
	}
}
function _callSuper2(t, o, e) {
	return o = _getPrototypeOf2(o), _possibleConstructorReturn2(t, _isNativeReflectConstruct2() ? Reflect.construct(o, e || [], _getPrototypeOf2(t).constructor) : o.apply(t, e));
}
function _possibleConstructorReturn2(self, call) {
	if (call && (_typeof3(call) === "object" || typeof call === "function")) {
		return call;
	} else if (call !== void 0) {
		throw new TypeError("Derived constructors may only return object or undefined");
	}
	return _assertThisInitialized2(self);
}
function _assertThisInitialized2(self) {
	if (self === void 0) {
		throw new ReferenceError("this hasn't been initialised - super() hasn't been called");
	}
	return self;
}
function _isNativeReflectConstruct2() {
	try {
		var t = !Boolean.prototype.valueOf.call(Reflect.construct(Boolean, [], function () {}));
	} catch (t) {}
	return (_isNativeReflectConstruct2 = function _isNativeReflectConstruct2() {
		return !!t;
	})();
}
function _getPrototypeOf2(o) {
	_getPrototypeOf2 = Object.setPrototypeOf ? Object.getPrototypeOf.bind() : function _getPrototypeOf(o) {
		return o.__proto__ || Object.getPrototypeOf(o);
	};
	return _getPrototypeOf2(o);
}
function _inherits2(subClass, superClass) {
	if (typeof superClass !== "function" && superClass !== null) {
		throw new TypeError("Super expression must either be null or a function");
	}
	subClass.prototype = Object.create(superClass && superClass.prototype, {
		constructor: {
			value: subClass,
			writable: true,
			configurable: true
		}
	});
	Object.defineProperty(subClass, "prototype", {
		writable: false
	});
	if (superClass) {
		_setPrototypeOf2(subClass, superClass);
	}
}
function _setPrototypeOf2(o, p) {
	_setPrototypeOf2 = Object.setPrototypeOf ? Object.setPrototypeOf.bind() : function _setPrototypeOf(o, p) {
		o.__proto__ = p;
		return o;
	};
	return _setPrototypeOf2(o, p);
}
var SagaMap = /*#__PURE__*/function (_Container) {
	_inherits(SagaMap, _Container);
	function SagaMap() {
		var _this;
		_classCallCheck(this, SagaMap);
		_this = _callSuper(this, SagaMap);
		_this.levels = [];
		_this.currentLevel = 0;
		return _this;
	}
	_createClass(SagaMap, [{
		key: "addLevel",
		value: function addLevel(level) {
			this.levels.push(level);
		}
	}, {
		key: "goToLevel",
		value: function goToLevel(index) {
			this.currentLevel = index;
			// Logic to switch to the specified level
			console.log('Switching to level:', index);
		}
	}, {
		key: "nextLevel",
		value: function nextLevel() {
			if (this.currentLevel < this.levels.length - 1) {
				this.goToLevel(this.currentLevel + 1);
			} else {
				console.log('No more levels!');
			}
		}
	}]);
	return SagaMap;
}(Container);
function _typeof2(o) {
	"@babel/helpers - typeof";
	return _typeof2 = "function" == typeof Symbol && "symbol" == typeof Symbol.iterator ? function (o) {
		return typeof o;
	} : function (o) {
		return o && "function" == typeof Symbol && o.constructor === Symbol && o !== Symbol.prototype ? "symbol" : typeof o;
	}, _typeof2(o);
}
function _classCallCheck(instance, Constructor) {
	if (!(instance instanceof Constructor)) {
		throw new TypeError("Cannot call a class as a function");
	}
}
function _defineProperties(target, props) {
	for (var i = 0; i < props.length; i++) {
		var descriptor = props[i];
		descriptor.enumerable = descriptor.enumerable || false;
		descriptor.configurable = true;
		if ("value" in descriptor) {
			descriptor.writable = true;
		}
		Object.defineProperty(target, _toPropertyKey2(descriptor.key), descriptor);
	}
}
function _createClass(Constructor, protoProps, staticProps) {
	if (protoProps) {
		_defineProperties(Constructor.prototype, protoProps);
	}
	if (staticProps) {
		_defineProperties(Constructor, staticProps);
	}
	Object.defineProperty(Constructor, "prototype", {
		writable: false
	});
	return Constructor;
}
function _toPropertyKey2(t) {
	var i = _toPrimitive2(t, "string");
	return "symbol" == _typeof2(i) ? i : String(i);
}
function _toPrimitive2(t, r) {
	if ("object" != _typeof2(t) || !t) {
		return t;
	}
	var e = t[Symbol.toPrimitive];
	if (void 0 !== e) {
		var i = e.call(t, r || "default");
		if ("object" != _typeof2(i)) {
			return i;
		}
		throw new TypeError("@@toPrimitive must return a primitive value.");
	}
	return ("string" === r ? String : Number)(t);
}
function _callSuper(t, o, e) {
	return o = _getPrototypeOf(o), _possibleConstructorReturn(t, _isNativeReflectConstruct() ? Reflect.construct(o, e || [], _getPrototypeOf(t).constructor) : o.apply(t, e));
}
function _possibleConstructorReturn(self, call) {
	if (call && (_typeof2(call) === "object" || typeof call === "function")) {
		return call;
	} else if (call !== void 0) {
		throw new TypeError("Derived constructors may only return object or undefined");
	}
	return _assertThisInitialized(self);
}
function _assertThisInitialized(self) {
	if (self === void 0) {
		throw new ReferenceError("this hasn't been initialised - super() hasn't been called");
	}
	return self;
}
function _isNativeReflectConstruct() {
	try {
		var t = !Boolean.prototype.valueOf.call(Reflect.construct(Boolean, [], function () {}));
	} catch (t) {}
	return (_isNativeReflectConstruct = function _isNativeReflectConstruct() {
		return !!t;
	})();
}
function _getPrototypeOf(o) {
	_getPrototypeOf = Object.setPrototypeOf ? Object.getPrototypeOf.bind() : function _getPrototypeOf(o) {
		return o.__proto__ || Object.getPrototypeOf(o);
	};
	return _getPrototypeOf(o);
}
function _inherits(subClass, superClass) {
	if (typeof superClass !== "function" && superClass !== null) {
		throw new TypeError("Super expression must either be null or a function");
	}
	subClass.prototype = Object.create(superClass && superClass.prototype, {
		constructor: {
			value: subClass,
			writable: true,
			configurable: true
		}
	});
	Object.defineProperty(subClass, "prototype", {
		writable: false
	});
	if (superClass) {
		_setPrototypeOf(subClass, superClass);
	}
}
function _setPrototypeOf(o, p) {
	_setPrototypeOf = Object.setPrototypeOf ? Object.setPrototypeOf.bind() : function _setPrototypeOf(o, p) {
		o.__proto__ = p;
		return o;
	};
	return _setPrototypeOf(o, p);
}
var SagaMap = /*#__PURE__*/function (_Container) {
	_inherits(SagaMap, _Container);
	function SagaMap() {
		var _this;
		_classCallCheck(this, SagaMap);
		_this = _callSuper(this, SagaMap);
		_this.levels = [];
		_this.currentLevel = 0;
		return _this;
	}
	_createClass(SagaMap, [{
		key: "addLevel",
		value: function addLevel(level) {
			this.levels.push(level);
		}
	}, {
		key: "goToLevel",
		value: function goToLevel(index) {
			this.currentLevel = index;
			// Logic to switch to the specified level
			console.log('Switching to level:', index);
		}
	}, {
		key: "nextLevel",
		value: function nextLevel() {
			if (this.currentLevel < this.levels.length - 1) {
				this.goToLevel(this.currentLevel + 1);
			} else {
				console.log('No more levels!');
			}
		}
	}]);
	return SagaMap;
}(Container);
var dragonSpawnTimer;
var isDragoning = false;
function triggerDragon() {
	if (dragonSpawnTimer) {
		LK.clearTimeout(dragonSpawnTimer);
	}
	if (!isDragoning && board && board.gems && board.gems.length > 0) {
		isDragoning = true;
		var randomIndex = Math.floor(Math.random() * board.gems.length);
		var gemToRemove = board.gems[randomIndex];
		if (gemToRemove) {
			var dragon = new Dragon(gemToRemove);
			dragon.x = -100; // Ensure dragon starts off-screen to the left
			dragon.y = gemToRemove.y; // Random y position within game bounds
			game.addChild(dragon);
			dragon._move_migrated();
		}
	}
	var nextSpawnTime = 5000 + Math.random() * 10000; // Random interval between 5 to 15 seconds
	dragonSpawnTimer = LK.setTimeout(triggerDragon, nextSpawnTime);
}
triggerDragon();
var goalGemType;
var matchedGemCount = 0;
var hintTimer;
var currentGoalGemSprite = false;
var goalLevel = 0;
// Function to randomly set the goal gem type from the available gem colors
function setRandomGoalGemType() {
	var gemColors = ['gemBlue', 'gemGreen', 'gemRed', 'gemPurple', 'gemYellow', 'gemOrange', 'gemCyan'];
	goalGemType = gemColors[Math.floor(Math.random() * gemColors.length)];
	goalGemCount = 3 + Math.floor(Math.random() * goalLevel);
	matchedGemCount = 0;
	LK.setTimeout(function () {
		// Update the goal text with the chosen gem type
		goalTxt.setText(matchedGemCount + '/' + goalGemCount);
		// Add hourglass sprite next to the timer
		if (currentGoalGemSprite) {
			currentGoalGemSprite.destroy();
		}
		currentGoalGemSprite = LK.getAsset(goalGemType, {
			x: 2048 - 100,
			// Position next to the timer
			y: 50,
			// Align with the timer's top margin
			anchorX: .5,
			// Anchor right for right alignment
			anchorY: .5 // Anchor top for top alignment
		});
		currentGoalGemSprite.y = goalTxt.y;
		currentGoalGemSprite.x = goalBackground.x; // Position next to the timer
		currentGoalGemSprite.anchor.set(0.5, 0.5); // Align with the timer's top margin
		currentGoalGemSprite.rotation = -.2;
		currentGoalGemSprite.scale.set(1.6);
		if (goalBackground.parent) {
			goalBackground.parent.removeChild(goalBackground);
		}
		if (goalTxt.parent) {
			goalTxt.parent.removeChild(goalTxt);
		}
		if (currentGoalGemSprite.parent) {
			currentGoalGemSprite.parent.removeChild(currentGoalGemSprite);
		}
		LK.setTimeout(function () {
			board.addChild(goalBackground);
			game.addChild(goalBackground);
			game.addChild(goalTxt);
			game.addChild(currentGoalGemSprite);
		}, 1000);
	}, 1000);
}
// setRandomGoalGemType(); // Initialize the goal gem type at the start of the game
// This call has been moved to after the definition of goalTxt to fix the bug
// Function to reset and start the hint timer
function resetHintTimer() {
	if (hintTimer) {
		LK.clearTimeout(hintTimer);
	}
	hintTimer = LK.setTimeout(function () {
		board.showHint();
		resetHintTimer();
	}, 5000); // Show hint after 5 seconds of inactivity
}
resetHintTimer();
// Reset the hint timer whenever a move is made
LK.on('tick', function () {
	// This is a placeholder for any game action, e.g., gem swap, that resets the hint timer
	// resetHintTimer();
});
function _typeof(o) {
	"@babel/helpers - typeof";
	return _typeof = "function" == typeof Symbol && "symbol" == typeof Symbol.iterator ? function (o) {
		return typeof o;
	} : function (o) {
		return o && "function" == typeof Symbol && o.constructor === Symbol && o !== Symbol.prototype ? "symbol" : typeof o;
	}, _typeof(o);
}
function _defineProperty(obj, key, value) {
	key = _toPropertyKey(key);
	if (key in obj) {
		Object.defineProperty(obj, key, {
			value: value,
			enumerable: true,
			configurable: true,
			writable: true
		});
	} else {
		obj[key] = value;
	}
	return obj;
}
function _toPropertyKey(t) {
	var i = _toPrimitive(t, "string");
	return "symbol" == _typeof(i) ? i : String(i);
}
function _toPrimitive(t, r) {
	if ("object" != _typeof(t) || !t) {
		return t;
	}
	var e = t[Symbol.toPrimitive];
	if (void 0 !== e) {
		var i = e.call(t, r || "default");
		if ("object" != _typeof(i)) {
			return i;
		}
		throw new TypeError("@@toPrimitive must return a primitive value.");
	}
	return ("string" === r ? String : Number)(t);
}
var welcomeText = new Text2("Magic Potions Match", {
	size: 110,
	fill: "#ffff00",
	x: 1024,
	// Center of the screen
	y: 1366,
	// Middle of the screen
	anchorX: 0.5,
	anchorY: 0.5,
	stroke: true,
	weight: 800,
	dropShadow: true,
	dropShadowDistance: 20,
	strokeColor: '#ff0000',
	strokeThickness: 14
});
welcomeText.anchor.set(.5);
LK.gui.center.addChild(welcomeText); // Add countdown display to the center GUI layer
welcomeText.y = -200;
var countdownValue = 3; // Start countdown from 3
var countdownTxt = new Text2(countdownValue.toString(), {
	size: 300,
	fill: "#ffffff",
	x: 1024,
	// Center of the screen
	y: 1366,
	// Middle of the screen
	anchorX: 0.5,
	anchorY: 0.5,
	stroke: true,
	weight: 800,
	dropShadow: true,
	strokeThickness: 14
});
countdownTxt.anchor.set(.5);
LK.gui.center.addChild(countdownTxt); // Add countdown display to the center GUI layer
var countdownInterval = LK.setInterval(function () {
	countdownValue -= 1;
	if (countdownValue > 0) {
		countdownTxt.setText(countdownValue.toString());
		// Bounce effect for countdown numbers
		var scaleUpDuration = 100; // Duration to scale up in milliseconds
		var scaleDownDuration = 100; // Duration to scale down in milliseconds
		var maxScale = 1.2; // Maximum scale factor
		var originalScale = 1; // Remember the original scale
		var scaleUp = function scaleUp() {
			var startTime = Date.now();
			var scaleStep = function scaleStep() {
				var currentTime = Date.now();
				var progress = Math.min(1, (currentTime - startTime) / scaleUpDuration);
				countdownTxt.scale.set(originalScale + (maxScale - originalScale) * progress);
				if (progress < 1) {
					LK.setTimeout(scaleStep, 16);
				} else {
					scaleDown();
				}
			};
			scaleStep();
		};
		var scaleDown = function scaleDown() {
			var startTime = Date.now();
			var scaleStep = function scaleStep() {
				var currentTime = Date.now();
				var progress = Math.min(1, (currentTime - startTime) / scaleDownDuration);
				countdownTxt.scale.set(maxScale - (maxScale - originalScale) * progress);
				if (progress < 1) {
					LK.setTimeout(scaleStep, 16);
				}
			};
			scaleStep();
		};
		scaleUp();
	} else if (countdownValue === 0) {
		var triggerFirework = function triggerFirework(fireworkDelay) {
			LK.setTimeout(function () {
				var x = -300 + Math.random() * 600;
				var y = -500 + Math.random() * 1000;
				var colors = [0xFFFFFF, 0xFF0000, 0x00FF00, 0xddddFF, 0xFFFF00, 0xFF00FF];
				var color = colors[Math.floor(Math.random() * colors.length)];
				var fireworkEffect = new FireworkEffect(x, y, 50, color);
				LK.gui.center.addChild(fireworkEffect);
			}, fireworkDelay);
		};
		;
		countdownTxt.setText('Welcome little witch!');
		countdownTxt.y = -50;
		countdownTxt.setStyle({
			size: 90,
			fill: "#ffffff",
			x: 1024,
			// Center of the screen
			y: 1366,
			// Middle of the screen
			anchorX: 0.5,
			anchorY: 0.5,
			stroke: true,
			weight: 800,
			dropShadow: true,
			dropShadowDistance: 20,
			strokeColor: '#ff0000',
			strokeThickness: 14
		});
		// Trigger firework effects at various places on the screen
		for (var i = 0; i < 16; i++) {
			triggerFirework(i * 100 + Math.random() * 500);
		}
		spinHourglass();
		// Bounce effect
		var scaleUpDuration = 1200; // Duration to scale up in milliseconds
		var scaleDownDuration = 200; // Duration to scale down in milliseconds
		var maxScale = 2; // Maximum scale factor
		var originalScale = 1; // Remember the original scale
		var scaleUp = function scaleUp() {
			var startTime = Date.now();
			var scaleStep = function scaleStep() {
				var currentTime = Date.now();
				var progress = Math.min(1, (currentTime - startTime) / scaleUpDuration);
				countdownTxt.scale.set(originalScale + (maxScale - originalScale) * progress);
				if (progress < 1) {
					LK.setTimeout(scaleStep, 16);
				} else {
					//scaleDown();
				}
			};
			scaleStep();
		};
		var scaleDown = function scaleDown() {
			var fadeOutDuration = 1000; // Duration for the fade out in milliseconds
			var startTime = Date.now();
			var fadeStep = function fadeStep() {
				var currentTime = Date.now();
				var progress = Math.min(1, (currentTime - startTime) / fadeOutDuration);
				countdownTxt.alpha = 1 - progress; // Fade out
				welcomeText.alpha = 1 - progress; // Fade out
				if (progress < 1) {
					LK.setTimeout(fadeStep, 16);
				} else {
					welcomeText.destroy(); // Remove countdown text after animation
					countdownTxt.destroy(); // Remove countdown text after animation
					LK.clearInterval(countdownInterval);
					setRandomGoalGemType();
				}
			};
			fadeStep();
		};
		LK.setTimeout(scaleDown, 200);
		scaleUp();
	}
}, 1000); // Update countdown every second
game.timer = 5; //120; // 2 minutes in seconds
// Implement a three second delay before starting the timer text interval
LK.setTimeout(function () {
	// Timer control is now handled inside the modal display logic to pause during the modal display.
}, 3000);
var score = 0; // Starting score
var scoreBg;
var scoreBgNode = LK.getAsset('scoreBg', {
	x: 1024 - 150,
	// Centered based on the background size
	y: 0,
	anchorX: 0.5,
	anchorY: 0
});
scoreBgNode.anchor.set(.5);
scoreBgNode.y = 50;
scoreBgNode.alpha = 1; // Set the background transparency to fully opaque to ensure visibility
LK.gui.top.addChild(scoreBgNode);
var scoreTxt = new Text2(score.toString(), _defineProperty(_defineProperty({
	size: 110,
	weight: 500,
	fill: "#ffffff",
	x: 1024,
	// Center of the screen
	y: 0,
	// Adjusted to be within the background
	anchorX: 0.5,
	// Center horizontally
	anchorY: 0,
	// Anchor at the top
	dropShadow: true,
	dropShadowColor: '#000000',
	shadowBlur: 4,
	shadowOffsetX: 2,
	shadowOffsetY: 2,
	stroke: true,
	strokeColor: '#000000'
}, "stroke", '#000000'), "strokeThickness", 7));
scoreTxt.anchor.set(.5, .5);
scoreTxt.y = 50;
LK.gui.top.addChild(scoreTxt); // Add score display to the top GUI layer
// List of background images for different goal levels
var backgroundImages = ['magicalBackground', 'enchantedForest', 'mysticCave', 'celestialRealm'];
// Function to update the game background according to the current goal level
function updateBackground() {
	var backgroundImageId = backgroundImages[goalLevel % backgroundImages.length];
	var oldBackground = game.background;
	if (oldBackground) {
		LK.setTimeout(function () {
			oldBackground.destroy();
		}, 1000);
	}
	var background = LK.getAsset(backgroundImageId, {
		anchorX: 0.5,
		anchorY: 0.5
	});
	background.x = game.width / 2;
	background.y = game.height / 2;
	background.scale.set(Math.max(game.height / background.height, game.width / background.width));
	background.alpha = 0; // Start fully transparent
	var fadeInDuration = 1000; // Duration for the fade in milliseconds
	var fadeInStartTime = Date.now();
	var fadeInStep = function fadeInStep() {
		var currentTime = Date.now();
		var progress = (currentTime - fadeInStartTime) / fadeInDuration;
		background.alpha = progress; // Fade in
		if (progress < 1) {
			LK.setTimeout(fadeInStep, 16);
		} else {
			background.alpha = 1;
			if (oldBackground) {}
		}
	};
	fadeInStep();
	// This line is removed to prevent script errors related to incorrect usage of addChildAt.
	// Instead, we'll use addChild and manage layering through careful addition order.
	game.addChildAt(background, Math.min(1, game.children.length));
	game.background = background;
}
// Initially set the background
updateBackground();
// Add the game board background to the game
var gameBoardBg = game.addChild(LK.getAsset('gameBoardBg', {
	x: 0,
	y: 0,
	anchorX: 0,
	anchorY: 0
}));
gameBoardBg.width = game.width * 0.9;
gameBoardBg.height = game.height * 0.9;
gameBoardBg.x = (game.width - gameBoardBg.width) / 2;
gameBoardBg.y = (game.height - gameBoardBg.height) / 2 + 80;
gameBoardBg.alpha = 0.6; // Set the background transparency to make it slightly visible
// Initialize the board
// Define assets for the game
var board = new Board();
game.addChild(board);
board.initBoard();
function animateGemsInWave(board) {
	for (var i = 0; i < 8; i++) {
		for (var j = 0; j < 6; j++) {
			var gem = board.gems[i * 6 + j];
			if (gem && typeof gem.scaleUpAndDown === 'function') {
				gem.scaleUpAndDown((i + j) * 50);
			}
		}
	}
}
animateGemsInWave(board);
// Game logic
LK.on('tick', function () {
	// Add game logic that needs to run every frame
	// For example, checking for matches, handling animations, etc.
});
// Add a label with the same styling as the timer text, but with the opposite x-coordinate
var goalTxt = new Text2('', {
	size: 100,
	weight: 500,
	fill: "#ffffff",
	x: 0,
	// Opposite x-coordinate
	y: 50,
	anchorX: 0,
	anchorY: 0,
	dropShadow: true,
	dropShadowColor: '#000000',
	shadowBlur: 4,
	shadowOffsetX: 2,
	shadowOffsetY: 2,
	strokeThickness: 7
});
board.addChild(goalTxt);
goalTxt.anchor.set(0, .5);
goalTxt.y = 100;
goalTxt.x = 450;
// Add hourglass sprite next to the timer
var goalBackground = LK.getAsset('goalBackgroundSprite', {
	x: 2048 - 100,
	// Position next to the timer
	y: 50,
	// Align with the timer's top margin
	anchorX: .5,
	// Anchor right for right alignment
	anchorY: .5 // Anchor top for top alignment
});
goalBackground.y = goalTxt.y;
goalBackground.x = goalTxt.x - 100; // Position next to the timer
goalBackground.anchor.set(0.5, 0.5); // Align with the timer's top margin
goalBackground.alpha = .6;
var timerTxt = new Text2(game.timer.toString(), {
	size: 100,
	// Made the text smaller
	weight: 500,
	fill: "#ffffff",
	x: 2048 - 200,
	y: 50,
	anchorX: 1,
	anchorY: 0,
	dropShadow: true,
	dropShadowColor: '#000000',
	shadowBlur: 4,
	shadowOffsetX: 2,
	shadowOffsetY: 2,
	strokeThickness: 7
});
// Add hourglass sprite next to the timer
var hourglassSprite = LK.getAsset('hourglass', {
	x: 2048 - 100,
	// Position next to the timer
	y: 50,
	// Align with the timer's top margin
	anchorX: .5,
	// Anchor right for right alignment
	anchorY: .5 // Anchor top for top alignment
});
function stopTimer() {
	if (board.timerInterval) {
		LK.clearInterval(board.timerInterval);
	}
}
function startTimer() {
	// Resume the game timer after the modal disappears
	stopTimer();
	board.timerInterval = LK.setInterval(function () {
		game.timer -= 1;
		timerTxt.setText(game.timer.toString());
		if (game.timer <= 0) {
			//LK.showGameOver('Final Score: ' + score);
			showScore();
		}
	}, 1000);
}
// Logic to spin the hourglass
var spinHourglass = function spinHourglass() {
	var rotationDuration = 500; // Duration of the spin in milliseconds
	var startTime = Date.now();
	var spinStep = function spinStep() {
		var currentTime = Date.now();
		var progress = (currentTime - startTime) / rotationDuration;
		hourglassSprite.rotation = progress * 2 * Math.PI; // Complete rotation
		if (progress < 1) {
			LK.setTimeout(spinStep, 16); // Aim for roughly 60fps
		} else {
			hourglassSprite.rotation = 0;
			startTimer();
		}
	};
	spinStep();
};
board.addChild(hourglassSprite);
timerTxt.anchor.set(1, .5);
timerTxt.y = 100;
timerTxt.x = 2048 - 240;
board.addChild(timerTxt); // Add timer display to the top GUI layer
hourglassSprite.y = timerTxt.y;
hourglassSprite.x = timerTxt.x + 70; // Position next to the timer
hourglassSprite.anchor.set(0.5, 0.5); // Align with the timer's top margin ===================================================================
--- original.js
+++ change.js
@@ -1559,8 +1559,14 @@
 ****/ 
 // Function to show the current score
 function showScore() {
 	stopTimer();
+	if (isDragoning) {
+		isDragoning = false;
+		if (dragonSpawnTimer) {
+			LK.clearTimeout(dragonSpawnTimer);
+		}
+	}
 	board.gems.forEach(function (gem) {
 		if (gem) {
 			gem.visible = false;
 		}
:quality(85)/https://cdn.frvr.ai/65cfb5efb370066057b9a334.png%3F3) 
 glow. Single Game Texture. In-Game asset. 2d. Blank background. High contrast. No shadows.
:quality(85)/https://cdn.frvr.ai/65d20e041a671a66cfbe85eb.png%3F3) 
 Glow glare star. Single Game Texture. In-Game asset. 2d. Blank background. High contrast. No shadows.
:quality(85)/https://cdn.frvr.ai/65d2d5c4cd9a1b6ee5942e71.png%3F3) 
 Shiny red envelope bao, chinese new years. Single Game Texture. In-Game asset. 2d. Blank background. High contrast. No shadows.
:quality(85)/https://cdn.frvr.ai/65d388a753acf798b193f756.png%3F3) 
 Brilliant Gold Checkmark. Single Game Texture. In-Game asset. 2d. Blank background. High contrast. No shadows.
:quality(85)/https://cdn.frvr.ai/65d5a2ea86d309c4969c3c57.png%3F3) 
 Mystic cavern. Single Game Texture. In-Game asset. 2d. Blank background. High contrast. No shadows.
:quality(85)/https://cdn.frvr.ai/669fec8f2d9b858094241dd7.png%3F3) 
 ponssion magique. Single Game Texture. In-Game asset. 2d. Blank background. High contrast. No shadows.
:quality(85)/https://cdn.frvr.ai/669fee732d9b858094241dea.png%3F3) 
 :quality(85)/https://cdn.frvr.ai/66aa0339f88bbc6bb41e1154.png%3F3) 
 potion magique orange. Single Game Texture. In-Game asset. 2d. Blank background. High contrast. No shadows.
:quality(85)/https://cdn.frvr.ai/66aa0449f88bbc6bb41e1161.png%3F3) 
 potion magique rouge. Single Game Texture. In-Game asset. 2d. Blank background. High contrast. No shadows.
:quality(85)/https://cdn.frvr.ai/66aa04d1f88bbc6bb41e116c.png%3F3) 
 potion magique violette. Single Game Texture. In-Game asset. 2d. Blank background. High contrast. No shadows.
:quality(85)/https://cdn.frvr.ai/66aa0543f88bbc6bb41e117d.png%3F3) 
 :quality(85)/https://cdn.frvr.ai/66aa05c7f88bbc6bb41e1193.png%3F3) 
 potion magique blanche lumineuse. Single Game Texture. In-Game asset. 2d. Blank background. High contrast. No shadows.
:quality(85)/https://cdn.frvr.ai/66aa0758f88bbc6bb41e11b6.png%3F3) 
 une sorciere mignone qui tape des mains. Single Game Texture. In-Game asset. 2d. Blank background. High contrast. No shadows.
:quality(85)/https://cdn.frvr.ai/66aa0fa2f88bbc6bb41e11e7.png%3F3) 
 une étoile en cristal. Single Game Texture. In-Game asset. 2d. Blank background. High contrast. No shadows.
:quality(85)/https://cdn.frvr.ai/66aa1214f88bbc6bb41e11fc.png%3F3) 
 une étoile en cristal blanc. Single Game Texture. In-Game asset. 2d. Blank background. High contrast. No shadows.
:quality(85)/https://cdn.frvr.ai/66af90172cdeab3e3e274360.png%3F3) 
 bat flying.
:quality(85)/https://cdn.frvr.ai/66afb2222cdeab3e3e2743b4.png%3F3) 
 :quality(85)/https://cdn.frvr.ai/66afb2aa2cdeab3e3e2743b8.png%3F3) 
 atelier de sorciere. Single Game Texture. In-Game asset. 2d. Blank background. High contrast. No shadows.
:quality(85)/https://cdn.frvr.ai/66afb4262cdeab3e3e2743c7.png%3F3) 
 atelier de sorciere. Single Game Texture. In-Game asset. 2d. Blank background. High contrast. No shadows.