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 isCheerNeeded = false; var hasActivePoop = false; var canFeedPet = false; var canPlayPet = false; var canCheerPet = 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 cheerXpLossTimer = null; // Timer for XP loss when cheer is ignored 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 = 200; 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", "cheer" // New: For random need logic var NEEDS = ["hunger", "boredom", "poop", "cheer"]; // 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; petLevel = 1; // Also reset the global petLevel variable 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 (canCheerPet && isCheerNeeded) { // Fulfill cheer need addXp(20); statusText.showMessage("Pet cheered! +20 XP"); canCheerPet = false; isCheerNeeded = false; // Hide cheer speech bubble if visible and it's showing the cheer message if (speechBubble && speechBubble.alpha > 0 && (speechBubble.text === "Pet me! \nI need a cheer!" || speechBubble.text === "I feel lonely! \nPet me please!")) { LK.setTimeout(function () { speechBubble.hide(300); }, 3000); } // Schedule next need after cheer is fulfilled game.scheduleNextNeed(); // Clear cheer XP loss timer if (cheerXpLossTimer) { LK.clearTimeout(cheerXpLossTimer); cheerXpLossTimer = null; } // Pet reacts (bounce/happy animation) if (pet && typeof pet.happy === "function") { pet.happy(); } lastPetClickImageXpTime = now; } else 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; } if (cheerXpLossTimer) { LK.clearTimeout(cheerXpLossTimer); cheerXpLossTimer = null; } canCheerPet = false; isCheerNeeded = false; } // Helper: pick a random need function pickRandomNeed() { // If there is active poop, always return "poop" if (activePoop) { return "poop"; } // Increase probability of 'boredom' by weighting the array // e.g. ["hunger", "boredom", "boredom", "boredom", "cheer"] var weightedNeeds = ["hunger", "boredom", "boredom", "boredom", "cheer"]; var idx = Math.floor(Math.random() * weightedNeeds.length); return weightedNeeds[idx]; } // Helper: schedule the next random need after a random delay (15-30s) function scheduleNextNeed() { var nextDelay = 15000 + Math.floor(Math.random() * 15000); // 15-30s needTimer = LK.setTimeout(function () { showRandomNeed(); }, nextDelay); } // Assign to game so it can be called as game.scheduleNextNeed() game.scheduleNextNeed = scheduleNextNeed; // Main: show a random need 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 = true; 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 === "cheer") { speechBubble.setText("Pet me! \nI need a cheer!"); speechBubble.show(500); canCheerPet = true; isCheerNeeded = true; // XP loss if ignored cheerXpLossTimer = LK.setTimeout(function () { if (petXp > 0) { addXp(-XP_LOSS_AMOUNT); statusText.showMessage("Pet feels lonely! Lost " + XP_LOSS_AMOUNT + " XP!"); speechBubble.setText("I feel lonely! \nPet me please!"); speechBubble.show(500); LK.setTimeout(function () { speechBubble.hide(300); }, 3000); } }, BORED_XP_LOSS_TIMEOUT); } 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(); // Set canCleanPet to true and enable cleanButton when poop spawns canCleanPet = true; if (cleanButton) { cleanButton.interactive = true; } } speechBubble.setText("Please clean \nthis mess!"); speechBubble.show(500); // Set canCleanPet to true when poop and clean speech bubble appear 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); } // Hide every speech bubble after 3 seconds LK.setTimeout(function () { speechBubble.hide(300); }, 3000); } // 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; } // Clear cheer XP loss timer if exists if (cheerXpLossTimer) { LK.clearTimeout(cheerXpLossTimer); cheerXpLossTimer = null; } canCheerPet = false; isCheerNeeded = false; // 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!") { LK.setTimeout(function () { speechBubble.hide(300); }, 3000); } // Schedule next need after feeding is resolved game.scheduleNextNeed(); // 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; } // Only allow cleaning if canCleanPet is true if (!canCleanPet) { statusText.showMessage("Pet doesn't need cleaning right now!"); 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; canCleanPet = false; // Reset after cleaning // Schedule next need after cleaning is resolved game.scheduleNextNeed(); }); // 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 3 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); } }, 3000); }, 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; } // Decide if memory game should appear (2 out of 3 times) if (typeof playMemoryGameCounter === "undefined") { playMemoryGameCounter = 0; } playMemoryGameCounter++; var playMemoryGame = false; if (playMemoryGameCounter >= 3) { playMemoryGameCounter = 1; } if (playMemoryGameCounter === 1 || playMemoryGameCounter === 2) { playMemoryGame = true; } LK.getSound('play').play(); pet.happy(); lastPlayed = currentTime; storage.lastPlayed = lastPlayed; if (playMemoryGame) { // Launch memory game for extra 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 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 () { 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 () { speechBubble.setText("I'm bored! \n Play with me!"); speechBubble.show(500); canPlayPet = true; storage.isBored = true; console.log("Pet is bored again - canPlayPet set to true"); }, 60000); 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; }, 60000); 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 () { var newMemoryGame = new MemoryGame(); game.addChild(newMemoryGame); newMemoryGame.onComplete = memoryGame.onComplete; }, 2000); 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); return; } // If not memory game, just play and give normal XP addXp(XP_GAIN_PLAY); statusText.showMessage("Played with pet! +" + XP_GAIN_PLAY + " XP"); speechBubble.setText("Yay! \nThat was fun!"); speechBubble.show(500); LK.setTimeout(function () { speechBubble.hide(300); }, 3000); canPlayPet = false; storage.isBored = false; if (boredXpLossTimer) { LK.clearTimeout(boredXpLossTimer); boredXpLossTimer = null; } 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; }, 60000); 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; }, 60000); 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); // Schedule next need after play is resolved game.scheduleNextNeed(); } 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 } };
===================================================================
--- original.js
+++ change.js
@@ -1495,11 +1495,13 @@
// 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];
+ // Increase probability of 'boredom' by weighting the array
+ // e.g. ["hunger", "boredom", "boredom", "boredom", "cheer"]
+ var weightedNeeds = ["hunger", "boredom", "boredom", "boredom", "cheer"];
+ var idx = Math.floor(Math.random() * weightedNeeds.length);
+ return weightedNeeds[idx];
}
// Helper: schedule the next random need after a random delay (15-30s)
function scheduleNextNeed() {
var nextDelay = 15000 + Math.floor(Math.random() * 15000); // 15-30s
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