/**** * Plugins ****/ var tween = LK.import("@upit/tween.v1"); var storage = LK.import("@upit/storage.v1"); /**** * Classes ****/ // --- Blackjack Game Logic --- var BlackjackGame = Container.expand(function () { var self = Container.call(this); // State self.currentSeat = 0; // Track which seat is currently active self.deck = []; self.playerHand = []; self.dealerHand = []; self.playerCards = []; self.dealerCards = []; self.state = 'bet'; // 'bet', 'player', 'dealer', 'result', 'betBehind' self.resultText = null; self.buttons = []; self.bet = betAmount; self.betBehind = 0; // Amount bet behind self.betBehindWin = 0; // Track bet behind win for this round // Add Blackjack table background image (bjTable) as the table background var bjTableBg = self.attachAsset('bjTable', { width: 1800, height: 900, anchorX: 0.5, anchorY: 0, x: 2048 / 2, y: 700 // position to fit under croupier and cards }); self.addChild(bjTableBg); // Add croupier image above the dealer cards, make it bigger to fit with the table var croupier = self.attachAsset('croupier', { width: 320, height: 320, anchorX: 0.5, anchorY: 1, x: 2048 / 2, y: 900 - 80 // slightly above dealer cards }); self.addChild(croupier); // Deal new deck self.newDeck = function () { var suits = ['♠', '♥', '♦', '♣']; var ranks = ['A', '2', '3', '4', '5', '6', '7', '8', '9', '10', 'J', 'Q', 'K']; var deck = []; for (var s = 0; s < 4; s++) { for (var r = 0; r < 13; r++) { deck.push({ rank: ranks[r], suit: suits[s] }); } } // Shuffle for (var i = deck.length - 1; i > 0; i--) { var j = Math.floor(Math.random() * (i + 1)); var t = deck[i]; deck[i] = deck[j]; deck[j] = t; } self.deck = deck; }; // Draw a card self.drawCard = function () { if (self.deck.length === 0) self.newDeck(); return self.deck.pop(); }; // Calculate hand value self.handValue = function (hand) { var value = 0; var aces = 0; for (var i = 0; i < hand.length; i++) { var r = hand[i].rank; if (r === 'A') { value += 11; aces++; } else if (r === 'K' || r === 'Q' || r === 'J') { value += 10; } else { value += parseInt(r); } } while (value > 21 && aces > 0) { value -= 10; aces--; } return value; }; // Start a new round self.startRound = function () { self.state = 'player'; self.playerHand = []; self.dealerHand = []; self.clearCards(); self.resultText && self.resultText.destroy(); self.resultText = null; // Bet self.bet = betAmount; self.betBehindWin = 0; self.perfectPairWin = false; // Track perfect pair win for this round if (playerBalance < self.bet) { self.showResult('Not enough balance!', true); return; } playerBalance -= self.bet; updateBalance(); // Deal // Deal cards with animation self.playerHand.push(self.drawCard()); self.dealerHand.push(self.drawCard()); self.playerHand.push(self.drawCard()); self.dealerHand.push(self.drawCard()); self.clearCards(); // --- Perfect Pair Side Bet Logic --- // If first two player cards are same rank and same suit, pay 25:1 self.perfectPairWin = false; self.perfectPairPayout = 0; if (self.playerHand.length === 2 && self.playerHand[0].rank === self.playerHand[1].rank && self.playerHand[0].suit === self.playerHand[1].suit) { self.perfectPairWin = true; self.perfectPairPayout = self.bet * 25; playerBalance += self.perfectPairPayout; updateBalance(); // Show a quick popup for perfect pair win var pairText = new Text2('Perfect Pair! +$' + self.perfectPairPayout, { size: 80, fill: 0xFFE066 }); pairText.anchor.set(0.5, 0.5); pairText.x = 2048 / 2; pairText.y = 1550; self.addChild(pairText); tween(pairText, { y: pairText.y - 120, alpha: 0 }, { duration: 1200, onFinish: function onFinish() { pairText.destroy(); } }); } // Card distribution animation var px = 2048 / 2 - 200; var py = 1700; var dx = 2048 / 2 - 200; var dy = 900; var dealDelay = 200; var dealDuration = 350; var dealStartX = 2048 / 2; var dealStartY = 1200; self.playerCards = []; self.dealerCards = []; // Helper to animate a card to its position with deal effect function animateCard(card, toX, toY, delay, isPlayer) { card.x = dealStartX; card.y = dealStartY; card.scaleX = 0.2; card.scaleY = 0.2; card.alpha = 0; card.visible = true; self.addChild(card); tween(card, { x: toX, y: toY, scaleX: 1, scaleY: 1, alpha: 1 }, { duration: dealDuration, easing: tween.cubicOut, delay: delay }); if (isPlayer) { self.playerCards.push(card); } else { self.dealerCards.push(card); } } // Create and animate cards in order: player1, dealer1, player2, dealer2 var playerCard1 = new Card(); playerCard1.setCard(self.playerHand[0].rank, self.playerHand[0].suit, true); playerCard1.visible = false; var dealerCard1 = new Card(); dealerCard1.setCard(self.dealerHand[0].rank, self.dealerHand[0].suit, true); dealerCard1.visible = false; var playerCard2 = new Card(); playerCard2.setCard(self.playerHand[1].rank, self.playerHand[1].suit, true); playerCard2.visible = false; var dealerCard2 = new Card(); dealerCard2.setCard(self.dealerHand[1].rank, self.dealerHand[1].suit, false); dealerCard2.visible = false; LK.setTimeout(function () { animateCard(playerCard1, px, py, 0, true); playerCard1.visible = true; LK.setTimeout(function () { animateCard(dealerCard1, dx, dy, 0, false); dealerCard1.visible = true; LK.setTimeout(function () { animateCard(playerCard2, px + 180, py, 0, true); // Increased spacing from 120 to 180 playerCard2.visible = true; LK.setTimeout(function () { animateCard(dealerCard2, dx + 180, dy, 0, false); // Increased spacing from 120 to 180 dealerCard2.visible = true; // After all cards are dealt, show buttons LK.setTimeout(function () { self.showButtons(['Hit', 'Stand']); }, dealDuration); }, dealDelay); }, dealDelay); }, dealDelay); }, 0); }; // Show cards on table self.showHands = function (revealDealer) { if (typeof revealDealer === "undefined") revealDealer = false; self.clearCards(); // Player var px = 2048 / 2 - 200; var py = 1700; for (var i = 0; i < self.playerHand.length; i++) { var c = new Card(); c.setCard(self.playerHand[i].rank, self.playerHand[i].suit, true); c.x = px + i * 180; // Increased spacing from 120 to 180 c.y = py; c.visible = true; // Player cards are visible self.addChild(c); self.playerCards.push(c); } // Dealer var dx = 2048 / 2 - 200; var dy = 900; for (var i = 0; i < self.dealerHand.length; i++) { var c = new Card(); var faceUp = i === 0 || revealDealer; c.setCard(self.dealerHand[i].rank, self.dealerHand[i].suit, faceUp); c.x = dx + i * 180; // Increased spacing from 120 to 180 c.y = dy; c.visible = revealDealer ? true : false; // Show dealer cards only if revealDealer is true self.addChild(c); self.dealerCards.push(c); } }; // Remove card objects self.clearCards = function () { for (var i = 0; i < self.playerCards.length; i++) { self.playerCards[i].destroy(); } for (var i = 0; i < self.dealerCards.length; i++) { self.dealerCards[i].destroy(); } self.playerCards = []; self.dealerCards = []; }; // Show action buttons self.showButtons = function (labels) { for (var i = 0; i < self.buttons.length; i++) { self.buttons[i].destroy(); } self.buttons = []; // If in player state, add Double if allowed (first move, enough balance, only 2 cards) var showDouble = false; if (self.state === 'player' && self.playerHand.length === 2 && playerBalance >= self.bet) { showDouble = true; if (labels.indexOf('Double') === -1) labels.push('Double'); } // Add Bet Behind button if in 'bet' state and player has enough balance if (self.state === 'bet' && playerBalance >= betAmount) { labels.push('Bet Behind'); } var startX = 2048 / 2 - (labels.length - 1) * 220; for (var i = 0; i < labels.length; i++) { var btn = new GameButton(); btn.setText(labels[i]); btn.x = startX + i * 440; btn.y = 2100; btn.action = labels[i]; btn.down = function () { this.flash(); if (this.action === 'Bet Behind') { // Place bet behind if (playerBalance >= betAmount) { self.betBehind += betAmount; playerBalance -= betAmount; updateBalance(); // Show quick popup for bet behind placed var bbText = new Text2('Bet Behind: $' + self.betBehind, { size: 70, fill: 0x66ffcc }); bbText.anchor.set(0.5, 0.5); bbText.x = 2048 / 2; bbText.y = 2000; self.addChild(bbText); tween(bbText, { y: bbText.y - 80, alpha: 0 }, { duration: 900, onFinish: function onFinish() { bbText.destroy(); } }); } } else { self.handleAction(this.action); } }; self.addChild(btn); self.buttons.push(btn); } }; // Handle player actions self.handleAction = function (action) { if (self.state !== 'player') return; if (action === 'Hit') { self.playerHand.push(self.drawCard()); self.showHands(false); //{21} // Always show dealer's first card only until round ends var val = self.handValue(self.playerHand); if (val > 21) { self.state = 'result'; self.showHands(true); self.showResult('Bust! You lose.'); } } else if (action === 'Stand') { self.state = 'dealer'; self.showHands(true); self.showButtons([]); self.dealerTurn(); } else if (action === 'Double') { // Double the bet, draw one card, then stand if (playerBalance >= self.bet && self.playerHand.length === 2) { playerBalance -= self.bet; self.bet *= 2; updateBalance(); self.playerHand.push(self.drawCard()); self.showHands(false); //{2f} // Always show dealer's first card only until round ends var val = self.handValue(self.playerHand); if (val > 21) { self.state = 'result'; self.showHands(true); self.showResult('Bust! You lose.'); } else { self.state = 'dealer'; self.showHands(true); self.showButtons([]); self.dealerTurn(); } } } }; // Dealer logic self.dealerTurn = function () { var self_ = self; var dealerVal = self.handValue(self.dealerHand); var playerVal = self.handValue(self.playerHand); function dealerStep() { dealerVal = self_.handValue(self_.dealerHand); if (dealerVal < 17) { self_.dealerHand.push(self_.drawCard()); self_.showHands(true); LK.setTimeout(dealerStep, 700); } else { self_.state = 'result'; self_.showHands(true); self_.showResult(self_.getResultText()); } } LK.setTimeout(dealerStep, 700); }; // Determine result self.getResultText = function () { var playerVal = self.handValue(self.playerHand); var dealerVal = self.handValue(self.dealerHand); if (playerVal > 21) return 'Bust! You lose.'; // Dealer busts if (dealerVal > 21) { playerBalance += self.bet * 2; // Bet behind wins if player hand not bust if (self.betBehind > 0 && playerVal <= 21) { self.betBehindWin = self.betBehind * 2; playerBalance += self.betBehindWin; } updateBalance(); return 'Dealer busts! You win!' + (self.betBehindWin > 0 ? '\nBet Behind Win: $' + self.betBehindWin : ''); } // Player wins if (playerVal > dealerVal) { // Check for natural 21 (Blackjack) on initial deal, no hit, and win var isNatural21 = self.playerHand.length === 2 && self.handValue(self.playerHand) === 21 && typeof self.lastAction !== "string" // No action taken (no hit/double) ; var winAmount = self.bet * 2; if (isNatural21) { // Award 50% more for natural 21 win without hit var bonus = Math.floor(self.bet * 0.5); winAmount += bonus; } playerBalance += winAmount; // Bet behind wins if player hand not bust if (self.betBehind > 0 && playerVal <= 21) { self.betBehindWin = self.betBehind * 2; playerBalance += self.betBehindWin; } updateBalance(); var winMsg = 'You win!' + (self.betBehindWin > 0 ? '\nBet Behind Win: $' + self.betBehindWin : ''); if (isNatural21) { winMsg = 'Blackjack! +50% bonus\n' + winMsg; } return winMsg; } // Player loses if (playerVal < dealerVal) { // Bet behind lost return 'You lose.' + (self.betBehind > 0 ? '\nBet Behind Lost: $' + self.betBehind : ''); } // Push playerBalance += self.bet; if (self.betBehind > 0) { playerBalance += self.betBehind; // Return bet behind on push self.betBehindWin = self.betBehind; } updateBalance(); return 'Push!' + (self.betBehind > 0 ? '\nBet Behind Push: $' + self.betBehind : ''); }; // Show result and next round self.showResult = function (txt, noNext) { self.resultText && self.resultText.destroy(); // If perfect pair win, append to result text if (self.perfectPairWin && txt && txt.indexOf('Perfect Pair!') === -1) { txt = 'Perfect Pair! +$' + self.perfectPairPayout + '\n' + txt; } // --- Quest: Play 3 Blackjack rounds --- if (typeof questEvent === "function") questEvent('blackjack_round'); // --- Quest: Win 2 Blackjack rounds --- if (typeof questEvent === "function" && txt && txt.indexOf('win') !== -1 && txt.toLowerCase().indexOf('you win') !== -1) questEvent('blackjack_win'); // --- Quest: Double Down in Blackjack --- if (typeof questEvent === "function" && self.lastAction === 'Double') questEvent('blackjack_double'); // --- Quest: Get Perfect Pair in Blackjack --- if (typeof questEvent === "function" && self.perfectPairWin) questEvent('blackjack_perfect_pair'); self.resultText = new Text2(txt, { size: 90, fill: "#fff" }); self.resultText.anchor.set(0.5, 0.5); self.resultText.x = 2048 / 2; self.resultText.y = 1450; self.addChild(self.resultText); self.showButtons(['New Round', 'Back']); self.buttons[0].down = function () { this.flash(); self.startRound(); }; self.buttons[1].down = function () { this.flash(); self.destroy(); blackjack = null; showModeSelect(); }; if (noNext) { self.buttons[0].visible = false; } }; // Destroy self.destroy = function () { self.clearCards(); for (var i = 0; i < self.buttons.length; i++) { self.buttons[i].destroy(); } self.buttons = []; self.resultText && self.resultText.destroy(); self.resultText = null; self.perfectPairWin = false; self.perfectPairPayout = 0; self.betBehind = 0; self.betBehindWin = 0; if (self.parent) self.parent.removeChild(self); }; // Start self.newDeck(); self.startRound(); return self; }); // Card class for Blackjack var Card = Container.expand(function () { var self = Container.call(this); // Card properties self.rank = null; // 2-10, J, Q, K, A self.suit = null; // '♠', '♥', '♦', '♣' self.faceUp = true; // Card background var cardBg = self.attachAsset('cardBg', { width: 180, height: 260, color: 0xffffff, shape: 'box', anchorX: 0.5, anchorY: 0.5 }); // Card text var cardText = new Text2('', { size: 80, fill: 0x222222 }); cardText.anchor.set(0.5, 0.5); self.addChild(cardText); // Set card value self.setCard = function (rank, suit, faceUp) { self.rank = rank; self.suit = suit; self.faceUp = faceUp !== false; if (self.faceUp) { cardText.setText(rank + suit); cardText.visible = true; cardBg.color = suit === '♥' || suit === '♦' ? 0xffeaea : 0xffffff; } else { cardText.setText(''); cardText.visible = false; cardBg.color = 0x8888aa; } }; // Flip card self.flip = function (up) { self.faceUp = up; self.setCard(self.rank, self.suit, up); }; return self; }); // Simple Button class var GameButton = Container.expand(function () { var self = Container.call(this); var btnBg = self.attachAsset('btnBg', { width: 420, height: 120, color: 0x333366, shape: 'box', anchorX: 0.5, anchorY: 0.5 }); self.btnBg = btnBg; // <-- Fix: assign btnBg as a property for external access var btnText = new Text2('', { size: 60, fill: 0xFFFFFF }); btnText.anchor.set(0.5, 0.5); self.addChild(btnText); self.setText = function (txt) { btnText.setText(txt); }; // For touch feedback self.flash = function () { tween(btnBg, { color: 0x6666cc }, { duration: 100, onFinish: function onFinish() { tween(btnBg, { color: 0x333366 }, { duration: 200 }); } }); }; return self; }); // --- Roulette Game Logic --- var RouletteGame = Container.expand(function () { var self = Container.call(this); // State self.state = 'bet'; // 'bet', 'spin', 'result' self.betType = null; // 'red', 'black', 'even', 'odd', 'number' self.betValue = null; // For number bet self.resultText = null; self.buttons = []; self.rouletteWheel = null; self.ball = null; self.spinBtn = null; self.backBtn = null; self.betOptions = []; self.selectedBetBtn = null; // Table background (roulette table image) var rouletteTableBg = self.attachAsset('RouletteBG', { width: 1400, height: 700, anchorX: 0.5, anchorY: 0.5, x: 2048 / 2, y: 800 }); // Draw roulette wheel using a realistic image and overlay visible numbers var wheelRadius = 320; var wheelCenterX = 2048 / 2; var wheelCenterY = 800; // Move wheel further up var numbers = []; for (var i = 0; i < 37; i++) numbers.push(i); // Red/Black numbers (European roulette) var reds = [1, 3, 5, 7, 9, 12, 14, 16, 18, 19, 21, 23, 25, 27, 30, 32, 34, 36]; var blacks = [2, 4, 6, 8, 10, 11, 13, 15, 17, 20, 22, 24, 26, 28, 29, 31, 33, 35]; // Draw wheel container self.rouletteWheel = new Container(); self.rouletteWheel.x = wheelCenterX; self.rouletteWheel.y = wheelCenterY; self.addChild(self.rouletteWheel); // Add roulette wheel image (should be a top-down wheel with visible slots) var wheelImg = self.rouletteWheel.attachAsset('rouletteWheelImg', { width: wheelRadius * 2, height: wheelRadius * 2, anchorX: 0.5, anchorY: 0.5, x: 0, y: 0 }); // Overlay numbers on the wheel image for visibility for (var i = 0; i < 37; i++) { var angle = i / 37 * Math.PI * 2 - Math.PI / 2; var num = numbers[i]; // European roulette: 0 is green, reds as defined, rest are black var color = "#fff"; var bgColor = 0x222222; if (num === 0) { bgColor = 0x1abc2c; // vivid green for 0 color = "#fff"; } else if (reds.indexOf(num) !== -1) { bgColor = 0xff0000; color = "#fff"; } else if (blacks.indexOf(num) !== -1) { bgColor = 0x222222; color = "#fff"; } // Draw number text with a subtle shadow for visibility var txt = new Text2(num + '', { size: 38, fill: color, stroke: "#000", strokeThickness: 6 }); txt.anchor.set(0.5, 0.5); txt.x = Math.cos(angle) * (wheelRadius - 38); txt.y = Math.sin(angle) * (wheelRadius - 38); self.rouletteWheel.addChild(txt); // Add invisible hit area for number bets (for touch/click) var hitSlot = self.rouletteWheel.attachAsset('cardBg', { width: 60, height: 60, color: 0x000000, alpha: 0, // invisible shape: 'box', anchorX: 0.5, anchorY: 0.5, x: Math.cos(angle) * (wheelRadius - 38), y: Math.sin(angle) * (wheelRadius - 38) }); hitSlot.hitArea = new Rectangle(-30, -30, 60, 60); hitSlot.down = function (betValue) { return function () { // Provide visual feedback by flashing the number text var txtNode = txt; if (typeof tween === "function" && txtNode && typeof txtNode.alpha !== "undefined") { var originalAlpha = txtNode.alpha; tween(txtNode, { alpha: 0.5 }, { duration: 100, onFinish: function onFinish() { tween(txtNode, { alpha: originalAlpha }, { duration: 200 }); } }); } // Unhighlight all bet buttons for (var j = 0; j < self.splitBetOptions.length; j++) { if (self.splitBetOptions[j].btnBg) self.splitBetOptions[j].btnBg.color = 0x333366; } if (self.redBtn && self.redBtn.btnBg) self.redBtn.btnBg.color = 0x333366; if (self.blackBtn && self.blackBtn.btnBg) self.blackBtn.btnBg.color = 0x333366; self.betType = 'number'; self.betValue = betValue; self.selectedBetBtn = this; self.showResult('Number bet: ' + self.betValue + ' ($' + Math.max(betAmount, 50) + ')', true); // Highlight selected number text txtNode.style = txtNode.style || {}; txtNode.style.fill = "#ffe066"; if (self.state === 'bet') { self.spinBtn.visible = true; } }; }(num); } // Ball self.ball = self.rouletteWheel.attachAsset('rouletteball', { width: 38, height: 38, anchorX: 0.5, anchorY: 0.5, x: Math.cos(-Math.PI / 2) * (wheelRadius - 40), y: Math.sin(-Math.PI / 2) * (wheelRadius - 40) }); // Bet options // Allow number bets (0-36) and split bets (adjacent numbers) in a compact grid below the wheel // Arrange numbers 0-36 in a 4-row grid: 0 on its own, then 1-12 in second, 13-24 in third, 25-36 in fourth var betGridCols = 12; var betGridRows = 4; // 0 in first row, 1-12 in second, 13-24 in third, 25-36 in fourth var betBtnW = 70; var betBtnH = 70; var betGridStartX = 2048 / 2 - betGridCols * betBtnW / 2 + betBtnW / 2; var betGridStartY = 1150; // Move up to match new wheel position self.betOptions = []; self.splitBetOptions = []; // Store split bet buttons // --- Number Bet Keyboard (below bet sign) --- // Move number bet keyboard to the left of the roulette wheel var numberKeyboardStartY = wheelCenterY - wheelRadius + 40; // Align top with wheel, with a little padding var numberKeyboardStartX = wheelCenterX - wheelRadius - 420; // Place to the left of the wheel, with some gap var numberKeyboardLabels = [['1', '2', '3', '4'], ['5', '6', '7', '8'], ['9', '10', '11', '12'], ['13', '14', '15', '16'], ['17', '18', '19', '20'], ['21', '22', '23', '24'], ['25', '26', '27', '28'], ['29', '30', '31', '32'], ['33', '34', '35', '36'], ['0']]; self.numberBetButtons = []; for (var row = 0; row < numberKeyboardLabels.length; row++) { for (var col = 0; col < numberKeyboardLabels[row].length; col++) { var label = numberKeyboardLabels[row][col]; var btn = new GameButton(); btn.setText(label); btn.btnBg.width = 80; btn.btnBg.height = 80; btn.x = numberKeyboardStartX + col * 90; btn.y = numberKeyboardStartY + row * 90; btn.betType = 'number'; btn.betValue = parseInt(label); btn.down = function (btnRef, value) { return function () { this.flash(); // Unhighlight all bet buttons for (var j = 0; j < self.betOptions.length; j++) { if (self.betOptions[j].btnBg) self.betOptions[j].btnBg.color = 0x333366; } for (var j = 0; j < self.splitBetOptions.length; j++) { if (self.splitBetOptions[j].btnBg) self.splitBetOptions[j].btnBg.color = 0x333366; } for (var j = 0; j < self.numberBetButtons.length; j++) { if (self.numberBetButtons[j].btnBg) self.numberBetButtons[j].btnBg.color = 0x333366; } if (self.redBtn && self.redBtn.btnBg) self.redBtn.btnBg.color = 0x333366; if (self.blackBtn && self.blackBtn.btnBg) self.blackBtn.btnBg.color = 0x333366; self.betType = 'number'; self.betValue = value; self.selectedBetBtn = this; self.showResult('Number bet: ' + value + ' ($' + Math.max(betAmount, 50) + ')', true); if (this.btnBg) this.btnBg.color = 0x6666cc; if (self.state === 'bet') { self.spinBtn.visible = true; } }; }(btn, parseInt(label)); self.addChild(btn); self.numberBetButtons.push(btn); } } // Helper to get grid position for a number function getGridPos(num) { if (num === 0) { return { col: 5.5, row: 0 }; // Center 0 above the grid } var idx = num - 1; return { col: idx % betGridCols, row: 1 + Math.floor(idx / betGridCols) }; } // --- Add Red/Black bet buttons --- // Move the red/black bet buttons even further down below the roulette wheel var colorBetY = numberKeyboardStartY + numberKeyboardLabels.length * 90 + 520; // Move even further down var colorBetXOffset = 200; // Increase horizontal offset for more space between buttons var redBtn = new GameButton(); redBtn.setText('Red'); redBtn.x = wheelCenterX - colorBetXOffset; redBtn.y = colorBetY; redBtn.betType = 'red'; redBtn.down = function () { this.flash(); // Unhighlight all bet buttons for (var j = 0; j < self.betOptions.length; j++) { if (self.betOptions[j].btnBg) self.betOptions[j].btnBg.color = 0x333366; } for (var j = 0; j < self.splitBetOptions.length; j++) { if (self.splitBetOptions[j].btnBg) self.splitBetOptions[j].btnBg.color = 0x333366; } if (self.blackBtn && self.blackBtn.btnBg) self.blackBtn.btnBg.color = 0x333366; if (self.redBtn && self.redBtn.btnBg) self.redBtn.btnBg.color = 0x333366; self.betType = 'red'; self.betValue = null; self.selectedBetBtn = this; self.showResult('Red bet ($' + Math.max(betAmount, 50) + ')', true); if (this.btnBg) this.btnBg.color = 0xff0000; if (self.state === 'bet') { self.spinBtn.visible = true; } }; self.addChild(redBtn); self.betOptions.push(redBtn); self.redBtn = redBtn; var blackBtn = new GameButton(); blackBtn.setText('Black'); blackBtn.x = wheelCenterX + colorBetXOffset; blackBtn.y = colorBetY; blackBtn.betType = 'black'; blackBtn.down = function () { this.flash(); // Unhighlight all bet buttons for (var j = 0; j < self.betOptions.length; j++) { if (self.betOptions[j].btnBg) self.betOptions[j].btnBg.color = 0x333366; } for (var j = 0; j < self.splitBetOptions.length; j++) { if (self.splitBetOptions[j].btnBg) self.splitBetOptions[j].btnBg.color = 0x333366; } if (self.redBtn && self.redBtn.btnBg) self.redBtn.btnBg.color = 0x333366; if (self.blackBtn && self.blackBtn.btnBg) self.blackBtn.btnBg.color = 0x333366; self.betType = 'black'; self.betValue = null; self.selectedBetBtn = this; self.showResult('Black bet ($' + Math.max(betAmount, 50) + ')', true); if (this.btnBg) this.btnBg.color = 0x222222; if (self.state === 'bet') { self.spinBtn.visible = true; } }; self.addChild(blackBtn); self.betOptions.push(blackBtn); self.blackBtn = blackBtn; // Create split bet buttons (between adjacent numbers: right and below) for (var i = 0; i < 37; i++) { var pos = getGridPos(i); // Split right (horizontal) if (pos.col < betGridCols - 1 && i + 1 < 37) { var splitBtn = new GameButton(); splitBtn.setText(i + '|' + (i + 1)); splitBtn.x = betGridStartX + pos.col * betBtnW + betBtnW / 2; splitBtn.y = betGridStartY + pos.row * (betBtnH + 10) + 200; // Moved down splitBtn.btnBg.width = 90; splitBtn.btnBg.height = 90; // Add even more space between split bet buttons horizontally splitBtn.x = betGridStartX + pos.col * (betBtnW + 50) + betBtnW / 2; splitBtn.y = betGridStartY + pos.row * (betBtnH + 50) + 200; // Moved down and spaced further splitBtn.betType = 'split'; splitBtn.betValue = [i, i + 1]; splitBtn.down = function (splitBtn) { return function () { this.flash(); // Unhighlight all bet buttons for (var j = 0; j < self.betOptions.length; j++) { if (self.betOptions[j].btnBg) self.betOptions[j].btnBg.color = 0x333366; } for (var j = 0; j < self.splitBetOptions.length; j++) { if (self.splitBetOptions[j].btnBg) self.splitBetOptions[j].btnBg.color = 0x333366; } self.betType = 'split'; self.betValue = splitBtn.betValue; self.selectedBetBtn = this; self.showResult('Split bet: ' + splitBtn.betValue[0] + ' & ' + splitBtn.betValue[1] + ' ($' + Math.max(betAmount, 50) + ')', true); if (this.btnBg) this.btnBg.color = 0x6666cc; if (self.state === 'bet') { self.spinBtn.visible = true; } }; }(splitBtn); self.addChild(splitBtn); self.splitBetOptions.push(splitBtn); } // Split below (vertical) if (pos.row < betGridRows - 1 && i + betGridCols < 37) { var splitBtn2 = new GameButton(); splitBtn2.setText(i + '\\' + (i + betGridCols)); splitBtn2.x = betGridStartX + pos.col * (betBtnW + 10); splitBtn2.y = betGridStartY + pos.row * (betBtnH + 10) + (betBtnH + 10) / 2 + 100; // Moved down splitBtn2.btnBg.width = 90; splitBtn2.btnBg.height = 90; // Add even more space between split bet buttons vertically splitBtn2.x = betGridStartX + pos.col * (betBtnW + 50); splitBtn2.y = betGridStartY + pos.row * (betBtnH + 50) + (betBtnH + 50) / 2 + 100; // Moved down and spaced further splitBtn2.betType = 'split'; splitBtn2.betValue = [i, i + betGridCols]; splitBtn2.down = function (splitBtn2) { return function () { this.flash(); // Unhighlight all bet buttons for (var j = 0; j < self.betOptions.length; j++) { if (self.betOptions[j].btnBg) self.betOptions[j].btnBg.color = 0x333366; } for (var j = 0; j < self.splitBetOptions.length; j++) { if (self.splitBetOptions[j].btnBg) self.splitBetOptions[j].btnBg.color = 0x333366; } self.betType = 'split'; self.betValue = splitBtn2.betValue; self.selectedBetBtn = this; self.showResult('Split bet: ' + splitBtn2.betValue[0] + ' & ' + splitBtn2.betValue[1] + ' ($' + Math.max(betAmount, 50) + ')', true); if (this.btnBg) this.btnBg.color = 0x6666cc; if (self.state === 'bet') { self.spinBtn.visible = true; } }; }(splitBtn2); self.addChild(splitBtn2); self.splitBetOptions.push(splitBtn2); } } // Spin button // Calculate betY for button positioning var betY = betGridStartY + betGridRows * betBtnH + 40; self.spinBtn = new GameButton(); self.spinBtn.setText('Spin'); // Make Spin button visually and structurally match the Back button self.spinBtn.x = 2048 / 2 - 600; self.spinBtn.y = betY + 300; self.spinBtn.btnBg.width = 420; self.spinBtn.btnBg.height = 120; self.spinBtn.visible = false; // Only show after bet selected self.spinBtn.down = function () { this.flash(); self.handleSpin(); }; self.addChild(self.spinBtn); // Back button self.backBtn = new GameButton(); self.backBtn.setText('Back'); // Move Back button further left of Spin self.backBtn.x = 2048 / 2 - 600; self.backBtn.y = betY + 450; self.backBtn.down = function () { self.destroy(); roulette = null; showModeSelect(); }; self.addChild(self.backBtn); // Show result text self.showResult = function (txt, noNext) { self.resultText && self.resultText.destroy(); self.resultText = new Text2(txt, { size: 90, fill: "#fff" }); self.resultText.anchor.set(0.5, 0.5); self.resultText.x = 2048 / 2; self.resultText.y = 1550; self.addChild(self.resultText); if (!noNext) { // Show "New Round" button var nextBtn = new GameButton(); nextBtn.setText('New Round'); nextBtn.x = 2048 / 2; nextBtn.y = betY + 600; nextBtn.down = function () { this.flash(); self.reset(); }; self.addChild(nextBtn); self.buttons.push(nextBtn); } }; // Handle spin self.handleSpin = function () { // Only allow spin if a bet is selected if (!self.betType || self.betType === 'number' && (typeof self.betValue !== "number" || self.betValue < 0 || self.betValue > 36)) { self.showResult('Select a bet first!', true); return; } if (betAmount < 50) { self.showResult('Minimum bet is $50!', true); return; } if (self.state !== 'bet') { self.showResult('You can only place one bet per round!', true); return; } self.state = 'spin'; if (playerBalance < betAmount) { self.showResult('Not enough balance!', true); return; } playerBalance -= betAmount; updateBalance(); self.state = 'spin'; self.spinBtn.visible = false; for (var i = 0; i < self.betOptions.length; i++) self.betOptions[i].visible = false; self.resultText && self.resultText.destroy(); // Animate ball spin var winningNumber = Math.floor(Math.random() * 37); var totalSpins = 3 + Math.floor(Math.random() * 2); var frames = 60 * totalSpins; var startAngle = -Math.PI / 2; var endAngle = winningNumber / 37 * Math.PI * 2 - Math.PI / 2; var currentFrame = 0; function animateBall() { var t = currentFrame / frames; var angle = startAngle + (endAngle - startAngle) * t + Math.PI * 2 * (1 - t) * totalSpins; self.ball.x = Math.cos(angle) * (wheelRadius - 40); self.ball.y = Math.sin(angle) * (wheelRadius - 40); currentFrame++; if (currentFrame <= frames) { LK.setTimeout(animateBall, 1000 / 60); } else { self.showSpinResult(winningNumber); // After result, allow new bet self.betType = null; self.betValue = null; if (self.selectedBetBtn && self.selectedBetBtn.btnBg) { self.selectedBetBtn.btnBg.color = 0x333366; } self.selectedBetBtn = null; // Show bet options for next round, but keep spin button hidden until bet is selected self.spinBtn.visible = false; for (var i = 0; i < self.betOptions.length; i++) self.betOptions[i].visible = true; } } animateBall(); }; // Show spin result and payout self.showSpinResult = function (winningNumber) { var win = false; var payout = 0; var msg = ''; if (self.betType === 'red' && reds.indexOf(winningNumber) !== -1) { win = true; payout = betAmount * 2; msg = 'Red wins!'; } else if (self.betType === 'black' && blacks.indexOf(winningNumber) !== -1) { win = true; payout = betAmount * 2; msg = 'Black wins!'; } else if (self.betType === 'even' && winningNumber !== 0 && winningNumber % 2 === 0) { win = true; payout = betAmount * 2; msg = 'Even wins!'; } else if (self.betType === 'odd' && winningNumber % 2 === 1) { win = true; payout = betAmount * 2; msg = 'Odd wins!'; } else if (self.betType === 'number' && self.betValue === winningNumber) { win = true; payout = betAmount * 36; msg = 'Number ' + winningNumber + ' wins!'; } else if (self.betType === 'split' && self.betValue && self.betValue.indexOf(winningNumber) !== -1) { win = true; payout = betAmount * 18; // Standard split bet payout is 17:1, so bet*18 msg = 'Split bet wins! Number ' + winningNumber + '!'; } else { msg = 'Number ' + winningNumber + '. You lose.'; } if (win) { playerBalance += payout; updateBalance(); msg += ' You win $' + payout + '!'; // --- Quest: Win $500 in Roulette --- if (typeof questEvent === "function") questEvent('roulette_win', payout); // --- Quest: Place 5 Roulette bets --- if (typeof questEvent === "function") questEvent('roulette_bet'); // --- Quest: Win on a number bet in Roulette --- if (typeof questEvent === "function" && self.betType === 'number' && self.betValue === winningNumber) questEvent('roulette_number_win'); // --- Quest: Win on Red/Black in Roulette --- if (typeof questEvent === "function" && (self.betType === 'red' || self.betType === 'black')) questEvent('roulette_red_black_win'); } else { // Even if lose, count bet for "Place 5 Roulette bets" if (typeof questEvent === "function") questEvent('roulette_bet'); } self.state = 'result'; self.showResult(msg); }; // Reset for new round self.reset = function () { self.betType = null; self.betValue = null; self.state = 'bet'; self.resultText && self.resultText.destroy(); for (var i = 0; i < self.buttons.length; i++) self.buttons[i].destroy(); self.buttons = []; self.spinBtn.visible = false; for (var i = 0; i < self.betOptions.length; i++) { self.betOptions[i].visible = true; if (self.betOptions[i].btnBg) self.betOptions[i].btnBg.color = 0x333366; } for (var i = 0; i < (self.splitBetOptions ? self.splitBetOptions.length : 0); i++) { self.splitBetOptions[i].visible = true; if (self.splitBetOptions[i].btnBg) self.splitBetOptions[i].btnBg.color = 0x333366; } self.selectedBetBtn = null; }; // Destroy self.destroy = function () { self.resultText && self.resultText.destroy(); for (var i = 0; i < self.betOptions.length; i++) self.betOptions[i].destroy(); self.betOptions = []; if (self.splitBetOptions) { for (var i = 0; i < self.splitBetOptions.length; i++) self.splitBetOptions[i].destroy(); self.splitBetOptions = []; } self.spinBtn && self.spinBtn.destroy(); self.backBtn && self.backBtn.destroy(); for (var i = 0; i < self.buttons.length; i++) self.buttons[i].destroy(); self.buttons = []; self.rouletteWheel && self.rouletteWheel.destroy(); self.state = 'bet'; if (self.parent) self.parent.removeChild(self); }; return self; }); // --- Sweet Bonanza Game Logic --- var SweetBonanzaGame = Container.expand(function () { var self = Container.call(this); // Slot config var ROWS = 5; var COLS = 6; var SYMBOLS = [{ id: 'red', color: 0xff4b5c, payout: 10 }, { id: 'blue', color: 0x4b7bff, payout: 8 }, { id: 'green', color: 0x4bff7b, payout: 6 }, { id: 'yellow', color: 0xffe066, payout: 4 }, { id: 'purple', color: 0xb266ff, payout: 12 }, { id: 'bomb', color: 0xffffff, payout: 0, isBomb: true }]; var symbolSize = 180; var gridOffsetX = 2048 / 2 - COLS * symbolSize / 2; var gridOffsetY = 900; var grid = []; var symbolNodes = []; var spinBtn = null; var resultText = null; var canSpin = true; // (Removed slot background) // Draw grid function drawGrid() { // Remove old for (var i = 0; i < symbolNodes.length; i++) { for (var j = 0; j < symbolNodes[i].length; j++) { symbolNodes[i][j].destroy(); } } symbolNodes = []; for (var row = 0; row < ROWS; row++) { symbolNodes[row] = []; for (var col = 0; col < COLS; col++) { var sym = grid[row][col]; var node = self.attachAsset('cardBg', { width: symbolSize - 10, height: symbolSize - 10, color: sym.color, shape: 'box', anchorX: 0.5, anchorY: 0.5, x: gridOffsetX + col * symbolSize + symbolSize / 2, y: gridOffsetY + row * symbolSize + symbolSize / 2 }); // Add symbol text var txt = new Text2(sym.isBomb ? '💣' : '', { size: 80, fill: "#222" }); txt.anchor.set(0.5, 0.5); node.addChild(txt); symbolNodes[row][col] = node; } } } // Generate random grid function randomGrid() { grid = []; for (var row = 0; row < ROWS; row++) { grid[row] = []; for (var col = 0; col < COLS; col++) { var sym = SYMBOLS[Math.floor(Math.random() * SYMBOLS.length)]; grid[row][col] = sym; } } } // Find clusters of 8+ matching symbols (Sweet Bonanza style) function findClusters() { var visited = []; for (var i = 0; i < ROWS; i++) visited[i] = []; var clusters = []; function dfs(r, c, id, cluster) { if (r < 0 || r >= ROWS || c < 0 || c >= COLS) return; if (visited[r][c]) return; if (grid[r][c].id !== id) return; visited[r][c] = true; cluster.push({ row: r, col: c }); dfs(r - 1, c, id, cluster); dfs(r + 1, c, id, cluster); dfs(r, c - 1, id, cluster); dfs(r, c + 1, id, cluster); } for (var row = 0; row < ROWS; row++) { for (var col = 0; col < COLS; col++) { if (!visited[row][col] && !grid[row][col].isBomb) { var cluster = []; dfs(row, col, grid[row][col].id, cluster); if (cluster.length >= 8) { clusters.push({ id: grid[row][col].id, cells: cluster, payout: grid[row][col].payout }); } } } } return clusters; } // Remove clusters and drop new symbols function removeClusters(clusters) { for (var i = 0; i < clusters.length; i++) { var cells = clusters[i].cells; for (var j = 0; j < cells.length; j++) { var r = cells[j].row; var c = cells[j].col; grid[r][c] = null; } } // Drop down for (var col = 0; col < COLS; col++) { var empty = []; for (var row = ROWS - 1; row >= 0; row--) { if (grid[row][col] === null) { empty.push(row); } else if (empty.length > 0) { var target = empty.shift(); grid[target][col] = grid[row][col]; grid[row][col] = null; empty.push(row); } } // Fill empty with new for (var k = 0; k < empty.length; k++) { var r = empty[k]; var sym = SYMBOLS[Math.floor(Math.random() * SYMBOLS.length)]; grid[r][col] = sym; } } } // Check for bombs function hasBomb() { for (var row = 0; row < ROWS; row++) { for (var col = 0; col < COLS; col++) { if (grid[row][col].isBomb) return true; } } return false; } // Spin logic function spin() { if (!canSpin) return; if (playerBalance < betAmount) { showResult('Not enough balance!'); return; } // --- Quest: Spin Sweet Bonanza 5 times --- if (typeof questEvent === "function") questEvent('sweet_spin'); canSpin = false; playerBalance -= betAmount; updateBalance(); resultText && resultText.destroy(); resultText = null; randomGrid(); drawGrid(); // Animate spin (simple delay) LK.setTimeout(function () { var clusters = findClusters(); var win = 0; for (var i = 0; i < clusters.length; i++) { win += clusters[i].payout * betAmount; } if (win > 0) { playerBalance += win; updateBalance(); showResult('Win! $' + win); } else if (hasBomb()) { showResult('💣 Bomb! Lose!'); } else { showResult('No win'); } // Remove clusters and drop new if (clusters.length > 0) { removeClusters(clusters); drawGrid(); } canSpin = true; }, 700); } // Show result text function showResult(txt) { resultText && resultText.destroy(); resultText = new Text2(txt, { size: 90, fill: "#fff" }); resultText.anchor.set(0.5, 0.5); resultText.x = 2048 / 2; resultText.y = gridOffsetY + ROWS * symbolSize + 120; self.addChild(resultText); } // Spin button spinBtn = new GameButton(); spinBtn.setText('Spin'); spinBtn.x = 2048 / 2; spinBtn.y = gridOffsetY + ROWS * symbolSize + 250; spinBtn.down = function () { this.flash(); spin(); }; self.addChild(spinBtn); // Back button var backBtn = new GameButton(); backBtn.setText('Back'); backBtn.x = 2048 / 2; backBtn.y = gridOffsetY + ROWS * symbolSize + 400; backBtn.down = function () { self.destroy(); sweetBonanza = null; showModeSelect(); }; self.addChild(backBtn); // Destroy self.destroy = function () { for (var i = 0; i < symbolNodes.length; i++) { for (var j = 0; j < symbolNodes[i].length; j++) { symbolNodes[i][j].destroy(); } } symbolNodes = []; spinBtn && spinBtn.destroy(); backBtn && backBtn.destroy(); resultText && resultText.destroy(); if (self.parent) self.parent.removeChild(self); }; // Init randomGrid(); drawGrid(); return self; }); /**** * Initialize Game ****/ var game = new LK.Game({ backgroundColor: 0x2e8b57 // deep green, matches Blackjack table }); /**** * Game Code ****/ // Blood red background (deep red) // --- Account System State --- // --- Global State --- // (Removed fullscreen Blackjack table background image) function _typeof(o) { "@babel/helpers - typeof"; return _typeof = "function" == typeof Symbol && "symbol" == typeof Symbol.iterator ? function (o) { return typeof o; } : function (o) { return o && "function" == typeof Symbol && o.constructor === Symbol && o !== Symbol.prototype ? "symbol" : typeof o; }, _typeof(o); } var accountState = { loggedIn: false, username: null }; var accountPrompt = null; var accountErrorText = null; var accountNameInput = null; var accountPasswordInput = null; var accountNameValue = ''; var accountPasswordValue = ''; var accountMode = 'login'; // 'login' or 'register' // Helper: get all accounts from storage function getAllAccounts() { // Use storage.getItem to retrieve accounts, fallback to empty object if not found var accounts = storage.getItem && typeof storage.getItem === "function" ? storage.getItem("accounts") : storage.accounts; if (!accounts || _typeof(accounts) !== "object") accounts = {}; return accounts; } // Helper: save all accounts to storage function saveAllAccounts(accounts) { // Use storage.setItem to persist accounts if available if (storage.setItem && typeof storage.setItem === "function") { storage.setItem("accounts", accounts); } storage.accounts = accounts; } // Helper: hash password (simple, not secure, but for demo) function hashPassword(pw) { // Ensure pw is a string to avoid errors on charCodeAt if (pw === undefined || pw === null) pw = ''; pw = String(pw); var h = 0; for (var i = 0; i < pw.length; i++) { // Defensive: check that pw is a string and pw[i] exists var ch = typeof pw === "string" && pw.length > i ? pw.charAt(i) : ''; if (typeof ch === "string" && ch.length === 1) { h += ch.charCodeAt(0) * (i + 17); } } // Defensive: ensure h is a number before converting to string if (typeof h !== "number" || isNaN(h)) h = 0; // Always return as string, and never undefined/null try { // Defensive: if h is not a string or number, return empty string if (typeof h === "string") return h; if (typeof h === "number") return String(h); // If h is not string or number, fallback to empty string return ''; } catch (e) { // In case of any error, always return empty string return ''; } // Final fallback: always return a string if (typeof h === "undefined" || h === null) return ''; // Defensive: ensure return is always a string try { // Fix: Always return a string, never throw if (typeof h === "string") return h; if (typeof h === "number") return String(h); return ''; } catch (e) { return ''; } // Absolute fallback return ''; } // Show account setup/login UI function showAccountPrompt() { // Remove old prompt if present if (accountPrompt) { accountPrompt.destroy(); accountPrompt = null; } accountPrompt = new Container(); game.addChild(accountPrompt); // Background overlay var overlay = accountPrompt.attachAsset('cardBg', { width: 900, height: 600, color: 0x222244, shape: 'box', anchorX: 0.5, anchorY: 0.5, x: 2048 / 2, y: 1200 }); // Title var title = new Text2(accountMode === 'register' ? 'Create Account' : 'Login', { size: 80, fill: "#fff" }); title.anchor.set(0.5, 0.5); title.x = 2048 / 2; title.y = 950; accountPrompt.addChild(title); // Username input accountNameInput = new Text2('Name: ' + accountNameValue, { size: 60, fill: "#fff" }); accountNameInput.anchor.set(0.5, 0.5); accountNameInput.x = 2048 / 2; accountNameInput.y = 1100; accountPrompt.addChild(accountNameInput); // Password input (show as ****) var stars = ''; for (var i = 0; i < accountPasswordValue.length; i++) stars += '*'; accountPasswordInput = new Text2('Password: ' + stars, { size: 60, fill: "#fff" }); accountPasswordInput.anchor.set(0.5, 0.5); accountPasswordInput.x = 2048 / 2; accountPasswordInput.y = 1200; accountPrompt.addChild(accountPasswordInput); function updateNameInputDisplay() { accountNameInput.setText('Name: ' + accountNameValue); if (accountErrorText) accountErrorText.setText(''); } function updatePasswordInputDisplay() { var stars = ''; for (var i = 0; i < accountPasswordValue.length; i++) stars += '*'; accountPasswordInput.setText('Password: ' + stars); if (accountErrorText) accountErrorText.setText(''); } function clearAccountInputs() { accountNameValue = ''; accountPasswordValue = ''; updateNameInputDisplay(); updatePasswordInputDisplay(); } // Error text accountErrorText = new Text2('', { size: 48, fill: 0xFF4444 }); accountErrorText.anchor.set(0.5, 0.5); accountErrorText.x = 2048 / 2; accountErrorText.y = 1270; accountPrompt.addChild(accountErrorText); // Name pad (A-Z, backspace, next) - split left var namePadStartX = 2048 / 2 - 500; var namePadStartY = 1350; var namePadLabels = [['A', 'B', 'C', 'D', 'E', 'F', 'G', 'H', 'I', 'J'], ['K', 'L', 'M', 'N', 'O', 'P', 'Q', 'R', 'S', 'T'], ['U', 'V', 'W', 'X', 'Y', 'Z', '/', '_', '<-', 'OK']]; function updateNameInputDisplay() { accountNameInput.setText('Name: ' + accountNameValue); if (accountErrorText) accountErrorText.setText(''); } function updatePasswordInputDisplay() { var stars = ''; for (var i = 0; i < accountPasswordValue.length; i++) stars += '*'; accountPasswordInput.setText('Password: ' + stars); if (accountErrorText) accountErrorText.setText(''); } function clearAccountInputs() { accountNameValue = ''; accountPasswordValue = ''; updateNameInputDisplay(); updatePasswordInputDisplay(); } function tryAccountSubmit() { var name = accountNameValue.trim(); var pw = accountPasswordValue; if (name.length < 3) { accountErrorText.setText('Name must be at least 3 characters.'); return; } if (pw.length < 6) { accountErrorText.setText('Password must be at least 6 digits.'); return; } var accounts = getAllAccounts(); if (accountMode === 'register') { if (accounts[name]) { accountErrorText.setText('Name already taken!'); return; } // Only allow digits in password if (!/^\d+$/.test(pw)) { accountErrorText.setText('Password must be digits only.'); return; } // Register accounts[name] = { password: hashPassword(pw), created: Date.now() }; saveAllAccounts(accounts); accountState.loggedIn = true; accountState.username = name; accountPasswordValue = ''; // Clear password after success if (accountPrompt) { accountPrompt.destroy(); accountPrompt = null; } showModeSelect(); } else { // Login if (!accounts[name]) { accountErrorText.setText('Account not found.'); return; } if (accounts[name].password !== hashPassword(pw)) { accountErrorText.setText('Incorrect password.'); return; } accountState.loggedIn = true; accountState.username = name; accountPasswordValue = ''; // Clear password after success if (accountPrompt) { accountPrompt.destroy(); accountPrompt = null; } showModeSelect(); } } function clearAccountInputs() { accountNameValue = ''; accountPasswordValue = ''; updateNameInputDisplay(); updatePasswordInputDisplay(); } var namePadStartY = 1350; var namePadLabels = [['A', 'B', 'C', 'D', 'E', 'F', 'G', 'H', 'I', 'J'], ['K', 'L', 'M', 'N', 'O', 'P', 'Q', 'R', 'S', 'T'], ['U', 'V', 'W', 'X', 'Y', 'Z', '/', '_', '<-', 'OK']]; function updateNameInputDisplay() { accountNameInput.setText('Name: ' + accountNameValue); if (accountErrorText) accountErrorText.setText(''); } function updatePasswordInputDisplay() { var stars = ''; for (var i = 0; i < accountPasswordValue.length; i++) stars += '*'; accountPasswordInput.setText('Password: ' + stars); if (accountErrorText) accountErrorText.setText(''); } function tryAccountSubmit() { var name = accountNameValue.trim(); var pw = accountPasswordValue; if (name.length < 3) { accountErrorText.setText('Name must be at least 3 characters.'); return; } if (pw.length < 6) { accountErrorText.setText('Password must be at least 6 digits.'); return; } var accounts = getAllAccounts(); if (accountMode === 'register') { if (accounts[name]) { accountErrorText.setText('Name already taken!'); return; } // Only allow digits in password if (!/^\d+$/.test(pw)) { accountErrorText.setText('Password must be digits only.'); return; } // Register accounts[name] = { password: hashPassword(pw), created: Date.now() }; saveAllAccounts(accounts); accountState.loggedIn = true; accountState.username = name; accountPasswordValue = ''; // Clear password after success if (accountPrompt) { accountPrompt.destroy(); accountPrompt = null; } showModeSelect(); } else { // Login if (!accounts[name]) { accountErrorText.setText('Account not found.'); return; } if (accounts[name].password !== hashPassword(pw)) { accountErrorText.setText('Incorrect password.'); return; } accountState.loggedIn = true; accountState.username = name; accountPasswordValue = ''; // Clear password after success if (accountPrompt) { accountPrompt.destroy(); accountPrompt = null; } showModeSelect(); } } function clearAccountInputs() { accountNameValue = ''; accountPasswordValue = ''; updateNameInputDisplay(); updatePasswordInputDisplay(); } // Draw name pad (letters only, left side) for (var row = 0; row < namePadLabels.length; row++) { for (var col = 0; col < namePadLabels[row].length; col++) { var label = namePadLabels[row][col]; var btn = new GameButton(); btn.setText(label); // Make buttons smaller and add more space between them btn.btnBg.width = 54; btn.btnBg.height = 54; btn.x = namePadStartX + col * 74; // 54px button + 20px gap btn.y = namePadStartY + row * 80; // 54px button + 26px gap // Make text a bit larger for visibility for (var t = 0; t < btn.children.length; t++) { if (btn.children[t] && typeof btn.children[t].setText === "function") { btn.children[t].style = btn.children[t].style || {}; btn.children[t].style.size = 36; btn.children[t].setText(label); } } if (label === '<-') btn.btnBg.color = 0xffcccc; if (label === 'OK') btn.btnBg.color = 0xccffcc; btn.down = function (lbl) { return function () { this.flash(); if (lbl === '<-') { if (accountNameValue.length > 0) { accountNameValue = accountNameValue.slice(0, -1); updateNameInputDisplay(); } } else if (lbl === 'OK') { // Move to password input // If already on password, try submit if (accountPasswordValue.length < 6) { accountErrorText.setText('Password must be at least 6 digits.'); return; } tryAccountSubmit(); } else { if (accountNameValue.length < 12 && /^[A-Z_\/]$/.test(lbl)) { accountNameValue += lbl; updateNameInputDisplay(); } } }; }(label); accountPrompt.addChild(btn); } } // Number pad (digits 0-9, C, OK) - right side var pwPadStartX = 2048 / 2 + 400; var pwPadStartY = 1350; var pwPadLabels = [['1', '2', '3'], ['4', '5', '6'], ['7', '8', '9'], ['C', '0', 'OK']]; for (var prow = 0; prow < 4; prow++) { for (var pcol = 0; pcol < 3; pcol++) { var plabel = pwPadLabels[prow][pcol]; var pbtn = new GameButton(); pbtn.setText(plabel); // Make buttons smaller and add more space between them pbtn.btnBg.width = 54; pbtn.btnBg.height = 54; pbtn.x = pwPadStartX + pcol * 74; // 54px button + 20px gap pbtn.y = pwPadStartY + prow * 80; // 54px button + 26px gap // Make text a bit larger for visibility for (var t = 0; t < pbtn.children.length; t++) { if (pbtn.children[t] && typeof pbtn.children[t].setText === "function") { pbtn.children[t].style = pbtn.children[t].style || {}; pbtn.children[t].style.size = 36; pbtn.children[t].setText(plabel); } } if (plabel === 'C') pbtn.btnBg.color = 0xffcccc; if (plabel === 'OK') pbtn.btnBg.color = 0xccffcc; pbtn.down = function (lbl) { return function () { this.flash(); if (lbl === 'C') { accountPasswordValue = ''; updatePasswordInputDisplay(); } else if (lbl === 'OK') { tryAccountSubmit(); } else if (lbl.length === 1 && accountPasswordValue.length < 12 && /^\d$/.test(lbl)) { accountPasswordValue += lbl; updatePasswordInputDisplay(); } }; }(plabel); accountPrompt.addChild(pbtn); } } // Switch mode button var switchBtn = new GameButton(); switchBtn.setText(accountMode === 'register' ? 'Have account? Login' : 'No account? Register'); switchBtn.x = 2048 / 2; switchBtn.y = 1800; // moved even further down switchBtn.btnBg.width = 400; switchBtn.btnBg.height = 70; switchBtn.down = function () { this.flash(); accountMode = accountMode === 'register' ? 'login' : 'register'; accountNameValue = ''; accountPasswordValue = ''; if (accountPrompt) { accountPrompt.destroy(); accountPrompt = null; } showAccountPrompt(); }; accountPrompt.addChild(switchBtn); } // On game start, allow guest play by default // Optionally, user can open account prompt from a button in the mode select screen // --- Top Left Back Button --- var topLeftBackBtn = null; function showTopLeftBackBtn(onBack) { // Remove if already present if (topLeftBackBtn && topLeftBackBtn.parent) { topLeftBackBtn.parent.removeChild(topLeftBackBtn); topLeftBackBtn.destroy(); topLeftBackBtn = null; } topLeftBackBtn = new GameButton(); topLeftBackBtn.setText('Back'); // Place at (100,220) to avoid the reserved 100x100px area and move a little further down topLeftBackBtn.x = 100 + 80; // 80px right of reserved area topLeftBackBtn.y = 100 + 160; // 160px below reserved area (moved a little further down) topLeftBackBtn.btnBg.width = 180; topLeftBackBtn.btnBg.height = 80; topLeftBackBtn.down = function () { this.flash(); if (typeof onBack === "function") onBack(); }; game.addChild(topLeftBackBtn); } function hideTopLeftBackBtn() { if (topLeftBackBtn && topLeftBackBtn.parent) { topLeftBackBtn.parent.removeChild(topLeftBackBtn); topLeftBackBtn.destroy(); topLeftBackBtn = null; } } /**** * Casino Carnival - MVP * Four-in-one casino game: Blackjack, Sweet Bonanza, Gates of Olympus, Sugar Rush * MVP: Game selection, basic betting, and one playable mode (Blackjack) ****/ var MODES = [{ id: 'blackjack', name: 'Blackjack' }, { id: 'roulette', name: 'Roulette' }]; var currentMode = null; // 'blackjack', etc. var playerBalance = storage.balance || 1000; var betAmount = 100; var minBet = 50; var maxBet = 500000; // --- Single Seat State --- var blackjack = null; // UI elements var modeButtons = []; var betText = null; var balanceText = null; var playArea = null; var blackjack = null; // --- GUI: Balance and Bet --- balanceText = new Text2('Balance: $' + playerBalance, { size: 60, fill: "#fff" }); balanceText.anchor.set(0.5, 0); LK.gui.top.addChild(balanceText); betText = new Text2('Bet: $' + betAmount, { size: 50, fill: "#fff" }); betText.anchor.set(0.5, 0); LK.gui.top.addChild(betText); // Position GUI elements balanceText.y = 10; betText.y = 80; // --- Game Selection Screen --- function showModeSelect() { hideTopLeftBackBtn(); // Clear play area if (playArea) { playArea.destroy(); playArea = null; } if (blackjack) { blackjack.destroy(); blackjack = null; } // Destroy blackjack instance if present if (blackjack && blackjack.destroy) { blackjack.destroy(); blackjack = null; } // Remove old mode buttons for (var i = 0; i < modeButtons.length; i++) { if (modeButtons[i].parent) modeButtons[i].parent.removeChild(modeButtons[i]); } modeButtons = []; // Title var title = new Text2('Casino Carnival', { size: 120, fill: 0xFFE066 }); title.anchor.set(0.5, 0.5); title.x = 2048 / 2; title.y = 350; game.addChild(title); // Mode buttons var startY = 700; var gapY = 200; for (var i = 0; i < MODES.length; i++) { var btn = new GameButton(); btn.setText(MODES[i].name); // Adjust font size to fit the button for 'Blackjack' and 'Roulette' if (MODES[i].name === 'Blackjack' || MODES[i].name === 'Roulette') { // Find the Text2 child and set its size smaller to fit the red area for (var j = 0; j < btn.children.length; j++) { if (btn.children[j] && typeof btn.children[j].setText === "function") { btn.children[j].style = btn.children[j].style || {}; btn.children[j].style.size = 48; // Reduce font size to fit btn.children[j].setText(MODES[i].name); } } } btn.x = 2048 / 2; btn.y = startY + i * gapY; btn.modeId = MODES[i].id; btn.down = function (x, y, obj) { this.flash(); selectMode(this.modeId); }; game.addChild(btn); modeButtons.push(btn); } // Bet controls var betMinus = new GameButton(); betMinus.setText('-'); betMinus.x = 2048 / 2 - 350; betMinus.y = startY + MODES.length * gapY + 60; betMinus.down = function () { var step = 50; if (betAmount > 20000) { step = 2000; } else if (betAmount > 10000) { step = 1000; } else if (betAmount > 5000) { step = 500; } else if (betAmount > 1000) { step = 100; } if (betAmount - step >= minBet) { betAmount -= step; } else if (betAmount > minBet) { betAmount = minBet; } betText.setText('Bet: $' + betAmount); }; game.addChild(betMinus); var betCustomBtn = new GameButton(); betCustomBtn.setText('✎'); betCustomBtn.x = 2048 / 2; betCustomBtn.y = startY + MODES.length * gapY + 60; betCustomBtn.btnBg.width = 100; betCustomBtn.btnBg.height = 100; betCustomBtn.down = function () { this.flash(); showCustomBetInput(); }; game.addChild(betCustomBtn); var betPlus = new GameButton(); betPlus.setText('+'); betPlus.x = 2048 / 2 + 350; betPlus.y = startY + MODES.length * gapY + 60; betPlus.down = function () { var step = 50; if (betAmount >= 20000) { step = 2000; } else if (betAmount >= 10000) { step = 1000; } else if (betAmount >= 5000) { step = 500; } else if (betAmount >= 1000) { step = 100; } if (betAmount + step <= maxBet) { betAmount += step; } else if (betAmount < maxBet) { betAmount = maxBet; } betText.setText('Bet: $' + betAmount); }; game.addChild(betPlus); // Store for later removal // Store for later removal modeButtons.push(title, betMinus, betCustomBtn, betPlus); // --- Custom Bet Input UI --- var customBetPrompt = null; function showCustomBetInput() { if (customBetPrompt) { customBetPrompt.destroy(); customBetPrompt = null; } customBetPrompt = new Container(); game.addChild(customBetPrompt); var overlay = customBetPrompt.attachAsset('cardBg', { width: 600, height: 400, color: 0x222244, shape: 'box', anchorX: 0.5, anchorY: 0.5, x: 2048 / 2, y: 1200 }); var title = new Text2('Enter Bet Amount', { size: 70, fill: "#fff" }); title.anchor.set(0.5, 0.5); title.x = 2048 / 2; title.y = 1050; customBetPrompt.addChild(title); var inputValue = ''; var inputText = new Text2('Bet: ', { size: 60, fill: "#fff" }); inputText.anchor.set(0.5, 0.5); inputText.x = 2048 / 2; inputText.y = 1200; customBetPrompt.addChild(inputText); var errorText = new Text2('', { size: 40, fill: 0xFF4444 }); errorText.anchor.set(0.5, 0.5); errorText.x = 2048 / 2; errorText.y = 1270; customBetPrompt.addChild(errorText); function updateInputDisplay() { inputText.setText('Bet: ' + inputValue); errorText.setText(''); } // Number pad (digits 0-9, C, OK) var padStartX = 2048 / 2 - 120; var padStartY = 1350; var padLabels = [['1', '2', '3'], ['4', '5', '6'], ['7', '8', '9'], ['C', '0', 'OK']]; for (var prow = 0; prow < 4; prow++) { for (var pcol = 0; pcol < 3; pcol++) { var plabel = padLabels[prow][pcol]; var pbtn = new GameButton(); pbtn.setText(plabel); pbtn.btnBg.width = 80; pbtn.btnBg.height = 80; pbtn.x = padStartX + pcol * 100; pbtn.y = padStartY + prow * 100; for (var t = 0; t < pbtn.children.length; t++) { if (pbtn.children[t] && typeof pbtn.children[t].setText === "function") { pbtn.children[t].style = pbtn.children[t].style || {}; pbtn.children[t].style.size = 36; pbtn.children[t].setText(plabel); } } if (plabel === 'C') pbtn.btnBg.color = 0xffcccc; if (plabel === 'OK') pbtn.btnBg.color = 0xccffcc; pbtn.down = function (lbl) { return function () { this.flash(); if (lbl === 'C') { inputValue = ''; updateInputDisplay(); } else if (lbl === 'OK') { var val = parseInt(inputValue, 10); if (isNaN(val) || val < minBet || val > maxBet) { errorText.setText('Enter $' + minBet + ' - $' + maxBet); return; } betAmount = val; betText.setText('Bet: $' + betAmount); if (customBetPrompt) { customBetPrompt.destroy(); customBetPrompt = null; } } else if (lbl.length === 1 && inputValue.length < 9 && /^\d$/.test(lbl)) { if (inputValue === '0') inputValue = ''; inputValue += lbl; updateInputDisplay(); } }; }(plabel); customBetPrompt.addChild(pbtn); } } // Cancel button var cancelBtn = new GameButton(); cancelBtn.setText('Cancel'); cancelBtn.x = 2048 / 2; cancelBtn.y = padStartY + 450; cancelBtn.btnBg.width = 200; cancelBtn.btnBg.height = 70; cancelBtn.down = function () { this.flash(); if (customBetPrompt) { customBetPrompt.destroy(); customBetPrompt = null; } }; customBetPrompt.addChild(cancelBtn); updateInputDisplay(); } // Add Instagram handle var instaHandle = new Text2('@ahmet_db', { size: 40, fill: 0xffffff }); instaHandle.anchor.set(0, 0.5); // Align to the left middle instaHandle.x = 2048 - 250; // Position slightly more left instaHandle.y = 130; // Position slightly more up game.addChild(instaHandle); // Add Instagram logo var instaLogo = LK.getAsset('instagramLogo', { width: 50, height: 50, anchorX: 1, // Align to the right anchorY: 0.5, // Align to the middle x: instaHandle.x - 10, // Position 10px to the left of the text y: instaHandle.y }); game.addChild(instaLogo); // Add "Open Account" button var openAccountBtn = new GameButton(); openAccountBtn.setText('Open Account'); openAccountBtn.x = 2048 / 2 + 750; // Position further to the right openAccountBtn.y = 200; // Position further upwards openAccountBtn.btnBg.width = 400; openAccountBtn.btnBg.height = 80; openAccountBtn.down = function () { this.flash(); accountMode = 'register'; // Set mode to register clearAccountInputs(); // Clear any previous input showAccountPrompt(); }; } // --- Mode Selection Handler --- // Password UI state var roulettePasswordPrompt = null; var roulettePasswordInput = null; var roulettePasswordError = null; function showRoulettePasswordPrompt() { showTopLeftBackBtn(function () { if (roulettePasswordPrompt) { roulettePasswordPrompt.destroy(); roulettePasswordPrompt = null; } showModeSelect(); }); // Remove any previous prompt if (roulettePasswordPrompt) { roulettePasswordPrompt.destroy(); roulettePasswordPrompt = null; } roulettePasswordPrompt = new Container(); game.addChild(roulettePasswordPrompt); // Background overlay var overlay = roulettePasswordPrompt.attachAsset('cardBg', { width: 900, height: 500, color: 0x222244, shape: 'box', anchorX: 0.5, anchorY: 0.5, x: 2048 / 2, y: 1200 }); // Title var promptTitle = new Text2('Enter Roulette Password', { size: 80, fill: "#fff" }); promptTitle.anchor.set(0.5, 0.5); promptTitle.x = 2048 / 2; promptTitle.y = 1050; roulettePasswordPrompt.addChild(promptTitle); // Password input (show as ****) var passwordValue = ''; roulettePasswordInput = new Text2('Password: ', { size: 60, fill: "#fff" }); roulettePasswordInput.anchor.set(0.5, 0.5); roulettePasswordInput.x = 2048 / 2; roulettePasswordInput.y = 1200; roulettePasswordPrompt.addChild(roulettePasswordInput); // Error text roulettePasswordError = new Text2('', { size: 48, fill: 0xFF4444 }); roulettePasswordError.anchor.set(0.5, 0.5); roulettePasswordError.x = 2048 / 2; roulettePasswordError.y = 1270; roulettePasswordPrompt.addChild(roulettePasswordError); // Number pad var padStartX = 2048 / 2 + 400; // moved even further right var padStartY = 1320; var padBtns = []; function updateInputDisplay() { var stars = ''; for (var i = 0; i < passwordValue.length; i++) stars += '*'; roulettePasswordInput.setText('Password: ' + stars); if (roulettePasswordError) roulettePasswordError.setText(''); } function clearInput() { passwordValue = ''; updateInputDisplay(); } function trySubmit() { if (passwordValue === '1334') { // Success if (roulettePasswordPrompt) { roulettePasswordPrompt.destroy(); roulettePasswordPrompt = null; } startRoulette(); } else { // Error if (roulettePasswordError) roulettePasswordError.setText('Incorrect password!'); clearInput(); } } // Password keypad layout: numbers in phone order var keypadLabels = [['1', '2', '3'], ['4', '5', '6'], ['7', '8', '9'], ['C', '0', 'OK']]; for (var row = 0; row < 4; row++) { for (var col = 0; col < 3; col++) { var label = keypadLabels[row][col]; var btn = new GameButton(); btn.setText(label); // Make buttons smaller and add more space between them btn.btnBg.width = 80; btn.btnBg.height = 80; btn.x = padStartX + col * 94; // 54px button + 40px gap btn.y = padStartY + row * 100; // 54px button + 46px gap // Make the button text larger for visibility for (var t = 0; t < btn.children.length; t++) { if (btn.children[t] && typeof btn.children[t].setText === "function") { btn.children[t].style = btn.children[t].style || {}; btn.children[t].style.size = 36; btn.children[t].setText(label); } } // Make the button background lighter for better contrast if (!isNaN(parseInt(label))) { if (label === '0') { btn.btnBg.color = 0xeeeeee; btn.setText(label); } else { btn.btnBg.color = 0xffffff; btn.setText(label); } } else if (label === 'C') { btn.btnBg.color = 0xffcccc; } else if (label === 'OK') { btn.btnBg.color = 0xccffcc; } btn.down = function (lbl) { return function () { this.flash(); if (lbl === 'C') { clearInput(); } else if (lbl === 'OK') { trySubmit(); } else if (lbl.length === 1 && passwordValue.length < 8) { passwordValue += lbl; updateInputDisplay(); } }; }(label); roulettePasswordPrompt.addChild(btn); padBtns.push(btn); } } updateInputDisplay(); } function selectMode(modeId) { currentMode = modeId; // Remove mode select UI for (var i = 0; i < modeButtons.length; i++) { if (modeButtons[i].parent) modeButtons[i].parent.removeChild(modeButtons[i]); } modeButtons = []; // Start selected mode if (modeId === 'blackjack') { startBlackjack(); } else if (modeId === 'roulette') { showRoulettePasswordPrompt(); } else { showComingSoon(modeId); } } // --- Coming Soon Placeholder --- function showComingSoon(modeId) { showTopLeftBackBtn(function () { if (playArea) playArea.destroy(); playArea = null; showModeSelect(); }); if (playArea) playArea.destroy(); playArea = new Container(); game.addChild(playArea); var txt = new Text2(MODES.filter(function (m) { return m.id === modeId; })[0].name + '\nComing Soon!', { size: 100, fill: "#fff" }); txt.anchor.set(0.5, 0.5); txt.x = 2048 / 2; txt.y = 1200; playArea.addChild(txt); // Back button var backBtn = new GameButton(); backBtn.setText('Back'); backBtn.x = 2048 / 2; backBtn.y = 1800; backBtn.down = function () { playArea.destroy(); playArea = null; showModeSelect(); }; playArea.addChild(backBtn); } // --- Start Blackjack --- function startBlackjack() { showTopLeftBackBtn(function () { if (playArea) playArea.destroy(); playArea = null; if (blackjack) { blackjack.destroy(); blackjack = null; } showModeSelect(); }); if (playArea) playArea.destroy(); playArea = new Container(); game.addChild(playArea); // Destroy old blackjack if any if (blackjack && blackjack.destroy) { blackjack.destroy(); blackjack = null; } blackjack = new BlackjackGame(); playArea.addChild(blackjack); } // (removed selectBlackjackSeat, not needed for single seat) // --- Start Sweet Bonanza --- function startSweetBonanza() { if (playArea) playArea.destroy(); playArea = new Container(); game.addChild(playArea); if (typeof sweetBonanza !== "undefined" && sweetBonanza && sweetBonanza.destroy) { sweetBonanza.destroy(); } sweetBonanza = new SweetBonanzaGame(); playArea.addChild(sweetBonanza); } // --- Start Roulette --- function startRoulette() { showTopLeftBackBtn(function () { if (playArea) playArea.destroy(); playArea = null; if (roulette) { roulette.destroy(); roulette = null; } showModeSelect(); }); if (playArea) playArea.destroy(); playArea = new Container(); game.addChild(playArea); if (typeof roulette !== "undefined" && roulette && roulette.destroy) { roulette.destroy(); } roulette = new RouletteGame(); playArea.addChild(roulette); } // --- Update Balance --- function updateBalance() { balanceText.setText('Balance: $' + playerBalance); storage.balance = playerBalance; } // --- Auto Reward System --- // Give +2000 every 10 minutes (600,000 ms) var AUTO_REWARD_AMOUNT = 2000; var AUTO_REWARD_INTERVAL = 600000; // 10 minutes in ms var lastRewardTime = storage.lastRewardTime || Date.now(); // --- Auto Reward Counter UI --- var autoRewardCounterText = new Text2('', { size: 40, fill: 0x66FFCC }); autoRewardCounterText.anchor.set(0.5, 0); // Place original counter in the center top (for legacy/compat) autoRewardCounterText.x = 2048 / 2; autoRewardCounterText.y = 160; LK.gui.top.addChild(autoRewardCounterText); // Add countdown timer to the top left var autoRewardCounterTextLeft = new Text2('', { size: 40, fill: 0x66FFCC }); autoRewardCounterTextLeft.anchor.set(0, 0); // left aligned, top autoRewardCounterTextLeft.x = 120; // 20px right of reserved area (100px reserved) autoRewardCounterTextLeft.y = 20; // 20px from top LK.gui.topLeft.addChild(autoRewardCounterTextLeft); // --- Quest System --- // Daily quest pool (at least 8, so 5 can be picked randomly each day) var QUEST_POOL = [{ id: 'bj_3rounds', desc: 'Play 3 Blackjack rounds', goal: 3, reward: 500 }, { id: 'roulette_win500', desc: 'Win $500 in Roulette', goal: 500, reward: 1000 }, { id: 'bj_blackjack_win2', desc: 'Win 2 Blackjack rounds', goal: 2, reward: 600 }, { id: 'roulette_bet5', desc: 'Place 5 Roulette bets', goal: 5, reward: 400 }, { id: 'bj_perfect_pair', desc: 'Get 1 Perfect Pair in Blackjack', goal: 1, reward: 1200 }, { id: 'roulette_number_win', desc: 'Win on a number bet in Roulette', goal: 1, reward: 900 }, { id: 'bj_double_down', desc: 'Double Down 2 times in Blackjack', goal: 2, reward: 700 }, { id: 'roulette_red_black', desc: 'Win 3 times on Red or Black in Roulette', goal: 3, reward: 500 }]; // Helper to get a deterministic "random" set of 5 quests per day function getDailyQuestIds() { var now = new Date(); var daySeed = now.getFullYear() * 10000 + (now.getMonth() + 1) * 100 + now.getDate(); var ids = []; var used = []; for (var i = 0; i < QUEST_POOL.length; i++) used[i] = false; var count = 0; var poolLen = QUEST_POOL.length; var seed = daySeed; while (ids.length < 5 && count < 20) { // Simple LCG for deterministic shuffle seed = (seed * 9301 + 49297) % 233280; var idx = Math.floor(seed / 233280 * poolLen); if (!used[idx]) { ids.push(QUEST_POOL[idx].id); used[idx] = true; } count++; } return ids; } // Build today's QUESTS array var QUESTS = []; var dailyIds = getDailyQuestIds(); for (var i = 0; i < dailyIds.length; i++) { for (var j = 0; j < QUEST_POOL.length; j++) { if (QUEST_POOL[j].id === dailyIds[i]) { // Clone quest object and add progress/complete QUESTS.push({ id: QUEST_POOL[j].id, desc: QUEST_POOL[j].desc, goal: QUEST_POOL[j].goal, reward: QUEST_POOL[j].reward, progress: 0, complete: false }); break; } } } // Load quest progress from storage if available and if for today if (storage.quests && storage.questsDay === new Date().toDateString()) { for (var i = 0; i < QUESTS.length; i++) { var q = QUESTS[i]; // Load from flat keys, e.g. quests.key_progress and quests.key_complete var progressKey = q.id + '_progress'; var completeKey = q.id + '_complete'; if (typeof storage.quests[progressKey] !== "undefined") { q.progress = storage.quests[progressKey]; } if (typeof storage.quests[completeKey] !== "undefined") { q.complete = storage.quests[completeKey]; } } } else { // New day, reset quest progress and save today's date // Initialize storage.quests as a flat object with only 1-level deep properties storage.quests = {}; storage.questsDay = new Date().toDateString(); } function saveQuests() { var save = {}; for (var i = 0; i < QUESTS.length; i++) { var q = QUESTS[i]; if (!storage.quests) storage.quests = {}; // Store as flat keys, e.g. quests.key_progress and quests.key_complete storage.quests[q.id + '_progress'] = q.progress; storage.quests[q.id + '_complete'] = q.complete; } storage.questsDay = new Date().toDateString(); } // Quest UI (bottom left, separate area) var questTextNodes = []; function updateQuestUI() { // Remove old for (var i = 0; i < questTextNodes.length; i++) { if (questTextNodes[i].parent) questTextNodes[i].parent.removeChild(questTextNodes[i]); questTextNodes[i].destroy(); } questTextNodes = []; // Place quests in bottom left, avoid left 100px reserved area var y = 40; // Padding from bottom for (var i = 0; i < QUESTS.length; i++) { var q = QUESTS[i]; var txt = new Text2((q.complete ? '✅ ' : '') + q.desc + ' [' + q.progress + '/' + q.goal + ']' + (q.complete ? ' (Claimed)' : ' Prize: $' + q.reward), { size: 32, fill: q.complete ? "#aaffaa" : "#fff" }); txt.anchor.set(0, 1); // left aligned, bottom txt.x = 120; // 20px right of reserved area txt.y = -y; // negative y for bottom alignment in LK.gui.bottomLeft LK.gui.bottomLeft.addChild(txt); questTextNodes.push(txt); y += 38; } } updateQuestUI(); // --- Daily Quest Timer UI (bottom right) --- var questTimerText = new Text2('', { size: 38, fill: 0xFFD700 }); questTimerText.anchor.set(1, 1); // right aligned, bottom questTimerText.x = -40; // 40px from right edge in LK.gui.bottomRight questTimerText.y = -40; // 40px from bottom LK.gui.bottomRight.addChild(questTimerText); function updateQuestTimer() { // Calculate time left until midnight var now = new Date(); var tomorrow = new Date(now.getFullYear(), now.getMonth(), now.getDate() + 1, 0, 0, 0, 0); var msLeft = tomorrow - now; if (msLeft < 0) msLeft = 0; var sec = Math.floor(msLeft / 1000) % 60; var min = Math.floor(msLeft / 60000) % 60; var hr = Math.floor(msLeft / 3600000); var timeStr = (hr < 10 ? '0' : '') + hr + ':' + (min < 10 ? '0' : '') + min + ':' + (sec < 10 ? '0' : '') + sec; questTimerText.setText('Daily quests reset in: ' + timeStr); } LK.setInterval(updateQuestTimer, 1000); updateQuestTimer(); // Quest logic: call these when player does actions function questEvent(event, value) { var updated = false; for (var i = 0; i < QUESTS.length; i++) { var q = QUESTS[i]; if (q.complete) continue; // Blackjack round played if (event === 'blackjack_round' && q.id === 'bj_3rounds') { q.progress++; if (q.progress >= q.goal) { q.progress = q.goal; q.complete = true; playerBalance += q.reward; updateBalance(); showQuestRewardPopup(q.reward, q.desc); } updated = true; } // Win 2 Blackjack rounds if (event === 'blackjack_win' && q.id === 'bj_blackjack_win2') { q.progress++; if (q.progress >= q.goal) { q.progress = q.goal; q.complete = true; playerBalance += q.reward; updateBalance(); showQuestRewardPopup(q.reward, q.desc); } updated = true; } // Double Down in Blackjack if (event === 'blackjack_double' && q.id === 'bj_double_down') { q.progress++; if (q.progress >= q.goal) { q.progress = q.goal; q.complete = true; playerBalance += q.reward; updateBalance(); showQuestRewardPopup(q.reward, q.desc); } updated = true; } // Get Perfect Pair in Blackjack if (event === 'blackjack_perfect_pair' && q.id === 'bj_perfect_pair') { q.progress++; if (q.progress >= q.goal) { q.progress = q.goal; q.complete = true; playerBalance += q.reward; updateBalance(); showQuestRewardPopup(q.reward, q.desc); } updated = true; } // Roulette win $500 if (event === 'roulette_win' && q.id === 'roulette_win500') { q.progress += value; if (q.progress >= q.goal) { q.progress = q.goal; q.complete = true; playerBalance += q.reward; updateBalance(); showQuestRewardPopup(q.reward, q.desc); } updated = true; } // Place 5 Roulette bets if (event === 'roulette_bet' && q.id === 'roulette_bet5') { q.progress++; if (q.progress >= q.goal) { q.progress = q.goal; q.complete = true; playerBalance += q.reward; updateBalance(); showQuestRewardPopup(q.reward, q.desc); } updated = true; } // Win on a number bet in Roulette if (event === 'roulette_number_win' && q.id === 'roulette_number_win') { q.progress++; if (q.progress >= q.goal) { q.progress = q.goal; q.complete = true; playerBalance += q.reward; updateBalance(); showQuestRewardPopup(q.reward, q.desc); } updated = true; } // Win on Red/Black in Roulette if (event === 'roulette_red_black_win' && q.id === 'roulette_red_black') { q.progress++; if (q.progress >= q.goal) { q.progress = q.goal; q.complete = true; playerBalance += q.reward; updateBalance(); showQuestRewardPopup(q.reward, q.desc); } updated = true; } } if (updated) { saveQuests(); updateQuestUI(); } } function showQuestRewardPopup(amount, desc) { var popup = new Text2('Quest Complete!\n' + desc + '\n+$' + amount, { size: 70, fill: 0xFFD700 }); popup.anchor.set(0.5, 0.5); popup.x = 2048 / 2; popup.y = 600; game.addChild(popup); tween(popup, { y: popup.y - 80, alpha: 0 }, { duration: 1400, onFinish: function onFinish() { popup.destroy(); } }); } // Update auto reward counter as before function updateAutoRewardCounter() { var now = Date.now(); var msLeft = AUTO_REWARD_INTERVAL - (now - lastRewardTime) % AUTO_REWARD_INTERVAL; if (msLeft < 0) msLeft = 0; var sec = Math.floor(msLeft / 1000) % 60; var min = Math.floor(msLeft / 60000); var timeStr = (min < 10 ? '0' : '') + min + ':' + (sec < 10 ? '0' : '') + sec; autoRewardCounterText.setText('Next Reward: +' + AUTO_REWARD_AMOUNT + ' in ' + timeStr); autoRewardCounterTextLeft.setText('Next reward: ' + timeStr); } function checkAutoReward() { var now = Date.now(); // If more than interval has passed, give reward (handle multiple missed intervals) var intervals = Math.floor((now - lastRewardTime) / AUTO_REWARD_INTERVAL); if (intervals > 0) { var totalReward = intervals * AUTO_REWARD_AMOUNT; playerBalance += totalReward; updateBalance(); lastRewardTime += intervals * AUTO_REWARD_INTERVAL; storage.lastRewardTime = lastRewardTime; // Optionally show a quick popup for reward var rewardText = new Text2('Auto Reward: +$' + totalReward, { size: 70, fill: 0x66ffcc }); rewardText.anchor.set(0.5, 0.5); rewardText.x = 2048 / 2; rewardText.y = 400; game.addChild(rewardText); tween(rewardText, { y: rewardText.y - 80, alpha: 0 }, { duration: 1200, onFinish: function onFinish() { rewardText.destroy(); } }); } updateAutoRewardCounter(); } // Check auto reward every 10 seconds, and update counter every second LK.setInterval(checkAutoReward, 10000); LK.setInterval(updateAutoRewardCounter, 1000); updateAutoRewardCounter(); // Check for new day and reset quests if needed function checkQuestDay() { var today = new Date().toDateString(); if (storage.questsDay !== today) { // Force reload of page to reset quests (or you can re-run quest init logic here) location.reload(); } } LK.setInterval(checkQuestDay, 60000); // check every minute // --- Start Game --- showModeSelect(); updateBalance(); // --- Touch Handling (for mobile) --- game.move = function (x, y, obj) { // No drag in this game }; game.down = function (x, y, obj) { // No drag in this game }; game.up = function (x, y, obj) { // No drag in this game }; // --- Game Tick --- game.update = function () { // No per-frame logic needed for MVP // Win/Lose system for all casino modes (except Blackjack, which already has it) // Placeholder for future slot/other games: if (currentMode === 'sweet') { // Example: If playerBalance <= 0, show lose popup if (playerBalance <= 0) { LK.showGameOver(); } // Example: If playerBalance >= 10000, show win popup if (playerBalance >= 10000) { LK.showYouWin(); } } };
/****
* Plugins
****/
var tween = LK.import("@upit/tween.v1");
var storage = LK.import("@upit/storage.v1");
/****
* Classes
****/
// --- Blackjack Game Logic ---
var BlackjackGame = Container.expand(function () {
var self = Container.call(this);
// State
self.currentSeat = 0; // Track which seat is currently active
self.deck = [];
self.playerHand = [];
self.dealerHand = [];
self.playerCards = [];
self.dealerCards = [];
self.state = 'bet'; // 'bet', 'player', 'dealer', 'result', 'betBehind'
self.resultText = null;
self.buttons = [];
self.bet = betAmount;
self.betBehind = 0; // Amount bet behind
self.betBehindWin = 0; // Track bet behind win for this round
// Add Blackjack table background image (bjTable) as the table background
var bjTableBg = self.attachAsset('bjTable', {
width: 1800,
height: 900,
anchorX: 0.5,
anchorY: 0,
x: 2048 / 2,
y: 700 // position to fit under croupier and cards
});
self.addChild(bjTableBg);
// Add croupier image above the dealer cards, make it bigger to fit with the table
var croupier = self.attachAsset('croupier', {
width: 320,
height: 320,
anchorX: 0.5,
anchorY: 1,
x: 2048 / 2,
y: 900 - 80 // slightly above dealer cards
});
self.addChild(croupier);
// Deal new deck
self.newDeck = function () {
var suits = ['♠', '♥', '♦', '♣'];
var ranks = ['A', '2', '3', '4', '5', '6', '7', '8', '9', '10', 'J', 'Q', 'K'];
var deck = [];
for (var s = 0; s < 4; s++) {
for (var r = 0; r < 13; r++) {
deck.push({
rank: ranks[r],
suit: suits[s]
});
}
}
// Shuffle
for (var i = deck.length - 1; i > 0; i--) {
var j = Math.floor(Math.random() * (i + 1));
var t = deck[i];
deck[i] = deck[j];
deck[j] = t;
}
self.deck = deck;
};
// Draw a card
self.drawCard = function () {
if (self.deck.length === 0) self.newDeck();
return self.deck.pop();
};
// Calculate hand value
self.handValue = function (hand) {
var value = 0;
var aces = 0;
for (var i = 0; i < hand.length; i++) {
var r = hand[i].rank;
if (r === 'A') {
value += 11;
aces++;
} else if (r === 'K' || r === 'Q' || r === 'J') {
value += 10;
} else {
value += parseInt(r);
}
}
while (value > 21 && aces > 0) {
value -= 10;
aces--;
}
return value;
};
// Start a new round
self.startRound = function () {
self.state = 'player';
self.playerHand = [];
self.dealerHand = [];
self.clearCards();
self.resultText && self.resultText.destroy();
self.resultText = null;
// Bet
self.bet = betAmount;
self.betBehindWin = 0;
self.perfectPairWin = false; // Track perfect pair win for this round
if (playerBalance < self.bet) {
self.showResult('Not enough balance!', true);
return;
}
playerBalance -= self.bet;
updateBalance();
// Deal
// Deal cards with animation
self.playerHand.push(self.drawCard());
self.dealerHand.push(self.drawCard());
self.playerHand.push(self.drawCard());
self.dealerHand.push(self.drawCard());
self.clearCards();
// --- Perfect Pair Side Bet Logic ---
// If first two player cards are same rank and same suit, pay 25:1
self.perfectPairWin = false;
self.perfectPairPayout = 0;
if (self.playerHand.length === 2 && self.playerHand[0].rank === self.playerHand[1].rank && self.playerHand[0].suit === self.playerHand[1].suit) {
self.perfectPairWin = true;
self.perfectPairPayout = self.bet * 25;
playerBalance += self.perfectPairPayout;
updateBalance();
// Show a quick popup for perfect pair win
var pairText = new Text2('Perfect Pair! +$' + self.perfectPairPayout, {
size: 80,
fill: 0xFFE066
});
pairText.anchor.set(0.5, 0.5);
pairText.x = 2048 / 2;
pairText.y = 1550;
self.addChild(pairText);
tween(pairText, {
y: pairText.y - 120,
alpha: 0
}, {
duration: 1200,
onFinish: function onFinish() {
pairText.destroy();
}
});
}
// Card distribution animation
var px = 2048 / 2 - 200;
var py = 1700;
var dx = 2048 / 2 - 200;
var dy = 900;
var dealDelay = 200;
var dealDuration = 350;
var dealStartX = 2048 / 2;
var dealStartY = 1200;
self.playerCards = [];
self.dealerCards = [];
// Helper to animate a card to its position with deal effect
function animateCard(card, toX, toY, delay, isPlayer) {
card.x = dealStartX;
card.y = dealStartY;
card.scaleX = 0.2;
card.scaleY = 0.2;
card.alpha = 0;
card.visible = true;
self.addChild(card);
tween(card, {
x: toX,
y: toY,
scaleX: 1,
scaleY: 1,
alpha: 1
}, {
duration: dealDuration,
easing: tween.cubicOut,
delay: delay
});
if (isPlayer) {
self.playerCards.push(card);
} else {
self.dealerCards.push(card);
}
}
// Create and animate cards in order: player1, dealer1, player2, dealer2
var playerCard1 = new Card();
playerCard1.setCard(self.playerHand[0].rank, self.playerHand[0].suit, true);
playerCard1.visible = false;
var dealerCard1 = new Card();
dealerCard1.setCard(self.dealerHand[0].rank, self.dealerHand[0].suit, true);
dealerCard1.visible = false;
var playerCard2 = new Card();
playerCard2.setCard(self.playerHand[1].rank, self.playerHand[1].suit, true);
playerCard2.visible = false;
var dealerCard2 = new Card();
dealerCard2.setCard(self.dealerHand[1].rank, self.dealerHand[1].suit, false);
dealerCard2.visible = false;
LK.setTimeout(function () {
animateCard(playerCard1, px, py, 0, true);
playerCard1.visible = true;
LK.setTimeout(function () {
animateCard(dealerCard1, dx, dy, 0, false);
dealerCard1.visible = true;
LK.setTimeout(function () {
animateCard(playerCard2, px + 180, py, 0, true); // Increased spacing from 120 to 180
playerCard2.visible = true;
LK.setTimeout(function () {
animateCard(dealerCard2, dx + 180, dy, 0, false); // Increased spacing from 120 to 180
dealerCard2.visible = true;
// After all cards are dealt, show buttons
LK.setTimeout(function () {
self.showButtons(['Hit', 'Stand']);
}, dealDuration);
}, dealDelay);
}, dealDelay);
}, dealDelay);
}, 0);
};
// Show cards on table
self.showHands = function (revealDealer) {
if (typeof revealDealer === "undefined") revealDealer = false;
self.clearCards();
// Player
var px = 2048 / 2 - 200;
var py = 1700;
for (var i = 0; i < self.playerHand.length; i++) {
var c = new Card();
c.setCard(self.playerHand[i].rank, self.playerHand[i].suit, true);
c.x = px + i * 180; // Increased spacing from 120 to 180
c.y = py;
c.visible = true; // Player cards are visible
self.addChild(c);
self.playerCards.push(c);
}
// Dealer
var dx = 2048 / 2 - 200;
var dy = 900;
for (var i = 0; i < self.dealerHand.length; i++) {
var c = new Card();
var faceUp = i === 0 || revealDealer;
c.setCard(self.dealerHand[i].rank, self.dealerHand[i].suit, faceUp);
c.x = dx + i * 180; // Increased spacing from 120 to 180
c.y = dy;
c.visible = revealDealer ? true : false; // Show dealer cards only if revealDealer is true
self.addChild(c);
self.dealerCards.push(c);
}
};
// Remove card objects
self.clearCards = function () {
for (var i = 0; i < self.playerCards.length; i++) {
self.playerCards[i].destroy();
}
for (var i = 0; i < self.dealerCards.length; i++) {
self.dealerCards[i].destroy();
}
self.playerCards = [];
self.dealerCards = [];
};
// Show action buttons
self.showButtons = function (labels) {
for (var i = 0; i < self.buttons.length; i++) {
self.buttons[i].destroy();
}
self.buttons = [];
// If in player state, add Double if allowed (first move, enough balance, only 2 cards)
var showDouble = false;
if (self.state === 'player' && self.playerHand.length === 2 && playerBalance >= self.bet) {
showDouble = true;
if (labels.indexOf('Double') === -1) labels.push('Double');
}
// Add Bet Behind button if in 'bet' state and player has enough balance
if (self.state === 'bet' && playerBalance >= betAmount) {
labels.push('Bet Behind');
}
var startX = 2048 / 2 - (labels.length - 1) * 220;
for (var i = 0; i < labels.length; i++) {
var btn = new GameButton();
btn.setText(labels[i]);
btn.x = startX + i * 440;
btn.y = 2100;
btn.action = labels[i];
btn.down = function () {
this.flash();
if (this.action === 'Bet Behind') {
// Place bet behind
if (playerBalance >= betAmount) {
self.betBehind += betAmount;
playerBalance -= betAmount;
updateBalance();
// Show quick popup for bet behind placed
var bbText = new Text2('Bet Behind: $' + self.betBehind, {
size: 70,
fill: 0x66ffcc
});
bbText.anchor.set(0.5, 0.5);
bbText.x = 2048 / 2;
bbText.y = 2000;
self.addChild(bbText);
tween(bbText, {
y: bbText.y - 80,
alpha: 0
}, {
duration: 900,
onFinish: function onFinish() {
bbText.destroy();
}
});
}
} else {
self.handleAction(this.action);
}
};
self.addChild(btn);
self.buttons.push(btn);
}
};
// Handle player actions
self.handleAction = function (action) {
if (self.state !== 'player') return;
if (action === 'Hit') {
self.playerHand.push(self.drawCard());
self.showHands(false); //{21} // Always show dealer's first card only until round ends
var val = self.handValue(self.playerHand);
if (val > 21) {
self.state = 'result';
self.showHands(true);
self.showResult('Bust! You lose.');
}
} else if (action === 'Stand') {
self.state = 'dealer';
self.showHands(true);
self.showButtons([]);
self.dealerTurn();
} else if (action === 'Double') {
// Double the bet, draw one card, then stand
if (playerBalance >= self.bet && self.playerHand.length === 2) {
playerBalance -= self.bet;
self.bet *= 2;
updateBalance();
self.playerHand.push(self.drawCard());
self.showHands(false); //{2f} // Always show dealer's first card only until round ends
var val = self.handValue(self.playerHand);
if (val > 21) {
self.state = 'result';
self.showHands(true);
self.showResult('Bust! You lose.');
} else {
self.state = 'dealer';
self.showHands(true);
self.showButtons([]);
self.dealerTurn();
}
}
}
};
// Dealer logic
self.dealerTurn = function () {
var self_ = self;
var dealerVal = self.handValue(self.dealerHand);
var playerVal = self.handValue(self.playerHand);
function dealerStep() {
dealerVal = self_.handValue(self_.dealerHand);
if (dealerVal < 17) {
self_.dealerHand.push(self_.drawCard());
self_.showHands(true);
LK.setTimeout(dealerStep, 700);
} else {
self_.state = 'result';
self_.showHands(true);
self_.showResult(self_.getResultText());
}
}
LK.setTimeout(dealerStep, 700);
};
// Determine result
self.getResultText = function () {
var playerVal = self.handValue(self.playerHand);
var dealerVal = self.handValue(self.dealerHand);
if (playerVal > 21) return 'Bust! You lose.';
// Dealer busts
if (dealerVal > 21) {
playerBalance += self.bet * 2;
// Bet behind wins if player hand not bust
if (self.betBehind > 0 && playerVal <= 21) {
self.betBehindWin = self.betBehind * 2;
playerBalance += self.betBehindWin;
}
updateBalance();
return 'Dealer busts! You win!' + (self.betBehindWin > 0 ? '\nBet Behind Win: $' + self.betBehindWin : '');
}
// Player wins
if (playerVal > dealerVal) {
// Check for natural 21 (Blackjack) on initial deal, no hit, and win
var isNatural21 = self.playerHand.length === 2 && self.handValue(self.playerHand) === 21 && typeof self.lastAction !== "string" // No action taken (no hit/double)
;
var winAmount = self.bet * 2;
if (isNatural21) {
// Award 50% more for natural 21 win without hit
var bonus = Math.floor(self.bet * 0.5);
winAmount += bonus;
}
playerBalance += winAmount;
// Bet behind wins if player hand not bust
if (self.betBehind > 0 && playerVal <= 21) {
self.betBehindWin = self.betBehind * 2;
playerBalance += self.betBehindWin;
}
updateBalance();
var winMsg = 'You win!' + (self.betBehindWin > 0 ? '\nBet Behind Win: $' + self.betBehindWin : '');
if (isNatural21) {
winMsg = 'Blackjack! +50% bonus\n' + winMsg;
}
return winMsg;
}
// Player loses
if (playerVal < dealerVal) {
// Bet behind lost
return 'You lose.' + (self.betBehind > 0 ? '\nBet Behind Lost: $' + self.betBehind : '');
}
// Push
playerBalance += self.bet;
if (self.betBehind > 0) {
playerBalance += self.betBehind; // Return bet behind on push
self.betBehindWin = self.betBehind;
}
updateBalance();
return 'Push!' + (self.betBehind > 0 ? '\nBet Behind Push: $' + self.betBehind : '');
};
// Show result and next round
self.showResult = function (txt, noNext) {
self.resultText && self.resultText.destroy();
// If perfect pair win, append to result text
if (self.perfectPairWin && txt && txt.indexOf('Perfect Pair!') === -1) {
txt = 'Perfect Pair! +$' + self.perfectPairPayout + '\n' + txt;
}
// --- Quest: Play 3 Blackjack rounds ---
if (typeof questEvent === "function") questEvent('blackjack_round');
// --- Quest: Win 2 Blackjack rounds ---
if (typeof questEvent === "function" && txt && txt.indexOf('win') !== -1 && txt.toLowerCase().indexOf('you win') !== -1) questEvent('blackjack_win');
// --- Quest: Double Down in Blackjack ---
if (typeof questEvent === "function" && self.lastAction === 'Double') questEvent('blackjack_double');
// --- Quest: Get Perfect Pair in Blackjack ---
if (typeof questEvent === "function" && self.perfectPairWin) questEvent('blackjack_perfect_pair');
self.resultText = new Text2(txt, {
size: 90,
fill: "#fff"
});
self.resultText.anchor.set(0.5, 0.5);
self.resultText.x = 2048 / 2;
self.resultText.y = 1450;
self.addChild(self.resultText);
self.showButtons(['New Round', 'Back']);
self.buttons[0].down = function () {
this.flash();
self.startRound();
};
self.buttons[1].down = function () {
this.flash();
self.destroy();
blackjack = null;
showModeSelect();
};
if (noNext) {
self.buttons[0].visible = false;
}
};
// Destroy
self.destroy = function () {
self.clearCards();
for (var i = 0; i < self.buttons.length; i++) {
self.buttons[i].destroy();
}
self.buttons = [];
self.resultText && self.resultText.destroy();
self.resultText = null;
self.perfectPairWin = false;
self.perfectPairPayout = 0;
self.betBehind = 0;
self.betBehindWin = 0;
if (self.parent) self.parent.removeChild(self);
};
// Start
self.newDeck();
self.startRound();
return self;
});
// Card class for Blackjack
var Card = Container.expand(function () {
var self = Container.call(this);
// Card properties
self.rank = null; // 2-10, J, Q, K, A
self.suit = null; // '♠', '♥', '♦', '♣'
self.faceUp = true;
// Card background
var cardBg = self.attachAsset('cardBg', {
width: 180,
height: 260,
color: 0xffffff,
shape: 'box',
anchorX: 0.5,
anchorY: 0.5
});
// Card text
var cardText = new Text2('', {
size: 80,
fill: 0x222222
});
cardText.anchor.set(0.5, 0.5);
self.addChild(cardText);
// Set card value
self.setCard = function (rank, suit, faceUp) {
self.rank = rank;
self.suit = suit;
self.faceUp = faceUp !== false;
if (self.faceUp) {
cardText.setText(rank + suit);
cardText.visible = true;
cardBg.color = suit === '♥' || suit === '♦' ? 0xffeaea : 0xffffff;
} else {
cardText.setText('');
cardText.visible = false;
cardBg.color = 0x8888aa;
}
};
// Flip card
self.flip = function (up) {
self.faceUp = up;
self.setCard(self.rank, self.suit, up);
};
return self;
});
// Simple Button class
var GameButton = Container.expand(function () {
var self = Container.call(this);
var btnBg = self.attachAsset('btnBg', {
width: 420,
height: 120,
color: 0x333366,
shape: 'box',
anchorX: 0.5,
anchorY: 0.5
});
self.btnBg = btnBg; // <-- Fix: assign btnBg as a property for external access
var btnText = new Text2('', {
size: 60,
fill: 0xFFFFFF
});
btnText.anchor.set(0.5, 0.5);
self.addChild(btnText);
self.setText = function (txt) {
btnText.setText(txt);
};
// For touch feedback
self.flash = function () {
tween(btnBg, {
color: 0x6666cc
}, {
duration: 100,
onFinish: function onFinish() {
tween(btnBg, {
color: 0x333366
}, {
duration: 200
});
}
});
};
return self;
});
// --- Roulette Game Logic ---
var RouletteGame = Container.expand(function () {
var self = Container.call(this);
// State
self.state = 'bet'; // 'bet', 'spin', 'result'
self.betType = null; // 'red', 'black', 'even', 'odd', 'number'
self.betValue = null; // For number bet
self.resultText = null;
self.buttons = [];
self.rouletteWheel = null;
self.ball = null;
self.spinBtn = null;
self.backBtn = null;
self.betOptions = [];
self.selectedBetBtn = null;
// Table background (roulette table image)
var rouletteTableBg = self.attachAsset('RouletteBG', {
width: 1400,
height: 700,
anchorX: 0.5,
anchorY: 0.5,
x: 2048 / 2,
y: 800
});
// Draw roulette wheel using a realistic image and overlay visible numbers
var wheelRadius = 320;
var wheelCenterX = 2048 / 2;
var wheelCenterY = 800; // Move wheel further up
var numbers = [];
for (var i = 0; i < 37; i++) numbers.push(i);
// Red/Black numbers (European roulette)
var reds = [1, 3, 5, 7, 9, 12, 14, 16, 18, 19, 21, 23, 25, 27, 30, 32, 34, 36];
var blacks = [2, 4, 6, 8, 10, 11, 13, 15, 17, 20, 22, 24, 26, 28, 29, 31, 33, 35];
// Draw wheel container
self.rouletteWheel = new Container();
self.rouletteWheel.x = wheelCenterX;
self.rouletteWheel.y = wheelCenterY;
self.addChild(self.rouletteWheel);
// Add roulette wheel image (should be a top-down wheel with visible slots)
var wheelImg = self.rouletteWheel.attachAsset('rouletteWheelImg', {
width: wheelRadius * 2,
height: wheelRadius * 2,
anchorX: 0.5,
anchorY: 0.5,
x: 0,
y: 0
});
// Overlay numbers on the wheel image for visibility
for (var i = 0; i < 37; i++) {
var angle = i / 37 * Math.PI * 2 - Math.PI / 2;
var num = numbers[i];
// European roulette: 0 is green, reds as defined, rest are black
var color = "#fff";
var bgColor = 0x222222;
if (num === 0) {
bgColor = 0x1abc2c; // vivid green for 0
color = "#fff";
} else if (reds.indexOf(num) !== -1) {
bgColor = 0xff0000;
color = "#fff";
} else if (blacks.indexOf(num) !== -1) {
bgColor = 0x222222;
color = "#fff";
}
// Draw number text with a subtle shadow for visibility
var txt = new Text2(num + '', {
size: 38,
fill: color,
stroke: "#000",
strokeThickness: 6
});
txt.anchor.set(0.5, 0.5);
txt.x = Math.cos(angle) * (wheelRadius - 38);
txt.y = Math.sin(angle) * (wheelRadius - 38);
self.rouletteWheel.addChild(txt);
// Add invisible hit area for number bets (for touch/click)
var hitSlot = self.rouletteWheel.attachAsset('cardBg', {
width: 60,
height: 60,
color: 0x000000,
alpha: 0,
// invisible
shape: 'box',
anchorX: 0.5,
anchorY: 0.5,
x: Math.cos(angle) * (wheelRadius - 38),
y: Math.sin(angle) * (wheelRadius - 38)
});
hitSlot.hitArea = new Rectangle(-30, -30, 60, 60);
hitSlot.down = function (betValue) {
return function () {
// Provide visual feedback by flashing the number text
var txtNode = txt;
if (typeof tween === "function" && txtNode && typeof txtNode.alpha !== "undefined") {
var originalAlpha = txtNode.alpha;
tween(txtNode, {
alpha: 0.5
}, {
duration: 100,
onFinish: function onFinish() {
tween(txtNode, {
alpha: originalAlpha
}, {
duration: 200
});
}
});
}
// Unhighlight all bet buttons
for (var j = 0; j < self.splitBetOptions.length; j++) {
if (self.splitBetOptions[j].btnBg) self.splitBetOptions[j].btnBg.color = 0x333366;
}
if (self.redBtn && self.redBtn.btnBg) self.redBtn.btnBg.color = 0x333366;
if (self.blackBtn && self.blackBtn.btnBg) self.blackBtn.btnBg.color = 0x333366;
self.betType = 'number';
self.betValue = betValue;
self.selectedBetBtn = this;
self.showResult('Number bet: ' + self.betValue + ' ($' + Math.max(betAmount, 50) + ')', true);
// Highlight selected number text
txtNode.style = txtNode.style || {};
txtNode.style.fill = "#ffe066";
if (self.state === 'bet') {
self.spinBtn.visible = true;
}
};
}(num);
}
// Ball
self.ball = self.rouletteWheel.attachAsset('rouletteball', {
width: 38,
height: 38,
anchorX: 0.5,
anchorY: 0.5,
x: Math.cos(-Math.PI / 2) * (wheelRadius - 40),
y: Math.sin(-Math.PI / 2) * (wheelRadius - 40)
});
// Bet options
// Allow number bets (0-36) and split bets (adjacent numbers) in a compact grid below the wheel
// Arrange numbers 0-36 in a 4-row grid: 0 on its own, then 1-12 in second, 13-24 in third, 25-36 in fourth
var betGridCols = 12;
var betGridRows = 4; // 0 in first row, 1-12 in second, 13-24 in third, 25-36 in fourth
var betBtnW = 70;
var betBtnH = 70;
var betGridStartX = 2048 / 2 - betGridCols * betBtnW / 2 + betBtnW / 2;
var betGridStartY = 1150; // Move up to match new wheel position
self.betOptions = [];
self.splitBetOptions = []; // Store split bet buttons
// --- Number Bet Keyboard (below bet sign) ---
// Move number bet keyboard to the left of the roulette wheel
var numberKeyboardStartY = wheelCenterY - wheelRadius + 40; // Align top with wheel, with a little padding
var numberKeyboardStartX = wheelCenterX - wheelRadius - 420; // Place to the left of the wheel, with some gap
var numberKeyboardLabels = [['1', '2', '3', '4'], ['5', '6', '7', '8'], ['9', '10', '11', '12'], ['13', '14', '15', '16'], ['17', '18', '19', '20'], ['21', '22', '23', '24'], ['25', '26', '27', '28'], ['29', '30', '31', '32'], ['33', '34', '35', '36'], ['0']];
self.numberBetButtons = [];
for (var row = 0; row < numberKeyboardLabels.length; row++) {
for (var col = 0; col < numberKeyboardLabels[row].length; col++) {
var label = numberKeyboardLabels[row][col];
var btn = new GameButton();
btn.setText(label);
btn.btnBg.width = 80;
btn.btnBg.height = 80;
btn.x = numberKeyboardStartX + col * 90;
btn.y = numberKeyboardStartY + row * 90;
btn.betType = 'number';
btn.betValue = parseInt(label);
btn.down = function (btnRef, value) {
return function () {
this.flash();
// Unhighlight all bet buttons
for (var j = 0; j < self.betOptions.length; j++) {
if (self.betOptions[j].btnBg) self.betOptions[j].btnBg.color = 0x333366;
}
for (var j = 0; j < self.splitBetOptions.length; j++) {
if (self.splitBetOptions[j].btnBg) self.splitBetOptions[j].btnBg.color = 0x333366;
}
for (var j = 0; j < self.numberBetButtons.length; j++) {
if (self.numberBetButtons[j].btnBg) self.numberBetButtons[j].btnBg.color = 0x333366;
}
if (self.redBtn && self.redBtn.btnBg) self.redBtn.btnBg.color = 0x333366;
if (self.blackBtn && self.blackBtn.btnBg) self.blackBtn.btnBg.color = 0x333366;
self.betType = 'number';
self.betValue = value;
self.selectedBetBtn = this;
self.showResult('Number bet: ' + value + ' ($' + Math.max(betAmount, 50) + ')', true);
if (this.btnBg) this.btnBg.color = 0x6666cc;
if (self.state === 'bet') {
self.spinBtn.visible = true;
}
};
}(btn, parseInt(label));
self.addChild(btn);
self.numberBetButtons.push(btn);
}
}
// Helper to get grid position for a number
function getGridPos(num) {
if (num === 0) {
return {
col: 5.5,
row: 0
}; // Center 0 above the grid
}
var idx = num - 1;
return {
col: idx % betGridCols,
row: 1 + Math.floor(idx / betGridCols)
};
}
// --- Add Red/Black bet buttons ---
// Move the red/black bet buttons even further down below the roulette wheel
var colorBetY = numberKeyboardStartY + numberKeyboardLabels.length * 90 + 520; // Move even further down
var colorBetXOffset = 200; // Increase horizontal offset for more space between buttons
var redBtn = new GameButton();
redBtn.setText('Red');
redBtn.x = wheelCenterX - colorBetXOffset;
redBtn.y = colorBetY;
redBtn.betType = 'red';
redBtn.down = function () {
this.flash();
// Unhighlight all bet buttons
for (var j = 0; j < self.betOptions.length; j++) {
if (self.betOptions[j].btnBg) self.betOptions[j].btnBg.color = 0x333366;
}
for (var j = 0; j < self.splitBetOptions.length; j++) {
if (self.splitBetOptions[j].btnBg) self.splitBetOptions[j].btnBg.color = 0x333366;
}
if (self.blackBtn && self.blackBtn.btnBg) self.blackBtn.btnBg.color = 0x333366;
if (self.redBtn && self.redBtn.btnBg) self.redBtn.btnBg.color = 0x333366;
self.betType = 'red';
self.betValue = null;
self.selectedBetBtn = this;
self.showResult('Red bet ($' + Math.max(betAmount, 50) + ')', true);
if (this.btnBg) this.btnBg.color = 0xff0000;
if (self.state === 'bet') {
self.spinBtn.visible = true;
}
};
self.addChild(redBtn);
self.betOptions.push(redBtn);
self.redBtn = redBtn;
var blackBtn = new GameButton();
blackBtn.setText('Black');
blackBtn.x = wheelCenterX + colorBetXOffset;
blackBtn.y = colorBetY;
blackBtn.betType = 'black';
blackBtn.down = function () {
this.flash();
// Unhighlight all bet buttons
for (var j = 0; j < self.betOptions.length; j++) {
if (self.betOptions[j].btnBg) self.betOptions[j].btnBg.color = 0x333366;
}
for (var j = 0; j < self.splitBetOptions.length; j++) {
if (self.splitBetOptions[j].btnBg) self.splitBetOptions[j].btnBg.color = 0x333366;
}
if (self.redBtn && self.redBtn.btnBg) self.redBtn.btnBg.color = 0x333366;
if (self.blackBtn && self.blackBtn.btnBg) self.blackBtn.btnBg.color = 0x333366;
self.betType = 'black';
self.betValue = null;
self.selectedBetBtn = this;
self.showResult('Black bet ($' + Math.max(betAmount, 50) + ')', true);
if (this.btnBg) this.btnBg.color = 0x222222;
if (self.state === 'bet') {
self.spinBtn.visible = true;
}
};
self.addChild(blackBtn);
self.betOptions.push(blackBtn);
self.blackBtn = blackBtn;
// Create split bet buttons (between adjacent numbers: right and below)
for (var i = 0; i < 37; i++) {
var pos = getGridPos(i);
// Split right (horizontal)
if (pos.col < betGridCols - 1 && i + 1 < 37) {
var splitBtn = new GameButton();
splitBtn.setText(i + '|' + (i + 1));
splitBtn.x = betGridStartX + pos.col * betBtnW + betBtnW / 2;
splitBtn.y = betGridStartY + pos.row * (betBtnH + 10) + 200; // Moved down
splitBtn.btnBg.width = 90;
splitBtn.btnBg.height = 90;
// Add even more space between split bet buttons horizontally
splitBtn.x = betGridStartX + pos.col * (betBtnW + 50) + betBtnW / 2;
splitBtn.y = betGridStartY + pos.row * (betBtnH + 50) + 200; // Moved down and spaced further
splitBtn.betType = 'split';
splitBtn.betValue = [i, i + 1];
splitBtn.down = function (splitBtn) {
return function () {
this.flash();
// Unhighlight all bet buttons
for (var j = 0; j < self.betOptions.length; j++) {
if (self.betOptions[j].btnBg) self.betOptions[j].btnBg.color = 0x333366;
}
for (var j = 0; j < self.splitBetOptions.length; j++) {
if (self.splitBetOptions[j].btnBg) self.splitBetOptions[j].btnBg.color = 0x333366;
}
self.betType = 'split';
self.betValue = splitBtn.betValue;
self.selectedBetBtn = this;
self.showResult('Split bet: ' + splitBtn.betValue[0] + ' & ' + splitBtn.betValue[1] + ' ($' + Math.max(betAmount, 50) + ')', true);
if (this.btnBg) this.btnBg.color = 0x6666cc;
if (self.state === 'bet') {
self.spinBtn.visible = true;
}
};
}(splitBtn);
self.addChild(splitBtn);
self.splitBetOptions.push(splitBtn);
}
// Split below (vertical)
if (pos.row < betGridRows - 1 && i + betGridCols < 37) {
var splitBtn2 = new GameButton();
splitBtn2.setText(i + '\\' + (i + betGridCols));
splitBtn2.x = betGridStartX + pos.col * (betBtnW + 10);
splitBtn2.y = betGridStartY + pos.row * (betBtnH + 10) + (betBtnH + 10) / 2 + 100; // Moved down
splitBtn2.btnBg.width = 90;
splitBtn2.btnBg.height = 90;
// Add even more space between split bet buttons vertically
splitBtn2.x = betGridStartX + pos.col * (betBtnW + 50);
splitBtn2.y = betGridStartY + pos.row * (betBtnH + 50) + (betBtnH + 50) / 2 + 100; // Moved down and spaced further
splitBtn2.betType = 'split';
splitBtn2.betValue = [i, i + betGridCols];
splitBtn2.down = function (splitBtn2) {
return function () {
this.flash();
// Unhighlight all bet buttons
for (var j = 0; j < self.betOptions.length; j++) {
if (self.betOptions[j].btnBg) self.betOptions[j].btnBg.color = 0x333366;
}
for (var j = 0; j < self.splitBetOptions.length; j++) {
if (self.splitBetOptions[j].btnBg) self.splitBetOptions[j].btnBg.color = 0x333366;
}
self.betType = 'split';
self.betValue = splitBtn2.betValue;
self.selectedBetBtn = this;
self.showResult('Split bet: ' + splitBtn2.betValue[0] + ' & ' + splitBtn2.betValue[1] + ' ($' + Math.max(betAmount, 50) + ')', true);
if (this.btnBg) this.btnBg.color = 0x6666cc;
if (self.state === 'bet') {
self.spinBtn.visible = true;
}
};
}(splitBtn2);
self.addChild(splitBtn2);
self.splitBetOptions.push(splitBtn2);
}
}
// Spin button
// Calculate betY for button positioning
var betY = betGridStartY + betGridRows * betBtnH + 40;
self.spinBtn = new GameButton();
self.spinBtn.setText('Spin');
// Make Spin button visually and structurally match the Back button
self.spinBtn.x = 2048 / 2 - 600;
self.spinBtn.y = betY + 300;
self.spinBtn.btnBg.width = 420;
self.spinBtn.btnBg.height = 120;
self.spinBtn.visible = false; // Only show after bet selected
self.spinBtn.down = function () {
this.flash();
self.handleSpin();
};
self.addChild(self.spinBtn);
// Back button
self.backBtn = new GameButton();
self.backBtn.setText('Back');
// Move Back button further left of Spin
self.backBtn.x = 2048 / 2 - 600;
self.backBtn.y = betY + 450;
self.backBtn.down = function () {
self.destroy();
roulette = null;
showModeSelect();
};
self.addChild(self.backBtn);
// Show result text
self.showResult = function (txt, noNext) {
self.resultText && self.resultText.destroy();
self.resultText = new Text2(txt, {
size: 90,
fill: "#fff"
});
self.resultText.anchor.set(0.5, 0.5);
self.resultText.x = 2048 / 2;
self.resultText.y = 1550;
self.addChild(self.resultText);
if (!noNext) {
// Show "New Round" button
var nextBtn = new GameButton();
nextBtn.setText('New Round');
nextBtn.x = 2048 / 2;
nextBtn.y = betY + 600;
nextBtn.down = function () {
this.flash();
self.reset();
};
self.addChild(nextBtn);
self.buttons.push(nextBtn);
}
};
// Handle spin
self.handleSpin = function () {
// Only allow spin if a bet is selected
if (!self.betType || self.betType === 'number' && (typeof self.betValue !== "number" || self.betValue < 0 || self.betValue > 36)) {
self.showResult('Select a bet first!', true);
return;
}
if (betAmount < 50) {
self.showResult('Minimum bet is $50!', true);
return;
}
if (self.state !== 'bet') {
self.showResult('You can only place one bet per round!', true);
return;
}
self.state = 'spin';
if (playerBalance < betAmount) {
self.showResult('Not enough balance!', true);
return;
}
playerBalance -= betAmount;
updateBalance();
self.state = 'spin';
self.spinBtn.visible = false;
for (var i = 0; i < self.betOptions.length; i++) self.betOptions[i].visible = false;
self.resultText && self.resultText.destroy();
// Animate ball spin
var winningNumber = Math.floor(Math.random() * 37);
var totalSpins = 3 + Math.floor(Math.random() * 2);
var frames = 60 * totalSpins;
var startAngle = -Math.PI / 2;
var endAngle = winningNumber / 37 * Math.PI * 2 - Math.PI / 2;
var currentFrame = 0;
function animateBall() {
var t = currentFrame / frames;
var angle = startAngle + (endAngle - startAngle) * t + Math.PI * 2 * (1 - t) * totalSpins;
self.ball.x = Math.cos(angle) * (wheelRadius - 40);
self.ball.y = Math.sin(angle) * (wheelRadius - 40);
currentFrame++;
if (currentFrame <= frames) {
LK.setTimeout(animateBall, 1000 / 60);
} else {
self.showSpinResult(winningNumber);
// After result, allow new bet
self.betType = null;
self.betValue = null;
if (self.selectedBetBtn && self.selectedBetBtn.btnBg) {
self.selectedBetBtn.btnBg.color = 0x333366;
}
self.selectedBetBtn = null;
// Show bet options for next round, but keep spin button hidden until bet is selected
self.spinBtn.visible = false;
for (var i = 0; i < self.betOptions.length; i++) self.betOptions[i].visible = true;
}
}
animateBall();
};
// Show spin result and payout
self.showSpinResult = function (winningNumber) {
var win = false;
var payout = 0;
var msg = '';
if (self.betType === 'red' && reds.indexOf(winningNumber) !== -1) {
win = true;
payout = betAmount * 2;
msg = 'Red wins!';
} else if (self.betType === 'black' && blacks.indexOf(winningNumber) !== -1) {
win = true;
payout = betAmount * 2;
msg = 'Black wins!';
} else if (self.betType === 'even' && winningNumber !== 0 && winningNumber % 2 === 0) {
win = true;
payout = betAmount * 2;
msg = 'Even wins!';
} else if (self.betType === 'odd' && winningNumber % 2 === 1) {
win = true;
payout = betAmount * 2;
msg = 'Odd wins!';
} else if (self.betType === 'number' && self.betValue === winningNumber) {
win = true;
payout = betAmount * 36;
msg = 'Number ' + winningNumber + ' wins!';
} else if (self.betType === 'split' && self.betValue && self.betValue.indexOf(winningNumber) !== -1) {
win = true;
payout = betAmount * 18; // Standard split bet payout is 17:1, so bet*18
msg = 'Split bet wins! Number ' + winningNumber + '!';
} else {
msg = 'Number ' + winningNumber + '. You lose.';
}
if (win) {
playerBalance += payout;
updateBalance();
msg += ' You win $' + payout + '!';
// --- Quest: Win $500 in Roulette ---
if (typeof questEvent === "function") questEvent('roulette_win', payout);
// --- Quest: Place 5 Roulette bets ---
if (typeof questEvent === "function") questEvent('roulette_bet');
// --- Quest: Win on a number bet in Roulette ---
if (typeof questEvent === "function" && self.betType === 'number' && self.betValue === winningNumber) questEvent('roulette_number_win');
// --- Quest: Win on Red/Black in Roulette ---
if (typeof questEvent === "function" && (self.betType === 'red' || self.betType === 'black')) questEvent('roulette_red_black_win');
} else {
// Even if lose, count bet for "Place 5 Roulette bets"
if (typeof questEvent === "function") questEvent('roulette_bet');
}
self.state = 'result';
self.showResult(msg);
};
// Reset for new round
self.reset = function () {
self.betType = null;
self.betValue = null;
self.state = 'bet';
self.resultText && self.resultText.destroy();
for (var i = 0; i < self.buttons.length; i++) self.buttons[i].destroy();
self.buttons = [];
self.spinBtn.visible = false;
for (var i = 0; i < self.betOptions.length; i++) {
self.betOptions[i].visible = true;
if (self.betOptions[i].btnBg) self.betOptions[i].btnBg.color = 0x333366;
}
for (var i = 0; i < (self.splitBetOptions ? self.splitBetOptions.length : 0); i++) {
self.splitBetOptions[i].visible = true;
if (self.splitBetOptions[i].btnBg) self.splitBetOptions[i].btnBg.color = 0x333366;
}
self.selectedBetBtn = null;
};
// Destroy
self.destroy = function () {
self.resultText && self.resultText.destroy();
for (var i = 0; i < self.betOptions.length; i++) self.betOptions[i].destroy();
self.betOptions = [];
if (self.splitBetOptions) {
for (var i = 0; i < self.splitBetOptions.length; i++) self.splitBetOptions[i].destroy();
self.splitBetOptions = [];
}
self.spinBtn && self.spinBtn.destroy();
self.backBtn && self.backBtn.destroy();
for (var i = 0; i < self.buttons.length; i++) self.buttons[i].destroy();
self.buttons = [];
self.rouletteWheel && self.rouletteWheel.destroy();
self.state = 'bet';
if (self.parent) self.parent.removeChild(self);
};
return self;
});
// --- Sweet Bonanza Game Logic ---
var SweetBonanzaGame = Container.expand(function () {
var self = Container.call(this);
// Slot config
var ROWS = 5;
var COLS = 6;
var SYMBOLS = [{
id: 'red',
color: 0xff4b5c,
payout: 10
}, {
id: 'blue',
color: 0x4b7bff,
payout: 8
}, {
id: 'green',
color: 0x4bff7b,
payout: 6
}, {
id: 'yellow',
color: 0xffe066,
payout: 4
}, {
id: 'purple',
color: 0xb266ff,
payout: 12
}, {
id: 'bomb',
color: 0xffffff,
payout: 0,
isBomb: true
}];
var symbolSize = 180;
var gridOffsetX = 2048 / 2 - COLS * symbolSize / 2;
var gridOffsetY = 900;
var grid = [];
var symbolNodes = [];
var spinBtn = null;
var resultText = null;
var canSpin = true;
// (Removed slot background)
// Draw grid
function drawGrid() {
// Remove old
for (var i = 0; i < symbolNodes.length; i++) {
for (var j = 0; j < symbolNodes[i].length; j++) {
symbolNodes[i][j].destroy();
}
}
symbolNodes = [];
for (var row = 0; row < ROWS; row++) {
symbolNodes[row] = [];
for (var col = 0; col < COLS; col++) {
var sym = grid[row][col];
var node = self.attachAsset('cardBg', {
width: symbolSize - 10,
height: symbolSize - 10,
color: sym.color,
shape: 'box',
anchorX: 0.5,
anchorY: 0.5,
x: gridOffsetX + col * symbolSize + symbolSize / 2,
y: gridOffsetY + row * symbolSize + symbolSize / 2
});
// Add symbol text
var txt = new Text2(sym.isBomb ? '💣' : '', {
size: 80,
fill: "#222"
});
txt.anchor.set(0.5, 0.5);
node.addChild(txt);
symbolNodes[row][col] = node;
}
}
}
// Generate random grid
function randomGrid() {
grid = [];
for (var row = 0; row < ROWS; row++) {
grid[row] = [];
for (var col = 0; col < COLS; col++) {
var sym = SYMBOLS[Math.floor(Math.random() * SYMBOLS.length)];
grid[row][col] = sym;
}
}
}
// Find clusters of 8+ matching symbols (Sweet Bonanza style)
function findClusters() {
var visited = [];
for (var i = 0; i < ROWS; i++) visited[i] = [];
var clusters = [];
function dfs(r, c, id, cluster) {
if (r < 0 || r >= ROWS || c < 0 || c >= COLS) return;
if (visited[r][c]) return;
if (grid[r][c].id !== id) return;
visited[r][c] = true;
cluster.push({
row: r,
col: c
});
dfs(r - 1, c, id, cluster);
dfs(r + 1, c, id, cluster);
dfs(r, c - 1, id, cluster);
dfs(r, c + 1, id, cluster);
}
for (var row = 0; row < ROWS; row++) {
for (var col = 0; col < COLS; col++) {
if (!visited[row][col] && !grid[row][col].isBomb) {
var cluster = [];
dfs(row, col, grid[row][col].id, cluster);
if (cluster.length >= 8) {
clusters.push({
id: grid[row][col].id,
cells: cluster,
payout: grid[row][col].payout
});
}
}
}
}
return clusters;
}
// Remove clusters and drop new symbols
function removeClusters(clusters) {
for (var i = 0; i < clusters.length; i++) {
var cells = clusters[i].cells;
for (var j = 0; j < cells.length; j++) {
var r = cells[j].row;
var c = cells[j].col;
grid[r][c] = null;
}
}
// Drop down
for (var col = 0; col < COLS; col++) {
var empty = [];
for (var row = ROWS - 1; row >= 0; row--) {
if (grid[row][col] === null) {
empty.push(row);
} else if (empty.length > 0) {
var target = empty.shift();
grid[target][col] = grid[row][col];
grid[row][col] = null;
empty.push(row);
}
}
// Fill empty with new
for (var k = 0; k < empty.length; k++) {
var r = empty[k];
var sym = SYMBOLS[Math.floor(Math.random() * SYMBOLS.length)];
grid[r][col] = sym;
}
}
}
// Check for bombs
function hasBomb() {
for (var row = 0; row < ROWS; row++) {
for (var col = 0; col < COLS; col++) {
if (grid[row][col].isBomb) return true;
}
}
return false;
}
// Spin logic
function spin() {
if (!canSpin) return;
if (playerBalance < betAmount) {
showResult('Not enough balance!');
return;
}
// --- Quest: Spin Sweet Bonanza 5 times ---
if (typeof questEvent === "function") questEvent('sweet_spin');
canSpin = false;
playerBalance -= betAmount;
updateBalance();
resultText && resultText.destroy();
resultText = null;
randomGrid();
drawGrid();
// Animate spin (simple delay)
LK.setTimeout(function () {
var clusters = findClusters();
var win = 0;
for (var i = 0; i < clusters.length; i++) {
win += clusters[i].payout * betAmount;
}
if (win > 0) {
playerBalance += win;
updateBalance();
showResult('Win! $' + win);
} else if (hasBomb()) {
showResult('💣 Bomb! Lose!');
} else {
showResult('No win');
}
// Remove clusters and drop new
if (clusters.length > 0) {
removeClusters(clusters);
drawGrid();
}
canSpin = true;
}, 700);
}
// Show result text
function showResult(txt) {
resultText && resultText.destroy();
resultText = new Text2(txt, {
size: 90,
fill: "#fff"
});
resultText.anchor.set(0.5, 0.5);
resultText.x = 2048 / 2;
resultText.y = gridOffsetY + ROWS * symbolSize + 120;
self.addChild(resultText);
}
// Spin button
spinBtn = new GameButton();
spinBtn.setText('Spin');
spinBtn.x = 2048 / 2;
spinBtn.y = gridOffsetY + ROWS * symbolSize + 250;
spinBtn.down = function () {
this.flash();
spin();
};
self.addChild(spinBtn);
// Back button
var backBtn = new GameButton();
backBtn.setText('Back');
backBtn.x = 2048 / 2;
backBtn.y = gridOffsetY + ROWS * symbolSize + 400;
backBtn.down = function () {
self.destroy();
sweetBonanza = null;
showModeSelect();
};
self.addChild(backBtn);
// Destroy
self.destroy = function () {
for (var i = 0; i < symbolNodes.length; i++) {
for (var j = 0; j < symbolNodes[i].length; j++) {
symbolNodes[i][j].destroy();
}
}
symbolNodes = [];
spinBtn && spinBtn.destroy();
backBtn && backBtn.destroy();
resultText && resultText.destroy();
if (self.parent) self.parent.removeChild(self);
};
// Init
randomGrid();
drawGrid();
return self;
});
/****
* Initialize Game
****/
var game = new LK.Game({
backgroundColor: 0x2e8b57 // deep green, matches Blackjack table
});
/****
* Game Code
****/
// Blood red background (deep red)
// --- Account System State ---
// --- Global State ---
// (Removed fullscreen Blackjack table background image)
function _typeof(o) {
"@babel/helpers - typeof";
return _typeof = "function" == typeof Symbol && "symbol" == typeof Symbol.iterator ? function (o) {
return typeof o;
} : function (o) {
return o && "function" == typeof Symbol && o.constructor === Symbol && o !== Symbol.prototype ? "symbol" : typeof o;
}, _typeof(o);
}
var accountState = {
loggedIn: false,
username: null
};
var accountPrompt = null;
var accountErrorText = null;
var accountNameInput = null;
var accountPasswordInput = null;
var accountNameValue = '';
var accountPasswordValue = '';
var accountMode = 'login'; // 'login' or 'register'
// Helper: get all accounts from storage
function getAllAccounts() {
// Use storage.getItem to retrieve accounts, fallback to empty object if not found
var accounts = storage.getItem && typeof storage.getItem === "function" ? storage.getItem("accounts") : storage.accounts;
if (!accounts || _typeof(accounts) !== "object") accounts = {};
return accounts;
}
// Helper: save all accounts to storage
function saveAllAccounts(accounts) {
// Use storage.setItem to persist accounts if available
if (storage.setItem && typeof storage.setItem === "function") {
storage.setItem("accounts", accounts);
}
storage.accounts = accounts;
}
// Helper: hash password (simple, not secure, but for demo)
function hashPassword(pw) {
// Ensure pw is a string to avoid errors on charCodeAt
if (pw === undefined || pw === null) pw = '';
pw = String(pw);
var h = 0;
for (var i = 0; i < pw.length; i++) {
// Defensive: check that pw is a string and pw[i] exists
var ch = typeof pw === "string" && pw.length > i ? pw.charAt(i) : '';
if (typeof ch === "string" && ch.length === 1) {
h += ch.charCodeAt(0) * (i + 17);
}
}
// Defensive: ensure h is a number before converting to string
if (typeof h !== "number" || isNaN(h)) h = 0;
// Always return as string, and never undefined/null
try {
// Defensive: if h is not a string or number, return empty string
if (typeof h === "string") return h;
if (typeof h === "number") return String(h);
// If h is not string or number, fallback to empty string
return '';
} catch (e) {
// In case of any error, always return empty string
return '';
}
// Final fallback: always return a string
if (typeof h === "undefined" || h === null) return '';
// Defensive: ensure return is always a string
try {
// Fix: Always return a string, never throw
if (typeof h === "string") return h;
if (typeof h === "number") return String(h);
return '';
} catch (e) {
return '';
}
// Absolute fallback
return '';
}
// Show account setup/login UI
function showAccountPrompt() {
// Remove old prompt if present
if (accountPrompt) {
accountPrompt.destroy();
accountPrompt = null;
}
accountPrompt = new Container();
game.addChild(accountPrompt);
// Background overlay
var overlay = accountPrompt.attachAsset('cardBg', {
width: 900,
height: 600,
color: 0x222244,
shape: 'box',
anchorX: 0.5,
anchorY: 0.5,
x: 2048 / 2,
y: 1200
});
// Title
var title = new Text2(accountMode === 'register' ? 'Create Account' : 'Login', {
size: 80,
fill: "#fff"
});
title.anchor.set(0.5, 0.5);
title.x = 2048 / 2;
title.y = 950;
accountPrompt.addChild(title);
// Username input
accountNameInput = new Text2('Name: ' + accountNameValue, {
size: 60,
fill: "#fff"
});
accountNameInput.anchor.set(0.5, 0.5);
accountNameInput.x = 2048 / 2;
accountNameInput.y = 1100;
accountPrompt.addChild(accountNameInput);
// Password input (show as ****)
var stars = '';
for (var i = 0; i < accountPasswordValue.length; i++) stars += '*';
accountPasswordInput = new Text2('Password: ' + stars, {
size: 60,
fill: "#fff"
});
accountPasswordInput.anchor.set(0.5, 0.5);
accountPasswordInput.x = 2048 / 2;
accountPasswordInput.y = 1200;
accountPrompt.addChild(accountPasswordInput);
function updateNameInputDisplay() {
accountNameInput.setText('Name: ' + accountNameValue);
if (accountErrorText) accountErrorText.setText('');
}
function updatePasswordInputDisplay() {
var stars = '';
for (var i = 0; i < accountPasswordValue.length; i++) stars += '*';
accountPasswordInput.setText('Password: ' + stars);
if (accountErrorText) accountErrorText.setText('');
}
function clearAccountInputs() {
accountNameValue = '';
accountPasswordValue = '';
updateNameInputDisplay();
updatePasswordInputDisplay();
}
// Error text
accountErrorText = new Text2('', {
size: 48,
fill: 0xFF4444
});
accountErrorText.anchor.set(0.5, 0.5);
accountErrorText.x = 2048 / 2;
accountErrorText.y = 1270;
accountPrompt.addChild(accountErrorText);
// Name pad (A-Z, backspace, next) - split left
var namePadStartX = 2048 / 2 - 500;
var namePadStartY = 1350;
var namePadLabels = [['A', 'B', 'C', 'D', 'E', 'F', 'G', 'H', 'I', 'J'], ['K', 'L', 'M', 'N', 'O', 'P', 'Q', 'R', 'S', 'T'], ['U', 'V', 'W', 'X', 'Y', 'Z', '/', '_', '<-', 'OK']];
function updateNameInputDisplay() {
accountNameInput.setText('Name: ' + accountNameValue);
if (accountErrorText) accountErrorText.setText('');
}
function updatePasswordInputDisplay() {
var stars = '';
for (var i = 0; i < accountPasswordValue.length; i++) stars += '*';
accountPasswordInput.setText('Password: ' + stars);
if (accountErrorText) accountErrorText.setText('');
}
function clearAccountInputs() {
accountNameValue = '';
accountPasswordValue = '';
updateNameInputDisplay();
updatePasswordInputDisplay();
}
function tryAccountSubmit() {
var name = accountNameValue.trim();
var pw = accountPasswordValue;
if (name.length < 3) {
accountErrorText.setText('Name must be at least 3 characters.');
return;
}
if (pw.length < 6) {
accountErrorText.setText('Password must be at least 6 digits.');
return;
}
var accounts = getAllAccounts();
if (accountMode === 'register') {
if (accounts[name]) {
accountErrorText.setText('Name already taken!');
return;
}
// Only allow digits in password
if (!/^\d+$/.test(pw)) {
accountErrorText.setText('Password must be digits only.');
return;
}
// Register
accounts[name] = {
password: hashPassword(pw),
created: Date.now()
};
saveAllAccounts(accounts);
accountState.loggedIn = true;
accountState.username = name;
accountPasswordValue = ''; // Clear password after success
if (accountPrompt) {
accountPrompt.destroy();
accountPrompt = null;
}
showModeSelect();
} else {
// Login
if (!accounts[name]) {
accountErrorText.setText('Account not found.');
return;
}
if (accounts[name].password !== hashPassword(pw)) {
accountErrorText.setText('Incorrect password.');
return;
}
accountState.loggedIn = true;
accountState.username = name;
accountPasswordValue = ''; // Clear password after success
if (accountPrompt) {
accountPrompt.destroy();
accountPrompt = null;
}
showModeSelect();
}
}
function clearAccountInputs() {
accountNameValue = '';
accountPasswordValue = '';
updateNameInputDisplay();
updatePasswordInputDisplay();
}
var namePadStartY = 1350;
var namePadLabels = [['A', 'B', 'C', 'D', 'E', 'F', 'G', 'H', 'I', 'J'], ['K', 'L', 'M', 'N', 'O', 'P', 'Q', 'R', 'S', 'T'], ['U', 'V', 'W', 'X', 'Y', 'Z', '/', '_', '<-', 'OK']];
function updateNameInputDisplay() {
accountNameInput.setText('Name: ' + accountNameValue);
if (accountErrorText) accountErrorText.setText('');
}
function updatePasswordInputDisplay() {
var stars = '';
for (var i = 0; i < accountPasswordValue.length; i++) stars += '*';
accountPasswordInput.setText('Password: ' + stars);
if (accountErrorText) accountErrorText.setText('');
}
function tryAccountSubmit() {
var name = accountNameValue.trim();
var pw = accountPasswordValue;
if (name.length < 3) {
accountErrorText.setText('Name must be at least 3 characters.');
return;
}
if (pw.length < 6) {
accountErrorText.setText('Password must be at least 6 digits.');
return;
}
var accounts = getAllAccounts();
if (accountMode === 'register') {
if (accounts[name]) {
accountErrorText.setText('Name already taken!');
return;
}
// Only allow digits in password
if (!/^\d+$/.test(pw)) {
accountErrorText.setText('Password must be digits only.');
return;
}
// Register
accounts[name] = {
password: hashPassword(pw),
created: Date.now()
};
saveAllAccounts(accounts);
accountState.loggedIn = true;
accountState.username = name;
accountPasswordValue = ''; // Clear password after success
if (accountPrompt) {
accountPrompt.destroy();
accountPrompt = null;
}
showModeSelect();
} else {
// Login
if (!accounts[name]) {
accountErrorText.setText('Account not found.');
return;
}
if (accounts[name].password !== hashPassword(pw)) {
accountErrorText.setText('Incorrect password.');
return;
}
accountState.loggedIn = true;
accountState.username = name;
accountPasswordValue = ''; // Clear password after success
if (accountPrompt) {
accountPrompt.destroy();
accountPrompt = null;
}
showModeSelect();
}
}
function clearAccountInputs() {
accountNameValue = '';
accountPasswordValue = '';
updateNameInputDisplay();
updatePasswordInputDisplay();
}
// Draw name pad (letters only, left side)
for (var row = 0; row < namePadLabels.length; row++) {
for (var col = 0; col < namePadLabels[row].length; col++) {
var label = namePadLabels[row][col];
var btn = new GameButton();
btn.setText(label);
// Make buttons smaller and add more space between them
btn.btnBg.width = 54;
btn.btnBg.height = 54;
btn.x = namePadStartX + col * 74; // 54px button + 20px gap
btn.y = namePadStartY + row * 80; // 54px button + 26px gap
// Make text a bit larger for visibility
for (var t = 0; t < btn.children.length; t++) {
if (btn.children[t] && typeof btn.children[t].setText === "function") {
btn.children[t].style = btn.children[t].style || {};
btn.children[t].style.size = 36;
btn.children[t].setText(label);
}
}
if (label === '<-') btn.btnBg.color = 0xffcccc;
if (label === 'OK') btn.btnBg.color = 0xccffcc;
btn.down = function (lbl) {
return function () {
this.flash();
if (lbl === '<-') {
if (accountNameValue.length > 0) {
accountNameValue = accountNameValue.slice(0, -1);
updateNameInputDisplay();
}
} else if (lbl === 'OK') {
// Move to password input
// If already on password, try submit
if (accountPasswordValue.length < 6) {
accountErrorText.setText('Password must be at least 6 digits.');
return;
}
tryAccountSubmit();
} else {
if (accountNameValue.length < 12 && /^[A-Z_\/]$/.test(lbl)) {
accountNameValue += lbl;
updateNameInputDisplay();
}
}
};
}(label);
accountPrompt.addChild(btn);
}
}
// Number pad (digits 0-9, C, OK) - right side
var pwPadStartX = 2048 / 2 + 400;
var pwPadStartY = 1350;
var pwPadLabels = [['1', '2', '3'], ['4', '5', '6'], ['7', '8', '9'], ['C', '0', 'OK']];
for (var prow = 0; prow < 4; prow++) {
for (var pcol = 0; pcol < 3; pcol++) {
var plabel = pwPadLabels[prow][pcol];
var pbtn = new GameButton();
pbtn.setText(plabel);
// Make buttons smaller and add more space between them
pbtn.btnBg.width = 54;
pbtn.btnBg.height = 54;
pbtn.x = pwPadStartX + pcol * 74; // 54px button + 20px gap
pbtn.y = pwPadStartY + prow * 80; // 54px button + 26px gap
// Make text a bit larger for visibility
for (var t = 0; t < pbtn.children.length; t++) {
if (pbtn.children[t] && typeof pbtn.children[t].setText === "function") {
pbtn.children[t].style = pbtn.children[t].style || {};
pbtn.children[t].style.size = 36;
pbtn.children[t].setText(plabel);
}
}
if (plabel === 'C') pbtn.btnBg.color = 0xffcccc;
if (plabel === 'OK') pbtn.btnBg.color = 0xccffcc;
pbtn.down = function (lbl) {
return function () {
this.flash();
if (lbl === 'C') {
accountPasswordValue = '';
updatePasswordInputDisplay();
} else if (lbl === 'OK') {
tryAccountSubmit();
} else if (lbl.length === 1 && accountPasswordValue.length < 12 && /^\d$/.test(lbl)) {
accountPasswordValue += lbl;
updatePasswordInputDisplay();
}
};
}(plabel);
accountPrompt.addChild(pbtn);
}
}
// Switch mode button
var switchBtn = new GameButton();
switchBtn.setText(accountMode === 'register' ? 'Have account? Login' : 'No account? Register');
switchBtn.x = 2048 / 2;
switchBtn.y = 1800; // moved even further down
switchBtn.btnBg.width = 400;
switchBtn.btnBg.height = 70;
switchBtn.down = function () {
this.flash();
accountMode = accountMode === 'register' ? 'login' : 'register';
accountNameValue = '';
accountPasswordValue = '';
if (accountPrompt) {
accountPrompt.destroy();
accountPrompt = null;
}
showAccountPrompt();
};
accountPrompt.addChild(switchBtn);
}
// On game start, allow guest play by default
// Optionally, user can open account prompt from a button in the mode select screen
// --- Top Left Back Button ---
var topLeftBackBtn = null;
function showTopLeftBackBtn(onBack) {
// Remove if already present
if (topLeftBackBtn && topLeftBackBtn.parent) {
topLeftBackBtn.parent.removeChild(topLeftBackBtn);
topLeftBackBtn.destroy();
topLeftBackBtn = null;
}
topLeftBackBtn = new GameButton();
topLeftBackBtn.setText('Back');
// Place at (100,220) to avoid the reserved 100x100px area and move a little further down
topLeftBackBtn.x = 100 + 80; // 80px right of reserved area
topLeftBackBtn.y = 100 + 160; // 160px below reserved area (moved a little further down)
topLeftBackBtn.btnBg.width = 180;
topLeftBackBtn.btnBg.height = 80;
topLeftBackBtn.down = function () {
this.flash();
if (typeof onBack === "function") onBack();
};
game.addChild(topLeftBackBtn);
}
function hideTopLeftBackBtn() {
if (topLeftBackBtn && topLeftBackBtn.parent) {
topLeftBackBtn.parent.removeChild(topLeftBackBtn);
topLeftBackBtn.destroy();
topLeftBackBtn = null;
}
}
/****
* Casino Carnival - MVP
* Four-in-one casino game: Blackjack, Sweet Bonanza, Gates of Olympus, Sugar Rush
* MVP: Game selection, basic betting, and one playable mode (Blackjack)
****/
var MODES = [{
id: 'blackjack',
name: 'Blackjack'
}, {
id: 'roulette',
name: 'Roulette'
}];
var currentMode = null; // 'blackjack', etc.
var playerBalance = storage.balance || 1000;
var betAmount = 100;
var minBet = 50;
var maxBet = 500000;
// --- Single Seat State ---
var blackjack = null;
// UI elements
var modeButtons = [];
var betText = null;
var balanceText = null;
var playArea = null;
var blackjack = null;
// --- GUI: Balance and Bet ---
balanceText = new Text2('Balance: $' + playerBalance, {
size: 60,
fill: "#fff"
});
balanceText.anchor.set(0.5, 0);
LK.gui.top.addChild(balanceText);
betText = new Text2('Bet: $' + betAmount, {
size: 50,
fill: "#fff"
});
betText.anchor.set(0.5, 0);
LK.gui.top.addChild(betText);
// Position GUI elements
balanceText.y = 10;
betText.y = 80;
// --- Game Selection Screen ---
function showModeSelect() {
hideTopLeftBackBtn();
// Clear play area
if (playArea) {
playArea.destroy();
playArea = null;
}
if (blackjack) {
blackjack.destroy();
blackjack = null;
}
// Destroy blackjack instance if present
if (blackjack && blackjack.destroy) {
blackjack.destroy();
blackjack = null;
}
// Remove old mode buttons
for (var i = 0; i < modeButtons.length; i++) {
if (modeButtons[i].parent) modeButtons[i].parent.removeChild(modeButtons[i]);
}
modeButtons = [];
// Title
var title = new Text2('Casino Carnival', {
size: 120,
fill: 0xFFE066
});
title.anchor.set(0.5, 0.5);
title.x = 2048 / 2;
title.y = 350;
game.addChild(title);
// Mode buttons
var startY = 700;
var gapY = 200;
for (var i = 0; i < MODES.length; i++) {
var btn = new GameButton();
btn.setText(MODES[i].name);
// Adjust font size to fit the button for 'Blackjack' and 'Roulette'
if (MODES[i].name === 'Blackjack' || MODES[i].name === 'Roulette') {
// Find the Text2 child and set its size smaller to fit the red area
for (var j = 0; j < btn.children.length; j++) {
if (btn.children[j] && typeof btn.children[j].setText === "function") {
btn.children[j].style = btn.children[j].style || {};
btn.children[j].style.size = 48; // Reduce font size to fit
btn.children[j].setText(MODES[i].name);
}
}
}
btn.x = 2048 / 2;
btn.y = startY + i * gapY;
btn.modeId = MODES[i].id;
btn.down = function (x, y, obj) {
this.flash();
selectMode(this.modeId);
};
game.addChild(btn);
modeButtons.push(btn);
}
// Bet controls
var betMinus = new GameButton();
betMinus.setText('-');
betMinus.x = 2048 / 2 - 350;
betMinus.y = startY + MODES.length * gapY + 60;
betMinus.down = function () {
var step = 50;
if (betAmount > 20000) {
step = 2000;
} else if (betAmount > 10000) {
step = 1000;
} else if (betAmount > 5000) {
step = 500;
} else if (betAmount > 1000) {
step = 100;
}
if (betAmount - step >= minBet) {
betAmount -= step;
} else if (betAmount > minBet) {
betAmount = minBet;
}
betText.setText('Bet: $' + betAmount);
};
game.addChild(betMinus);
var betCustomBtn = new GameButton();
betCustomBtn.setText('✎');
betCustomBtn.x = 2048 / 2;
betCustomBtn.y = startY + MODES.length * gapY + 60;
betCustomBtn.btnBg.width = 100;
betCustomBtn.btnBg.height = 100;
betCustomBtn.down = function () {
this.flash();
showCustomBetInput();
};
game.addChild(betCustomBtn);
var betPlus = new GameButton();
betPlus.setText('+');
betPlus.x = 2048 / 2 + 350;
betPlus.y = startY + MODES.length * gapY + 60;
betPlus.down = function () {
var step = 50;
if (betAmount >= 20000) {
step = 2000;
} else if (betAmount >= 10000) {
step = 1000;
} else if (betAmount >= 5000) {
step = 500;
} else if (betAmount >= 1000) {
step = 100;
}
if (betAmount + step <= maxBet) {
betAmount += step;
} else if (betAmount < maxBet) {
betAmount = maxBet;
}
betText.setText('Bet: $' + betAmount);
};
game.addChild(betPlus);
// Store for later removal
// Store for later removal
modeButtons.push(title, betMinus, betCustomBtn, betPlus);
// --- Custom Bet Input UI ---
var customBetPrompt = null;
function showCustomBetInput() {
if (customBetPrompt) {
customBetPrompt.destroy();
customBetPrompt = null;
}
customBetPrompt = new Container();
game.addChild(customBetPrompt);
var overlay = customBetPrompt.attachAsset('cardBg', {
width: 600,
height: 400,
color: 0x222244,
shape: 'box',
anchorX: 0.5,
anchorY: 0.5,
x: 2048 / 2,
y: 1200
});
var title = new Text2('Enter Bet Amount', {
size: 70,
fill: "#fff"
});
title.anchor.set(0.5, 0.5);
title.x = 2048 / 2;
title.y = 1050;
customBetPrompt.addChild(title);
var inputValue = '';
var inputText = new Text2('Bet: ', {
size: 60,
fill: "#fff"
});
inputText.anchor.set(0.5, 0.5);
inputText.x = 2048 / 2;
inputText.y = 1200;
customBetPrompt.addChild(inputText);
var errorText = new Text2('', {
size: 40,
fill: 0xFF4444
});
errorText.anchor.set(0.5, 0.5);
errorText.x = 2048 / 2;
errorText.y = 1270;
customBetPrompt.addChild(errorText);
function updateInputDisplay() {
inputText.setText('Bet: ' + inputValue);
errorText.setText('');
}
// Number pad (digits 0-9, C, OK)
var padStartX = 2048 / 2 - 120;
var padStartY = 1350;
var padLabels = [['1', '2', '3'], ['4', '5', '6'], ['7', '8', '9'], ['C', '0', 'OK']];
for (var prow = 0; prow < 4; prow++) {
for (var pcol = 0; pcol < 3; pcol++) {
var plabel = padLabels[prow][pcol];
var pbtn = new GameButton();
pbtn.setText(plabel);
pbtn.btnBg.width = 80;
pbtn.btnBg.height = 80;
pbtn.x = padStartX + pcol * 100;
pbtn.y = padStartY + prow * 100;
for (var t = 0; t < pbtn.children.length; t++) {
if (pbtn.children[t] && typeof pbtn.children[t].setText === "function") {
pbtn.children[t].style = pbtn.children[t].style || {};
pbtn.children[t].style.size = 36;
pbtn.children[t].setText(plabel);
}
}
if (plabel === 'C') pbtn.btnBg.color = 0xffcccc;
if (plabel === 'OK') pbtn.btnBg.color = 0xccffcc;
pbtn.down = function (lbl) {
return function () {
this.flash();
if (lbl === 'C') {
inputValue = '';
updateInputDisplay();
} else if (lbl === 'OK') {
var val = parseInt(inputValue, 10);
if (isNaN(val) || val < minBet || val > maxBet) {
errorText.setText('Enter $' + minBet + ' - $' + maxBet);
return;
}
betAmount = val;
betText.setText('Bet: $' + betAmount);
if (customBetPrompt) {
customBetPrompt.destroy();
customBetPrompt = null;
}
} else if (lbl.length === 1 && inputValue.length < 9 && /^\d$/.test(lbl)) {
if (inputValue === '0') inputValue = '';
inputValue += lbl;
updateInputDisplay();
}
};
}(plabel);
customBetPrompt.addChild(pbtn);
}
}
// Cancel button
var cancelBtn = new GameButton();
cancelBtn.setText('Cancel');
cancelBtn.x = 2048 / 2;
cancelBtn.y = padStartY + 450;
cancelBtn.btnBg.width = 200;
cancelBtn.btnBg.height = 70;
cancelBtn.down = function () {
this.flash();
if (customBetPrompt) {
customBetPrompt.destroy();
customBetPrompt = null;
}
};
customBetPrompt.addChild(cancelBtn);
updateInputDisplay();
}
// Add Instagram handle
var instaHandle = new Text2('@ahmet_db', {
size: 40,
fill: 0xffffff
});
instaHandle.anchor.set(0, 0.5); // Align to the left middle
instaHandle.x = 2048 - 250; // Position slightly more left
instaHandle.y = 130; // Position slightly more up
game.addChild(instaHandle);
// Add Instagram logo
var instaLogo = LK.getAsset('instagramLogo', {
width: 50,
height: 50,
anchorX: 1,
// Align to the right
anchorY: 0.5,
// Align to the middle
x: instaHandle.x - 10,
// Position 10px to the left of the text
y: instaHandle.y
});
game.addChild(instaLogo);
// Add "Open Account" button
var openAccountBtn = new GameButton();
openAccountBtn.setText('Open Account');
openAccountBtn.x = 2048 / 2 + 750; // Position further to the right
openAccountBtn.y = 200; // Position further upwards
openAccountBtn.btnBg.width = 400;
openAccountBtn.btnBg.height = 80;
openAccountBtn.down = function () {
this.flash();
accountMode = 'register'; // Set mode to register
clearAccountInputs(); // Clear any previous input
showAccountPrompt();
};
}
// --- Mode Selection Handler ---
// Password UI state
var roulettePasswordPrompt = null;
var roulettePasswordInput = null;
var roulettePasswordError = null;
function showRoulettePasswordPrompt() {
showTopLeftBackBtn(function () {
if (roulettePasswordPrompt) {
roulettePasswordPrompt.destroy();
roulettePasswordPrompt = null;
}
showModeSelect();
});
// Remove any previous prompt
if (roulettePasswordPrompt) {
roulettePasswordPrompt.destroy();
roulettePasswordPrompt = null;
}
roulettePasswordPrompt = new Container();
game.addChild(roulettePasswordPrompt);
// Background overlay
var overlay = roulettePasswordPrompt.attachAsset('cardBg', {
width: 900,
height: 500,
color: 0x222244,
shape: 'box',
anchorX: 0.5,
anchorY: 0.5,
x: 2048 / 2,
y: 1200
});
// Title
var promptTitle = new Text2('Enter Roulette Password', {
size: 80,
fill: "#fff"
});
promptTitle.anchor.set(0.5, 0.5);
promptTitle.x = 2048 / 2;
promptTitle.y = 1050;
roulettePasswordPrompt.addChild(promptTitle);
// Password input (show as ****)
var passwordValue = '';
roulettePasswordInput = new Text2('Password: ', {
size: 60,
fill: "#fff"
});
roulettePasswordInput.anchor.set(0.5, 0.5);
roulettePasswordInput.x = 2048 / 2;
roulettePasswordInput.y = 1200;
roulettePasswordPrompt.addChild(roulettePasswordInput);
// Error text
roulettePasswordError = new Text2('', {
size: 48,
fill: 0xFF4444
});
roulettePasswordError.anchor.set(0.5, 0.5);
roulettePasswordError.x = 2048 / 2;
roulettePasswordError.y = 1270;
roulettePasswordPrompt.addChild(roulettePasswordError);
// Number pad
var padStartX = 2048 / 2 + 400; // moved even further right
var padStartY = 1320;
var padBtns = [];
function updateInputDisplay() {
var stars = '';
for (var i = 0; i < passwordValue.length; i++) stars += '*';
roulettePasswordInput.setText('Password: ' + stars);
if (roulettePasswordError) roulettePasswordError.setText('');
}
function clearInput() {
passwordValue = '';
updateInputDisplay();
}
function trySubmit() {
if (passwordValue === '1334') {
// Success
if (roulettePasswordPrompt) {
roulettePasswordPrompt.destroy();
roulettePasswordPrompt = null;
}
startRoulette();
} else {
// Error
if (roulettePasswordError) roulettePasswordError.setText('Incorrect password!');
clearInput();
}
}
// Password keypad layout: numbers in phone order
var keypadLabels = [['1', '2', '3'], ['4', '5', '6'], ['7', '8', '9'], ['C', '0', 'OK']];
for (var row = 0; row < 4; row++) {
for (var col = 0; col < 3; col++) {
var label = keypadLabels[row][col];
var btn = new GameButton();
btn.setText(label);
// Make buttons smaller and add more space between them
btn.btnBg.width = 80;
btn.btnBg.height = 80;
btn.x = padStartX + col * 94; // 54px button + 40px gap
btn.y = padStartY + row * 100; // 54px button + 46px gap
// Make the button text larger for visibility
for (var t = 0; t < btn.children.length; t++) {
if (btn.children[t] && typeof btn.children[t].setText === "function") {
btn.children[t].style = btn.children[t].style || {};
btn.children[t].style.size = 36;
btn.children[t].setText(label);
}
}
// Make the button background lighter for better contrast
if (!isNaN(parseInt(label))) {
if (label === '0') {
btn.btnBg.color = 0xeeeeee;
btn.setText(label);
} else {
btn.btnBg.color = 0xffffff;
btn.setText(label);
}
} else if (label === 'C') {
btn.btnBg.color = 0xffcccc;
} else if (label === 'OK') {
btn.btnBg.color = 0xccffcc;
}
btn.down = function (lbl) {
return function () {
this.flash();
if (lbl === 'C') {
clearInput();
} else if (lbl === 'OK') {
trySubmit();
} else if (lbl.length === 1 && passwordValue.length < 8) {
passwordValue += lbl;
updateInputDisplay();
}
};
}(label);
roulettePasswordPrompt.addChild(btn);
padBtns.push(btn);
}
}
updateInputDisplay();
}
function selectMode(modeId) {
currentMode = modeId;
// Remove mode select UI
for (var i = 0; i < modeButtons.length; i++) {
if (modeButtons[i].parent) modeButtons[i].parent.removeChild(modeButtons[i]);
}
modeButtons = [];
// Start selected mode
if (modeId === 'blackjack') {
startBlackjack();
} else if (modeId === 'roulette') {
showRoulettePasswordPrompt();
} else {
showComingSoon(modeId);
}
}
// --- Coming Soon Placeholder ---
function showComingSoon(modeId) {
showTopLeftBackBtn(function () {
if (playArea) playArea.destroy();
playArea = null;
showModeSelect();
});
if (playArea) playArea.destroy();
playArea = new Container();
game.addChild(playArea);
var txt = new Text2(MODES.filter(function (m) {
return m.id === modeId;
})[0].name + '\nComing Soon!', {
size: 100,
fill: "#fff"
});
txt.anchor.set(0.5, 0.5);
txt.x = 2048 / 2;
txt.y = 1200;
playArea.addChild(txt);
// Back button
var backBtn = new GameButton();
backBtn.setText('Back');
backBtn.x = 2048 / 2;
backBtn.y = 1800;
backBtn.down = function () {
playArea.destroy();
playArea = null;
showModeSelect();
};
playArea.addChild(backBtn);
}
// --- Start Blackjack ---
function startBlackjack() {
showTopLeftBackBtn(function () {
if (playArea) playArea.destroy();
playArea = null;
if (blackjack) {
blackjack.destroy();
blackjack = null;
}
showModeSelect();
});
if (playArea) playArea.destroy();
playArea = new Container();
game.addChild(playArea);
// Destroy old blackjack if any
if (blackjack && blackjack.destroy) {
blackjack.destroy();
blackjack = null;
}
blackjack = new BlackjackGame();
playArea.addChild(blackjack);
}
// (removed selectBlackjackSeat, not needed for single seat)
// --- Start Sweet Bonanza ---
function startSweetBonanza() {
if (playArea) playArea.destroy();
playArea = new Container();
game.addChild(playArea);
if (typeof sweetBonanza !== "undefined" && sweetBonanza && sweetBonanza.destroy) {
sweetBonanza.destroy();
}
sweetBonanza = new SweetBonanzaGame();
playArea.addChild(sweetBonanza);
}
// --- Start Roulette ---
function startRoulette() {
showTopLeftBackBtn(function () {
if (playArea) playArea.destroy();
playArea = null;
if (roulette) {
roulette.destroy();
roulette = null;
}
showModeSelect();
});
if (playArea) playArea.destroy();
playArea = new Container();
game.addChild(playArea);
if (typeof roulette !== "undefined" && roulette && roulette.destroy) {
roulette.destroy();
}
roulette = new RouletteGame();
playArea.addChild(roulette);
}
// --- Update Balance ---
function updateBalance() {
balanceText.setText('Balance: $' + playerBalance);
storage.balance = playerBalance;
}
// --- Auto Reward System ---
// Give +2000 every 10 minutes (600,000 ms)
var AUTO_REWARD_AMOUNT = 2000;
var AUTO_REWARD_INTERVAL = 600000; // 10 minutes in ms
var lastRewardTime = storage.lastRewardTime || Date.now();
// --- Auto Reward Counter UI ---
var autoRewardCounterText = new Text2('', {
size: 40,
fill: 0x66FFCC
});
autoRewardCounterText.anchor.set(0.5, 0);
// Place original counter in the center top (for legacy/compat)
autoRewardCounterText.x = 2048 / 2;
autoRewardCounterText.y = 160;
LK.gui.top.addChild(autoRewardCounterText);
// Add countdown timer to the top left
var autoRewardCounterTextLeft = new Text2('', {
size: 40,
fill: 0x66FFCC
});
autoRewardCounterTextLeft.anchor.set(0, 0); // left aligned, top
autoRewardCounterTextLeft.x = 120; // 20px right of reserved area (100px reserved)
autoRewardCounterTextLeft.y = 20; // 20px from top
LK.gui.topLeft.addChild(autoRewardCounterTextLeft);
// --- Quest System ---
// Daily quest pool (at least 8, so 5 can be picked randomly each day)
var QUEST_POOL = [{
id: 'bj_3rounds',
desc: 'Play 3 Blackjack rounds',
goal: 3,
reward: 500
}, {
id: 'roulette_win500',
desc: 'Win $500 in Roulette',
goal: 500,
reward: 1000
}, {
id: 'bj_blackjack_win2',
desc: 'Win 2 Blackjack rounds',
goal: 2,
reward: 600
}, {
id: 'roulette_bet5',
desc: 'Place 5 Roulette bets',
goal: 5,
reward: 400
}, {
id: 'bj_perfect_pair',
desc: 'Get 1 Perfect Pair in Blackjack',
goal: 1,
reward: 1200
}, {
id: 'roulette_number_win',
desc: 'Win on a number bet in Roulette',
goal: 1,
reward: 900
}, {
id: 'bj_double_down',
desc: 'Double Down 2 times in Blackjack',
goal: 2,
reward: 700
}, {
id: 'roulette_red_black',
desc: 'Win 3 times on Red or Black in Roulette',
goal: 3,
reward: 500
}];
// Helper to get a deterministic "random" set of 5 quests per day
function getDailyQuestIds() {
var now = new Date();
var daySeed = now.getFullYear() * 10000 + (now.getMonth() + 1) * 100 + now.getDate();
var ids = [];
var used = [];
for (var i = 0; i < QUEST_POOL.length; i++) used[i] = false;
var count = 0;
var poolLen = QUEST_POOL.length;
var seed = daySeed;
while (ids.length < 5 && count < 20) {
// Simple LCG for deterministic shuffle
seed = (seed * 9301 + 49297) % 233280;
var idx = Math.floor(seed / 233280 * poolLen);
if (!used[idx]) {
ids.push(QUEST_POOL[idx].id);
used[idx] = true;
}
count++;
}
return ids;
}
// Build today's QUESTS array
var QUESTS = [];
var dailyIds = getDailyQuestIds();
for (var i = 0; i < dailyIds.length; i++) {
for (var j = 0; j < QUEST_POOL.length; j++) {
if (QUEST_POOL[j].id === dailyIds[i]) {
// Clone quest object and add progress/complete
QUESTS.push({
id: QUEST_POOL[j].id,
desc: QUEST_POOL[j].desc,
goal: QUEST_POOL[j].goal,
reward: QUEST_POOL[j].reward,
progress: 0,
complete: false
});
break;
}
}
}
// Load quest progress from storage if available and if for today
if (storage.quests && storage.questsDay === new Date().toDateString()) {
for (var i = 0; i < QUESTS.length; i++) {
var q = QUESTS[i];
// Load from flat keys, e.g. quests.key_progress and quests.key_complete
var progressKey = q.id + '_progress';
var completeKey = q.id + '_complete';
if (typeof storage.quests[progressKey] !== "undefined") {
q.progress = storage.quests[progressKey];
}
if (typeof storage.quests[completeKey] !== "undefined") {
q.complete = storage.quests[completeKey];
}
}
} else {
// New day, reset quest progress and save today's date
// Initialize storage.quests as a flat object with only 1-level deep properties
storage.quests = {};
storage.questsDay = new Date().toDateString();
}
function saveQuests() {
var save = {};
for (var i = 0; i < QUESTS.length; i++) {
var q = QUESTS[i];
if (!storage.quests) storage.quests = {};
// Store as flat keys, e.g. quests.key_progress and quests.key_complete
storage.quests[q.id + '_progress'] = q.progress;
storage.quests[q.id + '_complete'] = q.complete;
}
storage.questsDay = new Date().toDateString();
}
// Quest UI (bottom left, separate area)
var questTextNodes = [];
function updateQuestUI() {
// Remove old
for (var i = 0; i < questTextNodes.length; i++) {
if (questTextNodes[i].parent) questTextNodes[i].parent.removeChild(questTextNodes[i]);
questTextNodes[i].destroy();
}
questTextNodes = [];
// Place quests in bottom left, avoid left 100px reserved area
var y = 40; // Padding from bottom
for (var i = 0; i < QUESTS.length; i++) {
var q = QUESTS[i];
var txt = new Text2((q.complete ? '✅ ' : '') + q.desc + ' [' + q.progress + '/' + q.goal + ']' + (q.complete ? ' (Claimed)' : ' Prize: $' + q.reward), {
size: 32,
fill: q.complete ? "#aaffaa" : "#fff"
});
txt.anchor.set(0, 1); // left aligned, bottom
txt.x = 120; // 20px right of reserved area
txt.y = -y; // negative y for bottom alignment in LK.gui.bottomLeft
LK.gui.bottomLeft.addChild(txt);
questTextNodes.push(txt);
y += 38;
}
}
updateQuestUI();
// --- Daily Quest Timer UI (bottom right) ---
var questTimerText = new Text2('', {
size: 38,
fill: 0xFFD700
});
questTimerText.anchor.set(1, 1); // right aligned, bottom
questTimerText.x = -40; // 40px from right edge in LK.gui.bottomRight
questTimerText.y = -40; // 40px from bottom
LK.gui.bottomRight.addChild(questTimerText);
function updateQuestTimer() {
// Calculate time left until midnight
var now = new Date();
var tomorrow = new Date(now.getFullYear(), now.getMonth(), now.getDate() + 1, 0, 0, 0, 0);
var msLeft = tomorrow - now;
if (msLeft < 0) msLeft = 0;
var sec = Math.floor(msLeft / 1000) % 60;
var min = Math.floor(msLeft / 60000) % 60;
var hr = Math.floor(msLeft / 3600000);
var timeStr = (hr < 10 ? '0' : '') + hr + ':' + (min < 10 ? '0' : '') + min + ':' + (sec < 10 ? '0' : '') + sec;
questTimerText.setText('Daily quests reset in: ' + timeStr);
}
LK.setInterval(updateQuestTimer, 1000);
updateQuestTimer();
// Quest logic: call these when player does actions
function questEvent(event, value) {
var updated = false;
for (var i = 0; i < QUESTS.length; i++) {
var q = QUESTS[i];
if (q.complete) continue;
// Blackjack round played
if (event === 'blackjack_round' && q.id === 'bj_3rounds') {
q.progress++;
if (q.progress >= q.goal) {
q.progress = q.goal;
q.complete = true;
playerBalance += q.reward;
updateBalance();
showQuestRewardPopup(q.reward, q.desc);
}
updated = true;
}
// Win 2 Blackjack rounds
if (event === 'blackjack_win' && q.id === 'bj_blackjack_win2') {
q.progress++;
if (q.progress >= q.goal) {
q.progress = q.goal;
q.complete = true;
playerBalance += q.reward;
updateBalance();
showQuestRewardPopup(q.reward, q.desc);
}
updated = true;
}
// Double Down in Blackjack
if (event === 'blackjack_double' && q.id === 'bj_double_down') {
q.progress++;
if (q.progress >= q.goal) {
q.progress = q.goal;
q.complete = true;
playerBalance += q.reward;
updateBalance();
showQuestRewardPopup(q.reward, q.desc);
}
updated = true;
}
// Get Perfect Pair in Blackjack
if (event === 'blackjack_perfect_pair' && q.id === 'bj_perfect_pair') {
q.progress++;
if (q.progress >= q.goal) {
q.progress = q.goal;
q.complete = true;
playerBalance += q.reward;
updateBalance();
showQuestRewardPopup(q.reward, q.desc);
}
updated = true;
}
// Roulette win $500
if (event === 'roulette_win' && q.id === 'roulette_win500') {
q.progress += value;
if (q.progress >= q.goal) {
q.progress = q.goal;
q.complete = true;
playerBalance += q.reward;
updateBalance();
showQuestRewardPopup(q.reward, q.desc);
}
updated = true;
}
// Place 5 Roulette bets
if (event === 'roulette_bet' && q.id === 'roulette_bet5') {
q.progress++;
if (q.progress >= q.goal) {
q.progress = q.goal;
q.complete = true;
playerBalance += q.reward;
updateBalance();
showQuestRewardPopup(q.reward, q.desc);
}
updated = true;
}
// Win on a number bet in Roulette
if (event === 'roulette_number_win' && q.id === 'roulette_number_win') {
q.progress++;
if (q.progress >= q.goal) {
q.progress = q.goal;
q.complete = true;
playerBalance += q.reward;
updateBalance();
showQuestRewardPopup(q.reward, q.desc);
}
updated = true;
}
// Win on Red/Black in Roulette
if (event === 'roulette_red_black_win' && q.id === 'roulette_red_black') {
q.progress++;
if (q.progress >= q.goal) {
q.progress = q.goal;
q.complete = true;
playerBalance += q.reward;
updateBalance();
showQuestRewardPopup(q.reward, q.desc);
}
updated = true;
}
}
if (updated) {
saveQuests();
updateQuestUI();
}
}
function showQuestRewardPopup(amount, desc) {
var popup = new Text2('Quest Complete!\n' + desc + '\n+$' + amount, {
size: 70,
fill: 0xFFD700
});
popup.anchor.set(0.5, 0.5);
popup.x = 2048 / 2;
popup.y = 600;
game.addChild(popup);
tween(popup, {
y: popup.y - 80,
alpha: 0
}, {
duration: 1400,
onFinish: function onFinish() {
popup.destroy();
}
});
}
// Update auto reward counter as before
function updateAutoRewardCounter() {
var now = Date.now();
var msLeft = AUTO_REWARD_INTERVAL - (now - lastRewardTime) % AUTO_REWARD_INTERVAL;
if (msLeft < 0) msLeft = 0;
var sec = Math.floor(msLeft / 1000) % 60;
var min = Math.floor(msLeft / 60000);
var timeStr = (min < 10 ? '0' : '') + min + ':' + (sec < 10 ? '0' : '') + sec;
autoRewardCounterText.setText('Next Reward: +' + AUTO_REWARD_AMOUNT + ' in ' + timeStr);
autoRewardCounterTextLeft.setText('Next reward: ' + timeStr);
}
function checkAutoReward() {
var now = Date.now();
// If more than interval has passed, give reward (handle multiple missed intervals)
var intervals = Math.floor((now - lastRewardTime) / AUTO_REWARD_INTERVAL);
if (intervals > 0) {
var totalReward = intervals * AUTO_REWARD_AMOUNT;
playerBalance += totalReward;
updateBalance();
lastRewardTime += intervals * AUTO_REWARD_INTERVAL;
storage.lastRewardTime = lastRewardTime;
// Optionally show a quick popup for reward
var rewardText = new Text2('Auto Reward: +$' + totalReward, {
size: 70,
fill: 0x66ffcc
});
rewardText.anchor.set(0.5, 0.5);
rewardText.x = 2048 / 2;
rewardText.y = 400;
game.addChild(rewardText);
tween(rewardText, {
y: rewardText.y - 80,
alpha: 0
}, {
duration: 1200,
onFinish: function onFinish() {
rewardText.destroy();
}
});
}
updateAutoRewardCounter();
}
// Check auto reward every 10 seconds, and update counter every second
LK.setInterval(checkAutoReward, 10000);
LK.setInterval(updateAutoRewardCounter, 1000);
updateAutoRewardCounter();
// Check for new day and reset quests if needed
function checkQuestDay() {
var today = new Date().toDateString();
if (storage.questsDay !== today) {
// Force reload of page to reset quests (or you can re-run quest init logic here)
location.reload();
}
}
LK.setInterval(checkQuestDay, 60000); // check every minute
// --- Start Game ---
showModeSelect();
updateBalance();
// --- Touch Handling (for mobile) ---
game.move = function (x, y, obj) {
// No drag in this game
};
game.down = function (x, y, obj) {
// No drag in this game
};
game.up = function (x, y, obj) {
// No drag in this game
};
// --- Game Tick ---
game.update = function () {
// No per-frame logic needed for MVP
// Win/Lose system for all casino modes (except Blackjack, which already has it)
// Placeholder for future slot/other games:
if (currentMode === 'sweet') {
// Example: If playerBalance <= 0, show lose popup
if (playerBalance <= 0) {
LK.showGameOver();
}
// Example: If playerBalance >= 10000, show win popup
if (playerBalance >= 10000) {
LK.showYouWin();
}
}
};
empty card. In-Game asset. 2d. High contrast. No shadows
Metallic button frame, black snake patterns around, red middle of the button, metal gray frame. In-Game asset. 2d. High contrast. No shadows
instagram logo. In-Game asset. No shadows
more shiney , black areas are like night dark and lines are blood red
remove the cards and the other things make left just croupier
make it a blackjack table and make it fit with the fullscreen. In-Game asset. 2d. High contrast. No shadows