User prompt
Añade la música y el sonido al juego
User prompt
Crea música apropiada para el menú principal, la partida, el game over y efectos de sonido
User prompt
Crea un menú principal
User prompt
Haz cartas negativas, si el jugador pasa el turno las cartas negativas de ese turno se activan, para desactivar las cartas negativas hay que comprarlas
User prompt
Elimina la carta "God mode" Ya que es demasiado buena
User prompt
Please fix the bug: 'Uncaught TypeError: Cannot read properties of undefined (reading 'name')' in or related to this line: 'return {' Line Number: 636
User prompt
Haz que por cada turno el jugador obtenga más monedas por cada turno. Crea una nueva mecánica para poder hacer combos de cartas y haz cartas nuevas relacionadas a esta nueva mecánica
User prompt
Haz que cada 5 turnos en vez de perder los puntos el jugador los mantenga y además cada 5 turnos aparezcan mejores cartas (Haz más cartas con mejoras más complejas)
User prompt
Haz que haya más cartas con diferentes mecánicas (Ejemplos: multiplicar, reducir coste de futuras cartas, sumar puntos cuantas más cartas de un tipo específico hayan sido compradas, etc.)
User prompt
Haz las cartas el doble de grande repartidas en dos columnas verticales
User prompt
Haz las cartas más pequeñas y separadas entre ellas, y haz que la habilidad de las cartas se vea, porque el botón de comprar la carta tapa la habilidad
User prompt
En vez de que las cartas estén en una fila horizontal, repártelas por toda la pantalla y hazlas el tripe de grande
User prompt
Haz que las cartas y los textos sean más grandes para que se lean mejor
User prompt
Please fix the bug: 'Uncaught TypeError: Cannot read properties of undefined (reading 'toGlobal')' in or related to this line: 'var localPos = game.toLocal(obj.parent.toGlobal(obj.position));' Line Number: 347
Code edit (1 edits merged)
Please save this source code
User prompt
Card Collector: Score Rush
Initial prompt
Este juego trata de conseguir los mayores puntos posibles, el juego se va a dividir en turnos, en cada turno el jugador va consiguiendo monedas, al comienzo del turno van a aparecer 5 cartas diferentes aleatorias, cada carta da al jugador puntos de formas diferentes y cada una cuesta monedas dependiendo de lo buena que sea, cada 5 turnos el juego reclama una cantidad cierta cantidad de puntos, si el jugador no tiene esa cantidad de puntos el jugador pierde.
/**** * Plugins ****/ var tween = LK.import("@upit/tween.v1"); /**** * Classes ****/ var Card = Container.expand(function (cardData) { var self = Container.call(this); self.cardData = cardData; self.purchased = false; // Card border var border = self.attachAsset('cardBorder', { anchorX: 0.5, anchorY: 0.5 }); // Card background var background = self.attachAsset('cardBackground', { anchorX: 0.5, anchorY: 0.5 }); // Card title self.titleText = new Text2(cardData.name, { size: 56, fill: 0xFFFFFF }); self.titleText.anchor.set(0.5, 0); self.titleText.x = 0; self.titleText.y = -160; self.addChild(self.titleText); // Card description self.descText = new Text2(cardData.description, { size: 40, fill: 0xECF0F1 }); self.descText.anchor.set(0.5, 0); self.descText.x = 0; self.descText.y = -100; self.addChild(self.descText); // Points text self.pointsText = new Text2("+" + cardData.points + " pts", { size: 48, fill: 0xE74C3C }); self.pointsText.anchor.set(0.5, 0); self.pointsText.x = 0; self.pointsText.y = -40; self.addChild(self.pointsText); // Cost and buy button self.buyButton = self.attachAsset('buyButton', { anchorX: 0.5, anchorY: 0.5 }); self.buyButton.y = 120; self.costText = new Text2("Buy: " + cardData.cost + " coins", { size: 36, fill: 0xFFFFFF }); self.costText.anchor.set(0.5, 0.5); self.costText.x = 0; self.costText.y = 120; self.addChild(self.costText); self.updateVisual = function () { if (self.purchased) { if (self.cardData.type === "negative") { background.tint = 0x2ecc71; // Green for deactivated negative card self.titleText.setText(self.cardData.name + " (DEACTIVATED)"); } else { background.tint = 0x27ae60; } self.buyButton.visible = false; self.costText.visible = false; } else { var actualCost = Math.max(1, self.cardData.cost - nextCardCostReduction); if (self.cardData.type === "negative") { self.costText.setText("Deactivate: " + actualCost + " coins"); background.tint = 0xe74c3c; // Red for active negative card self.buyButton.tint = 0xe67e22; // Orange buy button for negative } else { if (nextCardCostReduction > 0) { self.costText.setText("Buy: " + actualCost + " coins (was " + self.cardData.cost + ")"); } else { self.costText.setText("Buy: " + actualCost + " coins"); } if (coins < actualCost) { background.tint = 0x7f8c8d; self.buyButton.tint = 0x7f8c8d; } else { background.tint = 0x2c3e50; self.buyButton.tint = 0x27ae60; } } } }; self.over = function (x, y, obj) { if (!self.purchased) { LK.getSound('cardHover').play(); } }; self.down = function (x, y, obj) { if (!self.purchased && coins >= self.cardData.cost) { self.purchase(); } }; self.purchase = function () { if (self.purchased || coins < self.cardData.cost) return; var actualCost = Math.max(1, self.cardData.cost - nextCardCostReduction); coins -= actualCost; nextCardCostReduction = 0; self.purchased = true; // Track card types if (!purchasedCardTypes[self.cardData.type]) { purchasedCardTypes[self.cardData.type] = 0; } purchasedCardTypes[self.cardData.type]++; // Apply card abilities var pointsToAdd = self.cardData.points; if (self.cardData.ability) { pointsToAdd = applyCardAbility(self.cardData, pointsToAdd); } // Apply global multiplier pointsToAdd = Math.floor(pointsToAdd * globalPointMultiplier); points += pointsToAdd; self.updateVisual(); updateUI(); LK.getSound('cardBuy').play(); tween(self, { scaleX: 1.1, scaleY: 1.1 }, { duration: 200, easing: tween.easeOut, onFinish: function onFinish() { tween(self, { scaleX: 1, scaleY: 1 }, { duration: 200, easing: tween.easeOut }); } }); }; return self; }); var MainMenu = Container.expand(function () { var self = Container.call(this); // Menu background var menuBg = self.attachAsset('gameBoard', { anchorX: 0.5, anchorY: 0.5, x: 1024, y: 1366 }); menuBg.tint = 0x2c3e50; // Game title var titleText = new Text2("CARD STRATEGY", { size: 120, fill: 0xFFFFFF }); titleText.anchor.set(0.5, 0.5); titleText.x = 1024; titleText.y = 400; self.addChild(titleText); // Subtitle var subtitleText = new Text2("Collect cards to survive!", { size: 60, fill: 0xBDC3C7 }); subtitleText.anchor.set(0.5, 0.5); subtitleText.x = 1024; subtitleText.y = 500; self.addChild(subtitleText); // Play button var playButton = self.attachAsset('buyButton', { anchorX: 0.5, anchorY: 0.5, x: 1024, y: 800, scaleX: 1.5, scaleY: 1.5 }); playButton.tint = 0x27ae60; var playText = new Text2("PLAY", { size: 80, fill: 0xFFFFFF }); playText.anchor.set(0.5, 0.5); playText.x = 1024; playText.y = 800; self.addChild(playText); // Instructions var instructionsText = new Text2("• Buy cards to earn points\n• Survive checkpoint requirements every 5 turns\n• Use combos and special abilities\n• Deactivate negative cards to avoid penalties", { size: 48, fill: 0xECF0F1 }); instructionsText.anchor.set(0.5, 0.5); instructionsText.x = 1024; instructionsText.y = 1200; self.addChild(instructionsText); // Credits var creditsText = new Text2("Made with FRVR", { size: 36, fill: 0x95A5A6 }); creditsText.anchor.set(0.5, 0.5); creditsText.x = 1024; creditsText.y = 1600; self.addChild(creditsText); // Play button click handler playButton.down = function (x, y, obj) { startGame(); }; return self; }); /**** * Initialize Game ****/ var game = new LK.Game({ backgroundColor: 0x0f1419 }); /**** * Game Code ****/ // Game state variables var coins = 10; var points = 0; var turn = 1; var checkpoint = 1; var requiredPoints = 20; var currentCards = []; var gamePhase = 'menu'; // 'menu', 'playing', 'checkpoint', 'gameOver' var mainMenu = null; // Game mechanics tracking var purchasedCardTypes = {}; var nextCardCostReduction = 0; var permanentCoinBonus = 0; var globalPointMultiplier = 1; var skipNextCheckpoint = false; // Combo system variables var comboMultiplier = 1; var comboCards = []; var maxComboSize = 3; var perTurnCoinGrowth = 0; // Negative cards system var negativeCards = []; var negativeCardTemplates = [{ name: "Tax Collector", description: "Lose 30% of coins", points: 0, cost: 8, type: "negative", negativeEffect: "taxCoins" }, { name: "Point Drain", description: "Lose 25% of points", points: 0, cost: 12, type: "negative", negativeEffect: "drainPoints" }, { name: "Coin Thief", description: "Lose 15 coins", points: 0, cost: 6, type: "negative", negativeEffect: "stealCoins" }, { name: "Deflation", description: "Reduce coin growth by 2", points: 0, cost: 10, type: "negative", negativeEffect: "reduceGrowth" }, { name: "Combo Breaker", description: "Reset all combos", points: 0, cost: 7, type: "negative", negativeEffect: "breakCombo" }]; // Card templates organized by checkpoint level var cardTemplatesByLevel = { 1: [{ // Basic cards for checkpoint 1 name: "Basic Card", description: "Simple points", points: 5, cost: 3, type: "basic" }, { name: "Coin Card", description: "Steady income", points: 3, cost: 2, type: "economy" }, { name: "Power Card", description: "High value", points: 12, cost: 8, type: "power" }, { name: "Lucky Card", description: "Bonus points", points: 8, cost: 5, type: "luck" }, { name: "Quick Card", description: "Fast points", points: 4, cost: 2, type: "quick" }], 2: [{ // Advanced cards for checkpoint 2+ name: "Mega Card", description: "Massive points", points: 20, cost: 15, type: "mega" }, { name: "Super Card", description: "Great value", points: 15, cost: 10, type: "super" }, { name: "Bonus Card", description: "Extra boost", points: 6, cost: 4, type: "bonus" }, { name: "Multiplier Card", description: "x2 next card points", points: 2, cost: 4, type: "multiplier", ability: "nextCardMultiplier" }, { name: "Discount Card", description: "Next card costs 50% less", points: 1, cost: 3, type: "discount", ability: "costReduction" }, { name: "Combo Starter", description: "Begin a combo chain", points: 3, cost: 2, type: "combo", ability: "comboStarter" }, { name: "Combo Builder", description: "Extend current combo", points: 5, cost: 4, type: "combo", ability: "comboBuilder" }], 3: [{ // Expert cards for checkpoint 3+ name: "Economy Synergy", description: "+3 pts per Economy card", points: 1, cost: 5, type: "synergy", ability: "economySynergy" }, { name: "Power Synergy", description: "+5 pts per Power card", points: 2, cost: 7, type: "synergy", ability: "powerSynergy" }, { name: "Collection Bonus", description: "+2 pts per unique type", points: 3, cost: 6, type: "collection", ability: "typeBonus" }, { name: "Lucky Streak", description: "+1 pt per Lucky card", points: 2, cost: 3, type: "streak", ability: "luckySynergy" }, { name: "Coin Generator", description: "+2 coins next turn", points: 1, cost: 2, type: "generator", ability: "coinBonus" }, { name: "Combo Master", description: "Complete combo +50% bonus", points: 8, cost: 6, type: "combo", ability: "comboMaster" }, { name: "Chain Reactor", description: "Each combo card +2 coins/turn", points: 4, cost: 5, type: "combo", ability: "comboEconomy" }], 4: [{ // Master cards for checkpoint 4+ name: "Point Doubler", description: "Double current points", points: 0, cost: 12, type: "doubler", ability: "doublePoints" }, { name: "Chain Multiplier", description: "Each purchased card +10% pts", points: 5, cost: 8, type: "chain", ability: "chainMultiplier" }, { name: "Compound Engine", description: "Points grow exponentially", points: 3, cost: 10, type: "compound", ability: "compoundGrowth" }, { name: "Universal Synergy", description: "+1 pt per ANY card owned", points: 2, cost: 6, type: "universal", ability: "universalSynergy" }, { name: "Mega Coin Bank", description: "+5 coins per turn forever", points: 5, cost: 15, type: "bank", ability: "megaCoinBonus" }, { name: "Combo Engine", description: "Triple combo bonuses", points: 10, cost: 18, type: "combo", ability: "comboTriple" }], 5: [{ // Legendary cards for checkpoint 5+ name: "Infinity Engine", description: "Triple all future points", points: 10, cost: 20, type: "infinity", ability: "tripleMultiplier" }, { name: "Checkpoint Keeper", description: "+50% req points for easier pass", points: 15, cost: 25, type: "keeper", ability: "easierCheckpoint" }, { name: "Card Recycler", description: "Get 50% coin refund on all cards", points: 8, cost: 18, type: "recycler", ability: "coinRefund" }, { name: "Time Manipulator", description: "Skip next checkpoint req", points: 20, cost: 30, type: "time", ability: "skipCheckpoint" }, { name: "Infinite Combos", description: "No combo size limit, x5 bonus", points: 30, cost: 40, type: "combo", ability: "infiniteCombo" }] }; // Legacy compatibility - combine all templates var cardTemplates = []; for (var level in cardTemplatesByLevel) { cardTemplates = cardTemplates.concat(cardTemplatesByLevel[level]); } // UI Elements var board = game.attachAsset('gameBoard', { anchorX: 0.5, anchorY: 0.5, x: 1024, y: 1366 }); // Coins display var coinsText = new Text2("Coins: " + coins, { size: 48, fill: 0xF1C40F }); coinsText.anchor.set(0, 0); coinsText.x = 100; coinsText.y = 150; LK.gui.topLeft.addChild(coinsText); // Points display var pointsText = new Text2("Points: " + points, { size: 48, fill: 0xE74C3C }); pointsText.anchor.set(0, 0); pointsText.x = 100; pointsText.y = 220; LK.gui.topLeft.addChild(pointsText); // Turn display var turnText = new Text2("Turn: " + turn, { size: 36, fill: 0x3498DB }); turnText.anchor.set(0, 0); turnText.x = 100; turnText.y = 290; LK.gui.topLeft.addChild(turnText); // Required points display var requiredText = new Text2("Need: " + requiredPoints + " pts", { size: 36, fill: 0xE67E22 }); requiredText.anchor.set(0, 0); requiredText.x = 100; requiredText.y = 340; LK.gui.topLeft.addChild(requiredText); // Combo display var comboText = new Text2("Combo: " + comboCards.length + "/" + maxComboSize, { size: 32, fill: 0x9B59B6 }); comboText.anchor.set(0, 0); comboText.x = 100; comboText.y = 390; LK.gui.topLeft.addChild(comboText); // Coin growth display var growthText = new Text2("Coin Growth: +" + perTurnCoinGrowth + "/turn", { size: 28, fill: 0x1ABC9C }); growthText.anchor.set(0, 0); growthText.x = 100; growthText.y = 440; LK.gui.topLeft.addChild(growthText); // Progress bar var progressBarBg = game.attachAsset('progressBar', { anchorX: 0.5, anchorY: 0, x: 1024, y: 200 }); var progressBarFill = game.attachAsset('progressFill', { anchorX: 0, anchorY: 0, x: 224, y: 200 }); // Next turn button var nextTurnButton = game.attachAsset('nextTurnButton', { anchorX: 0.5, anchorY: 0.5, x: 1024, y: 2500 }); var nextTurnText = new Text2("Next Turn", { size: 44, fill: 0xFFFFFF }); nextTurnText.anchor.set(0.5, 0.5); nextTurnText.x = 1024; nextTurnText.y = 2500; game.addChild(nextTurnText); function applyNegativeEffect(negativeEffect) { LK.getSound('negativeEffect').play(); switch (negativeEffect) { case "taxCoins": var coinsLost = Math.floor(coins * 0.3); coins = Math.max(0, coins - coinsLost); break; case "drainPoints": var pointsLost = Math.floor(points * 0.25); points = Math.max(0, points - pointsLost); break; case "stealCoins": coins = Math.max(0, coins - 15); break; case "reduceGrowth": perTurnCoinGrowth = Math.max(0, perTurnCoinGrowth - 2); break; case "breakCombo": comboCards = []; comboMultiplier = 1; break; } } function applyCardAbility(cardData, basePoints) { var bonusPoints = 0; switch (cardData.ability) { case "nextCardMultiplier": // This will be handled when the next card is purchased return basePoints; case "costReduction": nextCardCostReduction = Math.floor(cardData.cost * 0.5); return basePoints; case "economySynergy": bonusPoints = (purchasedCardTypes["economy"] || 0) * 3; return basePoints + bonusPoints; case "powerSynergy": bonusPoints = (purchasedCardTypes["power"] || 0) * 5; return basePoints + bonusPoints; case "luckySynergy": bonusPoints = (purchasedCardTypes["luck"] || 0) * 1; return basePoints + bonusPoints; case "typeBonus": var uniqueTypes = Object.keys(purchasedCardTypes).length; bonusPoints = uniqueTypes * 2; return basePoints + bonusPoints; case "coinBonus": coins += 2; return basePoints; case "doublePoints": points = points * 2; return 0; case "chainMultiplier": var totalCards = 0; for (var type in purchasedCardTypes) { totalCards += purchasedCardTypes[type]; } bonusPoints = Math.floor(totalCards * 0.1 * basePoints); return basePoints + bonusPoints; case "compoundGrowth": bonusPoints = Math.floor(points * 0.1); return basePoints + bonusPoints; case "universalSynergy": var totalCards = 0; for (var type in purchasedCardTypes) { totalCards += purchasedCardTypes[type]; } bonusPoints = totalCards; return basePoints + bonusPoints; case "megaCoinBonus": // Add permanent income bonus if (!permanentCoinBonus) permanentCoinBonus = 0; permanentCoinBonus += 5; return basePoints; case "tripleMultiplier": if (!globalPointMultiplier) globalPointMultiplier = 1; globalPointMultiplier *= 3; return basePoints; case "easierCheckpoint": requiredPoints = Math.floor(requiredPoints * 0.5); return basePoints; case "coinRefund": coins += Math.floor(cardData.cost * 0.5); return basePoints; case "skipCheckpoint": // Skip next checkpoint requirement skipNextCheckpoint = true; return basePoints; case "comboStarter": comboCards = [cardData]; comboMultiplier = 1.2; return basePoints; case "comboBuilder": if (comboCards.length > 0 && comboCards.length < maxComboSize) { comboCards.push(cardData); comboMultiplier += 0.3; bonusPoints = Math.floor(basePoints * (comboMultiplier - 1)); return basePoints + bonusPoints; } else { return basePoints; } case "comboMaster": if (comboCards.length >= maxComboSize) { bonusPoints = Math.floor(basePoints * 0.5); LK.getSound('comboComplete').play(); comboCards = []; comboMultiplier = 1; return basePoints + bonusPoints; } else { return basePoints; } case "comboEconomy": var comboCardCount = 0; for (var type in purchasedCardTypes) { if (type === "combo") { comboCardCount = purchasedCardTypes[type]; break; } } perTurnCoinGrowth += comboCardCount * 2; return basePoints; case "comboTriple": comboMultiplier *= 3; return basePoints; case "infiniteCombo": maxComboSize = 999; comboMultiplier *= 5; return basePoints; // Don't add base points since we doubled existing default: return basePoints; } } function generateRandomCard() { // 20% chance to generate a negative card from checkpoint 2 onwards if (checkpoint >= 2 && Math.random() < 0.2) { var template = negativeCardTemplates[Math.floor(Math.random() * negativeCardTemplates.length)]; var scaleFactor = 1 + (checkpoint - 1) * 0.15; return { name: template.name, description: template.description, points: template.points, cost: Math.floor(template.cost * scaleFactor), type: template.type, negativeEffect: template.negativeEffect }; } // Get available card templates based on current checkpoint var availableTemplates = []; for (var level = 1; level <= Math.min(checkpoint, 5); level++) { if (cardTemplatesByLevel[level]) { availableTemplates = availableTemplates.concat(cardTemplatesByLevel[level]); } } // Fallback to level 1 cards if no templates available if (availableTemplates.length === 0) { availableTemplates = cardTemplatesByLevel[1] || []; } // Higher checkpoints have better chance of getting advanced cards var template; if (checkpoint >= 3 && Math.random() < 0.6) { // 60% chance for advanced cards in checkpoint 3+ var advancedTemplates = []; for (var level = Math.max(2, checkpoint - 1); level <= Math.min(checkpoint, 5); level++) { if (cardTemplatesByLevel[level]) { advancedTemplates = advancedTemplates.concat(cardTemplatesByLevel[level]); } } if (advancedTemplates.length > 0) { template = advancedTemplates[Math.floor(Math.random() * advancedTemplates.length)]; } else { template = availableTemplates[Math.floor(Math.random() * availableTemplates.length)]; } } else { template = availableTemplates[Math.floor(Math.random() * availableTemplates.length)]; } // Final safety check - use first available template if still undefined if (!template && availableTemplates.length > 0) { template = availableTemplates[0]; } // If still no template, create a default one if (!template) { template = { name: "Emergency Card", description: "Basic fallback", points: 3, cost: 2, type: "basic" }; } var scaleFactor = 1 + (checkpoint - 1) * 0.2; return { name: template.name, description: template.description, points: Math.floor(template.points * scaleFactor), cost: Math.floor(template.cost * scaleFactor), type: template.type, ability: template.ability }; } function generateCards() { // Clear existing cards for (var i = 0; i < currentCards.length; i++) { currentCards[i].destroy(); } currentCards = []; // Clear negative cards tracking for new turn negativeCards = []; // Generate 5 new cards in two vertical columns with doubled size var cardPositions = [{ x: 700, y: 600 }, { x: 1348, y: 600 }, { x: 700, y: 1200 }, { x: 1348, y: 1200 }, { x: 700, y: 1800 }]; for (var i = 0; i < 5; i++) { var cardData = generateRandomCard(); var card = new Card(cardData); card.x = cardPositions[i].x; card.y = cardPositions[i].y; currentCards.push(card); game.addChild(card); // Track negative cards if (cardData.type === "negative") { negativeCards.push(card); } } updateCardsVisual(); } function updateCardsVisual() { for (var i = 0; i < currentCards.length; i++) { currentCards[i].updateVisual(); } } function updateUI() { coinsText.setText("Coins: " + coins); pointsText.setText("Points: " + points); turnText.setText("Turn: " + turn); requiredText.setText("Need: " + requiredPoints + " pts"); comboText.setText("Combo: " + comboCards.length + "/" + maxComboSize + " (x" + comboMultiplier.toFixed(1) + ")"); growthText.setText("Coin Growth: +" + perTurnCoinGrowth + "/turn"); // Update progress bar var progress = Math.min(points / requiredPoints, 1); progressBarFill.width = 1600 * progress; if (points >= requiredPoints) { progressBarFill.tint = 0x2ecc71; } else { progressBarFill.tint = 0xe74c3c; } updateCardsVisual(); } function nextTurn() { if (gamePhase !== 'playing') return; // Apply negative card effects before ending turn for (var i = 0; i < negativeCards.length; i++) { var negativeCard = negativeCards[i]; if (!negativeCard.purchased && negativeCard.cardData.negativeEffect) { applyNegativeEffect(negativeCard.cardData.negativeEffect); // Flash screen red briefly to show negative effect LK.effects.flashScreen(0xe74c3c, 300); } } turn++; LK.getSound('turnAdvance').play(); // Calculate total coin income: base + checkpoint bonus + permanent bonus + per-turn growth var baseCoinIncome = 3 + Math.floor(checkpoint / 2); var totalCoinIncome = baseCoinIncome + permanentCoinBonus + perTurnCoinGrowth; coins += totalCoinIncome; // Increase per-turn coin growth by 1 each turn perTurnCoinGrowth += 1; // Check for checkpoint every 5 turns if (turn % 5 === 1 && turn > 1) { checkCheckpoint(); } else { generateCards(); updateUI(); } } function startGame() { if (mainMenu) { mainMenu.destroy(); mainMenu = null; } // Stop menu music and start gameplay music LK.stopMusic(); LK.playMusic('gameplayMusic', { fade: { start: 0, end: 0.4, duration: 1000 } }); // Reset game state coins = 10; points = 0; turn = 1; checkpoint = 1; requiredPoints = 20; currentCards = []; gamePhase = 'playing'; purchasedCardTypes = {}; nextCardCostReduction = 0; permanentCoinBonus = 0; globalPointMultiplier = 1; skipNextCheckpoint = false; comboMultiplier = 1; comboCards = []; maxComboSize = 3; perTurnCoinGrowth = 0; negativeCards = []; // Show game UI elements coinsText.visible = true; pointsText.visible = true; turnText.visible = true; requiredText.visible = true; comboText.visible = true; growthText.visible = true; progressBarBg.visible = true; progressBarFill.visible = true; nextTurnButton.visible = true; nextTurnText.visible = true; // Start the game generateCards(); updateUI(); } function checkCheckpoint() { if (points >= requiredPoints) { // Pass checkpoint checkpoint++; requiredPoints = Math.floor(requiredPoints * 1.8); // Points are now maintained between checkpoints LK.getSound('checkpoint').play(); // Flash screen green LK.effects.flashScreen(0x2ecc71, 1000); generateCards(); updateUI(); LK.setScore(checkpoint - 1); } else { // Fail checkpoint - game over gamePhase = 'gameOver'; LK.getSound('gameOver').play(); LK.stopMusic(); LK.playMusic('gameOverMusic', { fade: { start: 0, end: 0.6, duration: 800 } }); LK.effects.flashScreen(0xe74c3c, 1500); LK.setTimeout(function () { LK.showGameOver(); }, 1500); } } // Event handlers nextTurnButton.down = function (x, y, obj) { nextTurn(); }; game.down = function (x, y, obj) { if (gamePhase !== 'playing') return; // Use direct x, y coordinates instead of trying to convert positions // Check if clicked on next turn button if (x >= nextTurnButton.x - 200 && x <= nextTurnButton.x + 200 && y >= nextTurnButton.y - 40 && y <= nextTurnButton.y + 40) { nextTurn(); } }; // Hide UI elements initially coinsText.visible = false; pointsText.visible = false; turnText.visible = false; requiredText.visible = false; comboText.visible = false; growthText.visible = false; progressBarBg.visible = false; progressBarFill.visible = false; nextTurnButton.visible = false; nextTurnText.visible = false; // Show main menu mainMenu = new MainMenu(); game.addChild(mainMenu); // Start menu music LK.playMusic('menuMusic', { fade: { start: 0, end: 0.7, duration: 1500 } });
/****
* Plugins
****/
var tween = LK.import("@upit/tween.v1");
/****
* Classes
****/
var Card = Container.expand(function (cardData) {
var self = Container.call(this);
self.cardData = cardData;
self.purchased = false;
// Card border
var border = self.attachAsset('cardBorder', {
anchorX: 0.5,
anchorY: 0.5
});
// Card background
var background = self.attachAsset('cardBackground', {
anchorX: 0.5,
anchorY: 0.5
});
// Card title
self.titleText = new Text2(cardData.name, {
size: 56,
fill: 0xFFFFFF
});
self.titleText.anchor.set(0.5, 0);
self.titleText.x = 0;
self.titleText.y = -160;
self.addChild(self.titleText);
// Card description
self.descText = new Text2(cardData.description, {
size: 40,
fill: 0xECF0F1
});
self.descText.anchor.set(0.5, 0);
self.descText.x = 0;
self.descText.y = -100;
self.addChild(self.descText);
// Points text
self.pointsText = new Text2("+" + cardData.points + " pts", {
size: 48,
fill: 0xE74C3C
});
self.pointsText.anchor.set(0.5, 0);
self.pointsText.x = 0;
self.pointsText.y = -40;
self.addChild(self.pointsText);
// Cost and buy button
self.buyButton = self.attachAsset('buyButton', {
anchorX: 0.5,
anchorY: 0.5
});
self.buyButton.y = 120;
self.costText = new Text2("Buy: " + cardData.cost + " coins", {
size: 36,
fill: 0xFFFFFF
});
self.costText.anchor.set(0.5, 0.5);
self.costText.x = 0;
self.costText.y = 120;
self.addChild(self.costText);
self.updateVisual = function () {
if (self.purchased) {
if (self.cardData.type === "negative") {
background.tint = 0x2ecc71; // Green for deactivated negative card
self.titleText.setText(self.cardData.name + " (DEACTIVATED)");
} else {
background.tint = 0x27ae60;
}
self.buyButton.visible = false;
self.costText.visible = false;
} else {
var actualCost = Math.max(1, self.cardData.cost - nextCardCostReduction);
if (self.cardData.type === "negative") {
self.costText.setText("Deactivate: " + actualCost + " coins");
background.tint = 0xe74c3c; // Red for active negative card
self.buyButton.tint = 0xe67e22; // Orange buy button for negative
} else {
if (nextCardCostReduction > 0) {
self.costText.setText("Buy: " + actualCost + " coins (was " + self.cardData.cost + ")");
} else {
self.costText.setText("Buy: " + actualCost + " coins");
}
if (coins < actualCost) {
background.tint = 0x7f8c8d;
self.buyButton.tint = 0x7f8c8d;
} else {
background.tint = 0x2c3e50;
self.buyButton.tint = 0x27ae60;
}
}
}
};
self.over = function (x, y, obj) {
if (!self.purchased) {
LK.getSound('cardHover').play();
}
};
self.down = function (x, y, obj) {
if (!self.purchased && coins >= self.cardData.cost) {
self.purchase();
}
};
self.purchase = function () {
if (self.purchased || coins < self.cardData.cost) return;
var actualCost = Math.max(1, self.cardData.cost - nextCardCostReduction);
coins -= actualCost;
nextCardCostReduction = 0;
self.purchased = true;
// Track card types
if (!purchasedCardTypes[self.cardData.type]) {
purchasedCardTypes[self.cardData.type] = 0;
}
purchasedCardTypes[self.cardData.type]++;
// Apply card abilities
var pointsToAdd = self.cardData.points;
if (self.cardData.ability) {
pointsToAdd = applyCardAbility(self.cardData, pointsToAdd);
}
// Apply global multiplier
pointsToAdd = Math.floor(pointsToAdd * globalPointMultiplier);
points += pointsToAdd;
self.updateVisual();
updateUI();
LK.getSound('cardBuy').play();
tween(self, {
scaleX: 1.1,
scaleY: 1.1
}, {
duration: 200,
easing: tween.easeOut,
onFinish: function onFinish() {
tween(self, {
scaleX: 1,
scaleY: 1
}, {
duration: 200,
easing: tween.easeOut
});
}
});
};
return self;
});
var MainMenu = Container.expand(function () {
var self = Container.call(this);
// Menu background
var menuBg = self.attachAsset('gameBoard', {
anchorX: 0.5,
anchorY: 0.5,
x: 1024,
y: 1366
});
menuBg.tint = 0x2c3e50;
// Game title
var titleText = new Text2("CARD STRATEGY", {
size: 120,
fill: 0xFFFFFF
});
titleText.anchor.set(0.5, 0.5);
titleText.x = 1024;
titleText.y = 400;
self.addChild(titleText);
// Subtitle
var subtitleText = new Text2("Collect cards to survive!", {
size: 60,
fill: 0xBDC3C7
});
subtitleText.anchor.set(0.5, 0.5);
subtitleText.x = 1024;
subtitleText.y = 500;
self.addChild(subtitleText);
// Play button
var playButton = self.attachAsset('buyButton', {
anchorX: 0.5,
anchorY: 0.5,
x: 1024,
y: 800,
scaleX: 1.5,
scaleY: 1.5
});
playButton.tint = 0x27ae60;
var playText = new Text2("PLAY", {
size: 80,
fill: 0xFFFFFF
});
playText.anchor.set(0.5, 0.5);
playText.x = 1024;
playText.y = 800;
self.addChild(playText);
// Instructions
var instructionsText = new Text2("• Buy cards to earn points\n• Survive checkpoint requirements every 5 turns\n• Use combos and special abilities\n• Deactivate negative cards to avoid penalties", {
size: 48,
fill: 0xECF0F1
});
instructionsText.anchor.set(0.5, 0.5);
instructionsText.x = 1024;
instructionsText.y = 1200;
self.addChild(instructionsText);
// Credits
var creditsText = new Text2("Made with FRVR", {
size: 36,
fill: 0x95A5A6
});
creditsText.anchor.set(0.5, 0.5);
creditsText.x = 1024;
creditsText.y = 1600;
self.addChild(creditsText);
// Play button click handler
playButton.down = function (x, y, obj) {
startGame();
};
return self;
});
/****
* Initialize Game
****/
var game = new LK.Game({
backgroundColor: 0x0f1419
});
/****
* Game Code
****/
// Game state variables
var coins = 10;
var points = 0;
var turn = 1;
var checkpoint = 1;
var requiredPoints = 20;
var currentCards = [];
var gamePhase = 'menu'; // 'menu', 'playing', 'checkpoint', 'gameOver'
var mainMenu = null;
// Game mechanics tracking
var purchasedCardTypes = {};
var nextCardCostReduction = 0;
var permanentCoinBonus = 0;
var globalPointMultiplier = 1;
var skipNextCheckpoint = false;
// Combo system variables
var comboMultiplier = 1;
var comboCards = [];
var maxComboSize = 3;
var perTurnCoinGrowth = 0;
// Negative cards system
var negativeCards = [];
var negativeCardTemplates = [{
name: "Tax Collector",
description: "Lose 30% of coins",
points: 0,
cost: 8,
type: "negative",
negativeEffect: "taxCoins"
}, {
name: "Point Drain",
description: "Lose 25% of points",
points: 0,
cost: 12,
type: "negative",
negativeEffect: "drainPoints"
}, {
name: "Coin Thief",
description: "Lose 15 coins",
points: 0,
cost: 6,
type: "negative",
negativeEffect: "stealCoins"
}, {
name: "Deflation",
description: "Reduce coin growth by 2",
points: 0,
cost: 10,
type: "negative",
negativeEffect: "reduceGrowth"
}, {
name: "Combo Breaker",
description: "Reset all combos",
points: 0,
cost: 7,
type: "negative",
negativeEffect: "breakCombo"
}];
// Card templates organized by checkpoint level
var cardTemplatesByLevel = {
1: [{
// Basic cards for checkpoint 1
name: "Basic Card",
description: "Simple points",
points: 5,
cost: 3,
type: "basic"
}, {
name: "Coin Card",
description: "Steady income",
points: 3,
cost: 2,
type: "economy"
}, {
name: "Power Card",
description: "High value",
points: 12,
cost: 8,
type: "power"
}, {
name: "Lucky Card",
description: "Bonus points",
points: 8,
cost: 5,
type: "luck"
}, {
name: "Quick Card",
description: "Fast points",
points: 4,
cost: 2,
type: "quick"
}],
2: [{
// Advanced cards for checkpoint 2+
name: "Mega Card",
description: "Massive points",
points: 20,
cost: 15,
type: "mega"
}, {
name: "Super Card",
description: "Great value",
points: 15,
cost: 10,
type: "super"
}, {
name: "Bonus Card",
description: "Extra boost",
points: 6,
cost: 4,
type: "bonus"
}, {
name: "Multiplier Card",
description: "x2 next card points",
points: 2,
cost: 4,
type: "multiplier",
ability: "nextCardMultiplier"
}, {
name: "Discount Card",
description: "Next card costs 50% less",
points: 1,
cost: 3,
type: "discount",
ability: "costReduction"
}, {
name: "Combo Starter",
description: "Begin a combo chain",
points: 3,
cost: 2,
type: "combo",
ability: "comboStarter"
}, {
name: "Combo Builder",
description: "Extend current combo",
points: 5,
cost: 4,
type: "combo",
ability: "comboBuilder"
}],
3: [{
// Expert cards for checkpoint 3+
name: "Economy Synergy",
description: "+3 pts per Economy card",
points: 1,
cost: 5,
type: "synergy",
ability: "economySynergy"
}, {
name: "Power Synergy",
description: "+5 pts per Power card",
points: 2,
cost: 7,
type: "synergy",
ability: "powerSynergy"
}, {
name: "Collection Bonus",
description: "+2 pts per unique type",
points: 3,
cost: 6,
type: "collection",
ability: "typeBonus"
}, {
name: "Lucky Streak",
description: "+1 pt per Lucky card",
points: 2,
cost: 3,
type: "streak",
ability: "luckySynergy"
}, {
name: "Coin Generator",
description: "+2 coins next turn",
points: 1,
cost: 2,
type: "generator",
ability: "coinBonus"
}, {
name: "Combo Master",
description: "Complete combo +50% bonus",
points: 8,
cost: 6,
type: "combo",
ability: "comboMaster"
}, {
name: "Chain Reactor",
description: "Each combo card +2 coins/turn",
points: 4,
cost: 5,
type: "combo",
ability: "comboEconomy"
}],
4: [{
// Master cards for checkpoint 4+
name: "Point Doubler",
description: "Double current points",
points: 0,
cost: 12,
type: "doubler",
ability: "doublePoints"
}, {
name: "Chain Multiplier",
description: "Each purchased card +10% pts",
points: 5,
cost: 8,
type: "chain",
ability: "chainMultiplier"
}, {
name: "Compound Engine",
description: "Points grow exponentially",
points: 3,
cost: 10,
type: "compound",
ability: "compoundGrowth"
}, {
name: "Universal Synergy",
description: "+1 pt per ANY card owned",
points: 2,
cost: 6,
type: "universal",
ability: "universalSynergy"
}, {
name: "Mega Coin Bank",
description: "+5 coins per turn forever",
points: 5,
cost: 15,
type: "bank",
ability: "megaCoinBonus"
}, {
name: "Combo Engine",
description: "Triple combo bonuses",
points: 10,
cost: 18,
type: "combo",
ability: "comboTriple"
}],
5: [{
// Legendary cards for checkpoint 5+
name: "Infinity Engine",
description: "Triple all future points",
points: 10,
cost: 20,
type: "infinity",
ability: "tripleMultiplier"
}, {
name: "Checkpoint Keeper",
description: "+50% req points for easier pass",
points: 15,
cost: 25,
type: "keeper",
ability: "easierCheckpoint"
}, {
name: "Card Recycler",
description: "Get 50% coin refund on all cards",
points: 8,
cost: 18,
type: "recycler",
ability: "coinRefund"
}, {
name: "Time Manipulator",
description: "Skip next checkpoint req",
points: 20,
cost: 30,
type: "time",
ability: "skipCheckpoint"
}, {
name: "Infinite Combos",
description: "No combo size limit, x5 bonus",
points: 30,
cost: 40,
type: "combo",
ability: "infiniteCombo"
}]
};
// Legacy compatibility - combine all templates
var cardTemplates = [];
for (var level in cardTemplatesByLevel) {
cardTemplates = cardTemplates.concat(cardTemplatesByLevel[level]);
}
// UI Elements
var board = game.attachAsset('gameBoard', {
anchorX: 0.5,
anchorY: 0.5,
x: 1024,
y: 1366
});
// Coins display
var coinsText = new Text2("Coins: " + coins, {
size: 48,
fill: 0xF1C40F
});
coinsText.anchor.set(0, 0);
coinsText.x = 100;
coinsText.y = 150;
LK.gui.topLeft.addChild(coinsText);
// Points display
var pointsText = new Text2("Points: " + points, {
size: 48,
fill: 0xE74C3C
});
pointsText.anchor.set(0, 0);
pointsText.x = 100;
pointsText.y = 220;
LK.gui.topLeft.addChild(pointsText);
// Turn display
var turnText = new Text2("Turn: " + turn, {
size: 36,
fill: 0x3498DB
});
turnText.anchor.set(0, 0);
turnText.x = 100;
turnText.y = 290;
LK.gui.topLeft.addChild(turnText);
// Required points display
var requiredText = new Text2("Need: " + requiredPoints + " pts", {
size: 36,
fill: 0xE67E22
});
requiredText.anchor.set(0, 0);
requiredText.x = 100;
requiredText.y = 340;
LK.gui.topLeft.addChild(requiredText);
// Combo display
var comboText = new Text2("Combo: " + comboCards.length + "/" + maxComboSize, {
size: 32,
fill: 0x9B59B6
});
comboText.anchor.set(0, 0);
comboText.x = 100;
comboText.y = 390;
LK.gui.topLeft.addChild(comboText);
// Coin growth display
var growthText = new Text2("Coin Growth: +" + perTurnCoinGrowth + "/turn", {
size: 28,
fill: 0x1ABC9C
});
growthText.anchor.set(0, 0);
growthText.x = 100;
growthText.y = 440;
LK.gui.topLeft.addChild(growthText);
// Progress bar
var progressBarBg = game.attachAsset('progressBar', {
anchorX: 0.5,
anchorY: 0,
x: 1024,
y: 200
});
var progressBarFill = game.attachAsset('progressFill', {
anchorX: 0,
anchorY: 0,
x: 224,
y: 200
});
// Next turn button
var nextTurnButton = game.attachAsset('nextTurnButton', {
anchorX: 0.5,
anchorY: 0.5,
x: 1024,
y: 2500
});
var nextTurnText = new Text2("Next Turn", {
size: 44,
fill: 0xFFFFFF
});
nextTurnText.anchor.set(0.5, 0.5);
nextTurnText.x = 1024;
nextTurnText.y = 2500;
game.addChild(nextTurnText);
function applyNegativeEffect(negativeEffect) {
LK.getSound('negativeEffect').play();
switch (negativeEffect) {
case "taxCoins":
var coinsLost = Math.floor(coins * 0.3);
coins = Math.max(0, coins - coinsLost);
break;
case "drainPoints":
var pointsLost = Math.floor(points * 0.25);
points = Math.max(0, points - pointsLost);
break;
case "stealCoins":
coins = Math.max(0, coins - 15);
break;
case "reduceGrowth":
perTurnCoinGrowth = Math.max(0, perTurnCoinGrowth - 2);
break;
case "breakCombo":
comboCards = [];
comboMultiplier = 1;
break;
}
}
function applyCardAbility(cardData, basePoints) {
var bonusPoints = 0;
switch (cardData.ability) {
case "nextCardMultiplier":
// This will be handled when the next card is purchased
return basePoints;
case "costReduction":
nextCardCostReduction = Math.floor(cardData.cost * 0.5);
return basePoints;
case "economySynergy":
bonusPoints = (purchasedCardTypes["economy"] || 0) * 3;
return basePoints + bonusPoints;
case "powerSynergy":
bonusPoints = (purchasedCardTypes["power"] || 0) * 5;
return basePoints + bonusPoints;
case "luckySynergy":
bonusPoints = (purchasedCardTypes["luck"] || 0) * 1;
return basePoints + bonusPoints;
case "typeBonus":
var uniqueTypes = Object.keys(purchasedCardTypes).length;
bonusPoints = uniqueTypes * 2;
return basePoints + bonusPoints;
case "coinBonus":
coins += 2;
return basePoints;
case "doublePoints":
points = points * 2;
return 0;
case "chainMultiplier":
var totalCards = 0;
for (var type in purchasedCardTypes) {
totalCards += purchasedCardTypes[type];
}
bonusPoints = Math.floor(totalCards * 0.1 * basePoints);
return basePoints + bonusPoints;
case "compoundGrowth":
bonusPoints = Math.floor(points * 0.1);
return basePoints + bonusPoints;
case "universalSynergy":
var totalCards = 0;
for (var type in purchasedCardTypes) {
totalCards += purchasedCardTypes[type];
}
bonusPoints = totalCards;
return basePoints + bonusPoints;
case "megaCoinBonus":
// Add permanent income bonus
if (!permanentCoinBonus) permanentCoinBonus = 0;
permanentCoinBonus += 5;
return basePoints;
case "tripleMultiplier":
if (!globalPointMultiplier) globalPointMultiplier = 1;
globalPointMultiplier *= 3;
return basePoints;
case "easierCheckpoint":
requiredPoints = Math.floor(requiredPoints * 0.5);
return basePoints;
case "coinRefund":
coins += Math.floor(cardData.cost * 0.5);
return basePoints;
case "skipCheckpoint":
// Skip next checkpoint requirement
skipNextCheckpoint = true;
return basePoints;
case "comboStarter":
comboCards = [cardData];
comboMultiplier = 1.2;
return basePoints;
case "comboBuilder":
if (comboCards.length > 0 && comboCards.length < maxComboSize) {
comboCards.push(cardData);
comboMultiplier += 0.3;
bonusPoints = Math.floor(basePoints * (comboMultiplier - 1));
return basePoints + bonusPoints;
} else {
return basePoints;
}
case "comboMaster":
if (comboCards.length >= maxComboSize) {
bonusPoints = Math.floor(basePoints * 0.5);
LK.getSound('comboComplete').play();
comboCards = [];
comboMultiplier = 1;
return basePoints + bonusPoints;
} else {
return basePoints;
}
case "comboEconomy":
var comboCardCount = 0;
for (var type in purchasedCardTypes) {
if (type === "combo") {
comboCardCount = purchasedCardTypes[type];
break;
}
}
perTurnCoinGrowth += comboCardCount * 2;
return basePoints;
case "comboTriple":
comboMultiplier *= 3;
return basePoints;
case "infiniteCombo":
maxComboSize = 999;
comboMultiplier *= 5;
return basePoints;
// Don't add base points since we doubled existing
default:
return basePoints;
}
}
function generateRandomCard() {
// 20% chance to generate a negative card from checkpoint 2 onwards
if (checkpoint >= 2 && Math.random() < 0.2) {
var template = negativeCardTemplates[Math.floor(Math.random() * negativeCardTemplates.length)];
var scaleFactor = 1 + (checkpoint - 1) * 0.15;
return {
name: template.name,
description: template.description,
points: template.points,
cost: Math.floor(template.cost * scaleFactor),
type: template.type,
negativeEffect: template.negativeEffect
};
}
// Get available card templates based on current checkpoint
var availableTemplates = [];
for (var level = 1; level <= Math.min(checkpoint, 5); level++) {
if (cardTemplatesByLevel[level]) {
availableTemplates = availableTemplates.concat(cardTemplatesByLevel[level]);
}
}
// Fallback to level 1 cards if no templates available
if (availableTemplates.length === 0) {
availableTemplates = cardTemplatesByLevel[1] || [];
}
// Higher checkpoints have better chance of getting advanced cards
var template;
if (checkpoint >= 3 && Math.random() < 0.6) {
// 60% chance for advanced cards in checkpoint 3+
var advancedTemplates = [];
for (var level = Math.max(2, checkpoint - 1); level <= Math.min(checkpoint, 5); level++) {
if (cardTemplatesByLevel[level]) {
advancedTemplates = advancedTemplates.concat(cardTemplatesByLevel[level]);
}
}
if (advancedTemplates.length > 0) {
template = advancedTemplates[Math.floor(Math.random() * advancedTemplates.length)];
} else {
template = availableTemplates[Math.floor(Math.random() * availableTemplates.length)];
}
} else {
template = availableTemplates[Math.floor(Math.random() * availableTemplates.length)];
}
// Final safety check - use first available template if still undefined
if (!template && availableTemplates.length > 0) {
template = availableTemplates[0];
}
// If still no template, create a default one
if (!template) {
template = {
name: "Emergency Card",
description: "Basic fallback",
points: 3,
cost: 2,
type: "basic"
};
}
var scaleFactor = 1 + (checkpoint - 1) * 0.2;
return {
name: template.name,
description: template.description,
points: Math.floor(template.points * scaleFactor),
cost: Math.floor(template.cost * scaleFactor),
type: template.type,
ability: template.ability
};
}
function generateCards() {
// Clear existing cards
for (var i = 0; i < currentCards.length; i++) {
currentCards[i].destroy();
}
currentCards = [];
// Clear negative cards tracking for new turn
negativeCards = [];
// Generate 5 new cards in two vertical columns with doubled size
var cardPositions = [{
x: 700,
y: 600
}, {
x: 1348,
y: 600
}, {
x: 700,
y: 1200
}, {
x: 1348,
y: 1200
}, {
x: 700,
y: 1800
}];
for (var i = 0; i < 5; i++) {
var cardData = generateRandomCard();
var card = new Card(cardData);
card.x = cardPositions[i].x;
card.y = cardPositions[i].y;
currentCards.push(card);
game.addChild(card);
// Track negative cards
if (cardData.type === "negative") {
negativeCards.push(card);
}
}
updateCardsVisual();
}
function updateCardsVisual() {
for (var i = 0; i < currentCards.length; i++) {
currentCards[i].updateVisual();
}
}
function updateUI() {
coinsText.setText("Coins: " + coins);
pointsText.setText("Points: " + points);
turnText.setText("Turn: " + turn);
requiredText.setText("Need: " + requiredPoints + " pts");
comboText.setText("Combo: " + comboCards.length + "/" + maxComboSize + " (x" + comboMultiplier.toFixed(1) + ")");
growthText.setText("Coin Growth: +" + perTurnCoinGrowth + "/turn");
// Update progress bar
var progress = Math.min(points / requiredPoints, 1);
progressBarFill.width = 1600 * progress;
if (points >= requiredPoints) {
progressBarFill.tint = 0x2ecc71;
} else {
progressBarFill.tint = 0xe74c3c;
}
updateCardsVisual();
}
function nextTurn() {
if (gamePhase !== 'playing') return;
// Apply negative card effects before ending turn
for (var i = 0; i < negativeCards.length; i++) {
var negativeCard = negativeCards[i];
if (!negativeCard.purchased && negativeCard.cardData.negativeEffect) {
applyNegativeEffect(negativeCard.cardData.negativeEffect);
// Flash screen red briefly to show negative effect
LK.effects.flashScreen(0xe74c3c, 300);
}
}
turn++;
LK.getSound('turnAdvance').play();
// Calculate total coin income: base + checkpoint bonus + permanent bonus + per-turn growth
var baseCoinIncome = 3 + Math.floor(checkpoint / 2);
var totalCoinIncome = baseCoinIncome + permanentCoinBonus + perTurnCoinGrowth;
coins += totalCoinIncome;
// Increase per-turn coin growth by 1 each turn
perTurnCoinGrowth += 1;
// Check for checkpoint every 5 turns
if (turn % 5 === 1 && turn > 1) {
checkCheckpoint();
} else {
generateCards();
updateUI();
}
}
function startGame() {
if (mainMenu) {
mainMenu.destroy();
mainMenu = null;
}
// Stop menu music and start gameplay music
LK.stopMusic();
LK.playMusic('gameplayMusic', {
fade: {
start: 0,
end: 0.4,
duration: 1000
}
});
// Reset game state
coins = 10;
points = 0;
turn = 1;
checkpoint = 1;
requiredPoints = 20;
currentCards = [];
gamePhase = 'playing';
purchasedCardTypes = {};
nextCardCostReduction = 0;
permanentCoinBonus = 0;
globalPointMultiplier = 1;
skipNextCheckpoint = false;
comboMultiplier = 1;
comboCards = [];
maxComboSize = 3;
perTurnCoinGrowth = 0;
negativeCards = [];
// Show game UI elements
coinsText.visible = true;
pointsText.visible = true;
turnText.visible = true;
requiredText.visible = true;
comboText.visible = true;
growthText.visible = true;
progressBarBg.visible = true;
progressBarFill.visible = true;
nextTurnButton.visible = true;
nextTurnText.visible = true;
// Start the game
generateCards();
updateUI();
}
function checkCheckpoint() {
if (points >= requiredPoints) {
// Pass checkpoint
checkpoint++;
requiredPoints = Math.floor(requiredPoints * 1.8);
// Points are now maintained between checkpoints
LK.getSound('checkpoint').play();
// Flash screen green
LK.effects.flashScreen(0x2ecc71, 1000);
generateCards();
updateUI();
LK.setScore(checkpoint - 1);
} else {
// Fail checkpoint - game over
gamePhase = 'gameOver';
LK.getSound('gameOver').play();
LK.stopMusic();
LK.playMusic('gameOverMusic', {
fade: {
start: 0,
end: 0.6,
duration: 800
}
});
LK.effects.flashScreen(0xe74c3c, 1500);
LK.setTimeout(function () {
LK.showGameOver();
}, 1500);
}
}
// Event handlers
nextTurnButton.down = function (x, y, obj) {
nextTurn();
};
game.down = function (x, y, obj) {
if (gamePhase !== 'playing') return;
// Use direct x, y coordinates instead of trying to convert positions
// Check if clicked on next turn button
if (x >= nextTurnButton.x - 200 && x <= nextTurnButton.x + 200 && y >= nextTurnButton.y - 40 && y <= nextTurnButton.y + 40) {
nextTurn();
}
};
// Hide UI elements initially
coinsText.visible = false;
pointsText.visible = false;
turnText.visible = false;
requiredText.visible = false;
comboText.visible = false;
growthText.visible = false;
progressBarBg.visible = false;
progressBarFill.visible = false;
nextTurnButton.visible = false;
nextTurnText.visible = false;
// Show main menu
mainMenu = new MainMenu();
game.addChild(mainMenu);
// Start menu music
LK.playMusic('menuMusic', {
fade: {
start: 0,
end: 0.7,
duration: 1500
}
});