/**** * Plugins ****/ var tween = LK.import("@upit/tween.v1"); var storage = LK.import("@upit/storage.v1"); /**** * Classes ****/ var BingoCard = Container.expand(function (cardIndex) { var self = Container.call(this); self.cardIndex = cardIndex; self.numbers = []; self.bingoNumbers = []; self.cardBg = self.attachAsset('bingoCard', { anchorX: 0.5, anchorY: 0.5 }); // Generate 15 random unique numbers between 1-75 self.generateNumbers = function () { var availableNumbers = []; for (var i = 1; i <= 75; i++) { availableNumbers.push(i); } for (var j = 0; j < 15; j++) { var randomIndex = Math.floor(Math.random() * availableNumbers.length); self.numbers.push(availableNumbers[randomIndex]); availableNumbers.splice(randomIndex, 1); } }; self.createNumberGrid = function () { var startX = -270; var startY = -90; var spacingX = 135; var spacingY = 90; for (var row = 0; row < 3; row++) { self.bingoNumbers[row] = []; for (var col = 0; col < 5; col++) { var numberIndex = row * 5 + col; var bingoNumber = new BingoNumber(self.numbers[numberIndex], self.cardIndex, row, col); bingoNumber.x = startX + col * spacingX; bingoNumber.y = startY + row * spacingY; self.addChild(bingoNumber); self.bingoNumbers[row][col] = bingoNumber; } } }; self.generateNumbers(); self.createNumberGrid(); // Add touch event to regenerate card numbers self.down = function (x, y, obj) { // Clear existing numbers and regenerate self.numbers = []; self.generateNumbers(); // Update all number displays for (var row = 0; row < 3; row++) { for (var col = 0; col < 5; col++) { var numberIndex = row * 5 + col; var bingoNumber = self.bingoNumbers[row][col]; // Reset the number and visual state bingoNumber.number = self.numbers[numberIndex]; bingoNumber.isMarked = false; // Reset background to unmarked state bingoNumber.removeChild(bingoNumber.bg); bingoNumber.bg = bingoNumber.attachAsset('bingoNumber', { anchorX: 0.5, anchorY: 0.5 }); // Update number text with new number and black color bingoNumber.removeChild(bingoNumber.numberText); bingoNumber.numberText = new Text2(bingoNumber.number.toString(), { size: 43, fill: 0x000000 }); bingoNumber.numberText.anchor.set(0.5, 0.5); bingoNumber.addChild(bingoNumber.numberText); } } }; return self; }); var BingoNumber = Container.expand(function (number, cardIndex, row, col) { var self = Container.call(this); self.number = number; self.cardIndex = cardIndex; self.row = row; self.col = col; self.isMarked = false; self.bg = self.attachAsset('bingoNumber', { anchorX: 0.5, anchorY: 0.5 }); self.numberText = new Text2(number.toString(), { size: 43, fill: 0x000000 }); self.numberText.anchor.set(0.5, 0.5); self.addChild(self.numberText); self.markNumber = function () { if (!self.isMarked) { self.isMarked = true; self.removeChild(self.bg); self.bg = self.attachAsset('markedNumber', { anchorX: 0.5, anchorY: 0.5 }); // Replace the text with white color self.removeChild(self.numberText); self.numberText = new Text2(self.number.toString(), { size: 43, fill: 0xFFFFFF }); self.numberText.anchor.set(0.5, 0.5); self.addChild(self.numberText); LK.getSound('numberMarked').play(); // Check for completed lines checkForCompletedLines(self.cardIndex); } }; self.down = function (x, y, obj) { // Numbers are now automatically marked, no manual interaction needed }; return self; }); var BingoWindow = Container.expand(function () { var self = Container.call(this); // Create celebration window background self.windowBg = self.attachAsset('bingoWindow', { anchorX: 0.5, anchorY: 0.5 }); // Create BINGO text self.bingoText = new Text2('BINGO!', { size: 120, fill: 0x000000 }); self.bingoText.anchor.set(0.5, 0.5); self.addChild(self.bingoText); // Position at center of screen self.x = 1024; self.y = 1366; // Start invisible self.alpha = 0; self.scaleX = 0.1; self.scaleY = 0.1; self.show = function () { // Animate window appearance tween(self, { alpha: 1, scaleX: 1, scaleY: 1 }, { duration: 500, easing: tween.easeOut }); // Add pulsing animation to text tween(self.bingoText, { scaleX: 1.2, scaleY: 1.2 }, { duration: 300, easing: tween.easeInOut, onFinish: function onFinish() { tween(self.bingoText, { scaleX: 1, scaleY: 1 }, { duration: 300, easing: tween.easeInOut }); } }); // Auto-hide after 0.75 seconds LK.setTimeout(function () { self.hide(); }, 750); }; self.hide = function () { tween(self, { alpha: 0, scaleX: 0.1, scaleY: 0.1 }, { duration: 300, easing: tween.easeIn, onFinish: function onFinish() { if (self.parent) { self.parent.removeChild(self); } } }); }; return self; }); var NumberBubble = Container.expand(function (number) { var self = Container.call(this); self.number = number; self.speed = -3; self.floatSpeed = 0; // Create bubble background self.bubbleBg = self.attachAsset('numberBubble', { anchorX: 0.5, anchorY: 0.5 }); // Create number text self.numberText = new Text2(number.toString(), { size: 48, fill: 0x000000 }); self.numberText.anchor.set(0.5, 0.5); self.addChild(self.numberText); // Calculate position in three horizontal rows var bubblesPerRow = 25; // 25 bubbles per row (75 total / 3 rows) var bubbleSpacing = 80; // Spacing between bubbles var rowSpacing = 90; // Spacing between rows var startX = 50; // Start position for each row var startY = 120; // Y position for first row var currentBubbleCount = numberBubbles.length; // Calculate which row and position within row var row = Math.floor(currentBubbleCount / bubblesPerRow); var positionInRow = currentBubbleCount % bubblesPerRow; // Set target position in three rows var targetX = startX + positionInRow * bubbleSpacing; var targetY = startY + row * rowSpacing; // Initialize position at bottom of screen for animation self.x = targetX; self.y = 2732 + 50; // Start below screen self.lastY = self.y; // Animate bubble entrance to target position tween(self, { y: targetY, scaleX: 1.0, scaleY: 1.0 }, { duration: 1500, easing: tween.easeOut }); // Add floating animation tween(self.bubbleBg, { rotation: Math.PI * 2 }, { duration: 4000, easing: tween.linear }); self.update = function () { // Bubbles stay fixed in position - no floating animation }; return self; }); var PauseWindow = Container.expand(function () { var self = Container.call(this); // Create window background self.windowBg = self.attachAsset('pauseWindow', { anchorX: 0.5, anchorY: 0.5, scaleX: 2, scaleY: 2 }); // Create pause title self.pauseTitle = new Text2('JUEGO PAUSADO', { size: 60, fill: 0xFFFFFF }); self.pauseTitle.anchor.set(0.5, 0.5); self.pauseTitle.y = -120; self.addChild(self.pauseTitle); // Create resume button self.resumeButton = new Container(); var resumeBg = LK.getAsset('resumeButton', { anchorX: 0.5, anchorY: 0.5 }); self.resumeButton.addChild(resumeBg); var resumeText = new Text2('CONTINUAR', { size: 40, fill: 0xFFFFFF }); resumeText.anchor.set(0.5, 0.5); self.resumeButton.addChild(resumeText); self.resumeButton.y = -20; self.addChild(self.resumeButton); // Create quit button self.quitButton = new Container(); var quitBg = LK.getAsset('quitButton', { anchorX: 0.5, anchorY: 0.5 }); self.quitButton.addChild(quitBg); var quitText = new Text2('SALIR', { size: 40, fill: 0xFFFFFF }); quitText.anchor.set(0.5, 0.5); self.quitButton.addChild(quitText); self.quitButton.y = 100; self.addChild(self.quitButton); // Position at center of screen self.x = 1024; self.y = 1366; // Start invisible self.alpha = 0; self.scaleX = 0.1; self.scaleY = 0.1; self.show = function () { // Animate window appearance tween(self, { alpha: 1, scaleX: 1, scaleY: 1 }, { duration: 300, easing: tween.easeOut }); }; self.hide = function () { tween(self, { alpha: 0, scaleX: 0.1, scaleY: 0.1 }, { duration: 200, easing: tween.easeIn, onFinish: function onFinish() { if (self.parent) { self.parent.removeChild(self); } } }); }; // Resume button event self.resumeButton.down = function (x, y, obj) { resumeGame(); }; // Quit button event self.quitButton.down = function (x, y, obj) { quitGame(); }; return self; }); var PaymentWindow = Container.expand(function () { var self = Container.call(this); // Load accumulated payments from storage, default to 0 self.totalPayments = storage.tokyoPayments || 0; // Create window background self.windowBg = self.attachAsset('paymentWindow', { anchorX: 0.5, anchorY: 0.5 }); // Create payment text self.paymentText = new Text2('Total de Tokens: $' + self.totalPayments, { size: 80, fill: 0xff0000 }); self.paymentText.anchor.set(0.5, 0.5); self.addChild(self.paymentText); // Method to add payment self.addPayment = function (amount) { self.totalPayments += amount; self.paymentText.setText('Total de Tokens: $' + self.totalPayments); // Save to storage storage.tokyoPayments = self.totalPayments; // Flash animation for payment addition tween(self.windowBg, { tint: 0xffd700 }, { duration: 200 }); tween(self.windowBg, { tint: 0xffffff }, { duration: 200 }); }; // Method to reset payments self.resetPayments = function () { self.totalPayments = 0; self.paymentText.setText('Total de Tokens: $' + self.totalPayments); storage.tokyoPayments = self.totalPayments; }; return self; }); var TokenWindow = Container.expand(function (cardIndex) { var self = Container.call(this); self.cardIndex = cardIndex; // Define predefined price options self.priceOptions = [10, 20, 30, 50, 100]; // Load saved price index from storage, default to 0 if not found var storageKey = 'tokenPrice_' + cardIndex; self.currentPriceIndex = storage[storageKey] || 0; // Create window background self.windowBg = self.attachAsset('tokenWindow', { anchorX: 0.5, anchorY: 0.5 }); // Create price text with saved price self.priceText = new Text2('Token Price: ' + self.priceOptions[self.currentPriceIndex], { size: 100, fill: 0xff0000 }); self.priceText.anchor.set(0.5, 0.5); self.addChild(self.priceText); // Add tap event to cycle through prices and save to storage self.down = function (x, y, obj) { // Only allow changing token price when game is not started if (!gameStarted) { self.currentPriceIndex = (self.currentPriceIndex + 1) % self.priceOptions.length; self.priceText.setText('Token Price: ' + self.priceOptions[self.currentPriceIndex]); // Save the selected price index to storage storage[storageKey] = self.currentPriceIndex; } }; return self; }); /**** * Initialize Game ****/ var game = new LK.Game({ backgroundColor: 0x1a1a2e }); /**** * Game Code ****/ var bingoCards = []; var currentCalledNumber = null; var calledNumbers = []; var availableNumbers = []; var callTimer = null; var completedLines = 0; var gameStarted = false; var startButton = null; var numberBubbles = []; var bingoWindow = null; var paymentWindow = null; var cardHorizontalLines = [0, 0, 0, 0]; // Track horizontal lines per card var gamePaused = false; var pauseWindow = null; var pauseButton = null; // Initialize available numbers for (var i = 1; i <= 75; i++) { availableNumbers.push(i); } // Create score display var scoreLabel = new Text2('Puntuación:', { size: 50, fill: 0xff0000 }); scoreLabel.anchor.set(0.5, 0); scoreLabel.x = -300; LK.gui.top.addChild(scoreLabel); scoreLabel.y = 250; var scoreText = new Text2('0', { size: 80, fill: 0xFFFFFF }); scoreText.anchor.set(0.5, 0); scoreText.x = -300; LK.gui.top.addChild(scoreText); scoreText.y = 300; // Create current called number display var calledNumberContainer = new Container(); var calledNumberBg = LK.getAsset('calledNumberBg', { anchorX: 0.5, anchorY: 0.5 }); calledNumberContainer.addChild(calledNumberBg); var calledNumberText = new Text2('--', { size: 36, fill: 0xFFFFFF }); calledNumberText.anchor.set(0.5, 0.5); calledNumberContainer.addChild(calledNumberText); game.addChild(calledNumberContainer); calledNumberContainer.x = 1024; calledNumberContainer.y = 150; // Create info text var infoText = new Text2('Tap START to begin the game!', { size: 30, fill: 0xFFFFFF }); infoText.anchor.set(0.5, 0.5); game.addChild(infoText); infoText.x = 1024; infoText.y = 250; // Create start button startButton = new Container(); var startButtonBg = LK.getAsset('startButton', { anchorX: 0.5, anchorY: 0.5 }); startButton.addChild(startButtonBg); var startButtonText = new Text2('START', { size: 96, fill: 0x000000 }); startButtonText.anchor.set(0.5, 0.5); startButton.addChild(startButtonText); startButton.x = 1024; startButton.y = 2500; game.addChild(startButton); startButton.down = function (x, y, obj) { if (!gameStarted) { gameStarted = true; game.removeChild(startButton); startButton = null; infoText.setText('Cards fill automatically as numbers are called!'); // Deduct token price from each card before starting the game for (var cardIdx = 0; cardIdx < bingoCards.length; cardIdx++) { var tokenStorageKey = 'tokenPrice_' + cardIdx; var tokenPriceIndex = storage[tokenStorageKey] || 0; var priceOptions = [10, 20, 30, 50, 100]; var tokenPrice = priceOptions[tokenPriceIndex]; // Deduct the token price (negative payment) paymentWindow.addPayment(-tokenPrice); } // Start the game LK.setTimeout(callNextNumber, 8); } }; // Create bingo cards - centered on screen for (var c = 0; c < 4; c++) { var card = new BingoCard(c); var row = Math.floor(c / 2); var col = c % 2; // Center cards on 2048x2732 screen - 2 cards per row var cardSpacingX = 900; // Space between cards horizontally var cardSpacingY = 780; // Space between cards vertically - increased separation var totalWidth = cardSpacingX; // Width for 2 cards var totalHeight = cardSpacingY; // Height for 2 rows var startX = (2048 - totalWidth) / 2; // Center horizontally var startY = 950; // Position below the UI elements - moved down card.x = startX + col * cardSpacingX; card.y = startY + row * cardSpacingY; game.addChild(card); bingoCards.push(card); // Create token price window below each card var tokenWindow = new TokenWindow(c); tokenWindow.x = card.x; tokenWindow.y = card.y + 350; // Position below the card game.addChild(tokenWindow); } // Create payment window at the top right of the screen paymentWindow = new PaymentWindow(); paymentWindow.x = 1500; // Position at top right - moved left paymentWindow.y = 400; game.addChild(paymentWindow); // Create buy tokens window below payment window var buyTokensWindow = new Container(); var buyTokensBg = LK.getAsset('buyTokensButton', { anchorX: 0.5, anchorY: 0.5 }); buyTokensWindow.addChild(buyTokensBg); var buyTokensText = new Text2('COMPRAR TOKENS', { size: 60, fill: 0x000000 }); buyTokensText.anchor.set(0.5, 0.5); buyTokensWindow.addChild(buyTokensText); buyTokensWindow.x = 1500; // Same x position as payment window buyTokensWindow.y = 580; // Position below payment window game.addChild(buyTokensWindow); // Create token purchase options window var tokenPurchaseWindow = null; var isTokenWindowVisible = false; // Add touch event to buy tokens window buyTokensWindow.down = function (x, y, obj) { if (!isTokenWindowVisible) { // Create purchase options window tokenPurchaseWindow = new Container(); var windowBg = LK.getAsset('pauseWindow', { anchorX: 0.5, anchorY: 0.5, scaleX: 2, scaleY: 2 }); tokenPurchaseWindow.addChild(windowBg); // Create title var titleText = new Text2('COMPRAR TOKENS', { size: 120, fill: 0xFFFFFF }); titleText.anchor.set(0.5, 0.5); titleText.y = -240; tokenPurchaseWindow.addChild(titleText); // Create 1000 tokens button var button1000 = new Container(); var button1000Bg = LK.getAsset('resumeButton', { anchorX: 0.5, anchorY: 0.5, scaleX: 2, scaleY: 2 }); button1000.addChild(button1000Bg); var text1000 = new Text2('1000 TOKENS', { size: 70, fill: 0xFFFFFF }); text1000.anchor.set(0.5, 0.5); button1000.addChild(text1000); button1000.y = -60; tokenPurchaseWindow.addChild(button1000); // Create 2000 tokens button var button2000 = new Container(); var button2000Bg = LK.getAsset('resumeButton', { anchorX: 0.5, anchorY: 0.5, scaleX: 2, scaleY: 2 }); button2000.addChild(button2000Bg); var text2000 = new Text2('2000 TOKENS', { size: 70, fill: 0xFFFFFF }); text2000.anchor.set(0.5, 0.5); button2000.addChild(text2000); button2000.y = 100; tokenPurchaseWindow.addChild(button2000); // Create close button var closeButton = new Container(); var closeBg = LK.getAsset('quitButton', { anchorX: 0.5, anchorY: 0.5, scaleX: 2, scaleY: 2 }); closeButton.addChild(closeBg); var closeText = new Text2('CERRAR', { size: 70, fill: 0xFFFFFF }); closeText.anchor.set(0.5, 0.5); closeButton.addChild(closeText); closeButton.y = 260; tokenPurchaseWindow.addChild(closeButton); // Position window at center tokenPurchaseWindow.x = 1024; tokenPurchaseWindow.y = 1366; tokenPurchaseWindow.alpha = 0; tokenPurchaseWindow.scaleX = 0.1; tokenPurchaseWindow.scaleY = 0.1; // Add to game game.addChild(tokenPurchaseWindow); isTokenWindowVisible = true; // Animate window appearance tween(tokenPurchaseWindow, { alpha: 1, scaleX: 1, scaleY: 1 }, { duration: 300, easing: tween.easeOut }); // Button events button1000.down = function (x, y, obj) { paymentWindow.addPayment(1000); hideTokenWindow(); }; button2000.down = function (x, y, obj) { paymentWindow.addPayment(2000); hideTokenWindow(); }; closeButton.down = function (x, y, obj) { hideTokenWindow(); }; } }; // Function to hide token purchase window function hideTokenWindow() { if (tokenPurchaseWindow && isTokenWindowVisible) { tween(tokenPurchaseWindow, { alpha: 0, scaleX: 0.1, scaleY: 0.1 }, { duration: 200, easing: tween.easeIn, onFinish: function onFinish() { if (tokenPurchaseWindow.parent) { tokenPurchaseWindow.parent.removeChild(tokenPurchaseWindow); } tokenPurchaseWindow = null; isTokenWindowVisible = false; } }); } } // Create pause button pauseButton = new Container(); var pauseButtonBg = LK.getAsset('pauseButton', { anchorX: 0.5, anchorY: 0.5 }); pauseButton.addChild(pauseButtonBg); var pauseButtonText = new Text2('||', { size: 120, fill: 0x000000 }); pauseButtonText.anchor.set(0.5, 0.5); pauseButton.addChild(pauseButtonText); pauseButton.x = 280; pauseButton.y = 2500; game.addChild(pauseButton); pauseButton.down = function (x, y, obj) { if (gameStarted && !gamePaused) { pauseGame(); } }; function pauseGame() { if (!gamePaused && gameStarted) { gamePaused = true; // Clear the current timer if (callTimer) { LK.clearTimeout(callTimer); callTimer = null; } // Show pause window pauseWindow = new PauseWindow(); game.addChild(pauseWindow); pauseWindow.show(); } } function resumeGame() { if (gamePaused) { gamePaused = false; // Hide pause window if (pauseWindow) { pauseWindow.hide(); pauseWindow = null; } // Resume number calling if game was active if (gameStarted && availableNumbers.length > 0) { var delay = Math.max(16 - completedLines * 6, 8); callTimer = LK.setTimeout(callNextNumber, delay); } } } function quitGame() { // Reset all game variables gamePaused = false; gameStarted = false; if (callTimer) { LK.clearTimeout(callTimer); callTimer = null; } // Hide pause window if (pauseWindow) { pauseWindow.hide(); pauseWindow = null; } // Show game over LK.setTimeout(function () { LK.showGameOver(); }, 300); } function callNextNumber() { if (availableNumbers.length > 0) { var randomIndex = Math.floor(Math.random() * availableNumbers.length); currentCalledNumber = availableNumbers[randomIndex]; availableNumbers.splice(randomIndex, 1); calledNumbers.push(currentCalledNumber); calledNumberText.setText(currentCalledNumber.toString()); LK.getSound('numberCalled').play(); // Create red bubble for the called number var bubble = new NumberBubble(currentCalledNumber); game.addChild(bubble); numberBubbles.push(bubble); // Automatically mark the called number on all cards with reduced probability for (var cardIndex = 0; cardIndex < bingoCards.length; cardIndex++) { var card = bingoCards[cardIndex]; for (var row = 0; row < 3; row++) { for (var col = 0; col < 5; col++) { var bingoNumber = card.bingoNumbers[row][col]; if (bingoNumber.number === currentCalledNumber && !bingoNumber.isMarked) { // Base probability is 70%, but reduce by 30% more for cards with existing horizontal lines var markProbability = 0.7; if (cardHorizontalLines[cardIndex] > 0) { markProbability = 0.7 * 0.5; // Reduce by 50% to achieve 30% overall reduction in second line probability } if (Math.random() < markProbability) { bingoNumber.markNumber(); } } } } } // Flash the called number tween(calledNumberBg, { tint: 0xffff00 }, { duration: 200 }); tween(calledNumberBg, { tint: 0xffffff }, { duration: 200 }); // Schedule next number call only if not paused if (!gamePaused) { var delay = Math.max(16 - completedLines * 6, 8); callTimer = LK.setTimeout(callNextNumber, delay); } } } function checkForCompletedLines(cardIndex) { var card = bingoCards[cardIndex]; var newLinesCompleted = 0; var horizontalLinesCompleted = 0; // Check horizontal lines for (var row = 0; row < 3; row++) { var lineComplete = true; for (var col = 0; col < 5; col++) { if (!card.bingoNumbers[row][col].isMarked) { lineComplete = false; break; } } if (lineComplete) { newLinesCompleted++; horizontalLinesCompleted++; } } // Update horizontal line count for this card cardHorizontalLines[cardIndex] = horizontalLinesCompleted; // Vertical and diagonal line checking removed - only horizontal lines count for scoring if (newLinesCompleted > 0) { completedLines += newLinesCompleted; LK.getSound('lineComplete').play(); // Calculate score based on token price instead of fixed 100 points var tokenStorageKey = 'tokenPrice_' + cardIndex; var tokenPriceIndex = storage[tokenStorageKey] || 0; var priceOptions = [10, 20, 30, 50, 100]; var tokenPrice = priceOptions[tokenPriceIndex]; var scoreAmount = tokenPrice * newLinesCompleted; LK.setScore(LK.getScore() + scoreAmount); scoreText.setText(LK.getScore()); // Add payment based on token price for this card var paymentAmount = tokenPrice * newLinesCompleted; paymentWindow.addPayment(paymentAmount); // Show BINGO celebration window for horizontal line completion if (horizontalLinesCompleted > 0) { bingoWindow = new BingoWindow(); game.addChild(bingoWindow); bingoWindow.show(); } // Flash the card tween(card.cardBg, { tint: 0x00ff00 }, { duration: 300 }); tween(card.cardBg, { tint: 0xffffff }, { duration: 300 }); // Check for full card completion var allMarked = true; for (var r = 0; r < 3; r++) { for (var c = 0; c < 5; c++) { if (!card.bingoNumbers[r][c].isMarked) { allMarked = false; break; } } if (!allMarked) break; } if (allMarked) { // Full card bonus is 5 times the token price var fullCardBonus = tokenPrice * 5; LK.setScore(LK.getScore() + fullCardBonus); scoreText.setText(LK.getScore()); // Check win condition - 3 completed lines or 1 full card if (completedLines >= 3) { LK.clearTimeout(callTimer); LK.setTimeout(function () { LK.showYouWin(); }, 1500); } } } } // Game will start when start button is pressed game.update = function () { // Update score display scoreText.setText(LK.getScore()); // Bubbles now stay at the top, no cleanup needed // Check if all numbers have been called if (availableNumbers.length === 0 && calledNumbers.length === 75) { LK.clearTimeout(callTimer); if (completedLines >= 1) { LK.setTimeout(function () { LK.showYouWin(); }, 1500); } else { LK.setTimeout(function () { LK.showGameOver(); }, 1500); } } };
/****
* Plugins
****/
var tween = LK.import("@upit/tween.v1");
var storage = LK.import("@upit/storage.v1");
/****
* Classes
****/
var BingoCard = Container.expand(function (cardIndex) {
var self = Container.call(this);
self.cardIndex = cardIndex;
self.numbers = [];
self.bingoNumbers = [];
self.cardBg = self.attachAsset('bingoCard', {
anchorX: 0.5,
anchorY: 0.5
});
// Generate 15 random unique numbers between 1-75
self.generateNumbers = function () {
var availableNumbers = [];
for (var i = 1; i <= 75; i++) {
availableNumbers.push(i);
}
for (var j = 0; j < 15; j++) {
var randomIndex = Math.floor(Math.random() * availableNumbers.length);
self.numbers.push(availableNumbers[randomIndex]);
availableNumbers.splice(randomIndex, 1);
}
};
self.createNumberGrid = function () {
var startX = -270;
var startY = -90;
var spacingX = 135;
var spacingY = 90;
for (var row = 0; row < 3; row++) {
self.bingoNumbers[row] = [];
for (var col = 0; col < 5; col++) {
var numberIndex = row * 5 + col;
var bingoNumber = new BingoNumber(self.numbers[numberIndex], self.cardIndex, row, col);
bingoNumber.x = startX + col * spacingX;
bingoNumber.y = startY + row * spacingY;
self.addChild(bingoNumber);
self.bingoNumbers[row][col] = bingoNumber;
}
}
};
self.generateNumbers();
self.createNumberGrid();
// Add touch event to regenerate card numbers
self.down = function (x, y, obj) {
// Clear existing numbers and regenerate
self.numbers = [];
self.generateNumbers();
// Update all number displays
for (var row = 0; row < 3; row++) {
for (var col = 0; col < 5; col++) {
var numberIndex = row * 5 + col;
var bingoNumber = self.bingoNumbers[row][col];
// Reset the number and visual state
bingoNumber.number = self.numbers[numberIndex];
bingoNumber.isMarked = false;
// Reset background to unmarked state
bingoNumber.removeChild(bingoNumber.bg);
bingoNumber.bg = bingoNumber.attachAsset('bingoNumber', {
anchorX: 0.5,
anchorY: 0.5
});
// Update number text with new number and black color
bingoNumber.removeChild(bingoNumber.numberText);
bingoNumber.numberText = new Text2(bingoNumber.number.toString(), {
size: 43,
fill: 0x000000
});
bingoNumber.numberText.anchor.set(0.5, 0.5);
bingoNumber.addChild(bingoNumber.numberText);
}
}
};
return self;
});
var BingoNumber = Container.expand(function (number, cardIndex, row, col) {
var self = Container.call(this);
self.number = number;
self.cardIndex = cardIndex;
self.row = row;
self.col = col;
self.isMarked = false;
self.bg = self.attachAsset('bingoNumber', {
anchorX: 0.5,
anchorY: 0.5
});
self.numberText = new Text2(number.toString(), {
size: 43,
fill: 0x000000
});
self.numberText.anchor.set(0.5, 0.5);
self.addChild(self.numberText);
self.markNumber = function () {
if (!self.isMarked) {
self.isMarked = true;
self.removeChild(self.bg);
self.bg = self.attachAsset('markedNumber', {
anchorX: 0.5,
anchorY: 0.5
});
// Replace the text with white color
self.removeChild(self.numberText);
self.numberText = new Text2(self.number.toString(), {
size: 43,
fill: 0xFFFFFF
});
self.numberText.anchor.set(0.5, 0.5);
self.addChild(self.numberText);
LK.getSound('numberMarked').play();
// Check for completed lines
checkForCompletedLines(self.cardIndex);
}
};
self.down = function (x, y, obj) {
// Numbers are now automatically marked, no manual interaction needed
};
return self;
});
var BingoWindow = Container.expand(function () {
var self = Container.call(this);
// Create celebration window background
self.windowBg = self.attachAsset('bingoWindow', {
anchorX: 0.5,
anchorY: 0.5
});
// Create BINGO text
self.bingoText = new Text2('BINGO!', {
size: 120,
fill: 0x000000
});
self.bingoText.anchor.set(0.5, 0.5);
self.addChild(self.bingoText);
// Position at center of screen
self.x = 1024;
self.y = 1366;
// Start invisible
self.alpha = 0;
self.scaleX = 0.1;
self.scaleY = 0.1;
self.show = function () {
// Animate window appearance
tween(self, {
alpha: 1,
scaleX: 1,
scaleY: 1
}, {
duration: 500,
easing: tween.easeOut
});
// Add pulsing animation to text
tween(self.bingoText, {
scaleX: 1.2,
scaleY: 1.2
}, {
duration: 300,
easing: tween.easeInOut,
onFinish: function onFinish() {
tween(self.bingoText, {
scaleX: 1,
scaleY: 1
}, {
duration: 300,
easing: tween.easeInOut
});
}
});
// Auto-hide after 0.75 seconds
LK.setTimeout(function () {
self.hide();
}, 750);
};
self.hide = function () {
tween(self, {
alpha: 0,
scaleX: 0.1,
scaleY: 0.1
}, {
duration: 300,
easing: tween.easeIn,
onFinish: function onFinish() {
if (self.parent) {
self.parent.removeChild(self);
}
}
});
};
return self;
});
var NumberBubble = Container.expand(function (number) {
var self = Container.call(this);
self.number = number;
self.speed = -3;
self.floatSpeed = 0;
// Create bubble background
self.bubbleBg = self.attachAsset('numberBubble', {
anchorX: 0.5,
anchorY: 0.5
});
// Create number text
self.numberText = new Text2(number.toString(), {
size: 48,
fill: 0x000000
});
self.numberText.anchor.set(0.5, 0.5);
self.addChild(self.numberText);
// Calculate position in three horizontal rows
var bubblesPerRow = 25; // 25 bubbles per row (75 total / 3 rows)
var bubbleSpacing = 80; // Spacing between bubbles
var rowSpacing = 90; // Spacing between rows
var startX = 50; // Start position for each row
var startY = 120; // Y position for first row
var currentBubbleCount = numberBubbles.length;
// Calculate which row and position within row
var row = Math.floor(currentBubbleCount / bubblesPerRow);
var positionInRow = currentBubbleCount % bubblesPerRow;
// Set target position in three rows
var targetX = startX + positionInRow * bubbleSpacing;
var targetY = startY + row * rowSpacing;
// Initialize position at bottom of screen for animation
self.x = targetX;
self.y = 2732 + 50; // Start below screen
self.lastY = self.y;
// Animate bubble entrance to target position
tween(self, {
y: targetY,
scaleX: 1.0,
scaleY: 1.0
}, {
duration: 1500,
easing: tween.easeOut
});
// Add floating animation
tween(self.bubbleBg, {
rotation: Math.PI * 2
}, {
duration: 4000,
easing: tween.linear
});
self.update = function () {
// Bubbles stay fixed in position - no floating animation
};
return self;
});
var PauseWindow = Container.expand(function () {
var self = Container.call(this);
// Create window background
self.windowBg = self.attachAsset('pauseWindow', {
anchorX: 0.5,
anchorY: 0.5,
scaleX: 2,
scaleY: 2
});
// Create pause title
self.pauseTitle = new Text2('JUEGO PAUSADO', {
size: 60,
fill: 0xFFFFFF
});
self.pauseTitle.anchor.set(0.5, 0.5);
self.pauseTitle.y = -120;
self.addChild(self.pauseTitle);
// Create resume button
self.resumeButton = new Container();
var resumeBg = LK.getAsset('resumeButton', {
anchorX: 0.5,
anchorY: 0.5
});
self.resumeButton.addChild(resumeBg);
var resumeText = new Text2('CONTINUAR', {
size: 40,
fill: 0xFFFFFF
});
resumeText.anchor.set(0.5, 0.5);
self.resumeButton.addChild(resumeText);
self.resumeButton.y = -20;
self.addChild(self.resumeButton);
// Create quit button
self.quitButton = new Container();
var quitBg = LK.getAsset('quitButton', {
anchorX: 0.5,
anchorY: 0.5
});
self.quitButton.addChild(quitBg);
var quitText = new Text2('SALIR', {
size: 40,
fill: 0xFFFFFF
});
quitText.anchor.set(0.5, 0.5);
self.quitButton.addChild(quitText);
self.quitButton.y = 100;
self.addChild(self.quitButton);
// Position at center of screen
self.x = 1024;
self.y = 1366;
// Start invisible
self.alpha = 0;
self.scaleX = 0.1;
self.scaleY = 0.1;
self.show = function () {
// Animate window appearance
tween(self, {
alpha: 1,
scaleX: 1,
scaleY: 1
}, {
duration: 300,
easing: tween.easeOut
});
};
self.hide = function () {
tween(self, {
alpha: 0,
scaleX: 0.1,
scaleY: 0.1
}, {
duration: 200,
easing: tween.easeIn,
onFinish: function onFinish() {
if (self.parent) {
self.parent.removeChild(self);
}
}
});
};
// Resume button event
self.resumeButton.down = function (x, y, obj) {
resumeGame();
};
// Quit button event
self.quitButton.down = function (x, y, obj) {
quitGame();
};
return self;
});
var PaymentWindow = Container.expand(function () {
var self = Container.call(this);
// Load accumulated payments from storage, default to 0
self.totalPayments = storage.tokyoPayments || 0;
// Create window background
self.windowBg = self.attachAsset('paymentWindow', {
anchorX: 0.5,
anchorY: 0.5
});
// Create payment text
self.paymentText = new Text2('Total de Tokens: $' + self.totalPayments, {
size: 80,
fill: 0xff0000
});
self.paymentText.anchor.set(0.5, 0.5);
self.addChild(self.paymentText);
// Method to add payment
self.addPayment = function (amount) {
self.totalPayments += amount;
self.paymentText.setText('Total de Tokens: $' + self.totalPayments);
// Save to storage
storage.tokyoPayments = self.totalPayments;
// Flash animation for payment addition
tween(self.windowBg, {
tint: 0xffd700
}, {
duration: 200
});
tween(self.windowBg, {
tint: 0xffffff
}, {
duration: 200
});
};
// Method to reset payments
self.resetPayments = function () {
self.totalPayments = 0;
self.paymentText.setText('Total de Tokens: $' + self.totalPayments);
storage.tokyoPayments = self.totalPayments;
};
return self;
});
var TokenWindow = Container.expand(function (cardIndex) {
var self = Container.call(this);
self.cardIndex = cardIndex;
// Define predefined price options
self.priceOptions = [10, 20, 30, 50, 100];
// Load saved price index from storage, default to 0 if not found
var storageKey = 'tokenPrice_' + cardIndex;
self.currentPriceIndex = storage[storageKey] || 0;
// Create window background
self.windowBg = self.attachAsset('tokenWindow', {
anchorX: 0.5,
anchorY: 0.5
});
// Create price text with saved price
self.priceText = new Text2('Token Price: ' + self.priceOptions[self.currentPriceIndex], {
size: 100,
fill: 0xff0000
});
self.priceText.anchor.set(0.5, 0.5);
self.addChild(self.priceText);
// Add tap event to cycle through prices and save to storage
self.down = function (x, y, obj) {
// Only allow changing token price when game is not started
if (!gameStarted) {
self.currentPriceIndex = (self.currentPriceIndex + 1) % self.priceOptions.length;
self.priceText.setText('Token Price: ' + self.priceOptions[self.currentPriceIndex]);
// Save the selected price index to storage
storage[storageKey] = self.currentPriceIndex;
}
};
return self;
});
/****
* Initialize Game
****/
var game = new LK.Game({
backgroundColor: 0x1a1a2e
});
/****
* Game Code
****/
var bingoCards = [];
var currentCalledNumber = null;
var calledNumbers = [];
var availableNumbers = [];
var callTimer = null;
var completedLines = 0;
var gameStarted = false;
var startButton = null;
var numberBubbles = [];
var bingoWindow = null;
var paymentWindow = null;
var cardHorizontalLines = [0, 0, 0, 0]; // Track horizontal lines per card
var gamePaused = false;
var pauseWindow = null;
var pauseButton = null;
// Initialize available numbers
for (var i = 1; i <= 75; i++) {
availableNumbers.push(i);
}
// Create score display
var scoreLabel = new Text2('Puntuación:', {
size: 50,
fill: 0xff0000
});
scoreLabel.anchor.set(0.5, 0);
scoreLabel.x = -300;
LK.gui.top.addChild(scoreLabel);
scoreLabel.y = 250;
var scoreText = new Text2('0', {
size: 80,
fill: 0xFFFFFF
});
scoreText.anchor.set(0.5, 0);
scoreText.x = -300;
LK.gui.top.addChild(scoreText);
scoreText.y = 300;
// Create current called number display
var calledNumberContainer = new Container();
var calledNumberBg = LK.getAsset('calledNumberBg', {
anchorX: 0.5,
anchorY: 0.5
});
calledNumberContainer.addChild(calledNumberBg);
var calledNumberText = new Text2('--', {
size: 36,
fill: 0xFFFFFF
});
calledNumberText.anchor.set(0.5, 0.5);
calledNumberContainer.addChild(calledNumberText);
game.addChild(calledNumberContainer);
calledNumberContainer.x = 1024;
calledNumberContainer.y = 150;
// Create info text
var infoText = new Text2('Tap START to begin the game!', {
size: 30,
fill: 0xFFFFFF
});
infoText.anchor.set(0.5, 0.5);
game.addChild(infoText);
infoText.x = 1024;
infoText.y = 250;
// Create start button
startButton = new Container();
var startButtonBg = LK.getAsset('startButton', {
anchorX: 0.5,
anchorY: 0.5
});
startButton.addChild(startButtonBg);
var startButtonText = new Text2('START', {
size: 96,
fill: 0x000000
});
startButtonText.anchor.set(0.5, 0.5);
startButton.addChild(startButtonText);
startButton.x = 1024;
startButton.y = 2500;
game.addChild(startButton);
startButton.down = function (x, y, obj) {
if (!gameStarted) {
gameStarted = true;
game.removeChild(startButton);
startButton = null;
infoText.setText('Cards fill automatically as numbers are called!');
// Deduct token price from each card before starting the game
for (var cardIdx = 0; cardIdx < bingoCards.length; cardIdx++) {
var tokenStorageKey = 'tokenPrice_' + cardIdx;
var tokenPriceIndex = storage[tokenStorageKey] || 0;
var priceOptions = [10, 20, 30, 50, 100];
var tokenPrice = priceOptions[tokenPriceIndex];
// Deduct the token price (negative payment)
paymentWindow.addPayment(-tokenPrice);
}
// Start the game
LK.setTimeout(callNextNumber, 8);
}
};
// Create bingo cards - centered on screen
for (var c = 0; c < 4; c++) {
var card = new BingoCard(c);
var row = Math.floor(c / 2);
var col = c % 2;
// Center cards on 2048x2732 screen - 2 cards per row
var cardSpacingX = 900; // Space between cards horizontally
var cardSpacingY = 780; // Space between cards vertically - increased separation
var totalWidth = cardSpacingX; // Width for 2 cards
var totalHeight = cardSpacingY; // Height for 2 rows
var startX = (2048 - totalWidth) / 2; // Center horizontally
var startY = 950; // Position below the UI elements - moved down
card.x = startX + col * cardSpacingX;
card.y = startY + row * cardSpacingY;
game.addChild(card);
bingoCards.push(card);
// Create token price window below each card
var tokenWindow = new TokenWindow(c);
tokenWindow.x = card.x;
tokenWindow.y = card.y + 350; // Position below the card
game.addChild(tokenWindow);
}
// Create payment window at the top right of the screen
paymentWindow = new PaymentWindow();
paymentWindow.x = 1500; // Position at top right - moved left
paymentWindow.y = 400;
game.addChild(paymentWindow);
// Create buy tokens window below payment window
var buyTokensWindow = new Container();
var buyTokensBg = LK.getAsset('buyTokensButton', {
anchorX: 0.5,
anchorY: 0.5
});
buyTokensWindow.addChild(buyTokensBg);
var buyTokensText = new Text2('COMPRAR TOKENS', {
size: 60,
fill: 0x000000
});
buyTokensText.anchor.set(0.5, 0.5);
buyTokensWindow.addChild(buyTokensText);
buyTokensWindow.x = 1500; // Same x position as payment window
buyTokensWindow.y = 580; // Position below payment window
game.addChild(buyTokensWindow);
// Create token purchase options window
var tokenPurchaseWindow = null;
var isTokenWindowVisible = false;
// Add touch event to buy tokens window
buyTokensWindow.down = function (x, y, obj) {
if (!isTokenWindowVisible) {
// Create purchase options window
tokenPurchaseWindow = new Container();
var windowBg = LK.getAsset('pauseWindow', {
anchorX: 0.5,
anchorY: 0.5,
scaleX: 2,
scaleY: 2
});
tokenPurchaseWindow.addChild(windowBg);
// Create title
var titleText = new Text2('COMPRAR TOKENS', {
size: 120,
fill: 0xFFFFFF
});
titleText.anchor.set(0.5, 0.5);
titleText.y = -240;
tokenPurchaseWindow.addChild(titleText);
// Create 1000 tokens button
var button1000 = new Container();
var button1000Bg = LK.getAsset('resumeButton', {
anchorX: 0.5,
anchorY: 0.5,
scaleX: 2,
scaleY: 2
});
button1000.addChild(button1000Bg);
var text1000 = new Text2('1000 TOKENS', {
size: 70,
fill: 0xFFFFFF
});
text1000.anchor.set(0.5, 0.5);
button1000.addChild(text1000);
button1000.y = -60;
tokenPurchaseWindow.addChild(button1000);
// Create 2000 tokens button
var button2000 = new Container();
var button2000Bg = LK.getAsset('resumeButton', {
anchorX: 0.5,
anchorY: 0.5,
scaleX: 2,
scaleY: 2
});
button2000.addChild(button2000Bg);
var text2000 = new Text2('2000 TOKENS', {
size: 70,
fill: 0xFFFFFF
});
text2000.anchor.set(0.5, 0.5);
button2000.addChild(text2000);
button2000.y = 100;
tokenPurchaseWindow.addChild(button2000);
// Create close button
var closeButton = new Container();
var closeBg = LK.getAsset('quitButton', {
anchorX: 0.5,
anchorY: 0.5,
scaleX: 2,
scaleY: 2
});
closeButton.addChild(closeBg);
var closeText = new Text2('CERRAR', {
size: 70,
fill: 0xFFFFFF
});
closeText.anchor.set(0.5, 0.5);
closeButton.addChild(closeText);
closeButton.y = 260;
tokenPurchaseWindow.addChild(closeButton);
// Position window at center
tokenPurchaseWindow.x = 1024;
tokenPurchaseWindow.y = 1366;
tokenPurchaseWindow.alpha = 0;
tokenPurchaseWindow.scaleX = 0.1;
tokenPurchaseWindow.scaleY = 0.1;
// Add to game
game.addChild(tokenPurchaseWindow);
isTokenWindowVisible = true;
// Animate window appearance
tween(tokenPurchaseWindow, {
alpha: 1,
scaleX: 1,
scaleY: 1
}, {
duration: 300,
easing: tween.easeOut
});
// Button events
button1000.down = function (x, y, obj) {
paymentWindow.addPayment(1000);
hideTokenWindow();
};
button2000.down = function (x, y, obj) {
paymentWindow.addPayment(2000);
hideTokenWindow();
};
closeButton.down = function (x, y, obj) {
hideTokenWindow();
};
}
};
// Function to hide token purchase window
function hideTokenWindow() {
if (tokenPurchaseWindow && isTokenWindowVisible) {
tween(tokenPurchaseWindow, {
alpha: 0,
scaleX: 0.1,
scaleY: 0.1
}, {
duration: 200,
easing: tween.easeIn,
onFinish: function onFinish() {
if (tokenPurchaseWindow.parent) {
tokenPurchaseWindow.parent.removeChild(tokenPurchaseWindow);
}
tokenPurchaseWindow = null;
isTokenWindowVisible = false;
}
});
}
}
// Create pause button
pauseButton = new Container();
var pauseButtonBg = LK.getAsset('pauseButton', {
anchorX: 0.5,
anchorY: 0.5
});
pauseButton.addChild(pauseButtonBg);
var pauseButtonText = new Text2('||', {
size: 120,
fill: 0x000000
});
pauseButtonText.anchor.set(0.5, 0.5);
pauseButton.addChild(pauseButtonText);
pauseButton.x = 280;
pauseButton.y = 2500;
game.addChild(pauseButton);
pauseButton.down = function (x, y, obj) {
if (gameStarted && !gamePaused) {
pauseGame();
}
};
function pauseGame() {
if (!gamePaused && gameStarted) {
gamePaused = true;
// Clear the current timer
if (callTimer) {
LK.clearTimeout(callTimer);
callTimer = null;
}
// Show pause window
pauseWindow = new PauseWindow();
game.addChild(pauseWindow);
pauseWindow.show();
}
}
function resumeGame() {
if (gamePaused) {
gamePaused = false;
// Hide pause window
if (pauseWindow) {
pauseWindow.hide();
pauseWindow = null;
}
// Resume number calling if game was active
if (gameStarted && availableNumbers.length > 0) {
var delay = Math.max(16 - completedLines * 6, 8);
callTimer = LK.setTimeout(callNextNumber, delay);
}
}
}
function quitGame() {
// Reset all game variables
gamePaused = false;
gameStarted = false;
if (callTimer) {
LK.clearTimeout(callTimer);
callTimer = null;
}
// Hide pause window
if (pauseWindow) {
pauseWindow.hide();
pauseWindow = null;
}
// Show game over
LK.setTimeout(function () {
LK.showGameOver();
}, 300);
}
function callNextNumber() {
if (availableNumbers.length > 0) {
var randomIndex = Math.floor(Math.random() * availableNumbers.length);
currentCalledNumber = availableNumbers[randomIndex];
availableNumbers.splice(randomIndex, 1);
calledNumbers.push(currentCalledNumber);
calledNumberText.setText(currentCalledNumber.toString());
LK.getSound('numberCalled').play();
// Create red bubble for the called number
var bubble = new NumberBubble(currentCalledNumber);
game.addChild(bubble);
numberBubbles.push(bubble);
// Automatically mark the called number on all cards with reduced probability
for (var cardIndex = 0; cardIndex < bingoCards.length; cardIndex++) {
var card = bingoCards[cardIndex];
for (var row = 0; row < 3; row++) {
for (var col = 0; col < 5; col++) {
var bingoNumber = card.bingoNumbers[row][col];
if (bingoNumber.number === currentCalledNumber && !bingoNumber.isMarked) {
// Base probability is 70%, but reduce by 30% more for cards with existing horizontal lines
var markProbability = 0.7;
if (cardHorizontalLines[cardIndex] > 0) {
markProbability = 0.7 * 0.5; // Reduce by 50% to achieve 30% overall reduction in second line probability
}
if (Math.random() < markProbability) {
bingoNumber.markNumber();
}
}
}
}
}
// Flash the called number
tween(calledNumberBg, {
tint: 0xffff00
}, {
duration: 200
});
tween(calledNumberBg, {
tint: 0xffffff
}, {
duration: 200
});
// Schedule next number call only if not paused
if (!gamePaused) {
var delay = Math.max(16 - completedLines * 6, 8);
callTimer = LK.setTimeout(callNextNumber, delay);
}
}
}
function checkForCompletedLines(cardIndex) {
var card = bingoCards[cardIndex];
var newLinesCompleted = 0;
var horizontalLinesCompleted = 0;
// Check horizontal lines
for (var row = 0; row < 3; row++) {
var lineComplete = true;
for (var col = 0; col < 5; col++) {
if (!card.bingoNumbers[row][col].isMarked) {
lineComplete = false;
break;
}
}
if (lineComplete) {
newLinesCompleted++;
horizontalLinesCompleted++;
}
}
// Update horizontal line count for this card
cardHorizontalLines[cardIndex] = horizontalLinesCompleted;
// Vertical and diagonal line checking removed - only horizontal lines count for scoring
if (newLinesCompleted > 0) {
completedLines += newLinesCompleted;
LK.getSound('lineComplete').play();
// Calculate score based on token price instead of fixed 100 points
var tokenStorageKey = 'tokenPrice_' + cardIndex;
var tokenPriceIndex = storage[tokenStorageKey] || 0;
var priceOptions = [10, 20, 30, 50, 100];
var tokenPrice = priceOptions[tokenPriceIndex];
var scoreAmount = tokenPrice * newLinesCompleted;
LK.setScore(LK.getScore() + scoreAmount);
scoreText.setText(LK.getScore());
// Add payment based on token price for this card
var paymentAmount = tokenPrice * newLinesCompleted;
paymentWindow.addPayment(paymentAmount);
// Show BINGO celebration window for horizontal line completion
if (horizontalLinesCompleted > 0) {
bingoWindow = new BingoWindow();
game.addChild(bingoWindow);
bingoWindow.show();
}
// Flash the card
tween(card.cardBg, {
tint: 0x00ff00
}, {
duration: 300
});
tween(card.cardBg, {
tint: 0xffffff
}, {
duration: 300
});
// Check for full card completion
var allMarked = true;
for (var r = 0; r < 3; r++) {
for (var c = 0; c < 5; c++) {
if (!card.bingoNumbers[r][c].isMarked) {
allMarked = false;
break;
}
}
if (!allMarked) break;
}
if (allMarked) {
// Full card bonus is 5 times the token price
var fullCardBonus = tokenPrice * 5;
LK.setScore(LK.getScore() + fullCardBonus);
scoreText.setText(LK.getScore());
// Check win condition - 3 completed lines or 1 full card
if (completedLines >= 3) {
LK.clearTimeout(callTimer);
LK.setTimeout(function () {
LK.showYouWin();
}, 1500);
}
}
}
}
// Game will start when start button is pressed
game.update = function () {
// Update score display
scoreText.setText(LK.getScore());
// Bubbles now stay at the top, no cleanup needed
// Check if all numbers have been called
if (availableNumbers.length === 0 && calledNumbers.length === 75) {
LK.clearTimeout(callTimer);
if (completedLines >= 1) {
LK.setTimeout(function () {
LK.showYouWin();
}, 1500);
} else {
LK.setTimeout(function () {
LK.showGameOver();
}, 1500);
}
}
};