Code edit (1 edits merged)
Please save this source code
User prompt
If the player is playing the memory game, the needs should wait to appear
User prompt
Change the whole way the pet needs work, now every 5~10 seconds it should appear a need, and it must be a random need of the 3
User prompt
Please fix the bug: 'boredTimer is not defined' in or related to this line: 'if (boredTimer) {' Line Number: 1695
User prompt
Please fix the bug: 'hungerTimer is not defined' in or related to this line: 'if (hungerTimer) {' Line Number: 1664
User prompt
Refactor the whole way the pet needs and speech bubles appear, now it should appear one random of the 3 needs every 5~10 seconds
User prompt
Set to while player is playing the memory game, the player cant cheer the pet
User prompt
the hunger speech buble should always appear repeatedly at the timerate, and when it appears set canFeedPet true
Code edit (1 edits merged)
Please save this source code
User prompt
Set the pet to poop 15 seconds after eating everytime
User prompt
Set the pet to poop 15 seconds after eating everytime
User prompt
Add a reaction to the pet when the player clicks the clickable cheer_image
User prompt
Whenever each needs speech buble appear it should set the variable to the action to true
Code edit (2 edits merged)
Please save this source code
User prompt
Create a variavle to the hunger speech buble appear repeatedly in seconds
User prompt
The hungry speech buble should appear befor taking xp loss for hunger
User prompt
Set the great job you earn x amount of xp speech bubble to desapear after 2 seconds
User prompt
Set the interval of the needs to half
Code edit (1 edits merged)
Please save this source code
User prompt
Create and add a new image for the cheering image/ the clickable image
User prompt
Create and add a new image for the clickable image
User prompt
When the player clicks in that image it should give the pet 15 more xp. The player can do this in every 5 seconds
User prompt
Add a mechanic, when the player clicks the pet, it shows an image above in y axis and left in x axis of the pet
User prompt
In the memory game the player cant turn another card if theres two cards with its upside up
User prompt
In the memory game, set to player can only turn a card if theres no card upside up
/****
* 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 = storage.isHungry !== undefined ? storage.isHungry : false;
var isBored = storage.isBored !== undefined ? storage.isBored : false;
var hasActivePoop = storage.hasActivePoop !== undefined ? storage.hasActivePoop : false;
var canFeedPet = !isHungry; // Initialize feeding state based on hunger
var canPlayPet = !isBored; // Initialize play state based on boredom
var speechBubble; // Variable for the speech bubble
var hungerTimer; // Timer for hunger message
var timeToHungry = 15000;
var xpLossTimer; // Timer for XP loss after not feeding
var XP_LOSS_TIMEOUT = 120000; // 5 minutes (300000ms)
var XP_LOSS_AMOUNT = 50; // Amount of XP to lose
var poopTimer; // Timer for when pet will poop
var poopSpawnTime = 30000; // 2 minutes (120000ms)
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 POOP_SPEECH_TIMEOUT = 60000; // 1 minute (60000ms)
var POOP_XP_LOSS_TIMEOUT = 120000; // 2 minutes (120000ms)
var boredTimer; // Timer for boredom message
var timeToBored = 45000; // 1.5 minutes (90000ms)
var boredXpLossTimer; // Timer for XP loss when bored
var BORED_XP_LOSS_TIMEOUT = 90000; // 4 minutes (240000ms)
// 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 XP_LOSS_INTERVAL = 180000; // 3 minutes interval for XP loss if player doesn't play with pet
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
// 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 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
var petClickImage = null;
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 (use 'bubble_speech' as a placeholder, can be changed)
petClickImage = LK.getAsset('bubble_speech', {
anchorX: 0.5,
anchorY: 0.5,
width: 200,
height: 200
});
// 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
});
// 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 hunger message
speechBubble = new BubbleSpeech("I'm hungry!");
speechBubble.x = pet.x + 450;
speechBubble.y = pet.y - 450; // Position above pet
speechBubble.alpha = 0; // Start invisible
game.addChild(speechBubble);
// Initialize state based on saved values
if (isHungry) {
speechBubble.setText("I'm hungry!");
speechBubble.show(500);
canFeedPet = true;
}
if (isBored) {
speechBubble.setText("I'm bored! \n Play with me!");
speechBubble.show(500);
canPlayPet = true;
}
if (hasActivePoop) {
// Create poop if it was active when game was closed
activePoop = new Poop();
activePoop.x = pet.x + Math.random() * 1000;
activePoop.y = pet.y + 100 + Math.random() * 50;
game.addChild(activePoop);
activePoop.appear();
}
// Clear any existing timer
if (hungerTimer) {
LK.clearTimeout(hungerTimer);
}
// Set timer to show hunger bubble after 1 minute (60000ms)
hungerTimer = LK.setTimeout(function () {
// Show speech bubble with animation
game.addChild(speechBubble); // Make sure it's in the display tree
// Set canFeedPet to true when hunger message appears
canFeedPet = true;
// Save hunger state in storage
storage.isHungry = true;
speechBubble.show(500);
console.log("Pet is now hungry - canFeedPet set to true");
}, timeToHungry);
// Set timer for XP loss after 5 minutes of not feeding
xpLossTimer = LK.setTimeout(function () {
// Only deduct XP if pet has any
if (petXp > 0) {
addXp(-XP_LOSS_AMOUNT); // Deduct XP
statusText.showMessage("Pet is hungry! Lost " + XP_LOSS_AMOUNT + " XP!");
}
}, XP_LOSS_TIMEOUT);
// Set timer to show boredom bubble after 1.5 minutes
boredTimer = LK.setTimeout(function () {
// Change speech bubble text to boredom message
speechBubble.setText("I'm bored! \n Play with me!");
// Set canPlayPet to true when boredom message appears
canPlayPet = true;
// Update boredom state in storage
storage.isBored = true;
// Show speech bubble with animation
speechBubble.show(500);
console.log("Pet is bored - canPlayPet set to true");
}, timeToBored);
// Set timer for XP loss after 4 minutes of not playing
boredXpLossTimer = LK.setTimeout(function () {
// Only deduct XP if pet has any
if (petXp > 0) {
addXp(-XP_LOSS_AMOUNT); // Deduct XP
statusText.showMessage("Pet is bored! Lost " + XP_LOSS_AMOUNT + " XP!");
}
}, BORED_XP_LOSS_TIMEOUT);
// Set up recurring XP loss every 3 minutes if player doesn't play with pet
playInactivityInterval = LK.setInterval(function () {
// Calculate time since last played
var currentTime = Date.now();
var timeSinceLastPlayed = currentTime - lastPlayed;
// If it's been more than 5 minutes since last played
if (timeSinceLastPlayed > 300000 && petXp > 0) {
// Deduct XP
addXp(-PLAY_INACTIVITY_XP_LOSS);
statusText.showMessage("Your pet misses you! Lost " + PLAY_INACTIVITY_XP_LOSS + " XP!");
// Show speech bubble about missing play time
speechBubble.setText("I miss \nplaying \nwith you!");
speechBubble.show(500);
// Hide speech bubble after 3 seconds
LK.setTimeout(function () {
speechBubble.hide(300);
}, 3000);
}
}, XP_LOSS_INTERVAL);
} //[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 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);
}
// 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 after being fed
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 + Math.random() * 1000; // Random position near pet
activePoop.y = pet.y + 100 + Math.random() * 50;
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);
}
}, poopSpawnTime);
} //[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;
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) {
// 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 a few 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);
}
}, 3000);
// 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
}
}; ===================================================================
--- original.js
+++ change.js
@@ -1272,8 +1272,52 @@
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
+ var petClickImage = null;
+ 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 (use 'bubble_speech' as a placeholder, can be changed)
+ petClickImage = LK.getAsset('bubble_speech', {
+ anchorX: 0.5,
+ anchorY: 0.5,
+ width: 200,
+ height: 200
+ });
+ // 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
+ });
+ // 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
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