User prompt
Use the five different colored poker chip assets for the 5 different poker chip enemies.
User prompt
Move the background up to the top of the screen.
Code edit (2 edits merged)
Please save this source code
User prompt
Move the player play area, hand and deal button down 15% on the screen, keeping current relationship.
User prompt
Move the player play area, hand and deal button down 20% on the screen, keeping current relationship.
User prompt
Increase card size by 50% and adjust spacing of hand and play area to compensate.
User prompt
Place background in the center of the screen.
User prompt
Jokers can’t be merged with, but they can merge with any other card no matter the level.
User prompt
Joker doesn’t need to have a level.
User prompt
Cards should be able to be combined in the players hand.
User prompt
Half enemy speed and spawn the enemies closer together.
User prompt
Combining logic isn’t working right. It should remove the two old cards and create the leveled up card. Analyze.
User prompt
Update only as needed with: var WaveSystem = { playerWaveTimer: 0, aiWaveTimer: 0, waveInterval: 300, // 5 seconds between waves (increased for balance) waveNumber: 1, getWaveData: function(waveNum) { var wave = { chips: [] }; // Early waves (1-5): Mostly 1-value chips if (waveNum <= 5) { var chipCount = Math.min(3 + Math.floor(waveNum / 2), 6); for (var i = 0; i < chipCount; i++) { wave.chips.push({ value: 1, delay: i * 800 // 0.8 second delay between each chip }); } } // Medium waves (6-15): Mix of 1s and 5s else if (waveNum <= 15) { var chipCount = Math.min(4 + Math.floor(waveNum / 3), 8); for (var i = 0; i < chipCount; i++) { var value = (i < 2 || Math.random() < 0.7) ? 1 : 5; wave.chips.push({ value: value, delay: i * 600 // Faster spawning }); } } // Later waves: More variety and higher values else { var chipCount = Math.min(5 + Math.floor(waveNum / 4), 10); for (var i = 0; i < chipCount; i++) { var value; var rand = Math.random(); if (rand < 0.4) value = 1; else if (rand < 0.7) value = 5; else if (rand < 0.9) value = 10; else value = 25; wave.chips.push({ value: value, delay: i * 500 }); } } return wave; }, spawnWave: function(isPlayerSide) { var waveData = this.getWaveData(this.waveNumber); console.log('Spawning wave', this.waveNumber, 'with', waveData.chips.length, 'chips on', isPlayerSide ? 'player' : 'AI', 'side'); waveData.chips.forEach(function(chipInfo, index) { setTimeout(function() { ChipSpawner.spawnChip(chipInfo.value, isPlayerSide); }, chipInfo.delay); }); }, update: function() { // Spawn waves on player side (enemies for player to fight) this.playerWaveTimer++; if (this.playerWaveTimer >= this.waveInterval) { this.playerWaveTimer = 0; this.spawnWave(true); } // Spawn waves on AI side (enemies for AI to fight) this.aiWaveTimer++; if (this.aiWaveTimer >= this.waveInterval) { this.aiWaveTimer = 0; this.spawnWave(false); } // Increase wave number when both sides have spawned if (this.playerWaveTimer === 0 && this.aiWaveTimer === 0) { this.waveNumber++; // Decrease wave interval slightly as game progresses (but not too fast) this.waveInterval = Math.max(240, this.waveInterval - 2); } } }; /**** * Updated Starting Resources ****/ var gameState = { playerGold: 200, // Increased starting gold aiGold: 200, playerLives: 3, aiLives: 3, isPlayerTurn: true, dealCost: 75, // Increased deal cost to match new economy dealCount: 0, playerDeck: [], playerHand: [], playerPlayArea: [], aiDeck: [], aiPlayArea: [] }; /**** * Update deal button text ****/ var dealButtonText = new Text2('Deal (75)', { size: 40, fill: 0xffffff, weight: 800 }); /**** * Updated Gold Display ****/ var playerGoldText = new Text2('Gold: 200', { size: 50, fill: 0xffd700, weight: 800 }); var aiGoldText = new Text2('AI Gold: 200', { size: 40, fill: 0xffd700, weight: 800 });
User prompt
Update as needed with: var WaveSystem = { playerWaveTimer: 0, aiWaveTimer: 0, waveInterval: 300, // 5 seconds between waves (increased for balance) waveNumber: 1, getWaveData: function(waveNum) { var wave = { chips: [] }; // Early waves (1-5): Mostly 1-value chips if (waveNum <= 5) { var chipCount = Math.min(3 + Math.floor(waveNum / 2), 6); for (var i = 0; i < chipCount; i++) { wave.chips.push({ value: 1, delay: i * 800 // 0.8 second delay between each chip }); } } // Medium waves (6-15): Mix of 1s and 5s else if (waveNum <= 15) { var chipCount = Math.min(4 + Math.floor(waveNum / 3), 8); for (var i = 0; i < chipCount; i++) { var value = (i < 2 || Math.random() < 0.7) ? 1 : 5; wave.chips.push({ value: value, delay: i * 600 // Faster spawning }); } } // Later waves: More variety and higher values else { var chipCount = Math.min(5 + Math.floor(waveNum / 4), 10); for (var i = 0; i < chipCount; i++) { var value; var rand = Math.random(); if (rand < 0.4) value = 1; else if (rand < 0.7) value = 5; else if (rand < 0.9) value = 10; else value = 25; wave.chips.push({ value: value, delay: i * 500 }); } } return wave; }, spawnWave: function(isPlayerSide) { var waveData = this.getWaveData(this.waveNumber); console.log('Spawning wave', this.waveNumber, 'with', waveData.chips.length, 'chips on', isPlayerSide ? 'player' : 'AI', 'side'); waveData.chips.forEach(function(chipInfo, index) { setTimeout(function() { ChipSpawner.spawnChip(chipInfo.value, isPlayerSide); }, chipInfo.delay); }); }, update: function() { // Spawn waves on player side (enemies for player to fight) this.playerWaveTimer++; if (this.playerWaveTimer >= this.waveInterval) { this.playerWaveTimer = 0; this.spawnWave(true); } // Spawn waves on AI side (enemies for AI to fight) this.aiWaveTimer++; if (this.aiWaveTimer >= this.waveInterval) { this.aiWaveTimer = 0; this.spawnWave(false); } // Increase wave number when both sides have spawned if (this.playerWaveTimer === 0 && this.aiWaveTimer === 0) { this.waveNumber++; // Decrease wave interval slightly as game progresses (but not too fast) this.waveInterval = Math.max(240, this.waveInterval - 2); } } }; /**** * Updated Starting Resources ****/ var gameState = { playerGold: 200, // Increased starting gold aiGold: 200, playerLives: 3, aiLives: 3, isPlayerTurn: true, dealCost: 75, // Increased deal cost to match new economy dealCount: 0, playerDeck: [], playerHand: [], playerPlayArea: [], aiDeck: [], aiPlayArea: [] }; /**** * Update deal button text ****/ var dealButtonText = new Text2('Deal (75)', { size: 40, fill: 0xffffff, weight: 800 }); /**** * Updated Gold Display ****/ var playerGoldText = new Text2('Gold: 200', { size: 50, fill: 0xffd700, weight: 800 }); var aiGoldText = new Text2('AI Gold: 200', { size: 40, fill: 0xffd700, weight: 800 });
User prompt
Update only as needed with: 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.1; self.pathProgress = 0; self.isPlayerSide = true; // ... visual setup stays the same ... self.activate = function(value, isPlayerSide) { self.active = true; self.visible = true; self.value = value; self.isPlayerSide = isPlayerSide; // Health scales with chip value - more valuable chips are tankier self.maxHealth = value * 50; // Much higher base health self.health = self.maxHealth; self.pathProgress = 0; self.setChipAppearance(); var startPos = PathSystem.getPathStart(isPlayerSide); self.x = startPos.x; self.y = startPos.y; }; self.setChipAppearance = function() { var colors = { 1: 0xffffff, // White - 50 HP 5: 0xff0000, // Red - 250 HP 10: 0x00ff00, // Green - 500 HP 25: 0x000000, // Black - 1250 HP 100: 0x800080 // Purple - 5000 HP }; chipGraphics.tint = colors[self.value] || 0xffffff; valueText.setText(self.value.toString()); // Show health on larger chips if (self.value >= 5) { valueText.setText(self.value + '\n' + self.health); } }; self.takeDamage = function(damage) { self.health -= damage; // Update visual if showing health if (self.value >= 5) { valueText.setText(self.value + '\n' + Math.max(0, self.health)); } // Flash red when taking damage var originalTint = chipGraphics.tint; chipGraphics.tint = 0xff6666; setTimeout(function() { chipGraphics.tint = originalTint; }, 100); if (self.health <= 0) { self.die(); } }; // ... rest of PokerChip stays the same ... return self; });
User prompt
Update as needed with: var Card = Container.expand(function(cardData) { var self = Container.call(this); self.cardData = cardData; self.level = 1; self.isInPlay = false; self.isPlayerCard = true; self.playSlotX = 0; self.playSlotY = 0; self.lastFired = 0; self.fireRate = 60; // Base fire rate (ticks between shots) self.damage = 25; // Increased base damage self.range = 200; self.handBonus = 1; // ... visual setup code stays the same ... self.calculateStats = function() { // Stats based on level only, not card face value var baseDamage = 25; // Increased from 10 var baseFireRate = 60; // Level scaling - more dramatic improvements per level self.damage = Math.floor(baseDamage * Math.pow(1.8, self.level - 1)); // Increased scaling self.fireRate = Math.max(15, Math.floor(baseFireRate / Math.pow(1.3, self.level - 1))); // Apply poker hand bonus self.damage = Math.floor(self.damage * self.handBonus); self.fireRate = Math.max(10, Math.floor(self.fireRate / self.handBonus)); }; // ... rest of Card class stays the same ... return self; });
User prompt
Update as needed with: var AISystem = { thinkTimer: 0, thinkDelay: 60, // Think every second (60 ticks) dealTimer: 0, dealDelay: 300, // Deal every 5 seconds initially update: function() { this.thinkTimer++; this.dealTimer++; if (this.thinkTimer >= this.thinkDelay) { this.thinkTimer = 0; this.makeMove(); } if (this.dealTimer >= this.dealDelay && this.shouldDeal()) { this.dealTimer = 0; this.dealAIHand(); this.dealDelay = Math.max(180, this.dealDelay - 10); // Deal faster as game progresses } }, shouldDeal: function() { // Deal if we can afford it and have empty slots or low-level cards if (gameState.aiGold < gameState.dealCost) return false; var emptySlots = this.countEmptySlots(); var lowLevelCards = this.countLowLevelCards(); // Deal if we have empty slots or mostly low-level cards return emptySlots > 2 || lowLevelCards > 6; }, countEmptySlots: function() { 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; }, countLowLevelCards: function() { 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; }, makeMove: function() { // Priority order: Merge cards > Place cards > Optimize positions if (this.tryMergeCards()) { // Successfully merged, wait for next think cycle return; } if (this.tryPlaceCards()) { // Successfully placed cards return; } this.optimizeCardPositions(); }, tryMergeCards: function() { // Look for mergeable cards 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; // Look for a card to merge with 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) continue; if (card1.canMergeWith(card2)) { this.mergeCards(card1, card2, row1, col1, row2, col2); return true; } } } } } return false; }, mergeCards: function(card1, card2, row1, col1, row2, col2) { var mergedCard = card1.mergeWith(card2); if (mergedCard) { // Remove old cards gameLayer.removeChild(card1); gameLayer.removeChild(card2); gameState.aiPlayArea[row1][col1] = null; gameState.aiPlayArea[row2][col2] = null; // Place merged card in the first position var pos = getSlotPosition(row1, col1, false); mergedCard.activate(pos.x, pos.y, true, false); gameLayer.addChild(mergedCard); gameState.aiPlayArea[row1][col1] = mergedCard; // Merge animation mergedCard.alpha = 0; mergedCard.scaleX = mergedCard.scaleY = 1.5; tween(mergedCard, { alpha: 1, scaleX: 1, scaleY: 1 }, { duration: 200, easing: tween.elasticOut }); this.applyAIHandBonuses(); } }, tryPlaceCards: function() { // AI doesn't have a "hand" like player, it deals directly to board // This function is for future expansion return false; }, optimizeCardPositions: function() { // Move stronger cards to better positions (like completing poker hands) // For now, just try to complete rows for hand bonuses this.tryCompletePokerHands(); }, tryCompletePokerHands: function() { for (var row = 0; row < PLAY_AREA_ROWS; row++) { var rowCards = []; var emptyPositions = []; for (var col = 0; col < PLAY_AREA_COLS; col++) { if (gameState.aiPlayArea[row][col]) { rowCards.push({card: gameState.aiPlayArea[row][col], col: col}); } else { emptyPositions.push(col); } } // If row is almost complete, try to fill it strategically if (rowCards.length >= 3 && emptyPositions.length > 0) { // Look for cards in other rows that might complete a hand this.tryMoveCardToCompleteHand(row, rowCards, emptyPositions[0]); } } }, tryMoveCardToCompleteHand: function(targetRow, existingCards, targetCol) { // Look for cards in other positions that might help complete a hand for (var row = 0; row < PLAY_AREA_ROWS; row++) { if (row === targetRow) continue; for (var col = 0; col < PLAY_AREA_COLS; col++) { var card = gameState.aiPlayArea[row][col]; if (!card) continue; // Simple heuristic: move cards of same suit or sequential values var shouldMove = this.cardHelpsHand(card, existingCards); if (shouldMove && Math.random() < 0.3) { // 30% chance to move // Move the card gameState.aiPlayArea[row][col] = null; gameState.aiPlayArea[targetRow][targetCol] = card; var newPos = getSlotPosition(targetRow, targetCol, false); tween(card, {x: newPos.x, y: newPos.y}, { duration: 300, easing: tween.quadOut }); this.applyAIHandBonuses(); return; } } } }, cardHelpsHand: function(card, existingCards) { // Simple heuristic to see if a card might help complete a poker hand var suits = {}; var values = {}; existingCards.forEach(function(cardInfo) { var c = cardInfo.card.cardData; suits[c.suit] = (suits[c.suit] || 0) + 1; values[c.value] = (values[c.value] || 0) + 1; }); // Check if card matches existing suits or values var cardSuit = card.cardData.suit; var cardValue = card.cardData.value; return suits[cardSuit] >= 2 || values[cardValue] >= 1; }, dealAIHand: function() { if (gameState.aiGold < gameState.dealCost) return; gameState.aiGold -= gameState.dealCost; // Deal cards directly to empty slots in AI play area var cardsDealt = 0; var maxCards = Math.min(5, this.countEmptySlots()); for (var attempt = 0; attempt < maxCards; attempt++) { if (gameState.aiDeck.length === 0) { gameState.aiDeck = CardSystem.createDeck(); } var cardData = gameState.aiDeck.pop(); var card = new Card(cardData); // Find best empty slot (prefer completing rows) var bestSlot = this.findBestEmptySlot(); if (bestSlot) { var pos = getSlotPosition(bestSlot.row, bestSlot.col, false); card.activate(pos.x, pos.y, true, false); gameLayer.addChild(card); gameState.aiPlayArea[bestSlot.row][bestSlot.col] = card; cardsDealt++; // Deal animation card.alpha = 0; card.scaleX = card.scaleY = 0.5; tween(card, { alpha: 1, scaleX: 1, scaleY: 1 }, { duration: 300, easing: tween.elasticOut }); } else { break; // No empty slots } } if (cardsDealt > 0) { this.applyAIHandBonuses(); } }, findBestEmptySlot: function() { var emptySlots = []; for (var row = 0; row < PLAY_AREA_ROWS; row++) { for (var col = 0; col < PLAY_AREA_COLS; col++) { if (!gameState.aiPlayArea[row][col]) { var score = this.evaluateSlotScore(row, col); emptySlots.push({row: row, col: col, score: score}); } } } if (emptySlots.length === 0) return null; // Sort by score (higher is better) emptySlots.sort(function(a, b) { return b.score - a.score; }); return emptySlots[0]; }, evaluateSlotScore: function(row, col) { var score = 0; var cardsInRow = 0; // Count cards in this row for (var c = 0; c < PLAY_AREA_COLS; c++) { if (gameState.aiPlayArea[row][c]) cardsInRow++; } // Prefer completing rows score += cardsInRow * 10; // Slight preference for middle positions score += (2 - Math.abs(col - 2)) * 2; return score; }, applyAIHandBonuses: function() { // Apply poker hand bonuses to AI cards for (var row = 0; row < PLAY_AREA_ROWS; row++) { var handEval = evaluateRowHand(row, false); for (var col = 0; col < PLAY_AREA_COLS; col++) { var card = gameState.aiPlayArea[row][col]; if (card) { card.handBonus = handEval.multiplier; card.calculateStats(); } } } } }; /**** * Update the main game loop to make sure AI bonuses are applied ****/ function applyHandBonuses() { // Apply bonuses to player cards for (var row = 0; row < PLAY_AREA_ROWS; row++) { var handEval = evaluateRowHand(row, true); for (var col = 0; col < PLAY_AREA_COLS; col++) { var card = gameState.playerPlayArea[row][col]; if (card) { card.handBonus = handEval.multiplier; card.calculateStats(); } } } // Apply bonuses to AI cards AISystem.applyAIHandBonuses(); } ↪💡 Consider importing and using the following plugins: @upit/tween.v1
User prompt
Please fix the bug: 'Script error.' in or related to this line: 'location.reload();' Line Number: 1458
User prompt
Update as needed with: function dealNewHand() { if (gameState.playerGold < gameState.dealCost) return; gameState.playerGold -= gameState.dealCost; gameState.dealCount++; gameState.dealCost = Math.floor(50 * Math.pow(1.2, gameState.dealCount)); // Clear current hand gameState.playerHand.forEach(card => { if (card) uiLayer.removeChild(card); }); gameState.playerHand = []; // Deal 5 new cards for (var i = 0; i < 5; i++) { if (gameState.playerDeck.length === 0) { gameState.playerDeck = CardSystem.createDeck(); } var cardData = gameState.playerDeck.pop(); var card = new Card(cardData); var slotX = PLAYER_AREA_X + i * DEAL_SLOT_WIDTH + (i * 20) + DEAL_SLOT_WIDTH/2; var slotY = PLAYER_DEAL_AREA_Y + DEAL_SLOT_HEIGHT/2; card.activate(slotX, slotY, false, true); // true = is player card uiLayer.addChild(card); gameState.playerHand[i] = card; } updateUI(); } /**** * Update AI card creation ****/ var AISystem = { // ... existing code ... dealAIHand: function() { gameState.aiGold -= gameState.dealCost; for (var attempt = 0; attempt < 5; attempt++) { if (gameState.aiDeck.length === 0) { gameState.aiDeck = CardSystem.createDeck(); } var cardData = gameState.aiDeck.pop(); var card = new Card(cardData); var placed = false; for (var row = 0; row < PLAY_AREA_ROWS && !placed; row++) { for (var col = 0; col < PLAY_AREA_COLS && !placed; col++) { if (!gameState.aiPlayArea[row][col]) { var pos = getSlotPosition(row, col, false); card.activate(pos.x, pos.y, true, false); // false = is AI card gameLayer.addChild(card); gameState.aiPlayArea[row][col] = card; placed = true; } } } if (!placed) break; } } };
User prompt
Update only as needed with: 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; self.damage = 10; self.range = 200; self.handBonus = 1; // ... all the visual setup code stays the same ... 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; if (inPlay) { self.calculateStats(); } }; self.findTarget = function() { // Player cards target enemies attacking the player (activePlayerChips) // AI cards target enemies attacking the AI (activeAIChips) var targets = self.isPlayerCard ? activePlayerChips : activeAIChips; for (var i = 0; i < targets.length; i++) { if (targets[i].active) { return targets[i]; } } return null; }; // ... rest of the methods stay the same ... return self; });
Code edit (1 edits merged)
Please save this source code
User prompt
Update as needed with: var PokerChip = Container.expand(function() { var self = Container.call(this); self.active = false; self.health = 10; self.maxHealth = 10; self.value = 1; self.speed = 0.5; // Much slower! Was 2, now 0.5 self.pathProgress = 0; self.isPlayerSide = true; // ... rest of PokerChip class stays the same var chipGraphics = self.attachAsset('pokerChip', { anchorX: 0.5, anchorY: 0.5 }); var valueText = new Text2('1', { size: 30, fill: 0xffffff, weight: 800 }); valueText.anchor.set(0.5, 0.5); self.addChild(valueText); self.activate = function(value, isPlayerSide) { self.active = true; self.visible = true; self.value = value; self.isPlayerSide = isPlayerSide; self.health = self.maxHealth = value; self.pathProgress = 0; self.setChipAppearance(); var startPos = PathSystem.getPathStart(isPlayerSide); self.x = startPos.x; self.y = startPos.y; }; self.setChipAppearance = function() { var colors = { 1: 0xffffff, // White 5: 0xff0000, // Red 10: 0x00ff00, // Green 25: 0x000000, // Black 100: 0x800080 // Purple }; chipGraphics.tint = colors[self.value] || 0xffffff; valueText.setText(self.value.toString()); }; self.takeDamage = function(damage) { self.health -= damage; if (self.health <= 0) { self.die(); } }; self.die = function() { var goldEarned = self.value; if (self.isPlayerSide) { gameState.playerGold += goldEarned; } else { gameState.aiGold += goldEarned; } PoolManager.returnChip(self); }; self.update = function() { if (!self.active) return; self.pathProgress += self.speed; var pathPos = PathSystem.getPositionAlongPath(self.pathProgress, self.isPlayerSide); if (pathPos.completed) { if (self.isPlayerSide) { gameState.playerLives--; } else { gameState.aiLives--; } PoolManager.returnChip(self); return; } self.x = pathPos.x; self.y = pathPos.y; }; return self; }); /**** * Wave Spawning System ****/ var WaveSystem = { playerWaveTimer: 0, aiWaveTimer: 0, waveInterval: 180, // 3 seconds between spawns waveNumber: 1, // Wave difficulty scaling getWaveData: function(waveNum) { var baseValue = 1; var maxValue = Math.min(10, Math.floor(1 + waveNum / 3)); // Increase max value every 3 waves var spawnCount = Math.min(5, Math.floor(1 + waveNum / 5)); // More enemies every 5 waves return { minValue: baseValue, maxValue: maxValue, count: spawnCount }; }, spawnWave: function(isPlayerSide) { var waveData = this.getWaveData(this.waveNumber); for (var i = 0; i < waveData.count; i++) { var chipValue = Math.floor(Math.random() * (waveData.maxValue - waveData.minValue + 1)) + waveData.minValue; // Delay each spawn in the wave (function(value, side, delay) { setTimeout(function() { ChipSpawner.spawnChip(value, side); }, delay); })(chipValue, isPlayerSide, i * 1000); // 1 second delay between each chip in wave } }, update: function() { // Spawn waves on player side (enemies for player to fight) this.playerWaveTimer++; if (this.playerWaveTimer >= this.waveInterval) { this.playerWaveTimer = 0; this.spawnWave(true); // Spawn on player side for player to defend against } // Spawn waves on AI side (enemies for AI to fight) this.aiWaveTimer++; if (this.aiWaveTimer >= this.waveInterval) { this.aiWaveTimer = 0; this.spawnWave(false); // Spawn on AI side for AI to defend against } // Increase wave difficulty every 10 waves if (this.playerWaveTimer === 0 && this.aiWaveTimer === 0) { this.waveNumber++; } } }; /**** * Updated initializeGame function ****/ function initializeGame() { PoolManager.init(); PathSystem.init(); // Initialize play areas gameState.playerPlayArea = []; gameState.aiPlayArea = []; 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(); // Deal initial hand dealNewHand(); // Start the wave system - first waves begin immediately setTimeout(function() { ChipSpawner.spawnChip(1, true); // First enemy on player side ChipSpawner.spawnChip(1, false); // First enemy on AI side }, 1000); } /**** * Updated main game loop ****/ game.update = function() { // 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(); } // 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 if (gameState.playerLives <= 0) { showGameOver(false); } else if (gameState.aiLives <= 0) { showGameOver(true); } updateUI(); }; /**** * Add wave info to UI ****/ var waveText = new Text2('Wave: 1', { size: 40, fill: 0xffffff, weight: 800 }); waveText.x = SCREEN_WIDTH - 200; waveText.y = 50; uiLayer.addChild(waveText); // Update the updateUI function to include wave info function updateUI() { playerGoldText.setText('Gold: ' + gameState.playerGold); playerLivesText.setText('Lives: ' + gameState.playerLives); aiGoldText.setText('AI Gold: ' + gameState.aiGold); aiLivesText.setText('AI Lives: ' + gameState.aiLives); dealButtonText.setText('Deal (' + gameState.dealCost + ')'); waveText.setText('Wave: ' + WaveSystem.waveNumber); // Update button color based on affordability if (gameState.playerGold >= gameState.dealCost) { dealButtonGraphics.tint = 0x00aa00; } else { dealButtonGraphics.tint = 0x666666; } }
User prompt
Update as needed with: var PathSystem = { playerPath: [], aiPath: [], init: function() { // Create player path - rectangular loop around the play area var padding = 80; // Distance from play area var leftX = PLAYER_AREA_X - padding; var rightX = PLAYER_AREA_X + (PLAY_AREA_COLS * SLOT_WIDTH) + padding; var topY = PLAYER_AREA_Y - padding; var bottomY = PLAYER_AREA_Y + (PLAY_AREA_ROWS * SLOT_HEIGHT) + padding; 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 aiTopY = AI_AREA_Y - padding; var aiBottomY = AI_AREA_Y + (PLAY_AREA_ROWS * SLOT_HEIGHT) + padding; 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} ]; }, // ... rest of the PathSystem methods stay the same getPathStart: function(isPlayerSide) { return isPlayerSide ? this.playerPath[0] : this.aiPath[0]; }, getPositionAlongPath: function(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(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(p1, p2) { var dx = p2.x - p1.x; var dy = p2.y - p1.y; return Math.sqrt(dx * dx + dy * dy); } };
User prompt
Update as needed with: var SCREEN_WIDTH = 2048; var SCREEN_HEIGHT = 2732; var PLAY_AREA_COLS = 5; var PLAY_AREA_ROWS = 2; var SLOT_WIDTH = 200; var SLOT_HEIGHT = 280; var DEAL_SLOT_WIDTH = 160; var DEAL_SLOT_HEIGHT = 220; // 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 - 1200; // Much higher up // Player deal area (hand slots) - below play area var PLAYER_DEAL_AREA_Y = PLAYER_AREA_Y + (PLAY_AREA_ROWS * SLOT_HEIGHT) + 40; // Deal button position - below hand slots with plenty of room var DEAL_BUTTON_Y = PLAYER_DEAL_AREA_Y + DEAL_SLOT_HEIGHT + 60; /**** * Updated Path System with Rectangular Paths ****/ var PathSystem = { playerPath: [], aiPath: [], init: function() { // Create player path - rectangular loop around the play area var padding = 80; // Distance from play area var leftX = PLAYER_AREA_X - padding; var rightX = PLAYER_AREA_X + (PLAY_AREA_COLS * SLOT_WIDTH) + padding; var topY = PLAYER_AREA_Y - padding; var bottomY = PLAYER_AREA_Y + (PLAY_AREA_ROWS * SLOT_HEIGHT) + padding; 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 - rectangular loop around the AI play area var aiLeftX = AI_AREA_X - padding; var aiRightX = AI_AREA_X + (PLAY_AREA_COLS * SLOT_WIDTH) + padding; var aiTopY = AI_AREA_Y - padding; var aiBottomY = AI_AREA_Y + (PLAY_AREA_ROWS * SLOT_HEIGHT) + padding; this.aiPath = [ // Start at bottom left {x: aiLeftX, y: aiBottomY}, // Go up the left side {x: aiLeftX, y: aiTopY}, // Go across the top {x: aiRightX, y: aiTopY}, // Go down the right side {x: aiRightX, y: aiBottomY} ]; }, getPathStart: function(isPlayerSide) { return isPlayerSide ? this.playerPath[0] : this.aiPath[0]; }, getPositionAlongPath: function(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(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(p1, p2) { var dx = p2.x - p1.x; var dy = p2.y - p1.y; return Math.sqrt(dx * dx + dy * dy); } }; /**** * Updated UI Elements Positioning ****/ var playerGoldText = new Text2('Gold: 100', { size: 50, fill: 0xffd700, weight: 800 }); playerGoldText.x = 50; playerGoldText.y = SCREEN_HEIGHT - 120; uiLayer.addChild(playerGoldText); var playerLivesText = new Text2('Lives: 3', { size: 50, fill: 0xff0000, weight: 800 }); playerLivesText.x = 50; playerLivesText.y = SCREEN_HEIGHT - 180; uiLayer.addChild(playerLivesText); // Add AI stats too for clarity var aiGoldText = new Text2('AI Gold: 100', { size: 40, fill: 0xffd700, weight: 800 }); aiGoldText.x = 50; aiGoldText.y = 50; uiLayer.addChild(aiGoldText); var aiLivesText = new Text2('AI Lives: 3', { size: 40, fill: 0xff0000, weight: 800 }); aiLivesText.x = 50; aiLivesText.y = 100; uiLayer.addChild(aiLivesText); var dealButton = new Container(); var dealButtonGraphics = dealButton.attachAsset('dealButton', { anchorX: 0.5, anchorY: 0.5 }); var dealButtonText = new Text2('Deal (50)', { size: 40, fill: 0xffffff, weight: 800 }); dealButtonText.anchor.set(0.5, 0.5); dealButton.addChild(dealButtonText); dealButton.x = SCREEN_WIDTH / 2; dealButton.y = DEAL_BUTTON_Y; uiLayer.addChild(dealButton); /**** * Update the updateUI function to include AI stats ****/ function updateUI() { playerGoldText.setText('Gold: ' + gameState.playerGold); playerLivesText.setText('Lives: ' + gameState.playerLives); aiGoldText.setText('AI Gold: ' + gameState.aiGold); aiLivesText.setText('AI Lives: ' + gameState.aiLives); dealButtonText.setText('Deal (' + gameState.dealCost + ')'); // Update button color based on affordability if (gameState.playerGold >= gameState.dealCost) { dealButtonGraphics.tint = 0x00aa00; } else { dealButtonGraphics.tint = 0x666666; } }
User prompt
Update as needed with: var SCREEN_WIDTH = 2048; var SCREEN_HEIGHT = 2732; var PLAY_AREA_COLS = 5; var PLAY_AREA_ROWS = 2; var SLOT_WIDTH = 200; var SLOT_HEIGHT = 280; var DEAL_SLOT_WIDTH = 160; var DEAL_SLOT_HEIGHT = 220; // AI area positioning (top) var AI_AREA_X = (SCREEN_WIDTH - (PLAY_AREA_COLS * SLOT_WIDTH)) / 2; var AI_AREA_Y = 100; // Moved up a bit // Player area positioning (middle-bottom, with room for hand below) var PLAYER_AREA_X = (SCREEN_WIDTH - (PLAY_AREA_COLS * SLOT_WIDTH)) / 2; var PLAYER_AREA_Y = SCREEN_HEIGHT - 800; // Much higher up to leave room // Player deal area (hand slots) - below play area var PLAYER_DEAL_AREA_Y = PLAYER_AREA_Y + (PLAY_AREA_ROWS * SLOT_HEIGHT) + 20; // 20px gap // Deal button position - below hand slots var DEAL_BUTTON_Y = PLAYER_DEAL_AREA_Y + DEAL_SLOT_HEIGHT + 30; // 30px gap below hand ``` And update the UI elements positioning: ```javascript /**** * Updated UI Elements Positioning ****/ var playerGoldText = new Text2('Gold: 100', { size: 50, fill: 0xffd700, weight: 800 }); playerGoldText.x = 50; playerGoldText.y = SCREEN_HEIGHT - 80; // Moved up from bottom uiLayer.addChild(playerGoldText); var playerLivesText = new Text2('Lives: 3', { size: 50, fill: 0xff0000, weight: 800 }); playerLivesText.x = 50; playerLivesText.y = SCREEN_HEIGHT - 140; // Moved up from bottom uiLayer.addChild(playerLivesText); var dealButton = new Container(); var dealButtonGraphics = dealButton.attachAsset('dealButton', { anchorX: 0.5, anchorY: 0.5 }); var dealButtonText = new Text2('Deal (50)', { size: 40, fill: 0xffffff, weight: 800 }); dealButtonText.anchor.set(0.5, 0.5); dealButton.addChild(dealButtonText); dealButton.x = SCREEN_WIDTH / 2; dealButton.y = DEAL_BUTTON_Y; // Use the new constant uiLayer.addChild(dealButton); ``` And update the `drawPlayAreas` function to use the correct AI positioning: ```javascript function drawPlayAreas() { // Draw player 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('playSlot', { anchorX: 0.5, anchorY: 0.5 }); slotGraphics.alpha = 0.3; 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); } } // 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('playSlot', { anchorX: 0.5, anchorY: 0.5 }); slotGraphics.alpha = 0.3; slotGraphics.tint = 0x440000; // Red tint for AI area 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); } } // Draw player deal area slots (hand) 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.2; dealSlot.x = PLAYER_AREA_X + i * DEAL_SLOT_WIDTH + (i * 20) + DEAL_SLOT_WIDTH/2; dealSlot.y = PLAYER_DEAL_AREA_Y + DEAL_SLOT_HEIGHT/2; gameLayer.addChild(dealSlot); } }
/**** * Plugins ****/ var tween = LK.import("@upit/tween.v1"); /**** * Classes ****/ /**** * Bullet Class ****/ var Bullet = Container.expand(function () { var self = Container.call(this); self.active = false; self.target = null; self.damage = 10; self.speed = 8; var bulletGraphics = self.attachAsset('bullet', { anchorX: 0.5, anchorY: 0.5 }); self.activate = function (startX, startY, target, damage) { self.active = true; self.visible = true; self.x = startX; self.y = startY; self.target = target; self.damage = damage; }; self.update = function () { if (!self.active || !self.target || !self.target.active) { PoolManager.returnBullet(self); return; } var dx = self.target.x - self.x; var dy = self.target.y - self.y; var distance = Math.sqrt(dx * dx + dy * dy); if (distance < self.speed) { // Hit target self.target.takeDamage(self.damage); PoolManager.returnBullet(self); } else { var angle = Math.atan2(dy, dx); self.x += Math.cos(angle) * self.speed; self.y += Math.sin(angle) * self.speed; } }; return self; }); /**** * 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 = 25; // Increased base damage self.range = 200; self.handBonus = 1; 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 var valueText = new Text2(cardData.value, { size: 45, fill: CardSystem.suitColors[cardData.suit] || 0x000000, weight: 800 }); valueText.anchor.set(0, 0); valueText.x = -95; // Top left valueText.y = -135; self.addChild(valueText); // Large suit symbol in center var suitText = new Text2(self.getSuitSymbol(cardData.suit), { size: 120, fill: CardSystem.suitColors[cardData.suit] || 0x000000, weight: 800 }); suitText.anchor.set(0.5, 0.5); suitText.y = -15; // Slightly above center self.addChild(suitText); // Level text at bottom var levelText = new Text2('Lvl 1', { size: 38, fill: 0x000000, weight: 800 }); 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; if (inPlay) { self.calculateStats(); } }; self.calculateStats = function () { // Stats based on level only, not card face value var baseDamage = 25; // Increased from 10 var baseFireRate = 60; // Level scaling - more dramatic improvements per level self.damage = Math.floor(baseDamage * Math.pow(1.8, self.level - 1)); // Increased scaling self.fireRate = Math.max(15, Math.floor(baseFireRate / Math.pow(1.3, self.level - 1))); // Apply poker hand bonus self.damage = Math.floor(self.damage * self.handBonus); self.fireRate = Math.max(10, Math.floor(self.fireRate / self.handBonus)); }; 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(); // Visual feedback for higher levels if (self.level > 1) { var glowIntensity = Math.min(0.3, self.level * 0.05); cardGraphics.alpha = 1 + glowIntensity; } }; 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.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; } // 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; } var newCardData; var newLevel; // If the dragged card is a Joker, level up the target card if (self.cardData.suit === 'joker') { newCardData = otherCard.cardData; newLevel = otherCard.level + 1; } else { // Standard merge logic newLevel = self.level + 1; // Increase level by 1 if (self.cardData.suit === otherCard.cardData.suit) { // Same suit: random value, keep suit var randomValue = CardSystem.values[Math.floor(Math.random() * CardSystem.values.length)]; newCardData = { suit: self.cardData.suit, value: randomValue, id: self.cardData.suit + '_' + randomValue }; } else { // Same value: increase value by 1, random suit var currentValueIndex = CardSystem.values.indexOf(self.cardData.value); var nextValueIndex = (currentValueIndex + 1) % CardSystem.values.length; var randomSuit = CardSystem.suits[Math.floor(Math.random() * CardSystem.suits.length)]; newCardData = { suit: randomSuit, value: CardSystem.values[nextValueIndex], id: randomSuit + '_' + CardSystem.values[nextValueIndex] }; } } 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 = self.isPlayerCard ? activePlayerChips : activeAIChips; for (var i = 0; i < targets.length; i++) { if (targets[i].active) { return targets[i]; } } return null; }; self.fire = function () { var target = self.findTarget(); if (!target) { return; } var bullet = PoolManager.getBullet(); if (bullet) { bullet.activate(self.x, self.y, target, self.damage); gameLayer.addChild(bullet); activeBullets.push(bullet); self.lastFired = LK.ticks; // Visual feedback for firing tween.stop(self, { scaleX: true, scaleY: true }); tween(self, { scaleX: 0.9, scaleY: 0.9 }, { 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; } if (LK.ticks - self.lastFired >= self.fireRate) { self.fire(); } }; // Initialize with level 1 self.setLevel(1); 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; 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 valueText = new Text2('1', { size: 30, fill: 0xffffff, weight: 800 }); valueText.anchor.set(0.5, 0.5); self.addChild(valueText); self.activate = function (value, isPlayerSide) { self.active = true; self.visible = true; self.value = value; self.isPlayerSide = isPlayerSide; // Health scales with chip value - more valuable chips are tankier self.maxHealth = value * 50; // Much higher base health self.health = self.maxHealth; self.pathProgress = 0; self.setChipAppearance(); var startPos = PathSystem.getPathStart(isPlayerSide); self.x = startPos.x; self.y = startPos.y; }; self.setChipAppearance = function () { if (chipGraphics) { chipGraphics.visible = false; } chipGraphics = chipGraphicsAssets[self.value] || chipGraphicsAssets[1]; if (chipGraphics) { chipGraphics.visible = true; } valueText.setText(self.value.toString()); // Show health on larger chips if (self.value >= 5) { valueText.setText(self.value + '\n' + self.health); } }; self.takeDamage = function (damage) { self.health -= damage; // Update visual if showing health if (self.value >= 5) { valueText.setText(self.value + '\n' + Math.max(0, self.health)); } // Flash red when taking damage if (chipGraphics) { var originalTint = chipGraphics.tint; chipGraphics.tint = 0xff6666; LK.setTimeout(function () { if (chipGraphics) { chipGraphics.tint = originalTint; } }, 100); } if (self.health <= 0) { self.die(); } }; self.die = function () { var goldEarned = self.value; if (self.isPlayerSide) { gameState.playerGold += goldEarned; } else { gameState.aiGold += goldEarned; } PoolManager.returnChip(self); }; self.update = function () { if (!self.active) { return; } self.pathProgress += self.speed; var pathPos = PathSystem.getPositionAlongPath(self.pathProgress, self.isPlayerSide); if (pathPos.completed) { if (self.isPlayerSide) { gameState.playerLives--; } else { gameState.aiLives--; } PoolManager.returnChip(self); return; } self.x = pathPos.x; self.y = pathPos.y; }; return self; }); /**** * Initialize Game ****/ var game = new LK.Game({ backgroundColor: 0x0f3d0f }); /**** * Game Code ****/ /**** * Poker Tower Defense - Complete Refactor ****/ /**** * Game Constants ****/ 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 + 40; // Deal button position - below hand slots with plenty of room var DEAL_BUTTON_Y = PLAYER_DEAL_AREA_Y + DEAL_SLOT_HEIGHT + 60; /**** * 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 }, 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.suit === 'joker') { return 14; } // Jokers are highest if (card.value === 'A') { return 14; } // Aces high if (card.value === 'K') { return 13; } if (card.value === 'Q') { return 12; } if (card.value === 'J') { return 11; } return parseInt(card.value); }, evaluatePokerHand: function evaluatePokerHand(cards) { var _this = this; if (!cards || cards.length !== 5) { return { type: 'none', strength: 0 }; } // 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.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; }); var isFlush = Object.keys(suitCounts).length === 1; var isStraight = this.checkStraight(values); // Royal Flush if (isFlush && isStraight && values[0] === 14 && values[4] === 10) { return { type: 'royal_flush', strength: 10, multiplier: 50 }; } // Straight Flush if (isFlush && isStraight) { return { type: 'straight_flush', strength: 9, multiplier: 25 }; } // Four of a Kind if (counts[0] === 4) { return { type: 'four_of_a_kind', strength: 8, multiplier: 15 }; } // Full House if (counts[0] === 3 && counts[1] === 2) { return { type: 'full_house', strength: 7, multiplier: 8 }; } // Flush if (isFlush) { return { type: 'flush', strength: 6, multiplier: 5 }; } // Straight if (isStraight) { return { type: 'straight', strength: 5, multiplier: 4 }; } // Three of a Kind if (counts[0] === 3) { return { type: 'three_of_a_kind', strength: 4, multiplier: 3 }; } // Two Pair if (counts[0] === 2 && counts[1] === 2) { return { type: 'two_pair', strength: 3, multiplier: 2.5 }; } // One Pair if (counts[0] === 2) { return { type: 'one_pair', strength: 2, multiplier: 1.5 }; } // High Card return { type: 'high_card', strength: 1, multiplier: 1 }; }, 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: [], CHIP_POOL_SIZE: 50, BULLET_POOL_SIZE: 100, CARD_POOL_SIZE: 60, 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); } }, 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; }, returnChip: function returnChip(chip) { chip.active = false; chip.visible = false; // Remove from active arrays var playerIndex = activePlayerChips.indexOf(chip); if (playerIndex !== -1) { activePlayerChips.splice(playerIndex, 1); } var aiIndex = activeAIChips.indexOf(chip); if (aiIndex !== -1) { activeAIChips.splice(aiIndex, 1); } gameLayer.removeChild(chip); }, returnBullet: function returnBullet(bullet) { bullet.active = false; bullet.visible = false; var index = activeBullets.indexOf(bullet); if (index !== -1) { activeBullets.splice(index, 1); } gameLayer.removeChild(bullet); } }; /**** * Path System ****/ var PathSystem = { playerPath: [], aiPath: [], init: function init() { // Create player path - rectangular loop around the play area var padding = 80; // Distance from play area var leftX = PLAYER_AREA_X - padding; var rightX = PLAYER_AREA_X + PLAY_AREA_COLS * SLOT_WIDTH + padding; var topY = PLAYER_AREA_Y - padding; var bottomY = PLAYER_AREA_Y + PLAY_AREA_ROWS * SLOT_HEIGHT + padding; 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 aiTopY = AI_AREA_Y - padding; var aiBottomY = AI_AREA_Y + PLAY_AREA_ROWS * SLOT_HEIGHT + padding; 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 }]; }, getPathStart: function getPathStart(isPlayerSide) { return isPlayerSide ? this.playerPath[0] : this.aiPath[0]; }, 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; } chip.activate(value, isPlayerSide); gameLayer.addChild(chip); if (isPlayerSide) { activePlayerChips.push(chip); } else { activeAIChips.push(chip); } } }; /**** * Wave Spawning System ****/ var WaveSystem = { playerWaveTimer: 0, aiWaveTimer: 0, waveInterval: 300, // 5 seconds between waves (increased for balance) waveNumber: 1, getWaveData: function getWaveData(waveNum) { var wave = { chips: [] }; // Early waves (1-5): Mostly 1-value chips if (waveNum <= 5) { var chipCount = Math.min(3 + Math.floor(waveNum / 2), 6); for (var i = 0; i < chipCount; i++) { wave.chips.push({ value: 1, delay: i * 400 // 0.4 second delay between each chip }); } } // Medium waves (6-15): Mix of 1s and 5s else if (waveNum <= 15) { var chipCount = Math.min(4 + Math.floor(waveNum / 3), 8); for (var i = 0; i < chipCount; i++) { var value = i < 2 || Math.random() < 0.7 ? 1 : 5; wave.chips.push({ value: value, delay: i * 300 // Faster spawning }); } } // Later waves: More variety and higher values else { var chipCount = Math.min(5 + Math.floor(waveNum / 4), 10); for (var i = 0; i < chipCount; i++) { var value; var rand = Math.random(); if (rand < 0.4) { value = 1; } else if (rand < 0.7) { value = 5; } else if (rand < 0.9) { value = 10; } else { value = 25; } wave.chips.push({ value: value, delay: i * 250 }); } } return wave; }, spawnWave: function spawnWave(isPlayerSide) { var waveData = this.getWaveData(this.waveNumber); console.log('Spawning wave', this.waveNumber, 'with', waveData.chips.length, 'chips on', isPlayerSide ? 'player' : 'AI', 'side'); waveData.chips.forEach(function (chipInfo, index) { LK.setTimeout(function () { ChipSpawner.spawnChip(chipInfo.value, isPlayerSide); }, chipInfo.delay); }); }, update: function update() { // Spawn waves on player side (enemies for player to fight) this.playerWaveTimer++; if (this.playerWaveTimer >= this.waveInterval) { this.playerWaveTimer = 0; this.spawnWave(true); } // Spawn waves on AI side (enemies for AI to fight) this.aiWaveTimer++; if (this.aiWaveTimer >= this.waveInterval) { this.aiWaveTimer = 0; this.spawnWave(false); } // Increase wave number when both sides have spawned if (this.playerWaveTimer === 0 && this.aiWaveTimer === 0) { this.waveNumber++; // Decrease wave interval slightly as game progresses (but not too fast) this.waveInterval = Math.max(240, this.waveInterval - 2); } } }; /**** * Game State ****/ var gameState = { playerGold: 200, // Increased starting gold aiGold: 200, playerLives: 3, aiLives: 3, isPlayerTurn: true, dealCost: 75, // Increased deal cost to match new economy dealCount: 0, playerDeck: [], playerHand: [], playerPlayArea: [], aiDeck: [], aiPlayArea: [] }; /**** * Game Variables ****/ var activePlayerChips = []; var activeAIChips = []; var activeBullets = []; var selectedCard = null; var isDragging = false; var originalCardPosition = null; var gameLayer = new Container(); var uiLayer = new Container(); game.addChild(gameLayer); game.addChild(uiLayer); /**** * UI Elements ****/ var playerGoldText = new Text2('Gold: 200', { size: 50, fill: 0xffd700, weight: 800 }); playerGoldText.x = 50; playerGoldText.y = SCREEN_HEIGHT - 120; uiLayer.addChild(playerGoldText); var playerLivesText = new Text2('Lives: 3', { size: 50, fill: 0xff0000, weight: 800 }); playerLivesText.x = 50; playerLivesText.y = SCREEN_HEIGHT - 180; uiLayer.addChild(playerLivesText); // Add AI stats too for clarity var aiGoldText = new Text2('AI Gold: 200', { size: 40, fill: 0xffd700, weight: 800 }); aiGoldText.x = 50; aiGoldText.y = 50; uiLayer.addChild(aiGoldText); var aiLivesText = new Text2('AI Lives: 3', { size: 40, fill: 0xff0000, weight: 800 }); aiLivesText.x = 50; aiLivesText.y = 100; uiLayer.addChild(aiLivesText); var waveText = new Text2('Wave: 1', { size: 40, fill: 0xffffff, weight: 800 }); waveText.x = SCREEN_WIDTH - 200; waveText.y = 50; uiLayer.addChild(waveText); var dealButton = new Container(); var dealButtonGraphics = dealButton.attachAsset('dealButton', { anchorX: 0.5, anchorY: 0.5 }); var dealButtonText = new Text2('Deal (75)', { size: 40, fill: 0xffffff, weight: 800 }); dealButtonText.anchor.set(0.5, 0.5); dealButton.addChild(dealButtonText); dealButton.x = SCREEN_WIDTH / 2; dealButton.y = DEAL_BUTTON_Y; uiLayer.addChild(dealButton); dealButton.down = function () { if (gameState.playerGold >= gameState.dealCost) { dealNewHand(); } }; /**** * Game Functions ****/ function initializeGame() { PoolManager.init(); PathSystem.init(); // Initialize play areas gameState.playerPlayArea = []; gameState.aiPlayArea = []; 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(); // Deal initial hand dealNewHand(); // Start the wave system - first waves begin immediately LK.setTimeout(function () { ChipSpawner.spawnChip(1, true); // First enemy on player side ChipSpawner.spawnChip(1, false); // First enemy on AI side }, 1000); } function dealNewHand() { if (gameState.playerGold < gameState.dealCost) { return; } gameState.playerGold -= gameState.dealCost; gameState.dealCount++; gameState.dealCost = Math.floor(50 * Math.pow(1.2, gameState.dealCount)); // Clear current hand gameState.playerHand.forEach(function (card) { if (card) { uiLayer.removeChild(card); } }); gameState.playerHand = []; // Deal 5 new cards for (var i = 0; i < 5; i++) { if (gameState.playerDeck.length === 0) { gameState.playerDeck = CardSystem.createDeck(); } var cardData = gameState.playerDeck.pop(); var card = new Card(cardData); var slotX = PLAYER_AREA_X + i * DEAL_SLOT_WIDTH + i * 30 + DEAL_SLOT_WIDTH / 2; var slotY = PLAYER_DEAL_AREA_Y + DEAL_SLOT_HEIGHT / 2; card.activate(slotX, slotY, false, true); // true = is player card uiLayer.addChild(card); gameState.playerHand[i] = card; } updateUI(); } function updateUI() { playerGoldText.setText('Gold: ' + gameState.playerGold); playerLivesText.setText('Lives: ' + gameState.playerLives); aiGoldText.setText('AI Gold: ' + gameState.aiGold); aiLivesText.setText('AI Lives: ' + gameState.aiLives); dealButtonText.setText('Deal (' + gameState.dealCost + ')'); waveText.setText('Wave: ' + WaveSystem.waveNumber); // Update button color based on affordability if (gameState.playerGold >= gameState.dealCost) { dealButtonGraphics.tint = 0x00aa00; } else { dealButtonGraphics.tint = 0x666666; } } function drawPlayAreas() { // Draw player 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('playSlot', { anchorX: 0.5, anchorY: 0.5 }); slotGraphics.alpha = 0.3; 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); } } // 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('playSlot', { anchorX: 0.5, anchorY: 0.5 }); slotGraphics.alpha = 0.3; slotGraphics.tint = 0x440000; // Red tint for AI area 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); } } // Draw player deal area slots (hand) 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.2; dealSlot.x = PLAYER_AREA_X + i * DEAL_SLOT_WIDTH + i * 30 + DEAL_SLOT_WIDTH / 2; dealSlot.y = PLAYER_DEAL_AREA_Y + DEAL_SLOT_HEIGHT / 2; gameLayer.addChild(dealSlot); } } function drawPaths() { // Draw player path for (var i = 0; i < PathSystem.playerPath.length - 1; i++) { var start = PathSystem.playerPath[i]; var end = PathSystem.playerPath[i + 1]; drawPathSegment(start, end, 0x666666); } // Draw AI path for (var i = 0; i < PathSystem.aiPath.length - 1; i++) { var start = PathSystem.aiPath[i]; var end = PathSystem.aiPath[i + 1]; drawPathSegment(start, end, 0x664444); } } function drawPathSegment(start, end, color) { var dx = end.x - start.x; var dy = end.y - start.y; var distance = Math.sqrt(dx * dx + dy * dy); var segments = Math.floor(distance / 20); for (var i = 0; i <= segments; i++) { var progress = i / segments; var x = start.x + dx * progress; var y = start.y + dy * progress; var pathDot = new Container(); var dotGraphics = pathDot.attachAsset('pathSegment', { anchorX: 0.5, anchorY: 0.5 }); dotGraphics.width = dotGraphics.height = 8; dotGraphics.tint = color; dotGraphics.alpha = 0.6; pathDot.x = x; pathDot.y = y; gameLayer.addChild(pathDot); } } 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) { for (var i = 0; i < 5; i++) { var slotXStart = PLAYER_AREA_X + i * (DEAL_SLOT_WIDTH + 30); var slotXEnd = slotXStart + DEAL_SLOT_WIDTH; if (x >= slotXStart && x <= slotXEnd) { return { area: 'hand', index: i }; } } } 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].cardData); } } if (cards.length === 5) { return CardSystem.evaluatePokerHand(cards); } return { type: 'none', strength: 0, multiplier: 1 }; } function applyHandBonuses() { // Apply bonuses to player cards for (var row = 0; row < PLAY_AREA_ROWS; row++) { var handEval = evaluateRowHand(row, true); for (var col = 0; col < PLAY_AREA_COLS; col++) { var card = gameState.playerPlayArea[row][col]; if (card) { card.handBonus = handEval.multiplier; card.calculateStats(); } } } // Apply bonuses to AI cards AISystem.applyAIHandBonuses(); } /**** * AI System ****/ var AISystem = { thinkTimer: 0, thinkDelay: 60, // Think every second (60 ticks) dealTimer: 0, dealDelay: 300, // Deal every 5 seconds initially update: function update() { this.thinkTimer++; this.dealTimer++; if (this.thinkTimer >= this.thinkDelay) { this.thinkTimer = 0; this.makeMove(); } if (this.dealTimer >= this.dealDelay && this.shouldDeal()) { this.dealTimer = 0; this.dealAIHand(); this.dealDelay = Math.max(180, this.dealDelay - 10); // Deal faster as game progresses } }, shouldDeal: function shouldDeal() { // Deal if we can afford it and have empty slots or low-level cards if (gameState.aiGold < gameState.dealCost) { return false; } var emptySlots = this.countEmptySlots(); var lowLevelCards = this.countLowLevelCards(); // Deal if we have empty slots or mostly low-level cards return emptySlots > 2 || lowLevelCards > 6; }, 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; }, 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; }, makeMove: function makeMove() { // Priority order: Merge cards > Place cards > Optimize positions if (this.tryMergeCards()) { // Successfully merged, wait for next think cycle return; } if (this.tryPlaceCards()) { // Successfully placed cards return; } this.optimizeCardPositions(); }, tryMergeCards: function tryMergeCards() { // Look for mergeable cards 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; } // Look for a card to merge with 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) { continue; } if (card1.canMergeWith(card2)) { this.mergeCards(card1, card2, row1, col1, row2, col2); return true; } } } } } return false; }, mergeCards: function mergeCards(card1, card2, row1, col1, row2, col2) { var mergedCard = card1.mergeWith(card2); if (mergedCard) { // Remove old cards gameLayer.removeChild(card1); gameLayer.removeChild(card2); gameState.aiPlayArea[row1][col1] = null; gameState.aiPlayArea[row2][col2] = null; // Place merged card in the first position var pos = getSlotPosition(row1, col1, false); mergedCard.activate(pos.x, pos.y, true, false); gameLayer.addChild(mergedCard); gameState.aiPlayArea[row1][col1] = mergedCard; // Merge animation mergedCard.alpha = 0; mergedCard.scaleX = mergedCard.scaleY = 1.5; tween(mergedCard, { alpha: 1, scaleX: 1, scaleY: 1 }, { duration: 200, easing: tween.elasticOut }); this.applyAIHandBonuses(); } }, tryPlaceCards: function tryPlaceCards() { // AI doesn't have a "hand" like player, it deals directly to board // This function is for future expansion return false; }, optimizeCardPositions: function optimizeCardPositions() { // Move stronger cards to better positions (like completing poker hands) // For now, just try to complete rows for hand bonuses this.tryCompletePokerHands(); }, tryCompletePokerHands: function tryCompletePokerHands() { for (var row = 0; row < PLAY_AREA_ROWS; row++) { var rowCards = []; var emptyPositions = []; for (var col = 0; col < PLAY_AREA_COLS; col++) { if (gameState.aiPlayArea[row][col]) { rowCards.push({ card: gameState.aiPlayArea[row][col], col: col }); } else { emptyPositions.push(col); } } // If row is almost complete, try to fill it strategically if (rowCards.length >= 3 && emptyPositions.length > 0) { // Look for cards in other rows that might complete a hand this.tryMoveCardToCompleteHand(row, rowCards, emptyPositions[0]); } } }, tryMoveCardToCompleteHand: function tryMoveCardToCompleteHand(targetRow, existingCards, targetCol) { // Look for cards in other positions that might help complete a hand for (var row = 0; row < PLAY_AREA_ROWS; row++) { if (row === targetRow) { continue; } for (var col = 0; col < PLAY_AREA_COLS; col++) { var card = gameState.aiPlayArea[row][col]; if (!card) { continue; } // Simple heuristic: move cards of same suit or sequential values var shouldMove = this.cardHelpsHand(card, existingCards); if (shouldMove && Math.random() < 0.3) { // 30% chance to move // Move the card gameState.aiPlayArea[row][col] = null; gameState.aiPlayArea[targetRow][targetCol] = card; var newPos = getSlotPosition(targetRow, targetCol, false); tween(card, { x: newPos.x, y: newPos.y }, { duration: 300, easing: tween.quadOut }); this.applyAIHandBonuses(); return; } } } }, cardHelpsHand: function cardHelpsHand(card, existingCards) { // Simple heuristic to see if a card might help complete a poker hand var suits = {}; var values = {}; existingCards.forEach(function (cardInfo) { var c = cardInfo.card.cardData; suits[c.suit] = (suits[c.suit] || 0) + 1; values[c.value] = (values[c.value] || 0) + 1; }); // Check if card matches existing suits or values var cardSuit = card.cardData.suit; var cardValue = card.cardData.value; return suits[cardSuit] >= 2 || values[cardValue] >= 1; }, dealAIHand: function dealAIHand() { if (gameState.aiGold < gameState.dealCost) { return; } gameState.aiGold -= gameState.dealCost; // Deal cards directly to empty slots in AI play area var cardsDealt = 0; var maxCards = Math.min(5, this.countEmptySlots()); for (var attempt = 0; attempt < maxCards; attempt++) { if (gameState.aiDeck.length === 0) { gameState.aiDeck = CardSystem.createDeck(); } var cardData = gameState.aiDeck.pop(); var card = new Card(cardData); // Find best empty slot (prefer completing rows) var bestSlot = this.findBestEmptySlot(); if (bestSlot) { var pos = getSlotPosition(bestSlot.row, bestSlot.col, false); card.activate(pos.x, pos.y, true, false); gameLayer.addChild(card); gameState.aiPlayArea[bestSlot.row][bestSlot.col] = card; cardsDealt++; // Deal animation card.alpha = 0; card.scaleX = card.scaleY = 0.5; tween(card, { alpha: 1, scaleX: 1, scaleY: 1 }, { duration: 300, easing: tween.elasticOut }); } else { break; // No empty slots } } if (cardsDealt > 0) { this.applyAIHandBonuses(); } }, findBestEmptySlot: function findBestEmptySlot() { var emptySlots = []; for (var row = 0; row < PLAY_AREA_ROWS; row++) { for (var col = 0; col < PLAY_AREA_COLS; col++) { if (!gameState.aiPlayArea[row][col]) { var score = this.evaluateSlotScore(row, col); emptySlots.push({ row: row, col: col, score: score }); } } } if (emptySlots.length === 0) { return null; } // Sort by score (higher is better) emptySlots.sort(function (a, b) { return b.score - a.score; }); return emptySlots[0]; }, evaluateSlotScore: function evaluateSlotScore(row, col) { var score = 0; var cardsInRow = 0; // Count cards in this row for (var c = 0; c < PLAY_AREA_COLS; c++) { if (gameState.aiPlayArea[row][c]) { cardsInRow++; } } // Prefer completing rows score += cardsInRow * 10; // Slight preference for middle positions score += (2 - Math.abs(col - 2)) * 2; return score; }, applyAIHandBonuses: function applyAIHandBonuses() { // Apply poker hand bonuses to AI cards for (var row = 0; row < PLAY_AREA_ROWS; row++) { var handEval = evaluateRowHand(row, false); for (var col = 0; col < PLAY_AREA_COLS; col++) { var card = gameState.aiPlayArea[row][col]; if (card) { card.handBonus = handEval.multiplier; card.calculateStats(); } } } } }; /**** * Input Handling ****/ game.down = function (x, y, obj) { // 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) { selectedCard = card; isDragging = true; originalCardPosition = { area: 'hand', index: i }; 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) { selectedCard = card; isDragging = true; originalCardPosition = { area: 'player', row: row, col: col }; // Remove from current position gameState.playerPlayArea[row][col] = null; return; } } } }; game.move = function (x, y, obj) { if (isDragging && selectedCard) { selectedCard.x = x; selectedCard.y = y; } }; game.up = function (x, y, obj) { if (isDragging && selectedCard) { isDragging = false; var targetSlot = getSlotFromPosition(x, y); if (targetSlot) { if (targetSlot.area === 'player') { var existingCard = gameState.playerPlayArea[targetSlot.row][targetSlot.col]; if (existingCard && selectedCard.canMergeWith(existingCard)) { // Merge in play area 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 }); createFloatingText('+Level Up!', mergedCard.x, mergedCard.y - 50, 0x00ff00); } } else if (!existingCard) { // Place in empty slot var pos = getSlotPosition(targetSlot.row, targetSlot.col, true); selectedCard.activate(pos.x, pos.y, true); 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 { returnCardToOriginalPosition(); } } else if (targetSlot.area === 'hand') { var existingCard = gameState.playerHand[targetSlot.index]; if (existingCard && existingCard !== selectedCard && selectedCard.canMergeWith(existingCard)) { // Merge in hand 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 slotX = PLAYER_AREA_X + 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 }); createFloatingText('+Level Up!', mergedCard.x, mergedCard.y - 50, 0x00ff00); } else { returnCardToOriginalPosition(); } } 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 slotX = PLAYER_AREA_X + 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 createFloatingText(text, x, y, color) { var floatingText = new Text2(text, { size: 40, fill: color || 0xffffff, weight: 800 }); floatingText.anchor.set(0.5, 0.5); floatingText.x = x; floatingText.y = y; floatingText.alpha = 1; uiLayer.addChild(floatingText); tween(floatingText, { y: y - 80, alpha: 0 }, { duration: 1500, easing: tween.quadOut, onFinish: function onFinish() { uiLayer.removeChild(floatingText); } }); } /**** * Main Game Loop ****/ game.update = function () { // 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(); } // 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 if (gameState.playerLives <= 0) { showGameOver(false); } else if (gameState.aiLives <= 0) { showGameOver(true); } updateUI(); }; /**** * Game Over ****/ function showGameOver(playerWon) { if (playerWon) { LK.showYouWin(); } else { LK.showGameOver(); } } /**** * Utility Functions ****/ 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); } } initializeGame(); var background = LK.getAsset('background', { anchorX: 0.5, anchorY: 0 }); background.x = SCREEN_WIDTH / 2; background.y = 0; gameLayer.addChild(background); ;
===================================================================
--- original.js
+++ change.js
@@ -275,12 +275,34 @@
self.value = 1;
self.speed = 0.05;
self.pathProgress = 0;
self.isPlayerSide = true;
- var chipGraphics = self.attachAsset('pokerChip', {
- anchorX: 0.5,
- anchorY: 0.5
- });
+ 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 valueText = new Text2('1', {
size: 30,
fill: 0xffffff,
weight: 800
@@ -301,20 +323,15 @@
self.x = startPos.x;
self.y = startPos.y;
};
self.setChipAppearance = function () {
- var colors = {
- 1: 0xffffff,
- // White - 50 HP
- 5: 0xff0000,
- // Red - 250 HP
- 10: 0x00ff00,
- // Green - 500 HP
- 25: 0x000000,
- // Black - 1250 HP
- 100: 0x800080 // Purple - 5000 HP
- };
- chipGraphics.tint = colors[self.value] || 0xffffff;
+ if (chipGraphics) {
+ chipGraphics.visible = false;
+ }
+ chipGraphics = chipGraphicsAssets[self.value] || chipGraphicsAssets[1];
+ if (chipGraphics) {
+ chipGraphics.visible = true;
+ }
valueText.setText(self.value.toString());
// Show health on larger chips
if (self.value >= 5) {
valueText.setText(self.value + '\n' + self.health);
@@ -326,13 +343,17 @@
if (self.value >= 5) {
valueText.setText(self.value + '\n' + Math.max(0, self.health));
}
// Flash red when taking damage
- var originalTint = chipGraphics.tint;
- chipGraphics.tint = 0xff6666;
- LK.setTimeout(function () {
- chipGraphics.tint = originalTint;
- }, 100);
+ if (chipGraphics) {
+ var originalTint = chipGraphics.tint;
+ chipGraphics.tint = 0xff6666;
+ LK.setTimeout(function () {
+ if (chipGraphics) {
+ chipGraphics.tint = originalTint;
+ }
+ }, 100);
+ }
if (self.health <= 0) {
self.die();
}
};
A long rack of different colored poker chips seen from above. Anime style.. In-Game asset. 2d. High contrast. No shadows
A graphic for the center of a joker card.
a 2:3 format thin black border with nothing in the center. In-Game asset. 2d. High contrast. No shadows
A small white explosion particle.. In-Game asset. 2d. High contrast. No shadows
Make the blue a lighter blue.
Make this in a white instead of blue. Keep everything else the same.
A couple different sized stacks of these chips beside each other.
Just the spade from this picture with a blue snowflake in the middle of it.
Just the heart from this picture with a flame in the cent t of it.
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.
Just the diamond from this picture with a dollar sign in the center
A white circle with a lightening gradient towards the edge.. Single Game Texture. In-Game asset. 2d. Blank background. High contrast. No shadows
A simple golden line break.. In-Game asset. 2d. High contrast. No shadows
A fanned card hand that shows a royal flush in spades. Anime style. In-Game asset. 2d. High contrast. No shadows
An SVG of the word 'Battle'. text in yellow with a black outline. In-Game asset. 2d. High contrast. No shadows
change the text to say "Mods"
The four card suits arranged in 2x2 grid layout, no lines. Anime style. In-Game asset. 2d. High contrast. No shadows
A single ice crystal. anime style. In-Game asset. 2d. High contrast. No shadows
Change the text to say ‘Refund’. Change the cards to a trash can.
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
A 3:2 ratio rectangular green button that says “PvP” using this yellow font.
Change the text to say ‘Co-op’
Change the font to say ‘Victory!’
Change the text to say ‘Defeat!’
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
Show these same cats smiling and instead of clenched fists they’re grasping hands because they’re friends.
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.
A small treasure chest with poker themed graphics on it. Anime style. In-Game asset. 2d. High contrast. No shadows
The hearts card suit symbol with two linked hearts in the center of it. Anime style.. In-Game asset. 2d. High contrast. No shadows
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
Just the club from this picture with a clock in the center.
Just the spade from this image with a land mine in the center of it.
Just the mine from this image.
Just the heart from this image with a piggy bank in the center.
Just the diamond from this picture with a sword with a small arrow pointing up in the center of the diamond.
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.
Just the spade with a skull in the center of it. Anime style.
This chest with the top open and nothing inside.
Change the text to say Shop
An old style cash register. The numeric read out says 7.77. Anime style.. In-Game asset. 2d. High contrast. No shadows
A giant question mark. Anime style.. In-Game asset. 2d. High contrast. No shadows
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
Change the text to say ‘Draw’
The back of a playing card. Blue pattern. Anime style.. In-Game asset. 2d. High contrast. No shadows
The back of a playing card. Red pattern with a heart in the center. Anime style.. In-Game asset. 2d. High contrast. No shadows