Code edit (3 edits merged)
Please save this source code
Code edit (2 edits merged)
Please save this source code
User prompt
Update as needed with: makeMove: function makeMove() { var difficulty = getAIDifficultySettings(storage.battleRating); var totalCards = this.countTotalCards(); var emptySlots = this.countEmptySlots(); var boardSpaceRatio = totalCards / (PLAY_AREA_ROWS * PLAY_AREA_COLS); // NEW: Check if AI has been inactive too long var timeSinceLastAction = Date.now() - this.lastActionTime; var isStuck = timeSinceLastAction > this.actionTimeoutThreshold; // PHASE 1: Fill the board first (priority when below target) var targetFill = difficulty.boardFillPriority || 0.95; if (boardSpaceRatio < targetFill) { if (this.shouldDeal()) { this.dealAIHand(); this.lastActionTime = Date.now(); // Update action time return; } if (this.tryPlaceCards()) { this.lastActionTime = Date.now(); // Update action time return; } } // PHASE 2: Smart merging based on damage calculations if (difficulty.canLevelUp && this.shouldMergeBasedOnDamage()) { if (this.tryMergeCards()) { this.lastActionTime = Date.now(); // Update action time return; } } // NEW PHASE 2.5: STUCK DETECTION - Force merge if AI hasn't acted in a while if (isStuck && difficulty.canLevelUp) { console.log("AI appears stuck, forcing emergency merge..."); if (this.tryEmergencyMerge()) { this.lastActionTime = Date.now(); return; } } // PHASE 3: Optimize positions var timeSinceLastOptimization = Date.now() - this.lastOptimizationTime; var optimizationDelay = boardSpaceRatio >= 0.95 ? 2000 : 3000; if (difficulty.shouldOptimize && boardSpaceRatio >= 0.7 && timeSinceLastOptimization > optimizationDelay) { if (this.optimizeCardPositions()) { this.lastOptimizationTime = Date.now(); this.lastActionTime = Date.now(); // Update action time return; } } // PHASE 4: Fill remaining empty slots if (this.shouldDeal()) { this.dealAIHand(); this.lastActionTime = Date.now(); // Update action time return; } // PHASE 5: EMERGENCY MODE - Board is full but AI has chips to spend if (emptySlots === 0 && gameState.aiChips >= gameState.dealCost) { this.dealAIHand(); this.lastActionTime = Date.now(); // Update action time return; } // NEW PHASE 6: DESPERATION MODE - Force ANY available merge if completely stuck if (isStuck && timeSinceLastAction > this.actionTimeoutThreshold * 2) { // 20 seconds console.log("AI in desperation mode, forcing ANY merge..."); if (this.tryEmergencyMerge()) { this.lastActionTime = Date.now(); return; } } }
User prompt
// Add to AISystem object initialization lastActionTime: Date.now(), actionTimeoutThreshold: 10000, // 10 seconds of inactivity triggers emergency mode
User prompt
Update as needed with: performMergeWithNewCard: function performMergeWithNewCard(newCard, target) { var pos = getSlotPosition(target.row, target.col, false); // Create merge animation similar to player merges var startY = -SLOT_HEIGHT; newCard.x = pos.x; newCard.y = startY; gameLayer.addChild(newCard); // Animate new card moving to target tween(newCard, { y: pos.y }, { duration: 400, easing: tween.quadOut, onFinish: function () { // Perform the actual merge var mergedCard = newCard.mergeWith(target.card); if (mergedCard) { var oldLevel = target.card.level; // Store old level for stats calculation // Remove old cards if (newCard.parent) { newCard.parent.removeChild(newCard); } if (target.card.parent) { target.card.parent.removeChild(target.card); } // Place merged card mergedCard.activate(pos.x, pos.y, true, false); gameLayer.addChild(mergedCard); gameState.aiPlayArea[target.row][target.col] = mergedCard; // ADD MISSING LEVEL UP EFFECTS: mergedCard.alpha = 0; mergedCard.scaleX = mergedCard.scaleY = 1.5; tween(mergedCard, { alpha: 1, scaleX: 1, scaleY: 1 }, { duration: 200, easing: tween.elasticOut }); // Level Up floating text createFloatingText('+Level Up!', mergedCard.x, mergedCard.y - 50, 0x00ff00, 60); // Damage increase stats text (similar to mergeCards function) var damageBefore = Math.floor(10 * Math.pow(1.6, oldLevel - 1)); var damageAfter = Math.floor(10 * Math.pow(1.6, mergedCard.level - 1)); var statText = ""; if (damageBefore > 0) { var dmgMult = (damageAfter / damageBefore).toFixed(2); statText = "Dmg x" + dmgMult; } createFloatingText(statText, mergedCard.x, mergedCard.y + 55, 0x00ff00, 35); // Update hand bonuses this.applyAIHandBonuses(); } }.bind(this) }); }
Code edit (1 edits merged)
Please save this source code
User prompt
When the AI merges cards that have the sabotage mod, it targets its own cards, not the player as it should.
User prompt
When the lock boss locks card, do not tint the cards white.
User prompt
Update with: makeMove: function makeMove() { var difficulty = getAIDifficultySettings(storage.battleRating); var totalCards = this.countTotalCards(); var emptySlots = this.countEmptySlots(); var boardSpaceRatio = totalCards / (PLAY_AREA_ROWS * PLAY_AREA_COLS); // PHASE 1: Fill the board first (priority when below target) var targetFill = difficulty.boardFillPriority || 0.95; if (boardSpaceRatio < targetFill) { if (this.shouldDeal()) { this.dealAIHand(); return; // ← Add this return! } if (this.tryPlaceCards()) { return; } } // PHASE 2: Smart merging based on damage calculations if (difficulty.canLevelUp && this.shouldMergeBasedOnDamage()) { if (this.tryMergeCards()) { return; } } // PHASE 3: Optimize positions var timeSinceLastOptimization = Date.now() - this.lastOptimizationTime; var optimizationDelay = boardSpaceRatio >= 0.95 ? 2000 : 3000; if (difficulty.shouldOptimize && boardSpaceRatio >= 0.7 && timeSinceLastOptimization > optimizationDelay) { if (this.optimizeCardPositions()) { this.lastOptimizationTime = Date.now(); return; } } // PHASE 4: Fill remaining empty slots if (this.shouldDeal()) { this.dealAIHand(); return; // ← Add this return! } // PHASE 5: EMERGENCY MODE - Board is full but AI has chips to spend // DON'T check shouldDeal() here - we want to force action even if shouldDeal() says no if (emptySlots === 0 && gameState.aiChips >= gameState.dealCost) { // Try to deal by merging (your new dealAIHand should handle this) this.dealAIHand(); return; // Alternative: Try emergency board-to-board merge if dealing fails // if (this.tryEmergencyMerge()) { // return; // } } },
User prompt
Update as needed with: makeMove: function makeMove() { var difficulty = getAIDifficultySettings(storage.battleRating); var totalCards = this.countTotalCards(); var emptySlots = this.countEmptySlots(); var boardSpaceRatio = totalCards / (PLAY_AREA_ROWS * PLAY_AREA_COLS); // PHASE 1: Fill the board first (priority when below target) var targetFill = difficulty.boardFillPriority || 0.95; if (boardSpaceRatio < targetFill) { if (this.shouldDeal()) { this.dealAIHand(); // This now uses the enhanced findBestEmptySlot() return; } // Try optimizing existing card positions if (this.tryPlaceCards()) { return; } } // PHASE 2: Smart merging based on damage calculations if (difficulty.canLevelUp && this.shouldMergeBasedOnDamage()) { if (this.tryMergeCards()) { return; } } // PHASE 3: Optimize positions (more frequent for poker hands) var timeSinceLastOptimization = Date.now() - this.lastOptimizationTime; var optimizationDelay = boardSpaceRatio >= 0.95 ? 2000 : 3000; // Faster when board full if (difficulty.shouldOptimize && boardSpaceRatio >= 0.7 && timeSinceLastOptimization > optimizationDelay) { if (this.optimizeCardPositions()) { this.lastOptimizationTime = Date.now(); return; } } // PHASE 4: Fill remaining empty slots if (this.shouldDeal()) { this.dealAIHand(); return; } // PHASE 5: EMERGENCY MODE - Board is full and AI wants to deal but can't if (emptySlots === 0 && this.shouldDeal() && gameState.aiChips >= gameState.dealCost) { // Try emergency board-to-board merge to free up space if (this.tryEmergencyMerge()) { return; } } },
Code edit (8 edits merged)
Please save this source code
User prompt
Replace with: dealAIHand: function dealAIHand() { if (gameState.aiChips < gameState.dealCost) { return; } gameState.aiChips -= gameState.dealCost; var cardData = CardSystem.dealUniqueCard(false, false); var startLevel = Math.floor((WaveSystem.waveNumber - 1) / 10) + 1; // Create a temporary card to evaluate placement vs merging var tempCard = new Card(cardData); tempCard.setLevel(startLevel); // Find best empty slot var bestEmptySlot = this.findBestEmptySlot(); var emptySlotScore = bestEmptySlot ? this.evaluateEmptySlotPlacement(bestEmptySlot.row, bestEmptySlot.col, tempCard) : -Infinity; // Find best merge target var bestMergeTarget = this.findBestMergeTarget(tempCard); var mergeScore = bestMergeTarget ? bestMergeTarget.score : -Infinity; // Choose the better option if (mergeScore > emptySlotScore && bestMergeTarget) { // Merge with existing card this.performMergeWithNewCard(tempCard, bestMergeTarget); } else if (bestEmptySlot) { // Place in empty slot (existing logic) this.placeCardInEmptySlot(tempCard, bestEmptySlot); } // If neither option is available, the card is lost (shouldn't happen) }, // New function to find the best card to merge with findBestMergeTarget: function findBestMergeTarget(newCard) { var bestTarget = null; var bestScore = -Infinity; for (var row = 0; row < PLAY_AREA_ROWS; row++) { for (var col = 0; col < PLAY_AREA_COLS; col++) { var boardCard = gameState.aiPlayArea[row][col]; if (!boardCard || !newCard.canMergeWith(boardCard)) { continue; } // Calculate merge value var currentDPS = boardCard.damage * (60 / boardCard.fireRate); var mergedDPS = this.simulateMergeDamage(newCard, boardCard); var dpsGain = mergedDPS - currentDPS; // Calculate hand bonus impact var handBonusScore = this.evaluateMergeHandBonus(row, col, newCard, boardCard); var totalScore = dpsGain + handBonusScore; if (totalScore > bestScore) { bestScore = totalScore; bestTarget = { card: boardCard, row: row, col: col, score: totalScore }; } } } return bestTarget; }, // New function to evaluate empty slot placement value evaluateEmptySlotPlacement: function evaluateEmptySlotPlacement(row, col, newCard) { var baseDPS = newCard.damage * (60 / newCard.fireRate); // Simulate hand bonus for placing in this position var simulatedHand = this.simulateHandAfterPlacement(row, col, newCard); var handBonusDPS = baseDPS * simulatedHand.multiplier; // Add positioning bonuses (prefer building toward poker hands) var positionBonus = this.evaluatePositionValue(row, col, newCard); return handBonusDPS + positionBonus; }, // New function to actually perform the merge performMergeWithNewCard: function performMergeWithNewCard(newCard, target) { var pos = getSlotPosition(target.row, target.col, false); // Create merge animation similar to player merges var startY = -SLOT_HEIGHT; newCard.x = pos.x; newCard.y = startY; gameLayer.addChild(newCard); // Animate new card moving to target tween(newCard, { y: pos.y }, { duration: 400, easing: tween.quadOut, onFinish: function() { // Perform the actual merge var mergedCard = newCard.mergeWith(target.card); if (mergedCard) { // Remove old cards if (newCard.parent) newCard.parent.removeChild(newCard); if (target.card.parent) target.card.parent.removeChild(target.card); // Place merged card mergedCard.activate(pos.x, pos.y, true, false); gameLayer.addChild(mergedCard); gameState.aiPlayArea[target.row][target.col] = mergedCard; // Update hand bonuses this.applyAIHandBonuses(); } }.bind(this) }); }
User prompt
Please fix the bug: 'TypeError: this.evaluateRowHand is not a function' in or related to this line: 'var currentHandEval = this.evaluateRowHand(mergeRow, false);' Line Number: 7091
Code edit (1 edits merged)
Please save this source code
/**** 
* Plugins
****/ 
var tween = LK.import("@upit/tween.v1");
var storage = LK.import("@upit/storage.v1", {
	battleRating: 0,
	money: 0,
	ownedMods: {},
	randomModPrice: 300,
	tutorialCompleted: false,
	coopHighestWave: 0
});
/**** 
* Classes
****/ 
/**** 
* Bullet Class
****/ 
var Bullet = Container.expand(function () {
	var self = Container.call(this);
	self.active = false;
	self.target = null;
	self.damage = 10;
	self.speed = 11.5;
	self.isPlayerCard = true;
	self.isSeekingLastPosition = false;
	self.targetLastX = 0;
	self.targetLastY = 0;
	self.level = 1;
	self.ricochetCount = 0;
	self.ricochetedFrom = [];
	var currentGraphic = null;
	// Add suitCircle backgrounds for each suit
	var suitCircleGraphics = {
		'hearts': self.attachAsset('suitCircle', {
			anchorX: 0.5,
			anchorY: 0.5
		}),
		'diamonds': self.attachAsset('suitCircle', {
			anchorX: 0.5,
			anchorY: 0.5
		}),
		'clubs': self.attachAsset('suitCircle', {
			anchorX: 0.5,
			anchorY: 0.5
		}),
		'spades': self.attachAsset('suitCircle', {
			anchorX: 0.5,
			anchorY: 0.5
		})
	};
	var baseSuitGraphics = {
		'hearts': self.attachAsset('heartSuit', {
			anchorX: 0.5,
			anchorY: 0.5
		}),
		'diamonds': self.attachAsset('diamondSuit', {
			anchorX: 0.5,
			anchorY: 0.5
		}),
		'clubs': self.attachAsset('clubSuit', {
			anchorX: 0.5,
			anchorY: 0.5
		}),
		'spades': self.attachAsset('spadeSuit', {
			anchorX: 0.5,
			anchorY: 0.5
		})
	};
	var modGraphicsCache = {};
	// Set scale and hide all suit graphics and suit circles initially.
	for (var suit in baseSuitGraphics) {
		var graphic = baseSuitGraphics[suit];
		var circle = suitCircleGraphics[suit];
		graphic.scale.set(0.3); // Small bullets
		graphic.visible = false;
		if (circle) {
			circle.scale.set(0.45); // Slightly larger than suit icon
			circle.visible = false;
			// Ensure circle is rendered below the suit icon
			self.setChildIndex(circle, Math.max(0, self.getChildIndex(graphic) - 1));
		}
	}
	self.activate = function (startX, startY, target, damage, suit, isPlayerCard, level) {
		self.active = true;
		self.visible = true;
		self.x = startX;
		self.y = startY;
		self.target = target;
		self.damage = damage;
		self.isPlayerCard = isPlayerCard;
		self.level = level || 1;
		self.suit = suit || 'hearts';
		self.isSeekingLastPosition = false;
		self.ricochetCount = 0;
		self.ricochetedFrom = [];
		self.hasRetargeted = false;
		if (suit === 'clubs' && ModSystem.getEquippedModAsset('clubs', isPlayerCard) === 'ricochetClubsMod') {
			// 3 bounces, +1 every 2 levels. Max 6. (Increased by 1)
			self.ricochetCount = Math.min(6, 3 + Math.floor((self.level - 1) / 2));
		}
		if (self.target) {
			self.targetLastX = self.target.x;
			self.targetLastY = self.target.y;
		}
		// Hide previous suitCircle if any
		if (currentGraphic) {
			currentGraphic.visible = false;
			// Hide all suit circles
			for (var suitKey in suitCircleGraphics) {
				if (suitCircleGraphics[suitKey]) {
					suitCircleGraphics[suitKey].visible = false;
				}
			}
		}
		suit = suit || 'hearts';
		var equippedMod = ModSystem.getEquippedModAsset(suit, self.isPlayerCard);
		if (equippedMod) {
			if (!modGraphicsCache[equippedMod]) {
				modGraphicsCache[equippedMod] = self.attachAsset(equippedMod, {
					anchorX: 0.5,
					anchorY: 0.5
				});
				modGraphicsCache[equippedMod].scale.set(0.3);
				modGraphicsCache[equippedMod].visible = false;
			}
			currentGraphic = modGraphicsCache[equippedMod];
		} else {
			currentGraphic = baseSuitGraphics[suit];
		}
		currentGraphic.visible = true;
		// Show and position the suitCircle under the current suit asset
		if (suitCircleGraphics[suit]) {
			suitCircleGraphics[suit].visible = true;
			// Ensure suitCircle is rendered below the suit icon
			if (self.getChildIndex(suitCircleGraphics[suit]) > self.getChildIndex(currentGraphic)) {
				self.setChildIndex(suitCircleGraphics[suit], Math.max(0, self.getChildIndex(currentGraphic) - 1));
			}
			// Center the circle (should already be, but for safety)
			suitCircleGraphics[suit].x = 0;
			suitCircleGraphics[suit].y = 0;
		}
	};
	self.findNewTarget = function () {
		// Use the same targeting logic as cards, but from bullet's perspective
		var targets;
		if (gameMode === 'coop') {
			targets = activePlayerChips.concat(activeAIChips);
		} else {
			targets = self.isPlayerCard ? activePlayerChips : activeAIChips;
		}
		var bestTarget = null;
		var shortestDistanceSq = Infinity;
		var turningPointY = SCREEN_HEIGHT / 2 - 200;
		for (var i = 0; i < targets.length; i++) {
			var chip = targets[i];
			if (chip.active) {
				if (gameMode === 'coop') {
					var isPlayerChip = chip.isPlayerSide;
					var isPlayerBullet = self.isPlayerCard;
					var onHorizontalPath = isPlayerChip ? chip.y <= turningPointY : chip.y >= turningPointY;
					if (!onHorizontalPath) {
						if (isPlayerBullet !== isPlayerChip) {
							continue;
						}
					}
				}
				var dx = chip.x - self.x;
				var dy = chip.y - self.y;
				var distanceSq = dx * dx + dy * dy;
				if (distanceSq < shortestDistanceSq) {
					shortestDistanceSq = distanceSq;
					bestTarget = chip;
				}
			}
		}
		return bestTarget;
	};
	self.findRicochetTarget = function () {
		// Use the same targeting logic as cards, but from bullet's perspective
		var targets;
		if (gameMode === 'coop') {
			targets = activePlayerChips.concat(activeAIChips);
		} else {
			targets = self.isPlayerCard ? activePlayerChips : activeAIChips;
		}
		var bestTarget = null;
		var shortestDistanceSq = Infinity;
		var turningPointY = SCREEN_HEIGHT / 2 - 200;
		for (var i = 0; i < targets.length; i++) {
			var potentialTarget = targets[i];
			if (potentialTarget.active && self.ricochetedFrom.indexOf(potentialTarget) === -1) {
				if (gameMode === 'coop') {
					var isPlayerChip = potentialTarget.isPlayerSide;
					var isPlayerBullet = self.isPlayerCard;
					var onHorizontalPath = isPlayerChip ? potentialTarget.y <= turningPointY : potentialTarget.y >= turningPointY;
					if (!onHorizontalPath) {
						if (isPlayerBullet !== isPlayerChip) {
							continue;
						}
					}
				}
				var dx = potentialTarget.x - self.x;
				var dy = potentialTarget.y - self.y;
				var distanceSq = dx * dx + dy * dy;
				if (distanceSq < shortestDistanceSq) {
					shortestDistanceSq = distanceSq;
					bestTarget = potentialTarget;
				}
			}
		}
		return bestTarget;
	};
	self.update = function () {
		if (!self.active) {
			return;
		}
		// If target is destroyed, try to find a new target instead of seeking last position
		if (self.target && !self.target.active) {
			var newTarget = null;
			if (!self.hasRetargeted) {
				newTarget = self.findNewTarget();
			}
			if (newTarget) {
				self.target = newTarget;
				self.targetLastX = newTarget.x;
				self.targetLastY = newTarget.y;
				self.hasRetargeted = true;
			} else {
				// No new target available, or already retargeted. Seek last position.
				self.isSeekingLastPosition = true;
				self.target = null;
			}
		}
		// If seeking, move towards the last position
		if (self.isSeekingLastPosition) {
			var dx = self.targetLastX - self.x;
			var dy = self.targetLastY - self.y;
			var distance = Math.sqrt(dx * dx + dy * dy);
			if (distance < self.speed) {
				// Arrived at destination, recycle bullet
				self.isSeekingLastPosition = false;
				if (currentGraphic) {
					currentGraphic.visible = false;
				}
				PoolManager.returnBullet(self);
			} else {
				// Move towards destination
				var angle = Math.atan2(dy, dx);
				self.x += Math.cos(angle) * self.speed;
				self.y += Math.sin(angle) * self.speed;
			}
		} else if (self.target) {
			// Store previous position for continuous collision detection
			var prevX = self.x;
			var prevY = self.y;
			// Update last known position
			self.targetLastX = self.target.x;
			self.targetLastY = self.target.y;
			var dx = self.target.x - self.x;
			var dy = self.target.y - self.y;
			var distance = Math.sqrt(dx * dx + dy * dy);
			// Calculate where bullet will be after this frame
			var angle = Math.atan2(dy, dx);
			var newX = self.x + Math.cos(angle) * self.speed;
			var newY = self.y + Math.sin(angle) * self.speed;
			// RELIABLE COLLISION DETECTION:
			// Check if the bullet's path for this frame intersects the target's radius.
			// This prevents "tunneling" where a fast bullet could pass through a target between frames.
			var hitRadius = 85; // Visual radius of the chip, matches chip graphics
			var collisionDistance = distancePointToLine(self.target.x, self.target.y, prevX, prevY, newX, newY);
			if (collisionDistance <= hitRadius) {
				// Hit detected
				// NEW: Check for Execute mod for Spades BEFORE dealing damage
				if (self.suit === 'spades' && ModSystem.getEquippedModAsset('spades', self.isPlayerCard) === 'deathSpadesMod') {
					// Execute threshold: starts at 15%, +1% per level. Max 40%.
					var executeThreshold = Math.min(0.60, 0.25 + (self.level - 1) * 0.01);
					// Execute chance: starts at 20%, +2% per level. Max 50%.
					var executeChance = Math.min(0.50, 0.20 + (self.level - 1) * 0.02);
					if (self.target.health / self.target.maxHealth <= executeThreshold) {
						if (Math.random() < executeChance) {
							// Execute!
							createFloatingText('EXECUTE!', self.target.x, self.target.y - 60, 0xaa00aa, 50);
							// Create the execution animation
							var executionEffect = LK.getAsset('deathSpadesMod', {
								anchorX: 0.5,
								anchorY: 0.5,
								x: self.target.x,
								y: self.target.y,
								scaleX: 0.1,
								scaleY: 0.1,
								alpha: 1
							});
							gameLayer.addChild(executionEffect);
							tween(executionEffect, {
								scaleX: 2,
								scaleY: 2,
								alpha: 0
							}, {
								duration: 500,
								easing: tween.quadOut,
								onFinish: function onFinish() {
									if (executionEffect.parent) {
										executionEffect.parent.removeChild(executionEffect);
									}
								}
							});
							self.target.takeDamage(self.target.health, self.isPlayerCard); // Deal fatal damage
							// Recycle bullet and stop further processing
							if (currentGraphic) {
								currentGraphic.visible = false;
							}
							PoolManager.returnBullet(self);
							return; // IMPORTANT: Exit update for this bullet
						}
					}
				}
				// If not executed, proceed with normal hit logic
				self.target.takeDamage(self.damage, self.isPlayerCard, self.suit);
				// NEW: Check if this is a hearts bullet and flame mod is equipped
				if (self.suit === 'hearts' && ModSystem.getEquippedModAsset('hearts', self.isPlayerCard) === 'burnHeartMod') {
					// Calculate burn damage (10% of hit damage per tick)
					var burnDamage = self.damage * 0.1;
					// Increase burn duration by 50% (from 5 to 7.5 ticks)
					var burnDuration = Math.round(5 * 1.5); // 7.5 → 8 ticks = ~4 seconds of burning
					// Apply burn effect
					self.target.applyBurn(burnDamage, burnDuration, self.isPlayerCard);
				}
				// NEW: Check if this is a spades bullet and freeze mod is equipped
				if (self.suit === 'spades' && ModSystem.getEquippedModAsset('spades', self.isPlayerCard) === 'freezeSpadeMod') {
					// Calculate freeze duration (3 seconds base)
					var freezeDuration = 180; // 180 ticks at 60fps = 3 seconds
					// Apply freeze effect
					self.target.applyFreeze(freezeDuration);
				}
				// NEW: Check if this is a clubs bullet and slow mod is equipped
				if (self.suit === 'clubs' && ModSystem.getEquippedModAsset('clubs', self.isPlayerCard) === 'slowClubsMod') {
					// Slow amount: 20% base, +5% per level. Max 70%.
					var slowAmount = Math.min(0.7, 0.2 + (self.level - 1) * 0.05);
					// Slow duration: 2s base, +0.5s per level.
					var slowDuration = 120 + (self.level - 1) * 30; // 120 ticks = 2s
					self.target.applySlow(slowAmount, slowDuration);
				}
				// NEW: Check if this is a clubs bullet and toxin mod is equipped
				if (self.suit === 'clubs' && ModSystem.getEquippedModAsset('clubs', self.isPlayerCard) === 'toxinClubMod') {
					// Calculate poison damage (5% of hit damage per tick)
					var poisonDamage = self.damage * 0.05;
					var poisonDuration = 10; // 10 ticks
					// Apply poison effect
					if (self.target && typeof self.target.applyPoison === "function") {
						self.target.applyPoison(poisonDamage, poisonDuration, self.isPlayerCard);
					}
				}
				// NEW: Check for ricochet mod for clubs
				if (self.ricochetCount > 0) {
					self.ricochetedFrom.push(self.target);
					var newTarget = self.findRicochetTarget();
					if (newTarget) {
						self.target = newTarget;
						self.targetLastX = newTarget.x;
						self.targetLastY = newTarget.y;
						self.ricochetCount--;
						self.damage = Math.floor(self.damage * 0.7); // 70% damage on next hit
						// Visual feedback for ricochet
						createExplosion(self.x, self.y, 0xcccccc);
						return; // Keep the bullet alive and moving to the new target
					}
				}
				if (currentGraphic) {
					currentGraphic.visible = false;
				}
				PoolManager.returnBullet(self);
			} else {
				// No hit, move bullet forward
				self.x = newX;
				self.y = newY;
			}
		} else {
			// No target and not seeking, recycle
			if (currentGraphic) {
				currentGraphic.visible = false;
			}
			PoolManager.returnBullet(self);
		}
	};
	return self;
});
// Helper function to calculate distance from point to line segment
/**** 
* Object Pool Manager
****/ 
/**** 
* Card Class
****/ 
var Card = Container.expand(function (cardData) {
	var self = Container.call(this);
	self.cardData = cardData;
	self.level = 1;
	self.isInPlay = false;
	self.isPlayerCard = true; // Track which player owns this card
	self.playSlotX = 0;
	self.playSlotY = 0;
	self.lastFired = 0;
	self.fireRate = 60; // Base fire rate (ticks between shots)
	self.damage = 35; // Increased base damage
	self.range = 200;
	self.handBonus = 1;
	self.timeOnBoard = 0;
	self.lastIncomeTick = 0;
	var redOutline = self.attachAsset('card', {
		anchorX: 0.5,
		anchorY: 0.5
	});
	redOutline.scale.set(1.1);
	redOutline.alpha = 1.0;
	redOutline.tint = 0xff0000; // Red color
	redOutline.visible = false;
	self.redOutline = redOutline;
	var greenOutline = self.attachAsset('card', {
		anchorX: 0.5,
		anchorY: 0.5
	});
	greenOutline.scale.set(1.1);
	greenOutline.alpha = 0.7;
	greenOutline.tint = 0x00ff00;
	greenOutline.visible = false;
	self.greenOutline = greenOutline;
	var cardGraphics = self.attachAsset('card', {
		anchorX: 0.5,
		anchorY: 0.5
	});
	// Define getSuitSymbol method before using it
	self.getSuitSymbol = function (suit) {
		switch (suit) {
			case 'hearts':
				return '♥';
			case 'diamonds':
				return '♦';
			case 'clubs':
				return '♣';
			case 'spades':
				return '♠';
			case 'joker':
				return '🃏';
			default:
				return '?';
		}
	};
	// Card value in top left corner
	if (cardData.suit !== 'joker') {
		var valueText = new Text2(cardData.value, {
			size: 56,
			fill: CardSystem.suitColors[cardData.suit] || 0x000000,
			weight: 800,
			stroke: 0x000000,
			strokeThickness: 0
		});
		valueText.anchor.set(0, 0);
		valueText.x = -95; // Top left
		valueText.y = -135;
		self.addChild(valueText);
	}
	// Large suit symbol in center, deferred to activate()
	var suitGraphics = null;
	var jokerSuitGraphics = null;
	// Level text at bottom
	var levelText = new Text2('Lvl 1', {
		size: 45,
		fill: 0x000000,
		weight: 800,
		stroke: 0x000000,
		strokeThickness: 0
	});
	levelText.anchor.set(0.5, 1);
	levelText.y = 128; // Bottom of card
	self.addChild(levelText);
	self.activate = function (x, y, inPlay, isPlayerCard) {
		self.x = x;
		self.y = y;
		self.isInPlay = inPlay || false;
		self.isPlayerCard = isPlayerCard !== undefined ? isPlayerCard : true;
		self.visible = true;
		// Remove old graphics if they exist
		if (suitGraphics && suitGraphics.parent) {
			suitGraphics.parent.removeChild(suitGraphics);
			suitGraphics = null;
		}
		if (jokerSuitGraphics && jokerSuitGraphics.parent) {
			jokerSuitGraphics.parent.removeChild(jokerSuitGraphics);
			jokerSuitGraphics = null;
		}
		// Create new suit graphic based on player/AI context
		var suitAssetId = null;
		var equippedMod = ModSystem.getEquippedModAsset(self.cardData.suit, self.isPlayerCard);
		if (equippedMod) {
			suitAssetId = equippedMod;
		} else {
			switch (self.cardData.suit) {
				case 'hearts':
					suitAssetId = 'heartSuit';
					break;
				case 'diamonds':
					suitAssetId = 'diamondSuit';
					break;
				case 'clubs':
					suitAssetId = 'clubSuit';
					break;
				case 'spades':
					suitAssetId = 'spadeSuit';
					break;
			}
		}
		if (suitAssetId) {
			suitGraphics = self.attachAsset(suitAssetId, {
				anchorX: 0.5,
				anchorY: 0.5
			});
			suitGraphics.y = -15;
			suitGraphics.scaleX = suitGraphics.scaleY = 0.8;
		} else if (self.cardData.suit === 'joker') {
			jokerSuitGraphics = self.attachAsset('jokerSuit', {
				anchorX: 0.5,
				anchorY: 0.5
			});
			jokerSuitGraphics.y = -15;
			jokerSuitGraphics.scale.set(1.5);
		}
		if (inPlay) {
			self.calculateStats();
		}
	};
	self.recreateVisuals = function (currentLevel) {
		// Remove ALL visual elements (we'll recreate everything)
		var childrenToRemove = [];
		for (var i = 0; i < self.children.length; i++) {
			var child = self.children[i];
			// Only keep the red and green outlines
			if (child !== self.redOutline && child !== self.greenOutline) {
				childrenToRemove.push(child);
			}
		}
		// Remove the identified children
		childrenToRemove.forEach(function (child) {
			if (child.parent) {
				child.parent.removeChild(child);
			}
		});
		// RECREATE THE MAIN CARD BACKGROUND
		var cardGraphics = self.attachAsset('card', {
			anchorX: 0.5,
			anchorY: 0.5
		});
		// Recreate card value text in top left corner (if not joker)
		if (self.cardData.suit !== 'joker') {
			var valueText = new Text2(self.cardData.value, {
				size: 56,
				fill: CardSystem.suitColors[self.cardData.suit] || 0x000000,
				weight: 800,
				stroke: 0x000000,
				strokeThickness: 0
			});
			valueText.anchor.set(0, 0);
			valueText.x = -95; // Top left
			valueText.y = -135;
			self.addChild(valueText);
		}
		// Recreate level text at bottom
		var levelText = new Text2('Lvl ' + currentLevel, {
			size: 45,
			fill: 0x000000,
			weight: 800,
			stroke: 0x000000,
			strokeThickness: 0
		});
		levelText.anchor.set(0.5, 1);
		levelText.y = 128; // Bottom of card
		self.addChild(levelText);
		// Set level to trigger stats recalculation
		self.setLevel(currentLevel);
	};
	self.calculateStats = function () {
		// Stats based on level only, not card face value
		var baseDamage = 10; // Reduced base damage
		var baseFireRate = 60;
		// Level scaling - more dramatic improvements per level
		self.damage = Math.floor(baseDamage * Math.pow(1.6, self.level - 1)); // Further decreased scaling from 1.7 to 1.6
		self.fireRate = Math.max(15, Math.floor(baseFireRate / Math.pow(1.2, self.level - 1))); // Reduced from 1.25 to 1.2
		// Apply poker hand bonus
		self.damage = Math.floor(self.damage * self.handBonus);
		self.fireRate = Math.max(10, Math.floor(self.fireRate / self.handBonus));
		// NEW: Apply Wildcard penalty
		if (self.cardData.suit === 'hearts' && ModSystem.getEquippedModAsset('hearts', self.isPlayerCard) === 'wildcardHeartMod') {
			self.damage = Math.floor(self.damage * 0.6); // 40% damage reduction
		}
		// NEW: Apply Gambit Diamond Mod bonuses
		if (self.cardData.suit === 'diamonds' && ModSystem.getEquippedModAsset('diamonds', self.isPlayerCard) === 'gambitDiamondMod') {
			var cardValue = CardSystem.getCardValue(self);
			var isOdd = false;
			// Check if card value is odd (A=14, K=13, Q=12, J=11)
			if (cardValue === 14 || cardValue === 13 || cardValue === 11 ||
			// A, K, J
			cardValue === 9 || cardValue === 7 || cardValue === 5 || cardValue === 3) {
				isOdd = true;
			}
			if (isOdd) {
				// Odd cards: +30% attack speed (reduce fire rate)
				self.fireRate = Math.max(10, Math.floor(self.fireRate * 0.7)); // 30% faster = 70% of original time
			} else {
				// Even cards: +40% attack power
				self.damage = Math.floor(self.damage * 1.4); // 40% more damage
			}
		}
		// NEW: Apply mod-specific stat changes
		if (self.cardData.suit === 'spades' && ModSystem.getEquippedModAsset('spades', self.isPlayerCard) === 'mineSpadesMod') {
			// Mine mod significantly slows fire rate in exchange for higher damage per mine.
			self.fireRate *= 2.5;
		}
	};
	self.setLevel = function (newLevel) {
		if (self.cardData.suit === 'joker') {
			self.level = 1;
			levelText.visible = false;
			self.calculateStats();
			return;
		}
		self.level = newLevel;
		levelText.setText('Lvl ' + self.level);
		self.calculateStats();
		self.resetInvestment();
		// Visual feedback for higher levels
		if (self.level > 1) {
			// The glow effect was causing cards to become translucent.
			// Level up is already indicated by animation and floating text.
		}
	};
	self.resetInvestment = function () {
		self.timeOnBoard = 0;
		self.lastIncomeTick = LK.ticks;
	};
	self.canMergeWith = function (otherCard) {
		if (!otherCard || otherCard === self) {
			return false;
		}
		// If the card being dropped onto is a Joker, it cannot be leveled up.
		if (otherCard.cardData && otherCard.cardData.suit === 'joker') {
			return false;
		}
		// If the card being dragged is a Joker, it can merge with any non-Joker card.
		if (self.cardData.suit === 'joker') {
			return true;
		}
		// NEW: If dragged card is Hearts with Wildcard mod, can merge with any same-level card
		if (self.cardData.suit === 'hearts' && ModSystem.getEquippedModAsset('hearts', self.isPlayerCard) === 'wildcardHeartMod' && self.level === otherCard.level) {
			return true;
		}
		// Must be same level AND (same suit OR same value)
		var sameLevel = self.level === otherCard.level;
		var sameSuit = self.cardData.suit === otherCard.cardData.suit;
		var sameValue = self.cardData.value === otherCard.cardData.value;
		return sameLevel && (sameSuit || sameValue);
	};
	self.mergeWith = function (otherCard) {
		if (!self.canMergeWith(otherCard)) {
			return null;
		}
		// ... existing merge logic ...
		// When merging, the new card levels up. The new level is one higher than the card on the board.
		var newLevel = otherCard.level + 1;
		// Special case: If the card being dragged is a Joker, the target card just increases its level
		if (self.cardData.suit === 'joker') {
			var mergedCard = new Card(otherCard.cardData);
			mergedCard.setLevel(newLevel);
			return mergedCard;
		}
		// NEW: Trigger sabotage effect if either card involved in the merge is a sabotage mod card
		var isSabotageInvolved = self.cardData.suit === 'spades' && ModSystem.getEquippedModAsset('spades', self.isPlayerCard) === 'sabotageSpadesMod' || otherCard.cardData.suit === 'spades' && ModSystem.getEquippedModAsset('spades', otherCard.isPlayerCard) === 'sabotageSpadesMod';
		if (isSabotageInvolved) {
			// Always call sabotage from the perspective of the player who performed the merge
			// If AI is merging, sabotage the player; if player is merging, sabotage the AI; in coop, boost the other side
			if (typeof self.performSabotage === "function") {
				// Determine which side is performing the merge
				var sabotageCard;
				// Determine which card should perform sabotage based on who has the sabotage mod
				var selfHasSabotage = self.cardData.suit === 'spades' && ModSystem.getEquippedModAsset('spades', self.isPlayerCard) === 'sabotageSpadesMod';
				var otherHasSabotage = otherCard.cardData.suit === 'spades' && ModSystem.getEquippedModAsset('spades', otherCard.isPlayerCard) === 'sabotageSpadesMod';
				if (selfHasSabotage) {
					// If self has sabotage, use self (maintains merge initiator's context)
					sabotageCard = self;
				} else if (otherHasSabotage) {
					// If only otherCard has sabotage, use otherCard
					sabotageCard = otherCard;
				}
				// Call performSabotage with correct context
				sabotageCard.performSabotage();
			}
		}
		// The new card is of a random type that doesn't already exist on this side
		var newCardData = CardSystem.generateUniqueCard(self.isPlayerCard);
		var mergedCard = new Card(newCardData);
		mergedCard.setLevel(newLevel);
		return mergedCard;
	};
	self.findTarget = function () {
		// Player cards target enemies attacking the player (activePlayerChips)
		// AI cards target enemies attacking the AI (activeAIChips)
		var targets;
		if (gameMode === 'coop') {
			// In coop, start with all targets and filter based on position
			targets = activePlayerChips.concat(activeAIChips);
		} else {
			targets = self.isPlayerCard ? activePlayerChips : activeAIChips;
		}
		var bestTarget = null;
		var highestProgress = -1;
		var turningPointY = SCREEN_HEIGHT / 2 - 200;
		for (var i = 0; i < targets.length; i++) {
			var chip = targets[i];
			// Add extra validation for alive targets
			if (chip.active && chip.health > 0 && chip.visible && chip.pathProgress > highestProgress) {
				if (gameMode === 'coop') {
					var isPlayerChip = chip.isPlayerSide;
					var isPlayerCard = self.isPlayerCard;
					// Player chips move up (y decreases), AI chips move down (y increases).
					var onHorizontalPath = isPlayerChip ? chip.y <= turningPointY : chip.y >= turningPointY;
					if (!onHorizontalPath) {
						// Not on the shared horizontal path yet, so cards can only target their own side's enemies.
						if (isPlayerCard !== isPlayerChip) {
							continue;
						}
					}
					// If onHorizontalPath is true, any card can target the chip, so no 'continue' needed.
				}
				highestProgress = chip.pathProgress;
				bestTarget = chip;
			}
		}
		return bestTarget;
	};
	self.fire = function () {
		// Add this check at the beginning of Card.fire function:
		if (self.isLocked) {
			return; // Locked cards cannot fire
		}
		var target = self.findTarget();
		if (!target) {
			return;
		}
		// NEW: Handle Mine Spades Mod
		if (self.cardData.suit === 'spades' && ModSystem.getEquippedModAsset('spades', self.isPlayerCard) === 'mineSpadesMod') {
			var mine = PoolManager.getMine(self.isPlayerCard);
			if (mine) {
				var pathProgress = Math.random() * 70 + 15;
				var minePos = PathSystem.getPositionAlongPath(pathProgress, self.isPlayerCard);
				var mineDamage = Math.floor(self.damage * 2); // Mines deal 2.5x card damage
				mine.activate(minePos.x, minePos.y, mineDamage, self.isPlayerCard);
				gameLayer.addChild(mine);
				activeMines.push(mine);
			}
		} else {
			var damageToDeal = self.damage;
			// NEW: Calculate Unity Bonus for Hearts
			if (self.cardData.suit === 'hearts' && ModSystem.getEquippedModAsset('hearts', self.isPlayerCard) === 'unityHeartsMod') {
				var playArea = self.isPlayerCard ? gameState.playerPlayArea : gameState.aiPlayArea;
				var cardRow = -1,
					cardCol = -1;
				// Find card's position in the grid
				for (var r = 0; r < PLAY_AREA_ROWS; r++) {
					for (var c = 0; c < PLAY_AREA_COLS; c++) {
						if (playArea[r][c] === self) {
							cardRow = r;
							cardCol = c;
							break;
						}
					}
					if (cardRow !== -1) {
						break;
					}
				}
				if (cardRow !== -1) {
					var adjacentHearts = 0;
					var neighbors = [[cardRow - 1, cardCol], [cardRow + 1, cardCol], [cardRow, cardCol - 1], [cardRow, cardCol + 1]];
					for (var i = 0; i < neighbors.length; i++) {
						var nRow = neighbors[i][0];
						var nCol = neighbors[i][1];
						// ADD BOUNDS CHECKING HERE
						if (nRow >= 0 && nRow < PLAY_AREA_ROWS && nCol >= 0 && nCol < PLAY_AREA_COLS) {
							var neighborCard = playArea[nRow][nCol];
							if (neighborCard && neighborCard.cardData.suit === 'hearts' && ModSystem.getEquippedModAsset('hearts', neighborCard.isPlayerCard) === 'unityHeartsMod') {
								adjacentHearts++;
							}
						}
					}
					// Each adjacent heart adds 25% bonus damage
					damageToDeal = Math.floor(damageToDeal * (1 + 0.20 * adjacentHearts));
				}
			}
			// NEW: Calculate Gambler Bonus for Diamonds
			if (self.cardData.suit === 'diamonds' && ModSystem.getEquippedModAsset('diamonds', self.isPlayerCard) === 'gamblerDiamondsMod') {
				// Base 50% chance of double damage, increases by 5% per level. Capped at 95%.
				var doubleDamageChance = Math.min(0.95, 0.5 + (self.level - 1) * 0.05);
				if (Math.random() < doubleDamageChance) {
					damageToDeal *= 2;
					createFloatingText('x2!', self.x, self.y - 70, 0xffd700, 30);
				} else {
					damageToDeal = Math.max(1, Math.floor(damageToDeal * 0.75)); // Changed from 0 to 10% damage
					createFloatingText('Weak!', self.x, self.y - 70, 0xaaaaaa, 30); // Changed text
				}
			}
			// NEW: Calculate Boost from adjacent Diamonds
			var playArea = self.isPlayerCard ? gameState.playerPlayArea : gameState.aiPlayArea;
			var cardRow = -1,
				cardCol = -1;
			// Find card's position in the grid
			for (var r = 0; r < PLAY_AREA_ROWS; r++) {
				for (var c = 0; c < PLAY_AREA_COLS; c++) {
					if (playArea[r][c] === self) {
						cardRow = r;
						cardCol = c;
						break;
					}
				}
				if (cardRow !== -1) {
					break;
				}
			}
			if (cardRow !== -1) {
				var totalBoostPercentage = 0;
				var neighbors = [[cardRow - 1, cardCol], [cardRow + 1, cardCol], [cardRow, cardCol - 1], [cardRow, cardCol + 1]];
				for (var i = 0; i < neighbors.length; i++) {
					var nRow = neighbors[i][0];
					var nCol = neighbors[i][1];
					if (nRow >= 0 && nRow < PLAY_AREA_ROWS && nCol >= 0 && nCol < PLAY_AREA_COLS) {
						var neighborCard = playArea[nRow][nCol];
						if (neighborCard && neighborCard.cardData.suit === 'diamonds' && ModSystem.getEquippedModAsset('diamonds', neighborCard.isPlayerCard) === 'boostDiamondsMod') {
							// Each level of the booster card adds 8% damage.
							totalBoostPercentage += neighborCard.level * 0.08;
						}
					}
				}
				if (totalBoostPercentage > 0) {
					damageToDeal = Math.floor(damageToDeal * (1 + totalBoostPercentage));
				}
			}
			// Check if this is a clubs card with spreadshot mod equipped
			var isSpreadshot = self.cardData.suit === 'clubs' && ModSystem.getEquippedModAsset('clubs', self.isPlayerCard) === 'spreadClubMod';
			if (isSpreadshot) {
				// Spreadshot: reduced damage but hits multiple targets
				var spreadDamage = Math.floor(self.damage * 0.5);
				var maxTargets = Math.min(1 + self.level, 5);
				var allTargets;
				if (gameMode === 'coop') {
					allTargets = activePlayerChips.concat(activeAIChips);
				} else {
					allTargets = self.isPlayerCard ? activePlayerChips : activeAIChips;
				}
				var closestTargets = []; // This will store {chip, distanceSq} objects
				var turningPointY = SCREEN_HEIGHT / 2 - 200;
				// Find multiple targets using an efficient selection method instead of sorting all targets
				for (var i = 0; i < allTargets.length; i++) {
					var chip = allTargets[i];
					if (chip.active && chip.health > 0 && chip.visible) {
						if (gameMode === 'coop') {
							var isPlayerChip = chip.isPlayerSide;
							var isPlayerCard = self.isPlayerCard;
							var onHorizontalPath = isPlayerChip ? chip.y <= turningPointY : chip.y >= turningPointY;
							if (!onHorizontalPath) {
								if (isPlayerCard !== isPlayerChip) {
									continue;
								}
							}
						}
						var dx = chip.x - self.x;
						var dy = chip.y - self.y;
						var distanceSq = dx * dx + dy * dy;
						if (closestTargets.length < maxTargets) {
							closestTargets.push({
								chip: chip,
								distanceSq: distanceSq
							});
						} else {
							var furthestDistSq = -1;
							var furthestIdx = -1;
							for (var j = 0; j < closestTargets.length; j++) {
								if (closestTargets[j].distanceSq > furthestDistSq) {
									furthestDistSq = closestTargets[j].distanceSq;
									furthestIdx = j;
								}
							}
							if (distanceSq < furthestDistSq) {
								closestTargets[furthestIdx] = {
									chip: chip,
									distanceSq: distanceSq
								};
							}
						}
					}
				}
				// Fire at the found targets
				for (var i = 0; i < closestTargets.length; i++) {
					var bullet = PoolManager.getBullet();
					if (bullet) {
						bullet.activate(self.x, self.y, closestTargets[i].chip, spreadDamage, self.cardData.suit, self.isPlayerCard, self.level);
						gameLayer.addChild(bullet);
						activeBullets.push(bullet);
					}
				}
			} else {
				// Normal single-target firing
				var bullet = PoolManager.getBullet();
				if (bullet) {
					bullet.activate(self.x, self.y, target, damageToDeal, self.cardData.suit, self.isPlayerCard, self.level);
					gameLayer.addChild(bullet);
					activeBullets.push(bullet);
				}
			}
		}
		// Play shoot sound for player cards
		if (self.isPlayerCard) {
			LK.getSound('shootSound').play();
		}
		self.lastFired = LK.ticks;
		// Visual feedback for firing (enhanced for spreadshot)
		tween.stop(self, {
			scaleX: true,
			scaleY: true
		});
		var isSpreadshot = self.cardData.suit === 'clubs' && ModSystem.getEquippedModAsset('clubs', self.isPlayerCard) === 'spreadClubMod';
		var scaleAmount = isSpreadshot ? 0.8 : 0.9; // More dramatic scale for spreadshot
		tween(self, {
			scaleX: scaleAmount,
			scaleY: scaleAmount
		}, {
			duration: 100,
			easing: tween.quadOut,
			onFinish: function onFinish() {
				tween(self, {
					scaleX: 1,
					scaleY: 1
				}, {
					duration: 150,
					easing: tween.elasticOut
				});
			}
		});
	};
	self.update = function () {
		if (!self.isInPlay) {
			return;
		}
		// NEW: Handle Investment Hearts Mod
		if (self.cardData.suit === 'hearts' && ModSystem.getEquippedModAsset('hearts', self.isPlayerCard) === 'investmentHeartsMod') {
			// Generate income every 5 seconds (300 ticks)
			var incomeInterval = 300;
			if (LK.ticks - self.lastIncomeTick >= incomeInterval) {
				self.lastIncomeTick = LK.ticks;
				// timeOnBoard is a counter of income ticks, not actual ticks on board
				self.timeOnBoard++;
				// Income formula: 1 chip base, +1 for every 2 intervals (10 seconds). Max 3.
				var income = 1 + Math.floor(self.timeOnBoard / 2);
				income = Math.min(income, 3); // Cap income (CHANGED from 5 to 3)
				if (self.isPlayerCard) {
					gameState.playerChips += income;
					createFloatingText('+' + income, self.x, self.y - 70, 0xffd700, 30);
					updateUI();
				} else {
					// AI gets income too
					gameState.aiChips += income;
				}
			}
		}
		if (LK.ticks - self.lastFired >= self.fireRate) {
			self.fire();
		}
	};
	self.performSabotage = function () {
		// Always sabotage the OPPOSITE side of the card performing the merge
		if (gameMode === 'coop') {
			// Co-op: boost random ally card (player boosts AI, AI boosts player)
			var allyPlayArea = self.isPlayerCard ? gameState.aiPlayArea : gameState.playerPlayArea;
			var allyCandidates = [];
			for (var row = 0; row < PLAY_AREA_ROWS; row++) {
				for (var col = 0; col < PLAY_AREA_COLS; col++) {
					var card = allyPlayArea[row][col];
					if (card && card !== self) {
						allyCandidates.push(card);
					}
				}
			}
			if (allyCandidates.length > 0) {
				var targetCard = allyCandidates[Math.floor(Math.random() * allyCandidates.length)];
				targetCard.setLevel(targetCard.level + 1);
				createFloatingText('BOOSTED!', targetCard.x, targetCard.y - 50, 0x00ff00, 40);
			}
		} else {
			// PvP: sabotage random enemy card (AI sabotages player, player sabotages AI)
			// The enemy is always the OPPOSITE of self.isPlayerCard
			var enemyPlayArea = self.isPlayerCard ? gameState.aiPlayArea : gameState.playerPlayArea;
			var enemyCandidates = [];
			for (var row = 0; row < PLAY_AREA_ROWS; row++) {
				for (var col = 0; col < PLAY_AREA_COLS; col++) {
					var card = enemyPlayArea[row][col];
					if (card && card.level > 1) {
						// Only target cards that can be reduced
						enemyCandidates.push(card);
					}
				}
			}
			if (enemyCandidates.length > 0) {
				var targetCard = enemyCandidates[Math.floor(Math.random() * enemyCandidates.length)];
				targetCard.setLevel(targetCard.level - 1);
				createFloatingText('SABOTAGED!', targetCard.x, targetCard.y - 50, 0xff0000, 40);
			}
		}
	};
	self.setLevel(1);
	return self;
});
var Mine = Container.expand(function () {
	var self = Container.call(this);
	self.active = false;
	self.damage = 50;
	self.isPlayerMine = true;
	self.explosionRadiusSq = 150 * 150;
	var mineGraphics = self.attachAsset('mine', {
		anchorX: 0.5,
		anchorY: 0.5
	});
	mineGraphics.scale.set(0.8);
	self.activate = function (x, y, damage, isPlayerMine) {
		self.active = true;
		self.visible = true;
		self.x = x;
		self.y = y;
		self.damage = damage;
		self.isPlayerMine = isPlayerMine;
		self.scale.set(0.1);
		tween(self, {
			scaleX: 1,
			scaleY: 1
		}, {
			duration: 200,
			easing: tween.backOut
		});
	};
	self.explode = function () {
		if (!self.active) {
			return;
		}
		self.active = false;
		createExplosion(self.x, self.y, 0xffa500);
		var targets;
		if (gameMode === 'coop') {
			targets = activePlayerChips.concat(activeAIChips);
		} else {
			targets = self.isPlayerMine ? activePlayerChips : activeAIChips;
		}
		var turningPointY = SCREEN_HEIGHT / 2 - 200;
		for (var i = targets.length - 1; i >= 0; i--) {
			var chip = targets[i];
			if (chip.active) {
				if (gameMode === 'coop') {
					var isPlayerChip = chip.isPlayerSide;
					var onHorizontalPath = isPlayerChip ? chip.y <= turningPointY : chip.y >= turningPointY;
					if (!onHorizontalPath) {
						if (self.isPlayerMine !== isPlayerChip) {
							continue;
						}
					}
				}
				var dx = chip.x - self.x;
				var dy = chip.y - self.y;
				var distanceSq = dx * dx + dy * dy;
				if (distanceSq < self.explosionRadiusSq) {
					// Mines deal 'spades' damage since they're from the spades mod
					chip.takeDamage(self.damage, self.isPlayerMine, 'spades');
				}
			}
		}
		PoolManager.returnMine(self);
	};
	self.update = function () {
		if (!self.active) {
			return;
		}
		var targets;
		if (gameMode === 'coop') {
			targets = activePlayerChips.concat(activeAIChips);
		} else {
			targets = self.isPlayerMine ? activePlayerChips : activeAIChips;
		}
		var collisionRadiusSq = 45 * 45;
		var turningPointY = SCREEN_HEIGHT / 2 - 200;
		for (var i = 0; i < targets.length; i++) {
			var chip = targets[i];
			if (chip.active) {
				if (gameMode === 'coop') {
					var isPlayerChip = chip.isPlayerSide;
					var onHorizontalPath = isPlayerChip ? chip.y <= turningPointY : chip.y >= turningPointY;
					if (!onHorizontalPath) {
						if (self.isPlayerMine !== isPlayerChip) {
							continue;
						}
					}
				}
				var dx = chip.x - self.x;
				var dy = chip.y - self.y;
				var distanceSq = dx * dx + dy * dy;
				if (distanceSq < collisionRadiusSq) {
					self.explode();
					break;
				}
			}
		}
	};
	return self;
});
/**** 
* Poker Chip Enemy Class
****/ 
var PokerChip = Container.expand(function () {
	var self = Container.call(this);
	self.active = false;
	self.health = 100; // Increased base health
	self.maxHealth = 100;
	self.value = 1;
	self.speed = 0.05;
	self.pathProgress = 0;
	self.isPlayerSide = true;
	self.damageFlashTimer = 0;
	self.burnDamage = 0;
	self.burnDuration = 0;
	self.burnTickTimer = 0;
	self.burnSourceIsPlayer = null;
	self.burnTickInterval = 30; // Burn ticks every 0.5 seconds (30 ticks at 60fps)
	self.slowDuration = 0;
	self.slowAmount = 0;
	self.freezeDuration = 0;
	self.originalSpeed = 0;
	self.iceCube = null; // Will hold the ice cube graphic
	self.freezeImmunityTimer = 0;
	self.slowEffectIcon = null;
	var chipGraphicsAssets = {
		1: self.attachAsset('yellowChip', {
			anchorX: 0.5,
			anchorY: 0.5
		}),
		5: self.attachAsset('redChip', {
			anchorX: 0.5,
			anchorY: 0.5
		}),
		10: self.attachAsset('greenChip', {
			anchorX: 0.5,
			anchorY: 0.5
		}),
		25: self.attachAsset('blueChip', {
			anchorX: 0.5,
			anchorY: 0.5
		}),
		100: self.attachAsset('purpleChip', {
			anchorX: 0.5,
			anchorY: 0.5
		})
	};
	var chipGraphics = null; // This will hold the current visible chip
	for (var val in chipGraphicsAssets) {
		chipGraphicsAssets[val].visible = false;
	}
	var healthText = new Text2('', {
		size: 80,
		fill: 0xffffff,
		weight: 800,
		stroke: 0x000000,
		strokeThickness: 8
	});
	healthText.anchor.set(0.5, 0.5);
	self.addChild(healthText);
	self.applyBurn = function (damage, duration, isPlayerSource) {
		// Stack burn damage but refresh duration
		self.burnDamage += damage;
		self.burnDuration = Math.max(self.burnDuration, duration);
		self.burnTickTimer = 0;
		if (isPlayerSource !== undefined) {
			self.burnSourceIsPlayer = isPlayerSource;
		}
		createBurnEffect(self.x, self.y);
	};
	self.applyFreeze = function (duration) {
		// Return if chip is immune to freeze
		if (self.freezeImmunityTimer > 0) {
			return;
		}
		// Don't freeze if already frozen - with special logic for bosses
		if (self.freezeDuration > 0) {
			if (!self.isBoss) {
				// Non-bosses can refresh duration
				self.freezeDuration = Math.max(self.freezeDuration, duration);
			}
			// Bosses simply ignore the new freeze request if they are already frozen.
			return;
		}
		self.freezeDuration = duration;
		// Store original speed and stop movement
		if (self.slowDuration <= 0) {
			self.originalSpeed = self.speed;
		}
		self.speed = 0;
		// Create ice cube encasement
		if (!self.iceCube) {
			self.iceCube = LK.getAsset('iceCube', {
				anchorX: 0.5,
				anchorY: 0.5
			});
			self.iceCube.scale.set(1.2); // Slightly larger than chip
			self.iceCube.alpha = 0.8;
			self.addChild(self.iceCube);
		}
		self.iceCube.visible = true;
		// Ice formation animation
		self.iceCube.scale.set(0.1);
		self.iceCube.alpha = 0;
		tween(self.iceCube, {
			scaleX: 1.2,
			scaleY: 1.2,
			alpha: 0.8
		}, {
			duration: 300,
			easing: tween.backOut
		});
	};
	self.processFreeze = function () {
		// Process immunity first, which ticks down every frame.
		if (self.freezeImmunityTimer > 0) {
			self.freezeImmunityTimer--;
		}
		if (self.freezeDuration <= 0) {
			return;
		}
		self.freezeDuration--;
		// Create occasional ice sparkle effects
		if (Math.random() < 0.1) {
			createIceSparkles(self.x, self.y);
		}
		// When freeze expires, break the ice
		if (self.freezeDuration <= 0) {
			if (self.slowDuration > 0) {
				self.speed = self.originalSpeed * (1 - self.slowAmount);
			} else {
				self.speed = self.originalSpeed;
			}
			self.freezeImmunityTimer = 120; // Apply 2-second immunity (120 ticks)
			if (self.iceCube) {
				// Ice breaking animation
				tween(self.iceCube, {
					scaleX: 1.5,
					scaleY: 1.5,
					alpha: 0
				}, {
					duration: 200,
					easing: tween.quadOut,
					onFinish: function onFinish() {
						self.iceCube.visible = false;
					}
				});
				// Create ice shatter particles
				createIceShatterEffect(self.x, self.y);
			}
		}
	};
	self.processBurnDamage = function () {
		if (self.burnDuration <= 0) {
			// Ensure burn is completely cleared
			self.burnDamage = 0;
			self.burnTickTimer = 0;
			return;
		}
		self.burnTickTimer++;
		if (self.burnTickTimer >= self.burnTickInterval) {
			self.burnTickTimer = 0;
			self.burnDuration--;
			// Apply burn damage (10% of original hit damage)
			var actualBurnDamage = Math.ceil(self.burnDamage);
			if (gameMode === 'coop' && self.burnSourceIsPlayer !== null) {
				var damageAmount = Math.min(actualBurnDamage, self.health);
				if (self.burnSourceIsPlayer) {
					playerTotalDamage += damageAmount;
				} else {
					aiTotalDamage += damageAmount;
				}
			}
			self.health -= actualBurnDamage;
			self.updateHealthText();
			// Create floating burn damage text
			createFloatingText('-' + actualBurnDamage, self.x + (Math.random() - 0.5) * 40, self.y - 30, 0xff4400, 30);
			// Burn particles
			createBurnEffect(self.x, self.y);
			if (self.health <= 0) {
				self.active = false;
				self.die();
				return;
			}
			// Reduce burn damage over time (burn weakens)
			self.burnDamage *= 0.9;
			// Clear burn when duration expires - NO TINT MANAGEMENT
			if (self.burnDuration <= 0) {
				self.burnDamage = 0;
				self.burnTickTimer = 0; // Also reset tick timer
			}
		}
	};
	self.applyPoison = function (damage, duration, sourceIsPlayer) {
		// Don't stack poison with itself, but can exist alongside burn
		if (self.poisonDuration > 0) {
			return; // Already poisoned, don't stack
		}
		self.poisonDamage = damage;
		self.poisonDuration = duration;
		self.poisonTickTimer = 0;
		self.poisonTickInterval = 60; // 1 second intervals
		self.poisonSourceIsPlayer = sourceIsPlayer;
		// Visual feedback
		createFloatingText('POISONED!', self.x, self.y - 40, 0x00ff00, 30);
	};
	self.processPoisonDamage = function () {
		if (self.poisonDuration <= 0) {
			self.poisonDamage = 0;
			self.poisonTickTimer = 0;
			return;
		}
		self.poisonTickTimer++;
		if (self.poisonTickTimer >= self.poisonTickInterval) {
			self.poisonTickTimer = 0;
			self.poisonDuration--;
			// Apply poison damage
			var actualPoisonDamage = Math.ceil(self.poisonDamage);
			if (gameMode === 'coop' && self.poisonSourceIsPlayer !== null) {
				var damageAmount = Math.min(actualPoisonDamage, self.health);
				if (self.poisonSourceIsPlayer) {
					playerTotalDamage += damageAmount;
				} else {
					aiTotalDamage += damageAmount;
				}
			}
			self.health -= actualPoisonDamage;
			self.updateHealthText();
			// Create floating poison damage text
			createFloatingText('-' + actualPoisonDamage, self.x + (Math.random() - 0.5) * 40, self.y - 30, 0x00ff00, 30);
			// Poison particles
			createPoisonEffect(self.x, self.y);
			if (self.health <= 0) {
				self.active = false;
				self.die();
				return;
			}
			// Clear poison when duration expires
			if (self.poisonDuration <= 0) {
				self.poisonDamage = 0;
				self.poisonTickTimer = 0;
			}
		}
	};
	self.applySlow = function (amount, duration) {
		// A new slow can be applied if it's stronger, or to refresh duration.
		// We won't let slow override freeze.
		if (self.freezeDuration > 0) {
			return;
		}
		if (self.slowDuration <= 0) {
			// Not currently slowed, so store the original speed
			self.originalSpeed = self.speed;
			// Apply visual effects
			if (chipGraphics) {
				chipGraphics.tint = 0xaaaaaa;
			}
			if (!self.slowEffectIcon) {
				self.slowEffectIcon = LK.getAsset('slowClubsMod', {
					anchorX: 0.5,
					anchorY: 0.5
				});
				self.slowEffectIcon.scale.set(0.7);
				self.addChild(self.slowEffectIcon);
			}
			self.slowEffectIcon.visible = true;
		}
		self.slowDuration = duration;
		self.slowAmount = amount;
		// Apply slow relative to the original speed before any slows were applied.
		self.speed = self.originalSpeed * (1 - self.slowAmount);
	};
	self.processSlow = function () {
		if (self.slowDuration > 0) {
			self.slowDuration--;
			if (self.slowDuration <= 0) {
				self.slowAmount = 0;
				// Slow has expired. If not frozen, restore speed.
				if (self.freezeDuration <= 0) {
					self.speed = self.originalSpeed;
				}
				// Remove visual effects
				if (chipGraphics && self.damageFlashTimer <= 0) {
					chipGraphics.tint = 0xffffff;
				}
				if (self.slowEffectIcon) {
					self.slowEffectIcon.visible = false;
				}
			}
		}
	};
	self.activate = function (value, isPlayerSide, startPos) {
		self.active = true;
		self.visible = true;
		self.value = value;
		self.isPlayerSide = isPlayerSide;
		// Snake boss segment properties
		self.isSnakeHead = false;
		self.isSnakeSegment = false;
		self.snakeParent = null;
		self.snakeChildren = [];
		self.snakeSpawnTimer = 0;
		self.snakeSpawnInterval = 60; // 3 seconds between segments
		// In PokerChip activate method, for snake boss:
		if (self.bossType === 'snake') {
			self.isSnakeHead = true;
			self.snakeChildren = [];
			self.snakeSpawnTimer = 0;
			self.snakeSpawnInterval = 60; // 3 seconds between segments
		}
		// Mark boss chips (they have much higher values than normal chips)
		self.isBoss = value >= 100;
		// Initialize boss properties
		self.bossType = null;
		self.bossAbilityTimer = 0;
		self.bossAbilityStartTime = null;
		self.bossImmuneToSuit = null;
		self.bossImmuneTimer = 0;
		self.bossScrambleCount = 0;
		self.bossRainTimer = 0;
		self.bossLockedCard = null;
		self.bossLockGraphic = null;
		self.bossSpeedStartTime = 0;
		self.bossOriginalSpeed = 0;
		// Health calculations
		self.maxHealth = value * 50;
		var healthMultiplier = Math.pow(1.5, Math.floor((WaveSystem.waveNumber - 1) / 5));
		self.maxHealth = self.maxHealth * healthMultiplier;
		if (self.isBoss) {
			self.maxHealth *= 0.7;
			if (typeof gameMode !== 'undefined' && gameMode === 'pvp') {
				self.maxHealth *= 1.2;
			}
		}
		self.health = self.maxHealth;
		self.pathProgress = 0;
		// Reset status effects
		self.burnDamage = 0;
		self.burnDuration = 0;
		self.burnTickTimer = 0;
		self.burnSourceIsPlayer = null;
		self.poisonDamage = 0;
		self.poisonDuration = 0;
		self.poisonTickTimer = 0;
		self.poisonSourceIsPlayer = null;
		self.slowDuration = 0;
		self.slowAmount = 0;
		self.freezeDuration = 0;
		self.originalSpeed = 0;
		if (self.iceCube) {
			self.iceCube.visible = false;
		}
		if (self.slowEffectIcon) {
			self.slowEffectIcon.visible = false;
		}
		self.freezeImmunityTimer = 0;
		// Set speed
		self.speed = 0.03;
		self.damageFlashTimer = 0;
		// Recreate healthText
		if (healthText && healthText.parent) {
			healthText.parent.removeChild(healthText);
		}
		healthText = new Text2('', {
			size: 80,
			fill: 0xffffff,
			weight: 800,
			stroke: 0x000000,
			strokeThickness: 8
		});
		healthText.anchor.set(0.5, 0.5);
		self.addChild(healthText);
		// NOW handle boss-specific setup BEFORE setChipAppearance
		if (self.isBoss && typeof gameMode !== 'undefined' && (gameMode === 'pvp' || gameMode === 'coop') && typeof BossSystem !== 'undefined' && BossSystem.currentBossType) {
			self.bossType = BossSystem.currentBossType.id;
			self.bossAbilityTimer = 0;
			self.bossSpeedStartTime = LK.ticks;
			self.bossOriginalSpeed = self.speed;
			console.log("Boss activated with type:", self.bossType, "Wave:", WaveSystem.waveNumber);
			// Apply boss abilities for both mini-bosses and main bosses
			// Speed boss starts slower
			if (self.bossType === 'speed') {
				self.speed = self.speed * 0.5;
			}
			// Immune boss starts with random suit immunity
			if (self.bossType === 'immune') {
				self.bossImmuneToSuit = null; // Will be set after spawn
				self.bossImmuneTimer = 0;
				self.immunityChanges = 0;
				var suits = ['hearts', 'diamonds', 'clubs', 'spades'];
				self.bossImmuneToSuit = suits[Math.floor(Math.random() * suits.length)];
				self.bossImmuneTimer = 0;
			}
			// Lock boss locks a random card
			if (self.bossType === 'lock') {
				self.lockedCards = [];
				self.lockAttempts = 0;
				if (typeof self.lockRandomCard === 'function') {
					self.lockRandomCard();
				}
			}
		}
		// Set appearance AFTER boss properties are set
		self.setChipAppearance();
		self.x = startPos.x;
		self.y = startPos.y;
	};
	self.updateHealthText = function () {
		// Remove the old text object
		if (healthText && healthText.parent) {
			healthText.parent.removeChild(healthText);
		}
		// Create a new text object with all styling properties
		healthText = new Text2(formatNumberWithSuffix(Math.max(0, self.health)), {
			size: 80,
			fill: 0xffffff,
			weight: 800,
			stroke: 0x000000,
			strokeThickness: 8
		});
		healthText.anchor.set(0.5, 0.5);
		self.addChild(healthText);
	};
	self.setChipAppearance = function () {
		// Hide previous graphic and reset its scale to default if it exists
		if (chipGraphics) {
			chipGraphics.visible = false;
			chipGraphics.scale.set(1);
		}
		// Hide previous graphic and reset its scale to default if it exists
		if (chipGraphics) {
			chipGraphics.visible = false;
			chipGraphics.scale.set(1);
		}
		// In setChipAppearance method, modify the boss asset selection:
		if (self.isBoss && typeof gameMode !== 'undefined' && (gameMode === 'pvp' || gameMode === 'coop') && self.bossType) {
			console.log("Setting boss appearance for type:", self.bossType);
			// Find the boss type data to get the correct asset
			var bossTypeData = typeof BossSystem !== 'undefined' && BossSystem.bossTypes && BossSystem.bossTypes.find(function (type) {
				return type.id === self.bossType;
			});
			if (bossTypeData) {
				// Create the boss chip graphic if it doesn't exist in our assets collection
				if (!chipGraphicsAssets[bossTypeData.chipAsset]) {
					chipGraphicsAssets[bossTypeData.chipAsset] = self.attachAsset(bossTypeData.chipAsset, {
						anchorX: 0.5,
						anchorY: 0.5
					});
					chipGraphicsAssets[bossTypeData.chipAsset].visible = false;
				}
				chipGraphics = chipGraphicsAssets[bossTypeData.chipAsset];
				console.log("Using boss asset:", bossTypeData.chipAsset);
			} else {
				console.log("Boss type data not found, using fallback");
				chipGraphics = chipGraphicsAssets[self.value] || chipGraphicsAssets[1];
			}
		} else {
			// Regular chip logic
			chipGraphics = chipGraphicsAssets[self.value] || chipGraphicsAssets[1];
		}
		if (chipGraphics) {
			chipGraphics.visible = true;
			// Apply boss scaling
			if (self.isBoss) {
				var bossScale = 1.25;
				// Apply segment size reduction if this is a snake segment
				if (self.isSnakeSegment && self.segmentSize) {
					bossScale *= self.segmentSize;
				}
				chipGraphics.scale.set(bossScale);
			}
		}
		self.updateHealthText();
	};
	self.takeDamage = function (damage, isPlayerSource, damageSuit) {
		// ADD VALIDATION
		if (typeof damage !== 'number' || isNaN(damage) || damage < 0) {
			console.warn("Invalid damage value:", damage);
			return;
		}
		if (typeof self.health !== 'number' || isNaN(self.health)) {
			console.warn("Invalid health value:", self.health);
			self.health = 1; // Emergency fix
		}
		// Check immunity for immune boss
		if (self.bossType === 'immune' && isPlayerSource !== undefined && self.bossImmuneToSuit && damageSuit) {
			if (damageSuit === self.bossImmuneToSuit) {
				createFloatingText('IMMUNE!', self.x, self.y - 30, 0xffff00, 40);
				return; // No damage taken
			}
		}
		if (damage > 0) {
			createFloatingText('-' + Math.round(damage), self.x + (Math.random() - 0.5) * 40, self.y - 60, 0xff0000, 50);
		}
		if (gameMode === 'coop' && isPlayerSource !== undefined) {
			var damageAmount = Math.min(damage, self.health);
			// ADD VALIDATION
			if (typeof damageAmount === 'number' && !isNaN(damageAmount) && damageAmount > 0) {
				if (isPlayerSource) {
					playerTotalDamage += damageAmount;
				} else {
					aiTotalDamage += damageAmount;
				}
			}
		}
		self.health -= damage;
		self.updateHealthText();
		self.damageFlashTimer = 10; // Flash for 10 ticks instead of setTimeout
		if (self.health <= 0) {
			// IMMEDIATELY mark as inactive to prevent further hits
			self.active = false;
			// Call kill counter handler before die() removes chip
			handleChipKill(self.isPlayerSide);
			self.die();
		}
	};
	self.die = function () {
		// Sound effect removed - no longer play pokerChipDie sound
		var chipsEarned = Math.ceil(self.value * 1.5);
		// REDUCE CHIPS FOR SNAKE SEGMENTS
		if (self.isSnakeSegment) {
			chipsEarned = Math.ceil(chipsEarned * 0.2); // Give only 20% of normal chips
		}
		if (self.isPlayerSide) {
			var greedBonus = calculateGreedBonus(true, chipsEarned);
			var totalEarned = chipsEarned + greedBonus;
			gameState.playerChips += totalEarned;
			if (greedBonus > 0) {
				createFloatingText('+' + formatNumberWithSuffix(totalEarned) + ' (+' + formatNumberWithSuffix(greedBonus) + ' greed)', self.x, self.y - 30, 0xffd700, 35);
			}
		} else {
			var greedBonus = calculateGreedBonus(false, chipsEarned);
			gameState.aiChips += chipsEarned + greedBonus;
		}
		if (self.isSnakeHead) {
			console.log("Snake head dying, making segments independent...");
			if (self.snakeChildren && self.snakeChildren.length) {
				for (var i = 0; i < self.snakeChildren.length; i++) {
					var segment = self.snakeChildren[i];
					if (segment && segment.active) {
						// Keep as segment but remove following behavior
						// segment.isSnakeSegment stays true for reduced rewards
						segment.snakeFollowTarget = null;
						segment.snakeHead = null;
						segment.speed = 0.03; // Resume normal independent movement
						console.log("Segment", i, "is now independent but still a segment");
					}
				}
			}
			self.snakeChildren = []; // Clear the array since segments are now independent
		} else if (self.isSnakeSegment && self.snakeHead && self.snakeHead.snakeChildren) {
			// Remove this segment from head's children array
			var index = self.snakeHead.snakeChildren.indexOf(self);
			if (index !== -1) {
				self.snakeHead.snakeChildren.splice(index, 1);
			}
		}
		if (self.bossType === 'lock') {
			self.unlockAllCards();
		}
		PoolManager.returnChip(self);
	};
	self.update = function () {
		if (!self.active) {
			return;
		}
		// Handle damage flash (keep this for regular damage)
		if (self.damageFlashTimer > 0) {
			self.damageFlashTimer--;
			if (chipGraphics) {
				if (self.damageFlashTimer > 0) {
					chipGraphics.tint = 0xff0000;
				} else {
					// Flash is over, restore correct tint
					if (self.slowDuration > 0) {
						chipGraphics.tint = 0xaaaaaa;
					} else {
						chipGraphics.tint = 0xffffff;
					}
				}
			}
		}
		// NEW: Process burn damage
		self.processBurnDamage();
		// NEW: Process poison damage
		if (typeof self.processPoisonDamage === "function") {
			self.processPoisonDamage();
		}
		// NEW: Process freeze effect
		self.processFreeze();
		// NEW: Process slow effect
		self.processSlow();
		// Boss ability update
		if (self.isBoss) {
			self.updateBossAbilities();
		}
		if (!self.active) {
			return;
		}
		self.pathProgress += self.speed;
		var pathPos = PathSystem.getPositionAlongPath(self.pathProgress, self.isPlayerSide);
		var isDefeated = pathPos.completed;
		if (!isDefeated && gameMode === 'coop') {
			// In coop mode, enemies are also defeated if they pass the right edge of the background.
			var rightEdge = coopBackground.x + coopBackground.width / 2;
			if (pathPos.x > rightEdge) {
				isDefeated = true;
			}
		}
		if (isDefeated) {
			// Boss chips remove 2 hearts instead of 1
			var heartsToRemove = self.isBoss ? 2 : 1;
			// Unlock cards if this is a lock boss that escaped
			if (self.bossType === 'lock') {
				self.unlockAllCards();
			}
			if (gameMode === 'coop') {
				gameState.playerLives -= heartsToRemove;
				gameState.aiLives = gameState.playerLives;
			} else {
				if (self.isPlayerSide) {
					gameState.playerLives -= heartsToRemove;
				} else {
					gameState.aiLives -= heartsToRemove;
				}
			}
			LK.effects.flashScreen(0xff0000, 300);
			PoolManager.returnChip(self);
			return;
		}
		self.x = pathPos.x;
		self.y = pathPos.y;
		// --- SNAKE SEGMENT FOLLOWING LOGIC ---
		if (self.isSnakeSegment && self.snakeFollowTarget && self.snakeFollowTarget.active) {
			// Follow target much closer - only 3% behind on path
			var targetPathProgress = self.snakeFollowTarget.pathProgress - 3;
			// Tighter following with faster interpolation
			var currentDiff = self.pathProgress - targetPathProgress;
			if (Math.abs(currentDiff) > 0.2) {
				// More sensitive adjustment
				self.pathProgress += (targetPathProgress - self.pathProgress) * 0.4; // Faster following
			}
			// Update position based on path progress
			var pathPos = PathSystem.getPositionAlongPath(self.pathProgress, self.isPlayerSide);
			self.x = pathPos.x;
			self.y = pathPos.y;
			// Don't do normal speed-based movement for segments
			return; // Skip normal pathProgress += self.speed
		}
	};
	// Boss ability: Lock a random card in the play area
	self.lockRandomCard = function () {
		var playArea = self.isPlayerSide ? gameState.playerPlayArea : gameState.aiPlayArea;
		var availableCards = [];
		for (var r = 0; r < PLAY_AREA_ROWS; r++) {
			for (var c = 0; c < PLAY_AREA_COLS; c++) {
				if (playArea[r][c] && !playArea[r][c].isLocked) {
					availableCards.push(playArea[r][c]);
				}
			}
		}
		if (availableCards.length > 0) {
			var cardToLock = availableCards[Math.floor(Math.random() * availableCards.length)];
			cardToLock.isLocked = true;
			// Apply grey tint to the card (do not tint white)
			cardToLock.tint = 0x666666;
			cardToLock.alpha = 0.7;
			// Create lock graphic using boss asset
			if (!cardToLock.lockGraphic) {
				cardToLock.lockGraphic = LK.getAsset('bossChipLock', {
					anchorX: 0.5,
					anchorY: 0.5
				});
				cardToLock.lockGraphic.scale.set(0.01); // Start very small
				cardToLock.lockGraphic.alpha = 0.9;
				cardToLock.addChild(cardToLock.lockGraphic);
				// Scale in animation
				tween(cardToLock.lockGraphic, {
					scaleX: 0.8,
					scaleY: 0.8
				}, {
					duration: 400,
					easing: tween.backOut
				});
			}
			// Track locked cards on the boss
			if (!self.lockedCards) {
				self.lockedCards = [];
			}
			self.lockedCards.push(cardToLock);
			createFloatingText('CARD LOCKED!', cardToLock.x, cardToLock.y - 50, 0xff0000, 50);
		}
	};
	// Boss ability: Scramble all cards in the play area
	self.scrambleCards = function () {
		var playArea = self.isPlayerSide ? gameState.playerPlayArea : gameState.aiPlayArea;
		var cardsToScramble = [];
		for (var r = 0; r < PLAY_AREA_ROWS; r++) {
			for (var c = 0; c < PLAY_AREA_COLS; c++) {
				if (playArea[r][c]) {
					cardsToScramble.push(playArea[r][c]);
				}
			}
		}
		cardsToScramble.forEach(function (card) {
			var randomSuit = CardSystem.suits[Math.floor(Math.random() * CardSystem.suits.length)];
			var randomValue = CardSystem.values[Math.floor(Math.random() * CardSystem.values.length)];
			// Store important properties
			var currentLevel = card.level;
			var currentPosition = {
				x: card.x,
				y: card.y
			};
			var isInPlay = card.isInPlay;
			var isPlayerCard = card.isPlayerCard;
			// Update card data
			card.cardData.suit = randomSuit;
			card.cardData.value = randomValue;
			card.cardData.id = randomSuit + '_' + randomValue;
			// Clear hand bonuses
			card.handBonus = 1;
			card.redOutline.visible = false;
			card.greenOutline.visible = false;
			// Visual effect
			createFloatingText('SCRAMBLED!', card.x, card.y, 0xff00ff, 40);
			// CRITICAL FIX: Recreate all visual elements properly
			card.recreateVisuals(currentLevel);
			// Re-activate to ensure proper suit graphics
			card.activate(currentPosition.x, currentPosition.y, isInPlay, isPlayerCard);
		});
		if (cardsToScramble.length > 0) {
			// Force hand bonus recalculation with delay
			LK.setTimeout(function () {
				applyHandBonuses();
			}, 50);
		}
	};
	// Boss ability: Update boss-specific abilities each tick
	self.updateBossAbilities = function () {
		if (!self.bossType) {
			return;
		}
		self.bossAbilityTimer++;
		switch (self.bossType) {
			case 'lock':
				if (!self.bossAbilityStartTime) {
					self.bossAbilityStartTime = LK.ticks;
					self.lastLockTrigger = -1; // Track last trigger time
				}
				var timeElapsed = LK.ticks - self.bossAbilityStartTime;
				var triggerInterval = Math.floor((timeElapsed - 180) / 600);
				if (timeElapsed >= 180 && triggerInterval >= 0 && triggerInterval !== self.lastLockTrigger) {
					self.lastLockTrigger = triggerInterval;
					self.lockRandomCard();
				}
				break;
			case 'scramble':
				if (!self.bossAbilityStartTime) {
					self.bossAbilityStartTime = LK.ticks;
					self.lastScrambleTrigger = -1; // Track last trigger time
				}
				var timeElapsed = LK.ticks - self.bossAbilityStartTime;
				var triggerInterval = Math.floor((timeElapsed - 180) / 600);
				if (timeElapsed >= 180 && triggerInterval >= 0 && triggerInterval !== self.lastScrambleTrigger) {
					self.lastScrambleTrigger = triggerInterval;
					self.scrambleCards();
				}
				break;
			case 'snake':
				// Only initialize once per boss
				if (!self.hasInitializedSnake) {
					self.isSnakeHead = true;
					self.snakeChildren = [];
					self.snakeSpawnTimer = 0;
					self.maxSnakeSegments = 4;
					self.hasInitializedSnake = true;
				}
				// Only spawn if we're still active and under limit
				if (self.isSnakeHead && self.active && self.snakeChildren.length < self.maxSnakeSegments) {
					self.snakeSpawnTimer++;
					if (self.snakeSpawnTimer >= self.snakeSpawnInterval) {
						self.spawnSnakeSegment();
						self.snakeSpawnTimer = 0;
					}
				}
				break;
			case 'immune':
				if (!self.bossAbilityStartTime) {
					self.bossAbilityStartTime = LK.ticks;
					self.lastImmuneTrigger = -1; // Track last trigger time
				}
				var timeElapsed = LK.ticks - self.bossAbilityStartTime;
				// Initial immunity at 3 seconds
				if (timeElapsed === 180 && !self.hasInitialImmunity) {
					self.hasInitialImmunity = true;
					var suits = ['hearts', 'diamonds', 'clubs', 'spades'];
					self.bossImmuneToSuit = suits[Math.floor(Math.random() * suits.length)];
					self.bossImmuneTimer = 0;
					createFloatingText('IMMUNE TO ' + self.bossImmuneToSuit.toUpperCase(), self.x, self.y - 50, 0xffff00, 40);
				}
				// Change immunity every 10 seconds starting at 13 seconds total
				var triggerInterval = Math.floor((timeElapsed - 780) / 600);
				if (timeElapsed >= 780 && triggerInterval >= 0 && triggerInterval !== self.lastImmuneTrigger) {
					self.lastImmuneTrigger = triggerInterval;
					self.changeImmunity();
				}
				break;
			case 'speed':
				var timeElapsed = LK.ticks - self.bossSpeedStartTime;
				var maxTime = 900; // 15 seconds
				var speedProgress = Math.min(timeElapsed / maxTime, 1);
				// Exponential acceleration
				var exponentialProgress = speedProgress * speedProgress;
				var speedMultiplier = 0.5 + exponentialProgress * 2.5;
				self.speed = self.bossOriginalSpeed * speedMultiplier;
				break;
		}
	};
	self.spawnSnakeSegment = function () {
		// Safety checks
		if (!self.isSnakeHead || !self.active || self.snakeChildren.length >= (self.maxSnakeSegments || 4)) {
			return;
		}
		var segment = PoolManager.getChip();
		if (!segment) {
			return;
		}
		var segmentNumber = self.snakeChildren.length + 1;
		var sizeReduction = 0.9;
		var segmentSize = Math.pow(sizeReduction, segmentNumber);
		// Calculate health distribution with minimum health
		var totalSegments = segmentNumber + 1;
		var headHealthRatio = 0.4;
		var segmentHealthRatio = 0.6 / segmentNumber;
		var originalHeadHealth = self.maxHealth;
		var newHeadHealth = Math.max(50, Math.floor(originalHeadHealth * headHealthRatio));
		var segmentHealth = Math.max(25, Math.floor(originalHeadHealth * segmentHealthRatio));
		// Update head health (only on first segment spawn)
		if (segmentNumber === 1) {
			self.maxHealth = newHeadHealth;
			self.health = Math.min(self.health, newHeadHealth);
			self.updateHealthText();
		}
		var followTarget = self.snakeChildren.length > 0 ? self.snakeChildren[self.snakeChildren.length - 1] : self;
		var segmentPathProgress = Math.max(0, followTarget.pathProgress - 3);
		var segmentPos = PathSystem.getPositionAlongPath(segmentPathProgress, self.isPlayerSide);
		// Set up segment properties directly (don't use activate() as it resets everything)
		segment.active = true;
		segment.visible = true;
		segment.value = self.value;
		segment.isPlayerSide = self.isPlayerSide;
		// CRITICAL FIX: Snake segments are NOT bosses
		segment.isBoss = false; // Don't make it a boss
		segment.bossType = null; // Remove boss type
		segment.isSnakeSegment = true; // Mark as segment
		segment.isSnakeHead = false; // Not a head
		segment.snakeHead = self; // Reference to head
		segment.snakeFollowTarget = followTarget;
		segment.x = segmentPos.x;
		segment.y = segmentPos.y;
		segment.pathProgress = segmentPathProgress;
		segment.segmentSize = segmentSize;
		segment.speed = self.speed;
		segment.damageFlashTimer = 0;
		// Set health
		segment.maxHealth = segmentHealth;
		segment.health = segmentHealth;
		// Reset status effects
		segment.burnDamage = 0;
		segment.burnDuration = 0;
		segment.burnTickTimer = 0;
		segment.burnSourceIsPlayer = null;
		segment.slowDuration = 0;
		segment.slowAmount = 0;
		segment.freezeDuration = 0;
		segment.originalSpeed = 0;
		if (segment.iceCube) {
			segment.iceCube.visible = false;
		}
		if (segment.slowEffectIcon) {
			segment.slowEffectIcon.visible = false;
		}
		segment.freezeImmunityTimer = 0;
		// Set appearance
		segment.setChipAppearance();
		// Validate health
		if (segment.health <= 0) {
			console.error("Segment created with 0 health! Fixing...");
			segment.health = 25;
			segment.maxHealth = 25;
			segment.updateHealthText();
		}
		// Add to tracking arrays AFTER setting up all properties
		self.snakeChildren.push(segment);
		if (segment.isPlayerSide) {
			activePlayerChips.push(segment);
			activePlayerChipsContainer.addChild(segment);
		} else {
			activeAIChips.push(segment);
			activeAIChipsContainer.addChild(segment);
		}
		console.log("Snake segment created:", segmentNumber, "Health:", segment.health, "Active:", segment.active);
	};
	// Add this function to the PokerChip class
	self.unlockAllCards = function () {
		if (self.lockedCards && self.lockedCards.length > 0) {
			for (var i = 0; i < self.lockedCards.length; i++) {
				var card = self.lockedCards[i];
				if (card && card.isLocked) {
					card.isLocked = false;
					// Restore card appearance
					card.tint = 0xffffff;
					card.alpha = 1.0;
					// Remove lock graphic with animation
					if (card.lockGraphic) {
						(function (cardRef) {
							tween(cardRef.lockGraphic, {
								scaleX: 0.01,
								scaleY: 0.01,
								alpha: 0
							}, {
								duration: 300,
								easing: tween.backIn,
								onFinish: function onFinish() {
									if (cardRef.lockGraphic && cardRef.lockGraphic.parent) {
										cardRef.lockGraphic.parent.removeChild(cardRef.lockGraphic);
										cardRef.lockGraphic = null;
									}
								}
							});
						})(card);
					}
					createFloatingText('UNLOCKED!', card.x, card.y - 30, 0x00ff00, 40);
				}
			}
			self.lockedCards = [];
		}
	};
	// Add this function to the PokerChip class
	self.changeImmunity = function () {
		var suits = ['hearts', 'diamonds', 'clubs', 'spades'];
		var oldSuit = self.bossImmuneToSuit;
		// Pick a different suit than the current one
		var availableSuits = suits.filter(function (suit) {
			return suit !== oldSuit;
		});
		self.bossImmuneToSuit = availableSuits[Math.floor(Math.random() * availableSuits.length)];
		self.bossImmuneTimer = 0;
		createFloatingText('NOW IMMUNE TO ' + self.bossImmuneToSuit.toUpperCase(), self.x, self.y - 50, 0xffff00, 40);
	};
	return self;
});
/**** 
* Initialize Game
****/ 
var game = new LK.Game({
	backgroundColor: 0x0f3d0f
});
/**** 
* Game Code
****/ 
/**** 
* Game Constants
****/ 
/**** 
* Poker Tower Defense - Complete Refactor
****/ 
// Helper function to calculate distance from point to line segment
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 _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 _toConsumableArray(r) {
	return _arrayWithoutHoles(r) || _iterableToArray(r) || _unsupportedIterableToArray2(r) || _nonIterableSpread();
}
function _nonIterableSpread() {
	throw new TypeError("Invalid attempt to spread non-iterable instance.\nIn order to be iterable, non-array objects must have a [Symbol.iterator]() method.");
}
function _unsupportedIterableToArray2(r, a) {
	if (r) {
		if ("string" == typeof r) {
			return _arrayLikeToArray2(r, a);
		}
		var t = {}.toString.call(r).slice(8, -1);
		return "Object" === t && r.constructor && (t = r.constructor.name), "Map" === t || "Set" === t ? Array.from(r) : "Arguments" === t || /^(?:Ui|I)nt(?:8|16|32)(?:Clamped)?Array$/.test(t) ? _arrayLikeToArray2(r, a) : void 0;
	}
}
function _iterableToArray(r) {
	if ("undefined" != typeof Symbol && null != r[Symbol.iterator] || null != r["@@iterator"]) {
		return Array.from(r);
	}
}
function _arrayWithoutHoles(r) {
	if (Array.isArray(r)) {
		return _arrayLikeToArray2(r);
	}
}
function _arrayLikeToArray2(r, a) {
	(null == a || a > r.length) && (a = r.length);
	for (var e = 0, n = Array(a); e < a; e++) {
		n[e] = r[e];
	}
	return n;
}
function distancePointToLine(px, py, x1, y1, x2, y2) {
	var A = px - x1;
	var B = py - y1;
	var C = x2 - x1;
	var D = y2 - y1;
	var dot = A * C + B * D;
	var lenSq = C * C + D * D;
	if (lenSq === 0) {
		// Line segment is actually a point
		return Math.sqrt(A * A + B * B);
	}
	var param = dot / lenSq;
	var xx, yy;
	if (param < 0) {
		xx = x1;
		yy = y1;
	} else if (param > 1) {
		xx = x2;
		yy = y2;
	} else {
		xx = x1 + param * C;
		yy = y1 + param * D;
	}
	var dx = px - xx;
	var dy = py - yy;
	return Math.sqrt(dx * dx + dy * dy);
}
function _createForOfIteratorHelper(r, e) {
	var t = "undefined" != typeof Symbol && r[Symbol.iterator] || r["@@iterator"];
	if (!t) {
		if (Array.isArray(r) || (t = _unsupportedIterableToArray(r)) || e && r && "number" == typeof r.length) {
			t && (r = t);
			var _n = 0,
				F = function F() {};
			return {
				s: F,
				n: function n() {
					return _n >= r.length ? {
						done: !0
					} : {
						done: !1,
						value: r[_n++]
					};
				},
				e: function e(r) {
					throw r;
				},
				f: F
			};
		}
		throw new TypeError("Invalid attempt to iterate non-iterable instance.\nIn order to be iterable, non-array objects must have a [Symbol.iterator]() method.");
	}
	var o,
		a = !0,
		u = !1;
	return {
		s: function s() {
			t = t.call(r);
		},
		n: function n() {
			var r = t.next();
			return a = r.done, r;
		},
		e: function e(r) {
			u = !0, o = r;
		},
		f: function f() {
			try {
				a || null == t["return"] || t["return"]();
			} finally {
				if (u) {
					throw o;
				}
			}
		}
	};
}
function _unsupportedIterableToArray(r, a) {
	if (r) {
		if ("string" == typeof r) {
			return _arrayLikeToArray(r, a);
		}
		var t = {}.toString.call(r).slice(8, -1);
		return "Object" === t && r.constructor && (t = r.constructor.name), "Map" === t || "Set" === t ? Array.from(r) : "Arguments" === t || /^(?:Ui|I)nt(?:8|16|32)(?:Clamped)?Array$/.test(t) ? _arrayLikeToArray(r, a) : void 0;
	}
}
function _arrayLikeToArray(r, a) {
	(null == a || a > r.length) && (a = r.length);
	for (var e = 0, n = Array(a); e < a; e++) {
		n[e] = r[e];
	}
	return n;
}
var SCREEN_WIDTH = 2048;
var SCREEN_HEIGHT = 2732;
var PLAY_AREA_COLS = 5;
var PLAY_AREA_ROWS = 2;
var SLOT_WIDTH = 300;
var SLOT_HEIGHT = 420;
var DEAL_SLOT_WIDTH = 240;
var DEAL_SLOT_HEIGHT = 330;
// AI area positioning (top)
var AI_AREA_X = (SCREEN_WIDTH - PLAY_AREA_COLS * SLOT_WIDTH) / 2;
var AI_AREA_Y = 150;
// Player area positioning (middle, with plenty of room below)
var PLAYER_AREA_X = (SCREEN_WIDTH - PLAY_AREA_COLS * SLOT_WIDTH) / 2;
var PLAYER_AREA_Y = SCREEN_HEIGHT - 1300; // Much higher up
// Player deal area (hand slots) - below play area
var PLAYER_DEAL_AREA_Y = PLAYER_AREA_Y + PLAY_AREA_ROWS * SLOT_HEIGHT + 100;
/**** 
* Card System
****/ 
var CardSystem = {
	suits: ['hearts', 'diamonds', 'clubs', 'spades'],
	values: ['A', '2', '3', '4', '5', '6', '7', '8', '9', '10', 'J', 'Q', 'K'],
	suitColors: {
		'hearts': 0xff0000,
		'diamonds': 0xff0000,
		'clubs': 0x000000,
		'spades': 0x000000
	},
	/** 
	* Returns true if a card with the given suit and value is in play (on board or in hand).
	* isPlayerSide: true for player, false for AI.
	*/ 
	isCardInPlay: function isCardInPlay(suit, value, isPlayerSide) {
		var cardId = suit + '_' + value;
		if (isPlayerSide) {
			// Check player's board
			for (var row = 0; row < PLAY_AREA_ROWS; row++) {
				for (var col = 0; col < PLAY_AREA_COLS; col++) {
					var card = gameState.playerPlayArea[row][col];
					if (card && card.cardData && card.cardData.id === cardId) {
						return true;
					}
				}
			}
			// Check player's hand
			for (var i = 0; i < gameState.playerHand.length; i++) {
				var card = gameState.playerHand[i];
				if (card && card.cardData && card.cardData.id === cardId) {
					return true;
				}
			}
		} else {
			// Check AI's board
			for (var row = 0; row < PLAY_AREA_ROWS; row++) {
				for (var col = 0; col < PLAY_AREA_COLS; col++) {
					var card = gameState.aiPlayArea[row][col];
					if (card && card.cardData && card.cardData.id === cardId) {
						return true;
					}
				}
			}
		}
		return false;
	},
	/** 
	* Generates a card not currently in play for the given side.
	* Tries up to maxAttempts times, then falls back to a random card.
	*/ 
	generateUniqueCard: function generateUniqueCard(isPlayerSide, maxAttempts) {
		maxAttempts = maxAttempts || 100; // Prevent infinite loops
		for (var attempt = 0; attempt < maxAttempts; attempt++) {
			var randomSuit = this.suits[Math.floor(Math.random() * this.suits.length)];
			var randomValue = this.values[Math.floor(Math.random() * this.values.length)];
			if (!this.isCardInPlay(randomSuit, randomValue, isPlayerSide)) {
				return {
					suit: randomSuit,
					value: randomValue,
					id: randomSuit + '_' + randomValue
				};
			}
		}
		// Fallback: if we can't find a unique card after many attempts,
		// return a random one anyway (this should be very rare)
		var fallbackSuit = this.suits[Math.floor(Math.random() * this.suits.length)];
		var fallbackValue = this.values[Math.floor(Math.random() * this.values.length)];
		return {
			suit: fallbackSuit,
			value: fallbackValue,
			id: fallbackSuit + '_' + fallbackValue
		};
	},
	/** 
	* Deals a unique card from the deck, skipping jokers if not allowed, and not duplicating cards in play.
	* If deck is empty or all cards are in play, reshuffles or recreates the deck and retries.
	*/ 
	dealUniqueCard: function dealUniqueCard(isPlayerSide, allowJokers, maxAttempts) {
		maxAttempts = maxAttempts || 50; // Reasonable limit
		allowJokers = allowJokers !== false; // Default to true
		var deck = isPlayerSide ? gameState.playerDeck : gameState.aiDeck;
		var originalDeckSize = deck.length;
		var attempts = 0;
		while (attempts < maxAttempts && deck.length > 0) {
			var cardData = deck.pop();
			// Check if AI wants to skip jokers
			if (!allowJokers && cardData.suit === 'joker') {
				// Put joker back at bottom of deck and try again
				deck.unshift(cardData);
				attempts++;
				continue;
			}
			// Check if this card is already in play on this side
			if (!this.isCardInPlay(cardData.suit, cardData.value, isPlayerSide)) {
				return cardData; // Found a unique card
			}
			// Card is already in play, put it back at bottom of deck
			deck.unshift(cardData);
			attempts++;
		}
		// If we couldn't find a unique card, either:
		// 1. Deck is empty - create new deck
		// 2. All remaining cards are duplicates - reshuffle deck
		if (deck.length === 0) {
			if (isPlayerSide) {
				gameState.playerDeck = this.createDeck();
			} else {
				gameState.aiDeck = this.createDeck();
			}
			return this.dealUniqueCard(isPlayerSide, allowJokers, 10); // Retry with new deck
		} else {
			// Reshuffle the deck and try once more
			if (isPlayerSide) {
				gameState.playerDeck = this.shuffleDeck(gameState.playerDeck);
			} else {
				gameState.aiDeck = this.shuffleDeck(gameState.aiDeck);
			}
			// Last resort: return any card (this should be very rare)
			var fallbackCard = deck.pop();
			if (!allowJokers && fallbackCard.suit === 'joker' && deck.length > 0) {
				deck.unshift(fallbackCard);
				return deck.pop();
			}
			return fallbackCard;
		}
	},
	createDeck: function createDeck() {
		var deck = [];
		var _iterator = _createForOfIteratorHelper(this.suits),
			_step;
		try {
			for (_iterator.s(); !(_step = _iterator.n()).done;) {
				var suit = _step.value;
				var _iterator2 = _createForOfIteratorHelper(this.values),
					_step2;
				try {
					for (_iterator2.s(); !(_step2 = _iterator2.n()).done;) {
						var value = _step2.value;
						deck.push({
							suit: suit,
							value: value,
							id: suit + '_' + value
						});
					}
				} catch (err) {
					_iterator2.e(err);
				} finally {
					_iterator2.f();
				}
			}
			// Add jokers
		} catch (err) {
			_iterator.e(err);
		} finally {
			_iterator.f();
		}
		deck.push({
			suit: 'joker',
			value: 'red',
			id: 'joker_red'
		});
		deck.push({
			suit: 'joker',
			value: 'black',
			id: 'joker_black'
		});
		return this.shuffleDeck(deck);
	},
	shuffleDeck: function shuffleDeck(deck) {
		for (var i = deck.length - 1; i > 0; i--) {
			var j = Math.floor(Math.random() * (i + 1));
			var temp = deck[i];
			deck[i] = deck[j];
			deck[j] = temp;
		}
		return deck;
	},
	getCardValue: function getCardValue(card) {
		if (card.cardData.suit === 'joker') {
			return 14;
		} // Jokers are highest
		if (card.cardData.value === 'A') {
			return 14;
		} // Aces high
		if (card.cardData.value === 'K') {
			return 13;
		}
		if (card.cardData.value === 'Q') {
			return 12;
		}
		if (card.cardData.value === 'J') {
			return 11;
		}
		return parseInt(card.cardData.value);
	},
	evaluatePokerHand: function evaluatePokerHand(cards) {
		var _this = this;
		if (!cards || cards.length === 0) {
			return {
				type: 'none',
				strength: 0,
				multiplier: 1,
				contributingCards: []
			};
		}
		// Sort cards by value for easier analysis
		var sortedCards = cards.slice().sort(function (a, b) {
			return _this.getCardValue(b) - _this.getCardValue(a);
		});
		var values = sortedCards.map(function (card) {
			return _this.getCardValue(card);
		});
		var suits = sortedCards.map(function (card) {
			return card.cardData.suit;
		});
		// Count values and suits
		var valueCounts = {};
		var suitCounts = {};
		values.forEach(function (value) {
			return valueCounts[value] = (valueCounts[value] || 0) + 1;
		});
		suits.forEach(function (suit) {
			return suitCounts[suit] = (suitCounts[suit] || 0) + 1;
		});
		var counts = Object.values(valueCounts).sort(function (a, b) {
			return b - a;
		});
		// Only check for 5-card hands if we have 5 cards
		var isFlush = false;
		var isStraight = false;
		if (cards.length === 5) {
			isFlush = Object.keys(suitCounts).length === 1;
			isStraight = this.checkStraight(values);
		}
		// Royal Flush
		if (isFlush && isStraight && values[0] === 14 && values[4] === 10) {
			return {
				type: 'royal_flush',
				strength: 10,
				multiplier: 25,
				contributingCards: sortedCards
			};
		}
		// Straight Flush
		if (isFlush && isStraight) {
			return {
				type: 'straight_flush',
				strength: 9,
				multiplier: 12,
				contributingCards: sortedCards
			};
		}
		// Four of a Kind
		if (counts[0] >= 4) {
			var quadValue;
			for (var v in valueCounts) {
				if (valueCounts[v] >= 4) {
					quadValue = parseInt(v);
					break;
				}
			}
			return {
				type: 'four_of_a_kind',
				strength: 8,
				multiplier: 8,
				contributingCards: sortedCards.filter(function (c) {
					return _this.getCardValue(c) === quadValue;
				})
			};
		}
		// Full House
		if (counts[0] === 3 && counts[1] === 2) {
			return {
				type: 'full_house',
				strength: 7,
				multiplier: 5,
				contributingCards: sortedCards
			};
		}
		// Flush
		if (isFlush) {
			return {
				type: 'flush',
				strength: 6,
				multiplier: 3.5,
				contributingCards: sortedCards
			};
		}
		// Straight
		if (isStraight) {
			return {
				type: 'straight',
				strength: 5,
				multiplier: 2.5,
				contributingCards: sortedCards
			};
		}
		// Three of a Kind
		if (counts[0] === 3) {
			var tripValue;
			for (var v in valueCounts) {
				if (valueCounts[v] === 3) {
					tripValue = parseInt(v);
					break;
				}
			}
			return {
				type: 'three_of_a_kind',
				strength: 4,
				multiplier: 2,
				contributingCards: sortedCards.filter(function (c) {
					return _this.getCardValue(c) === tripValue;
				})
			};
		}
		// Two Pair
		if (counts[0] === 2 && counts[1] === 2) {
			var pairValues = [];
			for (var v in valueCounts) {
				if (valueCounts[v] === 2) {
					pairValues.push(parseInt(v));
				}
			}
			return {
				type: 'two_pair',
				strength: 3,
				multiplier: 1.5,
				contributingCards: sortedCards.filter(function (c) {
					return pairValues.indexOf(_this.getCardValue(c)) !== -1;
				})
			};
		}
		// One Pair
		if (counts[0] === 2) {
			var pairValue;
			for (var v in valueCounts) {
				if (valueCounts[v] === 2) {
					pairValue = parseInt(v);
					break;
				}
			}
			return {
				type: 'one_pair',
				strength: 2,
				multiplier: 1.2,
				contributingCards: sortedCards.filter(function (c) {
					return _this.getCardValue(c) === pairValue;
				})
			};
		}
		// High Card
		return {
			type: 'high_card',
			strength: 1,
			multiplier: 1,
			contributingCards: [sortedCards[0]]
		};
	},
	checkStraight: function checkStraight(values) {
		if (values.length !== 5) {
			return false;
		}
		// Check for ace-low straight (A, 2, 3, 4, 5)
		if (values[0] === 14 && values[1] === 5 && values[2] === 4 && values[3] === 3 && values[4] === 2) {
			return true;
		}
		// Check normal straight
		for (var i = 0; i < 4; i++) {
			if (values[i] - values[i + 1] !== 1) {
				return false;
			}
		}
		return true;
	}
};
/**** 
* Object Pool Manager
****/ 
var PoolManager = {
	chipPool: [],
	bulletPool: [],
	cardPool: [],
	playerMinePool: [],
	aiMinePool: [],
	CHIP_POOL_SIZE: 50,
	BULLET_POOL_SIZE: 100,
	CARD_POOL_SIZE: 60,
	MINE_POOL_SIZE: 30,
	// 30 per side
	init: function init() {
		// Initialize pools
		for (var i = 0; i < this.CHIP_POOL_SIZE; i++) {
			var chip = new PokerChip();
			chip.active = false;
			chip.visible = false;
			this.chipPool.push(chip);
		}
		for (var i = 0; i < this.BULLET_POOL_SIZE; i++) {
			var bullet = new Bullet();
			bullet.active = false;
			bullet.visible = false;
			this.bulletPool.push(bullet);
		}
		for (var i = 0; i < this.MINE_POOL_SIZE; i++) {
			var playerMine = new Mine();
			playerMine.active = false;
			playerMine.visible = false;
			this.playerMinePool.push(playerMine);
			var aiMine = new Mine();
			aiMine.active = false;
			aiMine.visible = false;
			this.aiMinePool.push(aiMine);
		}
	},
	getChip: function getChip() {
		for (var i = 0; i < this.chipPool.length; i++) {
			if (!this.chipPool[i].active) {
				return this.chipPool[i];
			}
		}
		return null;
	},
	getBullet: function getBullet() {
		for (var i = 0; i < this.bulletPool.length; i++) {
			if (!this.bulletPool[i].active) {
				return this.bulletPool[i];
			}
		}
		return null;
	},
	getMine: function getMine(isPlayerMine) {
		var pool = isPlayerMine ? this.playerMinePool : this.aiMinePool;
		for (var i = 0; i < pool.length; i++) {
			if (!pool[i].active) {
				return pool[i];
			}
		}
		return null;
	},
	returnChip: function returnChip(chip) {
		// Force-set inactive state
		chip.active = false;
		chip.visible = false;
		chip.health = 0; // Ensure health is 0
		// Reset tint on all visual components of the chip.
		// This is to ensure that chip graphics don't retain the red damage flash tint
		// when being reused from the pool.
		if (chip.children) {
			for (var i = 0; i < chip.children.length; i++) {
				var child = chip.children[i];
				if (child.tint !== undefined) {
					child.tint = 0xffffff;
				}
			}
		}
		// NEW: Clear burn status completely
		chip.burnDamage = 0;
		chip.burnDuration = 0;
		chip.burnTickTimer = 0;
		// Clear poison status completely
		chip.poisonDamage = 0;
		chip.poisonDuration = 0;
		chip.poisonTickTimer = 0;
		chip.poisonSourceIsPlayer = null;
		// Clear ownership flag
		var wasPlayerSide = chip.isPlayerSide;
		chip.isPlayerSide = null;
		// Remove from active arrays (check both arrays to be safe)
		var playerIndex = activePlayerChips.indexOf(chip);
		if (playerIndex !== -1) {
			activePlayerChips.splice(playerIndex, 1);
		}
		var aiIndex = activeAIChips.indexOf(chip);
		if (aiIndex !== -1) {
			activeAIChips.splice(aiIndex, 1);
		}
		// Remove from containers
		if (chip.parent) {
			chip.parent.removeChild(chip);
		}
		// Reset ALL boss and snake properties
		chip.isBoss = false;
		chip.bossType = null;
		chip.isSnakeHead = false;
		chip.isSnakeSegment = false;
		chip.snakeHead = null;
		chip.snakeChildren = [];
		chip.hasInitializedSnake = false;
		// Double-check removal from both containers
		if (activePlayerChipsContainer.children.indexOf(chip) !== -1) {
			activePlayerChipsContainer.removeChild(chip);
		}
		if (activeAIChipsContainer.children.indexOf(chip) !== -1) {
			activeAIChipsContainer.removeChild(chip);
		}
	},
	returnBullet: function returnBullet(bullet) {
		var explosionColor = 0x333333; // Dark Grey for clubs/spades
		if (bullet.suit === 'hearts' || bullet.suit === 'diamonds') {
			explosionColor = 0xff0000; // Red for hearts/diamonds
		}
		createExplosion(bullet.x, bullet.y, explosionColor);
		bullet.active = false;
		bullet.visible = false;
		bullet.target = null; // Add this line to clear the target reference
		var index = activeBullets.indexOf(bullet);
		if (index !== -1) {
			activeBullets.splice(index, 1);
		}
		gameLayer.removeChild(bullet);
	},
	returnMine: function returnMine(mine) {
		mine.active = false;
		mine.visible = false;
		var index = activeMines.indexOf(mine);
		if (index !== -1) {
			activeMines.splice(index, 1);
		}
		if (mine.parent) {
			mine.parent.removeChild(mine);
		}
	}
};
/**** 
* Path System
****/ 
var PathSystem = {
	playerPath: [],
	aiPath: [],
	init: function init() {
		// Create player path - rectangular loop around the play area
		var padding = 130; // Distance from play area - increased by 50 pixels
		var verticalPadding = padding - 25 - 30; // Reduced by 25 + 30 to decrease side length by 110px total
		var leftX = PLAYER_AREA_X - padding + 10;
		var rightX = PLAYER_AREA_X + PLAY_AREA_COLS * SLOT_WIDTH + padding - 20 - 10;
		var topY = PLAYER_AREA_Y - verticalPadding;
		var bottomY = PLAYER_AREA_Y + PLAY_AREA_ROWS * SLOT_HEIGHT + verticalPadding;
		this.playerPath = [
		// Start at bottom left
		{
			x: leftX,
			y: bottomY
		},
		// Go up the left side
		{
			x: leftX,
			y: topY
		},
		// Go across the top
		{
			x: rightX,
			y: topY
		},
		// Go down the right side
		{
			x: rightX,
			y: bottomY
		}];
		// Create AI path - UPSIDE DOWN mirror of player path
		var aiLeftX = AI_AREA_X - padding;
		var aiRightX = AI_AREA_X + PLAY_AREA_COLS * SLOT_WIDTH + padding;
		var aiVerticalPadding = verticalPadding - 40 + 15; // Additional 40px reduction on each side for AI (80px total), extended by 15px
		var aiTopY = AI_AREA_Y - aiVerticalPadding;
		var aiBottomY = AI_AREA_Y + PLAY_AREA_ROWS * SLOT_HEIGHT + aiVerticalPadding;
		this.aiPath = [
		// Start at TOP left (opposite of player)
		{
			x: aiLeftX,
			y: aiTopY
		},
		// Go DOWN the left side (opposite of player)
		{
			x: aiLeftX,
			y: aiBottomY
		},
		// Go across the BOTTOM (opposite of player)
		{
			x: aiRightX,
			y: aiBottomY
		},
		// Go UP the right side (opposite of player)
		{
			x: aiRightX,
			y: aiTopY
		}];
		if (gameMode === 'coop') {
			var centerX = SCREEN_WIDTH / 2;
			var centerY = SCREEN_HEIGHT / 2;
			var turningPointY = centerY - 200; // 200 pixels up from center
			var goalX = SCREEN_WIDTH + 200;
			this.playerPath = [{
				x: leftX,
				y: bottomY
			}, {
				x: leftX,
				y: turningPointY
			}, {
				x: goalX,
				y: turningPointY
			}];
			this.aiPath = [{
				x: leftX,
				y: aiTopY
			}, {
				x: leftX,
				y: turningPointY
			}, {
				x: goalX,
				y: turningPointY
			}];
		}
	},
	// Alternative offset method that spreads chips along the path direction:
	getPathStart: function getPathStart(isPlayerSide) {
		var baseStart = isPlayerSide ? this.playerPath[0] : this.aiPath[0];
		var pathDirection = isPlayerSide ? this.playerPath[1] : this.aiPath[1];
		// Calculate direction vector from start to next point
		var dx = pathDirection.x - baseStart.x;
		var dy = pathDirection.y - baseStart.y;
		var length = Math.sqrt(dx * dx + dy * dy);
		// Normalize direction vector
		var normalizedX = dx / length;
		var normalizedY = dy / length;
		// Random offset along the path (backward from start point)
		var pathOffset = Math.random() * 80; // 0-80 pixels back along path
		var sideOffset = (Math.random() - 0.5) * 40; // -20 to +20 pixels to the side
		return {
			x: baseStart.x - normalizedX * pathOffset + normalizedY * sideOffset,
			y: baseStart.y - normalizedY * pathOffset - normalizedX * sideOffset
		};
	},
	getPositionAlongPath: function getPositionAlongPath(progress, isPlayerSide) {
		var path = isPlayerSide ? this.playerPath : this.aiPath;
		var pathLength = this.calculatePathLength(path);
		var targetDistance = progress / 100 * pathLength;
		if (targetDistance >= pathLength) {
			return {
				x: path[path.length - 1].x,
				y: path[path.length - 1].y,
				completed: true
			};
		}
		var currentDistance = 0;
		for (var i = 0; i < path.length - 1; i++) {
			var segmentLength = this.getDistance(path[i], path[i + 1]);
			if (currentDistance + segmentLength >= targetDistance) {
				var segmentProgress = (targetDistance - currentDistance) / segmentLength;
				return {
					x: path[i].x + (path[i + 1].x - path[i].x) * segmentProgress,
					y: path[i].y + (path[i + 1].y - path[i].y) * segmentProgress,
					completed: false
				};
			}
			currentDistance += segmentLength;
		}
		return {
			x: path[path.length - 1].x,
			y: path[path.length - 1].y,
			completed: true
		};
	},
	calculatePathLength: function calculatePathLength(path) {
		var total = 0;
		for (var i = 0; i < path.length - 1; i++) {
			total += this.getDistance(path[i], path[i + 1]);
		}
		return total;
	},
	getDistance: function getDistance(p1, p2) {
		var dx = p2.x - p1.x;
		var dy = p2.y - p1.y;
		return Math.sqrt(dx * dx + dy * dy);
	}
};
/**** 
* Chip Spawner
****/ 
var ChipSpawner = {
	spawnChip: function spawnChip(value, isPlayerSide) {
		var chip = PoolManager.getChip();
		if (!chip) {
			return;
		}
		var activeChips = isPlayerSide ? activePlayerChips : activeAIChips;
		var minDistance = 85; // Half the chip diameter (170/2) to allow controlled overlap
		var minDistanceSq = minDistance * minDistance;
		var newPos;
		// If no other chips exist, we can place it anywhere.
		if (activeChips.length === 0) {
			newPos = PathSystem.getPathStart(isPlayerSide);
		} else {
			var maxAttempts = 25; // Try to find a free spot with random placement first. It's fast.
			var foundPosition = false;
			for (var attempt = 0; attempt < maxAttempts; attempt++) {
				var candidatePos = PathSystem.getPathStart(isPlayerSide);
				var isValid = true;
				for (var i = 0; i < activeChips.length; i++) {
					var otherChip = activeChips[i];
					var dx = candidatePos.x - otherChip.x;
					var dy = candidatePos.y - otherChip.y;
					var distanceSq = dx * dx + dy * dy;
					if (distanceSq < minDistanceSq) {
						isValid = false;
						break;
					}
				}
				if (isValid) {
					newPos = candidatePos;
					foundPosition = true;
					break;
				}
			}
			// If random placements failed, use a more deterministic spiral search.
			if (!foundPosition) {
				var baseStart = PathSystem.getPathStart(isPlayerSide);
				var searchRadius = minDistance; // Start searching just outside the minimum distance.
				var angleStep = Math.PI / 6; // Check 12 directions.
				var spiralAttempts = 30;
				for (var i = 0; i < spiralAttempts; i++) {
					for (var angle = 0; angle < Math.PI * 2; angle += angleStep) {
						var testX = baseStart.x + Math.cos(angle) * searchRadius;
						var testY = baseStart.y + Math.sin(angle) * searchRadius;
						var isCandidateValid = true;
						for (var j = 0; j < activeChips.length; j++) {
							var otherChip = activeChips[j];
							var dx = testX - otherChip.x;
							var dy = testY - otherChip.y;
							var distanceSq = dx * dx + dy * dy;
							if (distanceSq < minDistanceSq) {
								isCandidateValid = false;
								break;
							}
						}
						if (isCandidateValid) {
							newPos = {
								x: testX,
								y: testY
							};
							foundPosition = true;
							break;
						}
					}
					if (foundPosition) {
						break;
					}
					searchRadius += 20; // Spiral outwards.
				}
			}
			// Ultimate fallback if no position is found (should be very rare).
			if (!foundPosition) {
				newPos = PathSystem.getPathStart(isPlayerSide);
			}
		}
		chip.activate(value, isPlayerSide, newPos);
		// IMPORTANT: Add chip to active array BEFORE the container
		// This ensures that subsequent chips spawned in the same batch
		// will detect this chip when checking for overlaps
		if (isPlayerSide) {
			activePlayerChips.push(chip);
			activePlayerChipsContainer.addChildAt(chip, 0);
		} else {
			activeAIChips.push(chip);
			activeAIChipsContainer.addChildAt(chip, 0);
		}
	},
	spawnChipAtPosition: function spawnChipAtPosition(value, isPlayerSide, position) {
		var chip = PoolManager.getChip();
		if (!chip) {
			return;
		}
		chip.activate(value, isPlayerSide, position);
		// Add chip to active array and container
		if (isPlayerSide) {
			activePlayerChips.push(chip);
			activePlayerChipsContainer.addChildAt(chip, 0);
		} else {
			activeAIChips.push(chip);
			activeAIChipsContainer.addChildAt(chip, 0);
		}
	}
};
/**** 
* Mod System
****/ 
var ModSystem = {
	equippedMods: {
		hearts: null,
		diamonds: null,
		clubs: null,
		spades: null
	},
	aiEquippedMods: {
		hearts: null,
		diamonds: null,
		clubs: null,
		spades: null
	},
	modData: {
		burnHeartMod: {
			suit: 'hearts',
			name: 'Flame',
			description: 'Hearts bullets apply burning damage over time. Burn damage is 10% of hit damage per tick for 4 seconds. Burn effects stack.'
		},
		unityHeartsMod: {
			suit: 'hearts',
			name: 'Unity',
			description: 'Increases bullet damage by 25% for each adjacent Hearts card.'
		},
		wildcardHeartMod: {
			suit: 'hearts',
			name: 'Wildcard',
			description: 'Hearts cards can merge with any suit or value of the same level, but deal 40% less damage.'
		},
		chipsDiamondMod: {
			suit: 'diamonds',
			name: 'Greed',
			description: 'Earn bonus chips when enemies are defeated, based on diamonds on board. Bonus scales with card level.'
		},
		gamblerDiamondsMod: {
			suit: 'diamonds',
			name: 'Gambler',
			description: 'Diamonds have a chance to deal double damage or none at all. The chance for double damage increases with card level.'
		},
		boostDiamondsMod: {
			suit: 'diamonds',
			name: 'Boost',
			description: 'Diamonds boost the attack power of adjacent cards. The boost increases with the card\'s level.'
		},
		// Add to ModSystem.modData:
		gambitDiamondMod: {
			suit: 'diamonds',
			name: 'Gambit',
			description: 'Odd cards (A,3,5,7,9,J,K) get +30% attack speed. Even cards (2,4,6,8,10,Q) get +40% attack power.'
		},
		freezeSpadeMod: {
			suit: 'spades',
			name: 'Freeze',
			description: 'Spades have a chance to freeze enemies in place when dealing damage. Duration scales with card level.'
		},
		sabotageSpadesMod: {
			suit: 'spades',
			name: 'Sabotage',
			description: 'When merged, reduces a random enemy card level by 1 (PvP) or boosts ally by 1 (Co-op).'
		},
		spreadClubMod: {
			suit: 'clubs',
			name: 'Spreadshot',
			description: 'Clubs deal reduced damage but hit multiple enemies. Extra targets scale with card level.'
		},
		slowClubsMod: {
			suit: 'clubs',
			name: 'Slow',
			description: 'Clubs bullets slow enemies on hit. Slow amount and duration scale with card level.'
		},
		ricochetClubsMod: {
			suit: 'clubs',
			name: 'Ricochet',
			description: 'Clubs bullets ricochet amongst enemies, with limited bounces, dealing less damage with each one.'
		},
		toxinClubMod: {
			suit: 'clubs',
			name: 'Toxin',
			description: 'Clubs bullets apply poison: 5% of hit damage per tick for 10 ticks. Does not stack with itself.'
		},
		mineSpadesMod: {
			suit: 'spades',
			name: 'Mine',
			description: 'Spades cards place mines on the enemy path that explode on contact, dealing area damage.'
		},
		deathSpadesMod: {
			suit: 'spades',
			name: 'Execute',
			description: 'When equipped spades bullets have a chance to execute low health targets immediately.'
		},
		investmentHeartsMod: {
			suit: 'hearts',
			name: 'Investment',
			description: 'Hearts cards generate income while on board. Income increases the longer the card is on board and resets on level up.'
		}
	},
	currentlyDisplayedMod: null,
	modDisplayContainer: null,
	topSuitGraphics: [],
	ownedMods: {},
	// Store references to top suit graphics
	init: function init() {
		if (storage.equippedMods) {
			this.equippedMods = storage.equippedMods;
		}
		if (storage.ownedMods) {
			this.ownedMods = storage.ownedMods;
		}
	},
	saveToStorage: function saveToStorage() {
		storage.equippedMods = this.equippedMods;
		storage.ownedMods = this.ownedMods;
	},
	isModOwned: function isModOwned(modAssetId) {
		return !!this.ownedMods[modAssetId];
	},
	unlockMod: function unlockMod(modAssetId) {
		this.ownedMods[modAssetId] = true;
		this.saveToStorage();
	},
	getUnownedMods: function getUnownedMods() {
		var unowned = [];
		for (var modId in this.modData) {
			if (!this.isModOwned(modId)) {
				unowned.push(modId);
			}
		}
		return unowned;
	},
	equipMod: function equipMod(modAssetId) {
		var modData = this.modData[modAssetId];
		if (!modData) {
			return;
		}
		this.equippedMods[modData.suit] = modAssetId;
		this.saveToStorage();
		this.updateTopSuitDisplay();
		this.hideModDisplay();
	},
	updateTopSuitDisplay: function updateTopSuitDisplay() {
		var suitAssets = ['heartSuit', 'diamondSuit', 'clubSuit', 'spadeSuit'];
		var suits = ['hearts', 'diamonds', 'clubs', 'spades'];
		for (var i = 0; i < this.topSuitGraphics.length; i++) {
			var container = this.topSuitGraphics[i];
			if (container) {
				// Make it an Ace card if it's not already
				var hasAceText = false;
				for (var k = 0; k < container.children.length; k++) {
					if (container.children[k].isAceText) {
						hasAceText = true;
						break;
					}
				}
				if (!hasAceText) {
					var suitForAce = suits[i];
					var suitColor = CardSystem.suitColors[suitForAce] || 0x000000;
					var valueText = new Text2('A', {
						size: 56 * 1.5,
						fill: suitColor,
						weight: 800,
						stroke: 0x000000,
						strokeThickness: 0
					});
					valueText.isAceText = true;
					valueText.anchor.set(0, 0);
					// The card background is scaled 1.5x, these coords are scaled to match.
					valueText.x = -95 * 1.5;
					valueText.y = -135 * 1.5;
					container.addChild(valueText);
				}
				// Remove the previous mod/suit icon if it exists
				for (var j = container.children.length - 1; j >= 0; j--) {
					if (container.children[j].isSuitIcon) {
						container.removeChildAt(j);
						break;
					}
				}
				// Add the appropriate icon (either mod or default suit)
				var suit = suits[i];
				var equippedMod = this.equippedMods[suit];
				var assetId = equippedMod || suitAssets[i];
				var suitIcon = LK.getAsset(assetId, {
					anchorX: 0.5,
					anchorY: 0.5
				});
				suitIcon.isSuitIcon = true;
				suitIcon.scale.set(1.2);
				// Center it in the background card
				suitIcon.x = 0;
				suitIcon.y = 0;
				container.addChild(suitIcon);
			}
		}
	},
	showModDisplay: function showModDisplay(modAssetId, sourceX, sourceY) {
		if (this.currentlyDisplayedMod) {
			return;
		}
		var modData = this.modData[modAssetId];
		if (!modData) {
			return;
		}
		this.currentlyDisplayedMod = modAssetId;
		this.modDisplayContainer = new Container();
		this.modDisplayContainer.interactive = true;
		uiLayer.addChild(this.modDisplayContainer);
		// Add a semi-transparent background to catch clicks outside the popup
		var bgBlocker = new Container();
		bgBlocker.interactive = true;
		bgBlocker.hitArea = new Rectangle(0, 0, SCREEN_WIDTH, SCREEN_HEIGHT);
		this.modDisplayContainer.addChild(bgBlocker);
		var enlargedMod = LK.getAsset(modAssetId, {
			anchorX: 0.5,
			anchorY: 0.5
		});
		enlargedMod.x = SCREEN_WIDTH / 2;
		enlargedMod.y = SCREEN_HEIGHT / 2 - 450;
		enlargedMod.scale.set(1);
		this.modDisplayContainer.addChild(enlargedMod);
		var overlayWidth = 600;
		var overlayHeight = 400;
		var descriptionOverlay = new Container();
		var overlayBg = LK.getAsset('card', {
			anchorX: 0.5,
			anchorY: 0.5
		});
		overlayBg.scale.set(overlayWidth / 150, overlayHeight / 240);
		overlayBg.tint = 0x000000;
		overlayBg.alpha = 0.8;
		descriptionOverlay.addChild(overlayBg);
		var descText = new Text2(modData.description, {
			size: 50,
			fill: 0xffffff,
			weight: 600,
			stroke: 0x000000,
			strokeThickness: 2,
			align: 'center',
			wordWrap: true,
			wordWrapWidth: overlayWidth - 40
		});
		descText.anchor.set(0.5, 0);
		descText.y = -overlayHeight / 2 + 40;
		descriptionOverlay.addChild(descText);
		var equipButton = LK.getAsset('card', {
			anchorX: 0.5,
			anchorY: 0.5,
			interactive: true
		});
		equipButton.scale.set(1.5, 0.5);
		equipButton.tint = 0x000000;
		equipButton.alpha = 0.8;
		equipButton.y = overlayHeight / 2 + 150;
		descriptionOverlay.addChild(equipButton);
		var equipText = new Text2('Equip', {
			size: 50,
			fill: 0xffffff,
			weight: 800,
			stroke: 0x000000,
			strokeThickness: 3
		});
		equipText.anchor.set(0.5, 0.5);
		equipText.y = equipButton.y;
		descriptionOverlay.addChild(equipText);
		descriptionOverlay.x = SCREEN_WIDTH / 2;
		descriptionOverlay.y = SCREEN_HEIGHT / 2 + 250;
		descriptionOverlay.alpha = 0;
		this.modDisplayContainer.addChild(descriptionOverlay);
		var self = this;
		var isOwned = this.isModOwned(modAssetId);
		if (isOwned) {
			equipText.setText('Equip');
			equipButton.down = function () {
				self.equipMod(modAssetId);
			};
		} else {
			equipText.setText('Not Owned');
			equipButton.interactive = false;
			equipButton.tint = 0x333333;
			enlargedMod.tint = 0x808080;
		}
		tween(enlargedMod, {
			scaleX: 4,
			scaleY: 4
		}, {
			duration: 300,
			easing: tween.backOut
		});
		tween(descriptionOverlay, {
			alpha: 1
		}, {
			duration: 200,
			delay: 150
		});
		bgBlocker.down = function () {
			self.hideModDisplay();
		};
	},
	hideModDisplay: function hideModDisplay() {
		if (!this.modDisplayContainer) {
			return;
		}
		var self = this;
		tween(this.modDisplayContainer, {
			alpha: 0
		}, {
			duration: 200,
			onFinish: function onFinish() {
				if (self.modDisplayContainer && self.modDisplayContainer.parent) {
					self.modDisplayContainer.parent.removeChild(self.modDisplayContainer);
				}
				self.modDisplayContainer = null;
				self.currentlyDisplayedMod = null;
			}
		});
	},
	getEquippedModAsset: function getEquippedModAsset(suit, isPlayerCard) {
		if (isPlayerCard === undefined) {
			isPlayerCard = true;
		}
		var mods = isPlayerCard ? this.equippedMods : this.aiEquippedMods;
		return mods[suit] || null;
	}
};
/**** 
* Wave Spawning System
****/ 
var WaveSystem = {
	playerSpawnTimer: 0,
	aiSpawnTimer: 0,
	waveNumber: 1,
	waveTimer: 0,
	waveDuration: 1800,
	// 30 seconds per wave (30 * 60 ticks)
	spawnInterval: 45,
	// Much faster: spawn every 0.75 seconds instead of 2 seconds
	bossSpawned: false,
	// Track if boss has been spawned this wave
	getChipValue: function getChipValue(waveNumber) {
		// Wave 1: Only 1-chips (easier)
		if (waveNumber === 1) {
			return 1;
		}
		// Wave 2-3: More 5s introduced earlier for increased difficulty
		else if (waveNumber <= 3) {
			return Math.random() < 0.2 ? 5 : 1; // 20% chance of 5-chip (increased from 10%)
		}
		// Wave 4-6: Even more 5s mixed in
		else if (waveNumber <= 6) {
			return Math.random() < 0.35 ? 5 : 1; // 35% chance of 5-chip (increased from 25%)
		}
		// Wave 7-9: More 5s than 1s for increased difficulty
		else if (waveNumber <= 9) {
			return Math.random() < 0.65 ? 5 : 1; // 65% chance of 5-chip (increased from 50%)
		}
		// Wave 11-15: Introduce 10-chips earlier and more frequently
		else if (waveNumber <= 15) {
			var rand = Math.random();
			if (rand < 0.15) {
				return 10;
			} else if (rand < 0.7) {
				return 5;
			} else {
				return 1;
			}
		}
		// Wave 16-19: More variety with higher values
		else if (waveNumber <= 19) {
			var rand = Math.random();
			if (rand < 0.3) {
				return 10;
			} else if (rand < 0.8) {
				return 5;
			} else {
				return 1;
			}
		}
		// Wave 21+: Keep scaling gradually with higher difficulty
		else if (!this.isBossWave(waveNumber)) {
			var rand = Math.random();
			if (rand < 0.08) {
				return 25;
			} else if (rand < 0.4) {
				return 10;
			} else if (rand < 0.85) {
				return 5;
			} else {
				return 1;
			}
		}
	},
	getBossChipValue: function getBossChipValue(waveNumber) {
		// Mini-boss waves (waves 5, 15, 25, etc.)
		if (waveNumber % 10 === 5) {
			var miniBossLevel = Math.floor(waveNumber / 10);
			var baseMiniBossValue = 100; // Purple chip value
			return baseMiniBossValue * Math.pow(2, miniBossLevel);
		}
		// Main boss waves (waves 10, 20, 30, etc.)
		var bossLevel = Math.floor(waveNumber / 10);
		// Base value derived from total health of wave 9 enemies
		var baseBossValue = 210;
		return baseBossValue * Math.pow(2, bossLevel - 1);
	},
	isBossWave: function isBossWave(waveNumber) {
		// Both PvP and Coop now have mini-bosses every 5 waves and main bosses every 10 waves
		return waveNumber > 0 && (waveNumber % 10 === 0 || waveNumber % 10 === 5);
	},
	spawnChip: function spawnChip(isPlayerSide) {
		if (this.isBossWave(this.waveNumber)) {
			// Boss wave: spawn ONE big enemy at the start, then nothing
			if (!this.bossSpawned) {
				var bossValue = this.getBossChipValue(this.waveNumber);
				ChipSpawner.spawnChip(bossValue, isPlayerSide);
				this.bossSpawned = true;
				console.log("BOSS spawned with value:", bossValue);
			}
			// Don't spawn anything else during boss wave
			return;
		}
		// Normal wave spawning - always single enemy
		var chipValue = this.getChipValue(this.waveNumber);
		ChipSpawner.spawnChip(chipValue, isPlayerSide);
	},
	playerBossDefeated: false,
	aiBossDefeated: false,
	update: function update() {
		this.waveTimer++;
		// Check if wave is complete
		if (this.waveTimer >= this.waveDuration) {
			// If it's a boss wave, only advance if both bosses are defeated.
			if (this.isBossWave(this.waveNumber) && (!this.playerBossDefeated || !this.aiBossDefeated)) {
				// Don't end the wave, just let it continue until bosses are defeated.
			} else {
				// For normal waves, or for boss waves where both bosses are defeated.
				// Check if both bosses were defeated in a boss wave
				if (this.isBossWave(this.waveNumber) && this.playerBossDefeated && this.aiBossDefeated) {
					var bossType = this.waveNumber % 10 === 5 ? "MINI-BOSS" : "BOSS";
					console.log("Both " + bossType + "es defeated! Moving to next round!");
					createFloatingText('ROUND COMPLETE!', SCREEN_WIDTH / 2, SCREEN_HEIGHT / 2, 0x00ff00);
					// Reset boss defeat flags
					this.playerBossDefeated = false;
					this.aiBossDefeated = false;
					// Advance to next wave
					var nextWave = this.waveNumber + 1;
					this.waveTimer = 0;
					this.waveNumber = nextWave;
					this.playerSpawnTimer = 0;
					this.aiSpawnTimer = 0;
					this.bossSpawned = false; // Reset boss spawn flag
					// Check if the next wave is a boss wave and show roulette if needed
					if (this.isBossWave(this.waveNumber)) {
						// Pause the game before showing roulette
						gameReady = false;
						BossSystem.showBossRoulette(function () {
							// Resume the game after roulette
							gameReady = true;
							// Roulette complete, continue with normal wave logic
							console.log("Boss roulette completed for wave " + WaveSystem.waveNumber);
						});
					}
					var waveType;
					if (this.isBossWave(this.waveNumber)) {
						waveType = this.waveNumber % 10 === 5 ? "MINI-BOSS WAVE" : "BOSS WAVE";
					} else {
						waveType = "Wave";
					}
					console.log(waveType + " " + this.waveNumber + " starting!");
					return;
				}
				this.waveTimer = 0;
				this.waveNumber++;
				this.playerSpawnTimer = 0;
				this.aiSpawnTimer = 0;
				this.bossSpawned = false; // Reset boss spawn flag
				var waveType;
				if (this.isBossWave(this.waveNumber)) {
					waveType = this.waveNumber % 10 === 5 ? "MINI-BOSS WAVE" : "BOSS WAVE";
				} else {
					waveType = "Wave";
				}
				console.log(waveType + " " + this.waveNumber + " starting!");
				return;
			}
		}
		// BOSS WAVE LOGIC - Spawn bosses immediately at start of wave
		if (this.isBossWave(this.waveNumber)) {
			if (!this.bossSpawned && this.waveTimer === 1) {
				var bossType = this.waveNumber % 10 === 5 ? "MINI-BOSS" : "BOSS";
				console.log("=== " + bossType + " WAVE " + this.waveNumber + " STARTING ===");
				// MODIFIED: Set the boss type from stored selection for BOTH mini-bosses and main bosses
				BossSystem.currentBossType = BossSystem.getBossTypeForWave(this.waveNumber);
				console.log("Setting boss type for wave " + this.waveNumber + ":", BossSystem.currentBossType);
				// Spawn bosses normally
				var playerBossValue = this.getBossChipValue(this.waveNumber);
				ChipSpawner.spawnChip(playerBossValue, true);
				if (gameMode === 'pvp' || gameMode === 'coop') {
					var aiBossValue = this.getBossChipValue(this.waveNumber);
					ChipSpawner.spawnChip(aiBossValue, false);
				} else {
					this.aiBossDefeated = true;
				}
				this.bossSpawned = true;
				return;
			}
			// MODIFIED: Boss defeat detection - show roulette for next wave
			if (this.bossSpawned && this.waveTimer > 120) {
				var bossType = this.waveNumber % 10 === 5 ? "MINI-BOSS" : "BOSS";
				// Check if player side boss is defeated
				// Count only active chips (not falling rain chips)
				var activePlayerChipsCount = 0;
				for (var i = 0; i < activePlayerChips.length; i++) {
					if (activePlayerChips[i].active) {
						activePlayerChipsCount++;
					}
				}
				if (!this.playerBossDefeated && activePlayerChipsCount === 0) {
					this.playerBossDefeated = true;
					createFloatingText(bossType + ' DEFEATED!', SCREEN_WIDTH / 2, PLAYER_AREA_Y + SLOT_HEIGHT, 0xffd700);
					// Show roulette for the NEXT boss wave (when both bosses are defeated)
					if ((gameMode === 'pvp' || gameMode === 'coop') && this.aiBossDefeated) {
						// Both defeated, show roulette for next boss wave
						this.showRouletteForNextBoss && this.showRouletteForNextBoss();
					} else if (gameMode !== 'pvp' && gameMode !== 'coop') {
						// In single player modes (not coop), show roulette immediately
						this.showRouletteForNextBoss && this.showRouletteForNextBoss();
					}
				}
				// Check if AI side boss is defeated (PvP and Coop)
				if (gameMode === 'pvp' || gameMode === 'coop') {
					var activeAIChipsCount = 0;
					for (var i = 0; i < activeAIChips.length; i++) {
						if (activeAIChips[i].active) {
							activeAIChipsCount++;
						}
					}
					if (!this.aiBossDefeated && activeAIChipsCount === 0) {
						this.aiBossDefeated = true;
						createFloatingText('AI ' + bossType + ' DEFEATED!', SCREEN_WIDTH / 2, AI_AREA_Y + SLOT_HEIGHT, 0xffd700);
						// Show roulette for next boss wave if player boss is also defeated
						if (this.playerBossDefeated) {
							this.showRouletteForNextBoss && this.showRouletteForNextBoss();
						}
					}
				}
				// If both bosses defeated, immediately end the wave
				if (this.playerBossDefeated && this.aiBossDefeated) {
					this.waveTimer = this.waveDuration - 1;
				}
			}
			return; // Don't do normal spawning during boss waves
		}
		// NORMAL WAVE LOGIC
		var currentSpawnInterval = this.spawnInterval;
		if (this.waveNumber === 1) {
			currentSpawnInterval = 75; // Slightly faster spawning for wave 1 (1.25 seconds)
		} else if (this.waveNumber >= 2) {
			currentSpawnInterval = Math.max(45, 60 - Math.floor((this.waveNumber - 2) * 15)); // Wave 2 is slower (60), then speeds up to normal (45) for wave 3+
		}
		// Spawn on player side
		this.playerSpawnTimer++;
		if (this.playerSpawnTimer >= currentSpawnInterval) {
			this.playerSpawnTimer = 0;
			this.spawnChip(true);
		}
		// Spawn on AI side
		this.aiSpawnTimer++;
		if (this.aiSpawnTimer >= currentSpawnInterval) {
			this.aiSpawnTimer = 0;
			this.spawnChip(false);
		}
	}
};
/**** 
* Game State
****/ 
var gameState = {
	playerChips: 200,
	aiChips: 200,
	playerLives: 3,
	aiLives: 3,
	isPlayerTurn: true,
	dealCost: 25,
	// Lowered from 38 to 25
	// Starting cost
	dealCount: 0,
	// ... rest remains the same
	playerDeck: [],
	playerHand: [],
	playerPlayArea: [],
	aiDeck: [],
	aiPlayArea: []
};
// Game state management
var currentGameState = 'start'; // 'start' or 'playing'
var startScreenElements = [];
var gameElements = [];
/**** 
* Game Variables
****/ 
var activePlayerChips = [];
var activeAIChips = [];
var activeBullets = [];
var activeMines = [];
var playerTotalDamage = 0;
var aiTotalDamage = 0;
var playerHandNameTexts = [];
var backgroundSuits = [];
var slotIndicators = [];
var selectedCard = null;
var isDragging = false;
var originalCardPosition = null;
var gameReady = false;
var activePlayerChipsContainer = new Container(); // Container for player chips
var activeAIChipsContainer = new Container(); // Container for AI chips
var playerLifeHearts = [];
var aiLifeHearts = [];
var opponentNameText = null;
var playerNameText = null;
var lastPlayerLives = 0;
var lastAiLives = 0;
var gameMode = 'pvp';
var gameLayer = new Container();
var floorBackground = LK.getAsset('floorbackround', {
	anchorX: 0.5,
	anchorY: 0.5
});
floorBackground.x = SCREEN_WIDTH / 2;
floorBackground.y = SCREEN_HEIGHT / 2;
gameLayer.addChild(floorBackground);
var uiLayer = new Container();
game.addChild(gameLayer);
game.addChild(uiLayer);
/**** 
* UI Elements
****/ 
var playerChipsText = new Text2('Chips: 200', {
	size: 50,
	fill: 0xffd700,
	weight: 800,
	stroke: 0x000000,
	strokeThickness: 0
});
playerChipsText.x = 50;
playerChipsText.y = SCREEN_HEIGHT - 120;
playerChipsText.visible = false;
uiLayer.addChild(playerChipsText);
gameElements.push(playerChipsText);
// Add AI stats too for clarity
var waveText = new Text2('Wave: 1', {
	size: 40,
	fill: 0xffffff,
	weight: 800,
	stroke: 0x000000,
	strokeThickness: 0
});
waveText.x = SCREEN_WIDTH - 200;
waveText.y = 50;
waveText.visible = false;
uiLayer.addChild(waveText);
gameElements.push(waveText);
var discardAreaContainer = new Container();
var dealButtonGraphic = discardAreaContainer.attachAsset('dealButton', {
	anchorX: 0.5,
	anchorY: 0.5
});
var refundButtonGraphic = discardAreaContainer.attachAsset('refundButton', {
	anchorX: 0.5,
	anchorY: 0.5
});
refundButtonGraphic.visible = false;
var discardAreaGraphic = dealButtonGraphic;
var discardText = new Text2('-25', {
	size: 50,
	fill: 0xffffff,
	weight: 800,
	stroke: 0x000000,
	strokeThickness: 0
});
discardText.anchor.set(0.5, 0.5);
discardText.y = 110;
discardAreaContainer.addChild(discardText);
// Position it right of the hand
var handWidthForDiscard = 5 * DEAL_SLOT_WIDTH + 4 * 30;
var handStartXForDiscard = (SCREEN_WIDTH - handWidthForDiscard) / 2;
var discardX = handStartXForDiscard + handWidthForDiscard + 30 + DEAL_SLOT_WIDTH / 2;
// Make sure it doesn't go off screen
if (discardX + DEAL_SLOT_WIDTH / 2 > SCREEN_WIDTH) {
	discardX = SCREEN_WIDTH - DEAL_SLOT_WIDTH / 2 - 20;
}
discardAreaContainer.x = discardX + 10 + 10;
discardAreaContainer.y = PLAYER_DEAL_AREA_Y + DEAL_SLOT_HEIGHT / 2 + 10 - 10;
discardAreaContainer.visible = false;
uiLayer.addChild(discardAreaContainer);
gameElements.push(discardAreaContainer);
discardAreaContainer.down = function () {
	if (!isDragging && gameState.playerChips >= gameState.dealCost) {
		// Scale down on press
		tween.stop(discardAreaContainer, {
			scaleX: true,
			scaleY: true
		});
		tween(discardAreaContainer, {
			scaleX: 0.85,
			scaleY: 0.85
		}, {
			duration: 150,
			easing: tween.quadOut
		});
	}
};
// Add this new up handler
discardAreaContainer.up = function () {
	if (!isDragging && gameState.playerChips >= gameState.dealCost) {
		// Scale back up on release
		tween.stop(discardAreaContainer, {
			scaleX: true,
			scaleY: true
		});
		tween(discardAreaContainer, {
			scaleX: 1.0,
			scaleY: 1.0
		}, {
			duration: 150,
			easing: tween.elasticOut
		});
		dealNewHand();
	}
};
/**** 
* Game Functions
****/ 
// --- Kill counter for extra enemy spawn (player kills only) ---
var playerKillCounter = 0;
function handleChipKill(isPlayerSide) {
	// Only count chip kills for extra enemy spawn in PvP mode
	if (gameMode !== 'pvp') {
		return;
	}
	// Only track player kills and spawn extra chips for the AI
	if (isPlayerSide) {
		playerKillCounter++;
		if (playerKillCounter >= 5) {
			playerKillCounter = 0;
			// Spawn extra enemy on AI side
			var chipValue = WaveSystem.getChipValue(WaveSystem.waveNumber);
			ChipSpawner.spawnChip(chipValue, false);
		}
	}
}
function dealInitialHand() {
	var cardsToDeal = 5;
	var dealDelay = 150; // ms
	var dealCard = function dealCard(i) {
		var cardData = CardSystem.dealUniqueCard(true, true); // isPlayerSide=true, allowJokers=true
		var startLevel = Math.floor((WaveSystem.waveNumber - 1) / 10) + 1;
		var handWidth = 5 * DEAL_SLOT_WIDTH + 4 * 30;
		var handStartX = (SCREEN_WIDTH - handWidth) / 2;
		var slotX = handStartX + i * DEAL_SLOT_WIDTH + i * 30 + DEAL_SLOT_WIDTH / 2;
		var slotY = PLAYER_DEAL_AREA_Y + DEAL_SLOT_HEIGHT / 2;
		var startX = slotX;
		var startY = SCREEN_HEIGHT + DEAL_SLOT_HEIGHT;
		// Mark slot as occupied immediately to prevent overwriting if deal is pressed too quickly
		gameState.playerHand[i] = true;
		var cardBack = LK.getAsset('cardBack', {
			anchorX: 0.5,
			anchorY: 0.5
		});
		cardBack.x = startX;
		cardBack.y = startY;
		uiLayer.addChild(cardBack);
		// Animate card flying into place and flipping
		tween(cardBack, {
			x: slotX,
			y: slotY
		}, {
			duration: 250,
			easing: tween.cubicOut,
			onFinish: function onFinish() {
				// Flip animation: shrink back
				tween(cardBack, {
					scaleX: 0.01
				}, {
					duration: 150,
					easing: tween.quadIn,
					onFinish: function onFinish() {
						if (cardBack.parent) {
							cardBack.parent.removeChild(cardBack);
						}
						// Create and show the real card
						var card = new Card(cardData);
						card.setLevel(startLevel);
						card.activate(slotX, slotY, false, true);
						card.scale.x = 0.01;
						uiLayer.addChild(card);
						// Replace the placeholder with the actual card object
						gameState.playerHand[i] = card;
						// Flip animation: expand card face
						tween(card, {
							scaleX: 1.0
						}, {
							duration: 150,
							easing: tween.quadOut,
							onFinish: function onFinish() {
								LK.getSound('cardLand').play();
							}
						});
					}
				});
			}
		});
	};
	for (var i = 0; i < cardsToDeal; i++) {
		(function (index) {
			LK.setTimeout(function () {
				dealCard(index);
			}, index * dealDelay);
		})(i);
	}
	// Enable deal button after all animations are scheduled to finish
	var totalAnimationTime = (cardsToDeal - 1) * dealDelay + 250 + 150 + 200; // Added buffer
	LK.setTimeout(function () {
		if (discardAreaContainer) {
			discardAreaContainer.interactive = true;
			updateUI();
		}
	}, totalAnimationTime);
}
function createBurnEffect(x, y) {
	var numParticles = 4; // Slightly more particles
	for (var i = 0; i < numParticles; i++) {
		var particle = LK.getAsset('burnHeartMod', {
			anchorX: 0.5,
			anchorY: 0.5
		});
		particle.x = x + (Math.random() - 0.5) * 80; // Wider spread
		particle.y = y + (Math.random() - 0.5) * 80;
		particle.scale.set(0.3 + Math.random() * 0.2); // Adjusted for new asset
		var angle = Math.random() * Math.PI * 2;
		var distance = Math.random() * 40 + 25; // Larger movement distance
		var duration = 400 + Math.random() * 500; // Slightly longer duration
		var targetX = x + Math.cos(angle) * distance;
		var targetY = y + Math.sin(angle) * distance - Math.random() * 50; // Float upward more
		gameLayer.addChild(particle);
		tween(particle, {
			x: targetX,
			y: targetY,
			alpha: 0,
			scaleX: 0.1,
			scaleY: 0.1
		}, {
			duration: duration,
			easing: tween.quadOut,
			onFinish: function (p) {
				return function () {
					if (p.parent) {
						p.parent.removeChild(p);
					}
				};
			}(particle)
		});
	}
}
// Add new function for poison particles:
function createPoisonEffect(x, y) {
	var numParticles = 3;
	for (var i = 0; i < numParticles; i++) {
		var particle = LK.getAsset('toxinClubMod', {
			anchorX: 0.5,
			anchorY: 0.5
		});
		particle.x = x + (Math.random() - 0.5) * 60;
		particle.y = y + (Math.random() - 0.5) * 60;
		particle.scale.set((0.2 + Math.random() * 0.1) * 2);
		particle.tint = 0x00ff00; // Green tint for poison
		var angle = Math.random() * Math.PI * 2;
		var distance = Math.random() * 30 + 20;
		var duration = 300 + Math.random() * 400;
		var targetX = x + Math.cos(angle) * distance;
		var targetY = y + Math.sin(angle) * distance - Math.random() * 40;
		gameLayer.addChild(particle);
		tween(particle, {
			x: targetX,
			y: targetY,
			alpha: 0,
			scaleX: 0.05,
			scaleY: 0.05
		}, {
			duration: duration,
			easing: tween.quadOut,
			onFinish: function (p) {
				return function () {
					if (p.parent) {
						p.parent.removeChild(p);
					}
				};
			}(particle)
		});
	}
}
function createIceSparkles(x, y) {
	var numSparkles = 2;
	for (var i = 0; i < numSparkles; i++) {
		var sparkle = LK.getAsset('iceCube', {
			anchorX: 0.5,
			anchorY: 0.5
		});
		sparkle.x = x + (Math.random() - 0.5) * 60;
		sparkle.y = y + (Math.random() - 0.5) * 60;
		sparkle.scale.set(0.1 + Math.random() * 0.1);
		sparkle.alpha = 0.6;
		sparkle.tint = 0x88ddff; // Light blue tint
		gameLayer.addChild(sparkle);
		tween(sparkle, {
			y: sparkle.y - 20,
			alpha: 0,
			scaleX: 0.05,
			scaleY: 0.05
		}, {
			duration: 800,
			easing: tween.quadOut,
			onFinish: function (p) {
				return function () {
					if (p.parent) {
						p.parent.removeChild(p);
					}
				};
			}(sparkle)
		});
	}
}
function createIceShatterEffect(x, y) {
	var numShards = 6;
	for (var i = 0; i < numShards; i++) {
		var shard = LK.getAsset('iceCube', {
			anchorX: 0.5,
			anchorY: 0.5
		});
		shard.x = x;
		shard.y = y;
		shard.scale.set(0.2 + Math.random() * 0.2);
		shard.tint = 0xaaeeff; // Ice blue tint
		var angle = Math.PI * 2 * i / numShards + (Math.random() - 0.5) * 0.5;
		var distance = 40 + Math.random() * 30;
		var targetX = x + Math.cos(angle) * distance;
		var targetY = y + Math.sin(angle) * distance;
		gameLayer.addChild(shard);
		tween(shard, {
			x: targetX,
			y: targetY,
			alpha: 0,
			rotation: Math.random() * Math.PI * 2,
			scaleX: 0.05,
			scaleY: 0.05
		}, {
			duration: 600,
			easing: tween.quadOut,
			onFinish: function (p) {
				return function () {
					if (p.parent) {
						p.parent.removeChild(p);
					}
				};
			}(shard)
		});
	}
}
function createModFloatAnimation(target, shadow) {
	var initialY = target.y;
	var floatDistance = 10;
	var baseDuration = 3000;
	var randomDurationOffset = 1500;
	var initialScale = shadow.scale.x;
	var minScale = initialScale * 0.7;
	var maxScale = initialScale * 1.0;
	function floatUp() {
		if (!target.parent || !target.parent.parent || !target.parent.parent.parent) {
			return;
		}
		var duration = baseDuration / 2 + Math.random() * randomDurationOffset;
		tween(target, {
			y: initialY - floatDistance
		}, {
			duration: duration,
			easing: tween.easeInOut,
			onFinish: floatDown
		});
		tween(shadow, {
			scaleX: minScale,
			scaleY: minScale
		}, {
			duration: duration,
			easing: tween.easeInOut
		});
	}
	function floatDown() {
		if (!target.parent || !target.parent.parent || !target.parent.parent.parent) {
			return;
		}
		var duration = baseDuration / 2 + Math.random() * randomDurationOffset;
		tween(target, {
			y: initialY + floatDistance
		}, {
			duration: duration,
			easing: tween.easeInOut,
			onFinish: floatUp
		});
		tween(shadow, {
			scaleX: maxScale,
			scaleY: maxScale
		}, {
			duration: duration,
			easing: tween.easeInOut
		});
	}
	LK.setTimeout(floatDown, Math.random() * baseDuration);
}
// Add this new function to calculate greed bonus
function calculateGreedBonus(isPlayerSide, baseChipsEarned) {
	// Only calculate bonus if greed mod is equipped
	if (ModSystem.getEquippedModAsset('diamonds', isPlayerSide) !== 'chipsDiamondMod') {
		return 0;
	}
	var playArea = isPlayerSide ? gameState.playerPlayArea : gameState.aiPlayArea;
	var totalBonusPercentage = 0;
	// Calculate bonus from each diamond card on the board
	for (var row = 0; row < PLAY_AREA_ROWS; row++) {
		for (var col = 0; col < PLAY_AREA_COLS; col++) {
			var card = playArea[row][col];
			if (card && card.cardData.suit === 'diamonds') {
				// The "base gain" for this card is 5%
				var baseGain = 0.05;
				// Each level adds an additional 10% gain
				var levelGain = card.level * 0.1;
				totalBonusPercentage += baseGain + levelGain * 0.6;
			}
		}
	}
	// Do not return fractional gains - round up
	return Math.ceil(baseChipsEarned * totalBonusPercentage);
}
function createStartScreen(fromMatch) {
	LK.playMusic('titleSong');
	ModSystem.init();
	// Clear any existing start screen elements
	startScreenElements.forEach(function (element) {
		if (element.parent) {
			element.parent.removeChild(element);
		}
	});
	startScreenElements = [];
	var battleScreenContainer;
	// Add background animation
	var startScreenAnimContainer = new Container();
	uiLayer.addChild(startScreenAnimContainer);
	startScreenElements.push(startScreenAnimContainer);
	var suitAssets = ['heartSuit', 'diamondSuit', 'clubSuit', 'spadeSuit'];
	var spacing = 400;
	var numCols = Math.ceil(SCREEN_WIDTH / spacing) + 3;
	var numRows = Math.ceil(SCREEN_HEIGHT / spacing) + 3;
	var patternWidth = numCols * spacing;
	var patternHeight = numRows * spacing;
	backgroundSuits = [];
	for (var row = 0; row < numRows; row++) {
		for (var col = 0; col < numCols; col++) {
			var suitIndex = (row + col) % suitAssets.length;
			var suitId = suitAssets[suitIndex];
			var suit = LK.getAsset(suitId, {
				anchorX: 0.5,
				anchorY: 0.5
			});
			suit.x = col * spacing - spacing;
			suit.y = row * spacing - spacing;
			suit.alpha = 0.8;
			suit.scale.set(1.5);
			suit.baseX = col * spacing;
			suit.baseY = row * spacing;
			startScreenAnimContainer.addChild(suit);
			backgroundSuits.push(suit);
		}
	}
	var gameLogo = LK.getAsset('titleLogo', {
		anchorX: 0.5,
		anchorY: 0.5
	});
	gameLogo.x = SCREEN_WIDTH / 2;
	gameLogo.y = SCREEN_HEIGHT / 2 - 200;
	uiLayer.addChild(gameLogo);
	startScreenElements.push(gameLogo);
	var bottomBarContainer = new Container();
	uiLayer.addChild(bottomBarContainer);
	startScreenElements.push(bottomBarContainer);
	function showBattleSelection() {
		gameLogo.visible = false;
		bottomBarContainer.visible = true;
		battleScreenContainer = new Container();
		uiLayer.addChild(battleScreenContainer);
		startScreenElements.push(battleScreenContainer);
		var pvpIcon = LK.getAsset('pvpIcon', {
			anchorX: 0.5,
			anchorY: 0.5,
			interactive: true
		});
		pvpIcon.scale.set(3);
		pvpIcon.x = SCREEN_WIDTH * 0.25;
		pvpIcon.y = SCREEN_HEIGHT * 0.45;
		battleScreenContainer.addChild(pvpIcon);
		var pvpButton = LK.getAsset('pvpButton', {
			anchorX: 0.5,
			anchorY: 0.5,
			interactive: true
		});
		pvpButton.scale.set(3);
		pvpButton.x = pvpIcon.x;
		pvpButton.y = pvpIcon.y + pvpIcon.height / 2 + pvpButton.height / 2 + 150;
		battleScreenContainer.addChild(pvpButton);
		var battleRatingText = new Text2('Battle rating: ' + storage.battleRating, {
			size: 70,
			fill: 0xffffff,
			weight: 800,
			stroke: 0x000000,
			strokeThickness: 4
		});
		battleRatingText.anchor.set(0.5, 0.5);
		var battleRatingIcon = LK.getAsset('battleRatingIcon', {
			anchorX: 0.5,
			anchorY: 0.5,
			scaleX: 0.8,
			scaleY: 0.8
		});
		var totalWidth = battleRatingIcon.width + 10 + battleRatingText.width;
		var yPos = pvpIcon.y + pvpIcon.height / 2 + 350;
		battleRatingIcon.x = pvpIcon.x - totalWidth / 2 + battleRatingIcon.width / 2;
		battleRatingIcon.y = yPos;
		battleRatingText.x = battleRatingIcon.x + battleRatingIcon.width / 2 + 10 + battleRatingText.width / 2;
		battleRatingText.y = yPos;
		battleScreenContainer.addChild(battleRatingIcon);
		battleScreenContainer.addChild(battleRatingText);
		var coopIcon = LK.getAsset('coopIcon', {
			anchorX: 0.5,
			anchorY: 0.5,
			interactive: true
		});
		coopIcon.scale.set(3);
		coopIcon.x = SCREEN_WIDTH * 0.75;
		coopIcon.y = pvpIcon.y;
		battleScreenContainer.addChild(coopIcon);
		var coopButton = LK.getAsset('coopButton', {
			anchorX: 0.5,
			anchorY: 0.5,
			interactive: true
		});
		coopButton.scale.set(3);
		coopButton.x = coopIcon.x;
		coopButton.y = coopIcon.y + coopIcon.height / 2 + coopButton.height / 2 + 150;
		battleScreenContainer.addChild(coopButton);
		var coopHighestWaveText = new Text2('Highest wave: ' + (storage.coopHighestWave || 0), {
			size: 70,
			fill: 0xffffff,
			weight: 800,
			stroke: 0x000000,
			strokeThickness: 4
		});
		coopHighestWaveText.anchor.set(0.5, 0.5);
		coopHighestWaveText.x = coopIcon.x;
		coopHighestWaveText.y = coopIcon.y + coopIcon.height / 2 + 350;
		battleScreenContainer.addChild(coopHighestWaveText);
		// === DEBUG BUTTON REMOVED ===
		function onPlay(isTutorial, mode) {
			startGame(isTutorial, mode);
		}
		if (!storage.tutorialCompleted && fromMatch !== true) {
			TutorialSystem.start();
			var items = TutorialSystem.startScreenItems;
			items.mods.button.interactive = false;
			items.mods.icon.interactive = false;
			items.shop.button.interactive = false;
			items.shop.icon.interactive = false;
			items.mods.button.alpha = 0.5;
			items.mods.icon.alpha = 0.5;
			items.shop.button.alpha = 0.5;
			items.shop.icon.alpha = 0.5;
			var overlay = new Container();
			overlay.interactive = true;
			overlay.hitArea = new Rectangle(0, 0, SCREEN_WIDTH, SCREEN_HEIGHT);
			var bg = LK.getAsset('card', {
				width: SCREEN_WIDTH,
				height: SCREEN_HEIGHT,
				anchorX: 0,
				anchorY: 0
			});
			bg.tint = 0x000000;
			bg.alpha = 0.7;
			overlay.addChild(bg);
			battleScreenContainer.addChild(overlay);
			battleScreenContainer.removeChild(pvpIcon);
			battleScreenContainer.removeChild(pvpButton);
			overlay.addChild(pvpIcon);
			overlay.addChild(pvpButton);
			coopIcon.interactive = false;
			coopIcon.alpha = 0.3;
			coopButton.interactive = false;
			coopButton.alpha = 0.3;
			TutorialSystem.pulseAnimation(pvpIcon);
			TutorialSystem.pulseAnimation(pvpButton);
			var welcomeText = new Text2("Welcome to Double Down Defense! Let’s jump right into a game, tap on PvP to start!", {
				size: 70,
				fill: 0xffffff,
				weight: 'bold',
				stroke: 0x000000,
				strokeThickness: 5,
				align: 'center',
				wordWrap: true,
				wordWrapWidth: SCREEN_WIDTH - 200
			});
			welcomeText.anchor.set(0.5, 0.5);
			welcomeText.x = SCREEN_WIDTH / 2;
			welcomeText.y = SCREEN_HEIGHT * 0.25;
			overlay.addChild(welcomeText);
			pvpIcon.down = function () {
				onPlay(true, 'pvp');
			};
			pvpButton.down = function () {
				onPlay(true, 'pvp');
			};
		} else {
			pvpIcon.down = function () {
				onPlay(false, 'pvp');
			};
			pvpButton.down = function () {
				onPlay(false, 'pvp');
			};
			coopIcon.down = function () {
				onPlay(false, 'coop');
			};
			coopButton.down = function () {
				onPlay(false, 'coop');
			};
		}
	}
	if (fromMatch) {
		showBattleSelection();
	} else {
		// Animate logo scaling in
		gameLogo.scale.set(0.01);
		bottomBarContainer.visible = false;
		tween(gameLogo, {
			scaleX: 1,
			scaleY: 1
		}, {
			duration: 1200,
			easing: tween.elasticOut,
			onFinish: function onFinish() {
				var tapToStartText = new Text2('Tap anywhere to start', {
					size: 90,
					fill: 0xffffff,
					weight: 'bold',
					stroke: 0x000000,
					strokeThickness: 6
				});
				tapToStartText.anchor.set(0.5, 0.5);
				tapToStartText.x = SCREEN_WIDTH / 2;
				tapToStartText.y = gameLogo.y + gameLogo.height / 2 + 250;
				uiLayer.addChild(tapToStartText);
				startScreenElements.push(tapToStartText);
				function flashAnimation() {
					if (!tapToStartText.parent) {
						return;
					}
					tween(tapToStartText, {
						alpha: 0.2
					}, {
						duration: 1200,
						easing: tween.easeInOut,
						onFinish: function onFinish() {
							if (!tapToStartText.parent) {
								return;
							}
							tween(tapToStartText, {
								alpha: 1.0
							}, {
								duration: 1200,
								easing: tween.easeInOut,
								onFinish: flashAnimation
							});
						}
					});
				}
				flashAnimation();
				var screenTapArea = new Container();
				screenTapArea.interactive = true;
				screenTapArea.hitArea = new Rectangle(0, 0, SCREEN_WIDTH, SCREEN_HEIGHT);
				uiLayer.addChild(screenTapArea);
				startScreenElements.push(screenTapArea);
				screenTapArea.down = function () {
					tween.stop(tapToStartText);
					uiLayer.removeChild(tapToStartText);
					uiLayer.removeChild(screenTapArea);
					showBattleSelection();
				};
			}
		});
	}
	var startBottomBar = LK.getAsset('bottomBar', {
		anchorX: 0.5,
		anchorY: 1
	});
	startBottomBar.x = SCREEN_WIDTH / 2;
	startBottomBar.y = SCREEN_HEIGHT;
	bottomBarContainer.addChild(startBottomBar);
	var topBar = LK.getAsset('bottomBar', {
		anchorX: 0.5,
		anchorY: 0
	});
	topBar.x = SCREEN_WIDTH / 2;
	topBar.y = 65;
	topBar.scale.y = 0.4;
	bottomBarContainer.addChild(topBar);
	var moneyText = new Text2('$' + storage.money, {
		size: 105,
		fill: 0xffd700,
		weight: 800,
		stroke: 0x000000,
		strokeThickness: 4
	});
	moneyText.anchor.set(1, 0.5);
	moneyText.x = SCREEN_WIDTH - 150;
	moneyText.y = topBar.y + topBar.height * topBar.scale.y / 2;
	bottomBarContainer.addChild(moneyText);
	// --- Title screen selection highlight asset ---
	var titleScreenSelection = LK.getAsset('titleScreenSelection', {
		anchorX: 0.5,
		anchorY: 1
	});
	titleScreenSelection.alpha = 0.3;
	bottomBarContainer.addChild(titleScreenSelection);
	// --- Track current selection: "battle", "mods", or "shop" ---
	var currentTitleScreenSelection = "battle";
	// --- Calculate button positions for highlight ---
	var playButton = LK.getAsset('playButton', {
		anchorX: 0.5,
		anchorY: 0.5,
		interactive: true
	});
	playButton.x = SCREEN_WIDTH / 2;
	playButton.y = SCREEN_HEIGHT - 100;
	// Add battleIcon directly above playButton
	var battleIcon = LK.getAsset('battleIcon', {
		anchorX: 0.5,
		anchorY: 1,
		interactive: true
	});
	battleIcon.x = playButton.x;
	battleIcon.y = playButton.y - playButton.height / 2 - 10; // 30px gap above playButton
	bottomBarContainer.addChild(battleIcon);
	bottomBarContainer.addChild(playButton);
	// --- Suit mod button and mods icon ---
	var suitModButton = LK.getAsset('suitModButton', {
		anchorX: 0.5,
		anchorY: 0.5,
		interactive: true
	});
	suitModButton.x = playButton.x + playButton.width / 2 + 100 + suitModButton.width / 2;
	suitModButton.y = playButton.y;
	// Add modsIcon directly above suitModButton, same orientation as battleIcon
	var modsIcon = LK.getAsset('modsIcon', {
		anchorX: 0.5,
		anchorY: 1,
		interactive: true
	});
	modsIcon.x = suitModButton.x;
	modsIcon.y = suitModButton.y - suitModButton.height / 2 - 10; // 10px gap above suitModButton
	bottomBarContainer.addChild(modsIcon);
	bottomBarContainer.addChild(suitModButton);
	// --- Shop button and icon ---
	var shopButton = LK.getAsset('shopButton', {
		anchorX: 0.5,
		anchorY: 0.5,
		interactive: true
	});
	shopButton.x = playButton.x - playButton.width / 2 - 100 - shopButton.width / 2;
	shopButton.y = playButton.y + 10;
	var shopIcon = LK.getAsset('shopIcon', {
		anchorX: 0.5,
		anchorY: 1,
		interactive: true
	});
	shopIcon.x = shopButton.x;
	shopIcon.y = shopButton.y - shopButton.height / 2 - 10;
	bottomBarContainer.addChild(shopIcon);
	bottomBarContainer.addChild(shopButton);
	// --- Mods container as before ---
	// Add modsContainer below the bottom bar and below equipped mods
	var modsContainer = new Container();
	modsContainer.visible = false;
	// Insert modsContainer into uiLayer just before bottomBarContainer to ensure it's below the bottom bar and equipped mods
	var bottomBarContainerIndex = uiLayer.getChildIndex(bottomBarContainer);
	if (bottomBarContainerIndex > 0) {
		uiLayer.addChildAt(modsContainer, bottomBarContainerIndex);
	} else {
		uiLayer.addChild(modsContainer);
	}
	startScreenElements.push(modsContainer);
	// --- Shop Container ---
	var shopContainer = new Container();
	shopContainer.visible = false;
	uiLayer.addChild(shopContainer);
	startScreenElements.push(shopContainer);
	var shopTitle = new Text2('Shop', {
		size: 150,
		fill: 0xffffff,
		weight: 'bold'
	});
	shopTitle.anchor.set(0.5, 0.5);
	shopTitle.x = SCREEN_WIDTH / 2;
	shopTitle.y = 400;
	shopContainer.addChild(shopTitle);
	// Add black overlay behind the random mod shop item
	var shopOverlay = LK.getAsset('card', {
		anchorX: 0.5,
		anchorY: 0.5
	});
	var overlayWidth = 800;
	var overlayHeight = 1200; // 2:3 ratio
	shopOverlay.scale.set(overlayWidth / shopOverlay.width, overlayHeight / shopOverlay.height);
	shopOverlay.x = SCREEN_WIDTH / 2;
	shopOverlay.y = 1476 - 200;
	shopOverlay.tint = 0x000000;
	shopOverlay.alpha = 0.8;
	shopContainer.addChild(shopOverlay);
	// Add shopRandomMod asset in center
	var shopRandomModAsset = LK.getAsset('shopRandomMod', {
		anchorX: 0.5,
		anchorY: 0.5
	});
	shopRandomModAsset.x = SCREEN_WIDTH / 2;
	shopRandomModAsset.y = SCREEN_HEIGHT / 2 - 200;
	shopRandomModAsset.scale.set(0.8);
	shopContainer.addChild(shopRandomModAsset);
	// Add descriptive text underneath
	var shopDescText = new Text2('Buy a random card mod', {
		size: 60,
		fill: 0xffffff,
		weight: 'bold',
		stroke: 0x000000,
		strokeThickness: 3
	});
	shopDescText.anchor.set(0.5, 0.5);
	shopDescText.x = SCREEN_WIDTH / 2;
	shopDescText.y = shopRandomModAsset.y + shopRandomModAsset.height / 2 + 100;
	shopContainer.addChild(shopDescText);
	// Add price text
	var shopPriceText = new Text2('$' + storage.randomModPrice, {
		size: 80,
		fill: 0xffd700,
		weight: 'bold',
		stroke: 0x000000,
		strokeThickness: 4
	});
	shopPriceText.anchor.set(0.5, 0.5);
	shopPriceText.x = SCREEN_WIDTH / 2;
	shopPriceText.y = shopDescText.y + 80;
	shopContainer.addChild(shopPriceText);
	function buyRandomMod() {
		if (storage.money < storage.randomModPrice) {
			createFloatingText("Not enough money!", SCREEN_WIDTH / 2, SCREEN_HEIGHT / 2, 0xff0000, 100);
			return;
		}
		var unownedMods = ModSystem.getUnownedMods();
		if (unownedMods.length === 0) {
			createFloatingText("All mods unlocked!", SCREEN_WIDTH / 2, SCREEN_HEIGHT / 2, 0x00ff00, 100);
			shopPriceText.setText('SOLD OUT');
			shopOverlay.interactive = false;
			shopRandomModAsset.interactive = false;
			return;
		}
		storage.money -= storage.randomModPrice;
		moneyText.setText('$' + storage.money);
		shopOverlay.interactive = false;
		shopRandomModAsset.interactive = false;
		// Hide the static shop random mod asset and its text
		shopRandomModAsset.visible = false;
		shopDescText.visible = false;
		shopPriceText.visible = false;
		var slotContainer = new Container();
		// Position it to replace the shopRandomModAsset
		slotContainer.x = shopRandomModAsset.x;
		slotContainer.y = shopRandomModAsset.y;
		shopContainer.addChild(slotContainer);
		var displayAsset = null;
		var spinDuration = 50;
		var spinsLeft = 20 + Math.floor(Math.random() * 15);
		// NEW LOGIC: Guarantee one of each suit before being fully random.
		// 1. Find which suits the player already owns at least one mod for.
		var ownedSuits = {};
		for (var ownedModId in ModSystem.ownedMods) {
			if (ModSystem.ownedMods[ownedModId]) {
				// Check if the value is true
				var modData = ModSystem.modData[ownedModId];
				if (modData) {
					ownedSuits[modData.suit] = true;
				}
			}
		}
		// 2. Identify suits for which the player owns no mods.
		var suitsWithNoMods = [];
		CardSystem.suits.forEach(function (suit) {
			if (!ownedSuits[suit]) {
				suitsWithNoMods.push(suit);
			}
		});
		// 3. Create a pool of "priority" mods to choose from.
		var priorityUnownedMods = [];
		if (suitsWithNoMods.length > 0) {
			unownedMods.forEach(function (unownedModId) {
				var modData = ModSystem.modData[unownedModId];
				if (modData && suitsWithNoMods.indexOf(modData.suit) !== -1) {
					priorityUnownedMods.push(unownedModId);
				}
			});
		}
		var finalModId;
		// 4. Decide which pool to pick the final mod from.
		if (priorityUnownedMods.length > 0) {
			// The player is missing mods for some suits, so guarantee one from that pool.
			finalModId = priorityUnownedMods[Math.floor(Math.random() * priorityUnownedMods.length)];
		} else {
			// The player either has at least one mod for every suit, or there are no unowned mods for the missing suits.
			// Fallback to picking any unowned mod.
			finalModId = unownedMods[Math.floor(Math.random() * unownedMods.length)];
		}
		function spin() {
			spinsLeft--;
			if (displayAsset && displayAsset.parent) {
				displayAsset.parent.removeChild(displayAsset);
			}
			var modIdToShow = spinsLeft <= 0 ? finalModId : unownedMods[Math.floor(Math.random() * unownedMods.length)];
			// Scale to fill the space of the shopRandomModAsset
			var sizingAsset = LK.getAsset('shopRandomMod', {});
			var modAssetForSizing = LK.getAsset(modIdToShow, {});
			// Match the visible height of the random mod asset, with a small margin
			var scaleToFit = sizingAsset.height * shopRandomModAsset.scale.y / modAssetForSizing.height * 0.9;
			displayAsset = LK.getAsset(modIdToShow, {
				anchorX: 0.5,
				anchorY: 0.5,
				scaleX: scaleToFit,
				scaleY: scaleToFit
			});
			slotContainer.addChild(displayAsset);
			if (spinsLeft <= 0) {
				// REVEAL SEQUENCE
				ModSystem.unlockMod(finalModId);
				if (!TutorialSystem.isActive) {
					storage.randomModPrice = Math.floor(storage.randomModPrice * 1.5) + 50;
				}
				shopPriceText.setText('$' + storage.randomModPrice);
				// Create grey-out overlay
				var revealOverlay = new Container();
				revealOverlay.interactive = true;
				revealOverlay.hitArea = new Rectangle(0, 0, SCREEN_WIDTH, SCREEN_HEIGHT);
				uiLayer.addChild(revealOverlay);
				var bg = LK.getAsset('card', {
					width: SCREEN_WIDTH,
					height: SCREEN_HEIGHT,
					anchorX: 0,
					anchorY: 0
				});
				bg.tint = 0x000000;
				bg.alpha = 0.8;
				revealOverlay.addChild(bg);
				// Move the final mod asset to the reveal overlay
				var finalModAsset = displayAsset;
				finalModAsset.parent.removeChild(finalModAsset);
				revealOverlay.addChild(finalModAsset);
				finalModAsset.x = SCREEN_WIDTH / 2;
				finalModAsset.y = SCREEN_HEIGHT / 2;
				// The slot container is now empty, remove it.
				if (slotContainer.parent) {
					slotContainer.parent.removeChild(slotContainer);
				}
				// Grow larger animation
				tween(finalModAsset, {
					scaleX: finalModAsset.scale.x * 1.5,
					scaleY: finalModAsset.scale.y * 1.5
				}, {
					duration: 500,
					easing: tween.elasticOut
				});
				// "You received" message
				var modData = ModSystem.modData[finalModId];
				var receivedText = new Text2("You received:\n" + modData.name, {
					size: 90,
					fill: 0xffd700,
					weight: 'bold',
					stroke: 0x000000,
					strokeThickness: 6,
					align: 'center'
				});
				receivedText.anchor.set(0.5, 0.5);
				receivedText.x = SCREEN_WIDTH / 2;
				receivedText.y = finalModAsset.y + finalModAsset.height * finalModAsset.scale.y / 2 + 150;
				revealOverlay.addChild(receivedText);
				// Tap to continue message
				var tapToContinue = new Text2("Tap to continue", {
					size: 60,
					fill: 0xffffff,
					weight: 'bold'
				});
				tapToContinue.anchor.set(0.5, 0.5);
				tapToContinue.x = SCREEN_WIDTH / 2;
				tapToContinue.y = SCREEN_HEIGHT - 200;
				revealOverlay.addChild(tapToContinue);
				// Set up tap to continue
				revealOverlay.down = function () {
					revealOverlay.interactive = false; // Prevent multiple taps
					// Fade out and remove reveal screen
					tween(revealOverlay, {
						alpha: 0
					}, {
						duration: 300,
						onFinish: function onFinish() {
							if (revealOverlay.parent) {
								revealOverlay.parent.removeChild(revealOverlay);
							}
							// Show shop elements again
							shopRandomModAsset.visible = true;
							shopDescText.visible = true;
							shopPriceText.visible = true;
							// Re-enable shop interaction if there are mods left
							if (ModSystem.getUnownedMods().length > 0) {
								shopOverlay.interactive = true;
								shopRandomModAsset.interactive = true;
							} else {
								shopPriceText.setText('SOLD OUT');
							}
						}
					});
				};
			} else {
				if (spinsLeft < 10) {
					spinDuration += 25;
				}
				if (spinsLeft < 5) {
					spinDuration += 40;
				}
				LK.setTimeout(spin, spinDuration);
			}
		}
		spin();
	}
	shopOverlay.interactive = true;
	shopOverlay.down = buyRandomMod;
	shopRandomModAsset.interactive = true;
	shopRandomModAsset.down = buyRandomMod;
	// Add pulsing animation to shopRandomMod
	function createPulseAnimation() {
		if (!shopRandomModAsset.parent) {
			return;
		}
		tween(shopRandomModAsset, {
			scaleX: 0.9,
			scaleY: 0.9
		}, {
			duration: 1000,
			easing: tween.easeInOut,
			onFinish: function onFinish() {
				if (!shopRandomModAsset.parent) {
					return;
				}
				tween(shopRandomModAsset, {
					scaleX: 0.8,
					scaleY: 0.8
				}, {
					duration: 1000,
					easing: tween.easeInOut,
					onFinish: createPulseAnimation
				});
			}
		});
	}
	createPulseAnimation();
	// --- Selection highlight logic ---
	// Helper to move the highlight to the correct button
	function updateTitleScreenSelectionHighlight() {
		var targetX, targetY, targetW, targetH;
		if (currentTitleScreenSelection === "battle") {
			targetX = playButton.x;
			targetY = playButton.y + playButton.height / 2; // anchorY:1, so bottom edge
			targetW = playButton.width * 1.1;
			targetH = playButton.height + battleIcon.height + 20; // Cover button, icon, and gap with padding
		} else if (currentTitleScreenSelection === "mods") {
			targetX = suitModButton.x;
			targetY = suitModButton.y + suitModButton.height / 2;
			targetW = suitModButton.width * 1.1;
			targetH = suitModButton.height + modsIcon.height + 20; // Cover button, icon, and gap with padding
		} else if (currentTitleScreenSelection === "shop") {
			targetX = shopButton.x;
			targetY = shopButton.y + shopButton.height / 2;
			targetW = shopButton.width * 1.2;
			targetH = shopButton.height + shopIcon.height + 20;
		}
		// Animate movement and scaling for smoothness
		tween.stop(titleScreenSelection);
		tween(titleScreenSelection, {
			x: targetX,
			y: targetY,
			width: targetW,
			height: targetH
		}, {
			duration: 180,
			easing: tween.cubicOut
		});
	}
	// Set initial size and position for highlight (battle by default)
	titleScreenSelection.width = playButton.width * 1.2;
	titleScreenSelection.height = playButton.height + battleIcon.height + 20;
	titleScreenSelection.x = playButton.x;
	titleScreenSelection.y = playButton.y + playButton.height / 2;
	// --- Selection switching logic ---
	// Screens: "battle", "mods", "shop"
	playButton.down = function () {
		if (currentTitleScreenSelection !== "battle") {
			currentTitleScreenSelection = "battle";
			updateTitleScreenSelectionHighlight();
		}
		// Show battle screen, hide mods, shop and logo
		modsContainer.visible = false;
		shopContainer.visible = false;
		if (battleScreenContainer) {
			battleScreenContainer.visible = true;
		}
		gameLogo.visible = false;
	};
	suitModButton.down = function () {
		if (currentTitleScreenSelection === "mods") {
			return;
		}
		if (currentTitleScreenSelection !== "mods") {
			currentTitleScreenSelection = "mods";
			updateTitleScreenSelectionHighlight();
		}
		// Show mods, hide others
		modsContainer.visible = true;
		shopContainer.visible = false;
		if (battleScreenContainer) {
			battleScreenContainer.visible = false;
		}
		gameLogo.visible = false;
		if (modsContainer.visible) {
			ModSystem.updateTopSuitDisplay();
			// Refresh mod grid visuals
			var gridContainer = modsContainer.children[modsContainer.children.length - 1];
			if (gridContainer && gridContainer.children.length > 0) {
				var suitModAssets = ['burnHeartMod', 'chipsDiamondMod', 'spreadClubMod', 'freezeSpadeMod', 'unityHeartsMod', 'gamblerDiamondsMod', 'slowClubsMod', 'mineSpadesMod', 'investmentHeartsMod', 'boostDiamondsMod', 'ricochetClubsMod', 'deathSpadesMod'];
				var childrenPerMod = 4; // Assumes cell, shadow, mod asset, name text
				for (var modIndex = 0; modIndex < suitModAssets.length; modIndex++) {
					var assetId = suitModAssets[modIndex];
					var isOwned = ModSystem.isModOwned(assetId);
					var cellIndex = modIndex * childrenPerMod;
					var modAssetIndex = cellIndex + 2;
					if (gridContainer.children[cellIndex] && gridContainer.children[modAssetIndex]) {
						var cell = gridContainer.children[cellIndex];
						var modAsset = gridContainer.children[modAssetIndex];
						if (isOwned) {
							modAsset.tint = 0xffffff;
							modAsset.alpha = 1.0;
							cell.tint = 0xffffff;
						} else {
							modAsset.tint = 0x555555;
							modAsset.alpha = 0.6;
							cell.tint = 0x888888;
						}
					}
				}
			}
		}
	};
	shopButton.down = function () {
		if (currentTitleScreenSelection === "shop") {
			return;
		}
		if (currentTitleScreenSelection !== "shop") {
			currentTitleScreenSelection = "shop";
			updateTitleScreenSelectionHighlight();
		}
		// Show shop, hide others
		shopContainer.visible = true;
		modsContainer.visible = false;
		if (battleScreenContainer) {
			battleScreenContainer.visible = false;
		}
		gameLogo.visible = false;
	};
	battleIcon.down = playButton.down;
	modsIcon.down = suitModButton.down;
	var originalPlayDown = playButton.down;
	var originalModsDown = suitModButton.down;
	var originalShopDown = shopButton.down;
	playButton.down = originalPlayDown;
	suitModButton.down = originalModsDown;
	shopButton.down = originalShopDown;
	battleIcon.down = playButton.down;
	modsIcon.down = suitModButton.down;
	shopIcon.down = shopButton.down;
	var shopItemsForTutorial = {
		overlay: shopOverlay,
		asset: shopRandomModAsset,
		buyButtonDown: buyRandomMod,
		priceText: shopPriceText
	};
	// --- Slots Container ---
	var slotsContainer = new Container();
	slotsContainer.visible = false;
	uiLayer.addChild(slotsContainer);
	startScreenElements.push(slotsContainer);
	// All possible combinations - we'll create these by stacking assets
	var suitAssets = ['heartSuit', 'diamondSuit', 'clubSuit', 'spadeSuit'];
	// Add the new symbols to your value assets
	var valueAssets = ['slot10', 'slotJ', 'slotQ', 'slotK', 'slotA'];
	// Add joker as a special symbol (we'll handle it separately)
	var specialSymbols = ['jokerSuit']; // Your existing joker asset
	// Function to create a stacked card symbol (50% larger for slots)
	function createStackedSymbol(suit, value, x, y) {
		var symbolContainer = new Container();
		symbolContainer.x = x;
		symbolContainer.y = y;
		// Add suit asset (background)
		var suitGraphic = LK.getAsset(suit, {
			anchorX: 0.5,
			anchorY: 0.5
		});
		suitGraphic.scale.set(0.8 * 1.4); // 50% larger
		symbolContainer.addChild(suitGraphic);
		// Add value asset (on top)
		var valueGraphic = LK.getAsset(value, {
			anchorX: 0.5,
			anchorY: 0.5
		});
		valueGraphic.scale.set(0.6 * 1.7); // 50% larger
		symbolContainer.addChild(valueGraphic);
		// Store the suit and value for later reference
		symbolContainer.cardSuit = suit;
		symbolContainer.cardValue = value;
		return symbolContainer;
	}
	// Create 5 slot reels with stacked symbols - NO MASKING
	var slotReels = [];
	var currentSymbols = []; // Only one symbol per reel visible
	var reelWidth = 120 * 2; // 50% larger
	var reelHeight = 300 * 2; // 50% larger
	var reelSpacing = 0; // Slightly more spacing for larger symbols
	var totalReelsWidth = 5 * reelWidth + 4 * reelSpacing;
	var startX = SCREEN_WIDTH / 2 - totalReelsWidth / 2;
	// All possible symbols including suits, numbers, and mod symbols
	var allSymbols = ['heartSuit', 'diamondSuit', 'clubSuit', 'spadeSuit', 'slot10', 'slotJ', 'slotQ', 'slotK', 'slotA'];
	// Add mod symbols to the pool
	var modSymbols = Object.keys(ModSystem.modData);
	allSymbols = allSymbols.concat(modSymbols);
	var reelCenters = []; // Add this array
	for (var i = 0; i < 5; i++) {
		// White background reel
		var reelBg = LK.getAsset('card', {
			anchorX: 0.5,
			anchorY: 0.5
		});
		reelBg.scale.set(reelWidth / reelBg.width, reelHeight / reelBg.height);
		reelBg.x = startX + reelWidth / 2 + i * (reelWidth + reelSpacing);
		reelBg.y = SCREEN_HEIGHT / 2 - 360; // Use the same y as slotMachine will be
		reelBg.tint = 0xffffff;
		slotsContainer.addChild(reelBg);
		// Store the center position for this reel
		reelCenters.push({
			x: reelBg.x,
			y: reelBg.y
		});
		// Create initial stacked symbol
		var randomSuit = suitAssets[Math.floor(Math.random() * suitAssets.length)];
		var randomValue = valueAssets[Math.floor(Math.random() * valueAssets.length)];
		var symbol = createStackedSymbol(randomSuit, randomValue, reelBg.x, reelBg.y);
		slotsContainer.addChild(symbol);
		slotReels.push(reelBg);
		currentSymbols.push(symbol);
	}
	// Slot machine graphic (move after reels so it appears above them)
	var slotMachine = LK.getAsset('slotMachine', {
		anchorX: 0.5,
		anchorY: 0.5
	});
	slotMachine.x = SCREEN_WIDTH / 2;
	slotMachine.y = SCREEN_HEIGHT / 2 - 50;
	slotsContainer.addChild(slotMachine);
	// Spin function with simple symbol replacement animation
	// Remove bet slider and handle, use only bet buttons for betting
	var currentBet = 10;
	var minBet = 10;
	var maxBet = Math.min(1000, storage.money || 100);
	var betText = new Text2('Bet: $' + currentBet, {
		size: 50,
		fill: 0xffffff,
		weight: 'bold'
	});
	betText.anchor.set(0.5, 0.5);
	// Place betText in a visually similar location as before
	betText.x = SCREEN_WIDTH / 2 + 560;
	betText.y = SCREEN_HEIGHT / 2 + 570;
	// Only add preset bet buttons for betting
	var betPresets = [10, 25, 50, 100];
	var betAssetIds = {
		10: 'bet10',
		25: 'bet25',
		50: 'bet50',
		100: 'bet100'
	};
	var betButtons = [];
	// Layout: 10 and 25 to the left of spin, 50 and 100 to the right
	var betButtonSpacingX = 220;
	var betButtonSpacingY = 220;
	var spinButtonCenterX = SCREEN_WIDTH / 2;
	var spinButtonY = SCREEN_HEIGHT / 2 + 650;
	var leftBetStartX = spinButtonCenterX - betButtonSpacingX * 2.6;
	var rightBetStartX = spinButtonCenterX + betButtonSpacingX * 1.6;
	var betButtonY = spinButtonY;
	var leftBets = [10, 25];
	var rightBets = [50, 100];
	// Store references to bet and selected assets for toggling
	var betButtonAssets = {};
	var betSelectedAssets = {};
	// Place 10 and 25 to the left of spin button
	for (var i = 0; i < leftBets.length; i++) {
		(function (betAmount, idx) {
			var assetId = betAssetIds[betAmount];
			var betBtn = LK.getAsset(assetId, {
				anchorX: 0.5,
				anchorY: 0.5,
				interactive: true
			});
			betBtn.x = leftBetStartX + idx * betButtonSpacingX;
			betBtn.y = betButtonY;
			betBtn.scale.set(1.2);
			slotsContainer.addChild(betBtn);
			betButtonAssets[betAmount] = betBtn;
			// Create selected asset in same position, alpha 0
			var selectedAssetId = assetId + "selected";
			var betSelected = LK.getAsset(selectedAssetId, {
				anchorX: 0.5,
				anchorY: 0.5,
				scaleX: 1.2,
				scaleY: 1.2,
				x: betBtn.x,
				y: betBtn.y,
				alpha: 0
			});
			slotsContainer.addChild(betSelected);
			betSelectedAssets[betAmount] = betSelected;
			betBtn.down = function () {
				if (isSpinning) {
					return;
				}
				if (betAmount <= maxBet) {
					// Play slotButton sound
					LK.getSound('slotButton').play();
					// Scale down the current visible button (Y-axis only)
					tween.stop(betBtn, {
						scaleY: true
					});
					tween(betBtn, {
						scaleY: 1.02 // 1.2 * 0.85
					}, {
						duration: 150,
						easing: tween.quadOut,
						onFinish: function onFinish() {
							// Now do the asset switch while scaled down
							currentBet = betAmount;
							betText.setText('Bet: $' + currentBet);
							// Show selected asset, hide original, hide others
							for (var b in betButtonAssets) {
								if (parseInt(b) === betAmount) {
									betButtonAssets[b].visible = false;
									betSelectedAssets[b].alpha = 1;
									betSelectedAssets[b].visible = true;
									// Make sure the selected asset starts at the same scaled down state
									betSelectedAssets[b].scaleY = 1.02;
								} else {
									betButtonAssets[b].visible = true;
									betSelectedAssets[b].alpha = 0;
									betSelectedAssets[b].visible = true;
									// Reset other buttons to normal scale
									betButtonAssets[b].scaleY = 1.2;
									betSelectedAssets[b].scaleY = 1.2;
								}
							}
							// Now scale the selected asset back up
							tween(betSelectedAssets[betAmount], {
								scaleY: 1.2
							}, {
								duration: 150,
								easing: tween.elasticOut
							});
						}
					});
				}
			};
			betButtons.push(betBtn);
		})(leftBets[i], i);
	}
	// Place 50 and 100 to the right of spin button
	for (var i = 0; i < rightBets.length; i++) {
		(function (betAmount, idx) {
			var assetId = betAssetIds[betAmount];
			var betBtn = LK.getAsset(assetId, {
				anchorX: 0.5,
				anchorY: 0.5,
				interactive: true
			});
			betBtn.x = rightBetStartX + idx * betButtonSpacingX;
			betBtn.y = betButtonY;
			betBtn.scale.set(1.2);
			slotsContainer.addChild(betBtn);
			betButtonAssets[betAmount] = betBtn;
			// Create selected asset in same position, alpha 0
			var selectedAssetId = assetId + "selected";
			var betSelected = LK.getAsset(selectedAssetId, {
				anchorX: 0.5,
				anchorY: 0.5,
				scaleX: 1.2,
				scaleY: 1.2,
				x: betBtn.x,
				y: betBtn.y,
				alpha: 0
			});
			slotsContainer.addChild(betSelected);
			betSelectedAssets[betAmount] = betSelected;
			betBtn.down = function () {
				if (isSpinning) {
					return;
				}
				if (betAmount <= maxBet) {
					// Play slotButton sound
					LK.getSound('slotButton').play();
					// Scale down the current visible button (Y-axis only)
					tween.stop(betBtn, {
						scaleY: true
					});
					tween(betBtn, {
						scaleY: 1 // 1.2 * 0.85
					}, {
						duration: 50,
						easing: tween.quadOut,
						onFinish: function onFinish() {
							// Now do the asset switch while scaled down
							currentBet = betAmount;
							betText.setText('Bet: $' + currentBet);
							// Show selected asset, hide original, hide others
							for (var b in betButtonAssets) {
								if (parseInt(b) === betAmount) {
									betButtonAssets[b].visible = false;
									betSelectedAssets[b].alpha = 1;
									betSelectedAssets[b].visible = true;
									// Make sure the selected asset starts at the same scaled down state
									betSelectedAssets[b].scaleY = 1.02;
								} else {
									betButtonAssets[b].visible = true;
									betSelectedAssets[b].alpha = 0;
									betSelectedAssets[b].visible = true;
									// Reset other buttons to normal scale
									betButtonAssets[b].scaleY = 1.2;
									betSelectedAssets[b].scaleY = 1.2;
								}
							}
							// Now scale the selected asset back up
							tween(betSelectedAssets[betAmount], {
								scaleY: 1.2
							}, {
								duration: 150,
								easing: tween.elasticOut
							});
						}
					});
				}
			};
			betButtons.push(betBtn);
		})(rightBets[i], i);
	}
	// Set initial selected state
	for (var b in betButtonAssets) {
		if (parseInt(b) === currentBet) {
			betButtonAssets[b].visible = false;
			betSelectedAssets[b].alpha = 1;
			betSelectedAssets[b].visible = true;
		} else {
			betButtonAssets[b].visible = true;
			betSelectedAssets[b].alpha = 0;
			betSelectedAssets[b].visible = true;
		}
	}
	// Spin button
	var spinButton = LK.getAsset('spinButton', {
		anchorX: 0.5,
		anchorY: 0.5,
		interactive: true
	});
	spinButton.x = SCREEN_WIDTH / 2;
	spinButton.y = SCREEN_HEIGHT / 2 + 650;
	slotsContainer.addChild(spinButton);
	// --- Glowing animation for spin button when not spinning ---
	var spinGlowTweenActive = false;
	function startSpinButtonGlow() {
		if (spinGlowTweenActive) {
			return;
		}
		spinGlowTweenActive = true;
		function glowIn() {
			if (!spinButton.parent || isSpinning) {
				spinGlowTweenActive = false;
				return;
			}
			tween(spinButton, {
				tint: 0x888888
			}, {
				duration: 700,
				easing: tween.easeInOut,
				onFinish: glowOut
			});
		}
		function glowOut() {
			if (!spinButton.parent || isSpinning) {
				spinGlowTweenActive = false;
				return;
			}
			tween(spinButton, {
				tint: 0xffffff
			}, {
				duration: 700,
				easing: tween.easeInOut,
				onFinish: glowIn
			});
		}
		glowIn();
	}
	function stopSpinButtonGlow() {
		spinGlowTweenActive = false;
		tween.stop(spinButton, {
			tint: true
		});
		spinButton.tint = 0xffffff;
	}
	// Start glow initially if not spinning
	if (!isSpinning) {
		startSpinButtonGlow();
	}
	// Paytable button
	var paytableButton = LK.getAsset('paytableButton', {
		anchorX: 0.5,
		anchorY: 0.5,
		interactive: true
	});
	paytableButton.x = SCREEN_WIDTH / 2 - 535;
	paytableButton.y = SCREEN_HEIGHT / 2 + 425;
	slotsContainer.addChild(paytableButton);
	var isSpinning = false;
	// Defensive: Define createFloatingText if not already defined to prevent 'Script error.'
	if (typeof createFloatingText !== "function") {
		var _createFloatingText = function _createFloatingText(text, x, y, color, size) {
			// Fallback: log to console if UI not available
			if (typeof console !== "undefined" && typeof console.log === "function") {
				console.log("[FLOATING TEXT]", text, x, y, color, size);
			}
		};
	}
	// Spin function - UPDATED WITH WEIGHTED MOD PROBABILITY
	function spinSlots() {
		if (isSpinning || storage.money < currentBet) {
			if (storage.money < currentBet) {
				createFloatingText("Not enough money!", SCREEN_WIDTH / 2, SCREEN_HEIGHT / 2, 0xff0000, 80);
			}
			return;
		}
		// Play slotSpin sound when the slots start spinning
		LK.getSound('slotSpin').play();
		// Animate the current symbols off screen first
		for (var i = 0; i < currentSymbols.length; i++) {
			(function (index) {
				var symbol = currentSymbols[index];
				if (symbol && symbol.parent) {
					tween(symbol, {
						y: symbol.y + 400
					}, {
						duration: 200,
						easing: tween.quadIn,
						onFinish: function onFinish() {
							if (symbol.parent) {
								symbol.parent.removeChild(symbol);
							}
						}
					});
				}
			})(i);
		}
		isSpinning = true;
		stopSpinButtonGlow();
		storage.money -= currentBet;
		moneyText.setText('$' + storage.money);
		// NEW: Choose a target mod for this spin (if any unowned mods exist)
		var targetMod = null;
		var unownedMods = ModSystem.getUnownedMods();
		if (unownedMods.length > 0) {
			targetMod = unownedMods[Math.floor(Math.random() * unownedMods.length)];
		}
		// Choose final symbols for each reel - UPDATED WITH WEIGHTED LOGIC
		var finalSymbols = [];
		for (var i = 0; i < 5; i++) {
			var rand = Math.random();
			if (rand < 0.008) {
				// 0.1% chance for Joker (super rare)
				finalSymbols.push({
					isJoker: true
				});
			} else if (targetMod && rand < 0.08) {
				// 20% chance for the target mod symbol (much higher than 0.5%)
				finalSymbols.push({
					isMod: true,
					modId: targetMod
				});
			} else if (rand < 0.005) {
				// 0.4% chance for any other random mod symbol
				if (unownedMods.length > 0) {
					var randomMod = unownedMods[Math.floor(Math.random() * unownedMods.length)];
					finalSymbols.push({
						isMod: true,
						modId: randomMod
					});
				} else {
					// Fallback to regular card
					finalSymbols.push({
						isMod: false,
						suit: suitAssets[Math.floor(Math.random() * suitAssets.length)],
						value: valueAssets[Math.floor(Math.random() * valueAssets.length)]
					});
				}
			} else if (rand < 0.4) {
				// 39.5% chance for slotX (junk symbol)
				finalSymbols.push({
					isJunk: true
				});
			} else {
				// 60% chance for regular card (suit + value combination)
				finalSymbols.push({
					isMod: false,
					suit: suitAssets[Math.floor(Math.random() * suitAssets.length)],
					value: valueAssets[Math.floor(Math.random() * valueAssets.length)]
				});
			}
		}
		var finishedReels = 0;
		// Animate each reel by rapidly changing symbols
		// Animate each reel by rapidly changing symbols
		for (var i = 0; i < 5; i++) {
			(function (reelIndex) {
				var spinCount = 0;
				var maxSpins = 20 + reelIndex * 5; // Each reel spins longer (this creates the stop timing difference)
				var currentDelay = 100; // Start fast
				function updateReelSymbol() {
					var symbol = currentSymbols[reelIndex];
					var reelCenter = reelCenters[reelIndex];
					var newSuit, newValue;
					if (spinCount >= maxSpins) {
						// Final symbol - use predetermined final result
						var finalResult = finalSymbols[reelIndex];
						var finalSymbol;
						if (finalResult.isJoker) {
							finalSymbol = LK.getAsset('jokerSuit', {
								anchorX: 0.5,
								anchorY: 0.5
							});
							finalSymbol.scale.set(0.8 * 1.5);
							finalSymbol.isJoker = true;
						} else if (finalResult.isJunk) {
							finalSymbol = LK.getAsset('slotX', {
								anchorX: 0.5,
								anchorY: 0.5
							});
							finalSymbol.scale.set(0.8 * 1.5);
							finalSymbol.isJunk = true;
						} else if (finalResult.isMod) {
							finalSymbol = LK.getAsset(finalResult.modId, {
								anchorX: 0.5,
								anchorY: 0.5
							});
							finalSymbol.scale.set(0.8 * 1.5);
							finalSymbol.isMod = true;
							finalSymbol.modId = finalResult.modId;
						} else {
							finalSymbol = createStackedSymbol(finalResult.suit, finalResult.value, 0, 0);
						}
						// Position final symbol at top of reel using stored center position
						finalSymbol.x = reelCenter.x;
						finalSymbol.y = reelCenter.y - 400; // Start above the reel
						// Insert before slot machine
						var slotMachineIndex = slotsContainer.getChildIndex(slotMachine);
						slotsContainer.addChildAt(finalSymbol, slotMachineIndex);
						// Tween to center position using stored center
						tween(finalSymbol, {
							y: reelCenter.y
						}, {
							duration: 300,
							easing: tween.quadOut,
							onFinish: function onFinish() {
								// Play reelStop sound when the symbol lands in the center
								LK.getSound('reelStop').play();
								if (symbol.parent) {
									symbol.parent.removeChild(symbol);
								}
								currentSymbols[reelIndex] = finalSymbol;
								finishedReels++;
								if (finishedReels === 5) {
									checkWin(finalSymbols);
									isSpinning = false;
									startSpinButtonGlow();
								}
							}
						});
						return;
					}
					// Create random spinning symbol - UPDATED WITH WEIGHTED LOGIC
					var newSymbol;
					var spinRand = Math.random();
					if (spinRand < 0.4) {
						newSymbol = LK.getAsset('slotX', {
							anchorX: 0.5,
							anchorY: 0.5
						});
						newSymbol.scale.set(0.8 * 1.5);
						newSymbol.isJunk = true;
					} else if (targetMod && spinRand < 0.5) {
						// 10% chance to show the target mod during spinning for excitement
						newSymbol = LK.getAsset(targetMod, {
							anchorX: 0.5,
							anchorY: 0.5
						});
						newSymbol.scale.set(0.8 * 1.5);
						newSymbol.isMod = true;
						newSymbol.modId = targetMod;
					} else if (spinRand < 0.52) {
						// 2% chance for any random mod during spinning
						if (unownedMods.length > 0) {
							var modSymbolId = unownedMods[Math.floor(Math.random() * unownedMods.length)];
							newSymbol = LK.getAsset(modSymbolId, {
								anchorX: 0.5,
								anchorY: 0.5
							});
							newSymbol.scale.set(0.8 * 1.5);
							newSymbol.isMod = true;
							newSymbol.modId = modSymbolId;
						} else {
							newSuit = suitAssets[Math.floor(Math.random() * suitAssets.length)];
							newValue = valueAssets[Math.floor(Math.random() * valueAssets.length)];
							newSymbol = createStackedSymbol(newSuit, newValue, 0, 0);
						}
					} else {
						newSuit = suitAssets[Math.floor(Math.random() * suitAssets.length)];
						newValue = valueAssets[Math.floor(Math.random() * valueAssets.length)];
						newSymbol = createStackedSymbol(newSuit, newValue, 0, 0);
					}
					// Position new symbol at top of reel using stored center position
					newSymbol.x = reelCenter.x;
					newSymbol.y = reelCenter.y - 400; // Start above the reel
					// Insert before slot machine
					var slotMachineIndex = slotsContainer.getChildIndex(slotMachine);
					slotsContainer.addChildAt(newSymbol, slotMachineIndex);
					// Tween new symbol down past the bottom using stored center position
					tween(newSymbol, {
						y: reelCenter.y + 400
					}, {
						duration: currentDelay,
						easing: tween.linear,
						onFinish: function onFinish() {
							if (newSymbol.parent) {
								newSymbol.parent.removeChild(newSymbol);
							}
						}
					});
					spinCount++;
					if (spinCount <= maxSpins) {
						currentDelay = Math.min(300, 100 + spinCount * 8);
						LK.setTimeout(updateReelSymbol, currentDelay * 0.7); // Start next symbol before current one finishes
					}
				}
				// FIXED: Start all reels immediately instead of staggered
				LK.setTimeout(updateReelSymbol, 0); // All reels start spinning at the same time
			})(i);
		}
	}
	// Win checking function
	function checkWin(symbols) {
		// Check for 3 mod symbols first
		var modCount = {};
		var cardSymbols = [];
		var jokerCount = 0;
		// Process all symbols, simply skip junk symbols
		for (var i = 0; i < currentSymbols.length; i++) {
			var symbol = currentSymbols[i];
			if (symbol && symbol.isJoker) {
				jokerCount++;
			} else if (symbol && symbol.isJunk) {
				// Just ignore junk symbols - they don't contribute but don't block wins
				continue;
			} else if (symbol && symbol.isMod) {
				// Mod symbol (from spinning)
				modCount[symbol.modId] = (modCount[symbol.modId] || 0) + 1;
			} else if (typeof symbol === "string" && modSymbols.indexOf(symbol) !== -1) {
				// Defensive: string mod symbol (legacy)
				modCount[symbol] = (modCount[symbol] || 0) + 1;
			} else if (symbol && symbol.cardSuit && symbol.cardValue) {
				// Stacked card symbol
				var suit = symbol.cardSuit.replace('Suit', ''); // 'heartSuit' -> 'heart'
				var value = symbol.cardValue.replace('slot', ''); // 'slot10' -> '10'
				cardSymbols.push({
					suit: suit + 's',
					value: value
				}); // Add 's' back: 'hearts'
			} else if (_typeof2(symbol) === "object" && symbol.suit && symbol.value) {
				// Already a card data object
				cardSymbols.push({
					suit: symbol.suit,
					value: symbol.value
				});
			}
		}
		// Check for mod wins (unchanged)
		for (var modSymbol in modCount) {
			if (modCount[modSymbol] >= 3) {
				ModSystem.unlockMod(modSymbol);
				createWinAnimation("MOD WON!", 0x00ff00);
				return;
			}
		}
		// Check for poker hand wins with whatever good symbols we have
		var totalGoodSymbols = cardSymbols.length + jokerCount;
		if (totalGoodSymbols >= 2) {
			// We have at least 2 good symbols (cards + jokers), try to evaluate
			var handEval = evaluateHandWithJokers(cardSymbols, jokerCount);
			var payout = calculateSlotsPayout(handEval, currentBet);
			if (payout > 0) {
				// Play slotWin sound effect when there's a win at the slots
				LK.getSound('slotWin').play();
				storage.money += payout;
				moneyText.setText('$' + storage.money);
				createWinAnimation(handEval.type.replace(/_/g, ' ').toUpperCase() + '\n WIN $' + payout, 0xffd700);
			}
		}
	}
	function calculateSlotsPayout(handEval, bet) {
		var multipliers = {
			'one_pair': 2,
			'two_pair': 3,
			'three_of_a_kind': 5,
			'straight': 8,
			'flush': 10,
			'full_house': 15,
			'four_of_a_kind': 25,
			'straight_flush': 50,
			'royal_flush': 100
		};
		return (multipliers[handEval.type] || 0) * bet;
	}
	function createWinAnimation(text, color) {
		// Use createFloatingText which has proper shadow handling
		var centerX = SCREEN_WIDTH / 2;
		var centerY = SCREEN_HEIGHT / 2 - 200;
		createFloatingText(text, centerX, centerY, color, 200);
		// Make the particle explosion much bigger and explode outwards in all directions from the floating win text
		var numParticles = 60;
		var minRadius = 180;
		var maxRadius = 600;
		for (var i = 0; i < numParticles; i++) {
			var particle = LK.getAsset('explosionParticle', {
				anchorX: 0.5,
				anchorY: 0.5
			});
			// Start at the win text center, with a small random offset for density
			particle.x = centerX + (Math.random() - 0.5) * 40;
			particle.y = centerY + (Math.random() - 0.5) * 40;
			particle.tint = color;
			particle.scale.set(1.2 + Math.random() * 0.7);
			// Calculate angle for even spread, but randomize a bit for natural look
			var angle = Math.PI * 2 * i / numParticles + (Math.random() - 0.5) * 0.25;
			var distance = minRadius + Math.random() * (maxRadius - minRadius);
			// Increase speed by increasing distance and reducing duration
			var speedMultiplier = 2.2; // Increase both distance and reduce duration for higher speed
			distance *= speedMultiplier;
			var targetX = centerX + Math.cos(angle) * distance;
			var targetY = centerY + Math.sin(angle) * distance;
			slotsContainer.addChild(particle);
			tween(particle, {
				x: targetX,
				y: targetY,
				alpha: 0,
				scaleX: 0.1,
				scaleY: 0.1,
				rotation: Math.random() * Math.PI * 2
			}, {
				duration: (1800 + Math.random() * 600) / speedMultiplier,
				easing: tween.quadOut,
				onFinish: function (p) {
					return function () {
						if (p.parent) {
							p.parent.removeChild(p);
						}
					};
				}(particle)
			});
		}
	}
	spinButton.down = function () {
		if (!isSpinning && storage.money >= currentBet) {
			// Play slotButton sound
			LK.getSound('slotButton').play();
			// Scale down on press (Y-axis only)
			tween.stop(spinButton, {
				scaleY: true
			});
			tween(spinButton, {
				scaleY: 0.80
			}, {
				duration: 50,
				easing: tween.quadOut
			});
		}
	};
	spinButton.up = function () {
		if (!isSpinning && storage.money >= currentBet) {
			// Scale back up on release (Y-axis only)
			tween.stop(spinButton, {
				scaleY: true
			});
			tween(spinButton, {
				scaleY: 1.0
			}, {
				duration: 150,
				easing: tween.elasticOut
			});
			spinSlots();
		}
	};
	// Paytable popup
	paytableButton.down = function () {
		showPaytable();
	};
	function showPaytable() {
		var paytableOverlay = new Container();
		paytableOverlay.interactive = true;
		paytableOverlay.hitArea = new Rectangle(0, 0, SCREEN_WIDTH, SCREEN_HEIGHT);
		uiLayer.addChild(paytableOverlay);
		var bg = LK.getAsset('card', {
			width: SCREEN_WIDTH,
			height: SCREEN_HEIGHT,
			anchorX: 0,
			anchorY: 0
		});
		bg.tint = 0x000000;
		bg.alpha = 0.8;
		paytableOverlay.addChild(bg);
		var paytableCard = LK.getAsset('card', {
			anchorX: 0.5,
			anchorY: 0.5
		});
		paytableCard.scale.set(1600 / paytableCard.width, 2400 / paytableCard.height);
		paytableCard.x = SCREEN_WIDTH / 2;
		paytableCard.y = SCREEN_HEIGHT / 2;
		paytableCard.tint = 0x222222;
		paytableOverlay.addChild(paytableCard);
		var title = new Text2('PAYTABLE', {
			size: 160,
			fill: 0xffffff,
			weight: 'bold'
		});
		title.anchor.set(0.5, 0.5);
		title.x = SCREEN_WIDTH / 2;
		title.y = SCREEN_HEIGHT / 2 - 800;
		paytableOverlay.addChild(title);
		var payouts = ['Royal Flush: 100x', 'Straight Flush: 50x', 'Four of a Kind: 25x', 'Full House: 15x', 'Flush: 10x', 'Straight: 8x', 'Three of a Kind: 5x', 'Two Pair: 3x', 'One Pair: 2x', '', '3 Mod Symbols: Free Mod!'];
		var yStart = SCREEN_HEIGHT / 2 - 600;
		payouts.forEach(function (payout, index) {
			if (payout) {
				var payoutText = new Text2(payout, {
					size: 100,
					fill: index === payouts.length - 1 ? 0x00ff00 : 0xffffff,
					weight: 'bold'
				});
				payoutText.anchor.set(0.5, 0.5);
				payoutText.x = SCREEN_WIDTH / 2;
				payoutText.y = yStart + index * 120;
				paytableOverlay.addChild(payoutText);
			}
		});
		var closeText = new Text2('Tap to close', {
			size: 120,
			fill: 0xcccccc,
			weight: 'bold'
		});
		closeText.anchor.set(0.5, 0.5);
		closeText.x = SCREEN_WIDTH / 2;
		closeText.y = SCREEN_HEIGHT / 2 + 900;
		paytableOverlay.addChild(closeText);
		paytableOverlay.down = function () {
			if (paytableOverlay.parent) {
				paytableOverlay.parent.removeChild(paytableOverlay);
			}
		};
	}
	// Add slots button to bottom bar (modify the existing button setup)
	var slotsButton = LK.getAsset('slotsButton', {
		anchorX: 0.5,
		anchorY: 0.5,
		interactive: true
	});
	slotsButton.x = shopButton.x - (shopButton.width + 120); // Position to the left of shop
	slotsButton.y = shopButton.y - 10;
	bottomBarContainer.addChild(slotsButton);
	var slotsIcon = LK.getAsset('slotsIcon', {
		anchorX: 0.5,
		anchorY: 1,
		interactive: true
	});
	slotsIcon.x = slotsButton.x;
	slotsIcon.y = slotsButton.y - slotsButton.height / 2 - 15;
	bottomBarContainer.addChild(slotsIcon);
	// Update selection highlighting to include slots
	var originalUpdateHighlight = updateTitleScreenSelectionHighlight;
	updateTitleScreenSelectionHighlight = function updateTitleScreenSelectionHighlight() {
		var targetX, targetY, targetW, targetH;
		if (currentTitleScreenSelection === "battle") {
			targetX = playButton.x;
			targetY = playButton.y + playButton.height / 2;
			targetW = playButton.width * 1.1;
			targetH = playButton.height + battleIcon.height + 20;
		} else if (currentTitleScreenSelection === "mods") {
			targetX = suitModButton.x;
			targetY = suitModButton.y + suitModButton.height / 2;
			targetW = suitModButton.width * 1.1;
			targetH = suitModButton.height + modsIcon.height + 20;
		} else if (currentTitleScreenSelection === "shop") {
			targetX = shopButton.x;
			targetY = shopButton.y + shopButton.height / 2;
			targetW = shopButton.width * 1.2;
			targetH = shopButton.height + shopIcon.height + 20;
		} else if (currentTitleScreenSelection === "slots") {
			targetX = slotsButton.x;
			targetY = slotsButton.y + slotsButton.height / 2;
			targetW = slotsButton.width * 1.2;
			targetH = slotsButton.height + slotsIcon.height + 20;
		}
		tween.stop(titleScreenSelection);
		tween(titleScreenSelection, {
			x: targetX,
			y: targetY,
			width: targetW,
			height: targetH
		}, {
			duration: 180,
			easing: tween.cubicOut
		});
	};
	// Add slots button click handlers
	// --- Navigation handlers for slots and other screens with spin lockout ---
	slotsButton.down = function () {
		// Prevent navigation to slots if already spinning (shouldn't happen, but defensive)
		if (isSpinning) {
			createFloatingText("Wait for the spin to finish!", SCREEN_WIDTH / 2, SCREEN_HEIGHT / 2, 0xff0000, 80);
			return;
		}
		if (currentTitleScreenSelection !== "slots") {
			currentTitleScreenSelection = "slots";
			updateTitleScreenSelectionHighlight();
		}
		// Show slots, hide others
		slotsContainer.visible = true;
		modsContainer.visible = false;
		shopContainer.visible = false;
		if (battleScreenContainer) {
			battleScreenContainer.visible = false;
		}
		gameLogo.visible = false;
		// Update max bet based on current money
		maxBet = Math.min(1000, storage.money || 100);
		currentBet = Math.min(currentBet, maxBet);
		betText.setText('Bet: $' + currentBet);
		// Update bet button/selected asset visibility
		if (typeof betButtonAssets !== "undefined" && typeof betSelectedAssets !== "undefined") {
			for (var b in betButtonAssets) {
				if (parseInt(b) === currentBet) {
					betButtonAssets[b].visible = false;
					betSelectedAssets[b].alpha = 1;
					betSelectedAssets[b].visible = true;
				} else {
					betButtonAssets[b].visible = true;
					betSelectedAssets[b].alpha = 0;
					betSelectedAssets[b].visible = true;
				}
			}
		}
	};
	// Helper to block navigation away from slots while spinning
	function blockNavigationIfSpinning() {
		if (isSpinning) {
			createFloatingText("Wait for the spin to finish!", SCREEN_WIDTH / 2, SCREEN_HEIGHT / 2, 0xff0000, 80);
			return true;
		}
		return false;
	}
	// Hide slots screen when navigating away using the bottom bar
	playButton.down = function () {
		if (blockNavigationIfSpinning()) {
			return;
		}
		if (currentTitleScreenSelection !== "battle") {
			currentTitleScreenSelection = "battle";
			updateTitleScreenSelectionHighlight();
		}
		// Show battle screen, hide mods, shop, slots and logo
		modsContainer.visible = false;
		shopContainer.visible = false;
		slotsContainer.visible = false;
		// Restore bet button visibility when leaving slots
		if (typeof betButtonAssets !== "undefined" && typeof betSelectedAssets !== "undefined") {
			for (var b in betButtonAssets) {
				betButtonAssets[b].visible = true;
				betSelectedAssets[b].alpha = 0;
				betSelectedAssets[b].visible = true;
			}
		}
		if (battleScreenContainer) {
			battleScreenContainer.visible = true;
		}
		gameLogo.visible = false;
	};
	suitModButton.down = function () {
		if (blockNavigationIfSpinning()) {
			return;
		}
		if (currentTitleScreenSelection === "mods") {
			return;
		}
		if (currentTitleScreenSelection !== "mods") {
			currentTitleScreenSelection = "mods";
			updateTitleScreenSelectionHighlight();
		}
		// Show mods, hide others
		modsContainer.visible = true;
		shopContainer.visible = false;
		slotsContainer.visible = false;
		if (battleScreenContainer) {
			battleScreenContainer.visible = false;
		}
		gameLogo.visible = false;
		if (modsContainer.visible) {
			ModSystem.updateTopSuitDisplay();
			// Refresh mod grid visuals
			var gridContainer = modsContainer.children[modsContainer.children.length - 1];
			if (gridContainer && gridContainer.children.length > 0) {
				var suitModAssets = ['burnHeartMod', 'chipsDiamondMod', 'spreadClubMod', 'freezeSpadeMod', 'unityHeartsMod', 'gamblerDiamondsMod', 'slowClubsMod', 'mineSpadesMod', 'investmentHeartsMod', 'boostDiamondsMod', 'ricochetClubsMod', 'deathSpadesMod'];
				var childrenPerMod = 4; // Assumes cell, shadow, mod asset, name text
				for (var modIndex = 0; modIndex < suitModAssets.length; modIndex++) {
					var assetId = suitModAssets[modIndex];
					var isOwned = ModSystem.isModOwned(assetId);
					var cellIndex = modIndex * childrenPerMod;
					var modAssetIndex = cellIndex + 2;
					if (gridContainer.children[cellIndex] && gridContainer.children[modAssetIndex]) {
						var cell = gridContainer.children[cellIndex];
						var modAsset = gridContainer.children[modAssetIndex];
						if (isOwned) {
							modAsset.tint = 0xffffff;
							modAsset.alpha = 1.0;
							cell.tint = 0xffffff;
						} else {
							modAsset.tint = 0x555555;
							modAsset.alpha = 0.6;
							cell.tint = 0x888888;
						}
					}
				}
			}
		}
	};
	shopButton.down = function () {
		if (blockNavigationIfSpinning()) {
			return;
		}
		if (currentTitleScreenSelection === "shop") {
			return;
		}
		if (currentTitleScreenSelection !== "shop") {
			currentTitleScreenSelection = "shop";
			updateTitleScreenSelectionHighlight();
		}
		// Show shop, hide others
		shopContainer.visible = true;
		modsContainer.visible = false;
		slotsContainer.visible = false;
		if (battleScreenContainer) {
			battleScreenContainer.visible = false;
		}
		gameLogo.visible = false;
	};
	battleIcon.down = playButton.down;
	modsIcon.down = suitModButton.down;
	shopIcon.down = shopButton.down;
	slotsIcon.down = slotsButton.down;
	// No slider drag logic needed for click-based slider; just call original handlers if they exist
	var originalGameMove = game.move;
	game.move = function (x, y, obj) {
		if (typeof originalGameMove === "function") {
			originalGameMove.call(this, x, y, obj);
		}
	};
	var originalGameUp = game.up;
	game.up = function (x, y, obj) {
		if (typeof originalGameUp === "function") {
			originalGameUp.call(this, x, y, obj);
		}
	};
	// Register slots screen with tutorial system
	TutorialSystem.registerStartScreenElements({
		battle: {
			button: playButton,
			icon: battleIcon,
			down: originalPlayDown
		},
		mods: {
			button: suitModButton,
			icon: modsIcon,
			down: originalModsDown
		},
		shop: {
			button: shopButton,
			icon: shopIcon,
			down: originalShopDown
		},
		slots: {
			button: slotsButton,
			icon: slotsIcon,
			down: slotsButton.down
		},
		modsContainer: modsContainer,
		shopContainer: shopContainer,
		slotsContainer: slotsContainer,
		shopItems: shopItemsForTutorial
	});
	if (TutorialSystem.isActive && fromMatch) {
		// A small delay to ensure the start screen elements are fully rendered
		LK.setTimeout(function () {
			TutorialSystem.advanceStep();
		}, 200);
	}
	var numCircles = suitAssets.length;
	var totalBarWidth = SCREEN_WIDTH - 200;
	var suitSpacing = totalBarWidth / numCircles;
	var startX = SCREEN_WIDTH / 2 - totalBarWidth / 2 + suitSpacing / 2;
	var yOffset = SCREEN_HEIGHT * 0.1;
	var circleY = 300 + yOffset;
	ModSystem.topSuitGraphics = []; // Reset the array
	for (var i = 0; i < numCircles; i++) {
		var circleX = startX + i * suitSpacing;
		var suitContainer = new Container();
		var circleBg = LK.getAsset('card', {
			anchorX: 0.5,
			anchorY: 0.5
		});
		circleBg.scale.set(1.5);
		suitContainer.addChild(circleBg);
		suitContainer.x = circleX;
		suitContainer.y = circleY - SCREEN_HEIGHT * 0.05 + 100;
		modsContainer.addChild(suitContainer);
		ModSystem.topSuitGraphics.push(suitContainer);
	}
	// --- Dark overlay below the four cards and above the equipped mods text ---
	var overlayCard = LK.getAsset('card', {
		anchorX: 0.5,
		anchorY: 0
	});
	var overlayWidth = totalBarWidth + 120; // Wide enough for all four cards and some margin
	var overlayHeight = 650; // Tall enough to cover the cards and the equipped mods text
	overlayCard.scale.set(overlayWidth / overlayCard.width, overlayHeight / overlayCard.height);
	overlayCard.x = SCREEN_WIDTH / 2;
	overlayCard.y = circleY - SCREEN_HEIGHT * 0.05 - overlayCard.height * overlayCard.scale.y / 2 + 130; // Start just above the cards
	overlayCard.alpha = 0.6;
	overlayCard.tint = 0x000000;
	modsContainer.addChildAt(overlayCard, 0);
	var equippedModsText = new Text2('Currently equipped mods', {
		size: 45,
		fill: 0xffffff,
		weight: '600'
	});
	equippedModsText.anchor.set(0.5, 0);
	equippedModsText.x = SCREEN_WIDTH / 2;
	equippedModsText.y = circleY - SCREEN_HEIGHT * 0.05 + 350; // Position 25px below the mod icons
	modsContainer.addChild(equippedModsText);
	// --- MODS SCROLLABLE CONTAINER SETUP ---
	var modsScrollContainer = new Container();
	modsScrollContainer.x = SCREEN_WIDTH / 2;
	modsScrollContainer.y = circleY + 450 - SCREEN_HEIGHT * 0.05;
	modsScrollContainer.hitArea = new Rectangle(-SCREEN_WIDTH / 2, -2000, SCREEN_WIDTH, 4000); // Full width, tall enough for all rows
	modsScrollContainer.interactive = true;
	modsContainer.addChildAt(modsScrollContainer, 0);
	// The gridContainer will be a child of the scrollable container
	var gridContainer = new Container();
	gridContainer.x = 0;
	gridContainer.y = 0;
	modsScrollContainer.addChild(gridContainer);
	var cols = 4;
	var rows = 4;
	var cardForSizing = LK.getAsset('card', {});
	var cellWidth = cardForSizing.width;
	var cellHeight = cardForSizing.height;
	var colSpacing = 160;
	var rowSpacing = 140;
	var gridTotalWidth = cols * cellWidth + (cols - 1) * colSpacing;
	var gridStartX = -gridTotalWidth / 2;
	var gridStartY = 50;
	// Add sabotageSpadesMod, toxinClubMod, gambitDiamondMod, and wildcardHeartMod as the last mods in the grid
	// Bottom row order: Wildcard, Gambit, Toxin, Sabotage
	var suitModAssets = ['burnHeartMod', 'chipsDiamondMod', 'spreadClubMod', 'freezeSpadeMod', 'unityHeartsMod', 'gamblerDiamondsMod', 'slowClubsMod', 'mineSpadesMod', 'investmentHeartsMod', 'boostDiamondsMod', 'ricochetClubsMod', 'deathSpadesMod', 'wildcardHeartMod', 'gambitDiamondMod', 'toxinClubMod', 'sabotageSpadesMod'];
	for (var r = 0; r < rows; r++) {
		for (var c = 0; c < cols; c++) {
			var cell = LK.getAsset('card', {
				anchorX: 0,
				anchorY: 0
			});
			cell.scale.set(1.3);
			cell.x = gridStartX + c * (cellWidth + colSpacing);
			cell.y = gridStartY + r * (cellHeight + rowSpacing);
			gridContainer.addChild(cell);
			var modIndex = r * cols + c;
			if (modIndex < suitModAssets.length) {
				var modAssetId = suitModAssets[modIndex];
				if (modAssetId) {
					var shadow = LK.getAsset('suitShadow', {
						anchorX: 0.5,
						anchorY: 0.5
					});
					shadow.x = cell.x + cell.width * cell.scale.x / 2;
					shadow.y = cell.y + cell.height * cell.scale.y - cell.height * cell.scale.y / 5 + 15;
					shadow.alpha = 0.3;
					gridContainer.addChild(shadow);
					var modAsset = LK.getAsset(modAssetId, {
						anchorX: 0.5,
						anchorY: 0.5
					});
					modAsset.x = cell.x + cell.width * cell.scale.x / 2;
					modAsset.y = cell.y + cell.height * cell.scale.y / 2;
					var isOwned = ModSystem.isModOwned(modAssetId);
					if (!isOwned) {
						modAsset.tint = 0x555555;
						modAsset.alpha = 0.6;
						cell.tint = 0x888888;
					}
					gridContainer.addChild(modAsset);
					var modData = ModSystem.modData[modAssetId];
					if (modData) {
						var nameText = new Text2(modData.name.toUpperCase(), {
							size: 35,
							fill: 0x000000,
							weight: 'bold',
							strokeThickness: 0
						});
						nameText.anchor.set(0.5, 0);
						nameText.x = cell.x + cell.width * cell.scale.x / 2;
						nameText.y = cell.y + 20;
						gridContainer.addChild(nameText);
					}
					createModFloatAnimation(modAsset, shadow);
					// Add click handler for mod display to the entire cell card
					cell.interactive = true;
					(function (assetId, modAssetRef) {
						cell.down = function () {
							ModSystem.showModDisplay(assetId, modAssetRef.x, modAssetRef.y);
						};
					})(modAssetId, modAsset);
				}
			}
		}
	}
	// --- SCROLL LOGIC FOR MODS SCREEN ---
	var modsScrollState = {
		isDragging: false,
		lastY: 0,
		startY: 0,
		startGridY: 0,
		minY: 0,
		maxY: 0
	};
	// Calculate scroll bounds after grid is built
	(function setupModsScrollBounds() {
		// The visible area height for the mods grid (approx 3 rows visible)
		var visibleHeight = 3 * cellHeight * 1.3 + 2 * rowSpacing + 100;
		// The total height of the grid
		var totalGridHeight = rows * cellHeight * 1.3 + (rows - 1) * rowSpacing;
		// The grid's y=0 is at the top of the first cell, so minY is negative
		modsScrollState.minY = Math.min(0, visibleHeight - totalGridHeight - gridStartY);
		modsScrollState.maxY = 0;
		gridContainer.y = 0;
	})();
	// Add drag handlers to the modsScrollContainer for full width drag
	modsScrollContainer.interactive = true;
	modsScrollContainer.down = function (x, y, obj) {
		// Only allow scroll if modsContainer is visible
		if (!modsContainer.visible) {
			return;
		}
		modsScrollState.isDragging = true;
		modsScrollState.lastY = y;
		modsScrollState.startY = y;
		modsScrollState.startGridY = gridContainer.y;
	};
	modsScrollContainer.move = function (x, y, obj) {
		if (!modsScrollState.isDragging) {
			return;
		}
		var dy = y - modsScrollState.lastY;
		modsScrollState.lastY = y;
		var newY = gridContainer.y + dy;
		// Clamp to bounds
		if (newY < modsScrollState.minY) {
			newY = modsScrollState.minY;
		}
		if (newY > modsScrollState.maxY) {
			newY = modsScrollState.maxY;
		}
		gridContainer.y = newY;
	};
	modsScrollContainer.up = function (x, y, obj) {
		modsScrollState.isDragging = false;
	};
	currentGameState = 'start';
}
function startGame(isTutorial, mode) {
	gameMode = mode || 'pvp';
	LK.stopMusic();
	// Clear start screen elements
	startScreenElements.forEach(function (element) {
		if (element.parent) {
			element.parent.removeChild(element);
		}
	});
	startScreenElements = [];
	backgroundSuits = [];
	// Show game elements
	gameElements.forEach(function (element) {
		element.visible = true;
	});
	if (gameMode === 'coop') {
		background.visible = false;
		coopBackground.visible = true;
	} else {
		background.visible = true;
		coopBackground.visible = false;
	}
	currentGameState = 'playing';
	initializeGame(isTutorial || false);
}
// Create a new function for the normal game start sequence:
function startNormalGameSequence() {
	var getReadyText = new Text2('Get ready…', {
		size: 150,
		fill: 0xffffff,
		weight: 'bold',
		stroke: 0x000000,
		strokeThickness: 10
	});
	getReadyText.anchor.set(0.5, 0.5);
	getReadyText.x = SCREEN_WIDTH / 2;
	getReadyText.y = SCREEN_HEIGHT / 2 - 155;
	getReadyText.alpha = 0;
	uiLayer.addChild(getReadyText);
	tween(getReadyText, {
		alpha: 1
	}, {
		duration: 500,
		onFinish: function onFinish() {
			LK.getSound('getReady').play();
		}
	});
	gameReady = false;
	LK.setTimeout(function () {
		if (!getReadyText.parent) {
			return;
		}
		getReadyText.setText('Deal \'em!');
		LK.getSound('gameStart').play();
		dealInitialHand();
		LK.setTimeout(function () {
			if (getReadyText.parent) {
				tween(getReadyText, {
					alpha: 0
				}, {
					duration: 500,
					onFinish: function onFinish() {
						if (getReadyText.parent) {
							getReadyText.parent.removeChild(getReadyText);
						}
						gameReady = true;
						LK.playMusic('pvpMusic');
					}
				});
			}
		}, 1000);
	}, 2000);
}
function initializeGame(isTutorial) {
	// Disable deal button at the start of the round
	discardAreaContainer.interactive = false;
	discardAreaGraphic.tint = 0x666666;
	discardAreaGraphic.alpha = 1.0;
	ModSystem.init();
	AISystem.setupMods();
	PoolManager.init();
	PathSystem.init();
	// Initialize play areas
	gameState.playerPlayArea = [];
	gameState.aiPlayArea = [];
	playerHandNameTexts = [null, null];
	for (var row = 0; row < PLAY_AREA_ROWS; row++) {
		gameState.playerPlayArea[row] = [];
		gameState.aiPlayArea[row] = [];
		for (var col = 0; col < PLAY_AREA_COLS; col++) {
			gameState.playerPlayArea[row][col] = null;
			gameState.aiPlayArea[row][col] = null;
		}
	}
	// Create initial decks
	gameState.playerDeck = CardSystem.createDeck();
	gameState.aiDeck = CardSystem.createDeck();
	// Draw grid lines
	drawPlayAreas();
	drawPaths();
	createLifeDisplays();
	lastPlayerLives = gameState.playerLives;
	if (gameMode === 'coop') {
		gameState.aiLives = gameState.playerLives;
		playerTotalDamage = 0;
		aiTotalDamage = 0;
	}
	lastAiLives = gameState.aiLives;
	// Initialize player's hand with empty slots
	gameState.playerHand = [null, null, null, null, null];
	// Center bar removed
	if (isTutorial) {
		LK.playMusic('pvpMusic');
		gameReady = false;
		AISystem.thinkDelay = 999999;
		TutorialSystem.startInGameTutorial();
	} else {
		// NEW: Show boss roulette at the very beginning
		BossSystem.showBossRoulette(function () {
			// After roulette, show "Get Ready" and start normal game
			startNormalGameSequence();
		});
	}
}
function createLifeDisplays() {
	// Clear any existing hearts and labels
	if (opponentNameText && opponentNameText.parent) {
		opponentNameText.parent.removeChild(opponentNameText);
	}
	if (playerNameText && playerNameText.parent) {
		playerNameText.parent.removeChild(playerNameText);
	}
	playerLifeHearts.forEach(function (h) {
		if (h.parent) {
			h.parent.removeChild(h);
		}
	});
	playerLifeHearts = [];
	aiLifeHearts.forEach(function (h) {
		if (h.parent) {
			h.parent.removeChild(h);
		}
	});
	aiLifeHearts = [];
	if (gameMode === 'coop') {
		var heartSpacing = 110;
		var heartScale = 0.5;
		// Position to the right of the coop background, adjusted up and left
		var startX = coopBackground.x + coopBackground.width / 2 + 80 - SCREEN_WIDTH * 0.05;
		var startY = SCREEN_HEIGHT / 2 - heartSpacing - SCREEN_HEIGHT * 0.07;
		// Player lives are unified in coop mode
		for (var i = 0; i < gameState.playerLives; i++) {
			var heart = LK.getAsset('heartSuit', {
				anchorX: 0.5,
				anchorY: 0.5,
				scaleX: heartScale,
				scaleY: heartScale
			});
			heart.x = startX;
			heart.y = startY + i * heartSpacing;
			uiLayer.addChild(heart);
			playerLifeHearts.push(heart);
		}
	} else {
		var heartSpacing = 110;
		var heartScale = 0.5;
		var startX_AI = 200 - 70;
		var startX_Player = SCREEN_WIDTH - 200 + 70;
		var yPos = SCREEN_HEIGHT / 2 - 137 + 10;
		var labelYPos = yPos - 60;
		// Opponent Name Text
		var totalAIHeartsWidth = (gameState.aiLives - 1) * heartSpacing;
		opponentNameText = new Text2('Opponent', {
			size: 40,
			fill: 0xffffff,
			weight: 800
		});
		opponentNameText.anchor.set(0.5, 1);
		opponentNameText.x = startX_AI + totalAIHeartsWidth / 2;
		opponentNameText.y = labelYPos;
		uiLayer.addChild(opponentNameText);
		// Player Name Text
		var totalPlayerHeartsWidth = (gameState.playerLives - 1) * heartSpacing;
		playerNameText = new Text2('Player', {
			size: 40,
			fill: 0xffffff,
			weight: 800
		});
		playerNameText.anchor.set(0.5, 1);
		playerNameText.x = startX_Player - totalPlayerHeartsWidth / 2;
		playerNameText.y = labelYPos;
		uiLayer.addChild(playerNameText);
		// AI Lives (left side)
		for (var i = 0; i < gameState.aiLives; i++) {
			var heart = LK.getAsset('heartSuit', {
				anchorX: 0.5,
				anchorY: 0.5,
				scaleX: heartScale,
				scaleY: heartScale
			});
			heart.x = startX_AI + i * heartSpacing;
			heart.y = yPos;
			uiLayer.addChild(heart);
			aiLifeHearts.push(heart);
		}
		// Player Lives (right side)
		for (var i = 0; i < gameState.playerLives; i++) {
			var heart = LK.getAsset('heartSuit', {
				anchorX: 0.5,
				anchorY: 0.5,
				scaleX: heartScale,
				scaleY: heartScale
			});
			heart.x = startX_Player - i * heartSpacing;
			heart.y = yPos;
			uiLayer.addChild(heart);
			playerLifeHearts.push(heart);
		}
	}
}
function dealNewHand() {
	if (gameState.playerChips < gameState.dealCost) {
		return;
	}
	// Find an empty slot in the player's hand
	var emptySlotIndex = -1;
	for (var i = 0; i < gameState.playerHand.length; i++) {
		if (!gameState.playerHand[i]) {
			emptySlotIndex = i;
			break;
		}
	}
	// If hand is full, do nothing
	if (emptySlotIndex === -1) {
		return;
	}
	gameState.playerChips -= gameState.dealCost;
	gameState.dealCount++;
	// Progressive cost increase with diminishing returns
	var baseCost = 25; // Changed from 38 to 25
	var newCost;
	if (gameState.dealCount <= 10) {
		// First 10 deals: 8% increase each time
		newCost = Math.floor(baseCost * Math.pow(1.08, gameState.dealCount));
	} else if (gameState.dealCount <= 25) {
		// Deals 11-25: 5% increase each time
		var cost10 = Math.floor(baseCost * Math.pow(1.08, 10)); // Cost at deal 10
		var additionalDeals = gameState.dealCount - 10;
		newCost = Math.floor(cost10 * Math.pow(1.05, additionalDeals));
	} else {
		// Deals 26+: 3% increase each time
		var cost10 = Math.floor(baseCost * Math.pow(1.08, 10));
		var cost25 = Math.floor(cost10 * Math.pow(1.05, 15)); // 15 deals at 5%
		var additionalDeals = gameState.dealCount - 25;
		newCost = Math.floor(cost25 * Math.pow(1.03, additionalDeals));
	}
	gameState.dealCost = newCost;
	var cardData = CardSystem.dealUniqueCard(true, true); // isPlayerSide=true, allowJokers=true
	// After every 10 waves, new cards dealt start one level higher
	var startLevel = Math.floor((WaveSystem.waveNumber - 1) / 10) + 1;
	var i = emptySlotIndex;
	var handWidth = 5 * DEAL_SLOT_WIDTH + 4 * 30; // 5 slots + 4 gaps of 30px
	var handStartX = (SCREEN_WIDTH - handWidth) / 2;
	var slotX = handStartX + i * DEAL_SLOT_WIDTH + i * 30 + DEAL_SLOT_WIDTH / 2;
	var slotY = PLAYER_DEAL_AREA_Y + DEAL_SLOT_HEIGHT / 2;
	// Start position - off to the bottom
	var startX = slotX + (Math.random() - 0.5) * 50; // Slight horizontal variance
	var startY = SCREEN_HEIGHT + DEAL_SLOT_HEIGHT;
	// Mark slot as occupied immediately to prevent overwriting if deal is pressed too quickly
	gameState.playerHand[i] = true;
	var cardBack = LK.getAsset('cardBack', {
		anchorX: 0.5,
		anchorY: 0.5
	});
	cardBack.x = startX;
	cardBack.y = startY;
	uiLayer.addChild(cardBack);
	// Animate card flying into place and flipping
	tween(cardBack, {
		x: slotX,
		y: slotY
	}, {
		duration: 250,
		easing: tween.cubicOut,
		onFinish: function onFinish() {
			// Flip animation: shrink back
			tween(cardBack, {
				scaleX: 0.01
			}, {
				duration: 150,
				easing: tween.quadIn,
				onFinish: function onFinish() {
					if (cardBack.parent) {
						cardBack.parent.removeChild(cardBack);
					}
					// Create and show the real card
					var card = new Card(cardData);
					card.setLevel(startLevel);
					card.activate(slotX, slotY, false, true);
					card.scale.x = 0.01;
					uiLayer.addChild(card);
					// Replace the placeholder with the actual card object
					gameState.playerHand[i] = card;
					// Flip animation: expand card face
					tween(card, {
						scaleX: 1.0
					}, {
						duration: 150,
						easing: tween.quadOut,
						onFinish: function onFinish() {
							LK.getSound('cardLand').play();
						}
					});
				}
			});
		}
	});
	updateUI();
}
function updateUI() {
	playerChipsText.setText('Chips: ' + formatNumberWithSuffix(gameState.playerChips));
	// Update combined deal/discard button text and appearance when not dragging
	if (!isDragging) {
		discardText.setText('-' + formatNumberWithSuffix(gameState.dealCost));
		discardText.fill = 0xffffff;
		// Update button color based on affordability
		if (gameState.playerChips >= gameState.dealCost) {
			discardAreaGraphic.tint = 0xffffff; // No tint when affordable
			discardAreaGraphic.alpha = 1.0; // Full alpha when affordable
		} else {
			discardAreaGraphic.tint = 0x666666; // Grey tint when not affordable
			discardAreaGraphic.alpha = 1.0; // Keep full alpha even when not affordable
		}
	}
	waveText.setText('Wave: ' + WaveSystem.waveNumber);
}
function drawPlayAreas() {
	// Draw player play area slots
	var hand1Text = 'HAND1';
	var hand2Text = 'HAND2';
	for (var row = 0; row < PLAY_AREA_ROWS; row++) {
		for (var col = 0; col < PLAY_AREA_COLS; col++) {
			var slot = new Container();
			var slotGraphics = slot.attachAsset('card', {
				anchorX: 0.5,
				anchorY: 0.5
			});
			slotGraphics.alpha = 0.5;
			var textToShow = row === 0 ? hand1Text : hand2Text;
			var text = new Text2(textToShow.charAt(col), {
				size: 180,
				fill: 0xffffff,
				weight: 'bold'
			});
			text.anchor.set(0.5);
			text.alpha = 0.3;
			slot.addChild(text);
			slot.x = PLAYER_AREA_X + col * SLOT_WIDTH + SLOT_WIDTH / 2;
			slot.y = PLAYER_AREA_Y + row * SLOT_HEIGHT + SLOT_HEIGHT / 2;
			gameLayer.addChild(slot);
			slotIndicators.push(slot);
		}
	}
	// Draw AI play area slots
	for (var row = 0; row < PLAY_AREA_ROWS; row++) {
		for (var col = 0; col < PLAY_AREA_COLS; col++) {
			var slot = new Container();
			var slotGraphics = slot.attachAsset('card', {
				anchorX: 0.5,
				anchorY: 0.5
			});
			slotGraphics.alpha = 0.5;
			slotGraphics.tint = 0xff8888; // Red tint for AI area
			var textToShow = row === 0 ? hand1Text : hand2Text;
			var text = new Text2(textToShow.charAt(col), {
				size: 180,
				fill: 0xffffff,
				weight: 'bold'
			});
			text.anchor.set(0.5);
			text.alpha = 0.3;
			slot.addChild(text);
			slot.x = AI_AREA_X + col * SLOT_WIDTH + SLOT_WIDTH / 2;
			slot.y = AI_AREA_Y + row * SLOT_HEIGHT + SLOT_HEIGHT / 2;
			gameLayer.addChild(slot);
			slotIndicators.push(slot);
		}
	}
	// Draw player deal area slots (hand)
	var rating = storage.battleRating;
	var ratingString = String(rating);
	while (ratingString.length < 4) {
		ratingString = '0' + ratingString;
	}
	for (var i = 0; i < 5; i++) {
		var dealSlot = new Container();
		var dealSlotGraphics = dealSlot.attachAsset('dealSlot', {
			anchorX: 0.5,
			anchorY: 0.5
		});
		dealSlotGraphics.alpha = 0.5;
		if (i === 0) {
			var icon = dealSlot.attachAsset('battleRatingIcon', {
				anchorX: 0.5,
				anchorY: 0.5
			});
			icon.alpha = 0.3;
			var iconScale = dealSlotGraphics.width * 0.8 / icon.width;
			icon.scale.set(iconScale);
		} else {
			var digit = ratingString.charAt(i - 1);
			var text = new Text2(digit, {
				size: 180,
				fill: 0xffffff,
				weight: 'bold'
			});
			text.anchor.set(0.5);
			text.alpha = 0.3;
			dealSlot.addChild(text);
		}
		var handWidth = 5 * DEAL_SLOT_WIDTH + 4 * 30; // 5 slots + 4 gaps of 30px
		var handStartX = (SCREEN_WIDTH - handWidth) / 2;
		dealSlot.x = handStartX + i * DEAL_SLOT_WIDTH + i * 30 + DEAL_SLOT_WIDTH / 2;
		dealSlot.y = PLAYER_DEAL_AREA_Y + DEAL_SLOT_HEIGHT / 2;
		gameLayer.addChild(dealSlot);
		slotIndicators.push(dealSlot);
	}
}
function drawPaths() {
	// Path lines removed - enemies still follow invisible paths
}
// drawPathSegment function removed - no longer needed since path lines are removed
function getSlotPosition(row, col, isPlayerArea) {
	var baseX = isPlayerArea ? PLAYER_AREA_X : AI_AREA_X;
	var baseY = isPlayerArea ? PLAYER_AREA_Y : AI_AREA_Y;
	return {
		x: baseX + col * SLOT_WIDTH + SLOT_WIDTH / 2,
		y: baseY + row * SLOT_HEIGHT + SLOT_HEIGHT / 2
	};
}
function getSlotFromPosition(x, y) {
	// Check player play area
	if (x >= PLAYER_AREA_X && x <= PLAYER_AREA_X + PLAY_AREA_COLS * SLOT_WIDTH && y >= PLAYER_AREA_Y && y <= PLAYER_AREA_Y + PLAY_AREA_ROWS * SLOT_HEIGHT) {
		var col = Math.floor((x - PLAYER_AREA_X) / SLOT_WIDTH);
		var row = Math.floor((y - PLAYER_AREA_Y) / SLOT_HEIGHT);
		if (col >= 0 && col < PLAY_AREA_COLS && row >= 0 && row < PLAY_AREA_ROWS) {
			return {
				area: 'player',
				row: row,
				col: col
			};
		}
	}
	// Check player hand area
	if (y >= PLAYER_DEAL_AREA_Y && y <= PLAYER_DEAL_AREA_Y + DEAL_SLOT_HEIGHT) {
		var handWidth = 5 * DEAL_SLOT_WIDTH + 4 * 30; // 5 slots + 4 gaps of 30px
		var handStartX = (SCREEN_WIDTH - handWidth) / 2;
		for (var i = 0; i < 5; i++) {
			var slotXStart = handStartX + i * (DEAL_SLOT_WIDTH + 30);
			var slotXEnd = slotXStart + DEAL_SLOT_WIDTH;
			if (x >= slotXStart && x <= slotXEnd) {
				return {
					area: 'hand',
					index: i
				};
			}
		}
	}
	// Check discard area
	if (discardAreaContainer && x >= discardAreaContainer.x - DEAL_SLOT_WIDTH / 2 && x <= discardAreaContainer.x + DEAL_SLOT_WIDTH / 2 && y >= discardAreaContainer.y - DEAL_SLOT_HEIGHT / 2 && y <= discardAreaContainer.y + DEAL_SLOT_HEIGHT / 2) {
		return {
			area: 'discard'
		};
	}
	return null;
}
function evaluateRowHand(row, isPlayerArea) {
	var playArea = isPlayerArea ? gameState.playerPlayArea : gameState.aiPlayArea;
	var cards = [];
	for (var col = 0; col < PLAY_AREA_COLS; col++) {
		if (playArea[row][col]) {
			cards.push(playArea[row][col]);
		}
	}
	return CardSystem.evaluatePokerHand(cards);
}
function updateHandNameDisplay(row, handEval) {
	var existingText = playerHandNameTexts[row];
	var shouldShowText = handEval.strength > 1;
	if (shouldShowText) {
		var handName = handEval.type.replace(/_/g, ' ').toUpperCase();
		if (existingText) {
			if (existingText.text !== handName) {
				existingText.setText(handName);
			}
			existingText.visible = true;
		} else {
			var newText = new Text2(handName, {
				size: 50,
				fill: 0xffffff,
				weight: '800',
				stroke: 0x000000,
				strokeThickness: 0
			});
			newText.anchor.set(0.5, 0);
			newText.alpha = 0.8;
			newText.x = PLAYER_AREA_X + PLAY_AREA_COLS * SLOT_WIDTH / 2;
			newText.y = PLAYER_AREA_Y + (row + 1) * SLOT_HEIGHT - 20;
			uiLayer.addChild(newText);
			playerHandNameTexts[row] = newText;
		}
	} else {
		if (existingText) {
			existingText.visible = false;
		}
	}
}
function applyHandBonuses() {
	// Apply bonuses to player cards
	for (var row = 0; row < PLAY_AREA_ROWS; row++) {
		var handEval = evaluateRowHand(row, true);
		updateHandNameDisplay(row, handEval);
		var contributingCards = handEval.contributingCards || [];
		for (var col = 0; col < PLAY_AREA_COLS; col++) {
			var card = gameState.playerPlayArea[row][col];
			if (card) {
				card.handBonus = handEval.multiplier;
				card.calculateStats();
				card.redOutline.visible = handEval.strength > 1 && contributingCards.indexOf(card) !== -1;
			}
		}
	}
	// Apply bonuses to AI cards
	AISystem.applyAIHandBonuses();
}
function getAIDifficultySettings(battleRating) {
	// Post-tutorial AI intelligence now scales more aggressively with battle rating.
	// Normalize rating from 0 to 1, clamped between 0 and a max rating of 1500 (was 2000).
	var maxRatingForScaling = 1500;
	var normalizedRating = Math.max(0, Math.min(battleRating || 0, maxRatingForScaling)) / maxRatingForScaling;
	// thinkDelay: from 300 (5s) down to 45 (0.75s). Starts faster than the original 360 (6s).
	var thinkDelay = 300 - normalizedRating * (300 - 45);
	// optimizationChance: from 10% up to 80%. Higher baseline and ceiling (was 5%-70%).
	var optimizationChance = 0.1 + normalizedRating * (0.8 - 0.1);
	// shouldOptimize: enabled above 50 rating (was 100).
	var shouldOptimize = (battleRating || 0) > 50;
	return {
		thinkDelay: Math.floor(thinkDelay),
		optimizationChance: optimizationChance,
		shouldOptimize: shouldOptimize,
		canLevelUp: (battleRating || 0) > 0,
		// ENHANCED: More aggressive poker focus
		aggressiveMerging: normalizedRating > 0.5,
		// Was 0.3, now more selective
		prioritizeHighHands: normalizedRating > 0.2,
		// Was 0.4, now starts earlier
		pokerFocusWeight: 0.4 + normalizedRating * 0.6,
		// Was 0.2, now 0.4-1.0
		// NEW: Additional poker-focused parameters
		handPotentialWeight: 0.3 + normalizedRating * 0.4,
		// 0.3-0.7 scaling
		minimumMergeThreshold: 15 + normalizedRating * 35,
		// 15-50% damage gain required
		boardFillPriority: 0.95 + normalizedRating * 0.04 // 95-99% fill target
	};
}
/**** 
* AI System
****/ 
var AISystem = {
	thinkTimer: 0,
	moveHistory: [],
	// Track recent moves to prevent oscillation
	lastOptimizationTime: 0,
	// Prevent too frequent optimizations
	lastActionTime: Date.now(),
	actionTimeoutThreshold: 10000,
	// 10 seconds of inactivity triggers emergency mode
	update: function update() {
		var difficulty = getAIDifficultySettings(storage.battleRating);
		var currentThinkDelay = TutorialSystem.isActive ? 999999 : difficulty.thinkDelay;
		this.thinkTimer++;
		if (this.thinkTimer >= currentThinkDelay) {
			this.thinkTimer = 0;
			this.cleanupMoveHistory(); // Clean old moves
			this.makeMove();
		}
	},
	// Track moves to prevent back-and-forth behavior
	addMoveToHistory: function addMoveToHistory(fromRow, fromCol, toRow, toCol, cardId) {
		var move = {
			fromRow: fromRow,
			fromCol: fromCol,
			toRow: toRow,
			toCol: toCol,
			cardId: cardId,
			timestamp: Date.now()
		};
		this.moveHistory.push(move);
		// Keep only last 10 moves
		if (this.moveHistory.length > 10) {
			this.moveHistory.shift();
		}
	},
	// Check if a move would create back-and-forth behavior
	wouldCreateOscillation: function wouldCreateOscillation(fromRow, fromCol, toRow, toCol, cardId) {
		var recentMoves = this.moveHistory.filter(function (move) {
			return move.cardId === cardId && Date.now() - move.timestamp < 10000; // Within last 10 seconds
		});
		// Check for direct back-and-forth (A->B then B->A)
		for (var i = 0; i < recentMoves.length; i++) {
			var move = recentMoves[i];
			if (move.fromRow === toRow && move.fromCol === toCol && move.toRow === fromRow && move.toCol === toCol) {
				return true; // Would reverse a recent move
			}
		}
		// Check for repetitive moves to/from same positions
		var positionCount = recentMoves.filter(function (move) {
			return move.fromRow === fromRow && move.fromCol === fromCol || move.toRow === toRow && move.toCol === toCol;
		}).length;
		return positionCount >= 3; // Too many moves involving these positions
	},
	cleanupMoveHistory: function cleanupMoveHistory() {
		var now = Date.now();
		this.moveHistory = this.moveHistory.filter(function (move) {
			return now - move.timestamp < 20000; // Keep moves from last 20 seconds
		});
	},
	shouldDeal: function shouldDeal() {
		if (gameState.aiChips < gameState.dealCost) {
			return false;
		}
		var emptySlots = this.countEmptySlots();
		return emptySlots > 0;
	},
	countEmptySlots: function countEmptySlots() {
		var count = 0;
		for (var row = 0; row < PLAY_AREA_ROWS; row++) {
			for (var col = 0; col < PLAY_AREA_COLS; col++) {
				if (!gameState.aiPlayArea[row][col]) {
					count++;
				}
			}
		}
		return count;
	},
	countTotalCards: function countTotalCards() {
		return PLAY_AREA_ROWS * PLAY_AREA_COLS - this.countEmptySlots();
	},
	countLowLevelCards: function countLowLevelCards() {
		var count = 0;
		for (var row = 0; row < PLAY_AREA_ROWS; row++) {
			for (var col = 0; col < PLAY_AREA_COLS; col++) {
				var card = gameState.aiPlayArea[row][col];
				if (card && card.level <= 2) {
					count++;
				}
			}
		}
		return count;
	},
	calculateTotalDamageOutput: function calculateTotalDamageOutput() {
		var totalDPS = 0;
		for (var row = 0; row < PLAY_AREA_ROWS; row++) {
			for (var col = 0; col < PLAY_AREA_COLS; col++) {
				var card = gameState.aiPlayArea[row][col];
				if (card) {
					var shotsPerSecond = 60 / card.fireRate;
					var cardDPS = card.damage * shotsPerSecond;
					totalDPS += cardDPS;
				}
			}
		}
		return totalDPS;
	},
	calculateRowDamageOutput: function calculateRowDamageOutput(row) {
		var rowDPS = 0;
		for (var col = 0; col < PLAY_AREA_COLS; col++) {
			var card = gameState.aiPlayArea[row][col];
			if (card) {
				var shotsPerSecond = 60 / card.fireRate;
				var cardDPS = card.damage * shotsPerSecond;
				rowDPS += cardDPS;
			}
		}
		return rowDPS;
	},
	simulateMergeDamage: function simulateMergeDamage(card1, card2) {
		var newLevel = Math.max(card1.level, card2.level) + 1;
		var baseDamage = 10;
		var baseFireRate = 60;
		var damage = Math.floor(baseDamage * Math.pow(1.6, newLevel - 1));
		var fireRate = Math.max(15, Math.floor(baseFireRate / Math.pow(1.2, newLevel - 1)));
		damage = Math.floor(damage * card1.handBonus);
		fireRate = Math.max(10, Math.floor(fireRate / card1.handBonus));
		var shotsPerSecond = 60 / fireRate;
		return damage * shotsPerSecond;
	},
	simulateHandAfterPlacement: function simulateHandAfterPlacement(row, col, newCard) {
		// Create cards array for evaluation without modifying game state
		var cards = [];
		// Add existing cards in the row
		for (var c = 0; c < PLAY_AREA_COLS; c++) {
			if (c === col) {
				// Add the new card at this position
				cards.push(newCard);
			} else if (gameState.aiPlayArea[row][c]) {
				// Add existing card
				cards.push(gameState.aiPlayArea[row][c]);
			}
		}
		// Use the actual poker evaluation system
		return CardSystem.evaluatePokerHand(cards);
	},
	makeMove: function makeMove() {
		var difficulty = getAIDifficultySettings(storage.battleRating);
		var totalCards = this.countTotalCards();
		var emptySlots = this.countEmptySlots();
		var boardSpaceRatio = totalCards / (PLAY_AREA_ROWS * PLAY_AREA_COLS);
		// NEW: Check if AI has been inactive too long
		var timeSinceLastAction = Date.now() - this.lastActionTime;
		var isStuck = timeSinceLastAction > this.actionTimeoutThreshold;
		// PHASE 1: Fill the board first (priority when below target)
		var targetFill = difficulty.boardFillPriority || 0.95;
		if (boardSpaceRatio < targetFill) {
			if (this.shouldDeal()) {
				this.dealAIHand();
				this.lastActionTime = Date.now();
				return; // ← Add this return!
			}
			if (this.tryPlaceCards()) {
				this.lastActionTime = Date.now();
				return;
			}
		}
		// PHASE 2: Smart merging based on damage calculations
		if (difficulty.canLevelUp && this.shouldMergeBasedOnDamage()) {
			if (this.tryMergeCards()) {
				this.lastActionTime = Date.now();
				return;
			}
		}
		// NEW PHASE 2.5: STUCK DETECTION - Force merge if AI hasn't acted in a while
		if (isStuck && difficulty.canLevelUp) {
			console.log("AI appears stuck, forcing emergency merge...");
			if (this.tryEmergencyMerge()) {
				this.lastActionTime = Date.now();
				return;
			}
		}
		// PHASE 3: Optimize positions
		var timeSinceLastOptimization = Date.now() - this.lastOptimizationTime;
		var optimizationDelay = boardSpaceRatio >= 0.95 ? 2000 : 3000;
		if (difficulty.shouldOptimize && boardSpaceRatio >= 0.7 && timeSinceLastOptimization > optimizationDelay) {
			if (this.optimizeCardPositions()) {
				this.lastOptimizationTime = Date.now();
				this.lastActionTime = Date.now();
				return;
			}
		}
		// PHASE 4: Fill remaining empty slots
		if (this.shouldDeal()) {
			this.dealAIHand();
			this.lastActionTime = Date.now();
			return; // ← Add this return!
		}
		// PHASE 5: EMERGENCY MODE - Board is full but AI has chips to spend
		if (emptySlots === 0 && gameState.aiChips >= gameState.dealCost) {
			this.dealAIHand();
			this.lastActionTime = Date.now();
			return;
		}
		// NEW PHASE 6: DESPERATION MODE - Force ANY available merge if completely stuck
		if (isStuck && timeSinceLastAction > this.actionTimeoutThreshold * 2) {
			// 20 seconds
			console.log("AI in desperation mode, forcing ANY merge...");
			if (this.tryEmergencyMerge()) {
				this.lastActionTime = Date.now();
				return;
			}
		}
	},
	tryEmergencyMerge: function tryEmergencyMerge() {
		// Find ANY merge possible, even if not optimal
		var availableMerges = [];
		for (var row1 = 0; row1 < PLAY_AREA_ROWS; row1++) {
			for (var col1 = 0; col1 < PLAY_AREA_COLS; col1++) {
				var card1 = gameState.aiPlayArea[row1][col1];
				if (!card1) {
					continue;
				}
				for (var row2 = 0; row2 < PLAY_AREA_ROWS; row2++) {
					for (var col2 = 0; col2 < PLAY_AREA_COLS; col2++) {
						if (row1 === row2 && col1 === col2) {
							continue;
						}
						var card2 = gameState.aiPlayArea[row2][col2];
						if (!card2 || !card1.canMergeWith(card2)) {
							continue;
						}
						// Calculate "damage" to current setup (lower is better)
						var mergeDamage = this.calculateEmergencyMergePenalty(row1, col1, row2, col2);
						availableMerges.push({
							card1: card1,
							card2: card2,
							row1: row1,
							col1: col1,
							row2: row2,
							col2: col2,
							penalty: mergeDamage
						});
					}
				}
			}
		}
		if (availableMerges.length === 0) {
			return false; // No merges possible
		}
		// Sort by least penalty (least damage to current setup)
		availableMerges.sort(function (a, b) {
			return a.penalty - b.penalty;
		});
		// Perform the least damaging merge
		var bestMerge = availableMerges[0];
		this.mergeCards(bestMerge.card1, bestMerge.card2, bestMerge.row1, bestMerge.col1, bestMerge.row2, bestMerge.col2);
		return true;
	},
	calculateEmergencyMergePenalty: function calculateEmergencyMergePenalty(row1, col1, row2, col2) {
		// Calculate how much "damage" this merge would do to current setup
		var penalty = 0;
		// Penalty for destroying poker hands
		var currentHand1 = evaluateRowHand(row1, false);
		var currentHand2 = row1 !== row2 ? evaluateRowHand(row2, false) : {
			multiplier: 1
		};
		// Higher penalty for destroying better hands
		penalty += (currentHand1.multiplier - 1) * 100;
		if (row1 !== row2) {
			penalty += (currentHand2.multiplier - 1) * 100;
		}
		// Prefer merging lower level cards
		var card1 = gameState.aiPlayArea[row1][col1];
		var card2 = gameState.aiPlayArea[row2][col2];
		penalty -= (card1.level + card2.level) * 10; // Negative = prefer lower levels
		return penalty;
	},
	evaluateHandPotential: function evaluateHandPotential(row, excludeCol) {
		var cards = [];
		for (var col = 0; col < PLAY_AREA_COLS; col++) {
			if (col !== excludeCol && gameState.aiPlayArea[row][col]) {
				cards.push(gameState.aiPlayArea[row][col]);
			}
		}
		if (cards.length < 2) {
			return 0;
		}
		var potential = 0;
		var suits = {};
		var values = {};
		var sortedValues = [];
		// Count suits and values
		cards.forEach(function (card) {
			suits[card.cardData.suit] = (suits[card.cardData.suit] || 0) + 1;
			values[card.cardData.value] = (values[card.cardData.value] || 0) + 1;
			sortedValues.push(this.getCardNumericValue(card.cardData.value));
		}.bind(this));
		sortedValues.sort(function (a, b) {
			return a - b;
		});
		// Flush potential (same suit)
		for (var suit in suits) {
			if (suits[suit] >= 2) {
				potential += suits[suit] * 15; // 15 points per card toward flush
			}
		}
		// Straight potential (consecutive values)
		var consecutiveCount = 1;
		var maxConsecutive = 1;
		for (var i = 1; i < sortedValues.length; i++) {
			if (sortedValues[i] === sortedValues[i - 1] + 1) {
				consecutiveCount++;
				maxConsecutive = Math.max(maxConsecutive, consecutiveCount);
			} else if (sortedValues[i] !== sortedValues[i - 1]) {
				consecutiveCount = 1;
			}
		}
		if (maxConsecutive >= 2) {
			potential += maxConsecutive * 12; // 12 points per card in sequence
		}
		// Pair/trips potential
		for (var value in values) {
			if (values[value] >= 2) {
				potential += values[value] * values[value] * 8; // Exponential for multiples
			}
		}
		return potential;
	},
	getCardNumericValue: function getCardNumericValue(value) {
		var valueMap = {
			'A': 1,
			'2': 2,
			'3': 3,
			'4': 4,
			'5': 5,
			'6': 6,
			'7': 7,
			'8': 8,
			'9': 9,
			'10': 10,
			'J': 11,
			'Q': 12,
			'K': 13
		};
		return valueMap[value] || 0;
	},
	shouldMergeBasedOnDamage: function shouldMergeBasedOnDamage() {
		var difficulty = getAIDifficultySettings(storage.battleRating);
		var bestMerge = this.findBestDamageMerge();
		if (!bestMerge) {
			return false;
		}
		var card1DPS = bestMerge.card1.damage * (60 / bestMerge.card1.fireRate);
		var card2DPS = bestMerge.card2.damage * (60 / bestMerge.card2.fireRate);
		var currentCombinedDPS = card1DPS + card2DPS;
		var mergedDPS = this.simulateMergeDamage(bestMerge.card1, bestMerge.card2);
		var damageGain = mergedDPS - currentCombinedDPS;
		var damageGainPercent = currentCombinedDPS > 0 ? damageGain / currentCombinedDPS * 100 : 0;
		// NEW: Much more selective merging
		var minimumGainPercent = difficulty.minimumMergeThreshold || 20;
		var handBonusScore = bestMerge.handBonusScore || 0;
		// Only merge if:
		// 1. Damage gain is substantial (15-50% based on difficulty), OR
		// 2. Hand bonus improvement is significant, OR  
		// 3. Emergency: too many low level cards clogging board
		var lowLevelCards = this.countLowLevelCards();
		var boardIsClogged = lowLevelCards >= 8 && currentCombinedDPS < 30;
		var substantialDamageGain = damageGainPercent >= minimumGainPercent;
		var significantHandImprovement = handBonusScore >= 100;
		return substantialDamageGain || significantHandImprovement || boardIsClogged;
	},
	findBestDamageMerge: function findBestDamageMerge() {
		var bestMerge = null;
		var bestScore = -Infinity;
		for (var row1 = 0; row1 < PLAY_AREA_ROWS; row1++) {
			for (var col1 = 0; col1 < PLAY_AREA_COLS; col1++) {
				var card1 = gameState.aiPlayArea[row1][col1];
				if (!card1) {
					continue;
				}
				for (var row2 = 0; row2 < PLAY_AREA_ROWS; row2++) {
					for (var col2 = 0; col2 < PLAY_AREA_COLS; col2++) {
						if (row1 === row2 && col1 === col2) {
							continue;
						}
						var card2 = gameState.aiPlayArea[row2][col2];
						if (!card2 || !card1.canMergeWith(card2)) {
							continue;
						}
						// Calculate current DPS including hand bonuses
						var currentDPS1 = card1.damage * (60 / card1.fireRate);
						var currentDPS2 = card2.damage * (60 / card2.fireRate);
						var currentCombined = currentDPS1 + currentDPS2;
						// Simulate merged card DPS with current hand bonus
						var simulatedMergedDPS = this.simulateMergeDamage(card1, card2);
						// Calculate hand bonus improvement
						var handBonusScore = this.evaluateMergeHandBonus(row1, col1, card1, card2);
						// Base damage gain
						var damageGain = simulatedMergedDPS - currentCombined;
						// Total score includes both damage and hand improvements
						var totalScore = damageGain + handBonusScore;
						if (totalScore > bestScore) {
							bestScore = totalScore;
							bestMerge = {
								card1: card1,
								card2: card2,
								row1: row1,
								col1: col1,
								row2: row2,
								col2: col2,
								damageGain: damageGain,
								handBonusScore: handBonusScore,
								totalScore: totalScore
							};
						}
					}
				}
			}
		}
		return bestMerge;
	},
	tryMergeCards: function tryMergeCards() {
		var bestMerge = this.findBestDamageMerge();
		if (!bestMerge) {
			return false;
		}
		this.mergeCards(bestMerge.card1, bestMerge.card2, bestMerge.row1, bestMerge.col1, bestMerge.row2, bestMerge.col2);
		return true;
	},
	evaluateMergeHandBonus: function evaluateMergeHandBonus(mergeRow, mergeCol, card1, card2) {
		var difficulty = getAIDifficultySettings(storage.battleRating);
		var bonus = 0;
		// Get current hand potential before merge
		var currentPotential = this.evaluateHandPotential(mergeRow, -1);
		var potentialAfterMerge = this.evaluateHandPotential(mergeRow, mergeCol);
		// Simulate row after merge
		var tempRow = [];
		for (var col = 0; col < PLAY_AREA_COLS; col++) {
			tempRow[col] = gameState.aiPlayArea[mergeRow][col];
		}
		var mergedCard = {
			cardData: card1.cardData,
			level: Math.max(card1.level, card2.level) + 1,
			handBonus: 1
		};
		// Clear merge positions and place merged card
		tempRow[mergeCol] = mergedCard;
		for (var col = 0; col < PLAY_AREA_COLS; col++) {
			if (tempRow[col] === card2) {
				tempRow[col] = null;
				break;
			}
		}
		var cards = tempRow.filter(function (card) {
			return card !== null;
		});
		// Current vs new hand evaluation
		var currentHandEval = evaluateRowHand(mergeRow, false);
		var newHandEval = CardSystem.evaluatePokerHand(cards);
		// MASSIVELY increased scoring
		var handStrengthImprovement = newHandEval.strength - currentHandEval.strength;
		var multiplierImprovement = newHandEval.multiplier - currentHandEval.multiplier;
		bonus += handStrengthImprovement * 75; // Was 15, now 75
		bonus += multiplierImprovement * 100; // Was 20, now 100
		// Major bonuses for completing strong hands
		if (newHandEval.strength >= 8) {
			// Straight flush
			bonus += 500;
		} else if (newHandEval.strength >= 7) {
			// Full house or four of a kind  
			bonus += 300; // Was 50
		} else if (newHandEval.strength >= 6) {
			// Flush
			bonus += 200;
		} else if (newHandEval.strength >= 5) {
			// Straight
			bonus += 150;
		} else if (newHandEval.strength >= 4) {
			// Three of a kind
			bonus += 100; // Was 25
		} else if (newHandEval.strength >= 2) {
			// Pair or two pair
			bonus += 50; // Was 10
		}
		// PENALTY for destroying hand potential
		var potentialLoss = currentPotential - potentialAfterMerge;
		if (potentialLoss > 0) {
			bonus -= potentialLoss * difficulty.handPotentialWeight;
		}
		return bonus * difficulty.pokerFocusWeight;
	},
	mergeCards: function mergeCards(card1, card2, row1, col1, row2, col2) {
		var mergedCard = card1.mergeWith(card2);
		if (mergedCard) {
			var oldLevel = card2.level;
			gameLayer.removeChild(card1);
			gameLayer.removeChild(card2);
			gameState.aiPlayArea[row1][col1] = null;
			gameState.aiPlayArea[row2][col2] = null;
			var pos = getSlotPosition(row1, col1, false);
			mergedCard.activate(pos.x, pos.y, true, false);
			gameLayer.addChild(mergedCard);
			gameState.aiPlayArea[row1][col1] = mergedCard;
			mergedCard.alpha = 0;
			mergedCard.scaleX = mergedCard.scaleY = 1.5;
			tween(mergedCard, {
				alpha: 1,
				scaleX: 1,
				scaleY: 1
			}, {
				duration: 200,
				easing: tween.elasticOut
			});
			createFloatingText('+Level Up!', mergedCard.x, mergedCard.y - 50, 0x00ff00, 60);
			var damageBefore = Math.floor(10 * Math.pow(1.6, oldLevel - 1));
			var fireRateBefore = Math.max(15, Math.floor(60 / Math.pow(1.2, oldLevel - 1)));
			var damageAfter = Math.floor(10 * Math.pow(1.6, mergedCard.level - 1));
			var fireRateAfter = Math.max(15, Math.floor(60 / Math.pow(1.2, mergedCard.level - 1)));
			var damageIncrease = damageBefore > 0 ? Math.round((damageAfter / damageBefore - 1) * 100) : 0;
			var fireRateIncrease = fireRateAfter > 0 && fireRateAfter < fireRateBefore ? Math.round((fireRateBefore / fireRateAfter - 1) * 100) : 0;
			var statText = "";
			if (damageBefore > 0) {
				var dmgMult = (damageAfter / damageBefore).toFixed(2);
				statText = "Dmg x" + dmgMult;
			}
			createFloatingText(statText, mergedCard.x, mergedCard.y + 55, 0x00ff00, 35);
			this.applyAIHandBonuses();
		}
	},
	// IMPLEMENTED: Previously unused function
	tryPlaceCards: function tryPlaceCards() {
		// This function can be used to move cards from less optimal to more optimal positions
		// without changing rows (within-row optimization)
		var difficulty = getAIDifficultySettings(storage.battleRating);
		for (var row = 0; row < PLAY_AREA_ROWS; row++) {
			var cards = [];
			var positions = [];
			// Collect cards in this row
			for (var col = 0; col < PLAY_AREA_COLS; col++) {
				if (gameState.aiPlayArea[row][col]) {
					cards.push(gameState.aiPlayArea[row][col]);
					positions.push(col);
				}
			}
			if (cards.length >= 2 && cards.length < PLAY_AREA_COLS) {
				// Try to optimize card arrangement within the row
				var bestArrangement = this.findBestRowArrangement(row, cards);
				if (bestArrangement && bestArrangement.improved) {
					this.implementRowArrangement(row, bestArrangement);
					return true;
				}
			}
		}
		return false;
	},
	optimizeCardPositions: function optimizeCardPositions() {
		var totalCards = this.countTotalCards();
		if (totalCards < 6) {
			return false;
		}
		return this.tryOptimizeForDamage();
	},
	// Enhanced optimization with oscillation prevention
	tryOptimizeForDamage: function tryOptimizeForDamage() {
		var difficulty = getAIDifficultySettings(storage.battleRating);
		var bestMove = null;
		var bestScore = 0;
		// Look for moves that improve poker hands
		for (var sourceRow = 0; sourceRow < PLAY_AREA_ROWS; sourceRow++) {
			for (var sourceCol = 0; sourceCol < PLAY_AREA_COLS; sourceCol++) {
				var card = gameState.aiPlayArea[sourceRow][sourceCol];
				if (!card) {
					continue;
				}
				var cardId = card.cardData.id;
				// Try moving this card to different rows
				for (var targetRow = 0; targetRow < PLAY_AREA_ROWS; targetRow++) {
					if (targetRow === sourceRow) {
						continue;
					}
					// Find empty slots in target row
					for (var targetCol = 0; targetCol < PLAY_AREA_COLS; targetCol++) {
						// FIXED: Properly check if target slot is empty
						if (gameState.aiPlayArea[targetRow][targetCol] !== null) {
							continue;
						}
						// CRITICAL: Check for oscillation before calculating
						if (this.wouldCreateOscillation(sourceRow, sourceCol, targetRow, targetCol, cardId)) {
							continue; // Skip moves that would create back-and-forth behavior
						}
						// Calculate current DPS for both rows
						var currentSourceDPS = this.calculateRowDamageOutput(sourceRow);
						var currentTargetDPS = this.calculateRowDamageOutput(targetRow);
						var currentTotal = currentSourceDPS + currentTargetDPS;
						// Simulate the move
						var currentSourceHand = evaluateRowHand(sourceRow, false);
						var simulatedTargetHand = this.simulateHandAfterPlacement(targetRow, targetCol, card);
						// Calculate new DPS after move
						var newSourceDPS = this.simulateRowDPSAfterRemoval(sourceRow, sourceCol);
						var baseTargetDPS = this.calculateRowDamageOutput(targetRow);
						var cardBaseDPS = card.damage * (60 / card.fireRate);
						var newTargetDPS = baseTargetDPS + cardBaseDPS * simulatedTargetHand.multiplier;
						var newTotal = newSourceDPS + newTargetDPS;
						var dpsGain = newTotal - currentTotal;
						var handScore = this.calculateHandScore(simulatedTargetHand, targetRow);
						var totalScore = dpsGain + handScore;
						// Require significant improvement to prevent minor oscillations
						if (totalScore > bestScore && totalScore > 50) {
							// Higher threshold
							bestScore = totalScore;
							bestMove = {
								card: card,
								fromRow: sourceRow,
								fromCol: sourceCol,
								toRow: targetRow,
								toCol: targetCol,
								dpsGain: dpsGain,
								handScore: handScore,
								cardId: cardId
							};
						}
					}
				}
			}
		}
		// Execute the best move with validation and history tracking
		if (bestMove && Math.random() < difficulty.optimizationChance * 0.7) {
			// Reduced frequency
			// FIXED: Add validation before executing move
			if (gameState.aiPlayArea[bestMove.toRow][bestMove.toCol] === null && gameState.aiPlayArea[bestMove.fromRow][bestMove.fromCol] === bestMove.card) {
				// Record the move in history
				this.addMoveToHistory(bestMove.fromRow, bestMove.fromCol, bestMove.toRow, bestMove.toCol, bestMove.cardId);
				// Execute the move
				gameState.aiPlayArea[bestMove.fromRow][bestMove.fromCol] = null;
				gameState.aiPlayArea[bestMove.toRow][bestMove.toCol] = bestMove.card;
				var newPos = getSlotPosition(bestMove.toRow, bestMove.toCol, false);
				tween(bestMove.card, {
					x: newPos.x,
					y: newPos.y
				}, {
					duration: 300,
					easing: tween.quadOut
				});
				this.applyAIHandBonuses();
				return true;
			}
		}
		return false;
	},
	// Helper function for hand scoring
	calculateHandScore: function calculateHandScore(handEval, targetRow) {
		var handScore = 0;
		// Bonus for creating better hands
		if (handEval.strength > 1) {
			handScore += handEval.strength * 20;
			handScore += (handEval.multiplier - 1) * 30;
		}
		// Extra bonus for high-value hands
		if (handEval.strength >= 4) {
			// Three of a kind or better
			handScore += 100;
		} else if (handEval.strength >= 2) {
			// Pair or better
			handScore += 40;
		}
		// Prefer moves to rows with more cards (build complete hands)
		var targetRowCardCount = 0;
		for (var c = 0; c < PLAY_AREA_COLS; c++) {
			if (gameState.aiPlayArea[targetRow][c]) {
				targetRowCardCount++;
			}
		}
		handScore += targetRowCardCount * 15;
		return handScore;
	},
	simulateRowDPSAfterMove: function simulateRowDPSAfterMove(row, newCard) {
		var totalDPS = 0;
		for (var col = 0; col < PLAY_AREA_COLS; col++) {
			var card = gameState.aiPlayArea[row][col];
			if (card) {
				var shotsPerSecond = 60 / card.fireRate;
				totalDPS += card.damage * shotsPerSecond;
			}
		}
		var estimatedHandBonus = 1;
		for (var col = 0; col < PLAY_AREA_COLS; col++) {
			var existingCard = gameState.aiPlayArea[row][col];
			if (existingCard && existingCard.handBonus > estimatedHandBonus) {
				estimatedHandBonus = existingCard.handBonus;
			}
		}
		var newCardBaseDPS = newCard.damage * (60 / newCard.fireRate);
		var estimatedNewCardDPS = newCardBaseDPS * estimatedHandBonus;
		totalDPS += estimatedNewCardDPS;
		return totalDPS;
	},
	simulateRowDPSAfterRemoval: function simulateRowDPSAfterRemoval(row, removedCol) {
		var totalDPS = 0;
		for (var col = 0; col < PLAY_AREA_COLS; col++) {
			if (col === removedCol) {
				continue;
			}
			var card = gameState.aiPlayArea[row][col];
			if (card) {
				var shotsPerSecond = 60 / card.fireRate;
				totalDPS += card.damage * shotsPerSecond;
			}
		}
		return totalDPS;
	},
	dealAIHand: function dealAIHand() {
		if (gameState.aiChips < gameState.dealCost) {
			return;
		}
		gameState.aiChips -= gameState.dealCost;
		var cardData = CardSystem.dealUniqueCard(false, false);
		var startLevel = Math.floor((WaveSystem.waveNumber - 1) / 10) + 1;
		// Create a temporary card to evaluate placement vs merging
		var tempCard = new Card(cardData);
		tempCard.setLevel(startLevel);
		// Find best empty slot
		var bestEmptySlot = this.findBestEmptySlot();
		var emptySlotScore = bestEmptySlot ? this.evaluateEmptySlotPlacement(bestEmptySlot.row, bestEmptySlot.col, tempCard) : -Infinity;
		// Find best merge target
		var bestMergeTarget = this.findBestMergeTarget(tempCard);
		var mergeScore = bestMergeTarget ? bestMergeTarget.score : -Infinity;
		// Choose the better option
		if (mergeScore > emptySlotScore && bestMergeTarget) {
			// Merge with existing card
			this.performMergeWithNewCard(tempCard, bestMergeTarget);
		} else if (bestEmptySlot) {
			// Place in empty slot (existing logic)
			this.placeCardInEmptySlot(tempCard, bestEmptySlot);
		}
		// If neither option is available, the card is lost (shouldn't happen)
	},
	// New function to find the best card to merge with
	findBestMergeTarget: function findBestMergeTarget(newCard) {
		var bestTarget = null;
		var bestScore = -Infinity;
		for (var row = 0; row < PLAY_AREA_ROWS; row++) {
			for (var col = 0; col < PLAY_AREA_COLS; col++) {
				var boardCard = gameState.aiPlayArea[row][col];
				if (!boardCard || !newCard.canMergeWith(boardCard)) {
					continue;
				}
				// Calculate merge value
				var currentDPS = boardCard.damage * (60 / boardCard.fireRate);
				var mergedDPS = this.simulateMergeDamage(newCard, boardCard);
				var dpsGain = mergedDPS - currentDPS;
				// Calculate hand bonus impact
				var handBonusScore = this.evaluateMergeHandBonus(row, col, newCard, boardCard);
				var totalScore = dpsGain + handBonusScore;
				if (totalScore > bestScore) {
					bestScore = totalScore;
					bestTarget = {
						card: boardCard,
						row: row,
						col: col,
						score: totalScore
					};
				}
			}
		}
		return bestTarget;
	},
	// New function to evaluate empty slot placement value
	evaluateEmptySlotPlacement: function evaluateEmptySlotPlacement(row, col, newCard) {
		var baseDPS = newCard.damage * (60 / newCard.fireRate);
		// Simulate hand bonus for placing in this position
		var simulatedHand = this.simulateHandAfterPlacement(row, col, newCard);
		var handBonusDPS = baseDPS * simulatedHand.multiplier;
		// Add positioning bonuses (prefer building toward poker hands)
		var positionBonus = this.evaluatePositionValue(row, col, newCard);
		return handBonusDPS + positionBonus;
	},
	// New function to actually perform the merge
	performMergeWithNewCard: function performMergeWithNewCard(newCard, target) {
		var pos = getSlotPosition(target.row, target.col, false);
		// Create merge animation similar to player merges
		var startY = -SLOT_HEIGHT;
		newCard.x = pos.x;
		newCard.y = startY;
		gameLayer.addChild(newCard);
		// Animate new card moving to target
		tween(newCard, {
			y: pos.y
		}, {
			duration: 400,
			easing: tween.quadOut,
			onFinish: function () {
				// Perform the actual merge
				var mergedCard = newCard.mergeWith(target.card);
				if (mergedCard) {
					var oldLevel = target.card.level; // Store old level for stats calculation
					// Remove old cards
					if (newCard.parent) {
						newCard.parent.removeChild(newCard);
					}
					if (target.card.parent) {
						target.card.parent.removeChild(target.card);
					}
					// Place merged card
					mergedCard.activate(pos.x, pos.y, true, false);
					gameLayer.addChild(mergedCard);
					gameState.aiPlayArea[target.row][target.col] = mergedCard;
					// ADD MISSING LEVEL UP EFFECTS:
					mergedCard.alpha = 0;
					mergedCard.scaleX = mergedCard.scaleY = 1.5;
					tween(mergedCard, {
						alpha: 1,
						scaleX: 1,
						scaleY: 1
					}, {
						duration: 200,
						easing: tween.elasticOut
					});
					// Level Up floating text
					createFloatingText('+Level Up!', mergedCard.x, mergedCard.y - 50, 0x00ff00, 60);
					// Damage increase stats text (similar to mergeCards function)
					var damageBefore = Math.floor(10 * Math.pow(1.6, oldLevel - 1));
					var damageAfter = Math.floor(10 * Math.pow(1.6, mergedCard.level - 1));
					var statText = "";
					if (damageBefore > 0) {
						var dmgMult = (damageAfter / damageBefore).toFixed(2);
						statText = "Dmg x" + dmgMult;
					}
					createFloatingText(statText, mergedCard.x, mergedCard.y + 55, 0x00ff00, 35);
					// Update hand bonuses
					this.applyAIHandBonuses();
				}
			}.bind(this)
		});
	},
	// New function to place card in empty slot (animation similar to old logic)
	placeCardInEmptySlot: function placeCardInEmptySlot(card, slot) {
		var self = this;
		var pos = getSlotPosition(slot.row, slot.col, false);
		var startY = -SLOT_HEIGHT;
		var aiCardBack = LK.getAsset('aiCardBack', {
			anchorX: 0.5,
			anchorY: 0.5
		});
		aiCardBack.x = pos.x;
		aiCardBack.y = startY;
		aiCardBack.rotation = Math.PI * 4;
		aiCardBack.scale.set(0.1);
		gameLayer.addChild(aiCardBack);
		tween(aiCardBack, {
			y: pos.y,
			rotation: 0,
			scaleX: 1,
			scaleY: 1
		}, {
			duration: 600,
			easing: tween.quadOut,
			onFinish: function onFinish() {
				tween(aiCardBack, {
					scaleX: 0.01
				}, {
					duration: 150,
					easing: tween.quadIn,
					onFinish: function onFinish() {
						if (aiCardBack.parent) {
							aiCardBack.parent.removeChild(aiCardBack);
						}
						card.x = pos.x;
						card.y = pos.y;
						card.activate(pos.x, pos.y, true, false);
						card.scale.x = 0.01;
						gameLayer.addChild(card);
						gameState.aiPlayArea[slot.row][slot.col] = card;
						tween(card, {
							scaleX: 1.0
						}, {
							duration: 150,
							easing: tween.quadOut,
							onFinish: function onFinish() {
								self.applyAIHandBonuses();
							}
						});
					}
				});
			}
		});
	},
	// New function to evaluate position value for empty slot placement
	evaluatePositionValue: function evaluatePositionValue(row, col, newCard) {
		// Simple: prefer center columns, and rows with more cards
		var centerCol = Math.floor((PLAY_AREA_COLS - 1) / 2);
		var centerBonus = 3 - Math.abs(col - centerCol);
		var rowCardCount = 0;
		for (var c = 0; c < PLAY_AREA_COLS; c++) {
			if (gameState.aiPlayArea[row][c]) {
				rowCardCount++;
			}
		}
		return centerBonus * 2 + rowCardCount * 10;
	},
	findBestEmptySlot: function findBestEmptySlot() {
		var difficulty = getAIDifficultySettings(storage.battleRating);
		var bestSlot = null;
		var bestScore = 0; // Changed from -1 to 0
		for (var row = 0; row < PLAY_AREA_ROWS; row++) {
			for (var col = 0; col < PLAY_AREA_COLS; col++) {
				if (gameState.aiPlayArea[row][col]) {
					continue; // Slot occupied
				}
				var score = 10; // Base score instead of starting at 0
				// POKER HAND POTENTIAL SCORING
				if (difficulty.prioritizeHighHands) {
					var rowCards = [];
					for (var c = 0; c < PLAY_AREA_COLS; c++) {
						if (c !== col && gameState.aiPlayArea[row][c]) {
							rowCards.push(gameState.aiPlayArea[row][c]);
						}
					}
					if (rowCards.length > 0) {
						// Bonus for placing in rows that already have cards
						score += rowCards.length * 20;
						// Analyze poker potential
						var suits = {};
						var values = {};
						rowCards.forEach(function (card) {
							suits[card.cardData.suit] = (suits[card.cardData.suit] || 0) + 1;
							values[card.cardData.value] = (values[card.cardData.value] || 0) + 1;
						});
						// Bonus for potential flush (same suit)
						for (var suit in suits) {
							if (suits[suit] >= 1) {
								// Even 1 card gives potential
								score += suits[suit] * 15;
							}
						}
						// Bonus for potential pairs/trips
						for (var value in values) {
							if (values[value] >= 1) {
								score += values[value] * 10;
							}
						}
					} else {
						// SMALL penalty instead of huge one for empty rows
						score -= 5; // Much smaller penalty
					}
				}
				// CENTER PREFERENCE
				var centerDistance = Math.abs(col - (PLAY_AREA_COLS - 1) / 2);
				score += (3 - centerDistance) * 2; // Smaller bonus
				if (score > bestScore) {
					bestScore = score;
					bestSlot = {
						row: row,
						col: col
					};
				}
			}
		}
		// FALLBACK: If no slot found with positive score, just return first empty slot
		if (!bestSlot) {
			for (var row = 0; row < PLAY_AREA_ROWS; row++) {
				for (var col = 0; col < PLAY_AREA_COLS; col++) {
					if (!gameState.aiPlayArea[row][col]) {
						return {
							row: row,
							col: col
						};
					}
				}
			}
		}
		return bestSlot;
	},
	evaluateSlotScore: function evaluateSlotScore(row, col) {
		var score = 0;
		var rowCards = [];
		var difficulty = getAIDifficultySettings(storage.battleRating);
		for (var c = 0; c < PLAY_AREA_COLS; c++) {
			var card = gameState.aiPlayArea[row][c];
			if (card) {
				rowCards.push(card);
			}
		}
		score += rowCards.length * 15;
		var currentRowDPS = this.calculateRowDamageOutput(row);
		if (rowCards.length >= 2) {
			var currentHandEval = evaluateRowHand(row, false);
			var potentialMultiplierImprovement = this.estimateHandMultiplierImprovement(rowCards);
			var potentialDPSImprovement = currentRowDPS * (potentialMultiplierImprovement - 1);
			score += potentialDPSImprovement * 0.1;
		}
		if (rowCards.length === 4) {
			score += 50;
		} else if (rowCards.length === 3) {
			score += 20;
		}
		score += (2 - Math.abs(col - 2)) * 1;
		return score;
	},
	estimateHandMultiplierImprovement: function estimateHandMultiplierImprovement(existingCards) {
		var suits = {};
		var values = {};
		existingCards.forEach(function (card) {
			var cardData = card.cardData;
			suits[cardData.suit] = (suits[cardData.suit] || 0) + 1;
			values[cardData.value] = (values[cardData.value] || 0) + 1;
		});
		var estimatedMultiplier = 1;
		for (var suit in suits) {
			if (suits[suit] >= 4) {
				estimatedMultiplier = Math.max(estimatedMultiplier, 2.5);
			} else if (suits[suit] >= 3) {
				estimatedMultiplier = Math.max(estimatedMultiplier, 2.0);
			}
		}
		var pairCount = 0;
		for (var value in values) {
			if (values[value] >= 2) {
				pairCount++;
			}
		}
		if (pairCount >= 2) {
			estimatedMultiplier = Math.max(estimatedMultiplier, 2.2);
		}
		return estimatedMultiplier;
	},
	applyAIHandBonuses: function applyAIHandBonuses() {
		for (var row = 0; row < PLAY_AREA_ROWS; row++) {
			var handEval = evaluateRowHand(row, false);
			var contributingCards = handEval.contributingCards || [];
			for (var col = 0; col < PLAY_AREA_COLS; col++) {
				var card = gameState.aiPlayArea[row][col];
				if (card) {
					card.handBonus = handEval.multiplier;
					card.calculateStats();
					card.redOutline.visible = handEval.strength > 1 && contributingCards.indexOf(card) !== -1;
				}
			}
		}
	},
	setupMods: function setupMods() {
		var playerModCount = 0;
		for (var suit in ModSystem.equippedMods) {
			if (ModSystem.equippedMods[suit]) {
				playerModCount++;
			}
		}
		var allMods = Object.keys(ModSystem.modData);
		var availableModsBySuit = {
			hearts: [],
			diamonds: [],
			clubs: [],
			spades: []
		};
		allMods.forEach(function (modId) {
			var suit = ModSystem.modData[modId].suit;
			if (suit && availableModsBySuit[suit]) {
				availableModsBySuit[suit].push(modId);
			}
		});
		ModSystem.aiEquippedMods = {
			hearts: null,
			diamonds: null,
			clubs: null,
			spades: null
		};
		var aiModCount = 0;
		var suits = ['hearts', 'diamonds', 'clubs', 'spades'];
		// Shuffle suits
		for (var i = suits.length - 1; i > 0; i--) {
			var j = Math.floor(Math.random() * (i + 1));
			var temp = suits[i];
			suits[i] = suits[j];
			suits[j] = temp;
		}
		for (var i = 0; i < suits.length; i++) {
			var suit = suits[i];
			if (aiModCount < playerModCount && availableModsBySuit[suit].length > 0) {
				var randomModForSuit = availableModsBySuit[suit][Math.floor(Math.random() * availableModsBySuit[suit].length)];
				ModSystem.aiEquippedMods[suit] = randomModForSuit;
				aiModCount++;
			}
		}
	},
	// New function for within-row optimization
	findBestRowArrangement: function findBestRowArrangement(row, cards) {
		if (cards.length < 2) {
			return null;
		}
		var currentHand = evaluateRowHand(row, false);
		var currentMultiplier = currentHand.multiplier;
		// Try different arrangements of the same cards
		// For now, implement a simple swap optimization
		var bestImprovement = 0;
		var bestArrangement = null;
		// Simple implementation: try centering cards for better poker potential
		if (cards.length <= 3) {
			var centerStart = Math.floor((PLAY_AREA_COLS - cards.length) / 2);
			var arrangement = [];
			for (var i = 0; i < PLAY_AREA_COLS; i++) {
				if (i >= centerStart && i < centerStart + cards.length) {
					arrangement[i] = cards[i - centerStart];
				} else {
					arrangement[i] = null;
				}
			}
			// This is a simplified version - full implementation would test all permutations
			return {
				improved: false,
				// Keep simple for now
				arrangement: arrangement
			};
		}
		return null;
	},
	implementRowArrangement: function implementRowArrangement(row, arrangement) {
		// Clear the row
		for (var col = 0; col < PLAY_AREA_COLS; col++) {
			gameState.aiPlayArea[row][col] = null;
		}
		// Implement new arrangement
		for (var col = 0; col < arrangement.arrangement.length; col++) {
			if (arrangement.arrangement[col]) {
				gameState.aiPlayArea[row][col] = arrangement.arrangement[col];
				var newPos = getSlotPosition(row, col, false);
				tween(arrangement.arrangement[col], {
					x: newPos.x,
					y: newPos.y
				}, {
					duration: 200,
					easing: tween.quadOut
				});
			}
		}
		this.applyAIHandBonuses();
	}
};
/**** 
* Input Handling
****/ 
game.down = function (x, y, obj) {
	// Only handle input during playing state
	if (currentGameState !== 'playing') {
		return;
	}
	// Check if clicking on a card in hand
	for (var i = 0; i < gameState.playerHand.length; i++) {
		var card = gameState.playerHand[i];
		if (card && Math.abs(x - card.x) < DEAL_SLOT_WIDTH / 2 && Math.abs(y - card.y) < DEAL_SLOT_HEIGHT / 2) {
			// Block dragging if card is locked
			if (card.isLocked) {
				createFloatingText('LOCKED!', card.x, card.y - 30, 0xff0000, 40);
				return;
			}
			selectedCard = card;
			isDragging = true;
			originalCardPosition = {
				area: 'hand',
				index: i
			};
			uiLayer.addChild(selectedCard);
			return;
		}
	}
	// Check if clicking on a card in play area
	for (var row = 0; row < PLAY_AREA_ROWS; row++) {
		for (var col = 0; col < PLAY_AREA_COLS; col++) {
			var card = gameState.playerPlayArea[row][col];
			if (card && Math.abs(x - card.x) < SLOT_WIDTH / 2 && Math.abs(y - card.y) < SLOT_HEIGHT / 2) {
				// Block dragging if card is locked
				if (card.isLocked) {
					createFloatingText('LOCKED!', card.x, card.y - 30, 0xff0000, 40);
					return;
				}
				selectedCard = card;
				isDragging = true;
				originalCardPosition = {
					area: 'player',
					row: row,
					col: col
				};
				// Remove from current position
				gameState.playerPlayArea[row][col] = null;
				gameLayer.addChild(selectedCard);
				return;
			}
		}
	}
};
game.move = function (x, y, obj) {
	// Only handle input during playing state
	if (currentGameState !== 'playing') {
		return;
	}
	if (isDragging && selectedCard) {
		selectedCard.x = x;
		selectedCard.y = y;
		// Highlight mergeable cards (but not locked ones)
		// Player's play area
		for (var row = 0; row < PLAY_AREA_ROWS; row++) {
			for (var col = 0; col < PLAY_AREA_COLS; col++) {
				var card = gameState.playerPlayArea[row][col];
				if (card) {
					// Only show green outline if card can merge AND is not locked
					card.greenOutline.visible = selectedCard.canMergeWith(card) && !card.isLocked;
				}
			}
		}
		// Player's hand
		for (var i = 0; i < gameState.playerHand.length; i++) {
			var card = gameState.playerHand[i];
			if (card && card !== selectedCard) {
				// Only show green outline if card can merge AND is not locked
				card.greenOutline.visible = selectedCard.canMergeWith(card) && !card.isLocked;
			}
		}
		// Switch to discard mode when dragging
		discardAreaGraphic.visible = false;
		refundButtonGraphic.visible = true;
		// Highlight discard area on hover
		var isOverDiscard = discardAreaContainer && x >= discardAreaContainer.x - DEAL_SLOT_WIDTH / 2 && x <= discardAreaContainer.x + DEAL_SLOT_WIDTH / 2 && y >= discardAreaContainer.y - DEAL_SLOT_HEIGHT / 2 && y <= discardAreaContainer.y + DEAL_SLOT_HEIGHT / 2;
		var chipRefund = Math.floor(gameState.dealCost / 2);
		discardText.setText('+' + formatNumberWithSuffix(chipRefund));
		if (isOverDiscard) {
			discardText.fill = 0xffd700; // Gold color
			refundButtonGraphic.alpha = 1.0;
		} else {
			refundButtonGraphic.alpha = 0.7;
			discardText.fill = 0x999999;
		}
	} else {
		// When not dragging, show as deal button
		discardAreaGraphic.visible = true;
		refundButtonGraphic.visible = false;
		updateUI();
	}
};
game.up = function (x, y, obj) {
	// Only handle input during playing state
	if (currentGameState !== 'playing') {
		return;
	}
	if (isDragging && selectedCard) {
		isDragging = false;
		discardAreaGraphic.visible = true;
		refundButtonGraphic.visible = false;
		// Clear all temporary green outlines
		for (var row = 0; row < PLAY_AREA_ROWS; row++) {
			for (var col = 0; col < PLAY_AREA_COLS; col++) {
				var card = gameState.playerPlayArea[row][col];
				if (card) {
					card.greenOutline.visible = false;
				}
			}
		}
		for (var i = 0; i < gameState.playerHand.length; i++) {
			var card = gameState.playerHand[i];
			if (card) {
				card.greenOutline.visible = false;
			}
		}
		// Reset to deal button mode
		updateUI();
		var targetSlot = getSlotFromPosition(x, y);
		if (targetSlot) {
			// Handle dropping card on discard area
			if (targetSlot.area === 'discard') {
				var chipRefund = Math.floor(gameState.dealCost / 2);
				gameState.playerChips += chipRefund;
				// Remove from original position data
				if (originalCardPosition.area === 'hand') {
					gameState.playerHand[originalCardPosition.index] = null;
				} else if (originalCardPosition.area === 'player') {
					// This is already null from game.down, so this is just for safety.
					gameState.playerPlayArea[originalCardPosition.row][originalCardPosition.col] = null;
				}
				// Remove card graphic from scene and memory
				if (selectedCard.parent) {
					selectedCard.parent.removeChild(selectedCard);
				}
				createFloatingText('+' + formatNumberWithSuffix(chipRefund) + ' Chips', selectedCard.x, selectedCard.y, 0xffd700);
				selectedCard = null;
				originalCardPosition = null;
				updateUI();
				// Recalculate bonuses if a card was removed from play area
				if (originalCardPosition && originalCardPosition.area === 'player') {
					applyHandBonuses();
				}
				return; // Exit early
			}
			if (targetSlot.area === 'player') {
				var existingCard = gameState.playerPlayArea[targetSlot.row][targetSlot.col];
				if (existingCard && selectedCard.canMergeWith(existingCard)) {
					// Block merging with locked cards
					if (existingCard.isLocked) {
						createFloatingText('Cannot merge with locked card!', existingCard.x, existingCard.y, 0xff0000, 40);
						returnCardToOriginalPosition();
						// Clear green outlines and reset UI
						for (var row = 0; row < PLAY_AREA_ROWS; row++) {
							for (var col = 0; col < PLAY_AREA_COLS; col++) {
								var card = gameState.playerPlayArea[row][col];
								if (card) {
									card.greenOutline.visible = false;
								}
							}
						}
						for (var i = 0; i < gameState.playerHand.length; i++) {
							var card = gameState.playerHand[i];
							if (card) {
								card.greenOutline.visible = false;
							}
						}
						selectedCard = null;
						originalCardPosition = null;
						updateUI();
						return;
					}
					// Merge in play area
					var oldLevel = existingCard.level;
					var mergedCard = selectedCard.mergeWith(existingCard);
					if (mergedCard) {
						gameLayer.removeChild(existingCard);
						var handIndex = gameState.playerHand.indexOf(selectedCard);
						if (handIndex !== -1) {
							uiLayer.removeChild(selectedCard);
							gameState.playerHand[handIndex] = null;
						} else {
							gameLayer.removeChild(selectedCard);
						}
						var pos = getSlotPosition(targetSlot.row, targetSlot.col, true);
						mergedCard.activate(pos.x, pos.y, true);
						gameLayer.addChild(mergedCard);
						gameState.playerPlayArea[targetSlot.row][targetSlot.col] = mergedCard;
						mergedCard.alpha = 0;
						mergedCard.scaleX = mergedCard.scaleY = 2;
						tween(mergedCard, {
							alpha: 1,
							scaleX: 1,
							scaleY: 1
						}, {
							duration: 300,
							easing: tween.elasticOut
						});
						LK.getSound('levelUp').play();
						createFloatingText('+Level Up!', mergedCard.x, mergedCard.y - 50, 0x00ff00, 60);
						var damageBefore = Math.floor(10 * Math.pow(1.6, oldLevel - 1));
						var fireRateBefore = Math.max(15, Math.floor(60 / Math.pow(1.2, oldLevel - 1)));
						var damageAfter = Math.floor(10 * Math.pow(1.6, mergedCard.level - 1));
						var fireRateAfter = Math.max(15, Math.floor(60 / Math.pow(1.2, mergedCard.level - 1)));
						var damageIncrease = damageBefore > 0 ? Math.round((damageAfter / damageBefore - 1) * 100) : 0;
						var fireRateIncrease = fireRateAfter > 0 && fireRateAfter < fireRateBefore ? Math.round((fireRateBefore / fireRateAfter - 1) * 100) : 0;
						var statText = "";
						if (damageBefore > 0) {
							var dmgMult = (damageAfter / damageBefore).toFixed(2);
							statText = "Dmg x" + dmgMult;
						}
						createFloatingText(statText, mergedCard.x, mergedCard.y + 55, 0x00ff00, 35);
					}
				} else if (!existingCard) {
					// Prevent Jokers from being played on the board directly. They can only merge.
					if (selectedCard.cardData.suit === 'joker') {
						createFloatingText('Jokers can only level up other cards.', selectedCard.x, selectedCard.y, 0xffcc00);
						returnCardToOriginalPosition();
					} else {
						// Place in empty slot
						var pos = getSlotPosition(targetSlot.row, targetSlot.col, true);
						selectedCard.activate(pos.x, pos.y, true);
						selectedCard.resetInvestment();
						var handIndex = gameState.playerHand.indexOf(selectedCard);
						if (handIndex !== -1) {
							uiLayer.removeChild(selectedCard);
							gameLayer.addChild(selectedCard);
							gameState.playerHand[handIndex] = null;
						}
						gameState.playerPlayArea[targetSlot.row][targetSlot.col] = selectedCard;
					}
				} else {
					// Prevent Jokers from being swapped onto the board.
					if (selectedCard.cardData.suit === 'joker') {
						createFloatingText('Jokers can only level up other cards.', selectedCard.x, selectedCard.y, 0xffcc00);
						returnCardToOriginalPosition();
					} else {
						// Card exists, but cannot merge: swap them with animation
						var swappedCard = gameState.playerPlayArea[targetSlot.row][targetSlot.col];
						// Determine target positions for animation
						var pos1 = getSlotPosition(targetSlot.row, targetSlot.col, true);
						var pos2;
						tween(selectedCard, {
							x: pos1.x,
							y: pos1.y
						}, {
							duration: 200,
							easing: tween.quadOut
						});
						// Update selectedCard state
						selectedCard.isInPlay = true;
						if (originalCardPosition.area === 'hand') {
							selectedCard.resetInvestment(); // Card moved from hand to play area
							gameState.playerHand[originalCardPosition.index] = null;
							uiLayer.removeChild(selectedCard);
							gameLayer.addChild(selectedCard);
						}
						gameState.playerPlayArea[targetSlot.row][targetSlot.col] = selectedCard;
						// Determine target for swappedCard and animate
						if (originalCardPosition.area === 'player') {
							pos2 = getSlotPosition(originalCardPosition.row, originalCardPosition.col, true);
							swappedCard.isInPlay = true;
							gameState.playerPlayArea[originalCardPosition.row][originalCardPosition.col] = swappedCard;
						} else {
							// original was hand, so swapped card goes to hand
							var origHandIndex = originalCardPosition.index;
							var handWidth = 5 * DEAL_SLOT_WIDTH + 4 * 30;
							var handStartX = (SCREEN_WIDTH - handWidth) / 2;
							pos2 = {
								x: handStartX + origHandIndex * DEAL_SLOT_WIDTH + origHandIndex * 30 + DEAL_SLOT_WIDTH / 2,
								y: PLAYER_DEAL_AREA_Y + DEAL_SLOT_HEIGHT / 2
							};
							swappedCard.isInPlay = false;
							gameLayer.removeChild(swappedCard);
							uiLayer.addChild(swappedCard);
							gameState.playerHand[origHandIndex] = swappedCard;
						}
						tween(swappedCard, {
							x: pos2.x,
							y: pos2.y
						}, {
							duration: 200,
							easing: tween.quadOut
						});
						selectedCard.calculateStats();
						swappedCard.calculateStats();
					}
				}
			} else if (targetSlot.area === 'hand') {
				var existingCard = gameState.playerHand[targetSlot.index];
				if (existingCard && existingCard !== selectedCard && selectedCard.canMergeWith(existingCard)) {
					// Block merging with locked cards
					if (existingCard.isLocked) {
						createFloatingText('Cannot merge with locked card!', existingCard.x, existingCard.y, 0xff0000, 40);
						returnCardToOriginalPosition();
						// Clear green outlines and reset UI
						for (var row = 0; row < PLAY_AREA_ROWS; row++) {
							for (var col = 0; col < PLAY_AREA_COLS; col++) {
								var card = gameState.playerPlayArea[row][col];
								if (card) {
									card.greenOutline.visible = false;
								}
							}
						}
						for (var i = 0; i < gameState.playerHand.length; i++) {
							var card = gameState.playerHand[i];
							if (card) {
								card.greenOutline.visible = false;
							}
						}
						selectedCard = null;
						originalCardPosition = null;
						updateUI();
						return;
					}
					// Merge in hand
					var oldLevel = existingCard.level;
					var mergedCard = selectedCard.mergeWith(existingCard);
					if (mergedCard) {
						// Remove old cards
						var handIndex1 = gameState.playerHand.indexOf(selectedCard);
						if (handIndex1 !== -1) {
							uiLayer.removeChild(selectedCard);
							gameState.playerHand[handIndex1] = null;
						} else {
							gameLayer.removeChild(selectedCard);
						}
						var handIndex2 = gameState.playerHand.indexOf(existingCard);
						if (handIndex2 !== -1) {
							uiLayer.removeChild(existingCard);
							gameState.playerHand[handIndex2] = null;
						}
						// Place merged card in hand
						var handWidth = 5 * DEAL_SLOT_WIDTH + 4 * 30; // 5 slots + 4 gaps of 30px
						var handStartX = (SCREEN_WIDTH - handWidth) / 2;
						var slotX = handStartX + targetSlot.index * DEAL_SLOT_WIDTH + targetSlot.index * 30 + DEAL_SLOT_WIDTH / 2;
						var slotY = PLAYER_DEAL_AREA_Y + DEAL_SLOT_HEIGHT / 2;
						mergedCard.activate(slotX, slotY, false, true);
						uiLayer.addChild(mergedCard);
						gameState.playerHand[targetSlot.index] = mergedCard;
						// Merge animation
						mergedCard.alpha = 0;
						mergedCard.scaleX = mergedCard.scaleY = 2;
						tween(mergedCard, {
							alpha: 1,
							scaleX: 1,
							scaleY: 1
						}, {
							duration: 300,
							easing: tween.elasticOut
						});
						LK.getSound('levelUp').play();
						createFloatingText('+Level Up!', mergedCard.x, mergedCard.y - 50, 0x00ff00, 60);
						var damageBefore = Math.floor(10 * Math.pow(1.6, oldLevel - 1));
						var fireRateBefore = Math.max(15, Math.floor(60 / Math.pow(1.2, oldLevel - 1)));
						var damageAfter = Math.floor(10 * Math.pow(1.6, mergedCard.level - 1));
						var fireRateAfter = Math.max(15, Math.floor(60 / Math.pow(1.2, mergedCard.level - 1)));
						var damageIncrease = damageBefore > 0 ? Math.round((damageAfter / damageBefore - 1) * 100) : 0;
						var fireRateIncrease = fireRateAfter > 0 && fireRateAfter < fireRateBefore ? Math.round((fireRateBefore / fireRateAfter - 1) * 100) : 0;
						var statText = "";
						if (damageBefore > 0) {
							var dmgMult = (damageAfter / damageBefore).toFixed(2);
							statText = "Dmg x" + dmgMult;
						}
						createFloatingText(statText, mergedCard.x, mergedCard.y + 55, 0x00ff00, 35);
					} else {
						returnCardToOriginalPosition();
					}
				} else if (existingCard && existingCard !== selectedCard) {
					// Cannot merge, so swap with animation
					var swappedCard = gameState.playerHand[targetSlot.index];
					// Get target positions
					var targetHandIndex = targetSlot.index;
					var handWidth1 = 5 * DEAL_SLOT_WIDTH + 4 * 30;
					var handStartX1 = (SCREEN_WIDTH - handWidth1) / 2;
					var pos1 = {
						x: handStartX1 + targetHandIndex * DEAL_SLOT_WIDTH + targetHandIndex * 30 + DEAL_SLOT_WIDTH / 2,
						y: PLAYER_DEAL_AREA_Y + DEAL_SLOT_HEIGHT / 2
					};
					var pos2;
					// Animate selectedCard
					tween(selectedCard, {
						x: pos1.x,
						y: pos1.y
					}, {
						duration: 200,
						easing: tween.quadOut
					});
					// Update selectedCard state
					selectedCard.isInPlay = false; // It's going to a hand slot
					if (originalCardPosition.area === 'player') {
						selectedCard.resetInvestment(); // Card moved from play area to hand - should not happen here, but for safety. Investment stops due to isInPlay=false
						gameLayer.removeChild(selectedCard);
						uiLayer.addChild(selectedCard);
					} else {
						// This is a hand-to-hand swap, timer should not be reset.
						gameState.playerHand[originalCardPosition.index] = null;
					}
					gameState.playerHand[targetHandIndex] = selectedCard;
					// Update swappedCard state
					if (originalCardPosition.area === 'player') {
						pos2 = getSlotPosition(originalCardPosition.row, originalCardPosition.col, true);
						swappedCard.isInPlay = true;
						uiLayer.removeChild(swappedCard);
						gameLayer.addChild(swappedCard);
						gameState.playerPlayArea[originalCardPosition.row][originalCardPosition.col] = swappedCard;
					} else {
						// original was hand
						var origHandIndex = originalCardPosition.index;
						var handWidth2 = 5 * DEAL_SLOT_WIDTH + 4 * 30;
						var handStartX2 = (SCREEN_WIDTH - handWidth2) / 2;
						pos2 = {
							x: handStartX2 + origHandIndex * DEAL_SLOT_WIDTH + origHandIndex * 30 + DEAL_SLOT_WIDTH / 2,
							y: PLAYER_DEAL_AREA_Y + DEAL_SLOT_HEIGHT / 2
						};
						swappedCard.isInPlay = false;
						gameState.playerHand[origHandIndex] = swappedCard;
					}
					tween(swappedCard, {
						x: pos2.x,
						y: pos2.y
					}, {
						duration: 200,
						easing: tween.quadOut
					});
					selectedCard.calculateStats();
					swappedCard.calculateStats();
				} else {
					returnCardToOriginalPosition();
				}
			}
		} else {
			returnCardToOriginalPosition();
		}
		selectedCard = null;
		originalCardPosition = null;
		applyHandBonuses();
	}
};
function returnCardToOriginalPosition() {
	if (!selectedCard || !originalCardPosition) {
		return;
	}
	if (originalCardPosition.area === 'hand') {
		// Return to hand slot
		var handIndex = originalCardPosition.index;
		var handWidth = 5 * DEAL_SLOT_WIDTH + 4 * 30; // 5 slots + 4 gaps of 30px
		var handStartX = (SCREEN_WIDTH - handWidth) / 2;
		var slotX = handStartX + handIndex * DEAL_SLOT_WIDTH + handIndex * 30 + DEAL_SLOT_WIDTH / 2;
		var slotY = PLAYER_DEAL_AREA_Y + DEAL_SLOT_HEIGHT / 2;
		selectedCard.x = slotX;
		selectedCard.y = slotY;
		gameState.playerHand[handIndex] = selectedCard;
	} else if (originalCardPosition.area === 'player') {
		// Return to play area slot
		var pos = getSlotPosition(originalCardPosition.row, originalCardPosition.col, true);
		selectedCard.x = pos.x;
		selectedCard.y = pos.y;
		gameState.playerPlayArea[originalCardPosition.row][originalCardPosition.col] = selectedCard;
	}
}
function createOutlinedText(text, options, outlineColor, outlineThickness) {
	var container = new Container();
	// Create the outline by placing shadow texts in 8 directions
	var offsets = [[-outlineThickness, -outlineThickness],
	// top-left
	[0, -outlineThickness],
	// top
	[outlineThickness, -outlineThickness],
	// top-right
	[outlineThickness, 0],
	// right
	[outlineThickness, outlineThickness],
	// bottom-right
	[0, outlineThickness],
	// bottom
	[-outlineThickness, outlineThickness],
	// bottom-left
	[-outlineThickness, 0] // left
	];
	// Create outline shadows
	offsets.forEach(function (offset) {
		var shadowText = new Text2(text, {
			size: options.size,
			fill: outlineColor,
			weight: options.weight
			// Don't use stroke properties for shadows
		});
		shadowText.anchor.set(options.anchor ? options.anchor[0] : 0.5, options.anchor ? options.anchor[1] : 0.5);
		shadowText.x = offset[0];
		shadowText.y = offset[1];
		container.addChild(shadowText);
	});
	// Create the main text on top
	var mainText = new Text2(text, {
		size: options.size,
		fill: options.fill,
		weight: options.weight
	});
	mainText.anchor.set(options.anchor ? options.anchor[0] : 0.5, options.anchor ? options.anchor[1] : 0.5);
	container.addChild(mainText);
	// Add a setText method to the container for easy updates
	container.setText = function (newText) {
		// Update all shadow texts
		for (var i = 0; i < offsets.length; i++) {
			container.children[i].setText(newText);
		}
		// Update main text
		mainText.setText(newText);
	};
	return container;
}
function createFloatingText(text, x, y, color, size) {
	var textOptions = {
		size: size || 40,
		fill: color || 0xffffff,
		weight: 800,
		anchor: [0.5, 0.5]
	};
	var outlineColor = 0x000000;
	var outlineThickness = 3;
	// Add black outline for green level up text
	if (color === 0x00ff00) {
		outlineThickness = 6;
		textOptions.size = (size || 40) * 1.5; // Make it smaller
	}
	// Make poker damage text white with black outline, bigger, and animate faster
	if (color === 0xff0000 && text.startsWith('-')) {
		textOptions.fill = 0xffffff; // White color
		outlineColor = 0x000000; // Black outline
		outlineThickness = 6; // Black outline thickness
		textOptions.size = (size || 40) * 1.5; // Make it 50% bigger (increased from 30%)
	}
	var floatingText = createOutlinedText(text, textOptions, outlineColor, outlineThickness);
	floatingText.x = x;
	floatingText.y = y;
	floatingText.alpha = 1;
	uiLayer.addChild(floatingText);
	// Use larger animation for important messages
	var animationDistance = size && size > 40 ? 120 : 80;
	var animationDuration = size && size > 40 ? 2000 : 1500;
	// Make poker damage text animate faster
	if (color === 0xff0000 && text.startsWith('-')) {
		animationDuration = 800; // Much faster animation
	}
	// Level up text fades faster now
	if (color === 0x00ff00) {
		animationDuration = 1000;
	}
	// Split animation into two parts
	var floatDuration = animationDuration * 0.6; // 60% of time for floating up
	var fadeDuration = animationDuration * 0.4; // 40% of time for fading out
	// First part: Float upwards with no alpha change
	tween(floatingText, {
		y: y - animationDistance * 0.7 // Float up 70% of the distance
	}, {
		duration: floatDuration,
		easing: tween.quadOut,
		onFinish: function onFinish() {
			// Second part: Continue floating while fading out
			tween(floatingText, {
				y: y - animationDistance,
				alpha: 0
			}, {
				duration: fadeDuration,
				easing: tween.quadOut,
				onFinish: function onFinish() {
					uiLayer.removeChild(floatingText);
				}
			});
		}
	});
}
function createExplosion(x, y, color) {
	var numParticles = 5;
	for (var i = 0; i < numParticles; i++) {
		var particle = LK.getAsset('explosionParticle', {
			anchorX: 0.5,
			anchorY: 0.5
		});
		particle.x = x;
		particle.y = y;
		particle.tint = color;
		particle.scale.set(0.5 + Math.random() * 0.5);
		var angle = Math.random() * Math.PI * 2;
		var distance = Math.random() * 50 + 20;
		var duration = 500 + Math.random() * 500;
		var targetX = x + Math.cos(angle) * distance;
		var targetY = y + Math.sin(angle) * distance;
		gameLayer.addChild(particle);
		tween(particle, {
			x: targetX,
			y: targetY,
			alpha: 0
		}, {
			duration: duration,
			easing: tween.quadOut,
			onFinish: function (p) {
				return function () {
					if (p.parent) {
						p.parent.removeChild(p);
					}
				};
			}(particle)
		});
	}
}
/**** 
* Main Game Loop
****/ 
game.update = function () {
	// Update tutorial system
	if (TutorialSystem.isActive) {
		TutorialSystem.update();
	}
	// Only run game logic when in playing state
	if (currentGameState !== 'playing') {
		if (currentGameState === 'start' && backgroundSuits.length > 0) {
			var speed = 0.5;
			var spacing = 400;
			// Calculate pattern dimensions
			var numCols = Math.ceil(SCREEN_WIDTH / spacing) + 3;
			var numRows = Math.ceil(SCREEN_HEIGHT / spacing) + 3;
			var patternWidth = numCols * spacing;
			var patternHeight = numRows * spacing;
			for (var i = 0; i < backgroundSuits.length; i++) {
				var suit = backgroundSuits[i];
				// Move diagonally
				suit.x += speed;
				suit.y += speed;
				// Wrap horizontally
				if (suit.x > SCREEN_WIDTH + spacing * 1.5) {
					suit.x -= patternWidth;
				}
				// Wrap vertically
				if (suit.y > SCREEN_HEIGHT + spacing * 1.5) {
					suit.y -= patternHeight;
				}
			}
		}
		return;
	}
	if (!gameReady) {
		return;
	}
	// Update wave spawning system
	WaveSystem.update();
	// Update active chips
	for (var i = activePlayerChips.length - 1; i >= 0; i--) {
		activePlayerChips[i].update();
	}
	for (var i = activeAIChips.length - 1; i >= 0; i--) {
		activeAIChips[i].update();
	}
	// Tutorial Assistance: If an enemy on the player's side gets halfway, destroy it.
	if (TutorialSystem.isActive) {
		var assistancePathThreshold = 50; // Halfway down the path
		for (var i = activePlayerChips.length - 1; i >= 0; i--) {
			var chip = activePlayerChips[i];
			if (chip.pathProgress > assistancePathThreshold) {
				if (!TutorialSystem.assistanceMessageShown) {
					TutorialSystem.assistanceMessageShown = true;
					var message = "It looks like you could use some help! I've taken care of that enemy for you.\n\nThis helping hand is only available in the tutorial. Try adding more cards, merging them, and aiming for better poker hands to get stronger!";
					TutorialSystem.showMessage(message, null, function () {
						TutorialSystem.clearMessage();
					});
				}
				// Instantly destroy the chip to assist the player, preventing them from losing in the tutorial.
				chip.takeDamage(chip.health * 2);
			}
		}
	}
	// Update active mines
	for (var i = activeMines.length - 1; i >= 0; i--) {
		if (activeMines[i]) {
			activeMines[i].update();
		}
	}
	// Update active bullets
	for (var i = activeBullets.length - 1; i >= 0; i--) {
		activeBullets[i].update();
	}
	// Update cards in play
	for (var row = 0; row < PLAY_AREA_ROWS; row++) {
		for (var col = 0; col < PLAY_AREA_COLS; col++) {
			if (gameState.playerPlayArea[row][col]) {
				gameState.playerPlayArea[row][col].update();
			}
			if (gameState.aiPlayArea[row][col]) {
				gameState.aiPlayArea[row][col].update();
			}
		}
	}
	// Update AI
	AISystem.update();
	// Check win/lose conditions
	// Update life displays
	while (gameState.playerLives < lastPlayerLives) {
		lastPlayerLives--;
		var heartToFade = playerLifeHearts[lastPlayerLives];
		if (heartToFade) {
			tween(heartToFade, {
				alpha: 0.2
			}, {
				duration: 500
			});
		}
	}
	while (gameState.aiLives < lastAiLives) {
		lastAiLives--;
		var heartToFade = aiLifeHearts[lastAiLives];
		if (heartToFade) {
			tween(heartToFade, {
				alpha: 0.2
			}, {
				duration: 500
			});
		}
	}
	if (gameMode === 'coop') {
		if (gameState.playerLives <= 0) {
			showCoopResultsScreen();
		}
	} else {
		if (gameState.playerLives <= 0) {
			showGameOver(false);
		} else if (gameState.aiLives <= 0) {
			showGameOver(true);
		}
	}
	updateUI();
};
/**** 
* Boss System
****/ 
var BossSystem = {
	bossTypes: [{
		id: 'scramble',
		name: 'Scramble Boss',
		description: 'Randomizes your cards',
		chipAsset: 'bossChipScramble'
	}, {
		id: 'lock',
		name: 'Lock Boss',
		description: 'Locks your cards',
		chipAsset: 'bossChipLock'
	}, {
		id: 'snake',
		name: 'Snake Boss',
		description: 'Creates a train of segments',
		chipAsset: 'bossChipRain'
	}, {
		id: 'immune',
		name: 'Immune Boss',
		description: 'Cycles through suit immunities',
		chipAsset: 'bossChipImmune'
	}, {
		id: 'speed',
		name: 'Speed Boss',
		description: 'Accelerates over time',
		chipAsset: 'bossChipSpeed'
	}],
	// NEW: Store boss selections for future waves
	selectedBosses: {},
	// Will store: { 10: bossType, 20: bossType, etc. }
	currentBossType: null,
	rouletteContainer: null,
	// NEW: Get the next main boss wave number
	getNextBossWave: function getNextBossWave() {
		var currentWave = WaveSystem.waveNumber;
		// Find the next boss wave (either mini-boss at x5 or main boss at x0)
		var nextBossWave;
		if (currentWave % 10 === 0) {
			// Just finished a main boss, next boss is at +5 (mini-boss)
			nextBossWave = currentWave + 5;
		} else if (currentWave % 10 === 5) {
			// Just finished a mini-boss, next boss is at +5 (main boss)
			nextBossWave = currentWave + 5;
		} else {
			// Find next boss wave (either mini or main)
			var remainder = currentWave % 10;
			if (remainder < 5) {
				nextBossWave = currentWave + (5 - remainder); // Next mini-boss
			} else {
				nextBossWave = currentWave + (10 - remainder); // Next main boss
			}
		}
		return nextBossWave;
	},
	selectRandomBossType: function selectRandomBossType() {
		return this.bossTypes[Math.floor(Math.random() * this.bossTypes.length)];
	},
	// MODIFIED: Now stores boss for future wave
	showBossRoulette: function showBossRoulette(callback) {
		// ADD THIS LINE - Play roulette sound when animation starts
		LK.getSound('roulette').play();
		// Pause the game during roulette
		var wasGameReady = typeof gameReady !== "undefined" ? gameReady : false;
		gameReady = false;
		// Play roulette sound effect at the start of the animation
		LK.getSound('roulette').play();
		var nextBossWave = this.getNextBossWave();
		// Determine if it's a mini-boss or main boss
		var isMiniBoss = nextBossWave % 10 === 5;
		var bossTypeText = isMiniBoss ? "MINI-BOSS" : "BOSS";
		this.rouletteContainer = new Container();
		uiLayer.addChild(this.rouletteContainer);
		// Dark overlay
		var bg = LK.getAsset('card', {
			width: SCREEN_WIDTH,
			height: SCREEN_HEIGHT,
			anchorX: 0,
			anchorY: 0
		});
		bg.tint = 0x000000;
		bg.alpha = 0.8;
		this.rouletteContainer.addChild(bg);
		// Title - show whether it's mini-boss or main boss
		var title = new Text2(bossTypeText + ' INCOMING', {
			size: 120,
			fill: isMiniBoss ? 0xff8800 : 0xff0000,
			// Orange for mini-boss, red for main boss
			weight: 'bold',
			stroke: 0x000000,
			strokeThickness: 6
		});
		title.anchor.set(0.5, 0.5);
		title.x = SCREEN_WIDTH / 2;
		title.y = 400;
		this.rouletteContainer.addChild(title);
		// Horizontal scrolling container
		var scrollContainer = new Container();
		scrollContainer.x = 0;
		scrollContainer.y = SCREEN_HEIGHT / 2;
		this.rouletteContainer.addChild(scrollContainer);
		// Create a long row of boss chips
		var chipSpacing = 300;
		var totalChips = 50;
		var bossChips = [];
		// Determine which boss will be selected
		var finalBossType = this.selectRandomBossType();
		var finalIndex = this.bossTypes.indexOf(finalBossType);
		// Calculate positioning
		var centerX = SCREEN_WIDTH / 2;
		var finalChipIndex = Math.floor(totalChips * 0.7);
		// Create the scrolling chips
		for (var i = 0; i < totalChips; i++) {
			var chipContainer = new Container();
			chipContainer.x = i * chipSpacing;
			chipContainer.y = 0;
			scrollContainer.addChild(chipContainer);
			// Determine which boss type this chip represents
			var bossTypeIndex;
			if (i === finalChipIndex) {
				bossTypeIndex = finalIndex;
			} else {
				bossTypeIndex = i % this.bossTypes.length; // Sequential repeating order instead of random
			}
			var bossType = this.bossTypes[bossTypeIndex];
			// Boss chip graphic
			var chip = LK.getAsset(bossType.chipAsset, {
				anchorX: 0.5,
				anchorY: 0.5
			});
			chip.scale.set(2);
			chipContainer.addChild(chip);
			// Store reference to the final chip
			if (i === finalChipIndex) {
				chipContainer.isFinalChip = true;
				chipContainer.bossType = bossType;
			}
			bossChips.push(chipContainer);
		}
		// Start the container off-screen to the left
		scrollContainer.x = -SCREEN_WIDTH;
		// Calculate final position so the selected chip ends up in center
		var finalScrollX = centerX - finalChipIndex * chipSpacing;
		// Animate the scrolling
		var scrollDuration = 1500;
		var self = this;
		tween(scrollContainer, {
			x: finalScrollX
		}, {
			duration: scrollDuration,
			easing: tween.quadOut,
			onFinish: function onFinish() {
				// Find the final chip
				var selectedChip = null;
				for (var i = 0; i < bossChips.length; i++) {
					if (bossChips[i].isFinalChip) {
						selectedChip = bossChips[i];
						break;
					}
				}
				if (selectedChip) {
					// Fade out all other chips
					for (var i = 0; i < bossChips.length; i++) {
						if (!bossChips[i].isFinalChip) {
							tween(bossChips[i], {
								alpha: 0
							}, {
								duration: 500
							});
						}
					}
					// Scale up and highlight the selected chip
					var selectedBossChip = selectedChip.children[0];
					LK.getSound('levelUp').play();
					tween(selectedChip, {
						scaleX: 2.0,
						// Scale up more dramatically
						scaleY: 2.0
					}, {
						duration: 800,
						easing: tween.elasticOut,
						onFinish: function onFinish() {
							// Change title to show wave number and type
							title.setText('WAVE ' + nextBossWave + ' ' + bossTypeText);
							title.fill = 0xffff00; // Change to yellow
							// Add the boss name text below the chip
							var nameText = new Text2(selectedChip.bossType.name.toUpperCase(), {
								size: 100,
								fill: 0xff0000,
								weight: 'bold',
								stroke: 0x000000,
								strokeThickness: 6
							});
							nameText.anchor.set(0.5, 0.5);
							nameText.y = 200;
							nameText.alpha = 0;
							selectedChip.addChild(nameText);
							// Add description text
							var descText = new Text2(selectedChip.bossType.description, {
								size: 60,
								fill: 0xffffff,
								weight: 'bold',
								stroke: 0x000000,
								strokeThickness: 4
							});
							descText.anchor.set(0.5, 0.5);
							descText.y = 320;
							descText.alpha = 0;
							selectedChip.addChild(descText);
							// Fade in the texts
							tween(nameText, {
								alpha: 1
							}, {
								duration: 500
							});
							tween(descText, {
								alpha: 1
							}, {
								duration: 500,
								delay: 200,
								onFinish: function onFinish() {
									// Store the selected boss
									self.selectedBosses[nextBossWave] = finalBossType;
									self.currentBossType = finalBossType;
									// Wait then fade out and continue
									LK.setTimeout(function () {
										tween(self.rouletteContainer, {
											alpha: 0
										}, {
											duration: 500,
											onFinish: function onFinish() {
												if (self.rouletteContainer && self.rouletteContainer.parent) {
													self.rouletteContainer.parent.removeChild(self.rouletteContainer);
												}
												self.rouletteContainer = null;
												// Restore game state and call the callback
												gameReady = wasGameReady;
												callback();
											}
										});
									}, 2000);
								}
							});
						}
					});
				}
			}
		});
	},
	/*
	showBossSelection: function showBossSelection(bossType, waveNumber, callback) {
		// This function is no longer needed
	}
	*/ 
	// NEW: Get the boss type for a specific wave
	getBossTypeForWave: function getBossTypeForWave(waveNumber) {
		return this.selectedBosses[waveNumber] || null;
	}
};
/**** 
* Game Over
****/ 
function resetGameAndReturnToMenu() {
	// This function now encapsulates all the logic to reset the game to its initial state.
	// 1. Remove all dynamically created game objects from the stage.
	[].concat(_toConsumableArray(activePlayerChips), _toConsumableArray(activeAIChips), _toConsumableArray(activeBullets), _toConsumableArray(activeMines)).forEach(function (obj) {
		if (obj.parent) {
			obj.parent.removeChild(obj);
		}
	});
	for (var r = 0; r < PLAY_AREA_ROWS; r++) {
		for (var c = 0; c < PLAY_AREA_COLS; c++) {
			var pCard = gameState.playerPlayArea[r][c];
			if (pCard && pCard.parent) {
				pCard.parent.removeChild(pCard);
			}
			var aCard = gameState.aiPlayArea[r][c];
			if (aCard && aCard.parent) {
				aCard.parent.removeChild(aCard);
			}
		}
	}
	gameState.playerHand.forEach(function (card) {
		if (card && card.parent) {
			card.parent.removeChild(card);
		}
	});
	playerLifeHearts.forEach(function (h) {
		if (h.parent) {
			h.parent.removeChild(h);
		}
	});
	aiLifeHearts.forEach(function (h) {
		if (h.parent) {
			h.parent.removeChild(h);
		}
	});
	playerHandNameTexts.forEach(function (t) {
		if (t && t.parent) {
			t.parent.removeChild(t);
		}
	});
	if (opponentNameText && opponentNameText.parent) {
		opponentNameText.parent.removeChild(opponentNameText);
	}
	if (playerNameText && playerNameText.parent) {
		playerNameText.parent.removeChild(playerNameText);
	}
	slotIndicators.forEach(function (indicator) {
		if (indicator.parent) {
			indicator.parent.removeChild(indicator);
		}
	});
	slotIndicators = [];
	// 2. Clear all tracking arrays.
	activePlayerChips = [];
	activeAIChips = [];
	activeBullets = [];
	activeMines = [];
	playerLifeHearts = [];
	aiLifeHearts = [];
	playerHandNameTexts = [];
	opponentNameText = null;
	playerNameText = null;
	// 3. Reset game state variables.
	gameState.playerChips = 200;
	gameState.aiChips = 200;
	gameState.playerLives = 3;
	gameState.aiLives = 3;
	gameState.isPlayerTurn = true;
	gameState.dealCost = 25; // Reset to starting cost of 25
	gameState.dealCount = 0; // Reset to starting count
	gameState.playerDeck = [];
	gameState.playerHand = [];
	gameState.playerPlayArea = [];
	gameState.aiDeck = [];
	gameState.aiPlayArea = [];
	// 4. Reset game systems.
	WaveSystem.waveNumber = 1;
	WaveSystem.waveTimer = 0;
	WaveSystem.bossSpawned = false;
	WaveSystem.playerBossDefeated = false;
	WaveSystem.aiBossDefeated = false;
	AISystem.thinkTimer = 0;
	// Add these lines to reset boss system:
	BossSystem.selectedBosses = {};
	BossSystem.currentBossType = null;
	if (BossSystem.rouletteContainer && BossSystem.rouletteContainer.parent) {
		BossSystem.rouletteContainer.parent.removeChild(BossSystem.rouletteContainer);
		BossSystem.rouletteContainer = null;
	}
	// 5. Reset other global variables.
	lastPlayerLives = 0;
	lastAiLives = 0;
	selectedCard = null;
	isDragging = false;
	originalCardPosition = null;
	gameReady = false;
	// 6. Hide persistent UI.
	gameElements.forEach(function (el) {
		el.visible = false;
	});
	background.visible = false;
	coopBackground.visible = false;
	// 7. Return to the main menu.
	createStartScreen(true);
}
function showResultsScreen() {
	var resultsContainer = new Container();
	uiLayer.addChild(resultsContainer);
	// Dark overlay
	var bg = LK.getAsset('card', {
		width: SCREEN_WIDTH,
		height: SCREEN_HEIGHT,
		anchorX: 0,
		anchorY: 0
	});
	bg.tint = 0x000000;
	bg.alpha = 0.7;
	resultsContainer.addChild(bg);
	var title = new Text2('VICTORY!', {
		size: 180,
		fill: 0xffd700,
		weight: 'bold',
		stroke: 0x000000,
		strokeThickness: 10
	});
	title.anchor.set(0.5, 0.5);
	title.x = SCREEN_WIDTH / 2;
	title.y = 300;
	resultsContainer.addChild(title);
	// Calculate Battle Rating
	var oldRating = storage.battleRating;
	var waveBonus = (WaveSystem.waveNumber - 1) * 5;
	var livesBonus = (gameState.playerLives - gameState.aiLives) * 10;
	var winBonus = 30;
	var ratingChange = waveBonus + livesBonus + winBonus;
	ratingChange = Math.max(5, ratingChange); // Minimum 5 rating gain on win
	var newRating = oldRating + ratingChange;
	storage.battleRating = newRating;
	// Display Rating Calculation
	var yPos = 600;
	var yStep = 120;
	var ySubStep = 90;
	var oldRatingText = new Text2('Previous Rating: ' + oldRating, {
		size: 80,
		fill: 0xffffff,
		weight: 'bold'
	});
	oldRatingText.anchor.set(0.5, 0.5);
	oldRatingText.x = SCREEN_WIDTH / 2;
	oldRatingText.y = yPos;
	resultsContainer.addChild(oldRatingText);
	yPos += yStep;
	var waveBonusText = new Text2('Wave Bonus (Wave ' + WaveSystem.waveNumber + '): +' + waveBonus, {
		size: 70,
		fill: 0x88ff88,
		weight: 'normal'
	});
	waveBonusText.anchor.set(0.5, 0.5);
	waveBonusText.x = SCREEN_WIDTH / 2;
	waveBonusText.y = yPos;
	resultsContainer.addChild(waveBonusText);
	yPos += ySubStep;
	var livesBonusText;
	if (livesBonus >= 0) {
		livesBonusText = new Text2('Performance Bonus: +' + livesBonus, {
			size: 70,
			fill: 0x88ff88,
			weight: 'normal'
		});
	} else {
		livesBonusText = new Text2('Performance Bonus: ' + livesBonus, {
			size: 70,
			fill: 0xff8888,
			weight: 'normal'
		});
	}
	livesBonusText.anchor.set(0.5, 0.5);
	livesBonusText.x = SCREEN_WIDTH / 2;
	livesBonusText.y = yPos;
	resultsContainer.addChild(livesBonusText);
	yPos += ySubStep;
	var winBonusText = new Text2('Victory Bonus: +' + winBonus, {
		size: 70,
		fill: 0x88ff88,
		weight: 'normal'
	});
	winBonusText.anchor.set(0.5, 0.5);
	winBonusText.x = SCREEN_WIDTH / 2;
	winBonusText.y = yPos;
	resultsContainer.addChild(winBonusText);
	yPos += yStep + 20;
	var lineBreak = LK.getAsset('lineBreak', {
		anchorX: 0.5,
		anchorY: 0.5
	});
	lineBreak.x = SCREEN_WIDTH / 2;
	lineBreak.y = yPos;
	lineBreak.scale.set(0.8);
	resultsContainer.addChild(lineBreak);
	yPos += yStep;
	var newRatingText = new Text2('New Rating: ' + newRating, {
		size: 100,
		fill: 0xffffff,
		weight: 'bold'
	});
	newRatingText.anchor.set(0.5, 0.5);
	var battleRatingIcon = LK.getAsset('battleRatingIcon', {
		anchorX: 0.5,
		anchorY: 0.5,
		scaleX: 0.8,
		scaleY: 0.8
	});
	var totalWidth = battleRatingIcon.width + 15 + newRatingText.width;
	battleRatingIcon.x = SCREEN_WIDTH / 2 - totalWidth / 2 + battleRatingIcon.width / 2;
	battleRatingIcon.y = yPos;
	newRatingText.x = battleRatingIcon.x + battleRatingIcon.width / 2 + 15 + newRatingText.width / 2;
	newRatingText.y = yPos;
	resultsContainer.addChild(battleRatingIcon);
	resultsContainer.addChild(newRatingText);
	// Create chest container
	var chestContainer = new Container();
	chestContainer.x = SCREEN_WIDTH / 2;
	chestContainer.y = 1600;
	resultsContainer.addChild(chestContainer);
	// Add small chest
	var chest = LK.getAsset('smallChest', {
		anchorX: 0.5,
		anchorY: 0.5
	});
	chest.scale.set(0.01);
	chestContainer.addChild(chest);
	// Tap to open text
	var tapToOpenText = new Text2('Tap to open', {
		size: 60,
		fill: 0xffffff,
		weight: 'bold',
		stroke: 0x000000,
		strokeThickness: 4
	});
	tapToOpenText.anchor.set(0.5, 0.5);
	tapToOpenText.y = 120;
	tapToOpenText.visible = false;
	chestContainer.addChild(tapToOpenText);
	// Make chest interactive
	chestContainer.interactive = true;
	chestContainer.hitArea = new Rectangle(-150, -150, 300, 300);
	var chestOpened = false;
	var moneyReward = 0;
	// Animate chest in with bounce
	tween(chest, {
		scaleX: 1.5,
		scaleY: 1.5
	}, {
		duration: 800,
		easing: tween.elasticOut,
		onFinish: function onFinish() {
			tapToOpenText.visible = true;
			// Pulse animation for tap to open text
			function pulseText() {
				if (!tapToOpenText.parent || chestOpened) {
					return;
				}
				tween(tapToOpenText, {
					scaleX: 1.1,
					scaleY: 1.1
				}, {
					duration: 600,
					easing: tween.easeInOut,
					onFinish: function onFinish() {
						if (!tapToOpenText.parent || chestOpened) {
							return;
						}
						tween(tapToOpenText, {
							scaleX: 1,
							scaleY: 1
						}, {
							duration: 600,
							easing: tween.easeInOut,
							onFinish: pulseText
						});
					}
				});
			}
			pulseText();
		}
	});
	chestContainer.down = function () {
		if (chestOpened) {
			return;
		}
		chestOpened = true;
		tapToOpenText.visible = false;
		// Wiggle animation
		tween(chest, {
			rotation: -0.1
		}, {
			duration: 100,
			easing: tween.linear,
			onFinish: function onFinish() {
				tween(chest, {
					rotation: 0.1
				}, {
					duration: 100,
					easing: tween.linear,
					onFinish: function onFinish() {
						tween(chest, {
							rotation: 0
						}, {
							duration: 100,
							easing: tween.linear,
							onFinish: function onFinish() {
								// Flash screen white
								LK.effects.flashScreen(0xffffff, 300);
								// Replace with open chest
								chestContainer.removeChild(chest);
								var openChest = LK.getAsset('smallChestOpen', {
									anchorX: 0.5,
									anchorY: 0.5
								});
								openChest.scale.set(1.5);
								chestContainer.addChild(openChest);
								// Generate random money reward
								moneyReward = Math.floor(Math.random() * 151) + 100; // 100-250
								var startMoney = storage.money;
								var targetMoney = startMoney + moneyReward;
								// Money text animation
								var moneyText = new Text2('$' + moneyReward, {
									size: 150,
									fill: 0xffffff,
									weight: 'bold',
									stroke: 0x000000,
									strokeThickness: 8
								});
								moneyText.anchor.set(0.5, 0.5);
								moneyText.y = -50;
								moneyText.scale.set(0.1);
								moneyText.alpha = 0;
								chestContainer.addChild(moneyText);
								// Animate scale property directly to avoid potential proxy issues with Text2 objects
								tween(moneyText.scale, {
									x: 1,
									y: 1
								}, {
									duration: 500,
									easing: tween.backOut
								});
								// Animate other properties on the text object itself
								tween(moneyText, {
									alpha: 1,
									y: -100
								}, {
									duration: 500,
									easing: tween.backOut,
									onFinish: function onFinish() {
										// Rolling number animation
										var rollDuration = 1000;
										var startTime = Date.now();
										var rollInterval = LK.setInterval(function () {
											var elapsed = Date.now() - startTime;
											var progress = Math.min(elapsed / rollDuration, 1);
											var easedProgress = 1 - Math.pow(1 - progress, 3); // Cubic ease out
											var currentValue = Math.floor(startMoney + moneyReward * easedProgress);
											storage.money = currentValue;
											if (progress >= 1) {
												LK.clearInterval(rollInterval);
												storage.money = targetMoney;
												// Show tap to continue
												var tapToContinueText = new Text2('Tap to continue', {
													size: 70,
													fill: 0x000000,
													weight: 'bold'
												});
												tapToContinueText.anchor.set(0.5, 0.5);
												tapToContinueText.y = 200;
												chestContainer.addChild(tapToContinueText);
												// Update chest interaction
												chestContainer.down = function () {
													tween(resultsContainer, {
														alpha: 0
													}, {
														duration: 300,
														onFinish: function onFinish() {
															if (resultsContainer.parent) {
																resultsContainer.parent.removeChild(resultsContainer);
															}
															resetGameAndReturnToMenu();
														}
													});
												};
											}
										}, 16); // ~60fps
									}
								});
							}
						});
					}
				});
			}
		});
	};
	// Animate the screen in
	resultsContainer.alpha = 0;
	tween(resultsContainer, {
		alpha: 1
	}, {
		duration: 500
	});
}
function showGameOver(playerWon) {
	// Stop all game action by changing the state. The main update loop will halt.
	LK.stopMusic();
	currentGameState = 'gameover_transition';
	// NEW: Immediately stop all active game objects and create particle effects
	stopAllActionWithParticles();
	// Animate the victory or defeat logo.
	var logoAssetId = playerWon ? 'victoryLogo' : 'defeatLogo';
	var endLogo = LK.getAsset(logoAssetId, {
		anchorX: 0.5,
		anchorY: 0.5,
		x: SCREEN_WIDTH / 2,
		y: SCREEN_HEIGHT / 2
	});
	endLogo.scale.set(0.01);
	uiLayer.addChild(endLogo);
	// Play victory sound when the victory logo is shown
	if (playerWon) {
		LK.getSound('victory').play();
	}
	tween(endLogo, {
		scaleX: 1,
		scaleY: 1
	}, {
		duration: 1200,
		easing: tween.elasticOut,
		onFinish: function onFinish() {
			// After the animation, wait a moment, then transition.
			LK.setTimeout(function () {
				if (endLogo.parent) {
					endLogo.parent.removeChild(endLogo);
				}
				if (playerWon) {
					if (TutorialSystem.isActive) {
						// In tutorial, we skip the normal results and go straight to reset/menu to continue tutorial
						resetGameAndReturnToMenu();
					} else {
						showResultsScreen();
					}
				} else {
					if (TutorialSystem.isActive) {
						// Player lost tutorial, let them retry from beginning
						storage.tutorialCompleted = false;
					}
					resetGameAndReturnToMenu();
				}
			}, 1500);
		}
	});
}
function showCoopResultsScreen() {
	LK.stopMusic();
	currentGameState = 'gameover_transition';
	// NEW: Immediately stop all active game objects and create particle effects
	stopAllActionWithParticles();
	var resultsContainer = new Container();
	uiLayer.addChild(resultsContainer);
	// ... rest of the function remains the same
	// Dark overlay
	var bg = LK.getAsset('card', {
		width: SCREEN_WIDTH,
		height: SCREEN_HEIGHT,
		anchorX: 0,
		anchorY: 0
	});
	bg.tint = 0x000000;
	bg.alpha = 0.7;
	resultsContainer.addChild(bg);
	var title = new Text2('RESULTS', {
		size: 180,
		fill: 0xffd700,
		weight: 'bold',
		stroke: 0x000000,
		strokeThickness: 10
	});
	title.anchor.set(0.5, 0.5);
	title.x = SCREEN_WIDTH / 2;
	title.y = 300;
	resultsContainer.addChild(title);
	// Wave Reached
	var waveText = new Text2('Wave Reached: ' + WaveSystem.waveNumber, {
		size: 80,
		fill: 0xffffff,
		weight: 'bold'
	});
	waveText.anchor.set(0.5, 0.5);
	waveText.x = SCREEN_WIDTH / 2;
	waveText.y = 600;
	resultsContainer.addChild(waveText);
	if (WaveSystem.waveNumber > (storage.coopHighestWave || 0)) {
		storage.coopHighestWave = WaveSystem.waveNumber;
	}
	// Damage percentages
	var totalDamage = playerTotalDamage + aiTotalDamage;
	var playerPercent = totalDamage > 0 ? Math.round(playerTotalDamage / totalDamage * 100) : 0;
	var aiPercent = totalDamage > 0 ? 100 - playerPercent : 0;
	var playerDamageText = new Text2('Player Damage: ' + playerPercent + '%', {
		size: 70,
		fill: 0x88ff88,
		weight: 'normal'
	});
	playerDamageText.anchor.set(0.5, 0.5);
	playerDamageText.x = SCREEN_WIDTH / 2;
	playerDamageText.y = 750;
	resultsContainer.addChild(playerDamageText);
	var aiDamageText = new Text2('AI Damage: ' + aiPercent + '%', {
		size: 70,
		fill: 0xff8888,
		weight: 'normal'
	});
	aiDamageText.anchor.set(0.5, 0.5);
	aiDamageText.x = SCREEN_WIDTH / 2;
	aiDamageText.y = 850;
	resultsContainer.addChild(aiDamageText);
	// Create chest container
	var chestContainer = new Container();
	chestContainer.x = SCREEN_WIDTH / 2;
	chestContainer.y = 1600;
	resultsContainer.addChild(chestContainer);
	// Add small chest
	var chest = LK.getAsset('smallChest', {
		anchorX: 0.5,
		anchorY: 0.5
	});
	chest.scale.set(0.01);
	chestContainer.addChild(chest);
	// Tap to open text
	var tapToOpenText = new Text2('Tap to open', {
		size: 60,
		fill: 0xffffff,
		weight: 'bold',
		stroke: 0x000000,
		strokeThickness: 4
	});
	tapToOpenText.anchor.set(0.5, 0.5);
	tapToOpenText.y = 120;
	tapToOpenText.visible = false;
	chestContainer.addChild(tapToOpenText);
	// Make chest interactive
	chestContainer.interactive = true;
	chestContainer.hitArea = new Rectangle(-150, -150, 300, 300);
	var chestOpened = false;
	// Animate chest in with bounce
	tween(chest, {
		scaleX: 1.5,
		scaleY: 1.5
	}, {
		duration: 800,
		easing: tween.elasticOut,
		onFinish: function onFinish() {
			tapToOpenText.visible = true;
			// Pulse animation for tap to open text
			function pulseText() {
				if (!tapToOpenText.parent || chestOpened) {
					return;
				}
				tween(tapToOpenText, {
					scaleX: 1.1,
					scaleY: 1.1
				}, {
					duration: 600,
					easing: tween.easeInOut,
					onFinish: function onFinish() {
						if (!tapToOpenText.parent || chestOpened) {
							return;
						}
						tween(tapToOpenText, {
							scaleX: 1,
							scaleY: 1
						}, {
							duration: 600,
							easing: tween.easeInOut,
							onFinish: pulseText
						});
					}
				});
			}
			pulseText();
		}
	});
	chestContainer.down = function () {
		if (chestOpened) {
			return;
		}
		chestOpened = true;
		tapToOpenText.visible = false;
		// Wiggle animation
		tween(chest, {
			rotation: -0.1
		}, {
			duration: 100,
			easing: tween.linear,
			onFinish: function onFinish() {
				tween(chest, {
					rotation: 0.1
				}, {
					duration: 100,
					easing: tween.linear,
					onFinish: function onFinish() {
						tween(chest, {
							rotation: 0
						}, {
							duration: 100,
							easing: tween.linear,
							onFinish: function onFinish() {
								// Flash screen white
								LK.effects.flashScreen(0xffffff, 300);
								// Replace with open chest
								chestContainer.removeChild(chest);
								var openChest = LK.getAsset('smallChestOpen', {
									anchorX: 0.5,
									anchorY: 0.5
								});
								openChest.scale.set(1.5);
								chestContainer.addChild(openChest);
								// Reward calculation
								var moneyReward = Math.floor(WaveSystem.waveNumber * 5 + playerPercent * 1.5);
								var startMoney = storage.money;
								var targetMoney = startMoney + moneyReward;
								// Money text animation
								var moneyText = new Text2('$' + moneyReward, {
									size: 150,
									fill: 0xffd700,
									weight: 'bold',
									stroke: 0x000000,
									strokeThickness: 8
								});
								moneyText.anchor.set(0.5, 0.5);
								moneyText.y = -50;
								moneyText.scale.set(0.1);
								moneyText.alpha = 0;
								chestContainer.addChild(moneyText);
								// Animate scale property directly to avoid potential proxy issues with Text2 objects
								tween(moneyText.scale, {
									x: 1,
									y: 1
								}, {
									duration: 500,
									easing: tween.backOut
								});
								// Animate other properties on the text object itself
								tween(moneyText, {
									alpha: 1,
									y: -100
								}, {
									duration: 500,
									easing: tween.backOut,
									onFinish: function onFinish() {
										// Rolling number animation
										var rollDuration = 1000;
										var startTime = Date.now();
										var rollInterval = LK.setInterval(function () {
											var elapsed = Date.now() - startTime;
											var progress = Math.min(elapsed / rollDuration, 1);
											var easedProgress = 1 - Math.pow(1 - progress, 3); // Cubic ease out
											var currentValue = Math.floor(startMoney + moneyReward * easedProgress);
											storage.money = currentValue;
											if (progress >= 1) {
												LK.clearInterval(rollInterval);
												storage.money = targetMoney;
												// Show tap to continue
												var tapToContinueText = new Text2('Tap to continue', {
													size: 70,
													fill: 0x000000,
													weight: 'bold'
												});
												tapToContinueText.anchor.set(0.5, 0.5);
												tapToContinueText.y = 200;
												chestContainer.addChild(tapToContinueText);
												// Update chest interaction
												chestContainer.down = function () {
													tween(resultsContainer, {
														alpha: 0
													}, {
														duration: 300,
														onFinish: function onFinish() {
															if (resultsContainer.parent) {
																resultsContainer.parent.removeChild(resultsContainer);
															}
															resetGameAndReturnToMenu();
														}
													});
												};
											}
										}, 16); // ~60fps
									}
								});
							}
						});
					}
				});
			}
		});
	};
	// Animate the screen in
	resultsContainer.alpha = 0;
	tween(resultsContainer, {
		alpha: 1
	}, {
		duration: 500
	});
}
// NEW: Function to stop all action and create particle effects
function stopAllActionWithParticles() {
	// Create explosion particles for all remaining chips
	[].concat(activePlayerChips, activeAIChips).forEach(function (chip) {
		if (chip.active && chip.visible) {
			createChipExplosionParticles(chip.x, chip.y, chip.value);
		}
		chip.active = false;
		chip.visible = false;
		if (chip.parent) {
			chip.parent.removeChild(chip);
		}
	});
	// Create explosion particles for bullets
	activeBullets.forEach(function (bullet) {
		if (bullet.active && bullet.visible) {
			var explosionColor = 0x333333; // Dark Grey for clubs/spades
			if (bullet.suit === 'hearts' || bullet.suit === 'diamonds') {
				explosionColor = 0xff0000; // Red for hearts/diamonds
			}
			createExplosion(bullet.x, bullet.y, explosionColor);
		}
		bullet.active = false;
		bullet.visible = false;
		if (bullet.parent) {
			bullet.parent.removeChild(bullet);
		}
	});
	// Explode mines
	activeMines.forEach(function (mine) {
		if (mine.active && mine.visible) {
			createExplosion(mine.x, mine.y, 0xffa500);
		}
		mine.active = false;
		mine.visible = false;
		if (mine.parent) {
			mine.parent.removeChild(mine);
		}
	});
	// Clear the arrays
	activePlayerChips.length = 0;
	activeAIChips.length = 0;
	activeBullets.length = 0;
	activeMines.length = 0;
	// Stop all card firing by marking them as not in play temporarily
	for (var row = 0; row < PLAY_AREA_ROWS; row++) {
		for (var col = 0; col < PLAY_AREA_COLS; col++) {
			if (gameState.playerPlayArea[row][col]) {
				gameState.playerPlayArea[row][col].isInPlay = false;
			}
			if (gameState.aiPlayArea[row][col]) {
				gameState.aiPlayArea[row][col].isInPlay = false;
			}
		}
	}
}
// NEW: Enhanced particle effect for chip explosions - celebratory version
function createChipExplosionParticles(x, y, chipValue) {
	var numParticles = Math.min(20, 10 + chipValue); // More particles for celebration
	var chipColor = getChipColor(chipValue);
	for (var i = 0; i < numParticles; i++) {
		var particle = LK.getAsset('explosionParticle', {
			anchorX: 0.5,
			anchorY: 0.5
		});
		particle.x = x + (Math.random() - 0.5) * 40; // Start in a tight cluster
		particle.y = y + (Math.random() - 0.5) * 40;
		particle.tint = chipColor;
		particle.scale.set(0.4 + Math.random() * 0.8);
		// Launch particles upward in a celebratory fountain pattern
		var angle = -Math.PI / 2 + (Math.random() - 0.5) * Math.PI * 0.8; // Mostly upward, some spread
		var initialSpeed = 300 + Math.random() * 400; // Strong upward velocity
		var gravity = 600; // Gravity pulls them down
		var velocityX = Math.cos(angle) * initialSpeed;
		var velocityY = Math.sin(angle) * initialSpeed; // Negative Y is upward
		var duration = 2000 + Math.random() * 1000; // 2-3 seconds of flight time
		var targetX = x + velocityX * (duration / 1000);
		var targetY = y + velocityY * (duration / 1000) + 0.5 * gravity * Math.pow(duration / 1000, 2);
		// Ensure particles fall well off screen for full celebration effect
		if (targetY < SCREEN_HEIGHT + 200) {
			targetY = SCREEN_HEIGHT + 200 + Math.random() * 300;
		}
		gameLayer.addChild(particle);
		// Animate with celebratory spinning and fading
		tween(particle, {
			x: targetX,
			y: targetY,
			alpha: 0,
			rotation: Math.random() * Math.PI * 6 // Extra spinning for celebration
		}, {
			duration: duration,
			easing: tween.quadIn,
			// Natural gravity acceleration
			onFinish: function (p) {
				return function () {
					if (p.parent) {
						p.parent.removeChild(p);
					}
				};
			}(particle)
		});
	}
}
// NEW: Helper function to get chip color based on value
function getChipColor(chipValue) {
	switch (chipValue) {
		case 1:
			return 0xffff00;
		// Yellow
		case 5:
			return 0xff0000;
		// Red
		case 10:
			return 0x00ff00;
		// Green
		case 25:
			return 0x0000ff;
		// Blue
		case 100:
			return 0x8000ff;
		// Purple
		default:
			return 0xffffff;
		// White for boss chips
	}
}
/**** 
* Utility Functions
****/ 
function formatNumberWithSuffix(number) {
	// ADD VALIDATION
	if (typeof number !== 'number' || isNaN(number) || number === Infinity || number === -Infinity) {
		console.warn("Invalid number for formatting:", number);
		return "0";
	}
	var num = Math.round(number);
	if (num < 1000) {
		return num.toString();
	}
	if (num < 1000000) {
		return (num / 1000).toFixed(1).replace(/\.0$/, '') + 'K';
	}
	if (num < 1000000000) {
		return (num / 1000000).toFixed(1).replace(/\.0$/, '') + 'M';
	}
	if (num < 1000000000000) {
		return (num / 1000000000).toFixed(1).replace(/\.0$/, '') + 'B';
	}
	return (num / 1000000000000).toFixed(1).replace(/\.0$/, '') + 'T';
}
function clearPlayerStorage() {
	storage.battleRating = 0;
	storage.money = 0;
	storage.equippedMods = null;
	storage.ownedMods = null;
	storage.randomModPrice = 300;
	storage.tutorialCompleted = false; // Also reset tutorial progress
	storage.coopHighestWave = 0; // Clear highest wave in coop
	// Also reset in-memory ModSystem if it's already initialized
	ModSystem.equippedMods = {
		hearts: null,
		diamonds: null,
		clubs: null,
		spades: null
	};
	ModSystem.ownedMods = {};
	createFloatingText("Player Storage Cleared!", SCREEN_WIDTH / 2, SCREEN_HEIGHT / 2, 0xff0000, 100);
}
var TutorialSystem = {
	isActive: false,
	step: 0,
	overlay: null,
	messageBox: null,
	pulsingElement: null,
	isWaitingForTap: false,
	isWaitingForDrag: false,
	isWaitingForMerge: false,
	isWaitingForChipKill: false,
	isWaitingForJokerMerge: false,
	nextStepCallback: null,
	assistanceMessageShown: false,
	startScreenItems: {},
	registerStartScreenElements: function registerStartScreenElements(items) {
		this.startScreenItems = items;
	},
	start: function start() {
		this.isActive = true;
		this.step = 0;
		this.assistanceMessageShown = false;
	},
	startInGameTutorial: function startInGameTutorial() {
		this.isActive = true;
		this.step = 1;
		this.assistanceMessageShown = false;
		dealInitialHand();
		var self = this;
		LK.setTimeout(function () {
			self.advanceStep();
		}, 1500);
	},
	update: function update() {
		if (!this.isActive) {
			return;
		}
		if (this.isWaitingForDrag) {
			for (var r = 0; r < PLAY_AREA_ROWS; r++) {
				for (var c = 0; c < PLAY_AREA_COLS; c++) {
					if (gameState.playerPlayArea[r][c]) {
						this.isWaitingForDrag = false;
						this.advanceStep();
						return;
					}
				}
			}
		}
		if (this.isWaitingForMerge) {
			var mergeCompleted = false;
			// Check play area for a leveled-up card
			for (var r = 0; r < PLAY_AREA_ROWS; r++) {
				for (var c = 0; c < PLAY_AREA_COLS; c++) {
					if (gameState.playerPlayArea[r][c] && gameState.playerPlayArea[r][c].level >= 2) {
						mergeCompleted = true;
						break;
					}
				}
				if (mergeCompleted) {
					break;
				}
			}
			// If not found in play area, check the hand
			if (!mergeCompleted) {
				for (var i = 0; i < gameState.playerHand.length; i++) {
					if (gameState.playerHand[i] && gameState.playerHand[i].level >= 2) {
						mergeCompleted = true;
						break;
					}
				}
			}
			if (mergeCompleted) {
				this.isWaitingForMerge = false;
				this.advanceStep();
				return;
			}
		}
		if (this.isWaitingForJokerMerge) {
			var hasLevel3PlusCard = false;
			var level2PlusCardCount = 0;
			// Check play area for cards
			for (var r = 0; r < PLAY_AREA_ROWS; r++) {
				for (var c = 0; c < PLAY_AREA_COLS; c++) {
					var card = gameState.playerPlayArea[r][c];
					if (card) {
						if (card.level >= 3) {
							hasLevel3PlusCard = true;
						}
						if (card.level >= 2) {
							level2PlusCardCount++;
						}
					}
				}
			}
			// Also check player's hand
			for (var i = 0; i < gameState.playerHand.length; i++) {
				var card = gameState.playerHand[i];
				if (card) {
					if (card.level >= 3) {
						hasLevel3PlusCard = true;
					}
					if (card.level >= 2) {
						level2PlusCardCount++;
					}
				}
			}
			if (hasLevel3PlusCard || level2PlusCardCount >= 2) {
				this.isWaitingForJokerMerge = false;
				this.advanceStep();
				return;
			}
		}
		if (this.isWaitingForChipKill) {
			if (activePlayerChips.length === 0) {
				this.isWaitingForChipKill = false;
				this.advanceStep();
			}
		}
	},
	advanceStep: function advanceStep() {
		this.clearMessage();
		this.step++;
		switch (this.step) {
			case 2:
				this.explainDrag();
				break;
			case 3:
				this.waitForDrag();
				break;
			case 4:
				this.spawnFirstEnemy();
				break;
			case 5:
				this.waitForKill();
				break;
			case 6:
				this.explainMerge();
				break;
			case 7:
				this.waitForMerge();
				break;
			case 8:
				this.explainJoker();
				break;
			case 9:
				this.instructJokerMerge();
				break;
			case 10:
				this.startWaves();
				break;
			case 11:
				this.explainPokerHands();
				break;
			case 12:
				this.explainDiscard();
				break;
			case 13:
				this.guaranteedWin();
				break;
			case 14:
				this.guideToShop();
				break;
			case 15:
				this.guideToRandomMod();
				break;
			case 16:
				this.guideToModsScreen();
				break;
			case 17:
				this.explainEquipMod();
				break;
			case 18:
				this.completeTutorial();
				break;
		}
	},
	showMessage: function showMessage(text, elementToPulse, waitForTapCallback, isPostGame) {
		this.clearMessage();
		this.overlay = new Container();
		if (!isPostGame) {
			this.overlay.interactive = true;
		}
		this.overlay.hitArea = new Rectangle(0, 0, SCREEN_WIDTH, SCREEN_HEIGHT);
		var bg = LK.getAsset('card', {
			width: SCREEN_WIDTH,
			height: SCREEN_HEIGHT,
			anchorX: 0,
			anchorY: 0
		});
		bg.tint = 0x000000;
		bg.alpha = 0.7;
		this.overlay.addChild(bg);
		uiLayer.addChild(this.overlay);
		this.messageBox = new Text2(text, {
			size: 70,
			fill: 0xffffff,
			weight: 'bold',
			stroke: 0x000000,
			strokeThickness: 5,
			align: 'center',
			wordWrap: true,
			wordWrapWidth: SCREEN_WIDTH - 200
		});
		this.messageBox.anchor.set(0.5, 0.5);
		this.messageBox.x = SCREEN_WIDTH / 2;
		this.messageBox.y = isPostGame ? SCREEN_HEIGHT - 650 : SCREEN_HEIGHT / 2;
		this.overlay.addChild(this.messageBox);
		if (elementToPulse) {
			this.pulsingElement = elementToPulse;
			if (elementToPulse.parent) {
				this.pulsingElementOriginalParent = elementToPulse.parent;
				this.overlay.addChild(elementToPulse);
			}
			this.pulseAnimation(elementToPulse);
		}
		if (waitForTapCallback) {
			this.isWaitingForTap = true;
			this.nextStepCallback = waitForTapCallback;
			this.overlay.down = function () {
				if (TutorialSystem.isWaitingForTap) {
					TutorialSystem.isWaitingForTap = false;
					TutorialSystem.nextStepCallback();
				}
			};
		}
	},
	clearMessage: function clearMessage() {
		if (this.pulsingElement) {
			tween.stop(this.pulsingElement);
			if (this.pulsingElement.scale) {
				tween.stop(this.pulsingElement.scale);
			}
			if (this.pulsingElement.originalScaleX) {
				this.pulsingElement.scale.set(this.pulsingElement.originalScaleX, this.pulsingElement.originalScaleY);
			}
			if (this.pulsingElementOriginalParent) {
				this.pulsingElementOriginalParent.addChild(this.pulsingElement);
				this.pulsingElementOriginalParent = null;
			}
			this.pulsingElement = null;
		}
		if (this.overlay) {
			if (this.overlay.parent) {
				this.overlay.parent.removeChild(this.overlay);
			}
			this.overlay = null;
			this.messageBox = null;
		}
	},
	pulseAnimation: function pulseAnimation(element) {
		var self = this;
		var originalScaleX = element.originalScaleX || (element.scale ? element.scale.x : 1);
		var originalScaleY = element.originalScaleY || (element.scale ? element.scale.y : 1);
		element.originalScaleX = originalScaleX;
		element.originalScaleY = originalScaleY;
		tween(element.scale, {
			x: originalScaleX * 1.1,
			y: originalScaleY * 1.1
		}, {
			duration: 700,
			easing: tween.easeInOut,
			onFinish: function onFinish() {
				if (element.parent) {
					tween(element.scale, {
						x: originalScaleX,
						y: originalScaleY
					}, {
						duration: 700,
						easing: tween.easeInOut,
						onFinish: function onFinish() {
							if (element.parent) {
								self.pulseAnimation(element);
							}
						}
					});
				}
			}
		});
	},
	explainDrag: function explainDrag() {
		var self = this;
		var cardInHand = gameState.playerHand.find(function (c) {
			return c !== null;
		});
		if (cardInHand) {
			self.showMessage("You've been dealt 5 cards. Drag one to an empty slot on your board to play it.", cardInHand, self.advanceStep.bind(self));
		}
	},
	waitForDrag: function waitForDrag() {
		this.isWaitingForDrag = true;
	},
	explainDiscard: function explainDiscard() {
		this.showMessage("You can also drag cards to the draw button to sell them for a refund.\n\nTap to continue.", discardAreaContainer, this.advanceStep.bind(this));
	},
	spawnFirstEnemy: function spawnFirstEnemy() {
		this.showMessage("Excellent! A card on the board will automatically attack enemies. Let's see it in action!", null, function () {
			TutorialSystem.clearMessage();
			ChipSpawner.spawnChip(1, true);
			TutorialSystem.advanceStep();
		});
	},
	waitForKill: function waitForKill() {
		this.isWaitingForChipKill = true;
	},
	explainMerge: function explainMerge() {
		this.showMessage("Well done! You can level up cards by merging them. Drag a card onto another of the SAME SUIT or SAME VALUE to merge them.\nNote: When you merge, the new card will be a random value and suit, but its level will increase!", null, function () {
			TutorialSystem.clearMessage();
			var cardIndices = [];
			for (var i = 0; i < gameState.playerHand.length; i++) {
				if (gameState.playerHand[i]) {
					cardIndices.push(i);
				}
			}
			if (cardIndices.length >= 2) {
				var index1 = cardIndices[0];
				var index2 = cardIndices[1];
				var oldCard1 = gameState.playerHand[index1];
				var oldCard2 = gameState.playerHand[index2];
				// Make them same suit to be mergeable
				var newCardData1 = {
					suit: 'spades',
					value: 'A',
					id: 'spades_A'
				};
				var newCardData2 = {
					suit: 'spades',
					value: 'K',
					id: 'spades_K'
				};
				if (oldCard1 && oldCard1.parent) {
					oldCard1.parent.removeChild(oldCard1);
				}
				if (oldCard2 && oldCard2.parent) {
					oldCard2.parent.removeChild(oldCard2);
				}
				placeCardInHand(new Card(newCardData1), index1);
				placeCardInHand(new Card(newCardData2), index2);
			}
			TutorialSystem.advanceStep();
		});
	},
	waitForMerge: function waitForMerge() {
		this.isWaitingForMerge = true;
	},
	explainJoker: function explainJoker() {
		this.showMessage("Fantastic! Jokers are special. They can merge with ANY card to raise its level.", null, function () {
			TutorialSystem.clearMessage();
			// Place a Joker in hand
			var jokerData = {
				suit: 'joker',
				value: 'black',
				id: 'joker_black'
			};
			placeCardInHand(new Card(jokerData), 2); // Place it in the middle of the hand
			TutorialSystem.advanceStep();
		});
	},
	instructJokerMerge: function instructJokerMerge() {
		var self = this;
		var jokerInHand = gameState.playerHand[2];
		if (jokerInHand) {
			var message = "Now drag the Joker from your hand onto a card on your board to level it up!";
			// We pulse the joker, as that's the one to drag.
			this.showMessage(message, jokerInHand, function () {
				self.clearMessage();
				self.isWaitingForJokerMerge = true;
			});
		} else {
			// Failsafe
			this.advanceStep();
		}
	},
	startWaves: function startWaves() {
		this.showMessage("Perfect! Merging is key to victory. Now, a real wave is coming. The AI will also start playing.", null, function () {
			TutorialSystem.clearMessage();
			gameReady = true;
			AISystem.thinkDelay = 240;
			TutorialSystem.advanceStep();
		});
	},
	explainPokerHands: function explainPokerHands() {
		LK.setTimeout(function () {
			TutorialSystem.showMessage("Placing cards in rows creates poker hands, like 'pairs' or 'straights', giving them a massive damage boost!", null, function () {
				TutorialSystem.clearMessage();
				TutorialSystem.advanceStep();
			});
		}, 8000);
	},
	guaranteedWin: function guaranteedWin() {},
	guideToShop: function guideToShop() {
		var items = this.startScreenItems;
		var message = "You won! As a reward, you get a FREE mod. Go to the shop to claim it.";
		this.setupPostGameGuide(message, items.shop.button, [items.battle.button, items.mods.button]);
		var shopClickHandler = function shopClickHandler() {
			items.shop.down();
			TutorialSystem.clearMessage();
			[items.battle.button, items.mods.button, items.shop.button].forEach(function (b) {
				b.interactive = true;
				b.alpha = 1;
			});
			TutorialSystem.advanceStep();
		};
		items.shop.button.down = shopClickHandler;
		items.shop.icon.down = shopClickHandler;
	},
	guideToRandomMod: function guideToRandomMod() {
		var items = this.startScreenItems.shopItems;
		var message = "Tap the glowing item to get your free random mod!";
		var originalPrice = storage.randomModPrice;
		storage.randomModPrice = 0;
		items.priceText.setText('$0');
		this.showMessage(message, null);
		if (this.overlay) {
			// Hide the dark background and make overlay non-interactive to allow clicks on shop
			this.overlay.getChildAt(0).visible = false;
			this.overlay.interactive = false;
		}
		items.overlay.interactive = items.asset.interactive = true;
		var originalBuy = items.buyButtonDown;
		items.overlay.down = items.asset.down = function () {
			items.overlay.down = items.asset.down = function () {}; // Prevent multi-click
			originalBuy();
			storage.randomModPrice = originalPrice;
			LK.setTimeout(function () {
				TutorialSystem.clearMessage();
				TutorialSystem.advanceStep();
			}, 3500);
		};
	},
	guideToModsScreen: function guideToModsScreen() {
		var items = this.startScreenItems;
		items.shopContainer.visible = false;
		var message = "Awesome! Now let's equip your new mod. Go to the mods screen.";
		this.setupPostGameGuide(message, items.mods.button, [items.battle.button, items.shop.button]);
		var modsClickHandler = function modsClickHandler() {
			items.mods.down();
			TutorialSystem.clearMessage();
			[items.battle.button, items.mods.button, items.shop.button].forEach(function (b) {
				b.interactive = true;
				b.alpha = 1;
			});
			TutorialSystem.advanceStep();
		};
		items.mods.button.down = modsClickHandler;
		items.mods.icon.down = modsClickHandler;
	},
	explainEquipMod: function explainEquipMod() {
		// First, manually refresh the visual state of all mods in the grid
		// because the grid was created before the player owned the new mod.
		var modsContainer = this.startScreenItems.modsContainer;
		// The gridContainer is the last major element added to the modsContainer.
		var gridContainer = modsContainer.children[modsContainer.children.length - 1];
		if (gridContainer && gridContainer.children.length > 0) {
			var suitModAssets = ['burnHeartMod', 'chipsDiamondMod', 'spreadClubMod', 'freezeSpadeMod', 'unityHeartsMod', 'gamblerDiamondsMod', 'slowClubsMod', 'mineSpadesMod', 'investmentHeartsMod', 'boostDiamondsMod', 'ricochetClubsMod', 'deathSpadesMod'];
			var childrenPerMod = 4; // Assumes cell, shadow, mod asset, name text
			for (var modIndex = 0; modIndex < suitModAssets.length; modIndex++) {
				var assetId = suitModAssets[modIndex];
				var isOwned = ModSystem.isModOwned(assetId);
				var cellIndex = modIndex * childrenPerMod;
				var modAssetIndex = cellIndex + 2;
				if (gridContainer.children[cellIndex] && gridContainer.children[modAssetIndex]) {
					var cell = gridContainer.children[cellIndex];
					var modAsset = gridContainer.children[modAssetIndex];
					if (isOwned) {
						modAsset.tint = 0xffffff;
						modAsset.alpha = 1.0;
						cell.tint = 0xffffff;
					} else {
						modAsset.tint = 0x555555;
						modAsset.alpha = 0.6;
						cell.tint = 0x888888;
					}
				}
			}
		}
		var message = "This screen shows all mods. Tap your new mod, then tap 'Equip' to use it in battle!";
		this.showMessage(message, null, function () {
			TutorialSystem.clearMessage();
			var originalEquip = ModSystem.equipMod;
			ModSystem.equipMod = function (modAssetId) {
				originalEquip.call(ModSystem, modAssetId);
				TutorialSystem.advanceStep();
				ModSystem.equipMod = originalEquip;
			};
		});
		// Make the tutorial overlay transparent so the mods screen is fully visible.
		if (this.overlay) {
			this.overlay.getChildAt(0).visible = false;
		}
	},
	completeTutorial: function completeTutorial() {
		this.showMessage("Tutorial complete! You're ready for battle. Good luck!", null, function () {
			TutorialSystem.clearMessage();
			storage.tutorialCompleted = true;
			TutorialSystem.isActive = false;
			var items = TutorialSystem.startScreenItems;
			[items.battle, items.mods, items.shop].forEach(function (item) {
				if (item && item.button && item.icon) {
					item.button.interactive = true;
					item.button.alpha = 1.0;
					item.icon.interactive = true;
					item.icon.alpha = 1.0;
				}
			});
			TutorialSystem.startScreenItems.modsContainer.visible = false;
			TutorialSystem.startScreenItems.battle.down();
		});
	},
	setupPostGameGuide: function setupPostGameGuide(message, elementToPulse, elementsToDisable) {
		this.clearMessage();
		this.showMessage(message, null, null, true); // isPostGame = true
		var items = this.startScreenItems;
		// Disable other buttons and their icons
		elementsToDisable.forEach(function (el) {
			el.interactive = false;
			el.alpha = 0.5;
			if (el === items.battle.button) {
				items.battle.icon.interactive = false;
				items.battle.icon.alpha = 0.5;
			} else if (el === items.mods.button) {
				items.mods.icon.interactive = false;
				items.mods.icon.alpha = 0.5;
			} else if (el === items.shop.button) {
				items.shop.icon.interactive = false;
				items.shop.icon.alpha = 0.5;
			}
		});
		// Enable the target button and its icon
		elementToPulse.interactive = true;
		elementToPulse.alpha = 1.0;
		var iconToPulse = null;
		if (elementToPulse === items.shop.button) {
			iconToPulse = items.shop.icon;
		} else if (elementToPulse === items.mods.button) {
			iconToPulse = items.mods.icon;
		}
		if (iconToPulse) {
			iconToPulse.interactive = true;
			iconToPulse.alpha = 1.0;
		}
		// Bring the container with all buttons on top of the overlay
		if (this.overlay && elementToPulse.parent && elementToPulse.parent.parent) {
			elementToPulse.parent.parent.addChild(elementToPulse.parent);
		}
		this.pulsingElement = elementToPulse;
		this.pulseAnimation(this.pulsingElement);
	}
};
function placeCardInHand(card, index) {
	var handWidth = 5 * DEAL_SLOT_WIDTH + 4 * 30;
	var handStartX = (SCREEN_WIDTH - handWidth) / 2;
	var slotX = handStartX + index * DEAL_SLOT_WIDTH + index * 30 + DEAL_SLOT_WIDTH / 2;
	var slotY = PLAYER_DEAL_AREA_Y + DEAL_SLOT_HEIGHT / 2;
	card.activate(slotX, slotY, false, true);
	uiLayer.addChild(card);
	gameState.playerHand[index] = card;
}
function displayHandInfo() {
	// Show current poker hand evaluations for debugging
	for (var row = 0; row < PLAY_AREA_ROWS; row++) {
		var handEval = evaluateRowHand(row, true);
		console.log('Player Row ' + row + ':', handEval.type, 'Multiplier:', handEval.multiplier);
	}
}
var background = LK.getAsset('background', {
	anchorX: 0.5,
	anchorY: 0
});
background.x = SCREEN_WIDTH / 2;
background.y = 50;
background.visible = false;
gameLayer.addChild(background);
var coopBackground = LK.getAsset('coopBackground', {
	anchorX: 0.5,
	anchorY: 0
});
coopBackground.x = SCREEN_WIDTH / 2;
coopBackground.y = 50;
coopBackground.visible = false;
gameLayer.addChild(coopBackground);
// Place two chipracks side by side in the center at the top of the screen
var chipRack1 = LK.getAsset('chipRack', {
	anchorX: 0.5,
	anchorY: 0
});
var rackWidth = chipRack1.width;
var rackHeight = chipRack1.height;
chipRack1.x = SCREEN_WIDTH / 2 - rackWidth / 2;
chipRack1.y = 60 - rackHeight * 0.75 + 30;
chipRack1.visible = false;
gameLayer.addChild(chipRack1);
gameElements.push(chipRack1);
var chipRack2 = LK.getAsset('chipRack', {
	anchorX: 0.5,
	anchorY: 0
});
chipRack2.x = SCREEN_WIDTH / 2 + rackWidth / 2;
chipRack2.y = 60 - rackHeight * 0.75 + 30;
chipRack2.visible = false;
gameLayer.addChild(chipRack2);
gameElements.push(chipRack2);
var border = LK.getAsset('border', {
	anchorX: 0.5,
	anchorY: 0.5
});
border.x = SCREEN_WIDTH / 2;
border.y = SCREEN_HEIGHT / 2;
border.visible = false;
gameLayer.addChild(border);
gameElements.push(border);
var bottomBar = LK.getAsset('bottomBar', {
	anchorX: 0.5,
	anchorY: 1
});
bottomBar.x = SCREEN_WIDTH / 2;
bottomBar.y = SCREEN_HEIGHT;
bottomBar.visible = false;
gameLayer.addChild(bottomBar);
gameElements.push(bottomBar);
// Show start screen instead of initializing game immediately
createStartScreen();
// Add active chips container below the bottom bar
gameLayer.addChildAt(activePlayerChipsContainer, gameLayer.getChildIndex(bottomBar));
gameLayer.addChildAt(activeAIChipsContainer, gameLayer.getChildIndex(bottomBar));
// Add chipStack asset above chips display
var chipStack = LK.getAsset('chipStack', {
	anchorX: 0.5,
	anchorY: 1
});
chipStack.x = playerChipsText.x + playerChipsText.width / 2;
chipStack.y = playerChipsText.y - 10;
chipStack.visible = false;
uiLayer.addChild(chipStack);
gameElements.push(chipStack);
;
;
// Helper to show roulette for the next boss wave
WaveSystem.showRouletteForNextBoss = function () {
	var nextBossWave = BossSystem.getNextBossWave();
	if (nextBossWave > this.waveNumber) {
		BossSystem.showBossRoulette(function () {
			// Roulette complete, continue with normal wave logic
			console.log("Boss roulette completed for wave " + nextBossWave);
		});
	}
};
function evaluateHandWithJokers(cardSymbols, jokerCount) {
	var totalSymbols = cardSymbols.length + jokerCount;
	if (jokerCount === 0 && cardSymbols.length >= 2) {
		// No jokers, use existing evaluation but allow for partial hands
		var tempCards = cardSymbols.map(function (data) {
			return {
				cardData: data
			};
		});
		return CardSystem.evaluatePokerHand(tempCards);
	}
	// With jokers present
	if (jokerCount >= 4) {
		return {
			type: 'four_of_a_kind',
			strength: 8,
			multiplier: 25
		};
	}
	if (jokerCount >= 3) {
		return {
			type: 'three_of_a_kind',
			strength: 4,
			multiplier: 5
		};
	}
	if (jokerCount >= 2) {
		return {
			type: 'three_of_a_kind',
			strength: 4,
			multiplier: 5
		};
	}
	if (jokerCount >= 1) {
		// 1 joker guarantees at least a pair
		return {
			type: 'one_pair',
			strength: 2,
			multiplier: 2
		};
	}
	// Fallback for edge cases
	return {
		type: 'none',
		strength: 0,
		multiplier: 1
	};
}
function clearAllGreenOutlines() {
	// Clear all temporary green outlines
	for (var row = 0; row < PLAY_AREA_ROWS; row++) {
		for (var col = 0; col < PLAY_AREA_COLS; col++) {
			var card = gameState.playerPlayArea[row][col];
			if (card) {
				card.greenOutline.visible = false;
			}
		}
	}
	for (var i = 0; i < gameState.playerHand.length; i++) {
		var card = gameState.playerHand[i];
		if (card) {
			card.greenOutline.visible = false;
		}
	}
} ===================================================================
--- original.js
+++ change.js
@@ -8903,9 +8903,9 @@
 	// Calculate Battle Rating
 	var oldRating = storage.battleRating;
 	var waveBonus = (WaveSystem.waveNumber - 1) * 5;
 	var livesBonus = (gameState.playerLives - gameState.aiLives) * 10;
-	var winBonus = 25;
+	var winBonus = 30;
 	var ratingChange = waveBonus + livesBonus + winBonus;
 	ratingChange = Math.max(5, ratingChange); // Minimum 5 rating gain on win
 	var newRating = oldRating + ratingChange;
 	storage.battleRating = newRating;
@@ -9394,9 +9394,9 @@
 								});
 								openChest.scale.set(1.5);
 								chestContainer.addChild(openChest);
 								// Reward calculation
-								var moneyReward = Math.floor(WaveSystem.waveNumber * 5 + playerPercent);
+								var moneyReward = Math.floor(WaveSystem.waveNumber * 5 + playerPercent * 1.5);
 								var startMoney = storage.money;
 								var targetMoney = startMoney + moneyReward;
 								// Money text animation
 								var moneyText = new Text2('$' + moneyReward, {
:quality(85)/https://cdn.frvr.ai/6871f39347e5ee9a217151ab.png%3F3) 
 :quality(85)/https://cdn.frvr.ai/6871f3b647e5ee9a217151af.png%3F3) 
 :quality(85)/https://cdn.frvr.ai/6871f3e247e5ee9a217151b3.png%3F3) 
 :quality(85)/https://cdn.frvr.ai/6871f41147e5ee9a217151b7.png%3F3) 
 :quality(85)/https://cdn.frvr.ai/6873439cb44764ef76be374f.png%3F3) 
 A long rack of different colored poker chips seen from above. Anime style.. In-Game asset. 2d. High contrast. No shadows
:quality(85)/https://cdn.frvr.ai/6874137ffba068a90d978fbd.png%3F3) 
 A graphic for the center of a joker card.
:quality(85)/https://cdn.frvr.ai/68741be377f9a93f7db14fbd.png%3F3) 
 a 2:3 format thin black border with nothing in the center. In-Game asset. 2d. High contrast. No shadows
:quality(85)/https://cdn.frvr.ai/68745754541492518eadfc2f.png%3F3) 
 A small white explosion particle.. In-Game asset. 2d. High contrast. No shadows
:quality(85)/https://cdn.frvr.ai/687469b83da8003be3584da0.png%3F3) 
 Make the blue a lighter blue.
:quality(85)/https://cdn.frvr.ai/68747a42f509ef0939542218.png%3F3) 
 Make this in a white instead of blue. Keep everything else the same.
:quality(85)/https://cdn.frvr.ai/6874830af509ef093954227b.png%3F3) 
 A couple different sized stacks of these chips beside each other.
:quality(85)/https://cdn.frvr.ai/6875c6dea0eee10ae850a892.png%3F3) 
 Just the spade from this picture with a blue snowflake in the middle of it.
:quality(85)/https://cdn.frvr.ai/6875c765a0eee10ae850a89d.png%3F3) 
 Just the heart from this picture with a flame in the cent t of it.
:quality(85)/https://cdn.frvr.ai/6875cb78a0eee10ae850a924.png%3F3) 
 Just the club from this picture with 1. **Fan/Spray Symbol** - Three or more lines radiating outward from a central point, yellow in color, in the center of the club.
:quality(85)/https://cdn.frvr.ai/6875d66fa0eee10ae850a93a.png%3F3) 
 Just the diamond from this picture with a dollar sign in the center
:quality(85)/https://cdn.frvr.ai/6875d703a0eee10ae850a944.png%3F3) 
 A white circle with a lightening gradient towards the edge.. Single Game Texture. In-Game asset. 2d. Blank background. High contrast. No shadows
:quality(85)/https://cdn.frvr.ai/687679b515e351708debd3c8.png%3F3) 
 A simple golden line break.. In-Game asset. 2d. High contrast. No shadows
:quality(85)/https://cdn.frvr.ai/687bd0137b6a9556f8fe7ed7.png%3F3) 
 A fanned card hand that shows a royal flush in spades. Anime style. In-Game asset. 2d. High contrast. No shadows
:quality(85)/https://cdn.frvr.ai/687bd0a97b6a9556f8fe7ef0.png%3F3) 
 An SVG of the word 'Battle'. text in yellow with a black outline. In-Game asset. 2d. High contrast. No shadows
:quality(85)/https://cdn.frvr.ai/687bd2ca7b6a9556f8fe7f06.png%3F3) 
 change the text to say "Mods"
:quality(85)/https://cdn.frvr.ai/687bd3bc7b6a9556f8fe7f1e.png%3F3) 
 The four card suits arranged in 2x2 grid layout, no lines. Anime style. In-Game asset. 2d. High contrast. No shadows
:quality(85)/https://cdn.frvr.ai/687be88fbf698a3c37ab2c0d.png%3F3) 
 A single ice crystal. anime style. In-Game asset. 2d. High contrast. No shadows
:quality(85)/https://cdn.frvr.ai/687c44d53cb288ad46200d5f.png%3F3) 
 Change the text to say ‘Refund’. Change the cards to a trash can.
:quality(85)/https://cdn.frvr.ai/687d0a4cc6f9ccf37b03795f.png%3F3) 
 A completely blank playing card with textured surface. Slightly used edges with a couple nicks out of it. Black background. In-Game asset. 2d. High contrast. No shadows
:quality(85)/https://cdn.frvr.ai/687d8a39d77e26bb4fad2eb6.png%3F3) 
 A 3:2 ratio rectangular green button that says “PvP” using this yellow font.
:quality(85)/https://cdn.frvr.ai/687d8ba7d77e26bb4fad2edc.png%3F3) 
 Change the text to say ‘Co-op’
:quality(85)/https://cdn.frvr.ai/687dc0392780cf1d777377c3.png%3F3) 
 Change the font to say ‘Victory!’
:quality(85)/https://cdn.frvr.ai/687dc0902780cf1d777377da.png%3F3) 
 Change the text to say ‘Defeat!’
:quality(85)/https://cdn.frvr.ai/687dcdd42780cf1d777378f3.png%3F3) 
 A 2:3 ratio rectangular picture that shows two card playing cats in a casino very close face to face with teeth bared and fists clenched as if they’re about to fight. Each cat has a different card suit pattern on the fur of their forehead. One is wearing a suit and the other is wearing tan leather jacket with a striped tank top underneath. Anime style.. In-Game asset. 2d. High contrast. No shadows
:quality(85)/https://cdn.frvr.ai/687dce972780cf1d77737901.png%3F3) 
 Show these same cats smiling and instead of clenched fists they’re grasping hands because they’re friends.
:quality(85)/https://cdn.frvr.ai/687dd0352780cf1d77737924.png%3F3) 
 Incorporate these two cats heads into a game logo for a poker based tower defense that includes the name “Double Down Defense”. Put their heads offset on either side with eyes open and looking at the logo.
:quality(85)/https://cdn.frvr.ai/687e834821a75d1f112ccb15.png%3F3) 
 A small treasure chest with poker themed graphics on it. Anime style. In-Game asset. 2d. High contrast. No shadows
:quality(85)/https://cdn.frvr.ai/688159052c87620a153bedee.png%3F3) 
 The hearts card suit symbol with two linked hearts in the center of it. Anime style.. In-Game asset. 2d. High contrast. No shadows
:quality(85)/https://cdn.frvr.ai/68817fc34ff423bd3706be40.png%3F3) 
 The diamond card suit with a coin in the center. The coin has a ‘2X’ in the center. Anime style.. In-Game asset. 2d. High contrast. No shadows
:quality(85)/https://cdn.frvr.ai/6881829328b77a2753d43375.png%3F3) 
 Just the club from this picture with a clock in the center.
:quality(85)/https://cdn.frvr.ai/6882c29eeb998a84393b5688.png%3F3) 
 Just the spade from this image with a land mine in the center of it.
:quality(85)/https://cdn.frvr.ai/6882c327eb998a84393b5698.png%3F3) 
 Just the mine from this image.
:quality(85)/https://cdn.frvr.ai/6882ccd3eb998a84393b576b.png%3F3) 
 Just the heart from this image with a piggy bank in the center.
:quality(85)/https://cdn.frvr.ai/6882f30ceb998a84393b5891.png%3F3) 
 Just the diamond from this picture with a sword with a small arrow pointing up in the center of the diamond.
:quality(85)/https://cdn.frvr.ai/68831a72c2e278fce844440e.png%3F3) 
 Just the club from this picture with an icon in the center of it that represents a projectile bouncing at an angle off of a surface.
:quality(85)/https://cdn.frvr.ai/68831f784e9918bacc12d984.png%3F3) 
 Just the spade with a skull in the center of it. Anime style.
:quality(85)/https://cdn.frvr.ai/6883273ec2e278fce844444f.png%3F3) 
 This chest with the top open and nothing inside.
:quality(85)/https://cdn.frvr.ai/6883bb65c6933e24c6f93380.png%3F3) 
 Change the text to say Shop
:quality(85)/https://cdn.frvr.ai/6883ca13c6933e24c6f93407.png%3F3) 
 An old style cash register. The numeric read out says 7.77. Anime style.. In-Game asset. 2d. High contrast. No shadows
:quality(85)/https://cdn.frvr.ai/68843ffdc4bce55370ff2d52.png%3F3) 
 A giant question mark. Anime style.. In-Game asset. 2d. High contrast. No shadows
:quality(85)/https://cdn.frvr.ai/6885b96abaf3f7950670e1f2.png%3F3) 
 A shield with a spade and heart card suit coat of arms on it with a sword crossed downwards, behind it. icon. Anime style.. In-Game asset. 2d. High contrast. No shadows
:quality(85)/https://cdn.frvr.ai/6886e81a8cf41ec47abf883d.png%3F3) 
 :quality(85)/https://cdn.frvr.ai/6889a07547ed6e06649e3a8a.png%3F3) 
 Change the text to say ‘Draw’
:quality(85)/https://cdn.frvr.ai/6889a49947ed6e06649e3a98.png%3F3) 
 The back of a playing card. Blue pattern. Anime style.. In-Game asset. 2d. High contrast. No shadows
:quality(85)/https://cdn.frvr.ai/6889a92547ed6e06649e3aaf.png%3F3) 
 The back of a playing card. Red pattern with a heart in the center. Anime style.. In-Game asset. 2d. High contrast. No shadows
:quality(85)/https://cdn.frvr.ai/6891494cceeb57e4193a1530.png%3F3) 
 Change the blue color to gold and put a blue glowing shield in the center.
:quality(85)/https://cdn.frvr.ai/68914a64ceeb57e4193a153c.png%3F3) 
 Change the image of the shield in the center into a red question mark lined with gold.
:quality(85)/https://cdn.frvr.ai/68914c12ceeb57e4193a1553.png%3F3) 
 Change the image of a shield in the center into a robotic cheetah head. Change the background color in the center to green.
:quality(85)/https://cdn.frvr.ai/68914caaceeb57e4193a155a.png%3F3) 
 Change the image of the shield into the center to a steel padlock with a keyhole on it. Change the background color in the center to yellow.
:quality(85)/https://cdn.frvr.ai/689e5938228ee267e70f6f8f.png%3F3) 
 Change the shield in the center to a picture of a winding snake and the background color in the center in purple.
:quality(85)/https://cdn.frvr.ai/68a3557aa04296e51096d9ea.png%3F3) 
 Change the word to say Slots
:quality(85)/https://cdn.frvr.ai/68a355fda04296e51096d9f0.png%3F3) 
 An icon of a slot machine. Anime style. High definition.. In-Game asset. 2d. High contrast. No shadows
:quality(85)/https://cdn.frvr.ai/68a3580ba04296e51096da04.png%3F3) 
 :quality(85)/https://cdn.frvr.ai/68a3583aa04296e51096da0e.png%3F3) 
 :quality(85)/https://cdn.frvr.ai/68a35872a04296e51096da11.png%3F3) 
 :quality(85)/https://cdn.frvr.ai/68a358a2a04296e51096da1a.png%3F3) 
 :quality(85)/https://cdn.frvr.ai/68a358d2a04296e51096da2d.png%3F3) 
 :quality(85)/https://cdn.frvr.ai/68a3f7a67ee4f25be27b2da9.png%3F3) 
 A “Spin” button for an electronic slot machine. Button is red and font is in yellow. Anime style. High definition.. In-Game asset. 2d. High contrast. No shadows
:quality(85)/https://cdn.frvr.ai/68a4cfea59adff9cca0cecda.png%3F3) 
 Create a symbol that’s just the white cats head looking straight forward with X’s for eyes and his tongue hanging out of the side of his mouth.
:quality(85)/https://cdn.frvr.ai/68a512866707d7644cd73f6d.png%3F3) 
 Change the text to say Paytable and adjust button shape to accommodate.
:quality(85)/https://cdn.frvr.ai/68a521877529137351ef5d96.png%3F3) 
 Change the button to say $10 and make it square.
:quality(85)/https://cdn.frvr.ai/68a5417f9e37e9dfd016d98d.png%3F3) 
 Change the button to say $25
:quality(85)/https://cdn.frvr.ai/68a541b29e37e9dfd016d993.png%3F3) 
 Change the button to say $50
:quality(85)/https://cdn.frvr.ai/68a542419e37e9dfd016d99c.png%3F3) 
 Change the button to say $100
:quality(85)/https://cdn.frvr.ai/68a6be01dd1d8ce0b5ce77ad.png%3F3) 
 :quality(85)/https://cdn.frvr.ai/68a75eb4af1b80c0d8e614c3.png%3F3) 
 Change the button color to light green.
:quality(85)/https://cdn.frvr.ai/68a75f17af1b80c0d8e614c9.png%3F3) 
 Change the button color to light green.
:quality(85)/https://cdn.frvr.ai/68a76491af1b80c0d8e61515.png%3F3) 
 Change the button color to light green.
:quality(85)/https://cdn.frvr.ai/68a76511af1b80c0d8e61522.png%3F3) 
 Change the button color to light green.
:quality(85)/https://cdn.frvr.ai/68a8e3f18f1da99e0db46a6a.png%3F3) 
 Add an icon of the four card suits in the center of the heart. Anime style.
:quality(85)/https://cdn.frvr.ai/68a8e7b7b101b8249c0a7a41.png%3F3) 
 Just the spade from this picture with an icon of a cartoon spy with a hood and a mask on in the center of the spade.
:quality(85)/https://cdn.frvr.ai/68a8e9c0b101b8249c0a7a63.png%3F3) 
 Just the club from this picture with a small bubbling green vial of poison in the center of it. Anime style.
:quality(85)/https://cdn.frvr.ai/68a8eb500d34fbb62cbc4683.png%3F3) 
 Just the diamond from this picture with an icon of a scale in the center.
titleSong
Music
pvpMusic
Music
getReady
Sound effect
gameStart
Sound effect
cardLand
Sound effect
shootSound
Sound effect
levelUp
Sound effect
buttonPress
Sound effect
pokerChipDie
Sound effect
roulette
Sound effect
victory
Sound effect
defeat
Sound effect
slotButton
Sound effect
slotSpin
Sound effect
reelStop
Sound effect
slotWin
Sound effect