User prompt
Game Background is Still Missing or Misplaced (Most Basic Issue): The code creates the game board (gameBoardContainer) and correctly shifts it right/down as requested. However, there is still no code to create a background image or color and place it correctly behind the game board. This means the game either has the default background color or, if a background is defined elsewhere, it's likely in the wrong position. This is a fundamental visual flaw. Activating Special Candies Freezes/Breaks the Game (Most Critical Gameplay Issue): When you match special candies (striped, color bomb), their powers start to activate (activateSpecialCandy). However, this activation happens asynchronously (out of sync) and incorrectly with the game's normal processing flow (match -> pop -> drop -> fill -> check again). The code doesn't wait for the special power's full effect (e.g., all pops from a row clear) to finish before proceeding with the next steps. This will very likely cause the game to freeze, crash, or behave completely erratically after using a special candy. Game Proceeds Before Striped/Color Bomb Effects Finish: Even though the special power effects (popping candies) begin, the game doesn't wait for these additional pops to complete. For example, while a striped candy is clearing a row, new candies might start falling from the bottom, or the game might check for new matches before the row is even fully cleared. This is directly related to the previous point and breaks the game flow. Selection Highlight Doesn't Fully Work: Highlighting the cell yellow when selected is good, but: When you try an invalid swap (candies move back) or deselect by clicking elsewhere, the yellow highlight doesn't revert to the original cell color; it stays yellow incorrectly. While less likely, there's a small chance the game engine doesn't properly support .tint on the cell shapes, meaning the highlight might not work at all. Game Board Background Size vs. Grid Size (Corrected): In the GameBoard class, the size of the visual background (boardVisual) now correctly matches the size of the actual candy grid (CELL_SIZE * rows/cols). The previous issue of the background being 20% larger seems fixed in this version. (If there's still an unwanted border, it might be due to positioning within the container). Level Objectives Still Non-Functional: Level objectives (jelly, ingredients) are mentioned in the code but have no impact on gameplay. There's no mechanism to track if you've completed them or win the level based on them. Winning is still only based on score. Animation Waiting System (Callbacks) is Complex and Risky: The code now uses a manual counter system instead of Promises to wait for animations. While this avoids Promise errors, it can be more prone to timing mistakes, especially when combined with the unsynchronized activation of special candy effects. There's still a risk of minor glitches or stutters in the game flow. Special Candies Persist After Reshuffling: Special candies remain special when the board is reshuffled. This now seems like a consistent and likely intended design choice. Unused Code: The isDropping variable is still defined but seems unused. In Summary: The most urgent and critical problems are the complete lack of a game background and the fact that activating special candies breaks the game's sequence, likely leading to freezes or crashes. The selection highlight not reverting is also a clear bug. Other issues like non-functional level objectives and potentially imperfect animation timing are less critical but still need addressing for a polished game.
User prompt
remove the game background.
User prompt
The game background must be moved to coordinates (x: 648, y: 990) to align with the game board and sit directly behind it. This ensures the background matches the new position of the game board, which has been centered and then shifted 200 pixels right and 200 pixels down.
User prompt
remove the game background.
User prompt
remove the game background.
User prompt
Bug Report: Game Background Incorrectly Layered and Positioned Issue Detected: The game's background (color or image) is currently appearing in front of or overlapping the game board (gameBoardContainer), instead of being correctly positioned behind it as expected. This obstructs the view of the game board and candies, making the game difficult or impossible to play. Expected Behavior: The game background should visually reside as the bottom-most layer, behind all other game elements (game board, candies, UI elements, etc.). Positioning Issue: Furthermore, since the game board has been intentionally shifted 200 pixels to the right and 200 pixels down from the screen's exact center (resulting in an approximate board center at coordinates 1224, 1566), the background must also be aligned with this specific shifted position. The background being both on the wrong layer and potentially at the wrong (e.g., centered or default) coordinates exacerbates the problem. Likely Cause: Adding Order: The background object might be added to the game stage using game.addChild after the gameBoardContainer is added. To be behind, it must be added before. Positioning: The background's x and y coordinates might not have been set to match the calculated shifted coordinates of the gameBoardContainer (approximately 1224, 1566). Suggested Fix: Within the setupGame function: Create the background object. Set the background's x and y coordinates to the same calculated, shifted x and y values used for the gameBoardContainer. Add the background object to the game stage using game.addChild first (before anything else). Subsequently, add the gameBoardContainer and other game elements.
User prompt
you will change the game background position. The location of the playground will remain the same. The location of the game background will move to the same place as the game background.
User prompt
the game background must be exactly in the same position as the playing field.
User prompt
It should be in the same place where it says Level. Playground in the horizontal plane.
User prompt
"Shift the game area right" or "Move the game area to the right" "Shift [it/the game area] down" or "Move [it/the game area] down"
User prompt
Please fix the bug: 'Uncaught ReferenceError: isDropping is not defined' in or related to this line: 'if (game && typeof game.handleCandyClick === 'function' && !isSwapping && !isDropping) {' Line Number: 181
User prompt
Activating Special Candies Likely Breaks/Freezes the Game (Most Critical Issue): When you match a special candy (striped, color bomb), its power now tries to activate (activateSpecialCandy). However, this activation happens concurrently and out of sequence with the game's normal flow (finish match -> wait for pops -> drop candies -> fill gaps -> check for new matches). The code attempts to activate the special power with a small delay (setTimeout), but it doesn't properly integrate this into the main game loop or wait for the special power's effects (like clearing a row) to finish before proceeding. This will almost certainly cause the game to freeze, crash, or enter a highly unpredictable state after a special candy is activated, as the normal game flow and the special power interfere with each other. Striped Candy Effect Doesn't Wait Properly: While the striped candy effect now has delays added to the pops (pop(col * 50, ...)), the main game loop doesn't wait for all these delayed pops to complete before potentially moving on to the handleDrops or handleFills stages. This is part of the core timing issue mentioned in point 1. Color Bomb Timing is Also Flawed: It's good that the color bomb now targets the swapped color (using candy.swappedWithType)! But, like the striped candy, activating it via setTimeout is not synchronized correctly with the game's processing sequence (processBoard -> handleMatches -> handleDrops -> handleFills). The game won't wait for the color bomb to finish clearing candies before continuing its steps. Cell Selection Highlight Might Not Fully Work: Highlighting the cell background (tint = 0xffff00) is implemented, which is great. However: The code to revert the highlight back to the original color (tint = 0x704f3d) is missing when an invalid swap occurs (candies move back) or potentially when clicking off the board to deselect. The cell might stay yellow incorrectly. There's still a possibility that the specific rendering engine or framework you're using might not fully support or update the .tint property on the cellBackground shapes as expected. If the highlight isn't appearing, this could be why. Animation Waiting Mechanism Still Potentially Unreliable: The system for waiting for animations using nested callbacks and counters (the (function(promises, callback) { ... }) structure) is an alternative to Promises but can still be fragile, especially with the added complexity of delayed special effects. There's still a risk of minor timing issues or race conditions in complex chain reactions. Game Board Background Size Mismatch: In the GameBoard class, the visual background (boardVisual) width and height are increased by 20% (* 1.2). However, the grid where candies are placed still uses the standard CELL_SIZE. This mismatch means the background graphic will be larger than the actual playing grid, creating an unnecessary visual border or frame around the cells. These sizes should typically match. Level Objectives Still Not Implemented: The objectives variable is defined in initializeLevel, but the game logic doesn't actually check or use these objectives (like clearJellies or bringIngredients). The only win condition remains reaching the targetScore. Special Candies Remain After Shuffling: Special candies now correctly persist after a reshuffle (the isSpecial: candy.isSpecial line was added back). This is likely the intended behavior. Unused Code: The isDropping variable is still present and appears unused. In Summary: The most critical issue is the timing and synchronization of special candy activations, which will likely break the game flow. Cell highlighting needs refinement for deselection/invalid swaps. The board background size is inconsistent with the grid. Animation timing might still have subtle issues, and level objectives are not functional.
User prompt
Game Background is in the Wrong Place: This is indeed a major issue. The game's background image or color, which should always be behind everything else, is currently appearing in front of the game board and candies, or mixed up with them. This obviously blocks the view of the game and looks very bad. Solution: The code needs to ensure that the background is created or added before the game board and all other game elements are added. It needs to be the bottom-most layer. Game Board is in the Top-Left, Not Centered: As you pointed out, the game board, which should be in the exact middle of the screen, is currently positioned somewhere near the top-left corner. This looks unbalanced and makes playing awkward. Solution: The calculation that sets the board's position (gameBoardContainer.x and gameBoardContainer.y) needs to be fixed. The x and y values should be calculated using the actual screen width and height to place the board precisely in the center. The current calculation is likely incorrect or incomplete.
User prompt
Larger Game Area: Making the candy grid take up a larger portion of the screen helps the player see the details (candy colors, types) more clearly and focus better on the game. Playing in a small area can be tiring for the eyes and lead to misclicks. Clear Boundaries and Position: It should be obvious where the game area is on the screen. Having too much empty space around the edges or having the board tucked into a corner can look messy and make the player wonder "where does the game actually end?". Centered Position: Placing the grid exactly in the middle of the screen looks more visually balanced and professional. It also makes interaction easier because the player is roughly equidistant from all parts of the board, especially when trying to reach candies near the edges. A board shifted too far left or right can be awkward to use. In summary: Making the game board appear larger, centering it perfectly on the screen, and ensuring its boundaries are clear will both make the game look better and feel much more comfortable and enjoyable to play. This allows the player to have better control and focus. Implementing these changes would likely involve adjusting the x and y coordinate calculations for the gameBoardContainer in the setupGame function, and possibly modifying the CELL_SIZE or the overall game scaling. Calculating the position dynamically based on the screen dimensions usually gives the best results.
User prompt
Currently, when a candy is selected, the candy itself gets an overlay (selectedOverlay). As you said, if the candies look similar, or if there are slight movements during animations, it can sometimes be difficult for players to be certain exactly which grid square the selected candy occupies. They might get confused about which one they actually clicked. Highlighting the underlying grid cell/square instead of the candy itself offers several advantages: Clearer Positional Information: It makes it 100% clear which square on the grid is selected. This is crucial, especially when selecting the second candy for the swap. Less Visual Confusion: Regardless of the candy's shape or color, the selected area is always a distinct, static square. This reduces visual clutter. Easier Targeting: When clicking the second candy, it's easier to see which square you are aiming to swap with. So, yes, temporarily changing the color of the cell background (cellBackground) under the selected candy, or drawing a bright border around that cell, is often a more understandable and user-friendly method for selection feedback. It can make the gameplay feel more precise. Technically, this would involve modifying the handleCandyClick function to change the appearance of the cell background (perhaps using a reference like GameBoard.cells[row][col]) instead of calling candy.select(), and reverting it when the selection is cleared or a swap occurs.
User prompt
Very Important Problem: Candies Don't Fall Correctly, They Pile Up: Normally, when candies pop and leave gaps, only the candies directly above the gaps should slide down step-by-step to fill them (like a waterfall or cascade effect). Then, new candies should fall from the top of the screen to fill the remaining gaps at the top. What's Happening Instead: In the game right now, when a candy disappears, it seems like all the candies in that entire column try to slide down at once towards the bottom. They don't fall one space at a time. This causes them to incorrectly stack on top of each other, creating a jumbled pile-up, especially in the bottom row. The proper step-by-step "cascade" effect is completely broken. Why it's a Problem (Technical Guess): This likely points to a fundamental flaw in the handleDrops function. Instead of correctly identifying the specific gap below each candy and moving it down just one space (or the required number of spaces), the logic might be telling all candies in the column to move to the lowest available spot simultaneously, or it might be treating the whole column as a single block to be moved down, leading to the pile-up. This breaks a core mechanic of the game.
User prompt
Please fix the bug: 'Uncaught ReferenceError: isDropping is not defined' in or related to this line: 'if (game && typeof game.handleCandyClick === 'function' && !isSwapping && !isDropping) {' Line Number: 181
User prompt
Activating Special Candies Breaks the Game (New & Important!): While special candies (striped, color bomb) now try to do something when matched, they do it in a way that disrupts the game's normal flow. When a special candy tries to clear a row or zap colors, those extra explosions don't wait for the game's usual "match finished, now drop candies" sequence. This will likely cause the game to hang, crash, or behave very strangely after a special candy is activated, because it's trying to handle the normal match and the special power effect at the same time, but out of order. Color Bomb Doesn't Work As Expected: When the color bomb (from a 5-match) is activated, it's supposed to clear all candies of the color it was swapped with. The current code picks a random color to clear instead. This might be surprising, but it's not how color bombs usually work. Special Candy Explosions are Abrupt: When a striped candy clears a row or column, all the candies in that line disappear instantly with no delay. Visually, this can feel sudden and unsatisfying. Usually, these effects have a more gradual or flowing animation. Animation Flow Still Not Perfectly Smooth: The system used to wait for pop and drop animations to finish (the complex callback/counter structure) seems to work mostly, but it might not be 100% seamless. It's still possible to experience minor stutters, pauses, or moments where things seem slightly out of sync, especially during complex cascades. Level Goals Are Still Just for Show: Although the code mentions setting up objectives like "clear jellies" or "bring ingredients down" at the start of a level, there's still no system in place to actually track these goals or win the level by completing them. The only way to win remains reaching the target score. Special Candies Remain After Shuffling (Design Choice?): When the board runs out of moves and reshuffles, special candies on the board now stay special. This might be intentional, but it's different from the previous version (where they became normal) and might be unexpected for some players. Old, Unused Code Part: The isDropping variable, which likely checked if candies were falling, is still in the code but doesn't seem to be used.
User prompt
Please fix the bug: 'TypeError: Cannot read properties of undefined (reading 'all')' in or related to this line: 'Promise.all(fillPromises).then(handleMatches); // Wait for fills, then check for new matches (cascade)' Line Number: 749
User prompt
Please fix the bug: 'TypeError: Promise is not a constructor' in or related to this line: 'fillPromises.push(new Promise(function (resolve) {' Line Number: 734
User prompt
Please fix the bug: 'TypeError: Cannot read properties of undefined (reading 'vars')' in or related to this line: 'dropTween.vars.onFinish = resolve;' Line Number: 685
User prompt
Please fix the bug: 'TypeError: Promise is not a constructor' in or related to this line: 'dropPromises.push(new Promise(function (resolve) {' Line Number: 683
User prompt
Please fix the bug: 'Uncaught ReferenceError: isDropping is not defined' in or related to this line: 'if (game && typeof game.handleCandyClick === 'function' && !isSwapping && !isDropping) {' Line Number: 181
User prompt
Special Candies Still Have No Powers: Although you create shiny special candies by matching 4 or 5, when you match these special candies, they still don't do anything special. They just pop like regular candies instead of clearing rows, exploding areas, or zapping colors. Special Candies Might Look Weird or Broken: The code tries to create specific types of special candies (like "colorBomb" or "stripedV"). However, it then looks for an image/shape with exactly that name (e.g., "colorBombCandy"). If you haven't defined what those specific special candy types should look like in the Assets section, they might show up as broken images or just a default shape, not the cool special candy visual you'd expect. Animations Can Still Feel a Bit Jerky or Off: The way the game waits for popping and falling animations to finish seems a bit complicated. This might still lead to moments where the game doesn't feel perfectly smooth; it might seem like things happen slightly out of order, or there could be tiny stutters, especially with candies dropping down. Game Goals Don't Actually Work Yet: When a level starts, the code mentions setting up goals like clearing jelly or dropping ingredients, but there's no actual gameplay mechanic to track these goals or win the level by completing them. The only way to win is still by reaching the target score. Special Candies Become Normal After Shuffling: If you run out of moves and the board reshuffles, any special candies you had on the board turn back into regular candies (they lose their shine/special status). This might be intended, but players often expect special items to survive a reshuffle. (Note: This is different from a previous version where they stayed special). An Old Unused Piece Remains: There's still a leftover piece of code (isDropping) that seems to check if candies are falling, but it doesn't appear to be used anymore.
User prompt
Please fix the bug: 'TypeError: Cannot read properties of undefined (reading 'vars')' in or related to this line: 'if (!dropTween.vars) {' Line Number: 638
/**** 
* Plugins
****/ 
var tween = LK.import("@upit/tween.v1");
var storage = LK.import("@upit/storage.v1", {
	level: 1,
	score: 0,
	highScore: 0
});
/**** 
* Classes
****/ 
var Candy = Container.expand(function (type, row, col) {
	var self = Container.call(this);
	self.type = type || 'redCandy';
	self.row = row || 0;
	self.col = col || 0;
	self.isSpecial = false; // Flag indicating if this candy is special (e.g., striped, wrapped)
	// Visual representation
	var visual = self.attachAsset(self.type, {
		anchorX: 0.5,
		anchorY: 0.5,
		alpha: 1
	});
	// Selection overlay (hidden by default)
	var overlay = self.attachAsset('selectedOverlay', {
		anchorX: 0.5,
		anchorY: 0.5,
		alpha: 0,
		visible: false // Start invisible
	});
	// Marker for special candies (optional, initially hidden)
	var specialMarker = null;
	self.setSpecial = function (special) {
		self.isSpecial = special;
		// Add visual distinction for special candies if needed
		if (special) {
			if (!specialMarker) {
				// Example: Add a marker instead of scaling/pulsing the base visual
				specialMarker = self.attachAsset('specialMarkerCandy', {
					anchorX: 0.5,
					anchorY: 0.5,
					alpha: 1 // Make it visible
				});
			}
			// Optional: Pulse animation for special marker
			tween.stop(specialMarker); // Stop previous tweens on marker
			specialMarker.alpha = 0.6;
			tween(specialMarker, {
				alpha: 1.0
			}, {
				duration: 800,
				easing: tween.easeInOut,
				yoyo: true,
				// Go back and forth
				loop: true // Repeat indefinitely
			});
		} else {
			if (specialMarker) {
				tween.stop(specialMarker); // Stop animation
				specialMarker.destroy();
				specialMarker = null;
			}
		}
	};
	self.select = function () {
		overlay.visible = true;
		tween.stop(overlay, {
			alpha: true
		}); // Stop previous animation
		tween(overlay, {
			alpha: 0.4
		}, {
			duration: 150
		});
	};
	self.deselect = function () {
		tween.stop(overlay, {
			alpha: true
		}); // Stop previous animation
		tween(overlay, {
			alpha: 0
		}, {
			duration: 150,
			onFinish: function onFinish() {
				overlay.visible = false; // Hide after fade out
			}
		});
	};
	self.moveTo = function (newRow, newCol, animate, delay, onComplete) {
		self.row = newRow;
		self.col = newCol;
		var newX = CELL_SIZE * self.col + CELL_SIZE / 2;
		var newY = CELL_SIZE * self.row + CELL_SIZE / 2;
		if (animate) {
			tween.stop(self, {
				x: true,
				y: true
			}); // Stop previous movement
			tween(self, {
				x: newX,
				y: newY
			}, {
				duration: 300,
				// Consistent duration
				delay: delay || 0,
				easing: tween.easeOutQuad,
				// Smooth easing
				onFinish: onComplete
			});
		} else {
			tween.stop(self, {
				x: true,
				y: true
			}); // Ensure any running tween is stopped
			self.x = newX;
			self.y = newY;
			if (onComplete) {
				onComplete();
			}
		}
	};
	// Pop animation - Returns the tween instance
	self.pop = function (delay, onComplete) {
		tween.stop(self, {
			alpha: true,
			scaleX: true,
			scaleY: true
		}); // Stop other tweens
		return tween(self, {
			alpha: 0,
			scaleX: 0.1,
			// Shrink down 
			scaleY: 0.1
		}, {
			duration: 250,
			delay: delay || 0,
			easing: tween.easeInQuad,
			// Ease in for disappearance 
			onFinish: function onFinish() {
				// Note: Actual destruction and removal from arrays happen elsewhere 
				if (onComplete) {
					onComplete();
				}
			}
		});
	};
	// Override destroy to clean up marker tween
	var baseDestroy = self.destroy;
	self.destroy = function () {
		if (specialMarker) {
			tween.stop(specialMarker);
		}
		baseDestroy.call(self); // Call original destroy
	};
	self.down = function (x, y, obj) {
		// Delegate to the main game click handler
		if (game && typeof game.handleCandyClick === 'function' && !isSwapping && !isDropping) {
			game.handleCandyClick(self);
		}
	};
	return self;
});
var GameBoard = Container.expand(function (rows, cols) {
	var self = Container.call(this);
	self.rows = rows || 8;
	self.cols = cols || 8;
	// Background board
	var boardVisual = self.attachAsset('gameBoard', {
		anchorX: 0.5,
		anchorY: 0.5
	});
	boardVisual.width = CELL_SIZE * self.cols; // Match width to grid
	boardVisual.height = CELL_SIZE * self.rows; // Match height to grid
	// Cell backgrounds
	self.cells = [];
	for (var row = 0; row < self.rows; row++) {
		self.cells[row] = []; // Initialize row array
		for (var col = 0; col < self.cols; col++) {
			var cell = self.attachAsset('cellBackground', {
				anchorX: 0.5,
				anchorY: 0.5,
				x: col * CELL_SIZE + CELL_SIZE / 2,
				y: row * CELL_SIZE + CELL_SIZE / 2
			});
			self.cells[row][col] = cell; // Store cell reference if needed later
		}
	}
	return self;
});
/**** 
* Initialize Game
****/ 
var game = new LK.Game({
	backgroundColor: 0x5D94FB // A pleasant blue
});
/**** 
* Game Code
****/ 
function activateSpecialCandy(candy) {
	switch (candy.type) {
		case 'colorBomb':
			// Clear all candies of the color it was swapped with
			var targetType = candy.swappedWithType; // Assume swappedWithType is set during swap
			candies.forEach(function (c) {
				if (c.type === targetType) {
					popPromises.push({
						then: function then(resolve) {
							c.pop(0, function () {
								c.destroy();
								resolve();
							});
						}
					});
				}
			});
			break;
		case 'stripedH':
			// Clear entire row
			for (var col = 0; col < BOARD_SIZE; col++) {
				var rowCandy = board[candy.row][col];
				if (rowCandy) {
					popPromises.push({
						then: function then(resolve) {
							rowCandy.pop(col * 50, function () {
								// Add delay based on column index
								rowCandy.destroy();
								resolve();
							});
						}
					});
				}
			}
			break;
		case 'stripedV':
			// Clear entire column
			for (var row = 0; row < BOARD_SIZE; row++) {
				var colCandy = board[row][candy.col];
				if (colCandy) {
					colCandy.pop(row * 50, function () {
						// Add delay based on row index
						colCandy.destroy();
					});
				}
			}
			break;
		default:
			break;
	}
}
// Sound for special candy creation/activation
// Keep as is for selection
// Example: Could be a different shape/texture
// Renamed specialCandy shape slightly for clarity
// Assets definition looks good, assuming LK.init.shape/sound works as expected.
// Constants
var BOARD_SIZE = 8;
var CELL_SIZE = 120; // Increase size of each cell for better visibility
var CANDY_TYPES = ['redCandy', 'yellowCandy', 'greenCandy', 'blueCandy', 'purpleCandy', 'orangeCandy'];
var NUM_CANDY_TYPES = CANDY_TYPES.length;
// Game state variables
var board; // 2D array holding Candy objects or null
var candies = []; // Flat list of all active Candy objects on the board
var selectedCandy = null;
var isSwapping = false; // True during the swap animation
var isProcessing = false; // General flag for when board is resolving (matches, drops, fills)
var moves = 0;
var score = 0;
var targetScore = 0;
var level = storage.level || 1;
var highScore = storage.highScore || 0;
// Game elements
var gameBoardContainer; // Holds the visual board and candies
var scoreTxt, movesTxt, levelTxt;
// --- Core Game Logic Functions ---
function setupGame() {
	// Create and center the game board container
	var background = LK.getAsset('gameBoard', {
		anchorX: 0.5,
		anchorY: 0.5,
		x: (2048 - CELL_SIZE * BOARD_SIZE) / 2 + 200,
		y: (2732 - CELL_SIZE * BOARD_SIZE) / 2 + 200
	});
	game.addChild(background);
	gameBoardContainer = new GameBoard(BOARD_SIZE, BOARD_SIZE);
	// Center the board (assuming 2048x2732 is the stage size)
	gameBoardContainer.x = (2048 - gameBoardContainer.width) / 2 + 200; // Shift right by 200 pixels
	gameBoardContainer.y = (2732 - gameBoardContainer.height) / 2 + 200; // Shift down by 200 pixels
	game.addChild(gameBoardContainer);
	// Setup UI elements
	scoreTxt = new Text2('Score: 0', {
		size: 70,
		fill: 0xFFFFFF,
		align: 'right'
	});
	scoreTxt.anchor.set(1, 0); // Anchor top-right
	LK.gui.topRight.addChild(scoreTxt);
	scoreTxt.x = -20; // Add some padding from the edge
	movesTxt = new Text2('Moves: 0', {
		size: 70,
		fill: 0xFFFFFF,
		align: 'left'
	});
	movesTxt.anchor.set(0, 0); // Anchor top-left
	LK.gui.topLeft.addChild(movesTxt);
	movesTxt.x = 20; // Add some padding from the edge
	levelTxt = new Text2('Level: 1', {
		size: 70,
		fill: 0xFFFFFF
	});
	levelTxt.anchor.set(0.5, 0); // Anchor top-center
	LK.gui.top.addChild(levelTxt);
	// Initialize the first level
	initializeLevel(level);
	// Start background music
	LK.playMusic('bgmusic', {
		loop: true,
		fade: {
			start: 0,
			end: 0.5,
			duration: 1000
		}
	});
	// Attach global click listener (if Candy.down isn't sufficient)
	// game.down = handleGameClick; // Use this if clicking empty cells should deselect
}
function initializeLevel(levelNum) {
	level = levelNum;
	score = 0;
	moves = 20 + (level - 1) * 2; // Example: Increase moves per level
	targetScore = 1000 * level; // Example: Increase target score per level
	// Add additional objectives like clearing jellies or bringing ingredients down
	var objectives = {
		clearJellies: Math.floor(level / 2),
		bringIngredients: Math.floor(level / 3)
	};
	selectedCandy = null;
	isSwapping = false;
	isProcessing = false;
	updateUI();
	initializeBoard();
}
function initializeBoard() {
	// Clear existing candies visually and from arrays
	for (var i = 0; i < candies.length; i++) {
		candies[i].destroy();
	}
	candies = [];
	board = [];
	// Create the board array and fill with candies
	for (var row = 0; row < BOARD_SIZE; row++) {
		board[row] = [];
		for (var col = 0; col < BOARD_SIZE; col++) {
			board[row][col] = null; // Ensure initialized to null
			// Generate candy ensuring no initial matches
			var attempts = 0;
			do {
				var type = getRandomCandyType();
				// Temporarily place to check for matches
				var tempCandy = {
					type: type
				}; // Lightweight check
				board[row][col] = tempCandy;
				attempts++;
				if (attempts > 50) {
					// Safety break for rare impossible scenarios
					console.warn("Struggling to place initial candy without match at", row, col);
					break;
				}
			} while (checkMatchAt(row, col));
			// If check passed or safety break, create the real candy
			var candy = new Candy(type, row, col);
			candy.moveTo(row, col, false); // Place instantly
			gameBoardContainer.addChild(candy);
			board[row][col] = candy; // Place real candy in board
			candies.push(candy);
		}
	}
	// Final check: Ensure there are possible moves
	if (!hasPossibleMoves()) {
		console.log("No initial moves, reshuffling...");
		// Use LK.setTimeout to allow the initial draw frame to happen first
		LK.setTimeout(reshuffleBoard, 100);
	}
}
// Helper to check for matches *only* at a specific new candy's location
function checkMatchAt(row, col) {
	var candy = board[row][col];
	if (!candy) {
		return false;
	}
	var type = candy.type;
	// Check Horizontal
	var count = 1;
	if (col > 0 && board[row][col - 1] && board[row][col - 1].type === type) {
		count++;
	}
	if (col > 1 && board[row][col - 2] && board[row][col - 2].type === type) {
		count++;
	}
	if (count >= 3) {
		return true;
	}
	// Check Vertical
	count = 1;
	if (row > 0 && board[row - 1][col] && board[row - 1][col].type === type) {
		count++;
	}
	if (row > 1 && board[row - 2][col] && board[row - 2][col].type === type) {
		count++;
	}
	if (count >= 3) {
		return true;
	}
	return false;
}
function getRandomCandyType() {
	var typesAvailable = Math.min(NUM_CANDY_TYPES, 3 + Math.floor(level / 3)); // Slower difficulty ramp
	return CANDY_TYPES[Math.floor(Math.random() * typesAvailable)];
}
function updateUI() {
	scoreTxt.setText('Score: ' + score);
	movesTxt.setText('Moves: ' + moves);
	levelTxt.setText('Level: ' + level);
}
// Renamed from handleCandyClick to be clearer
game.handleCandyClick = function (candy) {
	if (isProcessing || isSwapping || isDropping) {
		return;
	} // Ignore clicks during processing or animations
	if (selectedCandy === null) {
		selectedCandy = candy;
		// Highlight the cell background
		gameBoardContainer.cells[candy.row][candy.col].tint = 0xffff00; // Highlight with yellow
	} else {
		// Second selection
		if (selectedCandy === candy) {
			// Deselect if same candy clicked
			// Revert cell background tint
			gameBoardContainer.cells[selectedCandy.row][selectedCandy.col].tint = 0x704f3d; // Original color
			gameBoardContainer.cells[selectedCandy.row][selectedCandy.col].tint = 0x704f3d; // Revert tint
			selectedCandy = null;
		} else {
			// Check if candies are adjacent
			var rowDiff = Math.abs(selectedCandy.row - candy.row);
			var colDiff = Math.abs(selectedCandy.col - candy.col);
			if (rowDiff === 1 && colDiff === 0 || rowDiff === 0 && colDiff === 1) {
				// Adjacent: Initiate swap
				selectedCandy.deselect(); // Deselect the first one visually
				swapCandies(selectedCandy, candy);
				selectedCandy = null; // Clear selection after initiating swap
			} else {
				// Not adjacent: Change selection to the new candy
				// Revert previous selection's cell background tint
				gameBoardContainer.cells[selectedCandy.row][selectedCandy.col].tint = 0x704f3d; // Original color
				selectedCandy = candy;
				// Highlight new selection's cell background
				gameBoardContainer.cells[candy.row][candy.col].tint = 0xffff00; // Highlight with yellow
				LK.getSound('invalid').play(); // Sound for invalid selection change
			}
		}
	}
};
function swapCandies(candy1, candy2) {
	if (isSwapping || isProcessing) {
		return;
	} // Prevent overlapping swaps
	isSwapping = true;
	// Store original positions for potential revert
	var candy1Row = candy1.row;
	var candy1Col = candy1.col;
	var candy2Row = candy2.row;
	var candy2Col = candy2.col;
	// Track the type of candy a color bomb is swapped with
	if (candy1.type === 'colorBomb') {
		candy1.swappedWithType = candy2.type;
	} else if (candy2.type === 'colorBomb') {
		candy2.swappedWithType = candy1.type;
	}
	// Update board model immediately
	board[candy1Row][candy1Col] = candy2;
	board[candy2Row][candy2Col] = candy1;
	// Update candy objects' internal row/col
	candy1.row = candy2Row;
	candy1.col = candy2Col;
	candy2.row = candy1Row;
	candy2.col = candy1Col;
	// Animate the swap visually
	LK.getSound('swap').play();
	var tween1 = candy1.moveTo(candy2Row, candy2Col, true);
	var tween2 = candy2.moveTo(candy1Row, candy1Col, true);
	// After animation finishes (wait for the longer of the two, though they should be same duration)
	// Using a small timeout is simpler than tracking both tweens
	LK.setTimeout(function () {
		// Check if the swap resulted in a match
		var matchFound = checkMatchAt(candy1.row, candy1.col) || checkMatchAt(candy2.row, candy2.col) || findMatches().length > 0; // More robust check
		if (matchFound) {
			// Valid swap, deduct move and process matches
			moves--;
			updateUI();
			isSwapping = false; // Allow processing now
			processBoard(); // Start the match -> drop -> fill cycle
			// Check game state later, after processing finishes
		} else {
			// Invalid swap, animate back
			LK.getSound('invalid').play();
			// Update board model back
			board[candy1Row][candy1Col] = candy1;
			board[candy2Row][candy2Col] = candy2;
			// Update candy objects' internal row/col back
			candy1.row = candy1Row;
			candy1.col = candy1Col;
			candy2.row = candy2Row;
			candy2.col = candy2Col;
			// Animate back
			candy1.moveTo(candy1Row, candy1Col, true);
			candy2.moveTo(candy2Row, candy2Col, true);
			// After swap back animation finishes
			LK.setTimeout(function () {
				isSwapping = false; // Ready for next input
				gameBoardContainer.cells[candy1.row][candy1.col].tint = 0x704f3d; // Revert tint
				gameBoardContainer.cells[candy2.row][candy2.col].tint = 0x704f3d; // Revert tint
				selectedCandy = null;
			}, 310); // Slightly longer than moveTo duration
		}
	}, 310); // Wait for swap animation to mostly complete
}
// Main processing loop trigger
function processBoard() {
	if (isProcessing) {
		return;
	} // Avoid re-entry
	isProcessing = true;
	handleMatches();
}
// Step 1: Find and handle matches
function handleMatches() {
	var matches = findMatches();
	if (matches.length > 0) {
		LK.getSound('match').play();
		var pointsEarned = 0;
		var specialCandiesToCreate = []; // Store {row, col, type} for special creation
		// Mark candies for removal and calculate score/special
		var candiesToRemove = [];
		matches.forEach(function (match) {
			var matchSize = match.length;
			var pointsPerCandy = 10 * matchSize; // Bonus for longer matches
			// Decide if a special candy should be created from this match
			var createSpecial = null; // { type: 'stripedH', row: r, col: c } etc.
			if (matchSize >= 5) {
				// 5-in-a-row -> Color Bomb (example)
				createSpecial = {
					type: 'colorBomb',
					row: match.row,
					col: match.col + (match.horizontal ? Math.floor(matchSize / 2) : 0)
				};
				if (!match.horizontal) {
					createSpecial.col = match.col;
				}
				if (!match.horizontal) {
					createSpecial.row = match.row + Math.floor(matchSize / 2);
				}
			} else if (matchSize === 4) {
				// 4-in-a-row -> Striped (example)
				createSpecial = {
					type: match.horizontal ? 'stripedV' : 'stripedH',
					row: match.row,
					col: match.col + (match.horizontal ? Math.floor(matchSize / 2) : 0)
				};
				if (!match.horizontal) {
					createSpecial.col = match.col;
				}
				if (!match.horizontal) {
					createSpecial.row = match.row + Math.floor(matchSize / 2);
				}
			} // Add logic for L/T shapes for Wrapped candies if needed
			var specialCreated = false;
			for (var j = 0; j < matchSize; j++) {
				var row = match.horizontal ? match.row : match.row + j;
				var col = match.horizontal ? match.col + j : match.col;
				var candy = board[row][col];
				if (candy && candiesToRemove.indexOf(candy) === -1) {
					if (candy.isSpecial) {
						popPromises.push({
							then: function then(resolve) {
								setTimeout(function () {
									activateSpecialCandy(candy);
									resolve();
								}, 300); // Delay special candy activation to allow normal match processing
							}
						});
					}
					// Ensure not already marked
					candiesToRemove.push(candy);
					pointsEarned += pointsPerCandy * (candy.isSpecial ? 2 : 1); // More points for popping special candies
					// If this is the spot for special creation, mark it
					if (createSpecial && row === createSpecial.row && col === createSpecial.col) {
						specialCandiesToCreate.push(createSpecial);
						specialCreated = true;
					}
				}
			}
			// If special should be created but wasn't assigned to a specific candy (e.g., user swipe location matters), handle here
			// if (createSpecial && !specialCreated) { ... }
		});
		score += pointsEarned;
		updateUI();
		// Animate removal
		var popPromises = [];
		candiesToRemove.forEach(function (candy, index) {
			// Remove from board model immediately
			if (board[candy.row][candy.col] === candy) {
				board[candy.row][candy.col] = null;
			}
			// Animate pop
			popPromises.push({
				then: function then(resolve) {
					candy.pop(index * 30, resolve); // Pass resolve directly to pop as onComplete
				}
			});
			// Remove from the master list
			var listIndex = candies.indexOf(candy);
			if (listIndex > -1) {
				candies.splice(listIndex, 1);
			}
		});
		// After all pops are visually done, proceed to drop/fill
		(function (promises, callback) {
			var remaining = promises.length;
			if (remaining === 0) {
				callback();
			}
			promises.forEach(function (promise) {
				promise.then(function () {
					remaining--;
					if (remaining === 0) {
						callback();
					}
				});
			});
		})(popPromises, function () {
			candiesToRemove.forEach(function (candy) {
				return candy.destroy();
			}); // Final cleanup
			// Now create the special candies *before* dropping
			specialCandiesToCreate.forEach(function (spec) {
				var newType = spec.type; // Use the specified special type
				// In a real game, 'spec.type' would determine the *kind* of special candy
				// For now, we just make it visually 'special'
				var specialCandy = new Candy(spec.type, spec.row, spec.col);
				specialCandy.setSpecial(true); // Make it special
				specialCandy.moveTo(spec.row, spec.col, false); // Place instantly
				gameBoardContainer.addChild(specialCandy);
				board[spec.row][spec.col] = specialCandy;
				candies.push(specialCandy);
				LK.getSound('special').play();
			});
			handleDrops(); // Proceed to next step
		});
	} else {
		// No matches found, board is stable
		isProcessing = false;
		selectedCandy = null; // Clear selection
		// Check for possible moves ONLY if the board is stable
		if (!hasPossibleMoves()) {
			reshuffleBoard(); // This will set isProcessing again briefly
		} else {
			checkGameState(); // Check win/loss only when stable and moves exist
		}
	}
}
// Step 2: Handle candies dropping down
function handleDrops() {
	var dropsOccurred = false;
	var dropPromises = [];
	for (var col = 0; col < BOARD_SIZE; col++) {
		var emptyRow = BOARD_SIZE - 1; // Start checking from bottom
		// Find the lowest empty spot
		for (var row = BOARD_SIZE - 1; row >= 0; row--) {
			if (board[row][col] === null) {
				emptyRow = row; // Found the lowest empty row in this column
				break; // No need to check further up for the initial empty spot
			}
		}
		// Now check candies above this empty spot
		for (var row = BOARD_SIZE - 1; row >= 0; row--) {
			if (board[row][col] !== null) {
				// Check if there's a gap below this candy
				var targetRow = row;
				while (targetRow + 1 < BOARD_SIZE && board[targetRow + 1][col] === null) {
					targetRow++;
				}
				if (targetRow !== row) {
					// Move in model
					var candy = board[row][col];
					board[targetRow][col] = candy;
					board[row][col] = null;
					// Animate move
					var dropTween = candy.moveTo(targetRow, col, true, 0); // Drop animation
					dropPromises.push({
						then: function then(resolve) {
							if (dropTween && dropTween.vars) {
								dropTween.vars.onFinish = resolve;
							} else {
								resolve(); // Resolve immediately if dropTween or vars is undefined
							}
						}
					});
					dropsOccurred = true;
				}
			}
		}
	}
	if (dropsOccurred) {
		(function (promises, callback) {
			var remaining = promises.length;
			if (remaining === 0) {
				callback();
			}
			promises.forEach(function (promise) {
				promise.then(function () {
					remaining--;
					if (remaining === 0) {
						callback();
					}
				});
			});
		})(dropPromises, handleFills); // Wait for drops, then fill 
	} else {
		handleFills(); // No drops, proceed directly to filling
	}
}
// Step 3: Fill empty spaces from the top
function handleFills() {
	var fillsOccurred = false;
	var fillPromises = [];
	for (var col = 0; col < BOARD_SIZE; col++) {
		var fillRow = -1; // Start generating candies above the board
		for (var row = BOARD_SIZE - 1; row >= 0; row--) {
			if (board[row][col] === null) {
				// Found an empty spot
				var type = getRandomCandyType();
				var candy = new Candy(type, fillRow, col); // Create above the board
				candy.moveTo(fillRow, col, false); // Place instantly above
				gameBoardContainer.addChild(candy);
				board[row][col] = candy; // Assign to target cell in model
				candies.push(candy);
				// Animate move into place
				var delay = (-fillRow - 1) * 50; // Stagger based on how high it starts
				var fillTween = candy.moveTo(row, col, true, delay);
				fillPromises.push({
					then: function then(resolve) {
						if (fillTween && fillTween.vars) {
							fillTween.vars.onFinish = resolve;
						} else {
							resolve(); // Resolve immediately if fillTween or vars is undefined
						}
					}
				});
				fillsOccurred = true;
				fillRow--; // Next candy starts even higher
			}
		}
	}
	if (fillsOccurred) {
		if (typeof Promise !== 'undefined' && Promise.all) {
			Promise.all(fillPromises).then(handleMatches); // Wait for fills, then check for new matches (cascade)
		} else {
			console.error("Promise is not supported in this environment.");
			handleMatches(); // Fallback to directly calling handleMatches
		}
	} else {
		// No fills needed, implies no matches occurred in the previous step either. Board is stable.
		handleMatches(); // Final check (will find no matches and trigger end processing)
	}
}
function findMatches() {
	var matches = [];
	var checked = []; // Keep track of candies already part of a found match
	function markChecked(candy) {
		if (candy && checked.indexOf(candy) === -1) {
			checked.push(candy);
		}
	}
	// Check horizontal matches
	for (var row = 0; row < BOARD_SIZE; row++) {
		for (var col = 0; col < BOARD_SIZE - 2; col++) {
			var candy1 = board[row][col];
			if (!candy1 || checked.indexOf(candy1) > -1) {
				continue;
			} // Skip nulls or already checked
			var candy2 = board[row][col + 1];
			var candy3 = board[row][col + 2];
			if (candy2 && candy3 && candy1.type === candy2.type && candy1.type === candy3.type) {
				// Found a horizontal match of at least 3
				var currentMatch = [candy1, candy2, candy3];
				var matchLength = 3;
				// Check for longer match
				for (var k = col + 3; k < BOARD_SIZE; k++) {
					var nextCandy = board[row][k];
					if (nextCandy && nextCandy.type === candy1.type) {
						currentMatch.push(nextCandy);
						matchLength++;
					} else {
						break; // End of match
					}
				}
				// Store match details
				matches.push({
					candies: currentMatch,
					// Store the actual candy objects
					row: row,
					col: col,
					length: matchLength,
					horizontal: true
				});
				// Mark all candies in this match as checked
				currentMatch.forEach(markChecked);
				col += matchLength - 1; // Skip checked candies in the outer loop
			}
		}
	}
	// Check vertical matches
	for (var col = 0; col < BOARD_SIZE; col++) {
		for (var row = 0; row < BOARD_SIZE - 2; row++) {
			var candy1 = board[row][col];
			// Skip nulls or candies already part of a horizontal match
			if (!candy1 || checked.indexOf(candy1) > -1) {
				continue;
			}
			var candy2 = board[row + 1][col];
			var candy3 = board[row + 2][col];
			if (candy2 && candy3 && candy1.type === candy2.type && candy1.type === candy3.type) {
				// Found a vertical match of at least 3
				var currentMatch = [candy1, candy2, candy3];
				var matchLength = 3;
				// Check for longer match
				for (var k = row + 3; k < BOARD_SIZE; k++) {
					var nextCandy = board[k][col];
					if (nextCandy && nextCandy.type === candy1.type) {
						// Avoid adding if already part of a horizontal match found earlier
						if (checked.indexOf(nextCandy) === -1) {
							currentMatch.push(nextCandy);
						} else {
							// If it was part of a horizontal match, just increase length but don't re-add
						}
						matchLength++;
					} else {
						break; // End of match
					}
				}
				// Store match details
				matches.push({
					candies: currentMatch,
					// Store the actual candy objects
					row: row,
					col: col,
					length: matchLength,
					horizontal: false
				});
				// Mark all candies in this match as checked
				currentMatch.forEach(markChecked);
				row += matchLength - 1; // Skip checked candies in the outer loop
			}
		}
	}
	return matches;
}
function hasPossibleMoves() {
	// Check horizontal swaps that could create a match
	for (var row = 0; row < BOARD_SIZE; row++) {
		for (var col = 0; col < BOARD_SIZE - 1; col++) {
			if (canSwapCreateMatch(row, col, row, col + 1)) {
				return true;
			}
		}
	}
	// Check vertical swaps that could create a match
	for (var row = 0; row < BOARD_SIZE - 1; row++) {
		for (var col = 0; col < BOARD_SIZE; col++) {
			if (canSwapCreateMatch(row, col, row + 1, col)) {
				return true;
			}
		}
	}
	return false; // No possible moves found
}
// Helper function for hasPossibleMoves
function canSwapCreateMatch(r1, c1, r2, c2) {
	var candy1 = board[r1][c1];
	var candy2 = board[r2][c2];
	if (!candy1 || !candy2) {
		return false;
	} // Cannot swap with empty space
	// Temporarily swap types in the model (don't need full object swap)
	board[r1][c1] = candy2;
	board[r2][c2] = candy1;
	// Check if this swap creates a match around either position
	var createsMatch = checkMatchAt(r1, c1) || checkMatchAt(r2, c2) || findMatches().length > 0; // Simplified check
	// Swap back
	board[r1][c1] = candy1;
	board[r2][c2] = candy2;
	return createsMatch;
}
function reshuffleBoard() {
	if (isProcessing) {
		// Don't reshuffle if already processing
		LK.setTimeout(reshuffleBoard, 500); // Try again later
		return;
	}
	isProcessing = true; // Block input during reshuffle
	// Display reshuffling message
	var reshuffleTxt = new Text2('Reshuffling...', {
		size: 100,
		fill: 0xFFFFFF
	});
	reshuffleTxt.anchor.set(0.5, 0.5);
	LK.gui.center.addChild(reshuffleTxt);
	// 1. Collect all current candy types and special status
	var currentCandiesInfo = [];
	candies.forEach(function (candy) {
		currentCandiesInfo.push({
			type: candy.type,
			isSpecial: candy.isSpecial // Retain special status during reshuffle
		});
		candy.destroy(); // Remove old visuals immediately
	});
	candies = []; // Clear the list
	board = []; // Clear the board model
	// 2. Shuffle the collected info
	for (var i = currentCandiesInfo.length - 1; i > 0; i--) {
		var j = Math.floor(Math.random() * (i + 1));
		var _ref = [currentCandiesInfo[j], currentCandiesInfo[i]];
		currentCandiesInfo[i] = _ref[0];
		currentCandiesInfo[j] = _ref[1];
	}
	// 3. Rebuild the board ensuring no initial matches AND possible moves
	var attempts = 0;
	do {
		attempts++;
		if (attempts > 10) {
			// Safety break if it struggles too much
			console.error("Failed to reshuffle into a valid state after 10 attempts.");
			// Could force a simple known-good layout here or reset level
			isProcessing = false; // Unlock
			reshuffleTxt.destroy();
			// Maybe show a "No more moves" game over?
			checkGameState(true); // Force check, likely leading to game over if moves are 0
			return;
		}
		// Clear board for re-attempt
		candies.forEach(function (c) {
			return c.destroy();
		});
		candies = [];
		board = [];
		var infoIndex = 0;
		for (var row = 0; row < BOARD_SIZE; row++) {
			board[row] = [];
			for (var col = 0; col < BOARD_SIZE; col++) {
				var info = currentCandiesInfo[infoIndex++];
				board[row][col] = null; // Temp null for checkMatchAt
				// Ensure no immediate matches with shuffled type
				var placeAttempts = 0;
				do {
					var currentInfo = info; // Use the shuffled info
					board[row][col] = {
						type: currentInfo.type,
						isSpecial: currentInfo.isSpecial
					}; // Temp place
					placeAttempts++;
					if (placeAttempts > currentCandiesInfo.length) {
						// Avoid infinite loop if types are very limited
						// Swap with a later random type if stuck
						var swapIdx = infoIndex + Math.floor(Math.random() * (currentCandiesInfo.length - infoIndex));
						if (swapIdx < currentCandiesInfo.length) {
							var _ref2 = [currentCandiesInfo[swapIdx], currentCandiesInfo[infoIndex - 1]];
							currentCandiesInfo[infoIndex - 1] = _ref2[0];
							currentCandiesInfo[swapIdx] = _ref2[1];
							info = currentCandiesInfo[infoIndex - 1]; // Get the newly swapped info
						}
						board[row][col] = {
							type: info.type,
							isSpecial: info.isSpecial
						}; // Try again with swapped
						break; // Exit do-while for this cell after swap
					}
				} while (checkMatchAt(row, col)); // Check if placing this type creates a match
				// Create the actual candy
				var candy = new Candy(board[row][col].type, row, col);
				candy.setSpecial(board[row][col].isSpecial);
				candy.alpha = 0; // Start invisible
				candy.moveTo(row, col, false);
				gameBoardContainer.addChild(candy);
				board[row][col] = candy; // Replace temp object with real candy
				candies.push(candy);
				// Animate fade-in
				tween(candy, {
					alpha: 1
				}, {
					duration: 300,
					delay: (row + col) * 20
				});
			}
		}
		// Loop condition: Keep reshuffling if the new board has no possible moves
	} while (!hasPossibleMoves() && attempts < 10);
	// Reshuffle successful
	LK.setTimeout(function () {
		reshuffleTxt.destroy();
		isProcessing = false; // Unlock the board
	}, 500); // Keep message visible briefly
}
function checkGameState() {
	var forceCheck = arguments.length > 0 && arguments[0] !== undefined ? arguments[0] : false;
	// Don't check state while the board is actively processing, unless forced (e.g., reshuffle failed)
	if (isProcessing && !forceCheck) {
		return;
	}
	// Check Win Condition
	if (score >= targetScore) {
		console.log("Level " + level + " Complete!");
		isProcessing = true; // Prevent further input
		// Update storage
		level++;
		storage.level = level;
		if (score > highScore) {
			highScore = score;
			storage.highScore = highScore;
		}
		storage.score = score; // Save current score too, maybe for win screen display
		LK.setTimeout(function () {
			LK.showYouWin({
				level: level - 1,
				score: score,
				highScore: highScore
			});
		}, 1000); // Delay for effect
	}
	// Check Lose Condition
	else if (moves <= 0) {
		console.log("Game Over - Out of Moves!");
		isProcessing = true; // Prevent further input
		// Update high score if needed
		if (score > highScore) {
			highScore = score;
			storage.highScore = highScore;
		}
		storage.score = score; // Save final score
		LK.setTimeout(function () {
			LK.showGameOver({
				level: level,
				score: score,
				highScore: highScore
			});
		}, 1000); // Delay for effect
	}
	// Note: The "no possible moves" scenario is now handled by reshuffleBoard,
	// but if reshuffling fails repeatedly, it might also lead to a game over state here.
}
// --- Game Start ---
setupGame(); ===================================================================
--- original.js
+++ change.js
@@ -266,9 +266,8 @@
 var candies = []; // Flat list of all active Candy objects on the board
 var selectedCandy = null;
 var isSwapping = false; // True during the swap animation
 var isProcessing = false; // General flag for when board is resolving (matches, drops, fills)
-var isDropping = false; // Flag to indicate if candies are currently dropping
 var moves = 0;
 var score = 0;
 var targetScore = 0;
 var level = storage.level || 1;
@@ -278,8 +277,15 @@
 var scoreTxt, movesTxt, levelTxt;
 // --- Core Game Logic Functions ---
 function setupGame() {
 	// Create and center the game board container
+	var background = LK.getAsset('gameBoard', {
+		anchorX: 0.5,
+		anchorY: 0.5,
+		x: (2048 - CELL_SIZE * BOARD_SIZE) / 2 + 200,
+		y: (2732 - CELL_SIZE * BOARD_SIZE) / 2 + 200
+	});
+	game.addChild(background);
 	gameBoardContainer = new GameBoard(BOARD_SIZE, BOARD_SIZE);
 	// Center the board (assuming 2048x2732 is the stage size)
 	gameBoardContainer.x = (2048 - gameBoardContainer.width) / 2 + 200; // Shift right by 200 pixels
 	gameBoardContainer.y = (2732 - gameBoardContainer.height) / 2 + 200; // Shift down by 200 pixels
:quality(85)/https://cdn.frvr.ai/67f7fc73de9c6f2eb0513ba7.png%3F3) 
 Generate a high-quality icon asset of the specific **blue candy** shown in the provided Candy Crush screenshot. * **Shape:** A smooth, **round, slightly flattened sphere or thick disc** shape with perfectly curved edges. It should look plump and solid. * **Color:** A bright, **vibrant, medium blue**. Clear and saturated, avoiding overly dark (navy) or light (sky blue) tones. * **Surface & Finish:** **Highly glossy** and reflective, like polished hard candy or a glass marble. The surface should look perfectly smooth. * **Lighting & Highlights:** Features a **prominent, distinct, curved white specular highlight** positioned near the **top-left edge**, following the candy's spherical contour. Additional subtle, broader highlights should be visible across the top surface, giving it dimension. Clear shading should be present on the bottom and right sides to emphasize its **3D, spherical volume**. * **Style:** Clean, **stylized 3D render**, matching the cheerful, polished, and sli. Single Game Texture. In-Game asset. 2d. Blank background. High contrast. No shadows
:quality(85)/https://cdn.frvr.ai/67f7fe6dde9c6f2eb0513c6c.png%3F3) 
 Basic Prompt: Bright green candy, emerald green tones, crystallized texture, covered in small sugar granules, looking sweet and delicious. More Detailed Prompt (Optional): Bright green candy, with hints of emerald green and light lime green sparkles, crystallized texture, covered in small sugar granules, looking fresh and delicious as if it was just made. There is a faint halo of light around the candy, and the background is blurred. Additional Details to Add to the Prompt: Shape: Round, square, heart-shaped, etc. Material: Glass, frosted glass, sugar crystal, etc. Lighting: Soft, hard, dramatic, etc. Background: Solid color, patterned, blurred, themed (e.g., candy store), etc. Additional Objects: Other candies, paper packaging, ribbon, etc. Example Combined Prompt: Round, bright green candy with emerald green and lime green tones, crystallized texture, covered in small sugar granules, looking fresh and delicious. Soft lighting, blurred background.. Single Game Texture. In-Game asset. 2d. Blank background. High contrast. No shadows
:quality(85)/https://cdn.frvr.ai/67f7ff20de9c6f2eb0513c8e.png%3F3) 
 Basic Prompt: Bright orange candy, in shades of orange, with a smooth and glossy surface, sweet and appealing looking confection. More Detailed Prompt (Optional): Vibrant orange candy, luminous as if lit by sunlight, with hints of orange and light tangerine tones, possessing a smooth and flawless surface, high-quality candy. The candy has light reflections and the background is softly blurred. Additional Details to Add to the Prompt: Shape: Sphere, cube, star, etc. Texture: Smooth, matte, slightly grainy, etc. Lighting: Natural light, studio light, warm light, cool light, etc. Background: White, colored, patterned, candy store, kitchen counter, etc. Additional Objects: Candy wrapper, glass jar, candy stand, etc. Example Combined Prompt: Sphere-shaped, bright orange candy, luminous as if lit by sunlight, with hints of orange and light tangerine tones, possessing a smooth and flawless surface, high-quality candy. There are distinct light reflections on the candy. The background is white. Single Game Texture. In-Game asset. 2d. Blank background. High contrast. No shadows
:quality(85)/https://cdn.frvr.ai/67f80063347c096bf4d62455.png%3F3) 
 Basic Prompt: Bright purple candy, in shades of lavender and violet, with a smooth surface, sweet and enticing looking confection. More Detailed Prompt (Optional): Deep purple in color, with hints of lavender and light lilac where the light hits it, possessing a smooth and glossy surface, crystal clear like glass, high-quality purple candy. There's a subtle halo of light around the candy, and the background is softly blurred. Additional Details to Add to the Prompt: Shape: Crystal, drop, heart, round, etc. Texture: Glossy, matte, frosted, slightly rough, etc. Lighting: Soft, dramatic, natural light, artificial light, etc. Background: Solid color, patterned, candy store, countertop, etc. Additional Objects: Other candies, transparent packaging, ribbon, etc. Basic Prompt: Bright purple candy, in shades of lavender and violet, with a smooth surface, sweet and enticing looking confection. More Detailed Prompt (Optional): Deep purple in color, with hints of lavender and light lilac where th. Single Game Texture. In-Game asset. 2d. Blank background. High contrast. No shadows
:quality(85)/https://cdn.frvr.ai/67f800af347c096bf4d62460.png%3F3) 
 Basic Prompt: Bright yellow candy, lemon yellow color, smooth surface, sweet and tempting looking treat. More Detailed Prompt (Optional): Vibrant, sunny yellow candy, with subtle hints of lemon and gold. It has a smooth, glossy surface, almost like glass. The light catches it just right, creating a small sparkle. The background is slightly blurred. More Variations to add (Optional): Shape: Sphere, star, gumball, square, etc. Texture: Gummy, hard candy, crystalline, etc. Lighting: Soft, harsh, natural, artificial, etc. Background: Plain, gradient, candy store, etc. Additions: Candy wrapper, other candies, etc. Example Combination Prompt: Round, bright yellow candy like a gumball. Has a smooth, glossy surface with soft lighting. Hints of lemon and gold colors, p. Single Game Texture. In-Game asset. 2d. Blank background. High contrast. No shadows
:quality(85)/https://cdn.frvr.ai/67f80158347c096bf4d6247b.png%3F3) 
 Basic Prompt: Bright red candy, vibrant crimson color, smooth surface, sweet and appealing treat. More Detailed Prompt (Optional): A glistening, ruby-red candy, with a smooth, reflective surface. The color is a rich, deep crimson, almost like a precious gem. The light catches it beautifully, creating highlights and shadows. The background is soft and blurred. Possible Variations to Add (Optional): Shape: Heart, sphere, cube, star, twisted, etc. Texture: Glossy, matte, gummy, hard, crystalline, etc. Lighting: Soft, harsh, natural, artificial, dramatic, etc. Background: Solid color, patterned, candy store, blurred, bokeh, etc. Additions: Candy wrapper, other candies, sprinkles, sugar coating, etc. Example Combination Prompt: A heart-shaped, glistening, ruby-red candy with a smooth, reflective surface. Rich, deep crimson color. Soft lighting, blurred background.. Single Game Texture. In-Game asset. 2d. Blank background. High contrast. No shadows
:quality(85)/https://cdn.frvr.ai/67f80a49373bb4eb006be2cf.png%3F3) 
 Generate a high-quality asset representing a **single square background tile** for a match-3 game cell, inspired by the cell interiors in the provided Candy Crush screenshot, but made **significantly more transparent**. * **Shape:** A perfect **square**. * **Base Appearance:** * **Color:** A **muted, desaturated, cool grey-blue** or **dark teal-grey**. * **Texture:** Contains an **extremely subtle, fine-grained texture** (like faint diagonal lines or uniform digital noise) integrated into the color. * **Transparency:** The key feature is **increased translucency**. The tile should be **moderately to significantly see-through**, allowing layers placed underneath it to be clearly visible. It should *not* be fully opaque like the original screenshot implies, nor fully transparent (invisible). Aim for roughly **40-60% opacity**. * **Lighting:** Maintain **soft, even, ambient lighting** across the surface of the square. No internal highlights or shadows within the tile. Single Game Texture. In-Game asset. 2d. Blank background. High contrast. No shadows
:quality(85)/https://cdn.frvr.ai/67f81a0358b4222a3fa333e7.png%3F3)