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