/****
* 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
}
});