User prompt
increase the probability of the per being bored and asking to play
User prompt
Set to, 2 out of 3 times when the player clicks the playitem action button, it should play the memory game
User prompt
Reset the pet level to 1 when the player clicks reset game data
Code edit (1 edits merged)
Please save this source code
User prompt
when the poop spawns, the clean button must be active, canClean must be true
User prompt
the thank you speech bubble is not hiding after 3 seconds
User prompt
hide every speech bubble after 3 seconds
User prompt
hide every every speech buble after 3 seconds, except the 4 main ones, that says the pet is hungry, bored, need cheer or to clean
Code edit (1 edits merged)
Please save this source code
User prompt
Please fix the bug: 'TypeError: game.scheduleNextNeed is not a function' in or related to this line: 'game.scheduleNextNeed();' Line Number: 1945
Code edit (3 edits merged)
Please save this source code
User prompt
make the speech buble desapear after 3 seconds after the player completed that need's action
User prompt
the needs are not appearing each 15 to 30 seconds.they are appearing instantly after the other is finished
Code edit (1 edits merged)
Please save this source code
User prompt
change the time to appear each need from 15~30 seconds
User prompt
Add a new need to the pet, the need for cheer/ to pet
Code edit (1 edits merged)
Please save this source code
User prompt
change the time to appear each need from 5~10 seconds to 10~15 seconds
User prompt
whenever the poop appears and the clean speech buble appears set the canCleanPet to true and make the player be able to perform the clean pet by pressing the clean pet action button
User prompt
set to always that canFeedPet is true to the feedPet action button to function, that means that the pet is hungry and the player has to feed them
User prompt
Set the memory game to not appear always when the play action button is pressed, it should be an ocasional event, that gives extra xp
User prompt
Please fix the bug: 'ReferenceError: timeToBored is not defined' in or related to this line: 'boredTimer = LK.setTimeout(function () {' Line Number: 2000
Code edit (1 edits merged)
Please save this source code
/**** * Plugins ****/ var tween = LK.import("@upit/tween.v1"); var storage = LK.import("@upit/storage.v1", { petLevel: 1, petXp: 0, lastFed: 0, lastCleaned: 0, lastPlayed: 0, petName: "undefined", petType: "Fluffy" }); /**** * Classes ****/ var ActionButton = Container.expand(function (actionType, position) { var self = Container.call(this); var buttonShape; if (actionType === 'feed') { buttonShape = self.attachAsset('foodItem', { anchorX: 0.5, anchorY: 0.5 }); } else if (actionType === 'clean') { buttonShape = self.attachAsset('cleaningItem', { anchorX: 0.5, anchorY: 0.5 }); } else if (actionType === 'play') { buttonShape = self.attachAsset('playItem', { anchorX: 0.5, anchorY: 0.5 }); } self.buttonType = actionType; self.interactive = true; self.down = function (x, y, obj) { tween(buttonShape, { scaleX: 0.8, scaleY: 0.8 }, { duration: 100 }); }; self.up = function (x, y, obj) { tween(buttonShape, { scaleX: 1, scaleY: 1 }, { duration: 100, onFinish: function onFinish() { if (self.buttonType === 'feed') { performFeedAction(); } else if (self.buttonType === 'clean') { performCleanAction(); } else if (self.buttonType === 'play') { performPlayAction(); } } }); }; return self; }); var BubbleSpeech = Container.expand(function (text) { var self = Container.call(this); // Create the bubble background var bubbleBackground = LK.getAsset('bubble_speech', { anchorX: 0.5, anchorY: 0.5, width: 600, height: 600, tint: 0xFFFFFF }); // Round the corners by scaling bubbleBackground.scale.set(1); self.addChild(bubbleBackground); // Add text to bubble var bubbleText = new Text2(text || "", { size: 80, fill: 0x000000, align: "center", // You can set alignment to "left", "center", or "right" wordWrap: true, wordWrapWidth: 800 // Set this to control where text will wra }); bubbleText.anchor.set(0.5, 0.5); self.addChild(bubbleText); // Public methods self.setText = function (newText) { bubbleText.setText(newText); }; // Show with animation self.show = function (duration) { self.alpha = 0; self.scale.set(0.5); tween(self, { alpha: 1, scaleX: 1, scaleY: 1 }, { duration: duration || 300, easing: tween.easeOutBack }); }; // Hide with animation self.hide = function (duration, callback) { tween(self, { alpha: 0, scaleX: 0.5, scaleY: 0.5 }, { duration: duration || 300, easing: tween.easeInBack, onFinish: function onFinish() { if (callback) { callback(); } } }); }; return self; }); var CharacterSelect = Container.expand(function () { var self = Container.call(this); // Background image var background = self.attachAsset('menu_background', { anchorX: 0.5, anchorY: 0.5 }); background.x = 2048 / 2; background.y = 2732 / 2; // Title text var titleText = new Text2("Choose Your Pet", { size: 100, fill: 0xFFFFFF }); titleText.anchor.set(0.5, 0.5); titleText.x = 2048 / 2; titleText.y = 500; self.addChild(titleText); // Create character options var character1 = self.attachAsset('pet_select_1', { anchorX: 0.5, anchorY: 0.5, x: 2048 / 3, y: 2732 / 2 }); character1.interactive = true; var character2 = self.attachAsset('pet_select_2', { anchorX: 0.5, anchorY: 0.5, x: 2048 * 2 / 3, y: 2732 / 2 }); character2.interactive = true; // Character 1 label var label1 = new Text2("Fluffy", { size: 70, fill: 0xFFFFFF }); label1.anchor.set(0.5, 0.5); label1.x = character1.x; label1.y = character1.y + 350; self.addChild(label1); // Character 2 label var label2 = new Text2("Puffy", { size: 70, fill: 0xFFFFFF }); label2.anchor.set(0.5, 0.5); label2.x = character2.x; label2.y = character2.y + 350; self.addChild(label2); // Button animations and interaction character1.down = function (x, y, obj) { tween(character1, { scaleX: 0.95, scaleY: 0.95 }, { duration: 100 }); }; character1.up = function (x, y, obj) { tween(character1, { scaleX: 1, scaleY: 1 }, { duration: 100, onFinish: function onFinish() { if (self.onSelectCharacter) { storage.petType = 'Fluffy'; storage.petXp = 0; storage.petLevel = 1; self.onSelectCharacter('Fluffy'); } } }); }; character2.down = function (x, y, obj) { tween(character2, { scaleX: 0.95, scaleY: 0.95 }, { duration: 100 }); }; character2.up = function (x, y, obj) { tween(character2, { scaleX: 1, scaleY: 1 }, { duration: 100, onFinish: function onFinish() { if (self.onSelectCharacter) { storage.petType = 'Puffy'; storage.petXp = 0; storage.petLevel = 1; self.onSelectCharacter('Puffy'); } } }); }; return self; }); var MainMenu = Container.expand(function () { var self = Container.call(this); // Background image var background = self.attachAsset('menu_background', { anchorX: 0.5, anchorY: 0.5 }); background.x = 2048 / 2; background.y = 2732 / 2; // Game logo var gameLogo = self.attachAsset('game_logo', { anchorX: 0.5, anchorY: 0.5 }); gameLogo.x = 2048 / 2; gameLogo.y = 800; // Play button image var playButton = self.attachAsset('play_button', { anchorX: 0.5, anchorY: 0.5 }); playButton.x = 2048 / 2; playButton.y = 2732 / 2 + 200; playButton.interactive = true; // Reset button var resetButton = new Text2("Reset Game", { size: 60, fill: 0xFFFFFF }); resetButton.anchor.set(0.5, 0.5); resetButton.x = 2048 / 2; resetButton.y = 2732 / 2 + 400; resetButton.interactive = true; self.addChild(resetButton); // Button animations and interaction playButton.down = function (x, y, obj) { tween(playButton, { scaleX: 0.95, scaleY: 0.95 }, { duration: 100 }); }; playButton.up = function (x, y, obj) { tween(playButton, { scaleX: 1, scaleY: 1 }, { duration: 100, onFinish: function onFinish() { if (self.onStartGame) { self.onStartGame(); } } }); }; // Reset button interactions resetButton.down = function (x, y, obj) { tween(resetButton, { scaleX: 0.95, scaleY: 0.95 }, { duration: 100 }); }; resetButton.up = function (x, y, obj) { tween(resetButton, { scaleX: 1, scaleY: 1 }, { duration: 100, onFinish: function onFinish() { if (self.onResetGame) { self.onResetGame(); } } }); }; // Add some animation to the logo function animateLogo() { tween(gameLogo, { y: gameLogo.y - 15 }, { duration: 1500, easing: tween.easeInOut, onFinish: function onFinish() { tween(gameLogo, { y: gameLogo.y + 15 }, { duration: 1500, easing: tween.easeInOut, onFinish: animateLogo }); } }); } // Start the animation animateLogo(); return self; }); var MemoryCard = Container.expand(function (cardValue, cardBack) { var self = Container.call(this); self.value = cardValue; // Card match value self.revealed = false; // Is card face up self.matched = false; // Is card matched // Create card front (colored shape) self.front = LK.getAsset('memory_card_' + cardValue, { anchorX: 0.5, anchorY: 0.5 }); self.front.visible = false; self.addChild(self.front); // Create card back self.back = LK.getAsset('memory_card_back', { anchorX: 0.5, anchorY: 0.5 }); self.addChild(self.back); // Make card interactive self.interactive = true; // Flip card to show front self.reveal = function () { if (self.matched || self.revealed) { return; } // Already revealed or matched self.revealed = true; // Animate card flip tween(self.scale, { x: 0 }, { duration: 150, easing: tween.easeInQuad, onFinish: function onFinish() { self.front.visible = true; self.back.visible = false; tween(self.scale, { x: 1 }, { duration: 150, easing: tween.easeOutQuad }); } }); if (self.onReveal) { self.onReveal(self); } }; // Flip card to hide front self.hide = function () { if (self.matched) { return; } // Don't hide if matched // Animate card flip tween(self.scale, { x: 0 }, { duration: 150, easing: tween.easeInQuad, onFinish: function onFinish() { self.front.visible = false; self.back.visible = true; self.revealed = false; tween(self.scale, { x: 1 }, { duration: 150, easing: tween.easeOutQuad }); } }); }; // Mark card as matched self.setMatched = function () { self.matched = true; self.interactive = false; // Flash effect for matching tween(self, { alpha: 0.5 }, { duration: 200, easing: tween.easeInQuad, onFinish: function onFinish() { tween(self, { alpha: 1 }, { duration: 200, easing: tween.easeOutQuad }); } }); }; // Handle card click self.down = function (x, y, obj) { // If card is already matched, or not interactive, do nothing. if (self.matched || !self.interactive) { return; } // If card is already revealed (face up), do nothing on 'down'. if (self.revealed) { return; } // If two cards are already face up (checked via currentMemoryGame.canSelectCard()), // do not allow this card (which is currently face down) to be pressed/animated. // currentMemoryGame might be null if the game is not active, so check it. if (currentMemoryGame && !currentMemoryGame.canSelectCard()) { return; } // Card is face down, interactive, not matched, and we are allowed to select a card. // Animate press down. tween(self, { scaleX: 0.95, scaleY: 0.95 }, { duration: 100 }); }; self.up = function (x, y, obj) { // If card is already matched, or not interactive, do nothing. if (self.matched || !self.interactive) { return; } // If card is already revealed (face up), it means it was one of the selected cards. // Clicking it again on 'up' should just restore its scale if it was pressed. No re-reveal. if (self.revealed) { tween(self, { scaleX: 1, scaleY: 1 }, { duration: 100 }); // Restore scale return; } // At this point, card is face down, interactive, and not matched. // We need to check again if we are allowed to reveal it. This is a final gate. // The 'down' action might have scaled it down. // If currentMemoryGame is null or canSelectCard is false, just restore scale and don't reveal. if (!currentMemoryGame || !currentMemoryGame.canSelectCard()) { tween(self, { scaleX: 1, scaleY: 1 }, { duration: 100 }); // Restore scale return; } // Allowed to reveal. Animate scale back and then reveal. tween(self, { scaleX: 1, scaleY: 1 }, { duration: 100, onFinish: function onFinish() { self.reveal(); // self.reveal() has its own checks too. } }); }; return self; }); var MemoryGame = Container.expand(function () { var self = Container.call(this); // Game state variables var selectedCards = []; var matchedPairs = 0; var totalPairs = 8; var canSelect = true; var movesMade = 0; // Create cards array var cards = []; // Create semi-transparent background var gameBackground = LK.getAsset('pet_playing', { anchorX: 0.5, anchorY: 0.5, width: 2000, height: 2000, tint: 0x000000 }); gameBackground.alpha = 0.7; self.addChild(gameBackground); // Title text var titleText = new Text2("Memory Game", { size: 80, fill: 0xFFFFFF }); titleText.anchor.set(0.5, 0.5); titleText.y = -900; self.addChild(titleText); // Moves counter var movesText = new Text2("Moves: 0", { size: 60, fill: 0xFFFFFF }); movesText.anchor.set(0.5, 0.5); movesText.y = -800; self.addChild(movesText); // Setup the game self.startGame = function () { currentMemoryGame = self; // Set the global reference // Reset game state selectedCards = []; matchedPairs = 0; movesMade = 0; canSelect = true; // Create card values (pairs of 1-8) var values = [1, 1, 2, 2, 3, 3, 4, 4, 5, 5, 6, 6, 7, 7, 8, 8]; // Shuffle the array for (var i = values.length - 1; i > 0; i--) { var j = Math.floor(Math.random() * (i + 1)); var temp = values[i]; values[i] = values[j]; values[j] = temp; } // Create and position cards in a 4x4 grid var gridSize = 4; // Create a temp card to measure actual size var tempCard = new MemoryCard(1); // Calculate spacing based on actual card dimensions var cardWidth = tempCard.back.width; var cardHeight = tempCard.back.height; var cardSpacing = cardWidth * 1.2; // Add 20% of width as spacing var verticalSpacing = cardHeight * 1.4; // Add 40% of height as vertical spacing // Calculate starting coordinates using actual card dimensions var startX = -((gridSize - 1) * cardSpacing) / 2; var startY = -((gridSize - 1) * verticalSpacing) / 2; // Clean up temp card tempCard = null; for (var row = 0; row < gridSize; row++) { for (var col = 0; col < gridSize; col++) { var index = row * gridSize + col; var card = new MemoryCard(values[index]); // Position card in grid using dynamic spacing based on card size card.x = startX + col * cardSpacing; card.y = startY + row * verticalSpacing; // Set up reveal callback card.onReveal = handleCardReveal; // Add to game self.addChild(card); cards.push(card); } } // Update moves display updateMovesText(); // Fade in animation self.alpha = 0; tween(self, { alpha: 1 }, { duration: 500 }); }; // Handle card reveal function handleCardReveal(card) { if (!canSelect) { return; } // Add card to selected cards selectedCards.push(card); // If we have 2 cards selected if (selectedCards.length === 2) { canSelect = false; movesMade++; updateMovesText(); // Check for match if (selectedCards[0].value === selectedCards[1].value) { // Match found! selectedCards[0].setMatched(); selectedCards[1].setMatched(); matchedPairs++; // Clear selection selectedCards = []; canSelect = true; // Check if game is complete if (matchedPairs === totalPairs) { // Game won! LK.setTimeout(function () { endGame(); }, 500); } } else { // No match, flip cards back after a delay LK.setTimeout(function () { selectedCards[0].hide(); selectedCards[1].hide(); selectedCards = []; canSelect = true; }, 1000); } } } // Update moves text function updateMovesText() { movesText.setText("Moves: " + movesMade); } self.canSelectCard = function () { return canSelect; }; // End the game function endGame() { // Calculate score (higher for fewer moves) var baseScore = 100; var movesPenalty = Math.min(80, movesMade * 2); var finalScore = Math.max(20, baseScore - movesPenalty); // Show winning message var winText = new Text2("Memory Game Complete!\nScore: " + finalScore, { size: 80, fill: 0xFFFFFF, align: "center" }); winText.anchor.set(0.5, 0.5); self.addChild(winText); // Animate text winText.scale.set(0); tween(winText.scale, { x: 1, y: 1 }, { duration: 500, easing: tween.elasticOut }); // Close after delay LK.setTimeout(function () { // Fade out animation tween(self, { alpha: 0 }, { duration: 500, onFinish: function onFinish() { if (self.onComplete) { self.onComplete(finalScore); } currentMemoryGame = null; // Clear the global reference // Remove all cards for (var i = 0; i < cards.length; i++) { self.removeChild(cards[i]); } cards = []; // Remove win text self.removeChild(winText); // Remove self from parent if (self.parent) { self.parent.removeChild(self); } } }); }, 2000); } // Close button var closeButton = new Text2("X", { size: 80, fill: 0xFFFFFF }); closeButton.anchor.set(0.5, 0.5); closeButton.x = 900; closeButton.y = -900; closeButton.interactive = true; self.addChild(closeButton); closeButton.down = function () { tween(closeButton, { scaleX: 0.9, scaleY: 0.9 }, { duration: 100 }); }; closeButton.up = function () { tween(closeButton, { scaleX: 1, scaleY: 1 }, { duration: 100, onFinish: function onFinish() { // Fade out and close tween(self, { alpha: 0 }, { duration: 300, onFinish: function onFinish() { // Calculate partial score var partialScore = Math.max(5, matchedPairs * 10); if (self.onComplete) { self.onComplete(partialScore); } currentMemoryGame = null; // Clear the global reference // Remove all cards for (var i = 0; i < cards.length; i++) { self.removeChild(cards[i]); } cards = []; // Remove self from parent if (self.parent) { self.parent.removeChild(self); } } }); } }); }; // Center the game on screen self.x = 2048 / 2; self.y = 2732 / 2; // Start the game self.startGame(); return self; }); var NameSelect = Container.expand(function (petType) { var self = Container.call(this); var petName = ""; self.petType = petType; // Background setup var background = self.attachAsset('menu_background', { anchorX: 0.5, anchorY: 0.5 }); background.x = 2048 / 2; background.y = 2732 / 2; // Title text var titleText = new Text2("Name Your Pet", { size: 100, fill: 0xFFFFFF }); titleText.anchor.set(0.5, 0.5); titleText.x = 2048 / 2; titleText.y = 500; self.addChild(titleText); // Add selected pet preview var petPreview = self.attachAsset(petType === 'Fluffy' ? 'pet_select_1' : 'pet_select_2', { anchorX: 0.5, anchorY: 0.5, x: 2048 / 2, y: 2732 / 2 - 300 }); // Name input display var nameDisplay = new Text2("_", { size: 80, fill: 0xFFFFFF }); nameDisplay.anchor.set(0.5, 0.5); nameDisplay.x = 2048 / 2; nameDisplay.y = 2732 / 2 + 100; self.addChild(nameDisplay); // Instruction text var instructionText = new Text2("Tap letters to name your pet", { size: 60, fill: 0xFFFFFF }); instructionText.anchor.set(0.5, 0.5); instructionText.x = 2048 / 2; instructionText.y = 2732 / 2 + 200; self.addChild(instructionText); // Create keyboard layout var keyboard = new Container(); keyboard.x = 2048 / 2; keyboard.y = 2732 / 2 + 400; self.addChild(keyboard); // Define keyboard characters var keys = ["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", "⌫"]; // Create keyboard buttons var keySize = 150; var keysPerRow = 7; var keySpacing = 15; for (var i = 0; i < keys.length; i++) { var row = Math.floor(i / keysPerRow); var col = i % keysPerRow; // Create key background var keyBg = LK.getAsset('progressBar_bg', { anchorX: 0.5, anchorY: 0.5, width: keySize, height: keySize, tint: keys[i] === "⌫" ? 0xFF6B6B : 0x70a1ff }); // Create key text var keyText = new Text2(keys[i], { size: 60, fill: 0xFFFFFF }); keyText.anchor.set(0.5, 0.5); // Create key container var key = new Container(); key.addChild(keyBg); key.addChild(keyText); key.x = (col - keysPerRow / 2) * (keySize + keySpacing); key.y = row * (keySize + keySpacing); key.keyValue = keys[i]; key.interactive = true; // Key interactions key.down = function (x, y, obj) { tween(this, { scaleX: 0.9, scaleY: 0.9 }, { duration: 100 }); }; key.up = function (x, y, obj) { var keyValue = this.keyValue; tween(this, { scaleX: 1, scaleY: 1 }, { duration: 100, onFinish: function onFinish() { // Handle backspace if (keyValue === "⌫") { if (petName.length > 0) { petName = petName.slice(0, -1); } } // Add letter if name is less than 10 characters else if (petName.length < 10) { petName += keyValue; } // Update name display nameDisplay.setText(petName + "_"); } }); }; keyboard.addChild(key); } // Done button var doneButton = new Container(); var doneBg = LK.getAsset('progressBar_bg', { anchorX: 0.5, anchorY: 0.5, width: 300, height: 100, tint: 0x7bed9f }); var doneText = new Text2("DONE", { size: 70, fill: 0xFFFFFF }); doneText.anchor.set(0.5, 0.5); doneButton.addChild(doneBg); doneButton.addChild(doneText); doneButton.x = 2048 / 2; doneButton.y = 2732 / 2 + 1200; doneButton.interactive = true; self.addChild(doneButton); doneButton.down = function (x, y, obj) { tween(doneButton, { scaleX: 0.95, scaleY: 0.95 }, { duration: 100 }); }; doneButton.up = function (x, y, obj) { tween(doneButton, { scaleX: 1, scaleY: 1 }, { duration: 100, onFinish: function onFinish() { // Use default name if empty if (petName.length === 0) { petName = self.petType; } if (self.onNameSelected) { self.onNameSelected(petName); } } }); }; return self; }); var Pet = Container.expand(function () { var self = Container.call(this); var currentLevel = storage.petLevel || 1; var petName = storage.petName || "Pet"; var petType = storage.petType || "Fluffy"; var petAssetId = 'pet_baby'; // Determine which asset to use based on level and pet type if (petType === "Puffy") { if (currentLevel === 1) { petAssetId = 'pet_puffy_baby'; } else if (currentLevel === 2) { petAssetId = 'pet_puffy_child'; } else if (currentLevel === 3) { petAssetId = 'pet_puffy_teen'; } else if (currentLevel >= 4) { petAssetId = 'pet_puffy_adult'; } } else { // Default for Fluffy pet if (currentLevel === 1) { petAssetId = 'pet_baby'; } else if (currentLevel === 2) { petAssetId = 'pet_child'; } else if (currentLevel === 3) { petAssetId = 'pet_teen'; } else if (currentLevel >= 4) { petAssetId = 'pet_adult'; } } var petGraphics = self.attachAsset(petAssetId, { anchorX: 0.5, anchorY: 0.5 }); // Add pet name display var nameText = new Text2(petName, { size: 50, fill: 0xFFFFFF }); nameText.anchor.set(0.5, 0.5); nameText.y = -petGraphics.height / 2 - 40; // Initial position above pet self.addChild(nameText); // Method to reposition name to appear above level text self.positionNameAboveLevel = function () { // Remove from pet container self.removeChild(nameText); // Add directly to game container so it can be positioned independently game.addChild(nameText); // Position above level text nameText.x = 2048 / 2; nameText.y = 120; // Position above level text }; self.happy = function () { // Bounce animation tween(self, { y: self.y - 50 }, { duration: 300, easing: tween.easeOut, onFinish: function onFinish() { tween(self, { y: self.y + 50 }, { duration: 300, easing: tween.bounceOut, onFinish: function onFinish() { petPosition.x = self.x; petPosition.y = self.y; } }); } }); }; self.evolve = function () { // Evolution animation LK.getSound('evolve').play(); // Flash and grow LK.effects.flashObject(self, 0xFFFFFF, 1000); tween(petGraphics, { scaleX: 1.5, scaleY: 1.5 }, { duration: 500, easing: tween.easeOut, onFinish: function onFinish() { // Update to new visual based on new level currentLevel = storage.petLevel; var newPetAssetId; var petType = storage.petType || "Fluffy"; if (petType === "Puffy") { if (currentLevel === 2) { newPetAssetId = 'pet_puffy_child'; } else if (currentLevel === 3) { newPetAssetId = 'pet_puffy_teen'; } else if (currentLevel >= 4) { newPetAssetId = 'pet_puffy_adult'; } } else { // Default for Fluffy pet if (currentLevel === 2) { newPetAssetId = 'pet_child'; } else if (currentLevel === 3) { newPetAssetId = 'pet_teen'; } else if (currentLevel >= 4) { newPetAssetId = 'pet_adult'; } } // Remove old graphic and add new one self.removeChild(petGraphics); petGraphics = self.attachAsset(newPetAssetId, { anchorX: 0.5, anchorY: 0.5, scaleX: 1.5, scaleY: 1.5 }); // Reset scale with animation tween(petGraphics, { scaleX: 1, scaleY: 1 }, { duration: 300, easing: tween.easeOut }); } }); }; return self; }); var Poop = Container.expand(function () { var self = Container.call(this); // Create poop visual using a single image var poopGraphics = self.attachAsset('centerCircle', { anchorX: 0.5, anchorY: 0.5, scaleX: 1, scaleY: 1, tint: 0x8B4513 // Brown color }); // Add appear animation self.appear = function () { self.scale.set(0); tween(self, { scaleX: 1, scaleY: 1 }, { duration: 300, easing: tween.bounceOut }); }; // Add cleanup animation self.cleanup = function (callback) { tween(self, { alpha: 0, scaleX: 0.5, scaleY: 0.5 }, { duration: 300, easing: tween.easeInBack, onFinish: function onFinish() { if (callback) { callback(); } } }); }; return self; }); var StatusText = Text2.expand(function (initialText) { var self = Text2.call(this, initialText, { size: 60, fill: 0xFFFFFF }); self.anchor.set(0.5, 0.5); self.showMessage = function (message) { self.setText(message); self.alpha = 1; tween(self, { alpha: 0 }, { duration: 3000, easing: tween.linear }); }; return self; }); /**** * Initialize Game ****/ var game = new LK.Game({ backgroundColor: 0x7ED6DF }); /**** * Game Code ****/ // Game state - load these first var petLevel = storage.petLevel || 1; var petXp = storage.petXp || 0; var lastFed = storage.lastFed || 0; var lastCleaned = storage.lastCleaned || 0; var lastPlayed = storage.lastPlayed || 0; // Load pet state flags from storage var isHungry = false; var isBored = false; var hasActivePoop = false; var canFeedPet = false; var canPlayPet = false; var canCleanPet = false; var speechBubble; // Variable for the speech bubble // Timers and intervals for needs var needTimer = null; var needTimeout = null; var hungerTimer = null; // Added to fix 'hungerTimer is not defined' var boredTimer = null; // Added to fix 'boredTimer is not defined' var XP_LOSS_TIMEOUT = 60000; // 1 minute var POOP_SPEECH_TIMEOUT = 30000; // 30 seconds var POOP_XP_LOSS_TIMEOUT = 60000; // 1 minute var BORED_XP_LOSS_TIMEOUT = 90000; // 1.5 minutes var XP_LOSS_INTERVAL = 90000; // 1.5 minutes interval for XP loss if player doesn't play with pet var xpLossTimer; // Timer for XP loss after not feeding var XP_LOSS_AMOUNT = 50; // Amount of XP to lose var poopTimer; // Timer for when pet will poop var activePoop = null; // Reference to the active poop object var poopSpeechTimer; // Timer for poop speech bubble var poopXpLossTimer; // Timer for XP loss from uncleaned poop var boredXpLossTimer; // Timer for XP loss when bored // Define game constants - calculate after loading state var BASE_XP_PER_LEVEL = 500; var XP_PER_LEVEL = BASE_XP_PER_LEVEL * Math.pow(2, petLevel - 1); // Doubles with each level var XP_GAIN_FEED = 20; var XP_GAIN_CLEAN = 15; var XP_GAIN_PLAY = 25; var COOLDOWN_TIME = 10000; // 10 seconds cooldown between actions var PLAY_INACTIVITY_XP_LOSS = 15; // Amount of XP to lose from play inactivity var playInactivityInterval; // Interval for recurring XP loss due to play inactivity var hpText; // Define hpText in global scope var barFill; // Define barFill in global scope var barBackground; // Define barBackground in global scope // Track which need is currently active var currentNeed = null; // "hunger", "boredom", "poop" // New: For random need logic var NEEDS = ["hunger", "boredom", "poop"]; // Vector2 positions for pet at different evolution levels var petBabyPosition = { x: 2048 / 2, y: 2732 / 2 + 250 }; var petChildPosition = { x: 2048 / 2, y: 2732 / 2 + 200 }; var petTeenPosition = { x: 2048 / 2, y: 2732 / 2 + 150 }; var petAdultPosition = { x: 2048 / 2, y: 2732 / 2 + 150 }; // Track current game state var progressBar = new Container(); var currentScreen = "menu"; var mainMenu, pet, progressBar, statusText, levelText; var currentMemoryGame = null; // To hold the active MemoryGame instance var isMemoryGameActive = false; // Track if memory game is active var feedButton, cleanButton, playButton; var progressBarContainer = new Container(); // Current pet position based on level var petPosition = petBabyPosition; // Initialize menu function initMainMenu() { LK.playMusic('bgmusic'); // Clear previous game elements if they exist clearGameElements(); // Always show main menu first mainMenu = new MainMenu(); game.addChild(mainMenu); // Set up callbacks setupMainMenuCallbacks(); // Function to set up main menu callbacks function setupMainMenuCallbacks() { // Set up start game callback mainMenu.onStartGame = function () { // Check if it's first time playing or reset game if (!storage.petName) { // First time playing, transition to character select tween(mainMenu, { alpha: 0 }, { duration: 300, onFinish: function onFinish() { game.removeChild(mainMenu); // Show character select screen var characterSelect = new CharacterSelect(); game.addChild(characterSelect); // Handle character selection characterSelect.onSelectCharacter = function (selectedPetType) { // Show name selection screen tween(characterSelect, { alpha: 0 }, { duration: 300, onFinish: function onFinish() { game.removeChild(characterSelect); // Create name selection screen var nameSelect = new NameSelect(selectedPetType); game.addChild(nameSelect); // Handle name selection nameSelect.onNameSelected = function (selectedName) { // Save the selected name storage.petName = selectedName; // Hide name select and start game tween(nameSelect, { alpha: 0 }, { duration: 300, onFinish: function onFinish() { game.removeChild(nameSelect); // Now start the game currentScreen = "game"; initGameScreen(); } }); }; } }); }; } }); } else { // Returning player with saved data, go directly to gameplay currentScreen = "game"; initGameScreen(); } }; // Set up reset game callback mainMenu.onResetGame = function () { // Reset all storage values storage.petLevel = 1; storage.petXp = 0; petXp = 0; // Reset the current petXp value storage.lastFed = 0; storage.lastCleaned = 0; storage.lastPlayed = 0; storage.isHungry = false; storage.isBored = false; storage.hasActivePoop = false; storage.petName = null; // Reset pet name to trigger character select again // Show confirmation text var confirmText = new Text2("Game data reset!", { size: 60, fill: 0xFFFFFF }); confirmText.anchor.set(0.5, 0.5); confirmText.x = 2048 / 2; confirmText.y = 2732 / 2 + 500; mainMenu.addChild(confirmText); // Fade out confirmation text tween(confirmText, { alpha: 0 }, { duration: 2000, onFinish: function onFinish() { mainMenu.removeChild(confirmText); } }); }; } } // This function is now defined inside initMainMenu // Initialize game screen function initGameScreen() { console.log("Initializing game screen"); // Clear previous elements clearGameElements(); // Add game background var gameBackground = LK.getAsset('game_background', { anchorX: 0.5, anchorY: 0.5 }); gameBackground.x = 2048 / 2; gameBackground.y = 2732 / 2; game.addChild(gameBackground); // Create game elements pet = new Pet(); pet.x = petPosition.x; pet.y = petPosition.y; game.addChild(pet); // Position pet name above level text pet.positionNameAboveLevel(); // Add mechanic: show image above and left of pet when clicked, and allow XP gain on image click every 5s var petClickImage = null; var lastPetClickImageXpTime = 0; // Track last time XP was given from image pet.interactive = true; pet.down = function (x, y, obj) { // Remove previous image if exists if (petClickImage && petClickImage.parent) { petClickImage.parent.removeChild(petClickImage); petClickImage = null; } // Create the image (now using 'cheer_image' for cheering) petClickImage = LK.getAsset('cheer_image', { anchorX: 0.5, anchorY: 0.5, width: 400, height: 400 }); // Position above and left of pet petClickImage.x = pet.x - pet.width / 2 - 100; petClickImage.y = pet.y - pet.height / 2 - 100; game.addChild(petClickImage); // Animate in (optional) petClickImage.alpha = 0; tween(petClickImage, { alpha: 1 }, { duration: 200 }); // Add interaction to the image for XP gain petClickImage.interactive = true; petClickImage.down = function (x2, y2, obj2) { // Visual feedback for press tween(petClickImage, { scaleX: 0.9, scaleY: 0.9 }, { duration: 80 }); }; petClickImage.up = function (x2, y2, obj2) { // Prevent cheering if memory game is active if (isMemoryGameActive) { statusText.showMessage("Finish the memory game first!"); return; } // Restore scale tween(petClickImage, { scaleX: 1, scaleY: 1 }, { duration: 80 }); var now = Date.now(); if (!lastPetClickImageXpTime || now - lastPetClickImageXpTime >= 5000) { addXp(15); statusText.showMessage("Pet is happy! +15 XP"); lastPetClickImageXpTime = now; // Pet reacts (bounce/happy animation) if (pet && typeof pet.happy === "function") { pet.happy(); } } else { statusText.showMessage("Wait before cheering again!"); } }; // Hide after 1.5 seconds LK.setTimeout(function () { if (petClickImage && petClickImage.parent) { tween(petClickImage, { alpha: 0 }, { duration: 200, onFinish: function onFinish() { if (petClickImage && petClickImage.parent) { petClickImage.parent.removeChild(petClickImage); petClickImage = null; } } }); } }, 1500); }; // Level text levelText = new Text2("Level " + petLevel, { size: 80, fill: 0xFFFFFF }); levelText.anchor.set(0.5, 0.5); levelText.x = 2048 / 2; levelText.y = 200; game.addChild(levelText); // Create action buttons feedButton = new ActionButton('feed'); feedButton.x = 2048 / 4; feedButton.y = 2732 - 400; game.addChild(feedButton); cleanButton = new ActionButton('clean'); cleanButton.x = 2048 / 2; cleanButton.y = 2732 - 400; game.addChild(cleanButton); playButton = new ActionButton('play'); playButton.x = 2048 * 3 / 4; playButton.y = 2732 - 400; game.addChild(playButton); // Recalculate XP_PER_LEVEL based on current level XP_PER_LEVEL = BASE_XP_PER_LEVEL * Math.pow(2, petLevel - 1); console.log("Current petLevel:", petLevel, "XP_PER_LEVEL:", XP_PER_LEVEL); // Make sure all values are calculated before updating progress bar XP_PER_LEVEL = BASE_XP_PER_LEVEL * Math.pow(2, petLevel - 1); // Update the progress bar on start console.log("Initial progress bar update with petXp:", petXp, "XP_PER_LEVEL:", XP_PER_LEVEL); // Make sure variables are initialized properly petXp = petXp || 0; XP_PER_LEVEL = XP_PER_LEVEL || BASE_XP_PER_LEVEL; // Now create HP text after progress bar exists hpText = new Text2("XP: " + petXp + "/" + XP_PER_LEVEL, { size: 60, fill: 0xFFFFFF }); hpText.anchor.set(0, 0.5); hpText.x = progressBar.x + 10; hpText.y = progressBar.y - 50; game.addChild(hpText); // Create HP text display console.log("Creating HP text with petXp:", petXp, "XP_PER_LEVEL:", XP_PER_LEVEL); hpText = new Text2("XP: " + petXp + "/" + XP_PER_LEVEL, { size: 60, fill: 0xFFFFFF }); hpText.anchor.set(0, 0.5); game.addChild(hpText); console.log("Game screen initialization complete"); createProgressBar(); addBarFillXp(); // Status text statusText = new StatusText(""); statusText.x = 2048 / 2; statusText.y = progressBar.y + 100; statusText.alpha = 0; game.addChild(statusText); // Create speech bubble for needs speechBubble = new BubbleSpeech(""); speechBubble.x = pet.x + 450; speechBubble.y = pet.y - 450; // Position above pet speechBubble.alpha = 0; // Start invisible game.addChild(speechBubble); // Helper: clear any need timers function clearNeedTimers() { if (needTimer) { LK.clearTimeout(needTimer); needTimer = null; } if (needTimeout) { LK.clearTimeout(needTimeout); needTimeout = null; } if (xpLossTimer) { LK.clearTimeout(xpLossTimer); xpLossTimer = null; } if (boredXpLossTimer) { LK.clearTimeout(boredXpLossTimer); boredXpLossTimer = null; } if (playInactivityInterval) { LK.clearInterval(playInactivityInterval); playInactivityInterval = null; } if (poopSpeechTimer) { LK.clearTimeout(poopSpeechTimer); poopSpeechTimer = null; } if (poopXpLossTimer) { LK.clearTimeout(poopXpLossTimer); poopXpLossTimer = null; } } // Helper: pick a random need function pickRandomNeed() { // If there is active poop, always return "poop" if (activePoop) { return "poop"; } // Otherwise, pick randomly from the 3 needs var idx = Math.floor(Math.random() * NEEDS.length); return NEEDS[idx]; } // Main: show a random need every 5-10 seconds function showRandomNeed() { // If memory game is active, wait and try again later if (isMemoryGameActive) { // Try again in 2 seconds needTimer = LK.setTimeout(function () { showRandomNeed(); }, 2000); return; } clearNeedTimers(); // Pick a random need var need = pickRandomNeed(); currentNeed = need; canFeedPet = false; canPlayPet = false; canCleanPet = false; isHungry = false; isBored = false; // Show the bubble and set the action variable if (need === "hunger") { speechBubble.setText("I'm hungry!"); speechBubble.show(500); canFeedPet = true; isHungry = true; // XP loss if ignored xpLossTimer = LK.setTimeout(function () { if (petXp > 0) { addXp(-XP_LOSS_AMOUNT); statusText.showMessage("Pet is hungry! Lost " + XP_LOSS_AMOUNT + " XP!"); } }, XP_LOSS_TIMEOUT); } else if (need === "boredom") { speechBubble.setText("I'm bored! \nPlay with me!"); speechBubble.show(500); canPlayPet = true; isBored = true; // XP loss if ignored boredXpLossTimer = LK.setTimeout(function () { if (petXp > 0) { addXp(-XP_LOSS_AMOUNT); statusText.showMessage("Pet is bored! Lost " + XP_LOSS_AMOUNT + " XP!"); } }, BORED_XP_LOSS_TIMEOUT); // Play inactivity XP loss playInactivityInterval = LK.setInterval(function () { var currentTime = Date.now(); var timeSinceLastPlayed = currentTime - lastPlayed; if (timeSinceLastPlayed > 300000 && petXp > 0) { addXp(-PLAY_INACTIVITY_XP_LOSS); statusText.showMessage("Your pet misses you! Lost " + PLAY_INACTIVITY_XP_LOSS + " XP!"); speechBubble.setText("I miss \nplaying \nwith you!"); speechBubble.show(500); LK.setTimeout(function () { speechBubble.hide(300); }, 3000); } }, XP_LOSS_INTERVAL); } else if (need === "poop") { // If no active poop, spawn one if (!activePoop) { activePoop = new Poop(); activePoop.x = pet.x + 900; activePoop.y = pet.y + 200; game.addChild(activePoop); activePoop.appear(); } speechBubble.setText("Please clean \nthis mess!"); speechBubble.show(500); canCleanPet = true; // XP loss if ignored poopXpLossTimer = LK.setTimeout(function () { var loseXpInterval = LK.setInterval(function () { if (activePoop) { if (petXp > 0) { addXp(-XP_LOSS_AMOUNT); statusText.showMessage("Pet uncomfortable! Lost " + XP_LOSS_AMOUNT + " XP!"); speechBubble.setText("This mess \nis making \nme lose XP!"); speechBubble.show(500); LK.setTimeout(function () { speechBubble.hide(300); }, 3000); } } else { LK.clearInterval(loseXpInterval); } }, POOP_XP_LOSS_TIMEOUT); }, POOP_XP_LOSS_TIMEOUT); } // Schedule next need var nextDelay = 5000 + Math.floor(Math.random() * 5000); // 5-10s needTimer = LK.setTimeout(function () { showRandomNeed(); }, nextDelay); } // If there was an active poop, restore it if (activePoop) { activePoop = new Poop(); activePoop.x = pet.x + Math.random() * 1000; activePoop.y = pet.y + 100 + Math.random() * 50; game.addChild(activePoop); activePoop.appear(); } // Start the random need loop showRandomNeed(); } //[3J] // Clear all game elements // Function to stop a specific timer by name function stopTimer(timerName) { // Check if timer name is valid before attempting to stop if (!timerName) { console.log("Cannot stop timer: timer name is undefined or null"); return; } if (timerName === 'hunger' && hungerTimer) { LK.clearTimeout(hungerTimer); hungerTimer = null; console.log("Hunger timer stopped"); } else if (timerName === 'xpLoss' && xpLossTimer) { LK.clearTimeout(xpLossTimer); xpLossTimer = null; console.log("XP loss timer stopped"); } else if (timerName === 'poop' && poopTimer) { LK.clearTimeout(poopTimer); poopTimer = null; console.log("Poop timer stopped"); } else if (timerName === 'poopSpeech' && poopSpeechTimer) { LK.clearTimeout(poopSpeechTimer); poopSpeechTimer = null; console.log("Poop speech timer stopped"); } else if (timerName === 'poopXpLoss' && poopXpLossTimer) { LK.clearTimeout(poopXpLossTimer); poopXpLossTimer = null; console.log("Poop XP loss timer stopped"); } else if (timerName === 'bored' && boredTimer) { LK.clearTimeout(boredTimer); boredTimer = null; console.log("Bored timer stopped"); } else if (timerName === 'boredXpLoss' && boredXpLossTimer) { LK.clearTimeout(boredXpLossTimer); boredXpLossTimer = null; console.log("Bored XP loss timer stopped"); } else if (timerName === 'playInactivity' && playInactivityInterval) { LK.clearInterval(playInactivityInterval); playInactivityInterval = null; console.log("Play inactivity interval stopped"); } else { console.log("Timer not found or already stopped: " + timerName); } } function clearGameElements() { // Clear hunger timer if exists if (hungerTimer) { LK.clearTimeout(hungerTimer); hungerTimer = null; } // Clear hunger speech bubble interval if exists if (typeof hungerSpeechBubbleInterval !== "undefined" && hungerSpeechBubbleInterval) { LK.clearInterval(hungerSpeechBubbleInterval); hungerSpeechBubbleInterval = null; } // Clear XP loss timer if exists if (xpLossTimer) { LK.clearTimeout(xpLossTimer); xpLossTimer = null; } // Clear poop timer if exists if (poopTimer) { LK.clearTimeout(poopTimer); poopTimer = null; } // Clear poop speech timer if exists if (poopSpeechTimer) { LK.clearTimeout(poopSpeechTimer); poopSpeechTimer = null; } // Clear poop XP loss timer if exists if (poopXpLossTimer) { LK.clearTimeout(poopXpLossTimer); poopXpLossTimer = null; } // Clear bored timer if exists if (boredTimer) { LK.clearTimeout(boredTimer); boredTimer = null; } // Clear bored XP loss timer if exists if (boredXpLossTimer) { LK.clearTimeout(boredXpLossTimer); boredXpLossTimer = null; } // Clear play inactivity interval if exists if (playInactivityInterval) { LK.clearInterval(playInactivityInterval); playInactivityInterval = null; } // Reset active poop reference activePoop = null; while (game.children.length > 0) { game.removeChild(game.children[0]); } //[3K] } //[3L] // Start with main menu initMainMenu(); function performFeedAction() { console.log("performFeedAction called"); var currentTime = Date.now(); //[3O] // Check if pet is recently fed (on cooldown) if (currentTime - lastFed < COOLDOWN_TIME) { statusText.showMessage("Pet is still full! Wait a moment."); console.log("Action on cooldown, can't feed yet"); return; //[3P] } //[3Q] // Check if feeding is allowed using canFeedPet variable if (!canFeedPet) { statusText.showMessage("Pet isn't hungry yet!"); console.log("Pet can't be fed yet - canFeedPet is false"); return; } // If hunger message is showing, we can feed the pet if (speechBubble && speechBubble.alpha > 0 && speechBubble.text === "I'm hungry!") { // Pet is hungry with message showing, continue with feeding } else if (!canFeedPet) { statusText.showMessage("Pet isn't hungry yet!"); console.log("Pet isn't hungry yet"); return; } console.log("Feeding pet, adding XP:", XP_GAIN_FEED); LK.getSound('feed').play(); pet.happy(); //[3R] lastFed = currentTime; storage.lastFed = lastFed; addXp(XP_GAIN_FEED); console.log("After addXp call"); statusText.showMessage("Pet fed! +20 XP"); // Set canFeedPet to false after feeding canFeedPet = false; // Update hunger state in storage storage.isHungry = false; // Hide hunger speech bubble if visible and it's showing the hunger message if (speechBubble && speechBubble.alpha > 0 && speechBubble.text === "I'm hungry!") { speechBubble.hide(300); } // Clear the repeated hunger speech bubble interval if it exists if (typeof hungerSpeechBubbleInterval !== "undefined" && hungerSpeechBubbleInterval) { LK.clearInterval(hungerSpeechBubbleInterval); hungerSpeechBubbleInterval = null; } // Reset hunger timer if (hungerTimer) { LK.clearTimeout(hungerTimer); } hungerTimer = LK.setTimeout(function () { // Show speech bubble with animation speechBubble.show(500); // Set canFeedPet to true when hunger message appears again canFeedPet = true; // Update hunger state in storage storage.isHungry = true; console.log("Pet is hungry again - canFeedPet set to true"); }, 60000); // Reset XP loss timer when feeding if (xpLossTimer) { LK.clearTimeout(xpLossTimer); } xpLossTimer = LK.setTimeout(function () { if (petXp > 0) { addXp(-XP_LOSS_AMOUNT); statusText.showMessage("Pet is hungry! Lost " + XP_LOSS_AMOUNT + " XP!"); } }, XP_LOSS_TIMEOUT); // Set timer for pet to poop 15 seconds after being fed every time if (poopTimer) { LK.clearTimeout(poopTimer); } poopTimer = LK.setTimeout(function () { // Only create poop if there isn't one already if (!activePoop) { // Create new poop slightly behind the pet activePoop = new Poop(); activePoop.x = pet.x + 1000; // Random position near pet activePoop.y = pet.y + 200; game.addChild(activePoop); activePoop.appear(); // Update poop state in storage storage.hasActivePoop = true; // Create a speech bubble for the poop event speechBubble.setText("I made \na mess!"); speechBubble.show(500); // Hide speech bubble after 3 seconds LK.setTimeout(function () { speechBubble.hide(300); }, 3000); // Set timer to show clean up reminder after 1 minute if (poopSpeechTimer) { LK.clearTimeout(poopSpeechTimer); } poopSpeechTimer = LK.setTimeout(function () { speechBubble.setText("Please clean \nthis mess!"); speechBubble.show(500); }, POOP_SPEECH_TIMEOUT); // Set timer for XP loss after 2 minutes of not cleaning if (poopXpLossTimer) { LK.clearTimeout(poopXpLossTimer); } poopXpLossTimer = LK.setTimeout(function () { // Set up recurring XP loss every 2 minutes until cleaned var loseXpInterval = LK.setInterval(function () { if (activePoop) { if (petXp > 0) { addXp(-XP_LOSS_AMOUNT); statusText.showMessage("Pet uncomfortable! Lost " + XP_LOSS_AMOUNT + " XP!"); // Show speech bubble about being uncomfortable speechBubble.setText("This mess \nis making \nme lose XP!"); speechBubble.show(500); LK.setTimeout(function () { speechBubble.hide(300); }, 3000); } } else { // Clear interval if poop is gone LK.clearInterval(loseXpInterval); } }, POOP_XP_LOSS_TIMEOUT); }, POOP_XP_LOSS_TIMEOUT); } }, 15000); // Always 15 seconds after eating } //[3S] function performCleanAction() { var currentTime = Date.now(); if (currentTime - lastCleaned < COOLDOWN_TIME) { statusText.showMessage("Pet is already clean! Wait a moment."); return; } // Check if there's poop to clean if (activePoop) { LK.getSound('clean').play(); pet.happy(); lastCleaned = currentTime; storage.lastCleaned = lastCleaned; // Add extra XP for cleaning poop addXp(XP_GAIN_CLEAN * 2); statusText.showMessage("Poop cleaned! +30 XP"); // Animate poop cleanup activePoop.cleanup(function () { if (activePoop && activePoop.parent) { activePoop.parent.removeChild(activePoop); } // Clear poop speech bubble timer if (poopSpeechTimer) { LK.clearTimeout(poopSpeechTimer); poopSpeechTimer = null; } // Clear poop XP loss timer if (poopXpLossTimer) { LK.clearTimeout(poopXpLossTimer); poopXpLossTimer = null; } activePoop = null; // Update poop state in storage storage.hasActivePoop = false; }); // Pet is happy about cleaning LK.setTimeout(function () { // Save previous speech bubble text so we know if it was about cleaning var previousText = speechBubble.text; speechBubble.setText("Thank you!"); speechBubble.show(500); // Hide speech bubble after 2 seconds, but only if it was about cleaning LK.setTimeout(function () { // Only hide if we had shown the thank you message from cleaning if (speechBubble.text === "Thank you!" && (previousText === "Please clean \nthis mess!" || previousText === "I made \na mess!" || previousText === "This mess \nis making \nme lose XP!")) { speechBubble.hide(300); } }, 2000); }, 500); } else { // Don't allow cleaning if there's no poop statusText.showMessage("Nothing to clean right now!"); } } function performPlayAction() { var currentTime = Date.now(); if (currentTime - lastPlayed < COOLDOWN_TIME) { statusText.showMessage("Pet is tired! Wait a moment."); return; } // Check if playing is allowed using canPlayPet variable if (!canPlayPet) { statusText.showMessage("Pet isn't bored yet!"); console.log("Pet can't be played with yet - canPlayPet is false"); return; } // If pet is bored with message showing, proceed with playing // Otherwise, we'll still allow one play action before requiring the boredom message LK.getSound('play').play(); pet.happy(); lastPlayed = currentTime; storage.lastPlayed = lastPlayed; // Launch memory game instead of immediately adding XP speechBubble.setText("Let's play a \nmemory \ngame!"); speechBubble.show(500); // Pause all timers before starting memory game var savedTimers = { hungerTimer: hungerTimer, xpLossTimer: xpLossTimer, boredTimer: boredTimer, boredXpLossTimer: boredXpLossTimer, poopTimer: poopTimer, poopSpeechTimer: poopSpeechTimer, poopXpLossTimer: poopXpLossTimer }; // Clear all active timers if (hungerTimer) { LK.clearTimeout(hungerTimer); } if (xpLossTimer) { LK.clearTimeout(xpLossTimer); } if (boredTimer) { LK.clearTimeout(boredTimer); } if (boredXpLossTimer) { LK.clearTimeout(boredXpLossTimer); } if (poopTimer) { LK.clearTimeout(poopTimer); } if (poopSpeechTimer) { LK.clearTimeout(poopSpeechTimer); } if (poopXpLossTimer) { LK.clearTimeout(poopXpLossTimer); } if (playInactivityInterval) { LK.clearInterval(playInactivityInterval); } // Disable action buttons during memory game feedButton.interactive = false; cleanButton.interactive = false; playButton.interactive = false; isMemoryGameActive = true; var memoryGame = new MemoryGame(); // Add delay before creating and showing memory game LK.setTimeout(function () { // Create and start memory game game.addChild(memoryGame); }, 1500); // 0.5 second delay // Handle game completion memoryGame.onComplete = function (score) { isMemoryGameActive = false; // Re-enable action buttons when game completes feedButton.interactive = true; cleanButton.interactive = true; playButton.interactive = true; // Only add XP if the player completes the memory game with a score of at least 50 // (matches condition in endGame() where 50 score is shown for completing the game) if (score >= 50) { // Add XP based on score (higher score = more XP) var earnedXp = XP_GAIN_PLAY + score; addXp(earnedXp); statusText.showMessage("Beat memory game! +" + earnedXp + " XP"); // Tell player how they did speechBubble.setText("Great job! \nYou earned \n" + earnedXp + " XP!"); // Pet is happy after successful game completion pet.happy(); speechBubble.show(500); // Hide speech bubble after 2 seconds, but only if it's related to boredom LK.setTimeout(function () { // Only hide if it's showing the success message (not if it's showing hunger or poop messages) if (speechBubble && speechBubble.text && speechBubble.text.includes("Great job!")) { speechBubble.hide(300); } }, 2000); // Set canPlayPet to false after playing canPlayPet = false; // Update boredom state in storage storage.isBored = false; // Stop the boredXpLoss timer when winning the memory game if (boredXpLossTimer) { LK.clearTimeout(boredXpLossTimer); boredXpLossTimer = null; } // Reset boredom timer if (boredTimer) { LK.clearTimeout(boredTimer); } boredTimer = LK.setTimeout(function () { // Show speech bubble with animation speechBubble.setText("I'm bored! \n Play with me!"); speechBubble.show(500); // Set canPlayPet to true when boredom message appears canPlayPet = true; // Update boredom state in storage storage.isBored = true; console.log("Pet is bored again - canPlayPet set to true"); }, timeToBored); // Only reset boredom timer, not hunger timer // This prevents boredom while playing memory game but allows normal hunger progression if (boredTimer) { LK.clearTimeout(boredTimer); } boredTimer = LK.setTimeout(function () { speechBubble.setText("I'm bored! \n Play with me!"); speechBubble.show(500); canPlayPet = true; storage.isBored = true; }, timeToBored); if (xpLossTimer) { LK.clearTimeout(xpLossTimer); } xpLossTimer = LK.setTimeout(function () { if (petXp > 0) { addXp(-XP_LOSS_AMOUNT); statusText.showMessage("Pet is hungry! Lost " + XP_LOSS_AMOUNT + " XP!"); } }, XP_LOSS_TIMEOUT); } else { // Player quit or didn't complete the game statusText.showMessage("You must \ncomplete \nthe game!"); speechBubble.setText("Let's try \nagain!"); speechBubble.show(500); // Wait a moment and then start a new memory game LK.setTimeout(function () { // Create and start a new memory game var newMemoryGame = new MemoryGame(); game.addChild(newMemoryGame); // Pass the same onComplete callback to the new game newMemoryGame.onComplete = memoryGame.onComplete; }, 2000); // Don't update pet status since game isn't completed yet return; } }; // Reset bored XP loss timer if (boredXpLossTimer) { LK.clearTimeout(boredXpLossTimer); } boredXpLossTimer = LK.setTimeout(function () { if (petXp > 0) { addXp(-XP_LOSS_AMOUNT); statusText.showMessage("Pet is bored! Lost " + XP_LOSS_AMOUNT + " XP!"); } }, BORED_XP_LOSS_TIMEOUT); // Reset play inactivity interval to prevent additional XP loss if (playInactivityInterval) { LK.clearInterval(playInactivityInterval); playInactivityInterval = LK.setInterval(function () { var currentTime = Date.now(); var timeSinceLastPlayed = currentTime - lastPlayed; if (timeSinceLastPlayed > 300000 && petXp > 0) { addXp(-PLAY_INACTIVITY_XP_LOSS); statusText.showMessage("Your pet misses you! Lost " + PLAY_INACTIVITY_XP_LOSS + " XP!"); speechBubble.setText("I miss playing `\n with you!"); speechBubble.show(500); LK.setTimeout(function () { speechBubble.hide(300); }, 3000); } }, XP_LOSS_INTERVAL); } } function addXp(amount) { console.log("addXp called with amount:", amount); petXp += amount; storage.petXp = petXp; // Check if pet is at level 1 and XP goes below 0 if (petLevel === 1 && petXp < 0) { // Pet dies at level 1 with negative XP statusText.showMessage(storage.petName + " has died!"); // Show game over LK.setTimeout(function () { // Reset all storage values storage.petLevel = 1; storage.petXp = 0; storage.lastFed = 0; storage.lastCleaned = 0; storage.lastPlayed = 0; storage.isHungry = false; storage.isBored = false; storage.hasActivePoop = false; storage.petName = null; // Reset pet name to trigger character select again // Show game over screen LK.showGameOver(); }, 2000); return; // Stop execution } // Check if pet level is greater than 1 and XP goes below 0 if (petLevel > 1 && petXp < 0) { // Pet regresses to previous level petLevel -= 1; // Calculate new XP_PER_LEVEL for the previous level XP_PER_LEVEL = BASE_XP_PER_LEVEL * Math.pow(2, petLevel - 1); // Calculate how much XP to subtract from previous level's total // If XP is -50 and pet was at level 2, it should have XP_PER_LEVEL - 50 (e.g., 500 - 50 = 450) petXp = XP_PER_LEVEL + petXp; // Add negative XP to previous level's max XP // Update storage values storage.petLevel = petLevel; storage.petXp = petXp; // Update level text levelText.setText("Level " + petLevel); // Update pet position based on new level if (petLevel === 1) { petPosition = petBabyPosition; } else if (petLevel === 2) { petPosition = petChildPosition; } else if (petLevel === 3) { petPosition = petTeenPosition; } else if (petLevel >= 4) { petPosition = petAdultPosition; } // Update pet position pet.x = petPosition.x; pet.y = petPosition.y; // Show message about regression statusText.showMessage("Pet regressed to level " + petLevel + "!"); // Update pet appearance // Remove old graphic and add new one var petType = storage.petType || "Fluffy"; var newPetAssetId; if (petType === "Puffy") { if (petLevel === 1) { newPetAssetId = 'pet_puffy_baby'; } else if (petLevel === 2) { newPetAssetId = 'pet_puffy_child'; } else if (petLevel === 3) { newPetAssetId = 'pet_puffy_teen'; } else if (petLevel >= 4) { newPetAssetId = 'pet_puffy_adult'; } } else { // Default for Fluffy pet if (petLevel === 1) { newPetAssetId = 'pet_baby'; } else if (petLevel === 2) { newPetAssetId = 'pet_child'; } else if (petLevel === 3) { newPetAssetId = 'pet_teen'; } else if (petLevel >= 4) { newPetAssetId = 'pet_adult'; } } // Get reference to current graphics to replace var currentGraphics = pet.children.find(function (child) { return child.asset && child.asset.indexOf('pet_') === 0; }); if (currentGraphics) { // Set the current pet image as invisible currentGraphics.visible = false; pet.removeChild(currentGraphics); } var petGraphics = pet.attachAsset(newPetAssetId, { anchorX: 0.5, anchorY: 0.5 }); // Flash effect to indicate regression LK.effects.flashObject(pet, 0xFF0000, 1000); } // Check for level up if (petXp >= XP_PER_LEVEL) { console.log("Level up condition met!"); petLevel += 1; petXp = 0; storage.petLevel = petLevel; storage.petXp = petXp; // Recalculate XP_PER_LEVEL for next level - doubles with each level XP_PER_LEVEL = BASE_XP_PER_LEVEL * Math.pow(2, petLevel - 1); console.log("New level:", petLevel, "New XP_PER_LEVEL:", XP_PER_LEVEL); // Update pet position based on new level if (petLevel === 2) { petPosition = petChildPosition; } else if (petLevel === 3) { petPosition = petTeenPosition; } else if (petLevel >= 4) { petPosition = petAdultPosition; } // Update pet position pet.x = petPosition.x; pet.y = petPosition.y; levelText.setText("Level " + petLevel); pet.evolve(); if (petLevel >= 4) { statusText.showMessage("Maximum level reached!"); } else { statusText.showMessage("Pet evolved to level " + petLevel + "! Next level: " + XP_PER_LEVEL + " XP"); } } // Update the HP text with current XP if (hpText) { hpText.setText("XP: " + petXp + "/" + XP_PER_LEVEL); } else { console.log("hpText is undefined or null"); } addBarFillXp(); } function createProgressBar() { // Initialize position first progressBar.x = 2048 / 2 - 400; // Center it progressBar.y = 2732 - 200; // Near bottom barBackground = LK.getAsset('progressBar_bg', { anchorX: 0, anchorY: 0.5 }); progressBar.addChild(barBackground); barFill = LK.getAsset('progressBar_fill', { anchorX: 0, anchorY: 0.5 }); progressBar.addChild(barFill); // Add progress bar to game game.addChild(progressBar); // Update hpText position now that progressBar exists if (hpText) { hpText.x = progressBar.x + 10; hpText.y = progressBar.y - 50; } } function addBarFillXp() { // Store current width to animate from var currentWidth = barFill.width; // Calculate target width var targetWidth = petXp / XP_PER_LEVEL * barBackground.width; // Animate the width change tween(barFill, { width: targetWidth }, { duration: 800, easing: tween.easeOutQuad }); } // Game update function game.update = function () { // Screen-specific updates if (currentScreen === "game") { // Ensure we're not continuously updating the progress bar every frame // This was the source of the undefined parameters call } };
/****
* Plugins
****/
var tween = LK.import("@upit/tween.v1");
var storage = LK.import("@upit/storage.v1", {
petLevel: 1,
petXp: 0,
lastFed: 0,
lastCleaned: 0,
lastPlayed: 0,
petName: "undefined",
petType: "Fluffy"
});
/****
* Classes
****/
var ActionButton = Container.expand(function (actionType, position) {
var self = Container.call(this);
var buttonShape;
if (actionType === 'feed') {
buttonShape = self.attachAsset('foodItem', {
anchorX: 0.5,
anchorY: 0.5
});
} else if (actionType === 'clean') {
buttonShape = self.attachAsset('cleaningItem', {
anchorX: 0.5,
anchorY: 0.5
});
} else if (actionType === 'play') {
buttonShape = self.attachAsset('playItem', {
anchorX: 0.5,
anchorY: 0.5
});
}
self.buttonType = actionType;
self.interactive = true;
self.down = function (x, y, obj) {
tween(buttonShape, {
scaleX: 0.8,
scaleY: 0.8
}, {
duration: 100
});
};
self.up = function (x, y, obj) {
tween(buttonShape, {
scaleX: 1,
scaleY: 1
}, {
duration: 100,
onFinish: function onFinish() {
if (self.buttonType === 'feed') {
performFeedAction();
} else if (self.buttonType === 'clean') {
performCleanAction();
} else if (self.buttonType === 'play') {
performPlayAction();
}
}
});
};
return self;
});
var BubbleSpeech = Container.expand(function (text) {
var self = Container.call(this);
// Create the bubble background
var bubbleBackground = LK.getAsset('bubble_speech', {
anchorX: 0.5,
anchorY: 0.5,
width: 600,
height: 600,
tint: 0xFFFFFF
});
// Round the corners by scaling
bubbleBackground.scale.set(1);
self.addChild(bubbleBackground);
// Add text to bubble
var bubbleText = new Text2(text || "", {
size: 80,
fill: 0x000000,
align: "center",
// You can set alignment to "left", "center", or "right"
wordWrap: true,
wordWrapWidth: 800 // Set this to control where text will wra
});
bubbleText.anchor.set(0.5, 0.5);
self.addChild(bubbleText);
// Public methods
self.setText = function (newText) {
bubbleText.setText(newText);
};
// Show with animation
self.show = function (duration) {
self.alpha = 0;
self.scale.set(0.5);
tween(self, {
alpha: 1,
scaleX: 1,
scaleY: 1
}, {
duration: duration || 300,
easing: tween.easeOutBack
});
};
// Hide with animation
self.hide = function (duration, callback) {
tween(self, {
alpha: 0,
scaleX: 0.5,
scaleY: 0.5
}, {
duration: duration || 300,
easing: tween.easeInBack,
onFinish: function onFinish() {
if (callback) {
callback();
}
}
});
};
return self;
});
var CharacterSelect = Container.expand(function () {
var self = Container.call(this);
// Background image
var background = self.attachAsset('menu_background', {
anchorX: 0.5,
anchorY: 0.5
});
background.x = 2048 / 2;
background.y = 2732 / 2;
// Title text
var titleText = new Text2("Choose Your Pet", {
size: 100,
fill: 0xFFFFFF
});
titleText.anchor.set(0.5, 0.5);
titleText.x = 2048 / 2;
titleText.y = 500;
self.addChild(titleText);
// Create character options
var character1 = self.attachAsset('pet_select_1', {
anchorX: 0.5,
anchorY: 0.5,
x: 2048 / 3,
y: 2732 / 2
});
character1.interactive = true;
var character2 = self.attachAsset('pet_select_2', {
anchorX: 0.5,
anchorY: 0.5,
x: 2048 * 2 / 3,
y: 2732 / 2
});
character2.interactive = true;
// Character 1 label
var label1 = new Text2("Fluffy", {
size: 70,
fill: 0xFFFFFF
});
label1.anchor.set(0.5, 0.5);
label1.x = character1.x;
label1.y = character1.y + 350;
self.addChild(label1);
// Character 2 label
var label2 = new Text2("Puffy", {
size: 70,
fill: 0xFFFFFF
});
label2.anchor.set(0.5, 0.5);
label2.x = character2.x;
label2.y = character2.y + 350;
self.addChild(label2);
// Button animations and interaction
character1.down = function (x, y, obj) {
tween(character1, {
scaleX: 0.95,
scaleY: 0.95
}, {
duration: 100
});
};
character1.up = function (x, y, obj) {
tween(character1, {
scaleX: 1,
scaleY: 1
}, {
duration: 100,
onFinish: function onFinish() {
if (self.onSelectCharacter) {
storage.petType = 'Fluffy';
storage.petXp = 0;
storage.petLevel = 1;
self.onSelectCharacter('Fluffy');
}
}
});
};
character2.down = function (x, y, obj) {
tween(character2, {
scaleX: 0.95,
scaleY: 0.95
}, {
duration: 100
});
};
character2.up = function (x, y, obj) {
tween(character2, {
scaleX: 1,
scaleY: 1
}, {
duration: 100,
onFinish: function onFinish() {
if (self.onSelectCharacter) {
storage.petType = 'Puffy';
storage.petXp = 0;
storage.petLevel = 1;
self.onSelectCharacter('Puffy');
}
}
});
};
return self;
});
var MainMenu = Container.expand(function () {
var self = Container.call(this);
// Background image
var background = self.attachAsset('menu_background', {
anchorX: 0.5,
anchorY: 0.5
});
background.x = 2048 / 2;
background.y = 2732 / 2;
// Game logo
var gameLogo = self.attachAsset('game_logo', {
anchorX: 0.5,
anchorY: 0.5
});
gameLogo.x = 2048 / 2;
gameLogo.y = 800;
// Play button image
var playButton = self.attachAsset('play_button', {
anchorX: 0.5,
anchorY: 0.5
});
playButton.x = 2048 / 2;
playButton.y = 2732 / 2 + 200;
playButton.interactive = true;
// Reset button
var resetButton = new Text2("Reset Game", {
size: 60,
fill: 0xFFFFFF
});
resetButton.anchor.set(0.5, 0.5);
resetButton.x = 2048 / 2;
resetButton.y = 2732 / 2 + 400;
resetButton.interactive = true;
self.addChild(resetButton);
// Button animations and interaction
playButton.down = function (x, y, obj) {
tween(playButton, {
scaleX: 0.95,
scaleY: 0.95
}, {
duration: 100
});
};
playButton.up = function (x, y, obj) {
tween(playButton, {
scaleX: 1,
scaleY: 1
}, {
duration: 100,
onFinish: function onFinish() {
if (self.onStartGame) {
self.onStartGame();
}
}
});
};
// Reset button interactions
resetButton.down = function (x, y, obj) {
tween(resetButton, {
scaleX: 0.95,
scaleY: 0.95
}, {
duration: 100
});
};
resetButton.up = function (x, y, obj) {
tween(resetButton, {
scaleX: 1,
scaleY: 1
}, {
duration: 100,
onFinish: function onFinish() {
if (self.onResetGame) {
self.onResetGame();
}
}
});
};
// Add some animation to the logo
function animateLogo() {
tween(gameLogo, {
y: gameLogo.y - 15
}, {
duration: 1500,
easing: tween.easeInOut,
onFinish: function onFinish() {
tween(gameLogo, {
y: gameLogo.y + 15
}, {
duration: 1500,
easing: tween.easeInOut,
onFinish: animateLogo
});
}
});
}
// Start the animation
animateLogo();
return self;
});
var MemoryCard = Container.expand(function (cardValue, cardBack) {
var self = Container.call(this);
self.value = cardValue; // Card match value
self.revealed = false; // Is card face up
self.matched = false; // Is card matched
// Create card front (colored shape)
self.front = LK.getAsset('memory_card_' + cardValue, {
anchorX: 0.5,
anchorY: 0.5
});
self.front.visible = false;
self.addChild(self.front);
// Create card back
self.back = LK.getAsset('memory_card_back', {
anchorX: 0.5,
anchorY: 0.5
});
self.addChild(self.back);
// Make card interactive
self.interactive = true;
// Flip card to show front
self.reveal = function () {
if (self.matched || self.revealed) {
return;
} // Already revealed or matched
self.revealed = true;
// Animate card flip
tween(self.scale, {
x: 0
}, {
duration: 150,
easing: tween.easeInQuad,
onFinish: function onFinish() {
self.front.visible = true;
self.back.visible = false;
tween(self.scale, {
x: 1
}, {
duration: 150,
easing: tween.easeOutQuad
});
}
});
if (self.onReveal) {
self.onReveal(self);
}
};
// Flip card to hide front
self.hide = function () {
if (self.matched) {
return;
} // Don't hide if matched
// Animate card flip
tween(self.scale, {
x: 0
}, {
duration: 150,
easing: tween.easeInQuad,
onFinish: function onFinish() {
self.front.visible = false;
self.back.visible = true;
self.revealed = false;
tween(self.scale, {
x: 1
}, {
duration: 150,
easing: tween.easeOutQuad
});
}
});
};
// Mark card as matched
self.setMatched = function () {
self.matched = true;
self.interactive = false;
// Flash effect for matching
tween(self, {
alpha: 0.5
}, {
duration: 200,
easing: tween.easeInQuad,
onFinish: function onFinish() {
tween(self, {
alpha: 1
}, {
duration: 200,
easing: tween.easeOutQuad
});
}
});
};
// Handle card click
self.down = function (x, y, obj) {
// If card is already matched, or not interactive, do nothing.
if (self.matched || !self.interactive) {
return;
}
// If card is already revealed (face up), do nothing on 'down'.
if (self.revealed) {
return;
}
// If two cards are already face up (checked via currentMemoryGame.canSelectCard()),
// do not allow this card (which is currently face down) to be pressed/animated.
// currentMemoryGame might be null if the game is not active, so check it.
if (currentMemoryGame && !currentMemoryGame.canSelectCard()) {
return;
}
// Card is face down, interactive, not matched, and we are allowed to select a card.
// Animate press down.
tween(self, {
scaleX: 0.95,
scaleY: 0.95
}, {
duration: 100
});
};
self.up = function (x, y, obj) {
// If card is already matched, or not interactive, do nothing.
if (self.matched || !self.interactive) {
return;
}
// If card is already revealed (face up), it means it was one of the selected cards.
// Clicking it again on 'up' should just restore its scale if it was pressed. No re-reveal.
if (self.revealed) {
tween(self, {
scaleX: 1,
scaleY: 1
}, {
duration: 100
}); // Restore scale
return;
}
// At this point, card is face down, interactive, and not matched.
// We need to check again if we are allowed to reveal it. This is a final gate.
// The 'down' action might have scaled it down.
// If currentMemoryGame is null or canSelectCard is false, just restore scale and don't reveal.
if (!currentMemoryGame || !currentMemoryGame.canSelectCard()) {
tween(self, {
scaleX: 1,
scaleY: 1
}, {
duration: 100
}); // Restore scale
return;
}
// Allowed to reveal. Animate scale back and then reveal.
tween(self, {
scaleX: 1,
scaleY: 1
}, {
duration: 100,
onFinish: function onFinish() {
self.reveal(); // self.reveal() has its own checks too.
}
});
};
return self;
});
var MemoryGame = Container.expand(function () {
var self = Container.call(this);
// Game state variables
var selectedCards = [];
var matchedPairs = 0;
var totalPairs = 8;
var canSelect = true;
var movesMade = 0;
// Create cards array
var cards = [];
// Create semi-transparent background
var gameBackground = LK.getAsset('pet_playing', {
anchorX: 0.5,
anchorY: 0.5,
width: 2000,
height: 2000,
tint: 0x000000
});
gameBackground.alpha = 0.7;
self.addChild(gameBackground);
// Title text
var titleText = new Text2("Memory Game", {
size: 80,
fill: 0xFFFFFF
});
titleText.anchor.set(0.5, 0.5);
titleText.y = -900;
self.addChild(titleText);
// Moves counter
var movesText = new Text2("Moves: 0", {
size: 60,
fill: 0xFFFFFF
});
movesText.anchor.set(0.5, 0.5);
movesText.y = -800;
self.addChild(movesText);
// Setup the game
self.startGame = function () {
currentMemoryGame = self; // Set the global reference
// Reset game state
selectedCards = [];
matchedPairs = 0;
movesMade = 0;
canSelect = true;
// Create card values (pairs of 1-8)
var values = [1, 1, 2, 2, 3, 3, 4, 4, 5, 5, 6, 6, 7, 7, 8, 8];
// Shuffle the array
for (var i = values.length - 1; i > 0; i--) {
var j = Math.floor(Math.random() * (i + 1));
var temp = values[i];
values[i] = values[j];
values[j] = temp;
}
// Create and position cards in a 4x4 grid
var gridSize = 4;
// Create a temp card to measure actual size
var tempCard = new MemoryCard(1);
// Calculate spacing based on actual card dimensions
var cardWidth = tempCard.back.width;
var cardHeight = tempCard.back.height;
var cardSpacing = cardWidth * 1.2; // Add 20% of width as spacing
var verticalSpacing = cardHeight * 1.4; // Add 40% of height as vertical spacing
// Calculate starting coordinates using actual card dimensions
var startX = -((gridSize - 1) * cardSpacing) / 2;
var startY = -((gridSize - 1) * verticalSpacing) / 2;
// Clean up temp card
tempCard = null;
for (var row = 0; row < gridSize; row++) {
for (var col = 0; col < gridSize; col++) {
var index = row * gridSize + col;
var card = new MemoryCard(values[index]);
// Position card in grid using dynamic spacing based on card size
card.x = startX + col * cardSpacing;
card.y = startY + row * verticalSpacing;
// Set up reveal callback
card.onReveal = handleCardReveal;
// Add to game
self.addChild(card);
cards.push(card);
}
}
// Update moves display
updateMovesText();
// Fade in animation
self.alpha = 0;
tween(self, {
alpha: 1
}, {
duration: 500
});
};
// Handle card reveal
function handleCardReveal(card) {
if (!canSelect) {
return;
}
// Add card to selected cards
selectedCards.push(card);
// If we have 2 cards selected
if (selectedCards.length === 2) {
canSelect = false;
movesMade++;
updateMovesText();
// Check for match
if (selectedCards[0].value === selectedCards[1].value) {
// Match found!
selectedCards[0].setMatched();
selectedCards[1].setMatched();
matchedPairs++;
// Clear selection
selectedCards = [];
canSelect = true;
// Check if game is complete
if (matchedPairs === totalPairs) {
// Game won!
LK.setTimeout(function () {
endGame();
}, 500);
}
} else {
// No match, flip cards back after a delay
LK.setTimeout(function () {
selectedCards[0].hide();
selectedCards[1].hide();
selectedCards = [];
canSelect = true;
}, 1000);
}
}
}
// Update moves text
function updateMovesText() {
movesText.setText("Moves: " + movesMade);
}
self.canSelectCard = function () {
return canSelect;
};
// End the game
function endGame() {
// Calculate score (higher for fewer moves)
var baseScore = 100;
var movesPenalty = Math.min(80, movesMade * 2);
var finalScore = Math.max(20, baseScore - movesPenalty);
// Show winning message
var winText = new Text2("Memory Game Complete!\nScore: " + finalScore, {
size: 80,
fill: 0xFFFFFF,
align: "center"
});
winText.anchor.set(0.5, 0.5);
self.addChild(winText);
// Animate text
winText.scale.set(0);
tween(winText.scale, {
x: 1,
y: 1
}, {
duration: 500,
easing: tween.elasticOut
});
// Close after delay
LK.setTimeout(function () {
// Fade out animation
tween(self, {
alpha: 0
}, {
duration: 500,
onFinish: function onFinish() {
if (self.onComplete) {
self.onComplete(finalScore);
}
currentMemoryGame = null; // Clear the global reference
// Remove all cards
for (var i = 0; i < cards.length; i++) {
self.removeChild(cards[i]);
}
cards = [];
// Remove win text
self.removeChild(winText);
// Remove self from parent
if (self.parent) {
self.parent.removeChild(self);
}
}
});
}, 2000);
}
// Close button
var closeButton = new Text2("X", {
size: 80,
fill: 0xFFFFFF
});
closeButton.anchor.set(0.5, 0.5);
closeButton.x = 900;
closeButton.y = -900;
closeButton.interactive = true;
self.addChild(closeButton);
closeButton.down = function () {
tween(closeButton, {
scaleX: 0.9,
scaleY: 0.9
}, {
duration: 100
});
};
closeButton.up = function () {
tween(closeButton, {
scaleX: 1,
scaleY: 1
}, {
duration: 100,
onFinish: function onFinish() {
// Fade out and close
tween(self, {
alpha: 0
}, {
duration: 300,
onFinish: function onFinish() {
// Calculate partial score
var partialScore = Math.max(5, matchedPairs * 10);
if (self.onComplete) {
self.onComplete(partialScore);
}
currentMemoryGame = null; // Clear the global reference
// Remove all cards
for (var i = 0; i < cards.length; i++) {
self.removeChild(cards[i]);
}
cards = [];
// Remove self from parent
if (self.parent) {
self.parent.removeChild(self);
}
}
});
}
});
};
// Center the game on screen
self.x = 2048 / 2;
self.y = 2732 / 2;
// Start the game
self.startGame();
return self;
});
var NameSelect = Container.expand(function (petType) {
var self = Container.call(this);
var petName = "";
self.petType = petType;
// Background setup
var background = self.attachAsset('menu_background', {
anchorX: 0.5,
anchorY: 0.5
});
background.x = 2048 / 2;
background.y = 2732 / 2;
// Title text
var titleText = new Text2("Name Your Pet", {
size: 100,
fill: 0xFFFFFF
});
titleText.anchor.set(0.5, 0.5);
titleText.x = 2048 / 2;
titleText.y = 500;
self.addChild(titleText);
// Add selected pet preview
var petPreview = self.attachAsset(petType === 'Fluffy' ? 'pet_select_1' : 'pet_select_2', {
anchorX: 0.5,
anchorY: 0.5,
x: 2048 / 2,
y: 2732 / 2 - 300
});
// Name input display
var nameDisplay = new Text2("_", {
size: 80,
fill: 0xFFFFFF
});
nameDisplay.anchor.set(0.5, 0.5);
nameDisplay.x = 2048 / 2;
nameDisplay.y = 2732 / 2 + 100;
self.addChild(nameDisplay);
// Instruction text
var instructionText = new Text2("Tap letters to name your pet", {
size: 60,
fill: 0xFFFFFF
});
instructionText.anchor.set(0.5, 0.5);
instructionText.x = 2048 / 2;
instructionText.y = 2732 / 2 + 200;
self.addChild(instructionText);
// Create keyboard layout
var keyboard = new Container();
keyboard.x = 2048 / 2;
keyboard.y = 2732 / 2 + 400;
self.addChild(keyboard);
// Define keyboard characters
var keys = ["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", "⌫"];
// Create keyboard buttons
var keySize = 150;
var keysPerRow = 7;
var keySpacing = 15;
for (var i = 0; i < keys.length; i++) {
var row = Math.floor(i / keysPerRow);
var col = i % keysPerRow;
// Create key background
var keyBg = LK.getAsset('progressBar_bg', {
anchorX: 0.5,
anchorY: 0.5,
width: keySize,
height: keySize,
tint: keys[i] === "⌫" ? 0xFF6B6B : 0x70a1ff
});
// Create key text
var keyText = new Text2(keys[i], {
size: 60,
fill: 0xFFFFFF
});
keyText.anchor.set(0.5, 0.5);
// Create key container
var key = new Container();
key.addChild(keyBg);
key.addChild(keyText);
key.x = (col - keysPerRow / 2) * (keySize + keySpacing);
key.y = row * (keySize + keySpacing);
key.keyValue = keys[i];
key.interactive = true;
// Key interactions
key.down = function (x, y, obj) {
tween(this, {
scaleX: 0.9,
scaleY: 0.9
}, {
duration: 100
});
};
key.up = function (x, y, obj) {
var keyValue = this.keyValue;
tween(this, {
scaleX: 1,
scaleY: 1
}, {
duration: 100,
onFinish: function onFinish() {
// Handle backspace
if (keyValue === "⌫") {
if (petName.length > 0) {
petName = petName.slice(0, -1);
}
}
// Add letter if name is less than 10 characters
else if (petName.length < 10) {
petName += keyValue;
}
// Update name display
nameDisplay.setText(petName + "_");
}
});
};
keyboard.addChild(key);
}
// Done button
var doneButton = new Container();
var doneBg = LK.getAsset('progressBar_bg', {
anchorX: 0.5,
anchorY: 0.5,
width: 300,
height: 100,
tint: 0x7bed9f
});
var doneText = new Text2("DONE", {
size: 70,
fill: 0xFFFFFF
});
doneText.anchor.set(0.5, 0.5);
doneButton.addChild(doneBg);
doneButton.addChild(doneText);
doneButton.x = 2048 / 2;
doneButton.y = 2732 / 2 + 1200;
doneButton.interactive = true;
self.addChild(doneButton);
doneButton.down = function (x, y, obj) {
tween(doneButton, {
scaleX: 0.95,
scaleY: 0.95
}, {
duration: 100
});
};
doneButton.up = function (x, y, obj) {
tween(doneButton, {
scaleX: 1,
scaleY: 1
}, {
duration: 100,
onFinish: function onFinish() {
// Use default name if empty
if (petName.length === 0) {
petName = self.petType;
}
if (self.onNameSelected) {
self.onNameSelected(petName);
}
}
});
};
return self;
});
var Pet = Container.expand(function () {
var self = Container.call(this);
var currentLevel = storage.petLevel || 1;
var petName = storage.petName || "Pet";
var petType = storage.petType || "Fluffy";
var petAssetId = 'pet_baby';
// Determine which asset to use based on level and pet type
if (petType === "Puffy") {
if (currentLevel === 1) {
petAssetId = 'pet_puffy_baby';
} else if (currentLevel === 2) {
petAssetId = 'pet_puffy_child';
} else if (currentLevel === 3) {
petAssetId = 'pet_puffy_teen';
} else if (currentLevel >= 4) {
petAssetId = 'pet_puffy_adult';
}
} else {
// Default for Fluffy pet
if (currentLevel === 1) {
petAssetId = 'pet_baby';
} else if (currentLevel === 2) {
petAssetId = 'pet_child';
} else if (currentLevel === 3) {
petAssetId = 'pet_teen';
} else if (currentLevel >= 4) {
petAssetId = 'pet_adult';
}
}
var petGraphics = self.attachAsset(petAssetId, {
anchorX: 0.5,
anchorY: 0.5
});
// Add pet name display
var nameText = new Text2(petName, {
size: 50,
fill: 0xFFFFFF
});
nameText.anchor.set(0.5, 0.5);
nameText.y = -petGraphics.height / 2 - 40; // Initial position above pet
self.addChild(nameText);
// Method to reposition name to appear above level text
self.positionNameAboveLevel = function () {
// Remove from pet container
self.removeChild(nameText);
// Add directly to game container so it can be positioned independently
game.addChild(nameText);
// Position above level text
nameText.x = 2048 / 2;
nameText.y = 120; // Position above level text
};
self.happy = function () {
// Bounce animation
tween(self, {
y: self.y - 50
}, {
duration: 300,
easing: tween.easeOut,
onFinish: function onFinish() {
tween(self, {
y: self.y + 50
}, {
duration: 300,
easing: tween.bounceOut,
onFinish: function onFinish() {
petPosition.x = self.x;
petPosition.y = self.y;
}
});
}
});
};
self.evolve = function () {
// Evolution animation
LK.getSound('evolve').play();
// Flash and grow
LK.effects.flashObject(self, 0xFFFFFF, 1000);
tween(petGraphics, {
scaleX: 1.5,
scaleY: 1.5
}, {
duration: 500,
easing: tween.easeOut,
onFinish: function onFinish() {
// Update to new visual based on new level
currentLevel = storage.petLevel;
var newPetAssetId;
var petType = storage.petType || "Fluffy";
if (petType === "Puffy") {
if (currentLevel === 2) {
newPetAssetId = 'pet_puffy_child';
} else if (currentLevel === 3) {
newPetAssetId = 'pet_puffy_teen';
} else if (currentLevel >= 4) {
newPetAssetId = 'pet_puffy_adult';
}
} else {
// Default for Fluffy pet
if (currentLevel === 2) {
newPetAssetId = 'pet_child';
} else if (currentLevel === 3) {
newPetAssetId = 'pet_teen';
} else if (currentLevel >= 4) {
newPetAssetId = 'pet_adult';
}
}
// Remove old graphic and add new one
self.removeChild(petGraphics);
petGraphics = self.attachAsset(newPetAssetId, {
anchorX: 0.5,
anchorY: 0.5,
scaleX: 1.5,
scaleY: 1.5
});
// Reset scale with animation
tween(petGraphics, {
scaleX: 1,
scaleY: 1
}, {
duration: 300,
easing: tween.easeOut
});
}
});
};
return self;
});
var Poop = Container.expand(function () {
var self = Container.call(this);
// Create poop visual using a single image
var poopGraphics = self.attachAsset('centerCircle', {
anchorX: 0.5,
anchorY: 0.5,
scaleX: 1,
scaleY: 1,
tint: 0x8B4513 // Brown color
});
// Add appear animation
self.appear = function () {
self.scale.set(0);
tween(self, {
scaleX: 1,
scaleY: 1
}, {
duration: 300,
easing: tween.bounceOut
});
};
// Add cleanup animation
self.cleanup = function (callback) {
tween(self, {
alpha: 0,
scaleX: 0.5,
scaleY: 0.5
}, {
duration: 300,
easing: tween.easeInBack,
onFinish: function onFinish() {
if (callback) {
callback();
}
}
});
};
return self;
});
var StatusText = Text2.expand(function (initialText) {
var self = Text2.call(this, initialText, {
size: 60,
fill: 0xFFFFFF
});
self.anchor.set(0.5, 0.5);
self.showMessage = function (message) {
self.setText(message);
self.alpha = 1;
tween(self, {
alpha: 0
}, {
duration: 3000,
easing: tween.linear
});
};
return self;
});
/****
* Initialize Game
****/
var game = new LK.Game({
backgroundColor: 0x7ED6DF
});
/****
* Game Code
****/
// Game state - load these first
var petLevel = storage.petLevel || 1;
var petXp = storage.petXp || 0;
var lastFed = storage.lastFed || 0;
var lastCleaned = storage.lastCleaned || 0;
var lastPlayed = storage.lastPlayed || 0;
// Load pet state flags from storage
var isHungry = false;
var isBored = false;
var hasActivePoop = false;
var canFeedPet = false;
var canPlayPet = false;
var canCleanPet = false;
var speechBubble; // Variable for the speech bubble
// Timers and intervals for needs
var needTimer = null;
var needTimeout = null;
var hungerTimer = null; // Added to fix 'hungerTimer is not defined'
var boredTimer = null; // Added to fix 'boredTimer is not defined'
var XP_LOSS_TIMEOUT = 60000; // 1 minute
var POOP_SPEECH_TIMEOUT = 30000; // 30 seconds
var POOP_XP_LOSS_TIMEOUT = 60000; // 1 minute
var BORED_XP_LOSS_TIMEOUT = 90000; // 1.5 minutes
var XP_LOSS_INTERVAL = 90000; // 1.5 minutes interval for XP loss if player doesn't play with pet
var xpLossTimer; // Timer for XP loss after not feeding
var XP_LOSS_AMOUNT = 50; // Amount of XP to lose
var poopTimer; // Timer for when pet will poop
var activePoop = null; // Reference to the active poop object
var poopSpeechTimer; // Timer for poop speech bubble
var poopXpLossTimer; // Timer for XP loss from uncleaned poop
var boredXpLossTimer; // Timer for XP loss when bored
// Define game constants - calculate after loading state
var BASE_XP_PER_LEVEL = 500;
var XP_PER_LEVEL = BASE_XP_PER_LEVEL * Math.pow(2, petLevel - 1); // Doubles with each level
var XP_GAIN_FEED = 20;
var XP_GAIN_CLEAN = 15;
var XP_GAIN_PLAY = 25;
var COOLDOWN_TIME = 10000; // 10 seconds cooldown between actions
var PLAY_INACTIVITY_XP_LOSS = 15; // Amount of XP to lose from play inactivity
var playInactivityInterval; // Interval for recurring XP loss due to play inactivity
var hpText; // Define hpText in global scope
var barFill; // Define barFill in global scope
var barBackground; // Define barBackground in global scope
// Track which need is currently active
var currentNeed = null; // "hunger", "boredom", "poop"
// New: For random need logic
var NEEDS = ["hunger", "boredom", "poop"];
// Vector2 positions for pet at different evolution levels
var petBabyPosition = {
x: 2048 / 2,
y: 2732 / 2 + 250
};
var petChildPosition = {
x: 2048 / 2,
y: 2732 / 2 + 200
};
var petTeenPosition = {
x: 2048 / 2,
y: 2732 / 2 + 150
};
var petAdultPosition = {
x: 2048 / 2,
y: 2732 / 2 + 150
};
// Track current game state
var progressBar = new Container();
var currentScreen = "menu";
var mainMenu, pet, progressBar, statusText, levelText;
var currentMemoryGame = null; // To hold the active MemoryGame instance
var isMemoryGameActive = false; // Track if memory game is active
var feedButton, cleanButton, playButton;
var progressBarContainer = new Container();
// Current pet position based on level
var petPosition = petBabyPosition;
// Initialize menu
function initMainMenu() {
LK.playMusic('bgmusic');
// Clear previous game elements if they exist
clearGameElements();
// Always show main menu first
mainMenu = new MainMenu();
game.addChild(mainMenu);
// Set up callbacks
setupMainMenuCallbacks();
// Function to set up main menu callbacks
function setupMainMenuCallbacks() {
// Set up start game callback
mainMenu.onStartGame = function () {
// Check if it's first time playing or reset game
if (!storage.petName) {
// First time playing, transition to character select
tween(mainMenu, {
alpha: 0
}, {
duration: 300,
onFinish: function onFinish() {
game.removeChild(mainMenu);
// Show character select screen
var characterSelect = new CharacterSelect();
game.addChild(characterSelect);
// Handle character selection
characterSelect.onSelectCharacter = function (selectedPetType) {
// Show name selection screen
tween(characterSelect, {
alpha: 0
}, {
duration: 300,
onFinish: function onFinish() {
game.removeChild(characterSelect);
// Create name selection screen
var nameSelect = new NameSelect(selectedPetType);
game.addChild(nameSelect);
// Handle name selection
nameSelect.onNameSelected = function (selectedName) {
// Save the selected name
storage.petName = selectedName;
// Hide name select and start game
tween(nameSelect, {
alpha: 0
}, {
duration: 300,
onFinish: function onFinish() {
game.removeChild(nameSelect);
// Now start the game
currentScreen = "game";
initGameScreen();
}
});
};
}
});
};
}
});
} else {
// Returning player with saved data, go directly to gameplay
currentScreen = "game";
initGameScreen();
}
};
// Set up reset game callback
mainMenu.onResetGame = function () {
// Reset all storage values
storage.petLevel = 1;
storage.petXp = 0;
petXp = 0; // Reset the current petXp value
storage.lastFed = 0;
storage.lastCleaned = 0;
storage.lastPlayed = 0;
storage.isHungry = false;
storage.isBored = false;
storage.hasActivePoop = false;
storage.petName = null; // Reset pet name to trigger character select again
// Show confirmation text
var confirmText = new Text2("Game data reset!", {
size: 60,
fill: 0xFFFFFF
});
confirmText.anchor.set(0.5, 0.5);
confirmText.x = 2048 / 2;
confirmText.y = 2732 / 2 + 500;
mainMenu.addChild(confirmText);
// Fade out confirmation text
tween(confirmText, {
alpha: 0
}, {
duration: 2000,
onFinish: function onFinish() {
mainMenu.removeChild(confirmText);
}
});
};
}
}
// This function is now defined inside initMainMenu
// Initialize game screen
function initGameScreen() {
console.log("Initializing game screen");
// Clear previous elements
clearGameElements();
// Add game background
var gameBackground = LK.getAsset('game_background', {
anchorX: 0.5,
anchorY: 0.5
});
gameBackground.x = 2048 / 2;
gameBackground.y = 2732 / 2;
game.addChild(gameBackground);
// Create game elements
pet = new Pet();
pet.x = petPosition.x;
pet.y = petPosition.y;
game.addChild(pet);
// Position pet name above level text
pet.positionNameAboveLevel();
// Add mechanic: show image above and left of pet when clicked, and allow XP gain on image click every 5s
var petClickImage = null;
var lastPetClickImageXpTime = 0; // Track last time XP was given from image
pet.interactive = true;
pet.down = function (x, y, obj) {
// Remove previous image if exists
if (petClickImage && petClickImage.parent) {
petClickImage.parent.removeChild(petClickImage);
petClickImage = null;
}
// Create the image (now using 'cheer_image' for cheering)
petClickImage = LK.getAsset('cheer_image', {
anchorX: 0.5,
anchorY: 0.5,
width: 400,
height: 400
});
// Position above and left of pet
petClickImage.x = pet.x - pet.width / 2 - 100;
petClickImage.y = pet.y - pet.height / 2 - 100;
game.addChild(petClickImage);
// Animate in (optional)
petClickImage.alpha = 0;
tween(petClickImage, {
alpha: 1
}, {
duration: 200
});
// Add interaction to the image for XP gain
petClickImage.interactive = true;
petClickImage.down = function (x2, y2, obj2) {
// Visual feedback for press
tween(petClickImage, {
scaleX: 0.9,
scaleY: 0.9
}, {
duration: 80
});
};
petClickImage.up = function (x2, y2, obj2) {
// Prevent cheering if memory game is active
if (isMemoryGameActive) {
statusText.showMessage("Finish the memory game first!");
return;
}
// Restore scale
tween(petClickImage, {
scaleX: 1,
scaleY: 1
}, {
duration: 80
});
var now = Date.now();
if (!lastPetClickImageXpTime || now - lastPetClickImageXpTime >= 5000) {
addXp(15);
statusText.showMessage("Pet is happy! +15 XP");
lastPetClickImageXpTime = now;
// Pet reacts (bounce/happy animation)
if (pet && typeof pet.happy === "function") {
pet.happy();
}
} else {
statusText.showMessage("Wait before cheering again!");
}
};
// Hide after 1.5 seconds
LK.setTimeout(function () {
if (petClickImage && petClickImage.parent) {
tween(petClickImage, {
alpha: 0
}, {
duration: 200,
onFinish: function onFinish() {
if (petClickImage && petClickImage.parent) {
petClickImage.parent.removeChild(petClickImage);
petClickImage = null;
}
}
});
}
}, 1500);
};
// Level text
levelText = new Text2("Level " + petLevel, {
size: 80,
fill: 0xFFFFFF
});
levelText.anchor.set(0.5, 0.5);
levelText.x = 2048 / 2;
levelText.y = 200;
game.addChild(levelText);
// Create action buttons
feedButton = new ActionButton('feed');
feedButton.x = 2048 / 4;
feedButton.y = 2732 - 400;
game.addChild(feedButton);
cleanButton = new ActionButton('clean');
cleanButton.x = 2048 / 2;
cleanButton.y = 2732 - 400;
game.addChild(cleanButton);
playButton = new ActionButton('play');
playButton.x = 2048 * 3 / 4;
playButton.y = 2732 - 400;
game.addChild(playButton);
// Recalculate XP_PER_LEVEL based on current level
XP_PER_LEVEL = BASE_XP_PER_LEVEL * Math.pow(2, petLevel - 1);
console.log("Current petLevel:", petLevel, "XP_PER_LEVEL:", XP_PER_LEVEL);
// Make sure all values are calculated before updating progress bar
XP_PER_LEVEL = BASE_XP_PER_LEVEL * Math.pow(2, petLevel - 1);
// Update the progress bar on start
console.log("Initial progress bar update with petXp:", petXp, "XP_PER_LEVEL:", XP_PER_LEVEL);
// Make sure variables are initialized properly
petXp = petXp || 0;
XP_PER_LEVEL = XP_PER_LEVEL || BASE_XP_PER_LEVEL;
// Now create HP text after progress bar exists
hpText = new Text2("XP: " + petXp + "/" + XP_PER_LEVEL, {
size: 60,
fill: 0xFFFFFF
});
hpText.anchor.set(0, 0.5);
hpText.x = progressBar.x + 10;
hpText.y = progressBar.y - 50;
game.addChild(hpText);
// Create HP text display
console.log("Creating HP text with petXp:", petXp, "XP_PER_LEVEL:", XP_PER_LEVEL);
hpText = new Text2("XP: " + petXp + "/" + XP_PER_LEVEL, {
size: 60,
fill: 0xFFFFFF
});
hpText.anchor.set(0, 0.5);
game.addChild(hpText);
console.log("Game screen initialization complete");
createProgressBar();
addBarFillXp();
// Status text
statusText = new StatusText("");
statusText.x = 2048 / 2;
statusText.y = progressBar.y + 100;
statusText.alpha = 0;
game.addChild(statusText);
// Create speech bubble for needs
speechBubble = new BubbleSpeech("");
speechBubble.x = pet.x + 450;
speechBubble.y = pet.y - 450; // Position above pet
speechBubble.alpha = 0; // Start invisible
game.addChild(speechBubble);
// Helper: clear any need timers
function clearNeedTimers() {
if (needTimer) {
LK.clearTimeout(needTimer);
needTimer = null;
}
if (needTimeout) {
LK.clearTimeout(needTimeout);
needTimeout = null;
}
if (xpLossTimer) {
LK.clearTimeout(xpLossTimer);
xpLossTimer = null;
}
if (boredXpLossTimer) {
LK.clearTimeout(boredXpLossTimer);
boredXpLossTimer = null;
}
if (playInactivityInterval) {
LK.clearInterval(playInactivityInterval);
playInactivityInterval = null;
}
if (poopSpeechTimer) {
LK.clearTimeout(poopSpeechTimer);
poopSpeechTimer = null;
}
if (poopXpLossTimer) {
LK.clearTimeout(poopXpLossTimer);
poopXpLossTimer = null;
}
}
// Helper: pick a random need
function pickRandomNeed() {
// If there is active poop, always return "poop"
if (activePoop) {
return "poop";
}
// Otherwise, pick randomly from the 3 needs
var idx = Math.floor(Math.random() * NEEDS.length);
return NEEDS[idx];
}
// Main: show a random need every 5-10 seconds
function showRandomNeed() {
// If memory game is active, wait and try again later
if (isMemoryGameActive) {
// Try again in 2 seconds
needTimer = LK.setTimeout(function () {
showRandomNeed();
}, 2000);
return;
}
clearNeedTimers();
// Pick a random need
var need = pickRandomNeed();
currentNeed = need;
canFeedPet = false;
canPlayPet = false;
canCleanPet = false;
isHungry = false;
isBored = false;
// Show the bubble and set the action variable
if (need === "hunger") {
speechBubble.setText("I'm hungry!");
speechBubble.show(500);
canFeedPet = true;
isHungry = true;
// XP loss if ignored
xpLossTimer = LK.setTimeout(function () {
if (petXp > 0) {
addXp(-XP_LOSS_AMOUNT);
statusText.showMessage("Pet is hungry! Lost " + XP_LOSS_AMOUNT + " XP!");
}
}, XP_LOSS_TIMEOUT);
} else if (need === "boredom") {
speechBubble.setText("I'm bored! \nPlay with me!");
speechBubble.show(500);
canPlayPet = true;
isBored = true;
// XP loss if ignored
boredXpLossTimer = LK.setTimeout(function () {
if (petXp > 0) {
addXp(-XP_LOSS_AMOUNT);
statusText.showMessage("Pet is bored! Lost " + XP_LOSS_AMOUNT + " XP!");
}
}, BORED_XP_LOSS_TIMEOUT);
// Play inactivity XP loss
playInactivityInterval = LK.setInterval(function () {
var currentTime = Date.now();
var timeSinceLastPlayed = currentTime - lastPlayed;
if (timeSinceLastPlayed > 300000 && petXp > 0) {
addXp(-PLAY_INACTIVITY_XP_LOSS);
statusText.showMessage("Your pet misses you! Lost " + PLAY_INACTIVITY_XP_LOSS + " XP!");
speechBubble.setText("I miss \nplaying \nwith you!");
speechBubble.show(500);
LK.setTimeout(function () {
speechBubble.hide(300);
}, 3000);
}
}, XP_LOSS_INTERVAL);
} else if (need === "poop") {
// If no active poop, spawn one
if (!activePoop) {
activePoop = new Poop();
activePoop.x = pet.x + 900;
activePoop.y = pet.y + 200;
game.addChild(activePoop);
activePoop.appear();
}
speechBubble.setText("Please clean \nthis mess!");
speechBubble.show(500);
canCleanPet = true;
// XP loss if ignored
poopXpLossTimer = LK.setTimeout(function () {
var loseXpInterval = LK.setInterval(function () {
if (activePoop) {
if (petXp > 0) {
addXp(-XP_LOSS_AMOUNT);
statusText.showMessage("Pet uncomfortable! Lost " + XP_LOSS_AMOUNT + " XP!");
speechBubble.setText("This mess \nis making \nme lose XP!");
speechBubble.show(500);
LK.setTimeout(function () {
speechBubble.hide(300);
}, 3000);
}
} else {
LK.clearInterval(loseXpInterval);
}
}, POOP_XP_LOSS_TIMEOUT);
}, POOP_XP_LOSS_TIMEOUT);
}
// Schedule next need
var nextDelay = 5000 + Math.floor(Math.random() * 5000); // 5-10s
needTimer = LK.setTimeout(function () {
showRandomNeed();
}, nextDelay);
}
// If there was an active poop, restore it
if (activePoop) {
activePoop = new Poop();
activePoop.x = pet.x + Math.random() * 1000;
activePoop.y = pet.y + 100 + Math.random() * 50;
game.addChild(activePoop);
activePoop.appear();
}
// Start the random need loop
showRandomNeed();
} //[3J]
// Clear all game elements
// Function to stop a specific timer by name
function stopTimer(timerName) {
// Check if timer name is valid before attempting to stop
if (!timerName) {
console.log("Cannot stop timer: timer name is undefined or null");
return;
}
if (timerName === 'hunger' && hungerTimer) {
LK.clearTimeout(hungerTimer);
hungerTimer = null;
console.log("Hunger timer stopped");
} else if (timerName === 'xpLoss' && xpLossTimer) {
LK.clearTimeout(xpLossTimer);
xpLossTimer = null;
console.log("XP loss timer stopped");
} else if (timerName === 'poop' && poopTimer) {
LK.clearTimeout(poopTimer);
poopTimer = null;
console.log("Poop timer stopped");
} else if (timerName === 'poopSpeech' && poopSpeechTimer) {
LK.clearTimeout(poopSpeechTimer);
poopSpeechTimer = null;
console.log("Poop speech timer stopped");
} else if (timerName === 'poopXpLoss' && poopXpLossTimer) {
LK.clearTimeout(poopXpLossTimer);
poopXpLossTimer = null;
console.log("Poop XP loss timer stopped");
} else if (timerName === 'bored' && boredTimer) {
LK.clearTimeout(boredTimer);
boredTimer = null;
console.log("Bored timer stopped");
} else if (timerName === 'boredXpLoss' && boredXpLossTimer) {
LK.clearTimeout(boredXpLossTimer);
boredXpLossTimer = null;
console.log("Bored XP loss timer stopped");
} else if (timerName === 'playInactivity' && playInactivityInterval) {
LK.clearInterval(playInactivityInterval);
playInactivityInterval = null;
console.log("Play inactivity interval stopped");
} else {
console.log("Timer not found or already stopped: " + timerName);
}
}
function clearGameElements() {
// Clear hunger timer if exists
if (hungerTimer) {
LK.clearTimeout(hungerTimer);
hungerTimer = null;
}
// Clear hunger speech bubble interval if exists
if (typeof hungerSpeechBubbleInterval !== "undefined" && hungerSpeechBubbleInterval) {
LK.clearInterval(hungerSpeechBubbleInterval);
hungerSpeechBubbleInterval = null;
}
// Clear XP loss timer if exists
if (xpLossTimer) {
LK.clearTimeout(xpLossTimer);
xpLossTimer = null;
}
// Clear poop timer if exists
if (poopTimer) {
LK.clearTimeout(poopTimer);
poopTimer = null;
}
// Clear poop speech timer if exists
if (poopSpeechTimer) {
LK.clearTimeout(poopSpeechTimer);
poopSpeechTimer = null;
}
// Clear poop XP loss timer if exists
if (poopXpLossTimer) {
LK.clearTimeout(poopXpLossTimer);
poopXpLossTimer = null;
}
// Clear bored timer if exists
if (boredTimer) {
LK.clearTimeout(boredTimer);
boredTimer = null;
}
// Clear bored XP loss timer if exists
if (boredXpLossTimer) {
LK.clearTimeout(boredXpLossTimer);
boredXpLossTimer = null;
}
// Clear play inactivity interval if exists
if (playInactivityInterval) {
LK.clearInterval(playInactivityInterval);
playInactivityInterval = null;
}
// Reset active poop reference
activePoop = null;
while (game.children.length > 0) {
game.removeChild(game.children[0]);
} //[3K]
} //[3L]
// Start with main menu
initMainMenu();
function performFeedAction() {
console.log("performFeedAction called");
var currentTime = Date.now(); //[3O]
// Check if pet is recently fed (on cooldown)
if (currentTime - lastFed < COOLDOWN_TIME) {
statusText.showMessage("Pet is still full! Wait a moment.");
console.log("Action on cooldown, can't feed yet");
return; //[3P]
} //[3Q]
// Check if feeding is allowed using canFeedPet variable
if (!canFeedPet) {
statusText.showMessage("Pet isn't hungry yet!");
console.log("Pet can't be fed yet - canFeedPet is false");
return;
}
// If hunger message is showing, we can feed the pet
if (speechBubble && speechBubble.alpha > 0 && speechBubble.text === "I'm hungry!") {
// Pet is hungry with message showing, continue with feeding
} else if (!canFeedPet) {
statusText.showMessage("Pet isn't hungry yet!");
console.log("Pet isn't hungry yet");
return;
}
console.log("Feeding pet, adding XP:", XP_GAIN_FEED);
LK.getSound('feed').play();
pet.happy(); //[3R]
lastFed = currentTime;
storage.lastFed = lastFed;
addXp(XP_GAIN_FEED);
console.log("After addXp call");
statusText.showMessage("Pet fed! +20 XP");
// Set canFeedPet to false after feeding
canFeedPet = false;
// Update hunger state in storage
storage.isHungry = false;
// Hide hunger speech bubble if visible and it's showing the hunger message
if (speechBubble && speechBubble.alpha > 0 && speechBubble.text === "I'm hungry!") {
speechBubble.hide(300);
}
// Clear the repeated hunger speech bubble interval if it exists
if (typeof hungerSpeechBubbleInterval !== "undefined" && hungerSpeechBubbleInterval) {
LK.clearInterval(hungerSpeechBubbleInterval);
hungerSpeechBubbleInterval = null;
}
// Reset hunger timer
if (hungerTimer) {
LK.clearTimeout(hungerTimer);
}
hungerTimer = LK.setTimeout(function () {
// Show speech bubble with animation
speechBubble.show(500);
// Set canFeedPet to true when hunger message appears again
canFeedPet = true;
// Update hunger state in storage
storage.isHungry = true;
console.log("Pet is hungry again - canFeedPet set to true");
}, 60000);
// Reset XP loss timer when feeding
if (xpLossTimer) {
LK.clearTimeout(xpLossTimer);
}
xpLossTimer = LK.setTimeout(function () {
if (petXp > 0) {
addXp(-XP_LOSS_AMOUNT);
statusText.showMessage("Pet is hungry! Lost " + XP_LOSS_AMOUNT + " XP!");
}
}, XP_LOSS_TIMEOUT);
// Set timer for pet to poop 15 seconds after being fed every time
if (poopTimer) {
LK.clearTimeout(poopTimer);
}
poopTimer = LK.setTimeout(function () {
// Only create poop if there isn't one already
if (!activePoop) {
// Create new poop slightly behind the pet
activePoop = new Poop();
activePoop.x = pet.x + 1000; // Random position near pet
activePoop.y = pet.y + 200;
game.addChild(activePoop);
activePoop.appear();
// Update poop state in storage
storage.hasActivePoop = true;
// Create a speech bubble for the poop event
speechBubble.setText("I made \na mess!");
speechBubble.show(500);
// Hide speech bubble after 3 seconds
LK.setTimeout(function () {
speechBubble.hide(300);
}, 3000);
// Set timer to show clean up reminder after 1 minute
if (poopSpeechTimer) {
LK.clearTimeout(poopSpeechTimer);
}
poopSpeechTimer = LK.setTimeout(function () {
speechBubble.setText("Please clean \nthis mess!");
speechBubble.show(500);
}, POOP_SPEECH_TIMEOUT);
// Set timer for XP loss after 2 minutes of not cleaning
if (poopXpLossTimer) {
LK.clearTimeout(poopXpLossTimer);
}
poopXpLossTimer = LK.setTimeout(function () {
// Set up recurring XP loss every 2 minutes until cleaned
var loseXpInterval = LK.setInterval(function () {
if (activePoop) {
if (petXp > 0) {
addXp(-XP_LOSS_AMOUNT);
statusText.showMessage("Pet uncomfortable! Lost " + XP_LOSS_AMOUNT + " XP!");
// Show speech bubble about being uncomfortable
speechBubble.setText("This mess \nis making \nme lose XP!");
speechBubble.show(500);
LK.setTimeout(function () {
speechBubble.hide(300);
}, 3000);
}
} else {
// Clear interval if poop is gone
LK.clearInterval(loseXpInterval);
}
}, POOP_XP_LOSS_TIMEOUT);
}, POOP_XP_LOSS_TIMEOUT);
}
}, 15000); // Always 15 seconds after eating
} //[3S]
function performCleanAction() {
var currentTime = Date.now();
if (currentTime - lastCleaned < COOLDOWN_TIME) {
statusText.showMessage("Pet is already clean! Wait a moment.");
return;
}
// Check if there's poop to clean
if (activePoop) {
LK.getSound('clean').play();
pet.happy();
lastCleaned = currentTime;
storage.lastCleaned = lastCleaned;
// Add extra XP for cleaning poop
addXp(XP_GAIN_CLEAN * 2);
statusText.showMessage("Poop cleaned! +30 XP");
// Animate poop cleanup
activePoop.cleanup(function () {
if (activePoop && activePoop.parent) {
activePoop.parent.removeChild(activePoop);
}
// Clear poop speech bubble timer
if (poopSpeechTimer) {
LK.clearTimeout(poopSpeechTimer);
poopSpeechTimer = null;
}
// Clear poop XP loss timer
if (poopXpLossTimer) {
LK.clearTimeout(poopXpLossTimer);
poopXpLossTimer = null;
}
activePoop = null;
// Update poop state in storage
storage.hasActivePoop = false;
});
// Pet is happy about cleaning
LK.setTimeout(function () {
// Save previous speech bubble text so we know if it was about cleaning
var previousText = speechBubble.text;
speechBubble.setText("Thank you!");
speechBubble.show(500);
// Hide speech bubble after 2 seconds, but only if it was about cleaning
LK.setTimeout(function () {
// Only hide if we had shown the thank you message from cleaning
if (speechBubble.text === "Thank you!" && (previousText === "Please clean \nthis mess!" || previousText === "I made \na mess!" || previousText === "This mess \nis making \nme lose XP!")) {
speechBubble.hide(300);
}
}, 2000);
}, 500);
} else {
// Don't allow cleaning if there's no poop
statusText.showMessage("Nothing to clean right now!");
}
}
function performPlayAction() {
var currentTime = Date.now();
if (currentTime - lastPlayed < COOLDOWN_TIME) {
statusText.showMessage("Pet is tired! Wait a moment.");
return;
}
// Check if playing is allowed using canPlayPet variable
if (!canPlayPet) {
statusText.showMessage("Pet isn't bored yet!");
console.log("Pet can't be played with yet - canPlayPet is false");
return;
}
// If pet is bored with message showing, proceed with playing
// Otherwise, we'll still allow one play action before requiring the boredom message
LK.getSound('play').play();
pet.happy();
lastPlayed = currentTime;
storage.lastPlayed = lastPlayed;
// Launch memory game instead of immediately adding XP
speechBubble.setText("Let's play a \nmemory \ngame!");
speechBubble.show(500);
// Pause all timers before starting memory game
var savedTimers = {
hungerTimer: hungerTimer,
xpLossTimer: xpLossTimer,
boredTimer: boredTimer,
boredXpLossTimer: boredXpLossTimer,
poopTimer: poopTimer,
poopSpeechTimer: poopSpeechTimer,
poopXpLossTimer: poopXpLossTimer
};
// Clear all active timers
if (hungerTimer) {
LK.clearTimeout(hungerTimer);
}
if (xpLossTimer) {
LK.clearTimeout(xpLossTimer);
}
if (boredTimer) {
LK.clearTimeout(boredTimer);
}
if (boredXpLossTimer) {
LK.clearTimeout(boredXpLossTimer);
}
if (poopTimer) {
LK.clearTimeout(poopTimer);
}
if (poopSpeechTimer) {
LK.clearTimeout(poopSpeechTimer);
}
if (poopXpLossTimer) {
LK.clearTimeout(poopXpLossTimer);
}
if (playInactivityInterval) {
LK.clearInterval(playInactivityInterval);
}
// Disable action buttons during memory game
feedButton.interactive = false;
cleanButton.interactive = false;
playButton.interactive = false;
isMemoryGameActive = true;
var memoryGame = new MemoryGame();
// Add delay before creating and showing memory game
LK.setTimeout(function () {
// Create and start memory game
game.addChild(memoryGame);
}, 1500); // 0.5 second delay
// Handle game completion
memoryGame.onComplete = function (score) {
isMemoryGameActive = false;
// Re-enable action buttons when game completes
feedButton.interactive = true;
cleanButton.interactive = true;
playButton.interactive = true;
// Only add XP if the player completes the memory game with a score of at least 50
// (matches condition in endGame() where 50 score is shown for completing the game)
if (score >= 50) {
// Add XP based on score (higher score = more XP)
var earnedXp = XP_GAIN_PLAY + score;
addXp(earnedXp);
statusText.showMessage("Beat memory game! +" + earnedXp + " XP");
// Tell player how they did
speechBubble.setText("Great job! \nYou earned \n" + earnedXp + " XP!");
// Pet is happy after successful game completion
pet.happy();
speechBubble.show(500);
// Hide speech bubble after 2 seconds, but only if it's related to boredom
LK.setTimeout(function () {
// Only hide if it's showing the success message (not if it's showing hunger or poop messages)
if (speechBubble && speechBubble.text && speechBubble.text.includes("Great job!")) {
speechBubble.hide(300);
}
}, 2000);
// Set canPlayPet to false after playing
canPlayPet = false;
// Update boredom state in storage
storage.isBored = false;
// Stop the boredXpLoss timer when winning the memory game
if (boredXpLossTimer) {
LK.clearTimeout(boredXpLossTimer);
boredXpLossTimer = null;
}
// Reset boredom timer
if (boredTimer) {
LK.clearTimeout(boredTimer);
}
boredTimer = LK.setTimeout(function () {
// Show speech bubble with animation
speechBubble.setText("I'm bored! \n Play with me!");
speechBubble.show(500);
// Set canPlayPet to true when boredom message appears
canPlayPet = true;
// Update boredom state in storage
storage.isBored = true;
console.log("Pet is bored again - canPlayPet set to true");
}, timeToBored);
// Only reset boredom timer, not hunger timer
// This prevents boredom while playing memory game but allows normal hunger progression
if (boredTimer) {
LK.clearTimeout(boredTimer);
}
boredTimer = LK.setTimeout(function () {
speechBubble.setText("I'm bored! \n Play with me!");
speechBubble.show(500);
canPlayPet = true;
storage.isBored = true;
}, timeToBored);
if (xpLossTimer) {
LK.clearTimeout(xpLossTimer);
}
xpLossTimer = LK.setTimeout(function () {
if (petXp > 0) {
addXp(-XP_LOSS_AMOUNT);
statusText.showMessage("Pet is hungry! Lost " + XP_LOSS_AMOUNT + " XP!");
}
}, XP_LOSS_TIMEOUT);
} else {
// Player quit or didn't complete the game
statusText.showMessage("You must \ncomplete \nthe game!");
speechBubble.setText("Let's try \nagain!");
speechBubble.show(500);
// Wait a moment and then start a new memory game
LK.setTimeout(function () {
// Create and start a new memory game
var newMemoryGame = new MemoryGame();
game.addChild(newMemoryGame);
// Pass the same onComplete callback to the new game
newMemoryGame.onComplete = memoryGame.onComplete;
}, 2000);
// Don't update pet status since game isn't completed yet
return;
}
};
// Reset bored XP loss timer
if (boredXpLossTimer) {
LK.clearTimeout(boredXpLossTimer);
}
boredXpLossTimer = LK.setTimeout(function () {
if (petXp > 0) {
addXp(-XP_LOSS_AMOUNT);
statusText.showMessage("Pet is bored! Lost " + XP_LOSS_AMOUNT + " XP!");
}
}, BORED_XP_LOSS_TIMEOUT);
// Reset play inactivity interval to prevent additional XP loss
if (playInactivityInterval) {
LK.clearInterval(playInactivityInterval);
playInactivityInterval = LK.setInterval(function () {
var currentTime = Date.now();
var timeSinceLastPlayed = currentTime - lastPlayed;
if (timeSinceLastPlayed > 300000 && petXp > 0) {
addXp(-PLAY_INACTIVITY_XP_LOSS);
statusText.showMessage("Your pet misses you! Lost " + PLAY_INACTIVITY_XP_LOSS + " XP!");
speechBubble.setText("I miss playing `\n with you!");
speechBubble.show(500);
LK.setTimeout(function () {
speechBubble.hide(300);
}, 3000);
}
}, XP_LOSS_INTERVAL);
}
}
function addXp(amount) {
console.log("addXp called with amount:", amount);
petXp += amount;
storage.petXp = petXp;
// Check if pet is at level 1 and XP goes below 0
if (petLevel === 1 && petXp < 0) {
// Pet dies at level 1 with negative XP
statusText.showMessage(storage.petName + " has died!");
// Show game over
LK.setTimeout(function () {
// Reset all storage values
storage.petLevel = 1;
storage.petXp = 0;
storage.lastFed = 0;
storage.lastCleaned = 0;
storage.lastPlayed = 0;
storage.isHungry = false;
storage.isBored = false;
storage.hasActivePoop = false;
storage.petName = null; // Reset pet name to trigger character select again
// Show game over screen
LK.showGameOver();
}, 2000);
return; // Stop execution
}
// Check if pet level is greater than 1 and XP goes below 0
if (petLevel > 1 && petXp < 0) {
// Pet regresses to previous level
petLevel -= 1;
// Calculate new XP_PER_LEVEL for the previous level
XP_PER_LEVEL = BASE_XP_PER_LEVEL * Math.pow(2, petLevel - 1);
// Calculate how much XP to subtract from previous level's total
// If XP is -50 and pet was at level 2, it should have XP_PER_LEVEL - 50 (e.g., 500 - 50 = 450)
petXp = XP_PER_LEVEL + petXp; // Add negative XP to previous level's max XP
// Update storage values
storage.petLevel = petLevel;
storage.petXp = petXp;
// Update level text
levelText.setText("Level " + petLevel);
// Update pet position based on new level
if (petLevel === 1) {
petPosition = petBabyPosition;
} else if (petLevel === 2) {
petPosition = petChildPosition;
} else if (petLevel === 3) {
petPosition = petTeenPosition;
} else if (petLevel >= 4) {
petPosition = petAdultPosition;
}
// Update pet position
pet.x = petPosition.x;
pet.y = petPosition.y;
// Show message about regression
statusText.showMessage("Pet regressed to level " + petLevel + "!");
// Update pet appearance
// Remove old graphic and add new one
var petType = storage.petType || "Fluffy";
var newPetAssetId;
if (petType === "Puffy") {
if (petLevel === 1) {
newPetAssetId = 'pet_puffy_baby';
} else if (petLevel === 2) {
newPetAssetId = 'pet_puffy_child';
} else if (petLevel === 3) {
newPetAssetId = 'pet_puffy_teen';
} else if (petLevel >= 4) {
newPetAssetId = 'pet_puffy_adult';
}
} else {
// Default for Fluffy pet
if (petLevel === 1) {
newPetAssetId = 'pet_baby';
} else if (petLevel === 2) {
newPetAssetId = 'pet_child';
} else if (petLevel === 3) {
newPetAssetId = 'pet_teen';
} else if (petLevel >= 4) {
newPetAssetId = 'pet_adult';
}
}
// Get reference to current graphics to replace
var currentGraphics = pet.children.find(function (child) {
return child.asset && child.asset.indexOf('pet_') === 0;
});
if (currentGraphics) {
// Set the current pet image as invisible
currentGraphics.visible = false;
pet.removeChild(currentGraphics);
}
var petGraphics = pet.attachAsset(newPetAssetId, {
anchorX: 0.5,
anchorY: 0.5
});
// Flash effect to indicate regression
LK.effects.flashObject(pet, 0xFF0000, 1000);
}
// Check for level up
if (petXp >= XP_PER_LEVEL) {
console.log("Level up condition met!");
petLevel += 1;
petXp = 0;
storage.petLevel = petLevel;
storage.petXp = petXp;
// Recalculate XP_PER_LEVEL for next level - doubles with each level
XP_PER_LEVEL = BASE_XP_PER_LEVEL * Math.pow(2, petLevel - 1);
console.log("New level:", petLevel, "New XP_PER_LEVEL:", XP_PER_LEVEL);
// Update pet position based on new level
if (petLevel === 2) {
petPosition = petChildPosition;
} else if (petLevel === 3) {
petPosition = petTeenPosition;
} else if (petLevel >= 4) {
petPosition = petAdultPosition;
}
// Update pet position
pet.x = petPosition.x;
pet.y = petPosition.y;
levelText.setText("Level " + petLevel);
pet.evolve();
if (petLevel >= 4) {
statusText.showMessage("Maximum level reached!");
} else {
statusText.showMessage("Pet evolved to level " + petLevel + "! Next level: " + XP_PER_LEVEL + " XP");
}
}
// Update the HP text with current XP
if (hpText) {
hpText.setText("XP: " + petXp + "/" + XP_PER_LEVEL);
} else {
console.log("hpText is undefined or null");
}
addBarFillXp();
}
function createProgressBar() {
// Initialize position first
progressBar.x = 2048 / 2 - 400; // Center it
progressBar.y = 2732 - 200; // Near bottom
barBackground = LK.getAsset('progressBar_bg', {
anchorX: 0,
anchorY: 0.5
});
progressBar.addChild(barBackground);
barFill = LK.getAsset('progressBar_fill', {
anchorX: 0,
anchorY: 0.5
});
progressBar.addChild(barFill);
// Add progress bar to game
game.addChild(progressBar);
// Update hpText position now that progressBar exists
if (hpText) {
hpText.x = progressBar.x + 10;
hpText.y = progressBar.y - 50;
}
}
function addBarFillXp() {
// Store current width to animate from
var currentWidth = barFill.width;
// Calculate target width
var targetWidth = petXp / XP_PER_LEVEL * barBackground.width;
// Animate the width change
tween(barFill, {
width: targetWidth
}, {
duration: 800,
easing: tween.easeOutQuad
});
}
// Game update function
game.update = function () {
// Screen-specific updates
if (currentScreen === "game") {
// Ensure we're not continuously updating the progress bar every frame
// This was the source of the undefined parameters call
}
};
create a cute creature baby. In-Game asset. 2d. High contrast. No shadows
create a cute logo with Pocket Creature written. In-Game asset. 2d. High contrast. No shadows
create a cute button with play written inside. In-Game asset. 2d. High contrast. No shadows
create a cute room, lo fi room. In-Game asset. 2d. High contrast. No shadows
create a cute icon for cleaning item. In-Game asset. 2d. High contrast. No shadows
reimagine as a food item
Generate a smaller younger version of this character
Generate a smaller younger and cute version of this
Zoom out so it doesnt cut any elements off screen
Reimagine as younger cute version of this character
Reimagine as a younger cute version of this character
Reimagine as a cute younger version of this character
zoom out so it doesnt cut any elements off screen, make the outline thicker
Make a drawing of a cute poop. In-Game asset. 2d. High contrast. No shadows
Create an image for a memory game's card's back. In-Game asset. 2d. High contrast. No shadows
Create an image for a memory game's card's front with an icon of a play ball. In-Game asset. 2d. High contrast. No shadows
Create an image for a memory game's card's front with an icon of a chicken leg food. In-Game asset. 2d. High contrast. No shadows
Create an image for a memory game's card's front with an icon of a cute poop. In-Game asset. 2d. High contrast. No shadows
Create an image for a memory game's card's front with an icon of a cute pocket creature. In-Game asset. 2d. High contrast. No shadows
create a cute egg with some pattern and a peach and bege colors. In-Game asset. 2d. High contrast. No shadows
create a cute egg with some pattern and a light orange and light red colors. In-Game asset. 2d. High contrast. No shadows
simplify the eyes
Create a cute speech bubble with a heart. In-Game asset. 2d. High contrast. No shadows