/**** * Plugins ****/ var tween = LK.import("@upit/tween.v1"); var storage = LK.import("@upit/storage.v1", { highestScore: 0 }); /**** * Classes ****/ var Button = Container.expand(function (text, width, height, color) { var self = Container.call(this); self.buttonShape = self.attachAsset('button', { anchorX: 0.5, anchorY: 0.5, width: width || 300, height: height || 100, tint: color || 0x2ecc71 }); self.buttonText = new Text2(text, { size: 40, fill: 0xFFFFFF }); self.buttonText.anchor.set(0.5); self.addChild(self.buttonText); self.disable = function () { self.buttonShape.tint = 0x95a5a6; self.interactive = false; }; self.enable = function () { self.buttonShape.tint = color || 0x2ecc71; self.interactive = true; }; // Event handlers self.down = function (x, y, obj) { tween(self, { scaleX: 0.95, scaleY: 0.95 }, { duration: 100 }); }; self.up = function (x, y, obj) { tween(self, { scaleX: 1, scaleY: 1 }, { duration: 100 }); if (self.onPress) { self.onPress(); } }; return self; }); var Card = Container.expand(function (suit, rank) { var self = Container.call(this); self.suit = suit; self.rank = rank; self.isHeld = false; // Get suit symbol self.getSuitSymbol = function () { if (self.suit === 'hearts') { return '♥'; } if (self.suit === 'diamonds') { return '♦'; } if (self.suit === 'clubs') { return '♣'; } if (self.suit === 'spades') { return '♠'; } return ''; }; // Get card color self.getCardColor = function () { if (self.suit === 'hearts' || self.suit === 'diamonds') { return "#ff0000"; } return "#000000"; }; // Get card label self.getCardLabel = function () { return self.rank + self.getSuitSymbol(); }; // Front and back of card self.cardFront = self.attachAsset('cardFront', { anchorX: 0.5, anchorY: 0.5 }); self.cardBack = self.attachAsset('cardBack', { anchorX: 0.5, anchorY: 0.5 }); self.cardBack.visible = false; // Hold indicator self.holdIndicator = self.attachAsset('holdIndicator', { anchorX: 0.5, anchorY: 0.5, y: 130 }); self.holdIndicator.visible = false; // Card text (suit and rank) self.rankText = new Text2(self.getCardLabel(), { size: 58, fill: self.getCardColor() }); self.rankText.anchor.set(0.5); self.rankText.y = -100; self.addChild(self.rankText); // Suit symbol in the center self.suitText = new Text2(self.getSuitSymbol(), { size: 116, fill: self.getCardColor() }); self.suitText.anchor.set(0.5); self.addChild(self.suitText); // Hold text self.holdText = new Text2("HOLD", { size: 32, fill: 0x000000 }); self.holdText.anchor.set(0.5); self.holdText.y = 130; self.addChild(self.holdText); self.holdText.visible = false; // Toggle hold state self.toggleHold = function () { self.isHeld = !self.isHeld; self.holdIndicator.visible = self.isHeld; self.holdText.visible = self.isHeld; }; // Get card value for hand evaluations (1-13) self.getValue = function () { if (self.rank === 'A') { return 14; } if (self.rank === 'K') { return 13; } if (self.rank === 'Q') { return 12; } if (self.rank === 'J') { return 11; } return parseInt(self.rank); }; // Event handlers self.down = function (x, y, obj) { // Scale down slightly on press tween(self, { scaleX: 0.95, scaleY: 0.95 }, { duration: 100 }); }; self.up = function (x, y, obj) { // Scale back to normal tween(self, { scaleX: 1, scaleY: 1 }, { duration: 100 }); self.toggleHold(); // Play sound when toggling hold LK.getSound('holdCard').play(); // Add small bounce animation when card is held if (self.isHeld) { tween(self, { y: self.y - 15 }, { duration: 150, easing: tween.easeOutQuad, onFinish: function onFinish() { tween(self, { y: CARD_START_Y }, { duration: 200, easing: tween.elasticOut }); } }); } }; return self; }); var CashOutButton = Container.expand(function () { var self = Container.call(this); self.buttonShape = self.attachAsset('button', { anchorX: 0.5, anchorY: 0.5, tint: 0xe74c3c // Red color }); self.buttonText = new Text2("CASH OUT", { size: 40, fill: 0xFFFFFF }); self.buttonText.anchor.set(0.5); self.addChild(self.buttonText); // Event handlers self.down = function (x, y, obj) { tween(self, { scaleX: 0.95, scaleY: 0.95 }, { duration: 100 }); }; self.up = function (x, y, obj) { tween(self, { scaleX: 1, scaleY: 1 }, { duration: 100 }); if (self.onPress) { self.onPress(); } }; return self; }); /**** * Initialize Game ****/ var game = new LK.Game({ backgroundColor: 0x2c6e31 }); /**** * Game Code ****/ // Constants var CARD_SPACING = 260; var CARDS_PER_HAND = 5; var CARD_START_Y = 700; var DECK_POSITION_X = 300; var DECK_POSITION_Y = 300; // Game states var STATE_DEAL = "deal"; var STATE_PLAYER_TURN = "playerTurn"; var STATE_FINAL = "final"; // Game variables var deck = []; var playerHand = []; var gameState = STATE_DEAL; var handScore = 0; var handRank = ""; var highestScore = storage.highestScore || 0; var currentBet = 1; // Each bet costs 1 score // Game themes var themes = [{ name: "Classic", tableTint: 0x2c6e31, // Green buttonTint: 0x2ecc71, cardBackTint: 0x0e4d92, // Blue holdTint: 0xf39c12 // Orange }, { name: "Dark", tableTint: 0x2c3e50, // Dark blue buttonTint: 0x3498db, cardBackTint: 0x34495e, holdTint: 0xe74c3c }, { name: "Royal", tableTint: 0x8e44ad, // Purple buttonTint: 0x9b59b6, cardBackTint: 0x2980b9, holdTint: 0xf1c40f }]; var currentTheme = 0; // Start with classic theme // Hand rankings and their scores var handRankings = { "Royal Flush": 250, "Straight Flush": 50, "Four of a Kind": 25, "Full House": 15, "Flush": 12, // Doubled from 6 to 12 "Straight": 8, // Doubled from 4 to 8 "Three of a Kind": 3, "Two Pair": 2, "Jacks or Better": 1, "High Card": 0 }; // Create the table var table = game.addChild(LK.getAsset('table', { anchorX: 0.5, anchorY: 0.5, x: 2048 / 2, y: 2732 / 2 })); // Create scoreboard text var scoreText = new Text2("Score: 0", { size: 50, fill: 0xFFFFFF }); scoreText.anchor.set(0.5, 0); LK.gui.top.addChild(scoreText); scoreText.y = 50; // Create high score text var highScoreText = new Text2("High Score: " + highestScore, { size: 40, fill: 0xFFFFFF }); highScoreText.anchor.set(1, 0); LK.gui.topRight.addChild(highScoreText); highScoreText.x = -30; highScoreText.y = 30; // Create hand rank text var handRankText = new Text2("", { size: 60, fill: 0xFFFFFF }); handRankText.anchor.set(0.5, 0); handRankText.y = 150; LK.gui.top.addChild(handRankText); // Create paytable display var payTableContainer = new Container(); payTableContainer.x = 2048 / 2; payTableContainer.y = 1800; game.addChild(payTableContainer); // Create title for pay table var payTableTitle = new Text2("PAYOUTS", { size: 40, fill: 0xFFFFFF }); payTableTitle.anchor.set(0.5, 0); payTableTitle.y = -280; payTableContainer.addChild(payTableTitle); // Create pay table entries var payTableEntries = [{ hand: "Royal Flush", payout: "250×" }, { hand: "Straight Flush", payout: "50×" }, { hand: "Four of a Kind", payout: "25×" }, { hand: "Full House", payout: "15×" }, { hand: "Flush", payout: "12×" }, { hand: "Straight", payout: "8×" }, { hand: "Three of a Kind", payout: "3×" }, { hand: "Two Pair", payout: "2×" }, { hand: "Pairs of Jacks or Better", payout: "1×" }, { hand: "High Card", payout: "0×" }]; // Initialize references to pay table text objects var payTableTexts = {}; // Create each entry in the pay table for (var i = 0; i < payTableEntries.length; i++) { var entry = payTableEntries[i]; // Hand name var handText = new Text2(entry.hand, { size: 30, fill: 0xFFFFFF, align: 'right' }); handText.anchor.set(1, 0.5); handText.x = -20; handText.y = i * 40 - 220; payTableContainer.addChild(handText); // Payout value var payoutText = new Text2(entry.payout, { size: 30, fill: 0xFFFFFF, align: 'left' }); payoutText.anchor.set(0, 0.5); payoutText.x = 20; payoutText.y = i * 40 - 220; payTableContainer.addChild(payoutText); // Store references to text objects payTableTexts[entry.hand] = { hand: handText, payout: payoutText }; // Ensure text objects have style property initialized handText.style = handText.style || {}; payoutText.style = payoutText.style || {}; } // Function to highlight the current hand in the pay table function highlightPayTableEntry(handName) { // Reset all entries to default color for (var key in payTableTexts) { payTableTexts[key].hand.style.fill = 0xFFFFFF; payTableTexts[key].payout.style.fill = 0xFFFFFF; } // Highlight the matching entry if it exists if (payTableTexts[handName]) { payTableTexts[handName].hand.style.fill = 0xF1C40F; // Yellow highlight payTableTexts[handName].payout.style.fill = 0xF1C40F; // Add a scale animation to the highlighted entry tween.stop(payTableTexts[handName].hand); tween.stop(payTableTexts[handName].payout); tween(payTableTexts[handName].hand, { scaleX: 1.2, scaleY: 1.2 }, { duration: 300, easing: tween.elasticOut }); tween(payTableTexts[handName].payout, { scaleX: 1.2, scaleY: 1.2 }, { duration: 300, easing: tween.elasticOut }); } } // Create draw button var drawButton = new Button("DEAL", 400, 120); drawButton.x = 2048 / 2; drawButton.y = 1300; game.addChild(drawButton); // Create cost indicator text var costIndicator = new Text2("Each draw costs 1 score", { size: 30, fill: 0xFFFFFF }); costIndicator.anchor.set(0.5, 0); costIndicator.x = drawButton.x; costIndicator.y = drawButton.y + 70; game.addChild(costIndicator); // Setup button behavior drawButton.onPress = function () { if (gameState === STATE_DEAL) { startNewGame(); gameState = STATE_PLAYER_TURN; drawButton.buttonText.setText("DRAW"); } else if (gameState === STATE_PLAYER_TURN) { drawRemainingCards(); gameState = STATE_FINAL; drawButton.buttonText.setText("DEAL AGAIN"); } else if (gameState === STATE_FINAL) { resetGame(); gameState = STATE_DEAL; } }; // Initialize deck function createDeck() { var suits = ['hearts', 'diamonds', 'clubs', 'spades']; var ranks = ['2', '3', '4', '5', '6', '7', '8', '9', '10', 'J', 'Q', 'K', 'A']; var newDeck = []; for (var s = 0; s < suits.length; s++) { for (var r = 0; r < ranks.length; r++) { newDeck.push({ suit: suits[s], rank: ranks[r] }); } } return newDeck; } // Shuffle deck function shuffleDeck(deck) { // Play shuffle sound LK.getSound('shuffle').play(); // Regular shuffle first for (var i = deck.length - 1; i > 0; i--) { var j = Math.floor(Math.random() * (i + 1)); var temp = deck[i]; deck[i] = deck[j]; deck[j] = temp; } // Slightly increase chances for flushes and straights var rng = Math.random(); if (rng < 0.25) { // 25% chance to modify the deck for better hands (increased from 15%) if (Math.random() < 0.5) { // Try to create a flush by grouping cards of same suit deck.sort(function (a, b) { // Sort partially by suit, but keep some randomness if (a.suit === b.suit) { return Math.random() - 0.5; } return a.suit.localeCompare(b.suit); }); } else { // Try to create a straight by grouping sequential cards var ranks = ['2', '3', '4', '5', '6', '7', '8', '9', '10', 'J', 'Q', 'K', 'A']; deck.sort(function (a, b) { // Sort partially by rank, but keep some randomness var rankA = ranks.indexOf(a.rank); var rankB = ranks.indexOf(b.rank); if (Math.abs(rankA - rankB) <= 1) { return Math.random() - 0.5; } return rankA - rankB; }); } // Shuffle again but less thoroughly to maintain more of the patterns for (var i = deck.length - 1; i > 15; i--) { var j = Math.floor(Math.random() * (i + 1)); var temp = deck[i]; deck[i] = deck[j]; deck[j] = temp; } } return deck; } // Deal cards to player function dealCards() { // Remove old cards from display for (var i = 0; i < playerHand.length; i++) { if (playerHand[i] && playerHand[i].parent) { playerHand[i].parent.removeChild(playerHand[i]); } } // Clear hand playerHand = []; // Create new hand for (var i = 0; i < CARDS_PER_HAND; i++) { if (deck.length > 0) { var cardData = deck.pop(); var card = new Card(cardData.suit, cardData.rank); // Position card card.x = 2048 / 2 + (i - Math.floor(CARDS_PER_HAND / 2)) * CARD_SPACING; card.y = CARD_START_Y; // Add animation card.alpha = 0; card.y += 50; tween(card, { alpha: 1, y: CARD_START_Y }, { duration: 300, easing: tween.easeOutQuad, delay: i * 100 }); playerHand.push(card); game.addChild(card); // Play sound LK.setTimeout(function () { LK.getSound('cardDeal').play(); }, i * 100); } } } // Start a new game function startNewGame() { // Check if player has enough score to place a bet if (LK.getScore() < currentBet) { // Game over - not enough score to bet LK.showGameOver(); return; } // Deduct bet amount LK.setScore(LK.getScore() - currentBet); updateScore(); deck = createDeck(); shuffleDeck(deck); dealCards(); handRankText.setText(""); handScore = 0; // Reset pay table highlighting highlightPayTableEntry(""); } // Draw new cards to replace non-held cards function drawRemainingCards() { for (var i = 0; i < playerHand.length; i++) { if (!playerHand[i].isHeld && deck.length > 0) { var cardData = deck.pop(); // Store old card for animation var oldCard = playerHand[i]; // Create new card var newCard = new Card(cardData.suit, cardData.rank); newCard.x = oldCard.x; newCard.y = oldCard.y; // Disable card interaction - we're in final state now newCard.interactive = false; // Replace old card game.removeChild(oldCard); game.addChild(newCard); playerHand[i] = newCard; // Animation and sound newCard.alpha = 0; newCard.y += 20; tween(newCard, { alpha: 1, y: CARD_START_Y }, { duration: 200, easing: tween.easeOutQuad, delay: i * 50 }); LK.setTimeout(function () { LK.getSound('cardDeal').play(); }, i * 50); } else { // Disable interaction for held cards too playerHand[i].interactive = false; } } // Evaluate hand after a short delay LK.setTimeout(function () { evaluateHand(); }, 500); } // Reset the game for a new round function resetGame() { // Check if player has enough score to continue if (LK.getScore() <= 0) { // Game over - out of score LK.showGameOver(); return; } // Clear the board for (var i = 0; i < playerHand.length; i++) { if (playerHand[i] && playerHand[i].parent) { tween(playerHand[i], { alpha: 0, y: playerHand[i].y + 50 }, { duration: 300, delay: i * 50, onFinish: function () { if (this && this.parent) { this.parent.removeChild(this); } }.bind(playerHand[i]) }); } } playerHand = []; handRankText.setText(""); // Reset pay table highlighting highlightPayTableEntry(""); } // Evaluate the player's hand function evaluateHand() { var cardValues = playerHand.map(function (card) { return { value: card.getValue(), suit: card.suit }; }); // Sort cards by value (descending) cardValues.sort(function (a, b) { return b.value - a.value; }); // Count occurrences of each value var valueCounts = {}; var suitCounts = {}; for (var i = 0; i < cardValues.length; i++) { var value = cardValues[i].value; var suit = cardValues[i].suit; valueCounts[value] = (valueCounts[value] || 0) + 1; suitCounts[suit] = (suitCounts[suit] || 0) + 1; } // Check for pairs, three of a kind, etc. var pairs = 0; var threeOfAKind = false; var fourOfAKind = false; var hasPairOfJacksOrBetter = false; for (var value in valueCounts) { // Need to convert value from string to number for proper comparison var numValue = parseInt(value); if (valueCounts[value] === 2) { pairs++; if (numValue >= 11) { // Jack or better hasPairOfJacksOrBetter = true; } } else if (valueCounts[value] === 3) { threeOfAKind = true; } else if (valueCounts[value] === 4) { fourOfAKind = true; } } // Check for flush var isFlush = false; for (var suit in suitCounts) { if (suitCounts[suit] === 5) { isFlush = true; break; } } // Check for straight var isStraight = false; if (Object.keys(valueCounts).length === 5) { // Create an array with just the values for easier checking var values = cardValues.map(function (c) { return c.value; }); // Sort values in ascending order values.sort(function (a, b) { return a - b; }); // Check if all cards are in sequence var isSequential = true; for (var i = 0; i < values.length - 1; i++) { if (values[i] + 1 !== values[i + 1]) { isSequential = false; break; } } if (isSequential) { isStraight = true; } // Special case for A-5 straight (where Ace is low) if (values[0] === 2 && values[1] === 3 && values[2] === 4 && values[3] === 5 && values[4] === 14) { isStraight = true; } } // Determine hand rank if (isStraight && isFlush) { if (cardValues[0].value === 14 && cardValues[1].value === 13 && cardValues[2].value === 12 && cardValues[3].value === 11 && cardValues[4].value === 10) { handRank = "Royal Flush"; } else { handRank = "Straight Flush"; } } else if (fourOfAKind) { handRank = "Four of a Kind"; } else if (threeOfAKind && pairs === 1) { handRank = "Full House"; } else if (isFlush) { handRank = "Flush"; } else if (isStraight) { handRank = "Straight"; } else if (threeOfAKind) { handRank = "Three of a Kind"; } else if (pairs === 2) { handRank = "Two Pair"; } else if (hasPairOfJacksOrBetter) { handRank = "Jacks or Better"; } else { handRank = "High Card"; } // Set score handScore = handRankings[handRank]; LK.setScore(LK.getScore() + handScore); // Update high score if needed if (LK.getScore() > highestScore) { highestScore = LK.getScore(); storage.highestScore = highestScore; highScoreText.setText("High Score: " + highestScore); } // Display hand rank handRankText.setText(handRank + " - " + handScore + " points!"); // Update score updateScore(); // Highlight the current hand in the pay table highlightPayTableEntry(handRank); // Play win sound if score is positive if (handScore > 0) { // Animate winning cards for (var i = 0; i < playerHand.length; i++) { // Animate each card tween(playerHand[i], { rotation: Math.PI * 2, // Full rotation y: playerHand[i].y - 30 // Bounce up }, { duration: 800, easing: tween.elasticOut, delay: i * 100, onFinish: function () { // Back to normal position after animation tween(this, { y: CARD_START_Y }, { duration: 300, easing: tween.easeOutQuad }); }.bind(playerHand[i]) }); } // Choose appropriate win sound based on hand value if (handScore >= 25) { // Big wins (Royal Flush, Straight Flush, Four of a Kind) LK.getSound('bigWin').play(); // Add screen flash for big wins LK.effects.flashScreen(0xf1c40f, 500); // Gold/yellow flash } else { // Normal wins var volume = Math.min(0.5 + handScore / 100, 1.0); var winSound = LK.getSound('win'); winSound.volume = volume; winSound.play(); } } } // Update the score display function updateScore() { scoreText.setText("Score: " + LK.getScore()); } // Create theme button var themeButton = new Button("THEME", 200, 80, 0x3498db); themeButton.x = highScoreText.x - 140; themeButton.y = highScoreText.y + 100; game.addChild(themeButton); // Setup theme button behavior themeButton.onPress = function () { // Switch to next theme currentTheme = (currentTheme + 1) % themes.length; applyTheme(themes[currentTheme]); // Create notification text var notification = new Text2("Theme: " + themes[currentTheme].name, { size: 40, fill: 0xFFFFFF }); notification.anchor.set(0.5); notification.x = 2048 / 2; notification.y = 400; game.addChild(notification); // Set initial animation properties notification.alpha = 0; // Animate notification tween(notification, { alpha: 1, y: 350 }, { duration: 300, easing: tween.easeOutQuad, onFinish: function onFinish() { // Fade out after delay LK.setTimeout(function () { tween(notification, { alpha: 0, y: 300 }, { duration: 500, onFinish: function onFinish() { if (notification.parent) { notification.parent.removeChild(notification); } } }); }, 1500); } }); }; // Function to apply theme to game elements function applyTheme(theme) { // Apply to table table.tint = theme.tableTint; // Apply to buttons drawButton.buttonShape.tint = theme.buttonTint; themeButton.buttonShape.tint = theme.buttonTint; // Apply to cards for (var i = 0; i < playerHand.length; i++) { if (playerHand[i]) { playerHand[i].cardBack.tint = theme.cardBackTint; playerHand[i].holdIndicator.tint = theme.holdTint; } } } // Create cash out button var cashOutButton = new CashOutButton(); cashOutButton.x = 2048 / 2; cashOutButton.y = payTableContainer.y + 350; // Position lower below the pay table game.addChild(cashOutButton); // Setup cash out button behavior cashOutButton.onPress = function () { if (LK.getScore() > 0) { // Check if this is a new high score if (LK.getScore() > highestScore) { highestScore = LK.getScore(); storage.highestScore = highestScore; highScoreText.setText("High Score: " + highestScore); } // Show game over with current score LK.showYouWin(); } }; // Initialize the game with 10 score LK.setScore(10); updateScore(); LK.playMusic('bgMusic');
/****
* Plugins
****/
var tween = LK.import("@upit/tween.v1");
var storage = LK.import("@upit/storage.v1", {
highestScore: 0
});
/****
* Classes
****/
var Button = Container.expand(function (text, width, height, color) {
var self = Container.call(this);
self.buttonShape = self.attachAsset('button', {
anchorX: 0.5,
anchorY: 0.5,
width: width || 300,
height: height || 100,
tint: color || 0x2ecc71
});
self.buttonText = new Text2(text, {
size: 40,
fill: 0xFFFFFF
});
self.buttonText.anchor.set(0.5);
self.addChild(self.buttonText);
self.disable = function () {
self.buttonShape.tint = 0x95a5a6;
self.interactive = false;
};
self.enable = function () {
self.buttonShape.tint = color || 0x2ecc71;
self.interactive = true;
};
// Event handlers
self.down = function (x, y, obj) {
tween(self, {
scaleX: 0.95,
scaleY: 0.95
}, {
duration: 100
});
};
self.up = function (x, y, obj) {
tween(self, {
scaleX: 1,
scaleY: 1
}, {
duration: 100
});
if (self.onPress) {
self.onPress();
}
};
return self;
});
var Card = Container.expand(function (suit, rank) {
var self = Container.call(this);
self.suit = suit;
self.rank = rank;
self.isHeld = false;
// Get suit symbol
self.getSuitSymbol = function () {
if (self.suit === 'hearts') {
return '♥';
}
if (self.suit === 'diamonds') {
return '♦';
}
if (self.suit === 'clubs') {
return '♣';
}
if (self.suit === 'spades') {
return '♠';
}
return '';
};
// Get card color
self.getCardColor = function () {
if (self.suit === 'hearts' || self.suit === 'diamonds') {
return "#ff0000";
}
return "#000000";
};
// Get card label
self.getCardLabel = function () {
return self.rank + self.getSuitSymbol();
};
// Front and back of card
self.cardFront = self.attachAsset('cardFront', {
anchorX: 0.5,
anchorY: 0.5
});
self.cardBack = self.attachAsset('cardBack', {
anchorX: 0.5,
anchorY: 0.5
});
self.cardBack.visible = false;
// Hold indicator
self.holdIndicator = self.attachAsset('holdIndicator', {
anchorX: 0.5,
anchorY: 0.5,
y: 130
});
self.holdIndicator.visible = false;
// Card text (suit and rank)
self.rankText = new Text2(self.getCardLabel(), {
size: 58,
fill: self.getCardColor()
});
self.rankText.anchor.set(0.5);
self.rankText.y = -100;
self.addChild(self.rankText);
// Suit symbol in the center
self.suitText = new Text2(self.getSuitSymbol(), {
size: 116,
fill: self.getCardColor()
});
self.suitText.anchor.set(0.5);
self.addChild(self.suitText);
// Hold text
self.holdText = new Text2("HOLD", {
size: 32,
fill: 0x000000
});
self.holdText.anchor.set(0.5);
self.holdText.y = 130;
self.addChild(self.holdText);
self.holdText.visible = false;
// Toggle hold state
self.toggleHold = function () {
self.isHeld = !self.isHeld;
self.holdIndicator.visible = self.isHeld;
self.holdText.visible = self.isHeld;
};
// Get card value for hand evaluations (1-13)
self.getValue = function () {
if (self.rank === 'A') {
return 14;
}
if (self.rank === 'K') {
return 13;
}
if (self.rank === 'Q') {
return 12;
}
if (self.rank === 'J') {
return 11;
}
return parseInt(self.rank);
};
// Event handlers
self.down = function (x, y, obj) {
// Scale down slightly on press
tween(self, {
scaleX: 0.95,
scaleY: 0.95
}, {
duration: 100
});
};
self.up = function (x, y, obj) {
// Scale back to normal
tween(self, {
scaleX: 1,
scaleY: 1
}, {
duration: 100
});
self.toggleHold();
// Play sound when toggling hold
LK.getSound('holdCard').play();
// Add small bounce animation when card is held
if (self.isHeld) {
tween(self, {
y: self.y - 15
}, {
duration: 150,
easing: tween.easeOutQuad,
onFinish: function onFinish() {
tween(self, {
y: CARD_START_Y
}, {
duration: 200,
easing: tween.elasticOut
});
}
});
}
};
return self;
});
var CashOutButton = Container.expand(function () {
var self = Container.call(this);
self.buttonShape = self.attachAsset('button', {
anchorX: 0.5,
anchorY: 0.5,
tint: 0xe74c3c // Red color
});
self.buttonText = new Text2("CASH OUT", {
size: 40,
fill: 0xFFFFFF
});
self.buttonText.anchor.set(0.5);
self.addChild(self.buttonText);
// Event handlers
self.down = function (x, y, obj) {
tween(self, {
scaleX: 0.95,
scaleY: 0.95
}, {
duration: 100
});
};
self.up = function (x, y, obj) {
tween(self, {
scaleX: 1,
scaleY: 1
}, {
duration: 100
});
if (self.onPress) {
self.onPress();
}
};
return self;
});
/****
* Initialize Game
****/
var game = new LK.Game({
backgroundColor: 0x2c6e31
});
/****
* Game Code
****/
// Constants
var CARD_SPACING = 260;
var CARDS_PER_HAND = 5;
var CARD_START_Y = 700;
var DECK_POSITION_X = 300;
var DECK_POSITION_Y = 300;
// Game states
var STATE_DEAL = "deal";
var STATE_PLAYER_TURN = "playerTurn";
var STATE_FINAL = "final";
// Game variables
var deck = [];
var playerHand = [];
var gameState = STATE_DEAL;
var handScore = 0;
var handRank = "";
var highestScore = storage.highestScore || 0;
var currentBet = 1; // Each bet costs 1 score
// Game themes
var themes = [{
name: "Classic",
tableTint: 0x2c6e31,
// Green
buttonTint: 0x2ecc71,
cardBackTint: 0x0e4d92,
// Blue
holdTint: 0xf39c12 // Orange
}, {
name: "Dark",
tableTint: 0x2c3e50,
// Dark blue
buttonTint: 0x3498db,
cardBackTint: 0x34495e,
holdTint: 0xe74c3c
}, {
name: "Royal",
tableTint: 0x8e44ad,
// Purple
buttonTint: 0x9b59b6,
cardBackTint: 0x2980b9,
holdTint: 0xf1c40f
}];
var currentTheme = 0; // Start with classic theme
// Hand rankings and their scores
var handRankings = {
"Royal Flush": 250,
"Straight Flush": 50,
"Four of a Kind": 25,
"Full House": 15,
"Flush": 12,
// Doubled from 6 to 12
"Straight": 8,
// Doubled from 4 to 8
"Three of a Kind": 3,
"Two Pair": 2,
"Jacks or Better": 1,
"High Card": 0
};
// Create the table
var table = game.addChild(LK.getAsset('table', {
anchorX: 0.5,
anchorY: 0.5,
x: 2048 / 2,
y: 2732 / 2
}));
// Create scoreboard text
var scoreText = new Text2("Score: 0", {
size: 50,
fill: 0xFFFFFF
});
scoreText.anchor.set(0.5, 0);
LK.gui.top.addChild(scoreText);
scoreText.y = 50;
// Create high score text
var highScoreText = new Text2("High Score: " + highestScore, {
size: 40,
fill: 0xFFFFFF
});
highScoreText.anchor.set(1, 0);
LK.gui.topRight.addChild(highScoreText);
highScoreText.x = -30;
highScoreText.y = 30;
// Create hand rank text
var handRankText = new Text2("", {
size: 60,
fill: 0xFFFFFF
});
handRankText.anchor.set(0.5, 0);
handRankText.y = 150;
LK.gui.top.addChild(handRankText);
// Create paytable display
var payTableContainer = new Container();
payTableContainer.x = 2048 / 2;
payTableContainer.y = 1800;
game.addChild(payTableContainer);
// Create title for pay table
var payTableTitle = new Text2("PAYOUTS", {
size: 40,
fill: 0xFFFFFF
});
payTableTitle.anchor.set(0.5, 0);
payTableTitle.y = -280;
payTableContainer.addChild(payTableTitle);
// Create pay table entries
var payTableEntries = [{
hand: "Royal Flush",
payout: "250×"
}, {
hand: "Straight Flush",
payout: "50×"
}, {
hand: "Four of a Kind",
payout: "25×"
}, {
hand: "Full House",
payout: "15×"
}, {
hand: "Flush",
payout: "12×"
}, {
hand: "Straight",
payout: "8×"
}, {
hand: "Three of a Kind",
payout: "3×"
}, {
hand: "Two Pair",
payout: "2×"
}, {
hand: "Pairs of Jacks or Better",
payout: "1×"
}, {
hand: "High Card",
payout: "0×"
}];
// Initialize references to pay table text objects
var payTableTexts = {};
// Create each entry in the pay table
for (var i = 0; i < payTableEntries.length; i++) {
var entry = payTableEntries[i];
// Hand name
var handText = new Text2(entry.hand, {
size: 30,
fill: 0xFFFFFF,
align: 'right'
});
handText.anchor.set(1, 0.5);
handText.x = -20;
handText.y = i * 40 - 220;
payTableContainer.addChild(handText);
// Payout value
var payoutText = new Text2(entry.payout, {
size: 30,
fill: 0xFFFFFF,
align: 'left'
});
payoutText.anchor.set(0, 0.5);
payoutText.x = 20;
payoutText.y = i * 40 - 220;
payTableContainer.addChild(payoutText);
// Store references to text objects
payTableTexts[entry.hand] = {
hand: handText,
payout: payoutText
};
// Ensure text objects have style property initialized
handText.style = handText.style || {};
payoutText.style = payoutText.style || {};
}
// Function to highlight the current hand in the pay table
function highlightPayTableEntry(handName) {
// Reset all entries to default color
for (var key in payTableTexts) {
payTableTexts[key].hand.style.fill = 0xFFFFFF;
payTableTexts[key].payout.style.fill = 0xFFFFFF;
}
// Highlight the matching entry if it exists
if (payTableTexts[handName]) {
payTableTexts[handName].hand.style.fill = 0xF1C40F; // Yellow highlight
payTableTexts[handName].payout.style.fill = 0xF1C40F;
// Add a scale animation to the highlighted entry
tween.stop(payTableTexts[handName].hand);
tween.stop(payTableTexts[handName].payout);
tween(payTableTexts[handName].hand, {
scaleX: 1.2,
scaleY: 1.2
}, {
duration: 300,
easing: tween.elasticOut
});
tween(payTableTexts[handName].payout, {
scaleX: 1.2,
scaleY: 1.2
}, {
duration: 300,
easing: tween.elasticOut
});
}
}
// Create draw button
var drawButton = new Button("DEAL", 400, 120);
drawButton.x = 2048 / 2;
drawButton.y = 1300;
game.addChild(drawButton);
// Create cost indicator text
var costIndicator = new Text2("Each draw costs 1 score", {
size: 30,
fill: 0xFFFFFF
});
costIndicator.anchor.set(0.5, 0);
costIndicator.x = drawButton.x;
costIndicator.y = drawButton.y + 70;
game.addChild(costIndicator);
// Setup button behavior
drawButton.onPress = function () {
if (gameState === STATE_DEAL) {
startNewGame();
gameState = STATE_PLAYER_TURN;
drawButton.buttonText.setText("DRAW");
} else if (gameState === STATE_PLAYER_TURN) {
drawRemainingCards();
gameState = STATE_FINAL;
drawButton.buttonText.setText("DEAL AGAIN");
} else if (gameState === STATE_FINAL) {
resetGame();
gameState = STATE_DEAL;
}
};
// Initialize deck
function createDeck() {
var suits = ['hearts', 'diamonds', 'clubs', 'spades'];
var ranks = ['2', '3', '4', '5', '6', '7', '8', '9', '10', 'J', 'Q', 'K', 'A'];
var newDeck = [];
for (var s = 0; s < suits.length; s++) {
for (var r = 0; r < ranks.length; r++) {
newDeck.push({
suit: suits[s],
rank: ranks[r]
});
}
}
return newDeck;
}
// Shuffle deck
function shuffleDeck(deck) {
// Play shuffle sound
LK.getSound('shuffle').play();
// Regular shuffle first
for (var i = deck.length - 1; i > 0; i--) {
var j = Math.floor(Math.random() * (i + 1));
var temp = deck[i];
deck[i] = deck[j];
deck[j] = temp;
}
// Slightly increase chances for flushes and straights
var rng = Math.random();
if (rng < 0.25) {
// 25% chance to modify the deck for better hands (increased from 15%)
if (Math.random() < 0.5) {
// Try to create a flush by grouping cards of same suit
deck.sort(function (a, b) {
// Sort partially by suit, but keep some randomness
if (a.suit === b.suit) {
return Math.random() - 0.5;
}
return a.suit.localeCompare(b.suit);
});
} else {
// Try to create a straight by grouping sequential cards
var ranks = ['2', '3', '4', '5', '6', '7', '8', '9', '10', 'J', 'Q', 'K', 'A'];
deck.sort(function (a, b) {
// Sort partially by rank, but keep some randomness
var rankA = ranks.indexOf(a.rank);
var rankB = ranks.indexOf(b.rank);
if (Math.abs(rankA - rankB) <= 1) {
return Math.random() - 0.5;
}
return rankA - rankB;
});
}
// Shuffle again but less thoroughly to maintain more of the patterns
for (var i = deck.length - 1; i > 15; i--) {
var j = Math.floor(Math.random() * (i + 1));
var temp = deck[i];
deck[i] = deck[j];
deck[j] = temp;
}
}
return deck;
}
// Deal cards to player
function dealCards() {
// Remove old cards from display
for (var i = 0; i < playerHand.length; i++) {
if (playerHand[i] && playerHand[i].parent) {
playerHand[i].parent.removeChild(playerHand[i]);
}
}
// Clear hand
playerHand = [];
// Create new hand
for (var i = 0; i < CARDS_PER_HAND; i++) {
if (deck.length > 0) {
var cardData = deck.pop();
var card = new Card(cardData.suit, cardData.rank);
// Position card
card.x = 2048 / 2 + (i - Math.floor(CARDS_PER_HAND / 2)) * CARD_SPACING;
card.y = CARD_START_Y;
// Add animation
card.alpha = 0;
card.y += 50;
tween(card, {
alpha: 1,
y: CARD_START_Y
}, {
duration: 300,
easing: tween.easeOutQuad,
delay: i * 100
});
playerHand.push(card);
game.addChild(card);
// Play sound
LK.setTimeout(function () {
LK.getSound('cardDeal').play();
}, i * 100);
}
}
}
// Start a new game
function startNewGame() {
// Check if player has enough score to place a bet
if (LK.getScore() < currentBet) {
// Game over - not enough score to bet
LK.showGameOver();
return;
}
// Deduct bet amount
LK.setScore(LK.getScore() - currentBet);
updateScore();
deck = createDeck();
shuffleDeck(deck);
dealCards();
handRankText.setText("");
handScore = 0;
// Reset pay table highlighting
highlightPayTableEntry("");
}
// Draw new cards to replace non-held cards
function drawRemainingCards() {
for (var i = 0; i < playerHand.length; i++) {
if (!playerHand[i].isHeld && deck.length > 0) {
var cardData = deck.pop();
// Store old card for animation
var oldCard = playerHand[i];
// Create new card
var newCard = new Card(cardData.suit, cardData.rank);
newCard.x = oldCard.x;
newCard.y = oldCard.y;
// Disable card interaction - we're in final state now
newCard.interactive = false;
// Replace old card
game.removeChild(oldCard);
game.addChild(newCard);
playerHand[i] = newCard;
// Animation and sound
newCard.alpha = 0;
newCard.y += 20;
tween(newCard, {
alpha: 1,
y: CARD_START_Y
}, {
duration: 200,
easing: tween.easeOutQuad,
delay: i * 50
});
LK.setTimeout(function () {
LK.getSound('cardDeal').play();
}, i * 50);
} else {
// Disable interaction for held cards too
playerHand[i].interactive = false;
}
}
// Evaluate hand after a short delay
LK.setTimeout(function () {
evaluateHand();
}, 500);
}
// Reset the game for a new round
function resetGame() {
// Check if player has enough score to continue
if (LK.getScore() <= 0) {
// Game over - out of score
LK.showGameOver();
return;
}
// Clear the board
for (var i = 0; i < playerHand.length; i++) {
if (playerHand[i] && playerHand[i].parent) {
tween(playerHand[i], {
alpha: 0,
y: playerHand[i].y + 50
}, {
duration: 300,
delay: i * 50,
onFinish: function () {
if (this && this.parent) {
this.parent.removeChild(this);
}
}.bind(playerHand[i])
});
}
}
playerHand = [];
handRankText.setText("");
// Reset pay table highlighting
highlightPayTableEntry("");
}
// Evaluate the player's hand
function evaluateHand() {
var cardValues = playerHand.map(function (card) {
return {
value: card.getValue(),
suit: card.suit
};
});
// Sort cards by value (descending)
cardValues.sort(function (a, b) {
return b.value - a.value;
});
// Count occurrences of each value
var valueCounts = {};
var suitCounts = {};
for (var i = 0; i < cardValues.length; i++) {
var value = cardValues[i].value;
var suit = cardValues[i].suit;
valueCounts[value] = (valueCounts[value] || 0) + 1;
suitCounts[suit] = (suitCounts[suit] || 0) + 1;
}
// Check for pairs, three of a kind, etc.
var pairs = 0;
var threeOfAKind = false;
var fourOfAKind = false;
var hasPairOfJacksOrBetter = false;
for (var value in valueCounts) {
// Need to convert value from string to number for proper comparison
var numValue = parseInt(value);
if (valueCounts[value] === 2) {
pairs++;
if (numValue >= 11) {
// Jack or better
hasPairOfJacksOrBetter = true;
}
} else if (valueCounts[value] === 3) {
threeOfAKind = true;
} else if (valueCounts[value] === 4) {
fourOfAKind = true;
}
}
// Check for flush
var isFlush = false;
for (var suit in suitCounts) {
if (suitCounts[suit] === 5) {
isFlush = true;
break;
}
}
// Check for straight
var isStraight = false;
if (Object.keys(valueCounts).length === 5) {
// Create an array with just the values for easier checking
var values = cardValues.map(function (c) {
return c.value;
});
// Sort values in ascending order
values.sort(function (a, b) {
return a - b;
});
// Check if all cards are in sequence
var isSequential = true;
for (var i = 0; i < values.length - 1; i++) {
if (values[i] + 1 !== values[i + 1]) {
isSequential = false;
break;
}
}
if (isSequential) {
isStraight = true;
}
// Special case for A-5 straight (where Ace is low)
if (values[0] === 2 && values[1] === 3 && values[2] === 4 && values[3] === 5 && values[4] === 14) {
isStraight = true;
}
}
// Determine hand rank
if (isStraight && isFlush) {
if (cardValues[0].value === 14 && cardValues[1].value === 13 && cardValues[2].value === 12 && cardValues[3].value === 11 && cardValues[4].value === 10) {
handRank = "Royal Flush";
} else {
handRank = "Straight Flush";
}
} else if (fourOfAKind) {
handRank = "Four of a Kind";
} else if (threeOfAKind && pairs === 1) {
handRank = "Full House";
} else if (isFlush) {
handRank = "Flush";
} else if (isStraight) {
handRank = "Straight";
} else if (threeOfAKind) {
handRank = "Three of a Kind";
} else if (pairs === 2) {
handRank = "Two Pair";
} else if (hasPairOfJacksOrBetter) {
handRank = "Jacks or Better";
} else {
handRank = "High Card";
}
// Set score
handScore = handRankings[handRank];
LK.setScore(LK.getScore() + handScore);
// Update high score if needed
if (LK.getScore() > highestScore) {
highestScore = LK.getScore();
storage.highestScore = highestScore;
highScoreText.setText("High Score: " + highestScore);
}
// Display hand rank
handRankText.setText(handRank + " - " + handScore + " points!");
// Update score
updateScore();
// Highlight the current hand in the pay table
highlightPayTableEntry(handRank);
// Play win sound if score is positive
if (handScore > 0) {
// Animate winning cards
for (var i = 0; i < playerHand.length; i++) {
// Animate each card
tween(playerHand[i], {
rotation: Math.PI * 2,
// Full rotation
y: playerHand[i].y - 30 // Bounce up
}, {
duration: 800,
easing: tween.elasticOut,
delay: i * 100,
onFinish: function () {
// Back to normal position after animation
tween(this, {
y: CARD_START_Y
}, {
duration: 300,
easing: tween.easeOutQuad
});
}.bind(playerHand[i])
});
}
// Choose appropriate win sound based on hand value
if (handScore >= 25) {
// Big wins (Royal Flush, Straight Flush, Four of a Kind)
LK.getSound('bigWin').play();
// Add screen flash for big wins
LK.effects.flashScreen(0xf1c40f, 500); // Gold/yellow flash
} else {
// Normal wins
var volume = Math.min(0.5 + handScore / 100, 1.0);
var winSound = LK.getSound('win');
winSound.volume = volume;
winSound.play();
}
}
}
// Update the score display
function updateScore() {
scoreText.setText("Score: " + LK.getScore());
}
// Create theme button
var themeButton = new Button("THEME", 200, 80, 0x3498db);
themeButton.x = highScoreText.x - 140;
themeButton.y = highScoreText.y + 100;
game.addChild(themeButton);
// Setup theme button behavior
themeButton.onPress = function () {
// Switch to next theme
currentTheme = (currentTheme + 1) % themes.length;
applyTheme(themes[currentTheme]);
// Create notification text
var notification = new Text2("Theme: " + themes[currentTheme].name, {
size: 40,
fill: 0xFFFFFF
});
notification.anchor.set(0.5);
notification.x = 2048 / 2;
notification.y = 400;
game.addChild(notification);
// Set initial animation properties
notification.alpha = 0;
// Animate notification
tween(notification, {
alpha: 1,
y: 350
}, {
duration: 300,
easing: tween.easeOutQuad,
onFinish: function onFinish() {
// Fade out after delay
LK.setTimeout(function () {
tween(notification, {
alpha: 0,
y: 300
}, {
duration: 500,
onFinish: function onFinish() {
if (notification.parent) {
notification.parent.removeChild(notification);
}
}
});
}, 1500);
}
});
};
// Function to apply theme to game elements
function applyTheme(theme) {
// Apply to table
table.tint = theme.tableTint;
// Apply to buttons
drawButton.buttonShape.tint = theme.buttonTint;
themeButton.buttonShape.tint = theme.buttonTint;
// Apply to cards
for (var i = 0; i < playerHand.length; i++) {
if (playerHand[i]) {
playerHand[i].cardBack.tint = theme.cardBackTint;
playerHand[i].holdIndicator.tint = theme.holdTint;
}
}
}
// Create cash out button
var cashOutButton = new CashOutButton();
cashOutButton.x = 2048 / 2;
cashOutButton.y = payTableContainer.y + 350; // Position lower below the pay table
game.addChild(cashOutButton);
// Setup cash out button behavior
cashOutButton.onPress = function () {
if (LK.getScore() > 0) {
// Check if this is a new high score
if (LK.getScore() > highestScore) {
highestScore = LK.getScore();
storage.highestScore = highestScore;
highScoreText.setText("High Score: " + highestScore);
}
// Show game over with current score
LK.showYouWin();
}
};
// Initialize the game with 10 score
LK.setScore(10);
updateScore();
LK.playMusic('bgMusic');