/**** * Plugins ****/ var tween = LK.import("@upit/tween.v1"); var storage = LK.import("@upit/storage.v1"); /**** * Classes ****/ var AbandonButton = Container.expand(function () { var self = Container.call(this); var buttonShape = self.attachAsset('cleanButton', { anchorX: 0.5, anchorY: 0.5, tint: 0xcc0000 // Red color for warning }); var label = new Text2("ABANDON", { size: 40, fill: 0xFFFFFF }); label.anchor.set(0.5, 0.5); self.addChild(label); self.interactive = true; self.down = function (x, y, obj) { tween(buttonShape, { scaleX: 0.9, scaleY: 0.9 }, { duration: 100, easing: tween.easeOut }); }; self.up = function (x, y, obj) { tween(buttonShape, { scaleX: 1.0, scaleY: 1.0 }, { duration: 100, easing: tween.easeOut }); // Trigger nightmare mode self.triggerNightmareMode(); }; self.triggerNightmareMode = function () { // Add massive corruption to instantly transform pet if (pet) { // Maximum corruption pet.addCorruption(100); // Only activate nightmare mode if corruption is at 100% if (pet.corruption >= 100) { // Make everything scary // Dark background game.setBackgroundColor(0x110011); // Intense glitch effects for (var i = 0; i < 20; i++) { LK.setTimeout(function () { triggerGlitch(); }, i * 100); } // Make pet eyes red and distorted if (pet.leftEye && pet.rightEye) { pet.leftEye.tint = 0xff0000; pet.rightEye.tint = 0xff0000; // Distort eyes tween(pet.leftEye, { scaleX: 1.8, scaleY: 0.6 }, { duration: 500 }); tween(pet.rightEye, { scaleX: 0.6, scaleY: 1.8 }, { duration: 500 }); } // Distort mouth if (pet.mouth) { pet.mouth.tint = 0xff0000; tween(pet.mouth, { scaleX: 2.0, scaleY: 0.5, rotation: 0.5 }, { duration: 500 }); } // Reduce all pet stats to minimum pet.hunger = 1; pet.happiness = 1; pet.cleanliness = 1; updateStatusBars(); // Play glitch sound rapidly for (var i = 0; i < 5; i++) { LK.setTimeout(function () { LK.getSound('glitch').play(); }, i * 200); } } } }; return self; }); var ArcadeGame = Container.expand(function () { var self = Container.call(this); // Game state self.active = false; self.score = 0; self.gameOver = false; self.playerX = 0; self.targets = []; self.timeRemaining = 30; // 30 second game self.lastCountdownTime = 0; self.lives = 3; // Player has 3 lives // Create game background var background = self.attachAsset('cleanButton', { anchorX: 0.5, anchorY: 0.5, scaleX: 8, // Increased size scaleY: 9, // Increased size tint: 0x000000 }); // Create player - use pet body asset instead of generic shape var player = self.attachAsset('petBody', { anchorX: 0.5, anchorY: 0.5, scaleX: 0.3, scaleY: 0.3, y: 200, tint: 0x44FF44 }); // Create score text var scoreText = new Text2("Score: 0", { size: 40, fill: 0xFFFFFF }); scoreText.anchor.set(0.5, 0.5); scoreText.y = -350; self.addChild(scoreText); // Create countdown text var countdownText = new Text2("Time: 30", { size: 40, fill: 0xFFFFFF }); countdownText.anchor.set(0.5, 0.5); countdownText.y = -300; self.addChild(countdownText); // Create lives display var livesText = new Text2("Lives: 3", { size: 40, fill: 0xFFFFFF }); livesText.anchor.set(0.5, 0.5); livesText.y = -250; self.addChild(livesText); // Create game controls var leftButton = self.attachAsset('cleanButton', { anchorX: 0.5, anchorY: 0.5, scaleX: 1.0, scaleY: 1.0, x: -150, y: 300, tint: 0x4488FF }); var rightButton = self.attachAsset('cleanButton', { anchorX: 0.5, anchorY: 0.5, scaleX: 1.0, scaleY: 1.0, x: 150, y: 300, tint: 0x4488FF }); // Add arrow indicators to buttons var leftArrow = new Text2("<", { size: 80, fill: 0xFFFFFF }); leftArrow.anchor.set(0.5, 0.5); leftButton.addChild(leftArrow); var rightArrow = new Text2(">", { size: 80, fill: 0xFFFFFF }); rightArrow.anchor.set(0.5, 0.5); rightButton.addChild(rightArrow); // Make buttons interactive leftButton.interactive = true; rightButton.interactive = true; leftButton.down = function () { self.movePlayer(-10); }; rightButton.down = function () { self.movePlayer(10); }; // Initialize targets for (var i = 0; i < 5; i++) { var target = self.attachAsset('food', { anchorX: 0.5, anchorY: 0.5, x: (Math.random() - 0.5) * 300, y: -150 - Math.random() * 100, scaleX: 0.7, scaleY: 0.7, visible: false }); self.targets.push({ sprite: target, active: false, speed: 2 + Math.random() * 1.5 // Reduced from 3+random*2 to make it easier }); } self.movePlayer = function (amount) { if (!self.active || self.gameOver) { return; } self.playerX += amount; // Keep player within bounds self.playerX = Math.max(-150, Math.min(150, self.playerX)); // Use tween for smoother movement tween(player, { x: self.playerX, rotation: amount > 0 ? 0.1 : amount < 0 ? -0.1 : 0 // Tilt in direction of movement }, { duration: 150, easing: tween.easeOut, onFinish: function onFinish() { // Return to neutral rotation if (amount !== 0) { tween(player, { rotation: 0 }, { duration: 100 }); } } }); }; self.updateTargets = function () { var activeCount = 0; // Update existing targets for (var i = 0; i < self.targets.length; i++) { var target = self.targets[i]; if (target.active) { activeCount++; // Move target down target.sprite.y += target.speed; // Check if player caught the target var dx = target.sprite.x - player.x; var dy = target.sprite.y - player.y; var distance = Math.sqrt(dx * dx + dy * dy); if (distance < 40) { // Caught target - increase score self.score += 10; scoreText.setText("Score: " + self.score); // Deactivate target target.active = false; target.sprite.visible = false; } // Check if target reached bottom if (target.sprite.y > 250) { // Target missed target.active = false; target.sprite.visible = false; // Decrease lives instead of ending game immediately self.lives--; livesText.setText("Lives: " + self.lives); // Flash lives text red tween(livesText, { tint: 0xFF0000 }, { duration: 200, onFinish: function onFinish() { tween(livesText, { tint: 0xFFFFFF }, { duration: 200 }); } }); // End game if no lives left if (self.lives <= 0) { self.gameOver = true; self.endGame(); } } } } // Spawn new target if needed - further reduced spawn rate from 0.02 to 0.01 if (activeCount < 1 && Math.random() < 0.01 && !self.gameOver) { var randomTarget = self.targets[Math.floor(Math.random() * self.targets.length)]; if (!randomTarget.active) { randomTarget.active = true; randomTarget.sprite.visible = true; randomTarget.sprite.x = (Math.random() - 0.5) * 300; randomTarget.sprite.y = -200; } } }; self.startGame = function () { self.visible = true; self.active = true; self.gameOver = false; self.score = 0; self.playerX = 0; player.x = 0; scoreText.setText("Score: 0"); // Reset countdown self.timeRemaining = 30; self.lastCountdownTime = 0; countdownText.setText("Time: 30"); // Reset lives self.lives = 3; livesText.setText("Lives: 3"); // Reset all targets for (var i = 0; i < self.targets.length; i++) { self.targets[i].active = false; self.targets[i].sprite.visible = false; } }; self.endGame = function () { // Show game over message var gameOverText = new Text2("Game Over!", { size: 60, fill: 0xFF4444 }); gameOverText.anchor.set(0.5, 0.5); self.addChild(gameOverText); // Show final score with any time bonus var finalScore = self.score; if (self.timeRemaining > 0) { // Add bonus points for remaining time var timeBonus = self.timeRemaining * 5; finalScore += timeBonus; // Show bonus message var bonusText = new Text2("Time Bonus: +" + timeBonus, { size: 40, fill: 0x44FF44 }); bonusText.anchor.set(0.5, 0.5); bonusText.y = 60; gameOverText.addChild(bonusText); // Update score display scoreText.setText("Final Score: " + finalScore); } // Hide game over and give reward after delay LK.setTimeout(function () { self.deactivate(); // Increase pet happiness based on score - boosted happiness gain if (pet) { var happinessBoost = Math.min(60, finalScore / 8); // Increased from 50 to 60, and divided by 8 instead of 10 pet.happiness = Math.min(100, pet.happiness + happinessBoost); // Don't decrease hunger when playing arcade game updateStatusBars(); } }, 3000); }; self.update = function () { if (!self.active) { return; } self.updateTargets(); // Update countdown timer (every second) var currentTime = Math.floor(LK.ticks / 60); if (currentTime > self.lastCountdownTime) { self.lastCountdownTime = currentTime; self.timeRemaining--; countdownText.setText("Time: " + self.timeRemaining); // Flash countdown text when time is running out (less than 10 seconds) if (self.timeRemaining <= 10) { tween(countdownText, { tint: 0xFF0000 }, { duration: 200, onFinish: function onFinish() { tween(countdownText, { tint: 0xFFFFFF }, { duration: 200 }); } }); } // End game when time runs out if (self.timeRemaining <= 0) { self.gameOver = true; self.endGame(); } } }; self.deactivate = function () { self.active = false; tween(self, { alpha: 0 }, { duration: 300, onFinish: function onFinish() { self.visible = false; self.alpha = 1; } }); }; self.visible = false; return self; }); var Ball = Container.expand(function () { var self = Container.call(this); // Create ball using toy asset instead of buttonIcon var ballGraphics = self.attachAsset('toy', { anchorX: 0.5, anchorY: 0.5, scaleX: 1.2, scaleY: 1.2 }); // Add some decoration to make it look more like a ball var highlight = self.attachAsset('buttonIcon', { anchorX: 0.5, anchorY: 0.5, scaleX: 0.3, scaleY: 0.3, x: -15, y: -15, tint: 0xFFFFFF, alpha: 0.7 }); self.interactive = true; self.visible = false; self.active = false; self.originalX = 0; self.originalY = 0; self.down = function (x, y, obj) { // Scale down when pressed tween(ballGraphics, { scaleX: 0.9, scaleY: 0.9 }, { duration: 100, easing: tween.easeOut }); }; self.up = function (x, y, obj) { // Restore scale when released tween(ballGraphics, { scaleX: 1.0, scaleY: 1.0 }, { duration: 100, easing: tween.easeOut }); if (self.active) { // Check if ball is near pet var dx = self.x - pet.x; var dy = self.y - pet.y; var distance = Math.sqrt(dx * dx + dy * dy); if (distance < 150) { // Play with pet using the ball pet.play(); self.deactivate(); } else { // Return to original position self.returnToPosition(); } } }; self.activate = function () { self.visible = true; self.active = true; self.originalX = playButton.x; self.originalY = playButton.y - 150; self.x = self.originalX; self.y = self.originalY; // Animation to indicate it's ready tween(ballGraphics, { scaleX: 1.2, scaleY: 1.2 }, { duration: 200, onFinish: function onFinish() { tween(ballGraphics, { scaleX: 1.0, scaleY: 1.0 }, { duration: 200 }); } }); }; self.deactivate = function () { self.active = false; // Fade out tween(self, { alpha: 0 }, { duration: 300, onFinish: function onFinish() { self.visible = false; self.alpha = 1; } }); }; self.returnToPosition = function () { tween(self, { x: self.originalX, y: self.originalY }, { duration: 300 }); }; return self; }); var Button = Container.expand(function (type) { var self = Container.call(this); self.type = type; self.onCooldown = false; self.cooldownDuration = 2000; // 2 seconds cooldown var buttonShape = self.attachAsset(type + 'Button', { anchorX: 0.5, anchorY: 0.5 }); var icon = self.attachAsset('buttonIcon', { anchorX: 0.5, anchorY: 0.5, scaleX: 0.8, scaleY: 0.8 }); var label = new Text2(type.charAt(0).toUpperCase() + type.slice(1), { size: 40, fill: 0xFFFFFF }); label.anchor.set(0.5, 0.5); label.y = 70; self.addChild(label); self.interactive = true; self.startCooldown = function () { if (self.onCooldown) { return; } self.onCooldown = true; // Grey out the button during cooldown tween(buttonShape, { tint: 0x888888 }, { duration: 100 }); // Set a timeout to end the cooldown LK.setTimeout(function () { self.onCooldown = false; // Restore button color tween(buttonShape, { tint: 0xFFFFFF }, { duration: 100 }); }, self.cooldownDuration); }; self.down = function (x, y, obj) { tween(buttonShape, { scaleX: 0.9, scaleY: 0.9 }, { duration: 100, easing: tween.easeOut }); }; self.up = function (x, y, obj) { tween(buttonShape, { scaleX: 1.0, scaleY: 1.0 }, { duration: 100, easing: tween.easeOut }); // Only act if not on cooldown if (!self.onCooldown) { LK.getSound(self.type).play(); self.startCooldown(); switch (self.type) { case 'feed': // Activate food instead of directly feeding if (food) { food.activate(); } break; case 'play': // Show play options popup if (playOptionsMenu && !playOptionsMenu.visible) { playOptionsMenu.show(); } else { // Fallback to direct play if menu isn't available pet.play(); } break; case 'clean': // Activate vacuum when clean button is clicked if (vacuum && !vacuum.active) { vacuum.x = cleanButton.x; vacuum.y = cleanButton.y; vacuum.activate(); } else { pet.clean(); } break; } } }; return self; }); var CheckStats = Container.expand(function () { var self = Container.call(this); self.lastCheck = 0; self.checkInterval = 60; // Check every second (60 frames) self.nightmareModeActive = false; self.maxCorruption = 100; // Maximum corruption value self.update = function () { // Only check periodically to improve performance if (LK.ticks - self.lastCheck < self.checkInterval) { return; } self.lastCheck = LK.ticks; // Check if pet exists and has critically low stats AND corruption is at 100% if (pet && pet.hunger <= 10 && pet.happiness <= 10 && pet.cleanliness <= 10 && pet.corruption >= 100 && !self.nightmareModeActive) { self.activateNightmareMode(); } }; self.activateNightmareMode = function () { self.nightmareModeActive = true; // Send pet to maximum corruption pet.addCorruption(self.maxCorruption); // Show visual glitch effects for (var i = 0; i < 20; i++) { LK.setTimeout(function () { triggerGlitch(); }, i * 100); } // Dark background for nightmare mode game.setBackgroundColor(0x110011); // Make pet eyes red and distorted if (pet.leftEye && pet.rightEye) { pet.leftEye.tint = 0xff0000; pet.rightEye.tint = 0xff0000; // Distort eyes tween(pet.leftEye, { scaleX: 1.8, scaleY: 0.6 }, { duration: 500 }); tween(pet.rightEye, { scaleX: 0.6, scaleY: 1.8 }, { duration: 500 }); } // Distort mouth if (pet.mouth) { pet.mouth.tint = 0xff0000; tween(pet.mouth, { scaleX: 2.0, scaleY: 0.5, rotation: 0.5 }, { duration: 500 }); } // Play glitch sound rapidly for (var i = 0; i < 5; i++) { LK.setTimeout(function () { LK.getSound('glitch').play(); }, i * 200); } }; return self; }); var CorruptionParticle = Container.expand(function () { var self = Container.call(this); var particleGraphics = self.attachAsset('corruptionEffect', { anchorX: 0.5, anchorY: 0.5, alpha: 0.6 }); self.lifespan = 0; self.maxLife = 0; self.speedX = 0; self.speedY = 0; self.active = false; self.initialize = function (x, y, duration) { self.x = x; self.y = y; self.maxLife = duration; self.lifespan = duration; self.speedX = (Math.random() - 0.5) * 3; self.speedY = (Math.random() - 0.5) * 3; self.rotation = Math.random() * Math.PI * 2; self.active = true; self.visible = true; self.alpha = 0.6; // Color selection depends on corruption level - darker as corruption increases var randomColor = Math.random(); var corruptionLevel = pet ? pet.corruption : 0; var darkerColors = corruptionLevel > 50; var nightmareMode = corruptionLevel >= 95; if (nightmareMode) { // Extremely dark, scary colors for nightmare mode if (randomColor < 0.33) { particleGraphics.tint = 0xff0000; // Blood red } else if (randomColor < 0.66) { particleGraphics.tint = 0x660000; // Dark red } else { particleGraphics.tint = 0x330000; // Very dark red } // Larger and more intense for nightmare mode particleGraphics.scaleX = particleGraphics.scaleY = 1.5 + Math.random(); } else if (darkerColors) { // Darker, more ominous colors when corruption is higher if (randomColor < 0.33) { particleGraphics.tint = 0x4455aa; // Dark blue } else if (randomColor < 0.66) { particleGraphics.tint = 0x335566; // Dark teal } else { particleGraphics.tint = 0x556677; // Dark slate } } else { // Original brighter colors for lower corruption if (randomColor < 0.33) { particleGraphics.tint = 0x88aaff; // Light blue } else if (randomColor < 0.66) { particleGraphics.tint = 0x55ddaa; // Teal } else { particleGraphics.tint = 0xaaddff; // Sky blue } } }; self.update = function () { if (!self.active) { return; } self.lifespan--; self.x += self.speedX; self.y += self.speedY; self.alpha = self.lifespan / self.maxLife * 0.6; if (self.lifespan <= 0) { self.active = false; self.visible = false; } }; self.visible = false; self.active = false; return self; }); var Food = Container.expand(function () { var self = Container.call(this); var foodGraphics = self.attachAsset('food', { anchorX: 0.5, anchorY: 0.5 }); self.interactive = true; self.visible = false; self.active = false; self.down = function (x, y, obj) { // Scale down when pressed tween(foodGraphics, { scaleX: 0.9, scaleY: 0.9 }, { duration: 100, easing: tween.easeOut }); }; self.up = function (x, y, obj) { // Restore scale when released tween(foodGraphics, { scaleX: 1.0, scaleY: 1.0 }, { duration: 100, easing: tween.easeOut }); if (self.active) { // Check if food is near pet's mouth var dx = self.x - pet.x; var dy = self.y - (pet.y + pet.mouth.y); var distance = Math.sqrt(dx * dx + dy * dy); if (distance < 100) { // Feed the pet pet.feed(); self.deactivate(); } else { // Return to original position self.returnToPosition(); } } }; self.activate = function () { self.visible = true; self.active = true; self.originalX = feedButton.x; self.originalY = feedButton.y - 150; self.x = self.originalX; self.y = self.originalY; // Animation to indicate it's ready tween(foodGraphics, { scaleX: 1.2, scaleY: 1.2 }, { duration: 200, onFinish: function onFinish() { tween(foodGraphics, { scaleX: 1.0, scaleY: 1.0 }, { duration: 200 }); } }); }; self.deactivate = function () { self.active = false; // Fade out tween(self, { alpha: 0 }, { duration: 300, onFinish: function onFinish() { self.visible = false; self.alpha = 1; } }); }; self.returnToPosition = function () { tween(self, { x: self.originalX, y: self.originalY }, { duration: 300 }); }; return self; }); var GlitchEffect = Container.expand(function () { var self = Container.call(this); var glitchGraphics = self.attachAsset('glitchEffect', { anchorX: 0.5, anchorY: 0.5, alpha: 0.7 }); self.startGlitch = function () { self.visible = true; self.x = Math.random() * 2048; self.y = Math.random() * 2732; self.rotation = Math.random() * Math.PI * 2; self.alpha = 0.7; tween(self, { alpha: 0 }, { duration: 300 + Math.random() * 700, onFinish: function onFinish() { self.visible = false; } }); }; self.visible = false; return self; }); var IgnoreButton = Container.expand(function () { var self = Container.call(this); // Use the actual phone image rather than shape components var phoneImage = self.attachAsset('ignorePhone', { anchorX: 0.5, anchorY: 0.5, scaleX: 1.0, scaleY: 1.0 }); // Add label var label = new Text2("IGNORE", { size: 50, fill: 0xFFFFFF, bold: true }); label.anchor.set(0.5, 0.5); label.y = -120; self.addChild(label); self.interactive = true; self.down = function (x, y, obj) { tween(phoneImage, { scaleX: 0.9, scaleY: 0.9 }, { duration: 100, easing: tween.easeOut }); }; self.up = function (x, y, obj) { tween(phoneImage, { scaleX: 1.0, scaleY: 1.0 }, { duration: 100, easing: tween.easeOut }); // Drop all stats to very low values self.reduceAllStats(); }; self.reduceAllStats = function () { if (pet) { // Set all stats to very low values pet.hunger = 0; pet.happiness = 0; pet.cleanliness = 0; // Play glitch sound LK.getSound('glitch').play(); // Update status bars updateStatusBars(); // Create visual effect LK.effects.flashScreen(0x000000, 500); // Add glitch effects for (var i = 0; i < 10; i++) { LK.setTimeout(function () { triggerGlitch(); }, i * 100); } // Corrupt pet appearance pet.updateAppearance(); } }; return self; }); var Pet = Container.expand(function () { var self = Container.call(this); // Stats self.hunger = 100; self.happiness = 100; self.cleanliness = 100; self.corruption = 0; self.stage = 0; // 0 = normal, 1 = starting to corrupt, 2 = more corrupt, 3 = nightmare // Visual components var body = self.attachAsset('petBody', { anchorX: 0.5, anchorY: 0.5, scaleX: 1, scaleY: 1 }); // Make these properties accessible from outside for the abandon button self.leftEye = self.attachAsset('petEye', { anchorX: 0.5, anchorY: 0.5, x: -70, y: -50 }); self.rightEye = self.attachAsset('petEye', { anchorX: 0.5, anchorY: 0.5, x: 70, y: -50 }); self.mouth = self.attachAsset('petMouth', { anchorX: 0.5, anchorY: 0.5, x: 0, y: 0 }); // Food item that appears when feeding var foodItem = self.attachAsset('food', { anchorX: 0.5, anchorY: 0.5, visible: false, x: 0, y: -200 }); // Toy that appears when playing var toyItem = self.attachAsset('toy', { anchorX: 0.5, anchorY: 0.5, visible: false, x: 200, y: 0 }); // Dirt patches that appear when pet is dirty var dirtPatches = []; for (var i = 0; i < 5; i++) { var dirt = self.attachAsset('dirt', { anchorX: 0.5, anchorY: 0.5, visible: false, x: (Math.random() - 0.5) * 200, y: (Math.random() - 0.5) * 200 }); dirtPatches.push(dirt); } self.blink = function () { tween(self.leftEye, { scaleY: 0.1 }, { duration: 100, onFinish: function onFinish() { tween(self.leftEye, { scaleY: 1 }, { duration: 100 }); } }); tween(self.rightEye, { scaleY: 0.1 }, { duration: 100, onFinish: function onFinish() { tween(self.rightEye, { scaleY: 1 }, { duration: 100 }); } }); }; self.breathe = function () { tween(body, { scaleY: 1.05 }, { duration: 1000, onFinish: function onFinish() { tween(body, { scaleY: 1 }, { duration: 1000 }); } }); }; self.feed = function () { self.hunger = Math.min(100, self.hunger + 30); // Decrease cleanliness when feeding self.cleanliness = Math.max(0, self.cleanliness - 15); updateStatusBars(); // Make pet happy from feeding with more animated reaction // Move slightly up with excitement tween(self, { y: self.y - 30 }, { duration: 200, easing: tween.easeOut, onFinish: function onFinish() { tween(self, { y: self.y + 30 }, { duration: 300, easing: tween.easeIn }); } }); // More expressive mouth animation tween(self.mouth, { scaleX: 1.5, scaleY: 1.5, rotation: 0.1 }, { duration: 300, onFinish: function onFinish() { tween(self.mouth, { scaleX: 1, scaleY: 1, rotation: 0 }, { duration: 300 }); } }); // Sometimes add corruption from feeding in later stages if (self.corruption > 40 && Math.random() < 0.3) { self.addCorruption(5); triggerGlitch(); } }; self.play = function () { toyItem.visible = true; toyItem.x = 200; tween(toyItem, { x: 0 }, { duration: 500, onFinish: function onFinish() { self.happiness = Math.min(100, self.happiness + 30); // Decrease hunger when playing with the pet self.hunger = Math.max(0, self.hunger - 15); updateStatusBars(); // Bounce toy tween(toyItem, { y: -100 }, { duration: 300, easing: tween.easeOut, onFinish: function onFinish() { tween(toyItem, { y: 0, alpha: 0 }, { duration: 300, easing: tween.easeIn, onFinish: function onFinish() { toyItem.visible = false; toyItem.alpha = 1; } }); } }); // Make pet happy from playing tween(body, { rotation: 0.1 }, { duration: 200, onFinish: function onFinish() { tween(body, { rotation: -0.1 }, { duration: 200, onFinish: function onFinish() { tween(body, { rotation: 0 }, { duration: 200 }); } }); } }); } }); // Sometimes add corruption from playing in later stages if (self.corruption > 40 && Math.random() < 0.3) { self.addCorruption(5); triggerGlitch(); } }; self.clean = function () { // Activate vacuum cleaner instead of directly cleaning if (vacuum && !vacuum.active) { vacuum.x = cleanButton.x; vacuum.y = cleanButton.y; vacuum.activate(); return; // Exit early - actual cleaning happens when vacuum is dragged to pet } // This section only executes when cleaning is triggered by the vacuum self.cleanliness = Math.min(100, self.cleanliness + 30); // Reduce happiness more significantly when cleaning with vacuum self.happiness = Math.max(0, self.happiness - 25); updateStatusBars(); // Hide dirt patches for (var i = 0; i < dirtPatches.length; i++) { dirtPatches[i].visible = false; } // Sparkle effect tween(body, { alpha: 0.7 }, { duration: 200, onFinish: function onFinish() { tween(body, { alpha: 1 }, { duration: 200 }); } }); // Sometimes add corruption from cleaning in later stages if (self.corruption > 40 && Math.random() < 0.3) { self.addCorruption(5); triggerGlitch(); } }; self.updateStats = function () { // Decrease stats over time - increased decay rates self.hunger = Math.max(0, self.hunger - 0.3); self.happiness = Math.max(0, self.happiness - 0.4); self.cleanliness = Math.max(0, self.cleanliness - 0.35); // Show dirt when dirty for (var i = 0; i < dirtPatches.length; i++) { dirtPatches[i].visible = self.cleanliness < 50 + i * 10; } // Corruption increases when needs are low if (self.hunger < 30 || self.happiness < 30 || self.cleanliness < 30) { self.addCorruption(0.05); if (Math.random() < 0.1) { triggerGlitch(); } } // Random movement to make the pet more lively if (Math.random() < 0.05) { // Move in a random direction var moveX = (Math.random() - 0.5) * 30; var moveY = (Math.random() - 0.5) * 30; // Animate the movement tween(self, { x: self.x + moveX, y: self.y + moveY }, { duration: 800, easing: tween.easeInOut }); // Also add a small bounce effect tween(body, { scaleY: 1.1 }, { duration: 400, easing: tween.easeOut, onFinish: function onFinish() { tween(body, { scaleY: 1 }, { duration: 400, easing: tween.easeIn }); } }); } // Update visual based on corruption level self.updateAppearance(); }; self.addCorruption = function (amount) { var oldCorruption = self.corruption; self.corruption = Math.min(100, self.corruption + amount); if (oldCorruption < 33 && self.corruption >= 33) { self.evolve(1); } else if (oldCorruption < 66 && self.corruption >= 66) { self.evolve(2); } else if (oldCorruption < 100 && self.corruption >= 100) { self.evolve(3); } updateStatusBars(); // If corruption is crossing 50%, add extra visual effects if (oldCorruption < 50 && self.corruption >= 50 || amount > 5) { // Create more intense visual distortion for (var i = 0; i < 3; i++) { LK.setTimeout(function () { triggerGlitch(); }, i * 100); } // Create a momentary darkness effect var originalBg = game.backgroundColor; game.setBackgroundColor(0x333344); LK.setTimeout(function () { game.setBackgroundColor(originalBg); }, 200); } }; self.evolve = function (stage) { self.stage = stage; LK.getSound('transform').play(); // Create a strong glitch effect for evolution for (var i = 0; i < 10; i++) { LK.setTimeout(function () { triggerGlitch(); }, i * 200); } // Show strong visual change tween(body, { scaleX: 1.3, scaleY: 1.3, alpha: 0.5 }, { duration: 500, onFinish: function onFinish() { self.updateAppearance(); tween(body, { scaleX: 1, scaleY: 1, alpha: 1 }, { duration: 500 }); } }); }; self.updateAppearance = function () { // Base form - cute and blue if (self.stage === 0) { body.tint = 0xaae1fc; // Make eyes red when any stat gets too low (below 20) if (self.hunger < 20 || self.happiness < 20 || self.cleanliness < 20) { self.leftEye.tint = 0xff0000; self.rightEye.tint = 0xff0000; // NIGHTMARE MODE when stats are critically low AND corruption is 100% if (self.hunger < 10 && self.happiness < 10 && self.cleanliness < 10 && self.corruption >= 100) { // Turn pet body dark red body.tint = 0x330000; // Distort eyes to look evil self.leftEye.scaleX = 1.8; self.leftEye.scaleY = 0.4; self.rightEye.scaleX = 1.8; self.rightEye.scaleY = 0.4; // Make mouth distorted and evil self.mouth.tint = 0xff0000; self.mouth.scaleX = 2.0; self.mouth.scaleY = 0.3; self.mouth.rotation = 0.8; self.mouth.y = 70; // Make title text change if (titleText) { titleText.setText("DIGITAL PET NIGHTMARE"); titleText.fill = 0xff0000; // Make it shake titleText.x = 2048 / 2 + (Math.random() - 0.5) * 10; titleText.y = 100 + (Math.random() - 0.5) * 10; // Add a glowing effect titleText.alpha = 0.7 + Math.random() * 0.3; // Flicker effect } // Make evolution/corruption text change if (corruptionLabel) { corruptionLabel.setText("DIE DIE DIE DIE DIE DIE DIE DIE DIE DIE DIE DIE"); corruptionLabel.fill = 0xff0000; corruptionLabel.alpha = 1.0; // Make sure it's fully visible } } } else { self.leftEye.tint = 0x000000; self.rightEye.tint = 0x000000; } self.mouth.tint = 0x9966cc; self.leftEye.x = -70; self.rightEye.x = 70; self.leftEye.y = self.rightEye.y = -50; self.mouth.y = 30; // Reset any distortions if not in nightmare mode if (!(self.hunger < 10 && self.happiness < 10 && self.cleanliness < 10)) { self.leftEye.scaleX = self.leftEye.scaleY = 1; self.rightEye.scaleX = self.rightEye.scaleY = 1; self.mouth.scaleX = self.mouth.scaleY = 1; self.mouth.rotation = 0; } } // Stage 1 - starting to evolve else if (self.stage === 1) { body.tint = 0x99ddaa; // More green tint // Make eyes red when any stat gets too low (below 20) if (self.hunger < 20 || self.happiness < 20 || self.cleanliness < 20) { self.leftEye.tint = 0xff0000; self.rightEye.tint = 0xff0000; } else { self.leftEye.tint = 0x000000; self.rightEye.tint = 0x000000; } self.mouth.tint = 0x6655cc; // Slight asymmetry self.leftEye.x = -75; self.rightEye.x = 68; self.leftEye.scaleX = 1.1; self.rightEye.scaleX = 0.9; self.mouth.rotation = 0.1; } // Stage 2 - adolescent form else if (self.stage === 2) { body.tint = 0x77aacc; // More vibrant blue // Make eyes red when any stat gets too low (below 20) if (self.hunger < 20 || self.happiness < 20 || self.cleanliness < 20) { self.leftEye.tint = 0xff0000; self.rightEye.tint = 0xff0000; } else { self.leftEye.tint = 0x000088; // Blue eyes self.rightEye.tint = 0x000088; } self.mouth.tint = 0x5566dd; // More distinct features self.leftEye.x = -80; self.rightEye.x = 65; self.leftEye.y = -55; self.rightEye.y = -45; self.leftEye.scaleX = 1.2; self.leftEye.scaleY = 0.9; self.rightEye.scaleX = 0.9; self.rightEye.scaleY = 1.2; self.mouth.y = 60; self.mouth.scaleX = 1.2; self.mouth.rotation = 0.2; } // Stage 3 - final form else if (self.stage === 3) { body.tint = 0x5577cc; // Deeper blue // Make eyes red when any stat gets too low (below 20) if (self.hunger < 20 || self.happiness < 20 || self.cleanliness < 20) { self.leftEye.tint = 0xff0000; self.rightEye.tint = 0xff0000; } else { self.leftEye.tint = 0x0000ff; // Brighter blue eyes self.rightEye.tint = 0x0000ff; } self.mouth.tint = 0x6644dd; // Adult features self.leftEye.x = -85; self.rightEye.x = 65; self.leftEye.y = -60; self.rightEye.y = -40; self.leftEye.scaleX = 1.4; self.leftEye.scaleY = 0.8; self.rightEye.scaleX = 0.8; self.rightEye.scaleY = 1.4; self.mouth.y = 70; self.mouth.scaleX = 1.4; self.mouth.scaleY = 0.8; self.mouth.rotation = 0.3; } }; // Idle animations LK.setInterval(function () { self.blink(); }, 3000 + Math.random() * 2000); LK.setInterval(function () { self.breathe(); }, 2000); return self; }); var PlayOptionsMenu = Container.expand(function () { var self = Container.call(this); // Create menu background var background = self.attachAsset('cleanButton', { anchorX: 0.5, anchorY: 0.5, scaleX: 3, scaleY: 3, tint: 0x333333, alpha: 0.9 }); // Title text var titleText = new Text2("Play Options", { size: 60, fill: 0xFFFFFF }); titleText.anchor.set(0.5, 0.5); titleText.y = -180; self.addChild(titleText); // Option buttons var ballButton = self.attachAsset('buttonIcon', { anchorX: 0.5, anchorY: 0.5, x: -100, y: 0, tint: 0xFF4444 }); var ballLabel = new Text2("Play Ball", { size: 40, fill: 0xFFFFFF }); ballLabel.anchor.set(0.5, 0.5); ballLabel.y = 100; ballButton.addChild(ballLabel); var arcadeButton = self.attachAsset('buttonIcon', { anchorX: 0.5, anchorY: 0.5, x: 100, y: 0, tint: 0x44AAFF }); var arcadeLabel = new Text2("Arcade", { size: 40, fill: 0xFFFFFF }); arcadeLabel.anchor.set(0.5, 0.5); arcadeLabel.y = 100; arcadeButton.addChild(arcadeLabel); // Make buttons interactive ballButton.interactive = true; arcadeButton.interactive = true; ballButton.down = function () { // Choose ball play option self.hide(); if (ball) { ball.activate(); } }; arcadeButton.down = function () { // Choose arcade play option self.hide(); if (arcadeGame) { arcadeGame.startGame(); } }; // Close button var closeButton = self.attachAsset('buttonIcon', { anchorX: 0.5, anchorY: 0.5, x: 180, y: -180, scaleX: 0.5, scaleY: 0.5, tint: 0xFF4444 }); var closeLabel = new Text2("X", { size: 40, fill: 0xFFFFFF }); closeLabel.anchor.set(0.5, 0.5); closeButton.addChild(closeLabel); closeButton.interactive = true; closeButton.down = function () { self.hide(); }; self.show = function () { self.visible = true; self.alpha = 0; tween(self, { alpha: 1 }, { duration: 200 }); }; self.hide = function () { tween(self, { alpha: 0 }, { duration: 200, onFinish: function onFinish() { self.visible = false; } }); }; self.visible = false; return self; }); var Vacuum = Container.expand(function () { var self = Container.call(this); // Create vacuum using vacuum asset var vacuumBody = self.attachAsset('vacuum', { anchorX: 0.5, anchorY: 0.5, tint: 0xFFFFFF // Natural color for vacuum }); // Create vacuum nozzle var nozzle = self.attachAsset('vacuumNozzle', { anchorX: 0.5, anchorY: 0.5, scaleX: 1.0, scaleY: 1.0, x: 50, y: -20, tint: 0xFFFFFF // Natural color for nozzle }); // Create visual suction effect var suctionEffect = self.attachAsset('buttonIcon', { anchorX: 0.5, anchorY: 0.5, x: 80, y: -20, scaleX: 0.6, scaleY: 0.6, alpha: 0.6, tint: 0xaaaaff // Blue-ish suction effect }); self.startupPosition = { x: 0, y: 0 }; self.active = false; self.cleaning = false; // Animation for the suction effect self.animateSuction = function () { if (!self.active) { return; } tween(suctionEffect, { scaleX: 0.3, scaleY: 0.3, alpha: 0.3 }, { duration: 300, onFinish: function onFinish() { if (self.active) { tween(suctionEffect, { scaleX: 0.6, scaleY: 0.6, alpha: 0.6 }, { duration: 300, onFinish: self.animateSuction }); } } }); }; self.activate = function () { self.active = true; self.visible = true; // Store original position to return to self.startupPosition = { x: self.x, y: self.y }; // Move vacuum above the button and make it bigger self.y = self.y - 250; // Start suction animation self.animateSuction(); // Visual feedback that it's active - make it 2x bigger and apply tweening tween(self, { scaleX: 2.0, scaleY: 2.0 }, { duration: 200 }); }; self.deactivate = function () { self.active = false; // Return to original position with animation tween(self, { x: self.startupPosition.x, y: self.startupPosition.y }, { duration: 500, onFinish: function onFinish() { self.visible = false; // Reset scale vacuumBody.scaleX = vacuumBody.scaleY = 1.0; } }); }; self.cleanPet = function () { if (self.cleaning) { return; } self.cleaning = true; // Visual feedback for cleaning tween(suctionEffect, { scaleX: 1.0, scaleY: 1.0, alpha: 0.9 }, { duration: 300 }); // After cleaning is done, deactivate LK.setTimeout(function () { self.cleaning = false; self.deactivate(); }, 1000); }; self.visible = false; self.active = false; return self; }); /**** * Initialize Game ****/ var game = new LK.Game({ backgroundColor: 0x000000 }); /**** * Game Code ****/ // Game variables var pet; var feedButton, playButton, cleanButton; var statusBars = {}; var corruptionMeter; var gameTime = 0; var glitchEffects = []; var corruptionParticles = []; var gameStarted = false; var corruptionTextGlitching = false; var textGlitchTimer = null; var corruptionLabel; var titleText; var vacuum; var draggedItem = null; var food; var ball; var arcadeGame; var playOptionsMenu; // Initialize game elements function initGame() { // Setup background game.setBackgroundColor(0x66aadd); // Create pet pet = new Pet(); pet.x = 2048 / 2; pet.y = 2732 / 2 - 200; game.addChild(pet); // Create UI controls feedButton = new Button('feed'); feedButton.x = 2048 / 4; feedButton.y = 2732 - 200; game.addChild(feedButton); playButton = new Button('play'); playButton.x = 2048 / 2; playButton.y = 2732 - 200; game.addChild(playButton); cleanButton = new Button('clean'); cleanButton.x = 2048 * 3 / 4; cleanButton.y = 2732 - 200; game.addChild(cleanButton); // Add the Abandon button var abandonButton = new AbandonButton(); abandonButton.x = 2048 - 100; abandonButton.y = 100; game.addChild(abandonButton); // Add the Ignore (iPhone) button var ignoreButton = new IgnoreButton(); ignoreButton.x = 100; ignoreButton.y = 2732 / 2; game.addChild(ignoreButton); // Create status bars createStatusBars(); // Create glitch effects for (var i = 0; i < 10; i++) { var glitch = new GlitchEffect(); game.addChild(glitch); glitchEffects.push(glitch); } // Create corruption particles for (var i = 0; i < 50; i++) { var particle = new CorruptionParticle(); game.addChild(particle); corruptionParticles.push(particle); } // Create vacuum cleaner vacuum = new Vacuum(); vacuum.x = cleanButton.x; vacuum.y = cleanButton.y - 100; vacuum.visible = false; game.addChild(vacuum); // Create draggable food food = new Food(); food.x = feedButton.x; food.y = feedButton.y - 150; game.addChild(food); // Create play ball ball = new Ball(); ball.x = playButton.x; ball.y = playButton.y - 150; game.addChild(ball); // Create arcade game arcadeGame = new ArcadeGame(); arcadeGame.x = 2048 / 2; arcadeGame.y = 2732 / 2 - 200; game.addChild(arcadeGame); // Create play options menu playOptionsMenu = new PlayOptionsMenu(); playOptionsMenu.x = 2048 / 2; playOptionsMenu.y = 2732 / 2 - 200; game.addChild(playOptionsMenu); // Create and add title titleText = new Text2("Digital Pet Friend", { size: 100, fill: 0xFFFFFF }); titleText.anchor.set(0.5, 0); titleText.x = 2048 / 2; titleText.y = 100; LK.gui.addChild(titleText); // Create game instructions var instructionsText = new Text2("Feed, play with, and clean your pet to keep it happy. Watch how it evolves over time!", { size: 40, fill: 0xDDDDDD }); instructionsText.anchor.set(0.5, 0); instructionsText.x = 2048 / 2; instructionsText.y = 220; instructionsText.width = 1800; LK.gui.addChild(instructionsText); // Start game music LK.playMusic('petMusic', { fade: { start: 0, end: 0.8, duration: 1000 } }); // Create and initialize the stats checker for nightmare mode var statsChecker = new CheckStats(); game.addChild(statsChecker); gameStarted = true; } function createStatusBars() { // Create container for all status bars var statusContainer = new Container(); statusContainer.x = 2048 / 2; statusContainer.y = 400; game.addChild(statusContainer); // Create each status bar var statusTypes = [{ name: 'hunger', label: 'Hunger', color: 0x22cc88 }, { name: 'happiness', label: 'Happiness', color: 0xff8822 }, { name: 'cleanliness', label: 'Cleanliness', color: 0x2288ff }]; var yOffset = 0; for (var i = 0; i < statusTypes.length; i++) { var type = statusTypes[i]; // Create label var label = new Text2(type.label, { size: 40, fill: 0xFFFFFF }); label.anchor.set(1, 0.5); label.x = -20; label.y = yOffset; statusContainer.addChild(label); // Create background bar var barBg = LK.getAsset('feedButton', { anchorX: 0, anchorY: 0.5, x: 0, y: yOffset, scaleX: 4, scaleY: 0.5, tint: 0x444444 }); statusContainer.addChild(barBg); // Create value bar var bar = LK.getAsset('feedButton', { anchorX: 0, anchorY: 0.5, x: 0, y: yOffset, scaleX: 4, scaleY: 0.5, tint: type.color }); statusContainer.addChild(bar); // Store reference to bar statusBars[type.name] = bar; yOffset += 60; } // Create evolution meter corruptionLabel = new Text2("Evolution", { size: 40, fill: 0xFFFFFF // Change from blue to white for better visibility }); var corruptionTextGlitching = false; var textGlitchTimer = null; corruptionLabel.anchor.set(1, 0.5); corruptionLabel.x = -20; corruptionLabel.y = yOffset; statusContainer.addChild(corruptionLabel); var corruptionBg = LK.getAsset('feedButton', { anchorX: 0, anchorY: 0.5, x: 0, y: yOffset, scaleX: 4, scaleY: 0.5, tint: 0x444444 }); statusContainer.addChild(corruptionBg); corruptionMeter = LK.getAsset('feedButton', { anchorX: 0, anchorY: 0.5, x: 0, y: yOffset, scaleX: 0, scaleY: 0.5, tint: 0x44AAFF }); statusContainer.addChild(corruptionMeter); } function updateStatusBars() { if (!gameStarted) { return; } // Update status bars based on pet stats statusBars.hunger.scaleX = pet.hunger / 25; statusBars.happiness.scaleX = pet.happiness / 25; statusBars.cleanliness.scaleX = pet.cleanliness / 25; // Update corruption meter corruptionMeter.scaleX = pet.corruption / 25; // Calculate average status to determine visual darkness var avgStatus = (pet.hunger + pet.happiness + pet.cleanliness) / 3; // Adjust game visuals based on average status - darker and less vibrant as stats decrease var darknessLevel = 1 - avgStatus / 100; var saturationReduction = darknessLevel * 0.5; var brightnessReduction = darknessLevel * 0.5; // Adjust background color (from light blue to darker desaturated blue) var r = Math.round(102 * (1 - brightnessReduction)); var g = Math.round(170 * (1 - brightnessReduction - saturationReduction)); var b = Math.round(221 * (1 - brightnessReduction)); game.setBackgroundColor(r << 16 | g << 8 | b); // Adjust visual elements opacity based on status pet.alpha = 0.5 + avgStatus / 200; // Fade pet slightly as status decreases } function triggerGlitch() { // Play sparkle sound LK.getSound('glitch').play(); // Check for nightmare mode var nightmareMode = pet && pet.hunger < 10 && pet.happiness < 10 && pet.cleanliness < 10; // Visual glitch effects - intensify based on corruption level or nightmare mode var intensity = nightmareMode ? 10 : pet.corruption > 50 ? 5 : 3; for (var i = 0; i < intensity; i++) { var glitch = glitchEffects[Math.floor(Math.random() * glitchEffects.length)]; glitch.startGlitch(); } // If corruption is above 50%, add stronger visual distortions if (pet.corruption > 50 && Math.random() < 0.5) { // Briefly distort the entire game view var originalScale = game.scale.x; tween(game.scale, { x: originalScale * (1 + (Math.random() - 0.5) * 0.1), y: originalScale * (1 + (Math.random() - 0.5) * 0.1) }, { duration: 100, onFinish: function onFinish() { tween(game.scale, { x: originalScale, y: originalScale }, { duration: 100 }); } }); } // Temporarily distort pet if (Math.random() < 0.3) { var originalRotation = pet.rotation; tween(pet, { rotation: originalRotation + (Math.random() - 0.5) * 0.3 }, { duration: 150, onFinish: function onFinish() { tween(pet, { rotation: originalRotation }, { duration: 150 }); } }); } // Screen shake if (Math.random() < 0.2) { var originalX = game.x; var originalY = game.y; tween(game, { x: originalX + (Math.random() - 0.5) * 20 }, { duration: 100, onFinish: function onFinish() { tween(game, { x: originalX }, { duration: 100 }); } }); } } function spawnCorruptionParticle() { // Find an inactive particle for (var i = 0; i < corruptionParticles.length; i++) { var particle = corruptionParticles[i]; if (!particle.active) { // Calculate position relative to pet var offsetX = (Math.random() - 0.5) * 300; var offsetY = (Math.random() - 0.5) * 300; particle.initialize(pet.x + offsetX, pet.y + offsetY, 60 + Math.floor(Math.random() * 60)); break; } } } // Add event handlers for dragging game.down = function (x, y, obj) { // Get event position directly // Check if we clicked on the vacuum when it's active if (vacuum && vacuum.active && vacuum.visible) { // Use direct hit testing instead of bounds checking if (x >= vacuum.x - vacuum.width / 2 && x <= vacuum.x + vacuum.width / 2 && y >= vacuum.y - vacuum.height / 2 && y <= vacuum.y + vacuum.height / 2) { draggedItem = vacuum; } } // Check if we clicked on the food when it's active if (food && food.active && food.visible) { // Use direct hit testing if (x >= food.x - food.width / 2 && x <= food.x + food.width / 2 && y >= food.y - food.height / 2 && y <= food.y + food.height / 2) { draggedItem = food; } } // Check if we clicked on the ball when it's active if (ball && ball.active && ball.visible) { // Use direct hit testing if (x >= ball.x - ball.width / 2 && x <= ball.x + ball.width / 2 && y >= ball.y - ball.height / 2 && y <= ball.y + ball.height / 2) { draggedItem = ball; } } }; game.up = function (x, y, obj) { if (draggedItem === vacuum) { // Use simplified distance-based collision detection for better results var dx = vacuum.x - pet.x; var dy = vacuum.y - pet.y; var distance = Math.sqrt(dx * dx + dy * dy); // If vacuum is within 200px of pet center, consider it a hit if (distance < 200) { // Vacuum is over the pet - clean it! vacuum.cleanPet(); pet.clean(); // This now has modified behavior for vacuum } else { // Not over pet, return vacuum vacuum.deactivate(); } draggedItem = null; } else if (draggedItem === food) { // Check if food is near pet's mouth var dx = food.x - pet.x; var dy = food.y - (pet.y + pet.mouth.y); var distance = Math.sqrt(dx * dx + dy * dy); // If food is within 100px of pet's mouth, consider it a hit if (distance < 100) { // Feed the pet pet.feed(); food.deactivate(); } else { // Return food to original position food.returnToPosition(); } draggedItem = null; } else if (draggedItem === ball) { // Check if ball is near pet var dx = ball.x - pet.x; var dy = ball.y - pet.y; var distance = Math.sqrt(dx * dx + dy * dy); if (distance < 150) { // Play with pet using the ball pet.play(); ball.deactivate(); } else { // Return ball to original position ball.returnToPosition(); } draggedItem = null; } }; game.move = function (x, y, obj) { if (draggedItem) { // Use coordinates directly - no need to convert with toLocal draggedItem.x = x; draggedItem.y = y; } }; // Game Update Logic game.update = function () { if (!gameStarted) { initGame(); return; } gameTime++; // Update pet stats if (gameTime % 30 === 0) { pet.updateStats(); updateStatusBars(); // Check for nightmare mode - only if corruption is 100% var nightmareMode = pet.hunger < 10 && pet.happiness < 10 && pet.cleanliness < 10 && pet.corruption >= 100; // If in nightmare mode, apply special effects continuously if (nightmareMode) { // Occasional screen flashes if (Math.random() < 0.1) { LK.effects.flashScreen(0xff0000, 200); } // Random background color flashes if (Math.random() < 0.1) { var originalBg = game.backgroundColor; game.setBackgroundColor(0x330000); LK.setTimeout(function () { game.setBackgroundColor(originalBg); }, 100); } // Random glitches if (Math.random() < 0.2) { triggerGlitch(); } // Make title text shake constantly if (titleText) { titleText.x = 2048 / 2 + (Math.random() - 0.5) * 20; titleText.y = 100 + (Math.random() - 0.5) * 20; } // Make DIE text flash if (corruptionLabel && Math.random() < 0.5) { corruptionLabel.setText("DIE DIE DIE DIE DIE DIE DIE DIE DIE DIE DIE DIE"); corruptionLabel.fill = Math.random() < 0.5 ? 0xff0000 : 0xffff00; // Add pulsing effect for more intensity corruptionLabel.scaleX = corruptionLabel.scaleY = 1 + Math.random() * 0.3; } } // Handle corruption text glitching when corruption is around halfway and not in nightmare mode else if (pet.corruption >= 40 && pet.corruption <= 60) { if (!corruptionTextGlitching) { corruptionTextGlitching = true; textGlitchTimer = LK.setInterval(function () { // Toggle between "Evolution" and "Corruption" if (corruptionLabel.text === "Evolution") { corruptionLabel.setText("Corruption"); // Add slight visual glitch effect tween(corruptionLabel, { rotation: (Math.random() - 0.5) * 0.1 }, { duration: 100 }); } else { corruptionLabel.setText("Evolution"); // Reset rotation tween(corruptionLabel, { rotation: 0 }, { duration: 100 }); } }, 400); } } else if (corruptionTextGlitching && !nightmareMode) { // Stop glitching when out of the 40-60 range corruptionTextGlitching = false; LK.clearInterval(textGlitchTimer); corruptionLabel.setText(pet.corruption < 50 ? "Evolution" : "Corruption"); corruptionLabel.rotation = 0; } } // Spawn corruption particles based on corruption level if (pet.corruption > 30 && gameTime % Math.max(5, 30 - pet.corruption / 5) === 0) { spawnCorruptionParticle(); } // Automatically spawn vacuum cleaner periodically when pet needs cleaning if (pet.cleanliness < 50 && !vacuum.active && gameTime % 300 === 0) { vacuum.x = cleanButton.x; vacuum.y = cleanButton.y; vacuum.activate(); } // Update all corruption particles for (var i = 0; i < corruptionParticles.length; i++) { corruptionParticles[i].update(); } // Update arcade game if active if (arcadeGame && arcadeGame.active) { arcadeGame.update(); } // Random glitches when heavily corrupted if (pet.corruption > 70 && Math.random() < 0.005) { triggerGlitch(); } // Check for game over condition if (pet.corruption >= 100 && pet.hunger <= 0 && pet.happiness <= 0 && pet.cleanliness <= 0) { // Nightmare complete for (var i = 0; i < 20; i++) { LK.setTimeout(function () { triggerGlitch(); }, i * 100); } LK.setTimeout(function () { LK.showGameOver(); }, 2000); } };
/****
* Plugins
****/
var tween = LK.import("@upit/tween.v1");
var storage = LK.import("@upit/storage.v1");
/****
* Classes
****/
var AbandonButton = Container.expand(function () {
var self = Container.call(this);
var buttonShape = self.attachAsset('cleanButton', {
anchorX: 0.5,
anchorY: 0.5,
tint: 0xcc0000 // Red color for warning
});
var label = new Text2("ABANDON", {
size: 40,
fill: 0xFFFFFF
});
label.anchor.set(0.5, 0.5);
self.addChild(label);
self.interactive = true;
self.down = function (x, y, obj) {
tween(buttonShape, {
scaleX: 0.9,
scaleY: 0.9
}, {
duration: 100,
easing: tween.easeOut
});
};
self.up = function (x, y, obj) {
tween(buttonShape, {
scaleX: 1.0,
scaleY: 1.0
}, {
duration: 100,
easing: tween.easeOut
});
// Trigger nightmare mode
self.triggerNightmareMode();
};
self.triggerNightmareMode = function () {
// Add massive corruption to instantly transform pet
if (pet) {
// Maximum corruption
pet.addCorruption(100);
// Only activate nightmare mode if corruption is at 100%
if (pet.corruption >= 100) {
// Make everything scary
// Dark background
game.setBackgroundColor(0x110011);
// Intense glitch effects
for (var i = 0; i < 20; i++) {
LK.setTimeout(function () {
triggerGlitch();
}, i * 100);
}
// Make pet eyes red and distorted
if (pet.leftEye && pet.rightEye) {
pet.leftEye.tint = 0xff0000;
pet.rightEye.tint = 0xff0000;
// Distort eyes
tween(pet.leftEye, {
scaleX: 1.8,
scaleY: 0.6
}, {
duration: 500
});
tween(pet.rightEye, {
scaleX: 0.6,
scaleY: 1.8
}, {
duration: 500
});
}
// Distort mouth
if (pet.mouth) {
pet.mouth.tint = 0xff0000;
tween(pet.mouth, {
scaleX: 2.0,
scaleY: 0.5,
rotation: 0.5
}, {
duration: 500
});
}
// Reduce all pet stats to minimum
pet.hunger = 1;
pet.happiness = 1;
pet.cleanliness = 1;
updateStatusBars();
// Play glitch sound rapidly
for (var i = 0; i < 5; i++) {
LK.setTimeout(function () {
LK.getSound('glitch').play();
}, i * 200);
}
}
}
};
return self;
});
var ArcadeGame = Container.expand(function () {
var self = Container.call(this);
// Game state
self.active = false;
self.score = 0;
self.gameOver = false;
self.playerX = 0;
self.targets = [];
self.timeRemaining = 30; // 30 second game
self.lastCountdownTime = 0;
self.lives = 3; // Player has 3 lives
// Create game background
var background = self.attachAsset('cleanButton', {
anchorX: 0.5,
anchorY: 0.5,
scaleX: 8,
// Increased size
scaleY: 9,
// Increased size
tint: 0x000000
});
// Create player - use pet body asset instead of generic shape
var player = self.attachAsset('petBody', {
anchorX: 0.5,
anchorY: 0.5,
scaleX: 0.3,
scaleY: 0.3,
y: 200,
tint: 0x44FF44
});
// Create score text
var scoreText = new Text2("Score: 0", {
size: 40,
fill: 0xFFFFFF
});
scoreText.anchor.set(0.5, 0.5);
scoreText.y = -350;
self.addChild(scoreText);
// Create countdown text
var countdownText = new Text2("Time: 30", {
size: 40,
fill: 0xFFFFFF
});
countdownText.anchor.set(0.5, 0.5);
countdownText.y = -300;
self.addChild(countdownText);
// Create lives display
var livesText = new Text2("Lives: 3", {
size: 40,
fill: 0xFFFFFF
});
livesText.anchor.set(0.5, 0.5);
livesText.y = -250;
self.addChild(livesText);
// Create game controls
var leftButton = self.attachAsset('cleanButton', {
anchorX: 0.5,
anchorY: 0.5,
scaleX: 1.0,
scaleY: 1.0,
x: -150,
y: 300,
tint: 0x4488FF
});
var rightButton = self.attachAsset('cleanButton', {
anchorX: 0.5,
anchorY: 0.5,
scaleX: 1.0,
scaleY: 1.0,
x: 150,
y: 300,
tint: 0x4488FF
});
// Add arrow indicators to buttons
var leftArrow = new Text2("<", {
size: 80,
fill: 0xFFFFFF
});
leftArrow.anchor.set(0.5, 0.5);
leftButton.addChild(leftArrow);
var rightArrow = new Text2(">", {
size: 80,
fill: 0xFFFFFF
});
rightArrow.anchor.set(0.5, 0.5);
rightButton.addChild(rightArrow);
// Make buttons interactive
leftButton.interactive = true;
rightButton.interactive = true;
leftButton.down = function () {
self.movePlayer(-10);
};
rightButton.down = function () {
self.movePlayer(10);
};
// Initialize targets
for (var i = 0; i < 5; i++) {
var target = self.attachAsset('food', {
anchorX: 0.5,
anchorY: 0.5,
x: (Math.random() - 0.5) * 300,
y: -150 - Math.random() * 100,
scaleX: 0.7,
scaleY: 0.7,
visible: false
});
self.targets.push({
sprite: target,
active: false,
speed: 2 + Math.random() * 1.5 // Reduced from 3+random*2 to make it easier
});
}
self.movePlayer = function (amount) {
if (!self.active || self.gameOver) {
return;
}
self.playerX += amount;
// Keep player within bounds
self.playerX = Math.max(-150, Math.min(150, self.playerX));
// Use tween for smoother movement
tween(player, {
x: self.playerX,
rotation: amount > 0 ? 0.1 : amount < 0 ? -0.1 : 0 // Tilt in direction of movement
}, {
duration: 150,
easing: tween.easeOut,
onFinish: function onFinish() {
// Return to neutral rotation
if (amount !== 0) {
tween(player, {
rotation: 0
}, {
duration: 100
});
}
}
});
};
self.updateTargets = function () {
var activeCount = 0;
// Update existing targets
for (var i = 0; i < self.targets.length; i++) {
var target = self.targets[i];
if (target.active) {
activeCount++;
// Move target down
target.sprite.y += target.speed;
// Check if player caught the target
var dx = target.sprite.x - player.x;
var dy = target.sprite.y - player.y;
var distance = Math.sqrt(dx * dx + dy * dy);
if (distance < 40) {
// Caught target - increase score
self.score += 10;
scoreText.setText("Score: " + self.score);
// Deactivate target
target.active = false;
target.sprite.visible = false;
}
// Check if target reached bottom
if (target.sprite.y > 250) {
// Target missed
target.active = false;
target.sprite.visible = false;
// Decrease lives instead of ending game immediately
self.lives--;
livesText.setText("Lives: " + self.lives);
// Flash lives text red
tween(livesText, {
tint: 0xFF0000
}, {
duration: 200,
onFinish: function onFinish() {
tween(livesText, {
tint: 0xFFFFFF
}, {
duration: 200
});
}
});
// End game if no lives left
if (self.lives <= 0) {
self.gameOver = true;
self.endGame();
}
}
}
}
// Spawn new target if needed - further reduced spawn rate from 0.02 to 0.01
if (activeCount < 1 && Math.random() < 0.01 && !self.gameOver) {
var randomTarget = self.targets[Math.floor(Math.random() * self.targets.length)];
if (!randomTarget.active) {
randomTarget.active = true;
randomTarget.sprite.visible = true;
randomTarget.sprite.x = (Math.random() - 0.5) * 300;
randomTarget.sprite.y = -200;
}
}
};
self.startGame = function () {
self.visible = true;
self.active = true;
self.gameOver = false;
self.score = 0;
self.playerX = 0;
player.x = 0;
scoreText.setText("Score: 0");
// Reset countdown
self.timeRemaining = 30;
self.lastCountdownTime = 0;
countdownText.setText("Time: 30");
// Reset lives
self.lives = 3;
livesText.setText("Lives: 3");
// Reset all targets
for (var i = 0; i < self.targets.length; i++) {
self.targets[i].active = false;
self.targets[i].sprite.visible = false;
}
};
self.endGame = function () {
// Show game over message
var gameOverText = new Text2("Game Over!", {
size: 60,
fill: 0xFF4444
});
gameOverText.anchor.set(0.5, 0.5);
self.addChild(gameOverText);
// Show final score with any time bonus
var finalScore = self.score;
if (self.timeRemaining > 0) {
// Add bonus points for remaining time
var timeBonus = self.timeRemaining * 5;
finalScore += timeBonus;
// Show bonus message
var bonusText = new Text2("Time Bonus: +" + timeBonus, {
size: 40,
fill: 0x44FF44
});
bonusText.anchor.set(0.5, 0.5);
bonusText.y = 60;
gameOverText.addChild(bonusText);
// Update score display
scoreText.setText("Final Score: " + finalScore);
}
// Hide game over and give reward after delay
LK.setTimeout(function () {
self.deactivate();
// Increase pet happiness based on score - boosted happiness gain
if (pet) {
var happinessBoost = Math.min(60, finalScore / 8); // Increased from 50 to 60, and divided by 8 instead of 10
pet.happiness = Math.min(100, pet.happiness + happinessBoost);
// Don't decrease hunger when playing arcade game
updateStatusBars();
}
}, 3000);
};
self.update = function () {
if (!self.active) {
return;
}
self.updateTargets();
// Update countdown timer (every second)
var currentTime = Math.floor(LK.ticks / 60);
if (currentTime > self.lastCountdownTime) {
self.lastCountdownTime = currentTime;
self.timeRemaining--;
countdownText.setText("Time: " + self.timeRemaining);
// Flash countdown text when time is running out (less than 10 seconds)
if (self.timeRemaining <= 10) {
tween(countdownText, {
tint: 0xFF0000
}, {
duration: 200,
onFinish: function onFinish() {
tween(countdownText, {
tint: 0xFFFFFF
}, {
duration: 200
});
}
});
}
// End game when time runs out
if (self.timeRemaining <= 0) {
self.gameOver = true;
self.endGame();
}
}
};
self.deactivate = function () {
self.active = false;
tween(self, {
alpha: 0
}, {
duration: 300,
onFinish: function onFinish() {
self.visible = false;
self.alpha = 1;
}
});
};
self.visible = false;
return self;
});
var Ball = Container.expand(function () {
var self = Container.call(this);
// Create ball using toy asset instead of buttonIcon
var ballGraphics = self.attachAsset('toy', {
anchorX: 0.5,
anchorY: 0.5,
scaleX: 1.2,
scaleY: 1.2
});
// Add some decoration to make it look more like a ball
var highlight = self.attachAsset('buttonIcon', {
anchorX: 0.5,
anchorY: 0.5,
scaleX: 0.3,
scaleY: 0.3,
x: -15,
y: -15,
tint: 0xFFFFFF,
alpha: 0.7
});
self.interactive = true;
self.visible = false;
self.active = false;
self.originalX = 0;
self.originalY = 0;
self.down = function (x, y, obj) {
// Scale down when pressed
tween(ballGraphics, {
scaleX: 0.9,
scaleY: 0.9
}, {
duration: 100,
easing: tween.easeOut
});
};
self.up = function (x, y, obj) {
// Restore scale when released
tween(ballGraphics, {
scaleX: 1.0,
scaleY: 1.0
}, {
duration: 100,
easing: tween.easeOut
});
if (self.active) {
// Check if ball is near pet
var dx = self.x - pet.x;
var dy = self.y - pet.y;
var distance = Math.sqrt(dx * dx + dy * dy);
if (distance < 150) {
// Play with pet using the ball
pet.play();
self.deactivate();
} else {
// Return to original position
self.returnToPosition();
}
}
};
self.activate = function () {
self.visible = true;
self.active = true;
self.originalX = playButton.x;
self.originalY = playButton.y - 150;
self.x = self.originalX;
self.y = self.originalY;
// Animation to indicate it's ready
tween(ballGraphics, {
scaleX: 1.2,
scaleY: 1.2
}, {
duration: 200,
onFinish: function onFinish() {
tween(ballGraphics, {
scaleX: 1.0,
scaleY: 1.0
}, {
duration: 200
});
}
});
};
self.deactivate = function () {
self.active = false;
// Fade out
tween(self, {
alpha: 0
}, {
duration: 300,
onFinish: function onFinish() {
self.visible = false;
self.alpha = 1;
}
});
};
self.returnToPosition = function () {
tween(self, {
x: self.originalX,
y: self.originalY
}, {
duration: 300
});
};
return self;
});
var Button = Container.expand(function (type) {
var self = Container.call(this);
self.type = type;
self.onCooldown = false;
self.cooldownDuration = 2000; // 2 seconds cooldown
var buttonShape = self.attachAsset(type + 'Button', {
anchorX: 0.5,
anchorY: 0.5
});
var icon = self.attachAsset('buttonIcon', {
anchorX: 0.5,
anchorY: 0.5,
scaleX: 0.8,
scaleY: 0.8
});
var label = new Text2(type.charAt(0).toUpperCase() + type.slice(1), {
size: 40,
fill: 0xFFFFFF
});
label.anchor.set(0.5, 0.5);
label.y = 70;
self.addChild(label);
self.interactive = true;
self.startCooldown = function () {
if (self.onCooldown) {
return;
}
self.onCooldown = true;
// Grey out the button during cooldown
tween(buttonShape, {
tint: 0x888888
}, {
duration: 100
});
// Set a timeout to end the cooldown
LK.setTimeout(function () {
self.onCooldown = false;
// Restore button color
tween(buttonShape, {
tint: 0xFFFFFF
}, {
duration: 100
});
}, self.cooldownDuration);
};
self.down = function (x, y, obj) {
tween(buttonShape, {
scaleX: 0.9,
scaleY: 0.9
}, {
duration: 100,
easing: tween.easeOut
});
};
self.up = function (x, y, obj) {
tween(buttonShape, {
scaleX: 1.0,
scaleY: 1.0
}, {
duration: 100,
easing: tween.easeOut
});
// Only act if not on cooldown
if (!self.onCooldown) {
LK.getSound(self.type).play();
self.startCooldown();
switch (self.type) {
case 'feed':
// Activate food instead of directly feeding
if (food) {
food.activate();
}
break;
case 'play':
// Show play options popup
if (playOptionsMenu && !playOptionsMenu.visible) {
playOptionsMenu.show();
} else {
// Fallback to direct play if menu isn't available
pet.play();
}
break;
case 'clean':
// Activate vacuum when clean button is clicked
if (vacuum && !vacuum.active) {
vacuum.x = cleanButton.x;
vacuum.y = cleanButton.y;
vacuum.activate();
} else {
pet.clean();
}
break;
}
}
};
return self;
});
var CheckStats = Container.expand(function () {
var self = Container.call(this);
self.lastCheck = 0;
self.checkInterval = 60; // Check every second (60 frames)
self.nightmareModeActive = false;
self.maxCorruption = 100; // Maximum corruption value
self.update = function () {
// Only check periodically to improve performance
if (LK.ticks - self.lastCheck < self.checkInterval) {
return;
}
self.lastCheck = LK.ticks;
// Check if pet exists and has critically low stats AND corruption is at 100%
if (pet && pet.hunger <= 10 && pet.happiness <= 10 && pet.cleanliness <= 10 && pet.corruption >= 100 && !self.nightmareModeActive) {
self.activateNightmareMode();
}
};
self.activateNightmareMode = function () {
self.nightmareModeActive = true;
// Send pet to maximum corruption
pet.addCorruption(self.maxCorruption);
// Show visual glitch effects
for (var i = 0; i < 20; i++) {
LK.setTimeout(function () {
triggerGlitch();
}, i * 100);
}
// Dark background for nightmare mode
game.setBackgroundColor(0x110011);
// Make pet eyes red and distorted
if (pet.leftEye && pet.rightEye) {
pet.leftEye.tint = 0xff0000;
pet.rightEye.tint = 0xff0000;
// Distort eyes
tween(pet.leftEye, {
scaleX: 1.8,
scaleY: 0.6
}, {
duration: 500
});
tween(pet.rightEye, {
scaleX: 0.6,
scaleY: 1.8
}, {
duration: 500
});
}
// Distort mouth
if (pet.mouth) {
pet.mouth.tint = 0xff0000;
tween(pet.mouth, {
scaleX: 2.0,
scaleY: 0.5,
rotation: 0.5
}, {
duration: 500
});
}
// Play glitch sound rapidly
for (var i = 0; i < 5; i++) {
LK.setTimeout(function () {
LK.getSound('glitch').play();
}, i * 200);
}
};
return self;
});
var CorruptionParticle = Container.expand(function () {
var self = Container.call(this);
var particleGraphics = self.attachAsset('corruptionEffect', {
anchorX: 0.5,
anchorY: 0.5,
alpha: 0.6
});
self.lifespan = 0;
self.maxLife = 0;
self.speedX = 0;
self.speedY = 0;
self.active = false;
self.initialize = function (x, y, duration) {
self.x = x;
self.y = y;
self.maxLife = duration;
self.lifespan = duration;
self.speedX = (Math.random() - 0.5) * 3;
self.speedY = (Math.random() - 0.5) * 3;
self.rotation = Math.random() * Math.PI * 2;
self.active = true;
self.visible = true;
self.alpha = 0.6;
// Color selection depends on corruption level - darker as corruption increases
var randomColor = Math.random();
var corruptionLevel = pet ? pet.corruption : 0;
var darkerColors = corruptionLevel > 50;
var nightmareMode = corruptionLevel >= 95;
if (nightmareMode) {
// Extremely dark, scary colors for nightmare mode
if (randomColor < 0.33) {
particleGraphics.tint = 0xff0000; // Blood red
} else if (randomColor < 0.66) {
particleGraphics.tint = 0x660000; // Dark red
} else {
particleGraphics.tint = 0x330000; // Very dark red
}
// Larger and more intense for nightmare mode
particleGraphics.scaleX = particleGraphics.scaleY = 1.5 + Math.random();
} else if (darkerColors) {
// Darker, more ominous colors when corruption is higher
if (randomColor < 0.33) {
particleGraphics.tint = 0x4455aa; // Dark blue
} else if (randomColor < 0.66) {
particleGraphics.tint = 0x335566; // Dark teal
} else {
particleGraphics.tint = 0x556677; // Dark slate
}
} else {
// Original brighter colors for lower corruption
if (randomColor < 0.33) {
particleGraphics.tint = 0x88aaff; // Light blue
} else if (randomColor < 0.66) {
particleGraphics.tint = 0x55ddaa; // Teal
} else {
particleGraphics.tint = 0xaaddff; // Sky blue
}
}
};
self.update = function () {
if (!self.active) {
return;
}
self.lifespan--;
self.x += self.speedX;
self.y += self.speedY;
self.alpha = self.lifespan / self.maxLife * 0.6;
if (self.lifespan <= 0) {
self.active = false;
self.visible = false;
}
};
self.visible = false;
self.active = false;
return self;
});
var Food = Container.expand(function () {
var self = Container.call(this);
var foodGraphics = self.attachAsset('food', {
anchorX: 0.5,
anchorY: 0.5
});
self.interactive = true;
self.visible = false;
self.active = false;
self.down = function (x, y, obj) {
// Scale down when pressed
tween(foodGraphics, {
scaleX: 0.9,
scaleY: 0.9
}, {
duration: 100,
easing: tween.easeOut
});
};
self.up = function (x, y, obj) {
// Restore scale when released
tween(foodGraphics, {
scaleX: 1.0,
scaleY: 1.0
}, {
duration: 100,
easing: tween.easeOut
});
if (self.active) {
// Check if food is near pet's mouth
var dx = self.x - pet.x;
var dy = self.y - (pet.y + pet.mouth.y);
var distance = Math.sqrt(dx * dx + dy * dy);
if (distance < 100) {
// Feed the pet
pet.feed();
self.deactivate();
} else {
// Return to original position
self.returnToPosition();
}
}
};
self.activate = function () {
self.visible = true;
self.active = true;
self.originalX = feedButton.x;
self.originalY = feedButton.y - 150;
self.x = self.originalX;
self.y = self.originalY;
// Animation to indicate it's ready
tween(foodGraphics, {
scaleX: 1.2,
scaleY: 1.2
}, {
duration: 200,
onFinish: function onFinish() {
tween(foodGraphics, {
scaleX: 1.0,
scaleY: 1.0
}, {
duration: 200
});
}
});
};
self.deactivate = function () {
self.active = false;
// Fade out
tween(self, {
alpha: 0
}, {
duration: 300,
onFinish: function onFinish() {
self.visible = false;
self.alpha = 1;
}
});
};
self.returnToPosition = function () {
tween(self, {
x: self.originalX,
y: self.originalY
}, {
duration: 300
});
};
return self;
});
var GlitchEffect = Container.expand(function () {
var self = Container.call(this);
var glitchGraphics = self.attachAsset('glitchEffect', {
anchorX: 0.5,
anchorY: 0.5,
alpha: 0.7
});
self.startGlitch = function () {
self.visible = true;
self.x = Math.random() * 2048;
self.y = Math.random() * 2732;
self.rotation = Math.random() * Math.PI * 2;
self.alpha = 0.7;
tween(self, {
alpha: 0
}, {
duration: 300 + Math.random() * 700,
onFinish: function onFinish() {
self.visible = false;
}
});
};
self.visible = false;
return self;
});
var IgnoreButton = Container.expand(function () {
var self = Container.call(this);
// Use the actual phone image rather than shape components
var phoneImage = self.attachAsset('ignorePhone', {
anchorX: 0.5,
anchorY: 0.5,
scaleX: 1.0,
scaleY: 1.0
});
// Add label
var label = new Text2("IGNORE", {
size: 50,
fill: 0xFFFFFF,
bold: true
});
label.anchor.set(0.5, 0.5);
label.y = -120;
self.addChild(label);
self.interactive = true;
self.down = function (x, y, obj) {
tween(phoneImage, {
scaleX: 0.9,
scaleY: 0.9
}, {
duration: 100,
easing: tween.easeOut
});
};
self.up = function (x, y, obj) {
tween(phoneImage, {
scaleX: 1.0,
scaleY: 1.0
}, {
duration: 100,
easing: tween.easeOut
});
// Drop all stats to very low values
self.reduceAllStats();
};
self.reduceAllStats = function () {
if (pet) {
// Set all stats to very low values
pet.hunger = 0;
pet.happiness = 0;
pet.cleanliness = 0;
// Play glitch sound
LK.getSound('glitch').play();
// Update status bars
updateStatusBars();
// Create visual effect
LK.effects.flashScreen(0x000000, 500);
// Add glitch effects
for (var i = 0; i < 10; i++) {
LK.setTimeout(function () {
triggerGlitch();
}, i * 100);
}
// Corrupt pet appearance
pet.updateAppearance();
}
};
return self;
});
var Pet = Container.expand(function () {
var self = Container.call(this);
// Stats
self.hunger = 100;
self.happiness = 100;
self.cleanliness = 100;
self.corruption = 0;
self.stage = 0; // 0 = normal, 1 = starting to corrupt, 2 = more corrupt, 3 = nightmare
// Visual components
var body = self.attachAsset('petBody', {
anchorX: 0.5,
anchorY: 0.5,
scaleX: 1,
scaleY: 1
});
// Make these properties accessible from outside for the abandon button
self.leftEye = self.attachAsset('petEye', {
anchorX: 0.5,
anchorY: 0.5,
x: -70,
y: -50
});
self.rightEye = self.attachAsset('petEye', {
anchorX: 0.5,
anchorY: 0.5,
x: 70,
y: -50
});
self.mouth = self.attachAsset('petMouth', {
anchorX: 0.5,
anchorY: 0.5,
x: 0,
y: 0
});
// Food item that appears when feeding
var foodItem = self.attachAsset('food', {
anchorX: 0.5,
anchorY: 0.5,
visible: false,
x: 0,
y: -200
});
// Toy that appears when playing
var toyItem = self.attachAsset('toy', {
anchorX: 0.5,
anchorY: 0.5,
visible: false,
x: 200,
y: 0
});
// Dirt patches that appear when pet is dirty
var dirtPatches = [];
for (var i = 0; i < 5; i++) {
var dirt = self.attachAsset('dirt', {
anchorX: 0.5,
anchorY: 0.5,
visible: false,
x: (Math.random() - 0.5) * 200,
y: (Math.random() - 0.5) * 200
});
dirtPatches.push(dirt);
}
self.blink = function () {
tween(self.leftEye, {
scaleY: 0.1
}, {
duration: 100,
onFinish: function onFinish() {
tween(self.leftEye, {
scaleY: 1
}, {
duration: 100
});
}
});
tween(self.rightEye, {
scaleY: 0.1
}, {
duration: 100,
onFinish: function onFinish() {
tween(self.rightEye, {
scaleY: 1
}, {
duration: 100
});
}
});
};
self.breathe = function () {
tween(body, {
scaleY: 1.05
}, {
duration: 1000,
onFinish: function onFinish() {
tween(body, {
scaleY: 1
}, {
duration: 1000
});
}
});
};
self.feed = function () {
self.hunger = Math.min(100, self.hunger + 30);
// Decrease cleanliness when feeding
self.cleanliness = Math.max(0, self.cleanliness - 15);
updateStatusBars();
// Make pet happy from feeding with more animated reaction
// Move slightly up with excitement
tween(self, {
y: self.y - 30
}, {
duration: 200,
easing: tween.easeOut,
onFinish: function onFinish() {
tween(self, {
y: self.y + 30
}, {
duration: 300,
easing: tween.easeIn
});
}
});
// More expressive mouth animation
tween(self.mouth, {
scaleX: 1.5,
scaleY: 1.5,
rotation: 0.1
}, {
duration: 300,
onFinish: function onFinish() {
tween(self.mouth, {
scaleX: 1,
scaleY: 1,
rotation: 0
}, {
duration: 300
});
}
});
// Sometimes add corruption from feeding in later stages
if (self.corruption > 40 && Math.random() < 0.3) {
self.addCorruption(5);
triggerGlitch();
}
};
self.play = function () {
toyItem.visible = true;
toyItem.x = 200;
tween(toyItem, {
x: 0
}, {
duration: 500,
onFinish: function onFinish() {
self.happiness = Math.min(100, self.happiness + 30);
// Decrease hunger when playing with the pet
self.hunger = Math.max(0, self.hunger - 15);
updateStatusBars();
// Bounce toy
tween(toyItem, {
y: -100
}, {
duration: 300,
easing: tween.easeOut,
onFinish: function onFinish() {
tween(toyItem, {
y: 0,
alpha: 0
}, {
duration: 300,
easing: tween.easeIn,
onFinish: function onFinish() {
toyItem.visible = false;
toyItem.alpha = 1;
}
});
}
});
// Make pet happy from playing
tween(body, {
rotation: 0.1
}, {
duration: 200,
onFinish: function onFinish() {
tween(body, {
rotation: -0.1
}, {
duration: 200,
onFinish: function onFinish() {
tween(body, {
rotation: 0
}, {
duration: 200
});
}
});
}
});
}
});
// Sometimes add corruption from playing in later stages
if (self.corruption > 40 && Math.random() < 0.3) {
self.addCorruption(5);
triggerGlitch();
}
};
self.clean = function () {
// Activate vacuum cleaner instead of directly cleaning
if (vacuum && !vacuum.active) {
vacuum.x = cleanButton.x;
vacuum.y = cleanButton.y;
vacuum.activate();
return; // Exit early - actual cleaning happens when vacuum is dragged to pet
}
// This section only executes when cleaning is triggered by the vacuum
self.cleanliness = Math.min(100, self.cleanliness + 30);
// Reduce happiness more significantly when cleaning with vacuum
self.happiness = Math.max(0, self.happiness - 25);
updateStatusBars();
// Hide dirt patches
for (var i = 0; i < dirtPatches.length; i++) {
dirtPatches[i].visible = false;
}
// Sparkle effect
tween(body, {
alpha: 0.7
}, {
duration: 200,
onFinish: function onFinish() {
tween(body, {
alpha: 1
}, {
duration: 200
});
}
});
// Sometimes add corruption from cleaning in later stages
if (self.corruption > 40 && Math.random() < 0.3) {
self.addCorruption(5);
triggerGlitch();
}
};
self.updateStats = function () {
// Decrease stats over time - increased decay rates
self.hunger = Math.max(0, self.hunger - 0.3);
self.happiness = Math.max(0, self.happiness - 0.4);
self.cleanliness = Math.max(0, self.cleanliness - 0.35);
// Show dirt when dirty
for (var i = 0; i < dirtPatches.length; i++) {
dirtPatches[i].visible = self.cleanliness < 50 + i * 10;
}
// Corruption increases when needs are low
if (self.hunger < 30 || self.happiness < 30 || self.cleanliness < 30) {
self.addCorruption(0.05);
if (Math.random() < 0.1) {
triggerGlitch();
}
}
// Random movement to make the pet more lively
if (Math.random() < 0.05) {
// Move in a random direction
var moveX = (Math.random() - 0.5) * 30;
var moveY = (Math.random() - 0.5) * 30;
// Animate the movement
tween(self, {
x: self.x + moveX,
y: self.y + moveY
}, {
duration: 800,
easing: tween.easeInOut
});
// Also add a small bounce effect
tween(body, {
scaleY: 1.1
}, {
duration: 400,
easing: tween.easeOut,
onFinish: function onFinish() {
tween(body, {
scaleY: 1
}, {
duration: 400,
easing: tween.easeIn
});
}
});
}
// Update visual based on corruption level
self.updateAppearance();
};
self.addCorruption = function (amount) {
var oldCorruption = self.corruption;
self.corruption = Math.min(100, self.corruption + amount);
if (oldCorruption < 33 && self.corruption >= 33) {
self.evolve(1);
} else if (oldCorruption < 66 && self.corruption >= 66) {
self.evolve(2);
} else if (oldCorruption < 100 && self.corruption >= 100) {
self.evolve(3);
}
updateStatusBars();
// If corruption is crossing 50%, add extra visual effects
if (oldCorruption < 50 && self.corruption >= 50 || amount > 5) {
// Create more intense visual distortion
for (var i = 0; i < 3; i++) {
LK.setTimeout(function () {
triggerGlitch();
}, i * 100);
}
// Create a momentary darkness effect
var originalBg = game.backgroundColor;
game.setBackgroundColor(0x333344);
LK.setTimeout(function () {
game.setBackgroundColor(originalBg);
}, 200);
}
};
self.evolve = function (stage) {
self.stage = stage;
LK.getSound('transform').play();
// Create a strong glitch effect for evolution
for (var i = 0; i < 10; i++) {
LK.setTimeout(function () {
triggerGlitch();
}, i * 200);
}
// Show strong visual change
tween(body, {
scaleX: 1.3,
scaleY: 1.3,
alpha: 0.5
}, {
duration: 500,
onFinish: function onFinish() {
self.updateAppearance();
tween(body, {
scaleX: 1,
scaleY: 1,
alpha: 1
}, {
duration: 500
});
}
});
};
self.updateAppearance = function () {
// Base form - cute and blue
if (self.stage === 0) {
body.tint = 0xaae1fc;
// Make eyes red when any stat gets too low (below 20)
if (self.hunger < 20 || self.happiness < 20 || self.cleanliness < 20) {
self.leftEye.tint = 0xff0000;
self.rightEye.tint = 0xff0000;
// NIGHTMARE MODE when stats are critically low AND corruption is 100%
if (self.hunger < 10 && self.happiness < 10 && self.cleanliness < 10 && self.corruption >= 100) {
// Turn pet body dark red
body.tint = 0x330000;
// Distort eyes to look evil
self.leftEye.scaleX = 1.8;
self.leftEye.scaleY = 0.4;
self.rightEye.scaleX = 1.8;
self.rightEye.scaleY = 0.4;
// Make mouth distorted and evil
self.mouth.tint = 0xff0000;
self.mouth.scaleX = 2.0;
self.mouth.scaleY = 0.3;
self.mouth.rotation = 0.8;
self.mouth.y = 70;
// Make title text change
if (titleText) {
titleText.setText("DIGITAL PET NIGHTMARE");
titleText.fill = 0xff0000;
// Make it shake
titleText.x = 2048 / 2 + (Math.random() - 0.5) * 10;
titleText.y = 100 + (Math.random() - 0.5) * 10;
// Add a glowing effect
titleText.alpha = 0.7 + Math.random() * 0.3; // Flicker effect
}
// Make evolution/corruption text change
if (corruptionLabel) {
corruptionLabel.setText("DIE DIE DIE DIE DIE DIE DIE DIE DIE DIE DIE DIE");
corruptionLabel.fill = 0xff0000;
corruptionLabel.alpha = 1.0; // Make sure it's fully visible
}
}
} else {
self.leftEye.tint = 0x000000;
self.rightEye.tint = 0x000000;
}
self.mouth.tint = 0x9966cc;
self.leftEye.x = -70;
self.rightEye.x = 70;
self.leftEye.y = self.rightEye.y = -50;
self.mouth.y = 30;
// Reset any distortions if not in nightmare mode
if (!(self.hunger < 10 && self.happiness < 10 && self.cleanliness < 10)) {
self.leftEye.scaleX = self.leftEye.scaleY = 1;
self.rightEye.scaleX = self.rightEye.scaleY = 1;
self.mouth.scaleX = self.mouth.scaleY = 1;
self.mouth.rotation = 0;
}
}
// Stage 1 - starting to evolve
else if (self.stage === 1) {
body.tint = 0x99ddaa; // More green tint
// Make eyes red when any stat gets too low (below 20)
if (self.hunger < 20 || self.happiness < 20 || self.cleanliness < 20) {
self.leftEye.tint = 0xff0000;
self.rightEye.tint = 0xff0000;
} else {
self.leftEye.tint = 0x000000;
self.rightEye.tint = 0x000000;
}
self.mouth.tint = 0x6655cc;
// Slight asymmetry
self.leftEye.x = -75;
self.rightEye.x = 68;
self.leftEye.scaleX = 1.1;
self.rightEye.scaleX = 0.9;
self.mouth.rotation = 0.1;
}
// Stage 2 - adolescent form
else if (self.stage === 2) {
body.tint = 0x77aacc; // More vibrant blue
// Make eyes red when any stat gets too low (below 20)
if (self.hunger < 20 || self.happiness < 20 || self.cleanliness < 20) {
self.leftEye.tint = 0xff0000;
self.rightEye.tint = 0xff0000;
} else {
self.leftEye.tint = 0x000088; // Blue eyes
self.rightEye.tint = 0x000088;
}
self.mouth.tint = 0x5566dd;
// More distinct features
self.leftEye.x = -80;
self.rightEye.x = 65;
self.leftEye.y = -55;
self.rightEye.y = -45;
self.leftEye.scaleX = 1.2;
self.leftEye.scaleY = 0.9;
self.rightEye.scaleX = 0.9;
self.rightEye.scaleY = 1.2;
self.mouth.y = 60;
self.mouth.scaleX = 1.2;
self.mouth.rotation = 0.2;
}
// Stage 3 - final form
else if (self.stage === 3) {
body.tint = 0x5577cc; // Deeper blue
// Make eyes red when any stat gets too low (below 20)
if (self.hunger < 20 || self.happiness < 20 || self.cleanliness < 20) {
self.leftEye.tint = 0xff0000;
self.rightEye.tint = 0xff0000;
} else {
self.leftEye.tint = 0x0000ff; // Brighter blue eyes
self.rightEye.tint = 0x0000ff;
}
self.mouth.tint = 0x6644dd;
// Adult features
self.leftEye.x = -85;
self.rightEye.x = 65;
self.leftEye.y = -60;
self.rightEye.y = -40;
self.leftEye.scaleX = 1.4;
self.leftEye.scaleY = 0.8;
self.rightEye.scaleX = 0.8;
self.rightEye.scaleY = 1.4;
self.mouth.y = 70;
self.mouth.scaleX = 1.4;
self.mouth.scaleY = 0.8;
self.mouth.rotation = 0.3;
}
};
// Idle animations
LK.setInterval(function () {
self.blink();
}, 3000 + Math.random() * 2000);
LK.setInterval(function () {
self.breathe();
}, 2000);
return self;
});
var PlayOptionsMenu = Container.expand(function () {
var self = Container.call(this);
// Create menu background
var background = self.attachAsset('cleanButton', {
anchorX: 0.5,
anchorY: 0.5,
scaleX: 3,
scaleY: 3,
tint: 0x333333,
alpha: 0.9
});
// Title text
var titleText = new Text2("Play Options", {
size: 60,
fill: 0xFFFFFF
});
titleText.anchor.set(0.5, 0.5);
titleText.y = -180;
self.addChild(titleText);
// Option buttons
var ballButton = self.attachAsset('buttonIcon', {
anchorX: 0.5,
anchorY: 0.5,
x: -100,
y: 0,
tint: 0xFF4444
});
var ballLabel = new Text2("Play Ball", {
size: 40,
fill: 0xFFFFFF
});
ballLabel.anchor.set(0.5, 0.5);
ballLabel.y = 100;
ballButton.addChild(ballLabel);
var arcadeButton = self.attachAsset('buttonIcon', {
anchorX: 0.5,
anchorY: 0.5,
x: 100,
y: 0,
tint: 0x44AAFF
});
var arcadeLabel = new Text2("Arcade", {
size: 40,
fill: 0xFFFFFF
});
arcadeLabel.anchor.set(0.5, 0.5);
arcadeLabel.y = 100;
arcadeButton.addChild(arcadeLabel);
// Make buttons interactive
ballButton.interactive = true;
arcadeButton.interactive = true;
ballButton.down = function () {
// Choose ball play option
self.hide();
if (ball) {
ball.activate();
}
};
arcadeButton.down = function () {
// Choose arcade play option
self.hide();
if (arcadeGame) {
arcadeGame.startGame();
}
};
// Close button
var closeButton = self.attachAsset('buttonIcon', {
anchorX: 0.5,
anchorY: 0.5,
x: 180,
y: -180,
scaleX: 0.5,
scaleY: 0.5,
tint: 0xFF4444
});
var closeLabel = new Text2("X", {
size: 40,
fill: 0xFFFFFF
});
closeLabel.anchor.set(0.5, 0.5);
closeButton.addChild(closeLabel);
closeButton.interactive = true;
closeButton.down = function () {
self.hide();
};
self.show = function () {
self.visible = true;
self.alpha = 0;
tween(self, {
alpha: 1
}, {
duration: 200
});
};
self.hide = function () {
tween(self, {
alpha: 0
}, {
duration: 200,
onFinish: function onFinish() {
self.visible = false;
}
});
};
self.visible = false;
return self;
});
var Vacuum = Container.expand(function () {
var self = Container.call(this);
// Create vacuum using vacuum asset
var vacuumBody = self.attachAsset('vacuum', {
anchorX: 0.5,
anchorY: 0.5,
tint: 0xFFFFFF // Natural color for vacuum
});
// Create vacuum nozzle
var nozzle = self.attachAsset('vacuumNozzle', {
anchorX: 0.5,
anchorY: 0.5,
scaleX: 1.0,
scaleY: 1.0,
x: 50,
y: -20,
tint: 0xFFFFFF // Natural color for nozzle
});
// Create visual suction effect
var suctionEffect = self.attachAsset('buttonIcon', {
anchorX: 0.5,
anchorY: 0.5,
x: 80,
y: -20,
scaleX: 0.6,
scaleY: 0.6,
alpha: 0.6,
tint: 0xaaaaff // Blue-ish suction effect
});
self.startupPosition = {
x: 0,
y: 0
};
self.active = false;
self.cleaning = false;
// Animation for the suction effect
self.animateSuction = function () {
if (!self.active) {
return;
}
tween(suctionEffect, {
scaleX: 0.3,
scaleY: 0.3,
alpha: 0.3
}, {
duration: 300,
onFinish: function onFinish() {
if (self.active) {
tween(suctionEffect, {
scaleX: 0.6,
scaleY: 0.6,
alpha: 0.6
}, {
duration: 300,
onFinish: self.animateSuction
});
}
}
});
};
self.activate = function () {
self.active = true;
self.visible = true;
// Store original position to return to
self.startupPosition = {
x: self.x,
y: self.y
};
// Move vacuum above the button and make it bigger
self.y = self.y - 250;
// Start suction animation
self.animateSuction();
// Visual feedback that it's active - make it 2x bigger and apply tweening
tween(self, {
scaleX: 2.0,
scaleY: 2.0
}, {
duration: 200
});
};
self.deactivate = function () {
self.active = false;
// Return to original position with animation
tween(self, {
x: self.startupPosition.x,
y: self.startupPosition.y
}, {
duration: 500,
onFinish: function onFinish() {
self.visible = false;
// Reset scale
vacuumBody.scaleX = vacuumBody.scaleY = 1.0;
}
});
};
self.cleanPet = function () {
if (self.cleaning) {
return;
}
self.cleaning = true;
// Visual feedback for cleaning
tween(suctionEffect, {
scaleX: 1.0,
scaleY: 1.0,
alpha: 0.9
}, {
duration: 300
});
// After cleaning is done, deactivate
LK.setTimeout(function () {
self.cleaning = false;
self.deactivate();
}, 1000);
};
self.visible = false;
self.active = false;
return self;
});
/****
* Initialize Game
****/
var game = new LK.Game({
backgroundColor: 0x000000
});
/****
* Game Code
****/
// Game variables
var pet;
var feedButton, playButton, cleanButton;
var statusBars = {};
var corruptionMeter;
var gameTime = 0;
var glitchEffects = [];
var corruptionParticles = [];
var gameStarted = false;
var corruptionTextGlitching = false;
var textGlitchTimer = null;
var corruptionLabel;
var titleText;
var vacuum;
var draggedItem = null;
var food;
var ball;
var arcadeGame;
var playOptionsMenu;
// Initialize game elements
function initGame() {
// Setup background
game.setBackgroundColor(0x66aadd);
// Create pet
pet = new Pet();
pet.x = 2048 / 2;
pet.y = 2732 / 2 - 200;
game.addChild(pet);
// Create UI controls
feedButton = new Button('feed');
feedButton.x = 2048 / 4;
feedButton.y = 2732 - 200;
game.addChild(feedButton);
playButton = new Button('play');
playButton.x = 2048 / 2;
playButton.y = 2732 - 200;
game.addChild(playButton);
cleanButton = new Button('clean');
cleanButton.x = 2048 * 3 / 4;
cleanButton.y = 2732 - 200;
game.addChild(cleanButton);
// Add the Abandon button
var abandonButton = new AbandonButton();
abandonButton.x = 2048 - 100;
abandonButton.y = 100;
game.addChild(abandonButton);
// Add the Ignore (iPhone) button
var ignoreButton = new IgnoreButton();
ignoreButton.x = 100;
ignoreButton.y = 2732 / 2;
game.addChild(ignoreButton);
// Create status bars
createStatusBars();
// Create glitch effects
for (var i = 0; i < 10; i++) {
var glitch = new GlitchEffect();
game.addChild(glitch);
glitchEffects.push(glitch);
}
// Create corruption particles
for (var i = 0; i < 50; i++) {
var particle = new CorruptionParticle();
game.addChild(particle);
corruptionParticles.push(particle);
}
// Create vacuum cleaner
vacuum = new Vacuum();
vacuum.x = cleanButton.x;
vacuum.y = cleanButton.y - 100;
vacuum.visible = false;
game.addChild(vacuum);
// Create draggable food
food = new Food();
food.x = feedButton.x;
food.y = feedButton.y - 150;
game.addChild(food);
// Create play ball
ball = new Ball();
ball.x = playButton.x;
ball.y = playButton.y - 150;
game.addChild(ball);
// Create arcade game
arcadeGame = new ArcadeGame();
arcadeGame.x = 2048 / 2;
arcadeGame.y = 2732 / 2 - 200;
game.addChild(arcadeGame);
// Create play options menu
playOptionsMenu = new PlayOptionsMenu();
playOptionsMenu.x = 2048 / 2;
playOptionsMenu.y = 2732 / 2 - 200;
game.addChild(playOptionsMenu);
// Create and add title
titleText = new Text2("Digital Pet Friend", {
size: 100,
fill: 0xFFFFFF
});
titleText.anchor.set(0.5, 0);
titleText.x = 2048 / 2;
titleText.y = 100;
LK.gui.addChild(titleText);
// Create game instructions
var instructionsText = new Text2("Feed, play with, and clean your pet to keep it happy. Watch how it evolves over time!", {
size: 40,
fill: 0xDDDDDD
});
instructionsText.anchor.set(0.5, 0);
instructionsText.x = 2048 / 2;
instructionsText.y = 220;
instructionsText.width = 1800;
LK.gui.addChild(instructionsText);
// Start game music
LK.playMusic('petMusic', {
fade: {
start: 0,
end: 0.8,
duration: 1000
}
});
// Create and initialize the stats checker for nightmare mode
var statsChecker = new CheckStats();
game.addChild(statsChecker);
gameStarted = true;
}
function createStatusBars() {
// Create container for all status bars
var statusContainer = new Container();
statusContainer.x = 2048 / 2;
statusContainer.y = 400;
game.addChild(statusContainer);
// Create each status bar
var statusTypes = [{
name: 'hunger',
label: 'Hunger',
color: 0x22cc88
}, {
name: 'happiness',
label: 'Happiness',
color: 0xff8822
}, {
name: 'cleanliness',
label: 'Cleanliness',
color: 0x2288ff
}];
var yOffset = 0;
for (var i = 0; i < statusTypes.length; i++) {
var type = statusTypes[i];
// Create label
var label = new Text2(type.label, {
size: 40,
fill: 0xFFFFFF
});
label.anchor.set(1, 0.5);
label.x = -20;
label.y = yOffset;
statusContainer.addChild(label);
// Create background bar
var barBg = LK.getAsset('feedButton', {
anchorX: 0,
anchorY: 0.5,
x: 0,
y: yOffset,
scaleX: 4,
scaleY: 0.5,
tint: 0x444444
});
statusContainer.addChild(barBg);
// Create value bar
var bar = LK.getAsset('feedButton', {
anchorX: 0,
anchorY: 0.5,
x: 0,
y: yOffset,
scaleX: 4,
scaleY: 0.5,
tint: type.color
});
statusContainer.addChild(bar);
// Store reference to bar
statusBars[type.name] = bar;
yOffset += 60;
}
// Create evolution meter
corruptionLabel = new Text2("Evolution", {
size: 40,
fill: 0xFFFFFF // Change from blue to white for better visibility
});
var corruptionTextGlitching = false;
var textGlitchTimer = null;
corruptionLabel.anchor.set(1, 0.5);
corruptionLabel.x = -20;
corruptionLabel.y = yOffset;
statusContainer.addChild(corruptionLabel);
var corruptionBg = LK.getAsset('feedButton', {
anchorX: 0,
anchorY: 0.5,
x: 0,
y: yOffset,
scaleX: 4,
scaleY: 0.5,
tint: 0x444444
});
statusContainer.addChild(corruptionBg);
corruptionMeter = LK.getAsset('feedButton', {
anchorX: 0,
anchorY: 0.5,
x: 0,
y: yOffset,
scaleX: 0,
scaleY: 0.5,
tint: 0x44AAFF
});
statusContainer.addChild(corruptionMeter);
}
function updateStatusBars() {
if (!gameStarted) {
return;
}
// Update status bars based on pet stats
statusBars.hunger.scaleX = pet.hunger / 25;
statusBars.happiness.scaleX = pet.happiness / 25;
statusBars.cleanliness.scaleX = pet.cleanliness / 25;
// Update corruption meter
corruptionMeter.scaleX = pet.corruption / 25;
// Calculate average status to determine visual darkness
var avgStatus = (pet.hunger + pet.happiness + pet.cleanliness) / 3;
// Adjust game visuals based on average status - darker and less vibrant as stats decrease
var darknessLevel = 1 - avgStatus / 100;
var saturationReduction = darknessLevel * 0.5;
var brightnessReduction = darknessLevel * 0.5;
// Adjust background color (from light blue to darker desaturated blue)
var r = Math.round(102 * (1 - brightnessReduction));
var g = Math.round(170 * (1 - brightnessReduction - saturationReduction));
var b = Math.round(221 * (1 - brightnessReduction));
game.setBackgroundColor(r << 16 | g << 8 | b);
// Adjust visual elements opacity based on status
pet.alpha = 0.5 + avgStatus / 200; // Fade pet slightly as status decreases
}
function triggerGlitch() {
// Play sparkle sound
LK.getSound('glitch').play();
// Check for nightmare mode
var nightmareMode = pet && pet.hunger < 10 && pet.happiness < 10 && pet.cleanliness < 10;
// Visual glitch effects - intensify based on corruption level or nightmare mode
var intensity = nightmareMode ? 10 : pet.corruption > 50 ? 5 : 3;
for (var i = 0; i < intensity; i++) {
var glitch = glitchEffects[Math.floor(Math.random() * glitchEffects.length)];
glitch.startGlitch();
}
// If corruption is above 50%, add stronger visual distortions
if (pet.corruption > 50 && Math.random() < 0.5) {
// Briefly distort the entire game view
var originalScale = game.scale.x;
tween(game.scale, {
x: originalScale * (1 + (Math.random() - 0.5) * 0.1),
y: originalScale * (1 + (Math.random() - 0.5) * 0.1)
}, {
duration: 100,
onFinish: function onFinish() {
tween(game.scale, {
x: originalScale,
y: originalScale
}, {
duration: 100
});
}
});
}
// Temporarily distort pet
if (Math.random() < 0.3) {
var originalRotation = pet.rotation;
tween(pet, {
rotation: originalRotation + (Math.random() - 0.5) * 0.3
}, {
duration: 150,
onFinish: function onFinish() {
tween(pet, {
rotation: originalRotation
}, {
duration: 150
});
}
});
}
// Screen shake
if (Math.random() < 0.2) {
var originalX = game.x;
var originalY = game.y;
tween(game, {
x: originalX + (Math.random() - 0.5) * 20
}, {
duration: 100,
onFinish: function onFinish() {
tween(game, {
x: originalX
}, {
duration: 100
});
}
});
}
}
function spawnCorruptionParticle() {
// Find an inactive particle
for (var i = 0; i < corruptionParticles.length; i++) {
var particle = corruptionParticles[i];
if (!particle.active) {
// Calculate position relative to pet
var offsetX = (Math.random() - 0.5) * 300;
var offsetY = (Math.random() - 0.5) * 300;
particle.initialize(pet.x + offsetX, pet.y + offsetY, 60 + Math.floor(Math.random() * 60));
break;
}
}
}
// Add event handlers for dragging
game.down = function (x, y, obj) {
// Get event position directly
// Check if we clicked on the vacuum when it's active
if (vacuum && vacuum.active && vacuum.visible) {
// Use direct hit testing instead of bounds checking
if (x >= vacuum.x - vacuum.width / 2 && x <= vacuum.x + vacuum.width / 2 && y >= vacuum.y - vacuum.height / 2 && y <= vacuum.y + vacuum.height / 2) {
draggedItem = vacuum;
}
}
// Check if we clicked on the food when it's active
if (food && food.active && food.visible) {
// Use direct hit testing
if (x >= food.x - food.width / 2 && x <= food.x + food.width / 2 && y >= food.y - food.height / 2 && y <= food.y + food.height / 2) {
draggedItem = food;
}
}
// Check if we clicked on the ball when it's active
if (ball && ball.active && ball.visible) {
// Use direct hit testing
if (x >= ball.x - ball.width / 2 && x <= ball.x + ball.width / 2 && y >= ball.y - ball.height / 2 && y <= ball.y + ball.height / 2) {
draggedItem = ball;
}
}
};
game.up = function (x, y, obj) {
if (draggedItem === vacuum) {
// Use simplified distance-based collision detection for better results
var dx = vacuum.x - pet.x;
var dy = vacuum.y - pet.y;
var distance = Math.sqrt(dx * dx + dy * dy);
// If vacuum is within 200px of pet center, consider it a hit
if (distance < 200) {
// Vacuum is over the pet - clean it!
vacuum.cleanPet();
pet.clean(); // This now has modified behavior for vacuum
} else {
// Not over pet, return vacuum
vacuum.deactivate();
}
draggedItem = null;
} else if (draggedItem === food) {
// Check if food is near pet's mouth
var dx = food.x - pet.x;
var dy = food.y - (pet.y + pet.mouth.y);
var distance = Math.sqrt(dx * dx + dy * dy);
// If food is within 100px of pet's mouth, consider it a hit
if (distance < 100) {
// Feed the pet
pet.feed();
food.deactivate();
} else {
// Return food to original position
food.returnToPosition();
}
draggedItem = null;
} else if (draggedItem === ball) {
// Check if ball is near pet
var dx = ball.x - pet.x;
var dy = ball.y - pet.y;
var distance = Math.sqrt(dx * dx + dy * dy);
if (distance < 150) {
// Play with pet using the ball
pet.play();
ball.deactivate();
} else {
// Return ball to original position
ball.returnToPosition();
}
draggedItem = null;
}
};
game.move = function (x, y, obj) {
if (draggedItem) {
// Use coordinates directly - no need to convert with toLocal
draggedItem.x = x;
draggedItem.y = y;
}
};
// Game Update Logic
game.update = function () {
if (!gameStarted) {
initGame();
return;
}
gameTime++;
// Update pet stats
if (gameTime % 30 === 0) {
pet.updateStats();
updateStatusBars();
// Check for nightmare mode - only if corruption is 100%
var nightmareMode = pet.hunger < 10 && pet.happiness < 10 && pet.cleanliness < 10 && pet.corruption >= 100;
// If in nightmare mode, apply special effects continuously
if (nightmareMode) {
// Occasional screen flashes
if (Math.random() < 0.1) {
LK.effects.flashScreen(0xff0000, 200);
}
// Random background color flashes
if (Math.random() < 0.1) {
var originalBg = game.backgroundColor;
game.setBackgroundColor(0x330000);
LK.setTimeout(function () {
game.setBackgroundColor(originalBg);
}, 100);
}
// Random glitches
if (Math.random() < 0.2) {
triggerGlitch();
}
// Make title text shake constantly
if (titleText) {
titleText.x = 2048 / 2 + (Math.random() - 0.5) * 20;
titleText.y = 100 + (Math.random() - 0.5) * 20;
}
// Make DIE text flash
if (corruptionLabel && Math.random() < 0.5) {
corruptionLabel.setText("DIE DIE DIE DIE DIE DIE DIE DIE DIE DIE DIE DIE");
corruptionLabel.fill = Math.random() < 0.5 ? 0xff0000 : 0xffff00;
// Add pulsing effect for more intensity
corruptionLabel.scaleX = corruptionLabel.scaleY = 1 + Math.random() * 0.3;
}
}
// Handle corruption text glitching when corruption is around halfway and not in nightmare mode
else if (pet.corruption >= 40 && pet.corruption <= 60) {
if (!corruptionTextGlitching) {
corruptionTextGlitching = true;
textGlitchTimer = LK.setInterval(function () {
// Toggle between "Evolution" and "Corruption"
if (corruptionLabel.text === "Evolution") {
corruptionLabel.setText("Corruption");
// Add slight visual glitch effect
tween(corruptionLabel, {
rotation: (Math.random() - 0.5) * 0.1
}, {
duration: 100
});
} else {
corruptionLabel.setText("Evolution");
// Reset rotation
tween(corruptionLabel, {
rotation: 0
}, {
duration: 100
});
}
}, 400);
}
} else if (corruptionTextGlitching && !nightmareMode) {
// Stop glitching when out of the 40-60 range
corruptionTextGlitching = false;
LK.clearInterval(textGlitchTimer);
corruptionLabel.setText(pet.corruption < 50 ? "Evolution" : "Corruption");
corruptionLabel.rotation = 0;
}
}
// Spawn corruption particles based on corruption level
if (pet.corruption > 30 && gameTime % Math.max(5, 30 - pet.corruption / 5) === 0) {
spawnCorruptionParticle();
}
// Automatically spawn vacuum cleaner periodically when pet needs cleaning
if (pet.cleanliness < 50 && !vacuum.active && gameTime % 300 === 0) {
vacuum.x = cleanButton.x;
vacuum.y = cleanButton.y;
vacuum.activate();
}
// Update all corruption particles
for (var i = 0; i < corruptionParticles.length; i++) {
corruptionParticles[i].update();
}
// Update arcade game if active
if (arcadeGame && arcadeGame.active) {
arcadeGame.update();
}
// Random glitches when heavily corrupted
if (pet.corruption > 70 && Math.random() < 0.005) {
triggerGlitch();
}
// Check for game over condition
if (pet.corruption >= 100 && pet.hunger <= 0 && pet.happiness <= 0 && pet.cleanliness <= 0) {
// Nightmare complete
for (var i = 0; i < 20; i++) {
LK.setTimeout(function () {
triggerGlitch();
}, i * 100);
}
LK.setTimeout(function () {
LK.showGameOver();
}, 2000);
}
};
dirt speck. In-Game asset. 2d. High contrast. No shadows
chicken leg. In-Game asset. 2d. High contrast. No shadows
sitting cat with no eyes and mouth. In-Game asset. 2d. High contrast. No shadows
closed black cat mouth by itself. In-Game asset. 2d. High contrast. No shadows
glitch effect by itself. In-Game asset. 2d. High contrast. No shadows
ball. In-Game asset. 2d. High contrast. No shadows
vaccum. In-Game asset. 2d. High contrast. No shadows
Iphone. In-Game asset. 2d. High contrast. No shadows