/**** * Plugins ****/ var tween = LK.import("@upit/tween.v1"); var storage = LK.import("@upit/storage.v1"); /**** * Classes ****/ var Background = Container.expand(function () { var self = Container.call(this); // Create sky gradient var skyGradient = new Container(); // Create several bands of sky color var skyColors = [0x1a3c80, 0x3a5c9f, 0x5a7cbf, 0x7a9cdf, 0x9abcff]; var bandHeight = 2732 / skyColors.length; for (var i = 0; i < skyColors.length; i++) { var skyBand = LK.getAsset('skyBand' + i, { width: 2048, height: bandHeight, color: skyColors[i], shape: 'box', y: i * bandHeight }); skyGradient.addChild(skyBand); } self.addChild(skyGradient); // Create buildings var buildings = new Container(); self.addChild(buildings); // Far buildings (darker) var buildingColors = [0x222a40, 0x323a50, 0x424a60]; var buildingCount = 15; for (var i = 0; i < buildingCount; i++) { var buildingWidth = 100 + Math.random() * 150; var buildingHeight = 300 + Math.random() * 400; var building = LK.getAsset('building_far_' + i, { width: buildingWidth, height: buildingHeight, color: buildingColors[Math.floor(Math.random() * buildingColors.length)], shape: 'box', x: i * (2048 / buildingCount), y: 2732 - buildingHeight, anchorY: 0 }); buildings.addChild(building); } // Near buildings (slightly lighter) var nearBuildingColors = [0x303a50, 0x404a60, 0x505a70]; var nearBuildingCount = 10; for (var i = 0; i < nearBuildingCount; i++) { var buildingWidth = 180 + Math.random() * 150; var buildingHeight = 500 + Math.random() * 600; var building = LK.getAsset('building_near_' + i, { width: buildingWidth, height: buildingHeight, color: nearBuildingColors[Math.floor(Math.random() * nearBuildingColors.length)], shape: 'box', x: i * (2048 / nearBuildingCount), y: 2732 - buildingHeight, anchorY: 0 }); buildings.addChild(building); } // Add some windows to buildings (as small yellow rectangles) for (var b = 0; b < buildings.children.length; b++) { var building = buildings.children[b]; var windowCount = Math.floor(building.width / 30) * Math.floor(building.height / 40); // Limit window count for performance windowCount = Math.min(windowCount, 20); for (var w = 0; w < windowCount; w++) { var windowSize = 10 + Math.random() * 10; var windowX = Math.random() * (building.width - windowSize); var windowY = Math.random() * (building.height - windowSize); // Only add some windows (randomized lighting effect) if (Math.random() > 0.4) { var windowLight = LK.getAsset('window_' + b + '_' + w, { width: windowSize, height: windowSize, color: Math.random() > 0.7 ? 0xffcc66 : 0x888888, // Some windows lit, some not shape: 'box', x: building.x + windowX, y: building.y + windowY }); self.addChild(windowLight); } } } // Add clouds var clouds = new Container(); self.clouds = clouds; self.addChild(clouds); var cloudCount = 6; for (var i = 0; i < cloudCount; i++) { var cloudWidth = 200 + Math.random() * 300; var cloudHeight = 100 + Math.random() * 100; var cloud = LK.getAsset('cloud_' + i, { width: cloudWidth, height: cloudHeight, color: 0xddddff, shape: 'ellipse', x: Math.random() * 2048, y: 200 + Math.random() * 400, alpha: 0.7 }); // Add some variation to clouds with slight scaling cloud.scaleX = 0.8 + Math.random() * 0.4; cloud.scaleY = 0.8 + Math.random() * 0.4; // Store cloud speed for animation cloud.speedX = 0.2 + Math.random() * 0.3; clouds.addChild(cloud); } // Update function to animate clouds self.update = function () { // Move clouds horizontally for (var i = 0; i < clouds.children.length; i++) { var cloud = clouds.children[i]; cloud.x += cloud.speedX; // Loop clouds when they move off screen if (cloud.x > 2048 + cloud.width) { cloud.x = -cloud.width; cloud.y = 200 + Math.random() * 400; } } }; return self; }); var BreathingCircle = Container.expand(function () { var self = Container.call(this); // Create the breathing circle var innerCircle = self.attachAsset('centerCircle', { width: 200, height: 200, color: 0x3a5c9f, anchorX: 0.5, anchorY: 0.5, alpha: 0.4 }); var outerCircle = LK.getAsset('centerCircle', { width: 240, height: 240, color: 0x5a7cbf, anchorX: 0.5, anchorY: 0.5, alpha: 0.2 }); self.addChild(outerCircle); // Breathing animation state self.breathPhase = 0; // 0: inhale growing, 1: hold, 2: exhale shrinking, 3: hold self.breathTimer = 0; self.inhaleDuration = 240; // 4 seconds self.holdDuration = 120; // 2 seconds self.exhaleDuration = 240; // 4 seconds self.restDuration = 60; // 1 second // Text guide for breathing self.breathText = new Text2("Breathe In", { size: 40, fill: 0xffffff }); self.breathText.anchor.set(0.5, 0.5); self.breathText.y = -160; self.addChild(self.breathText); // Update method to animate the breathing circle self.update = function () { self.breathTimer++; // Determine current phase based on timer if (self.breathPhase === 0) { // Inhale var progress = self.breathTimer / self.inhaleDuration; var scale = 1 + progress * 0.5; innerCircle.scale.x = innerCircle.scale.y = scale; outerCircle.scale.x = outerCircle.scale.y = 0.9 + progress * 0.5; self.breathText.setText("Breathe In"); if (self.breathTimer >= self.inhaleDuration) { self.breathPhase = 1; self.breathTimer = 0; } } else if (self.breathPhase === 1) { // Hold after inhale self.breathText.setText("Hold"); if (self.breathTimer >= self.holdDuration) { self.breathPhase = 2; self.breathTimer = 0; } } else if (self.breathPhase === 2) { // Exhale var progress = self.breathTimer / self.exhaleDuration; var scale = 1.5 - progress * 0.5; innerCircle.scale.x = innerCircle.scale.y = scale; outerCircle.scale.x = outerCircle.scale.y = 1.4 - progress * 0.5; self.breathText.setText("Breathe Out"); if (self.breathTimer >= self.exhaleDuration) { self.breathPhase = 3; self.breathTimer = 0; } } else { // Hold after exhale self.breathText.setText("Rest"); if (self.breathTimer >= self.restDuration) { self.breathPhase = 0; self.breathTimer = 0; } } }; return self; }); var Bullet = Container.expand(function () { var self = Container.call(this); var bulletGraphics = self.attachAsset('bullet', { anchorX: 0.5, anchorY: 0.5 }); self.speed = 12; self.direction = { x: 0, y: -1 }; // Default upward self.lifespan = 120; // 2 seconds at 60fps self.age = 0; self.damage = 1; self.update = function () { self.x += self.direction.x * self.speed; self.y += self.direction.y * self.speed; self.age++; if (self.age > self.lifespan) { self.markForDeletion = true; } }; return self; }); var Criminal = Container.expand(function () { var self = Container.call(this); var criminalGraphics = self.attachAsset('criminal', { anchorX: 0.5, anchorY: 0.5 }); self.speed = 2; self.health = 2; // Reduced from 3 self.shootCooldown = 0; self.shootDelay = 120; // Frames between shots self.attackRange = 300; // Reduced from 500 self.movePattern = Math.floor(Math.random() * 3); // 0: direct, 1: zigzag, 2: circle self.moveTimer = 0; self.update = function () { // Target the player var dx = player.x - self.x; var dy = player.y - self.y; var distance = Math.sqrt(dx * dx + dy * dy); // Movement based on pattern if (distance > 100) { // Keep some distance var moveX = 0; var moveY = 0; switch (self.movePattern) { case 0: // Direct moveX = dx / distance; moveY = dy / distance; break; case 1: // Zigzag self.moveTimer++; moveX = dx / distance + Math.sin(self.moveTimer * 0.1) * 0.5; moveY = dy / distance; break; case 2: // Circle self.moveTimer++; moveX = dx / distance + Math.sin(self.moveTimer * 0.05) * 0.8; moveY = dy / distance + Math.cos(self.moveTimer * 0.05) * 0.8; break; } self.x += moveX * self.speed; self.y += moveY * self.speed; } // Shooting logic if (distance < self.attackRange) { if (self.shootCooldown <= 0) { // Create enemy bullet var bullet = new Bullet(); bullet.x = self.x; bullet.y = self.y; // Calculate direction toward player var dirX = dx / distance; var dirY = dy / distance; bullet.direction = { x: dirX, y: dirY }; // Mark as enemy bullet bullet.isEnemyBullet = true; // Add to game's bullets array bullets.push(bullet); game.addChild(bullet); // Reset cooldown with some randomness self.shootCooldown = self.shootDelay + Math.random() * 60; } } if (self.shootCooldown > 0) { self.shootCooldown--; } }; self.takeDamage = function () { self.health--; LK.effects.flashObject(self, 0xFF0000, 300); if (self.health <= 0) { LK.getSound('criminal_down').play(); LK.setScore(LK.getScore() + 1); self.markForDeletion = true; // Track criminal elimination task var eliminateTask = tasks.find(function (task) { return task.id === 'eliminate'; }); if (eliminateTask && !eliminateTask.completed) { eliminateTask.count++; if (eliminateTask.count >= eliminateTask.target) { eliminateTask.completed = true; LK.effects.flashObject(taskTexts[1], 0x00FF00, 1000); } updateTaskDisplay(); } } }; return self; }); var EmergencyCall = Container.expand(function () { var self = Container.call(this); var callGraphics = self.attachAsset('emergencyCall', { anchorX: 0.5, anchorY: 0.5 }); self.lifetime = 600; // 10 seconds at 60fps self.age = 0; self.flashInterval = 30; self.update = function () { self.age++; // Flash effect if (self.age % self.flashInterval === 0) { if (callGraphics.alpha === 1) { tween(callGraphics, { alpha: 0.3 }, { duration: 500 }); } else { tween(callGraphics, { alpha: 1 }, { duration: 500 }); } } // Expire after lifetime if (self.age > self.lifetime) { self.markForDeletion = true; } }; self.down = function () { // Responding to call LK.getSound('radiochatter').play(); // Spawn criminals from top of screen, using emergency call's X position spawnCriminals(self.x, 0, 2 + Math.floor(Math.random() * 3)); self.markForDeletion = true; // Increase score for responding LK.setScore(LK.getScore() + 2); // Track emergency call response task var respondTask = tasks.find(function (task) { return task.id === 'respond'; }); if (respondTask && !respondTask.completed) { respondTask.count++; if (respondTask.count >= respondTask.target) { respondTask.completed = true; LK.effects.flashObject(taskTexts[0], 0x00FF00, 1000); } updateTaskDisplay(); } }; return self; }); var MeditationGuide = Container.expand(function () { var self = Container.call(this); // Create a text display for meditation prompts self.promptText = new Text2("Breathe deeply...", { size: 60, fill: 0xffffff, align: 'center' }); self.promptText.anchor.set(0.5, 0.5); self.addChild(self.promptText); // List of meditation prompts self.prompts = ["Breathe deeply...", "Focus on your breath...", "Let go of your thoughts...", "Feel the peace within...", "You are present...", "Allow yourself to be...", "Feel the energy flow...", "Find your center..."]; self.currentPrompt = 0; self.promptTimer = 0; self.promptDuration = 300; // 5 seconds per prompt // Update method to cycle through prompts self.update = function () { self.promptTimer++; // Change prompt periodically if (self.promptTimer >= self.promptDuration) { self.currentPrompt = (self.currentPrompt + 1) % self.prompts.length; self.promptText.setText(self.prompts[self.currentPrompt]); self.promptTimer = 0; // Animate text appearance self.promptText.alpha = 0; tween(self.promptText, { alpha: 1 }, { duration: 1000 }); } // Subtle pulse animation var scale = 1 + 0.05 * Math.sin(self.promptTimer * 0.01); self.promptText.scale.x = scale; self.promptText.scale.y = scale; }; return self; }); var MeditationSpace = Container.expand(function () { var self = Container.call(this); // Create a peaceful gradient background var background = new Container(); self.addChild(background); // Create calming gradient colors for the background var skyColors = [0x081832, 0x112a4e, 0x1a3c6a, 0x234e86, 0x2c60a2]; var bandHeight = 2732 / skyColors.length; for (var i = 0; i < skyColors.length; i++) { var skyBand = LK.getAsset('skyBand' + i, { width: 2048, height: bandHeight, color: skyColors[i], y: i * bandHeight }); background.addChild(skyBand); } // Create stars var stars = new Container(); self.stars = stars; self.addChild(stars); // Add stars to the night sky var starCount = 100; for (var i = 0; i < starCount; i++) { var starSize = 2 + Math.random() * 4; var star = LK.getAsset('star_' + i, { width: starSize, height: starSize, color: 0xffffff, shape: 'ellipse', x: Math.random() * 2048, y: Math.random() * 1200, alpha: 0.5 + Math.random() * 0.5 }); star.pulseSpeed = 0.01 + Math.random() * 0.02; star.pulsePhase = Math.random() * Math.PI * 2; stars.addChild(star); } // Add floating lotus flowers var lotusFlowers = new Container(); self.lotusFlowers = lotusFlowers; self.addChild(lotusFlowers); var lotusCount = 5; for (var i = 0; i < lotusCount; i++) { var lotusSize = 80 + Math.random() * 40; var lotus = LK.getAsset('lotus_' + i, { width: lotusSize, height: lotusSize, color: 0xffb6c1, shape: 'ellipse', x: 400 + Math.random() * 1200, y: 1500 + Math.random() * 800 }); lotus.floatSpeed = 0.2 + Math.random() * 0.3; lotus.floatPhase = Math.random() * Math.PI * 2; lotusFlowers.addChild(lotus); } // Add water ripples var ripples = new Container(); self.ripples = ripples; self.addChild(ripples); self.rippleTimer = 0; // Update function to animate elements self.update = function () { // Animate stars (pulsing effect) for (var i = 0; i < stars.children.length; i++) { var star = stars.children[i]; star.pulsePhase += star.pulseSpeed; star.alpha = 0.5 + 0.5 * Math.sin(star.pulsePhase); } // Animate lotus flowers (gentle floating) for (var i = 0; i < lotusFlowers.children.length; i++) { var lotus = lotusFlowers.children[i]; lotus.floatPhase += 0.01; lotus.y += Math.sin(lotus.floatPhase) * lotus.floatSpeed; } // Create new ripples periodically self.rippleTimer++; if (self.rippleTimer > 120) { // Every 2 seconds self.createRipple(400 + Math.random() * 1200, 1500 + Math.random() * 800); self.rippleTimer = 0; } // Update existing ripples for (var i = ripples.children.length - 1; i >= 0; i--) { var ripple = ripples.children[i]; ripple.age++; // Expand ripple ripple.scale.x += 0.01; ripple.scale.y += 0.01; // Fade out ripple ripple.alpha = 1 - ripple.age / ripple.lifespan; // Remove old ripples if (ripple.age >= ripple.lifespan) { ripple.destroy(); ripples.removeChild(ripple); } } }; // Method to create a new water ripple self.createRipple = function (x, y) { var ripple = LK.getAsset('ripple', { width: 50, height: 50, color: 0xffffff, shape: 'ellipse', x: x, y: y, anchorX: 0.5, anchorY: 0.5, alpha: 0.7 }); ripple.age = 0; ripple.lifespan = 120; // 2 seconds ripples.addChild(ripple); }; return self; }); var Player = Container.expand(function () { var self = Container.call(this); var playerGraphics = self.attachAsset('player', { anchorX: 0.5, anchorY: 0.5 }); self.speed = 5; self.health = 100; self.maxHealth = 100; self.shootCooldown = 0; self.shootDelay = 15; // Frames between shots self.canMove = true; // Health bar setup var healthBarBg = self.attachAsset('healthBarBackground', { anchorX: 0.5, anchorY: 0, y: 120 }); var healthBarFill = self.attachAsset('healthBar', { anchorX: 0.5, anchorY: 0, y: 122 }); self.updateHealthBar = function () { var healthPercentage = self.health / self.maxHealth; healthBarFill.scale.x = healthPercentage; // Center the health bar healthBarFill.x = -100 * (1 - healthPercentage); }; self.takeDamage = function (amount) { self.health -= amount; if (self.health <= 0) { self.health = 0; LK.effects.flashScreen(0xFF0000, 1000); LK.showGameOver(); } self.updateHealthBar(); }; self.shoot = function () { if (self.shootCooldown <= 0) { var bullet = new Bullet(); bullet.x = self.x; bullet.y = self.y - 40; // Add to game's bullets array bullets.push(bullet); game.addChild(bullet); // Play gun sound LK.getSound('gunshot').play(); // Reset cooldown self.shootCooldown = self.shootDelay; } }; self.update = function () { if (self.shootCooldown > 0) { self.shootCooldown--; } }; self.down = function (x, y, obj) { self.shoot(); }; // Initialize health bar self.updateHealthBar(); return self; }); var SoulOrb = Container.expand(function () { var self = Container.call(this); // Create the soul orb with a glowing effect var orbCore = self.attachAsset('centerCircle', { width: 60, height: 60, color: 0x83de44, anchorX: 0.5, anchorY: 0.5 }); // Create outer glow var orbGlow = LK.getAsset('centerCircle', { width: 100, height: 100, color: 0xb8ffb0, anchorX: 0.5, anchorY: 0.5, alpha: 0.5 }); self.addChild(orbGlow); // Add pulsating animation to the glow self.glowPhase = 0; self.energy = 0; // Energy level (0-100) self.maxEnergy = 100; self.pulseSpeed = 0.05; // Update method to animate the orb self.update = function () { self.glowPhase += self.pulseSpeed; orbGlow.scale.x = 1 + 0.2 * Math.sin(self.glowPhase); orbGlow.scale.y = 1 + 0.2 * Math.sin(self.glowPhase); // Adjust color based on energy level var energyRatio = self.energy / self.maxEnergy; var r = Math.floor(131 + (255 - 131) * energyRatio); var g = Math.floor(222 + (255 - 222) * energyRatio); var b = Math.floor(68 + (255 - 68) * energyRatio); // Convert RGB to hex var color = r << 16 | g << 8 | b; orbCore.tint = color; }; // Method to add energy to the orb self.addEnergy = function (amount) { self.energy = Math.min(self.maxEnergy, self.energy + amount); // Flash with increasing brightness as energy increases LK.effects.flashObject(self, 0xffffff, 300); }; return self; }); /**** * Initialize Game ****/ var game = new LK.Game({ backgroundColor: 0x081832 }); /**** * Game Code ****/ // Game variables var meditationSpace; var soulOrb; var breathingCircle; var meditationGuide; var gameActive = true; var dragOffset = { x: 0, y: 0 }; var meditationLevel = 1; var meditationTime = 0; var soulEnergy = 0; var maxSoulEnergy = 100; var breathingTimer = 0; // Meditation practices var practices = [{ id: 'breathe', text: 'Complete 5 breathing cycles', count: 0, target: 5, completed: false }, { id: 'focus', text: 'Maintain focus for 60 seconds', count: 0, target: 60, completed: false }, { id: 'energy', text: 'Fill your soul with energy', count: 0, target: 100, completed: false }]; // Setup practice UI var practiceContainer = new Container(); practiceContainer.x = 40; practiceContainer.y = 180; LK.gui.left.addChild(practiceContainer); var practiceTitle = new Text2('PRACTICES:', { size: 50, fill: 0xFFFFFF }); practiceContainer.addChild(practiceTitle); // Create text for each practice var practiceTexts = []; for (var i = 0; i < practices.length; i++) { var practiceText = new Text2('• ' + practices[i].text + ' (0/' + practices[i].target + ')', { size: 40, fill: 0xCCCCCC }); practiceText.y = 60 + i * 50; practiceContainer.addChild(practiceText); practiceTexts.push(practiceText); } // Function to update practice UI function updatePracticeDisplay() { for (var i = 0; i < practices.length; i++) { var practice = practices[i]; var color = practice.completed ? 0x83de44 : 0xCCCCCC; practiceTexts[i].setText('• ' + practice.text + ' (' + practice.count + '/' + practice.target + ')'); practiceTexts[i].fill = color; } } // Setup UI var energyTxt = new Text2('Soul Energy: 0%', { size: 60, fill: 0xFFFFFF }); energyTxt.anchor.set(0.5, 0); LK.gui.top.addChild(energyTxt); var levelTxt = new Text2('Meditation Level: 1', { size: 60, fill: 0xFFFFFF }); levelTxt.anchor.set(0.5, 0); levelTxt.y = 70; LK.gui.top.addChild(levelTxt); // Create and add meditation space meditationSpace = new MeditationSpace(); game.addChild(meditationSpace); // Initialize soul orb soulOrb = new SoulOrb(); soulOrb.x = 2048 / 2; soulOrb.y = 2732 / 3; game.addChild(soulOrb); // Initialize breathing circle breathingCircle = new BreathingCircle(); breathingCircle.x = 2048 / 2; breathingCircle.y = 2732 / 2 + 200; game.addChild(breathingCircle); // Initialize meditation guide meditationGuide = new MeditationGuide(); meditationGuide.x = 2048 / 2; meditationGuide.y = 2732 / 5; game.addChild(meditationGuide); // Play meditation music LK.playMusic('background_music'); // Create a ripple at a position (utility function) function createRipple(x, y) { meditationSpace.createRipple(x, y); } // Add soul energy function addSoulEnergy(amount) { soulOrb.addEnergy(amount); // Update energy practice var energyPractice = practices.find(function (practice) { return practice.id === 'energy'; }); if (energyPractice && !energyPractice.completed) { energyPractice.count = Math.floor(soulOrb.energy); if (energyPractice.count >= energyPractice.target) { energyPractice.completed = true; LK.effects.flashObject(practiceTexts[2], 0x83de44, 1000); } updatePracticeDisplay(); } } // Check if meditation level should increase function checkMeditationProgress() { // Check if practices are completed to progress meditation level var completedPractices = practices.filter(function (practice) { return practice.completed; }).length; var newLevel = 1 + Math.floor(completedPractices / 2); if (newLevel > meditationLevel) { meditationLevel = newLevel; levelTxt.setText('Meditation Level: ' + meditationLevel); // Bonus for reaching new level addSoulEnergy(10 * meditationLevel); // Visual feedback LK.effects.flashScreen(0x83de44, 500); } } // Meditation interaction handling game.down = function (x, y, obj) { // Calculate distances to interactive elements var distToOrb = Math.sqrt(Math.pow(x - soulOrb.x, 2) + Math.pow(y - soulOrb.y, 2)); // If touching the soul orb if (distToOrb < 100) { // Add energy to the soul soulOrb.addEnergy(5); // Emit a ripple effect from the interaction point meditationSpace.createRipple(x, y); // Create visual feedback LK.effects.flashObject(soulOrb, 0xFFFFFF, 500); } else { // Create ripple at touch point meditationSpace.createRipple(x, y); } // Set drag offset for moving the orb dragOffset.x = soulOrb.x - x; dragOffset.y = soulOrb.y - y; }; game.move = function (x, y, obj) { // Move soul orb with drag soulOrb.x = x + dragOffset.x; soulOrb.y = y + dragOffset.y; // Keep soul orb in bounds soulOrb.x = Math.max(100, Math.min(2048 - 100, soulOrb.x)); soulOrb.y = Math.max(100, Math.min(2732 - 100, soulOrb.y)); // Create subtle ripple effects during movement if (Math.random() < 0.1) { meditationSpace.createRipple(soulOrb.x + (Math.random() * 100 - 50), soulOrb.y + (Math.random() * 100 - 50)); } }; game.up = function () { // Create final ripple at release point meditationSpace.createRipple(soulOrb.x, soulOrb.y); }; // Game update loop game.update = function () { if (!gameActive) return; // Update meditation space meditationSpace.update(); // Update soul orb, breathing circle, and guide soulOrb.update(); breathingCircle.update(); meditationGuide.update(); // Update energy display energyTxt.setText('Soul Energy: ' + Math.floor(soulOrb.energy / maxSoulEnergy * 100) + '%'); // Track breathing cycles for breathe practice if (breathingCircle.breathPhase === 3 && breathingCircle.breathTimer === 0) { // Just completed a full breathing cycle var breathePractice = practices.find(function (practice) { return practice.id === 'breathe'; }); if (breathePractice && !breathePractice.completed) { breathePractice.count++; if (breathePractice.count >= breathePractice.target) { breathePractice.completed = true; LK.effects.flashObject(practiceTexts[0], 0x83de44, 1000); // Add soul energy when completing breathing practice soulOrb.addEnergy(20); } updatePracticeDisplay(); } } // Track focus time for focus practice meditationTime++; if (meditationTime % 60 === 0) { // Every second var focusPractice = practices.find(function (practice) { return practice.id === 'focus'; }); if (focusPractice && !focusPractice.completed) { focusPractice.count++; if (focusPractice.count >= focusPractice.target) { focusPractice.completed = true; LK.effects.flashObject(practiceTexts[1], 0x83de44, 1000); // Add soul energy when completing focus practice soulOrb.addEnergy(30); } updatePracticeDisplay(); } } // Add soul energy over time with active meditation if (meditationTime % 180 === 0) { // Every 3 seconds soulOrb.addEnergy(1); // Track soul energy for energy practice var energyPractice = practices.find(function (practice) { return practice.id === 'energy'; }); if (energyPractice && !energyPractice.completed) { energyPractice.count = Math.floor(soulOrb.energy); if (energyPractice.count >= energyPractice.target) { energyPractice.completed = true; LK.effects.flashObject(practiceTexts[2], 0x83de44, 1000); } updatePracticeDisplay(); } } // Check for meditation level up if (meditationTime % 600 === 0) { // Every 10 seconds meditationLevel++; levelTxt.setText('Meditation Level: ' + meditationLevel); // Visual feedback for level up LK.effects.flashScreen(0x83de44, 500); } // Check if all practices are completed var allPracticesCompleted = practices.every(function (practice) { return practice.completed; }); if (allPracticesCompleted && gameActive) { // Show enlightenment message var enlightenmentMessage = new Text2('ENLIGHTENMENT ACHIEVED!', { size: 100, fill: 0xFFFFFF }); enlightenmentMessage.anchor.set(0.5, 0.5); enlightenmentMessage.x = 2048 / 2; enlightenmentMessage.y = 2732 / 2; game.addChild(enlightenmentMessage); // Visual effects for enlightenment LK.effects.flashScreen(0xFFFFFF, 2000); // Create new practices with higher requirements practices = [{ id: 'breathe', text: 'Complete 10 breathing cycles', count: 0, target: 10, completed: false }, { id: 'focus', text: 'Maintain focus for 120 seconds', count: 0, target: 120, completed: false }, { id: 'energy', text: 'Achieve deeper enlightenment', count: 0, target: 200, completed: false }]; // Update practice display for (var i = 0; i < practices.length; i++) { practiceTexts[i].setText('• ' + practices[i].text + ' (0/' + practices[i].target + ')'); practiceTexts[i].fill = 0xCCCCCC; } // Increase soul orb capacity maxSoulEnergy = 200; // Remove the enlightenment message after 3 seconds LK.setTimeout(function () { enlightenmentMessage.destroy(); updatePracticeDisplay(); }, 3000); } };
/****
* Plugins
****/
var tween = LK.import("@upit/tween.v1");
var storage = LK.import("@upit/storage.v1");
/****
* Classes
****/
var Background = Container.expand(function () {
var self = Container.call(this);
// Create sky gradient
var skyGradient = new Container();
// Create several bands of sky color
var skyColors = [0x1a3c80, 0x3a5c9f, 0x5a7cbf, 0x7a9cdf, 0x9abcff];
var bandHeight = 2732 / skyColors.length;
for (var i = 0; i < skyColors.length; i++) {
var skyBand = LK.getAsset('skyBand' + i, {
width: 2048,
height: bandHeight,
color: skyColors[i],
shape: 'box',
y: i * bandHeight
});
skyGradient.addChild(skyBand);
}
self.addChild(skyGradient);
// Create buildings
var buildings = new Container();
self.addChild(buildings);
// Far buildings (darker)
var buildingColors = [0x222a40, 0x323a50, 0x424a60];
var buildingCount = 15;
for (var i = 0; i < buildingCount; i++) {
var buildingWidth = 100 + Math.random() * 150;
var buildingHeight = 300 + Math.random() * 400;
var building = LK.getAsset('building_far_' + i, {
width: buildingWidth,
height: buildingHeight,
color: buildingColors[Math.floor(Math.random() * buildingColors.length)],
shape: 'box',
x: i * (2048 / buildingCount),
y: 2732 - buildingHeight,
anchorY: 0
});
buildings.addChild(building);
}
// Near buildings (slightly lighter)
var nearBuildingColors = [0x303a50, 0x404a60, 0x505a70];
var nearBuildingCount = 10;
for (var i = 0; i < nearBuildingCount; i++) {
var buildingWidth = 180 + Math.random() * 150;
var buildingHeight = 500 + Math.random() * 600;
var building = LK.getAsset('building_near_' + i, {
width: buildingWidth,
height: buildingHeight,
color: nearBuildingColors[Math.floor(Math.random() * nearBuildingColors.length)],
shape: 'box',
x: i * (2048 / nearBuildingCount),
y: 2732 - buildingHeight,
anchorY: 0
});
buildings.addChild(building);
}
// Add some windows to buildings (as small yellow rectangles)
for (var b = 0; b < buildings.children.length; b++) {
var building = buildings.children[b];
var windowCount = Math.floor(building.width / 30) * Math.floor(building.height / 40);
// Limit window count for performance
windowCount = Math.min(windowCount, 20);
for (var w = 0; w < windowCount; w++) {
var windowSize = 10 + Math.random() * 10;
var windowX = Math.random() * (building.width - windowSize);
var windowY = Math.random() * (building.height - windowSize);
// Only add some windows (randomized lighting effect)
if (Math.random() > 0.4) {
var windowLight = LK.getAsset('window_' + b + '_' + w, {
width: windowSize,
height: windowSize,
color: Math.random() > 0.7 ? 0xffcc66 : 0x888888,
// Some windows lit, some not
shape: 'box',
x: building.x + windowX,
y: building.y + windowY
});
self.addChild(windowLight);
}
}
}
// Add clouds
var clouds = new Container();
self.clouds = clouds;
self.addChild(clouds);
var cloudCount = 6;
for (var i = 0; i < cloudCount; i++) {
var cloudWidth = 200 + Math.random() * 300;
var cloudHeight = 100 + Math.random() * 100;
var cloud = LK.getAsset('cloud_' + i, {
width: cloudWidth,
height: cloudHeight,
color: 0xddddff,
shape: 'ellipse',
x: Math.random() * 2048,
y: 200 + Math.random() * 400,
alpha: 0.7
});
// Add some variation to clouds with slight scaling
cloud.scaleX = 0.8 + Math.random() * 0.4;
cloud.scaleY = 0.8 + Math.random() * 0.4;
// Store cloud speed for animation
cloud.speedX = 0.2 + Math.random() * 0.3;
clouds.addChild(cloud);
}
// Update function to animate clouds
self.update = function () {
// Move clouds horizontally
for (var i = 0; i < clouds.children.length; i++) {
var cloud = clouds.children[i];
cloud.x += cloud.speedX;
// Loop clouds when they move off screen
if (cloud.x > 2048 + cloud.width) {
cloud.x = -cloud.width;
cloud.y = 200 + Math.random() * 400;
}
}
};
return self;
});
var BreathingCircle = Container.expand(function () {
var self = Container.call(this);
// Create the breathing circle
var innerCircle = self.attachAsset('centerCircle', {
width: 200,
height: 200,
color: 0x3a5c9f,
anchorX: 0.5,
anchorY: 0.5,
alpha: 0.4
});
var outerCircle = LK.getAsset('centerCircle', {
width: 240,
height: 240,
color: 0x5a7cbf,
anchorX: 0.5,
anchorY: 0.5,
alpha: 0.2
});
self.addChild(outerCircle);
// Breathing animation state
self.breathPhase = 0; // 0: inhale growing, 1: hold, 2: exhale shrinking, 3: hold
self.breathTimer = 0;
self.inhaleDuration = 240; // 4 seconds
self.holdDuration = 120; // 2 seconds
self.exhaleDuration = 240; // 4 seconds
self.restDuration = 60; // 1 second
// Text guide for breathing
self.breathText = new Text2("Breathe In", {
size: 40,
fill: 0xffffff
});
self.breathText.anchor.set(0.5, 0.5);
self.breathText.y = -160;
self.addChild(self.breathText);
// Update method to animate the breathing circle
self.update = function () {
self.breathTimer++;
// Determine current phase based on timer
if (self.breathPhase === 0) {
// Inhale
var progress = self.breathTimer / self.inhaleDuration;
var scale = 1 + progress * 0.5;
innerCircle.scale.x = innerCircle.scale.y = scale;
outerCircle.scale.x = outerCircle.scale.y = 0.9 + progress * 0.5;
self.breathText.setText("Breathe In");
if (self.breathTimer >= self.inhaleDuration) {
self.breathPhase = 1;
self.breathTimer = 0;
}
} else if (self.breathPhase === 1) {
// Hold after inhale
self.breathText.setText("Hold");
if (self.breathTimer >= self.holdDuration) {
self.breathPhase = 2;
self.breathTimer = 0;
}
} else if (self.breathPhase === 2) {
// Exhale
var progress = self.breathTimer / self.exhaleDuration;
var scale = 1.5 - progress * 0.5;
innerCircle.scale.x = innerCircle.scale.y = scale;
outerCircle.scale.x = outerCircle.scale.y = 1.4 - progress * 0.5;
self.breathText.setText("Breathe Out");
if (self.breathTimer >= self.exhaleDuration) {
self.breathPhase = 3;
self.breathTimer = 0;
}
} else {
// Hold after exhale
self.breathText.setText("Rest");
if (self.breathTimer >= self.restDuration) {
self.breathPhase = 0;
self.breathTimer = 0;
}
}
};
return self;
});
var Bullet = Container.expand(function () {
var self = Container.call(this);
var bulletGraphics = self.attachAsset('bullet', {
anchorX: 0.5,
anchorY: 0.5
});
self.speed = 12;
self.direction = {
x: 0,
y: -1
}; // Default upward
self.lifespan = 120; // 2 seconds at 60fps
self.age = 0;
self.damage = 1;
self.update = function () {
self.x += self.direction.x * self.speed;
self.y += self.direction.y * self.speed;
self.age++;
if (self.age > self.lifespan) {
self.markForDeletion = true;
}
};
return self;
});
var Criminal = Container.expand(function () {
var self = Container.call(this);
var criminalGraphics = self.attachAsset('criminal', {
anchorX: 0.5,
anchorY: 0.5
});
self.speed = 2;
self.health = 2; // Reduced from 3
self.shootCooldown = 0;
self.shootDelay = 120; // Frames between shots
self.attackRange = 300; // Reduced from 500
self.movePattern = Math.floor(Math.random() * 3); // 0: direct, 1: zigzag, 2: circle
self.moveTimer = 0;
self.update = function () {
// Target the player
var dx = player.x - self.x;
var dy = player.y - self.y;
var distance = Math.sqrt(dx * dx + dy * dy);
// Movement based on pattern
if (distance > 100) {
// Keep some distance
var moveX = 0;
var moveY = 0;
switch (self.movePattern) {
case 0:
// Direct
moveX = dx / distance;
moveY = dy / distance;
break;
case 1:
// Zigzag
self.moveTimer++;
moveX = dx / distance + Math.sin(self.moveTimer * 0.1) * 0.5;
moveY = dy / distance;
break;
case 2:
// Circle
self.moveTimer++;
moveX = dx / distance + Math.sin(self.moveTimer * 0.05) * 0.8;
moveY = dy / distance + Math.cos(self.moveTimer * 0.05) * 0.8;
break;
}
self.x += moveX * self.speed;
self.y += moveY * self.speed;
}
// Shooting logic
if (distance < self.attackRange) {
if (self.shootCooldown <= 0) {
// Create enemy bullet
var bullet = new Bullet();
bullet.x = self.x;
bullet.y = self.y;
// Calculate direction toward player
var dirX = dx / distance;
var dirY = dy / distance;
bullet.direction = {
x: dirX,
y: dirY
};
// Mark as enemy bullet
bullet.isEnemyBullet = true;
// Add to game's bullets array
bullets.push(bullet);
game.addChild(bullet);
// Reset cooldown with some randomness
self.shootCooldown = self.shootDelay + Math.random() * 60;
}
}
if (self.shootCooldown > 0) {
self.shootCooldown--;
}
};
self.takeDamage = function () {
self.health--;
LK.effects.flashObject(self, 0xFF0000, 300);
if (self.health <= 0) {
LK.getSound('criminal_down').play();
LK.setScore(LK.getScore() + 1);
self.markForDeletion = true;
// Track criminal elimination task
var eliminateTask = tasks.find(function (task) {
return task.id === 'eliminate';
});
if (eliminateTask && !eliminateTask.completed) {
eliminateTask.count++;
if (eliminateTask.count >= eliminateTask.target) {
eliminateTask.completed = true;
LK.effects.flashObject(taskTexts[1], 0x00FF00, 1000);
}
updateTaskDisplay();
}
}
};
return self;
});
var EmergencyCall = Container.expand(function () {
var self = Container.call(this);
var callGraphics = self.attachAsset('emergencyCall', {
anchorX: 0.5,
anchorY: 0.5
});
self.lifetime = 600; // 10 seconds at 60fps
self.age = 0;
self.flashInterval = 30;
self.update = function () {
self.age++;
// Flash effect
if (self.age % self.flashInterval === 0) {
if (callGraphics.alpha === 1) {
tween(callGraphics, {
alpha: 0.3
}, {
duration: 500
});
} else {
tween(callGraphics, {
alpha: 1
}, {
duration: 500
});
}
}
// Expire after lifetime
if (self.age > self.lifetime) {
self.markForDeletion = true;
}
};
self.down = function () {
// Responding to call
LK.getSound('radiochatter').play();
// Spawn criminals from top of screen, using emergency call's X position
spawnCriminals(self.x, 0, 2 + Math.floor(Math.random() * 3));
self.markForDeletion = true;
// Increase score for responding
LK.setScore(LK.getScore() + 2);
// Track emergency call response task
var respondTask = tasks.find(function (task) {
return task.id === 'respond';
});
if (respondTask && !respondTask.completed) {
respondTask.count++;
if (respondTask.count >= respondTask.target) {
respondTask.completed = true;
LK.effects.flashObject(taskTexts[0], 0x00FF00, 1000);
}
updateTaskDisplay();
}
};
return self;
});
var MeditationGuide = Container.expand(function () {
var self = Container.call(this);
// Create a text display for meditation prompts
self.promptText = new Text2("Breathe deeply...", {
size: 60,
fill: 0xffffff,
align: 'center'
});
self.promptText.anchor.set(0.5, 0.5);
self.addChild(self.promptText);
// List of meditation prompts
self.prompts = ["Breathe deeply...", "Focus on your breath...", "Let go of your thoughts...", "Feel the peace within...", "You are present...", "Allow yourself to be...", "Feel the energy flow...", "Find your center..."];
self.currentPrompt = 0;
self.promptTimer = 0;
self.promptDuration = 300; // 5 seconds per prompt
// Update method to cycle through prompts
self.update = function () {
self.promptTimer++;
// Change prompt periodically
if (self.promptTimer >= self.promptDuration) {
self.currentPrompt = (self.currentPrompt + 1) % self.prompts.length;
self.promptText.setText(self.prompts[self.currentPrompt]);
self.promptTimer = 0;
// Animate text appearance
self.promptText.alpha = 0;
tween(self.promptText, {
alpha: 1
}, {
duration: 1000
});
}
// Subtle pulse animation
var scale = 1 + 0.05 * Math.sin(self.promptTimer * 0.01);
self.promptText.scale.x = scale;
self.promptText.scale.y = scale;
};
return self;
});
var MeditationSpace = Container.expand(function () {
var self = Container.call(this);
// Create a peaceful gradient background
var background = new Container();
self.addChild(background);
// Create calming gradient colors for the background
var skyColors = [0x081832, 0x112a4e, 0x1a3c6a, 0x234e86, 0x2c60a2];
var bandHeight = 2732 / skyColors.length;
for (var i = 0; i < skyColors.length; i++) {
var skyBand = LK.getAsset('skyBand' + i, {
width: 2048,
height: bandHeight,
color: skyColors[i],
y: i * bandHeight
});
background.addChild(skyBand);
}
// Create stars
var stars = new Container();
self.stars = stars;
self.addChild(stars);
// Add stars to the night sky
var starCount = 100;
for (var i = 0; i < starCount; i++) {
var starSize = 2 + Math.random() * 4;
var star = LK.getAsset('star_' + i, {
width: starSize,
height: starSize,
color: 0xffffff,
shape: 'ellipse',
x: Math.random() * 2048,
y: Math.random() * 1200,
alpha: 0.5 + Math.random() * 0.5
});
star.pulseSpeed = 0.01 + Math.random() * 0.02;
star.pulsePhase = Math.random() * Math.PI * 2;
stars.addChild(star);
}
// Add floating lotus flowers
var lotusFlowers = new Container();
self.lotusFlowers = lotusFlowers;
self.addChild(lotusFlowers);
var lotusCount = 5;
for (var i = 0; i < lotusCount; i++) {
var lotusSize = 80 + Math.random() * 40;
var lotus = LK.getAsset('lotus_' + i, {
width: lotusSize,
height: lotusSize,
color: 0xffb6c1,
shape: 'ellipse',
x: 400 + Math.random() * 1200,
y: 1500 + Math.random() * 800
});
lotus.floatSpeed = 0.2 + Math.random() * 0.3;
lotus.floatPhase = Math.random() * Math.PI * 2;
lotusFlowers.addChild(lotus);
}
// Add water ripples
var ripples = new Container();
self.ripples = ripples;
self.addChild(ripples);
self.rippleTimer = 0;
// Update function to animate elements
self.update = function () {
// Animate stars (pulsing effect)
for (var i = 0; i < stars.children.length; i++) {
var star = stars.children[i];
star.pulsePhase += star.pulseSpeed;
star.alpha = 0.5 + 0.5 * Math.sin(star.pulsePhase);
}
// Animate lotus flowers (gentle floating)
for (var i = 0; i < lotusFlowers.children.length; i++) {
var lotus = lotusFlowers.children[i];
lotus.floatPhase += 0.01;
lotus.y += Math.sin(lotus.floatPhase) * lotus.floatSpeed;
}
// Create new ripples periodically
self.rippleTimer++;
if (self.rippleTimer > 120) {
// Every 2 seconds
self.createRipple(400 + Math.random() * 1200, 1500 + Math.random() * 800);
self.rippleTimer = 0;
}
// Update existing ripples
for (var i = ripples.children.length - 1; i >= 0; i--) {
var ripple = ripples.children[i];
ripple.age++;
// Expand ripple
ripple.scale.x += 0.01;
ripple.scale.y += 0.01;
// Fade out ripple
ripple.alpha = 1 - ripple.age / ripple.lifespan;
// Remove old ripples
if (ripple.age >= ripple.lifespan) {
ripple.destroy();
ripples.removeChild(ripple);
}
}
};
// Method to create a new water ripple
self.createRipple = function (x, y) {
var ripple = LK.getAsset('ripple', {
width: 50,
height: 50,
color: 0xffffff,
shape: 'ellipse',
x: x,
y: y,
anchorX: 0.5,
anchorY: 0.5,
alpha: 0.7
});
ripple.age = 0;
ripple.lifespan = 120; // 2 seconds
ripples.addChild(ripple);
};
return self;
});
var Player = Container.expand(function () {
var self = Container.call(this);
var playerGraphics = self.attachAsset('player', {
anchorX: 0.5,
anchorY: 0.5
});
self.speed = 5;
self.health = 100;
self.maxHealth = 100;
self.shootCooldown = 0;
self.shootDelay = 15; // Frames between shots
self.canMove = true;
// Health bar setup
var healthBarBg = self.attachAsset('healthBarBackground', {
anchorX: 0.5,
anchorY: 0,
y: 120
});
var healthBarFill = self.attachAsset('healthBar', {
anchorX: 0.5,
anchorY: 0,
y: 122
});
self.updateHealthBar = function () {
var healthPercentage = self.health / self.maxHealth;
healthBarFill.scale.x = healthPercentage;
// Center the health bar
healthBarFill.x = -100 * (1 - healthPercentage);
};
self.takeDamage = function (amount) {
self.health -= amount;
if (self.health <= 0) {
self.health = 0;
LK.effects.flashScreen(0xFF0000, 1000);
LK.showGameOver();
}
self.updateHealthBar();
};
self.shoot = function () {
if (self.shootCooldown <= 0) {
var bullet = new Bullet();
bullet.x = self.x;
bullet.y = self.y - 40;
// Add to game's bullets array
bullets.push(bullet);
game.addChild(bullet);
// Play gun sound
LK.getSound('gunshot').play();
// Reset cooldown
self.shootCooldown = self.shootDelay;
}
};
self.update = function () {
if (self.shootCooldown > 0) {
self.shootCooldown--;
}
};
self.down = function (x, y, obj) {
self.shoot();
};
// Initialize health bar
self.updateHealthBar();
return self;
});
var SoulOrb = Container.expand(function () {
var self = Container.call(this);
// Create the soul orb with a glowing effect
var orbCore = self.attachAsset('centerCircle', {
width: 60,
height: 60,
color: 0x83de44,
anchorX: 0.5,
anchorY: 0.5
});
// Create outer glow
var orbGlow = LK.getAsset('centerCircle', {
width: 100,
height: 100,
color: 0xb8ffb0,
anchorX: 0.5,
anchorY: 0.5,
alpha: 0.5
});
self.addChild(orbGlow);
// Add pulsating animation to the glow
self.glowPhase = 0;
self.energy = 0; // Energy level (0-100)
self.maxEnergy = 100;
self.pulseSpeed = 0.05;
// Update method to animate the orb
self.update = function () {
self.glowPhase += self.pulseSpeed;
orbGlow.scale.x = 1 + 0.2 * Math.sin(self.glowPhase);
orbGlow.scale.y = 1 + 0.2 * Math.sin(self.glowPhase);
// Adjust color based on energy level
var energyRatio = self.energy / self.maxEnergy;
var r = Math.floor(131 + (255 - 131) * energyRatio);
var g = Math.floor(222 + (255 - 222) * energyRatio);
var b = Math.floor(68 + (255 - 68) * energyRatio);
// Convert RGB to hex
var color = r << 16 | g << 8 | b;
orbCore.tint = color;
};
// Method to add energy to the orb
self.addEnergy = function (amount) {
self.energy = Math.min(self.maxEnergy, self.energy + amount);
// Flash with increasing brightness as energy increases
LK.effects.flashObject(self, 0xffffff, 300);
};
return self;
});
/****
* Initialize Game
****/
var game = new LK.Game({
backgroundColor: 0x081832
});
/****
* Game Code
****/
// Game variables
var meditationSpace;
var soulOrb;
var breathingCircle;
var meditationGuide;
var gameActive = true;
var dragOffset = {
x: 0,
y: 0
};
var meditationLevel = 1;
var meditationTime = 0;
var soulEnergy = 0;
var maxSoulEnergy = 100;
var breathingTimer = 0;
// Meditation practices
var practices = [{
id: 'breathe',
text: 'Complete 5 breathing cycles',
count: 0,
target: 5,
completed: false
}, {
id: 'focus',
text: 'Maintain focus for 60 seconds',
count: 0,
target: 60,
completed: false
}, {
id: 'energy',
text: 'Fill your soul with energy',
count: 0,
target: 100,
completed: false
}];
// Setup practice UI
var practiceContainer = new Container();
practiceContainer.x = 40;
practiceContainer.y = 180;
LK.gui.left.addChild(practiceContainer);
var practiceTitle = new Text2('PRACTICES:', {
size: 50,
fill: 0xFFFFFF
});
practiceContainer.addChild(practiceTitle);
// Create text for each practice
var practiceTexts = [];
for (var i = 0; i < practices.length; i++) {
var practiceText = new Text2('• ' + practices[i].text + ' (0/' + practices[i].target + ')', {
size: 40,
fill: 0xCCCCCC
});
practiceText.y = 60 + i * 50;
practiceContainer.addChild(practiceText);
practiceTexts.push(practiceText);
}
// Function to update practice UI
function updatePracticeDisplay() {
for (var i = 0; i < practices.length; i++) {
var practice = practices[i];
var color = practice.completed ? 0x83de44 : 0xCCCCCC;
practiceTexts[i].setText('• ' + practice.text + ' (' + practice.count + '/' + practice.target + ')');
practiceTexts[i].fill = color;
}
}
// Setup UI
var energyTxt = new Text2('Soul Energy: 0%', {
size: 60,
fill: 0xFFFFFF
});
energyTxt.anchor.set(0.5, 0);
LK.gui.top.addChild(energyTxt);
var levelTxt = new Text2('Meditation Level: 1', {
size: 60,
fill: 0xFFFFFF
});
levelTxt.anchor.set(0.5, 0);
levelTxt.y = 70;
LK.gui.top.addChild(levelTxt);
// Create and add meditation space
meditationSpace = new MeditationSpace();
game.addChild(meditationSpace);
// Initialize soul orb
soulOrb = new SoulOrb();
soulOrb.x = 2048 / 2;
soulOrb.y = 2732 / 3;
game.addChild(soulOrb);
// Initialize breathing circle
breathingCircle = new BreathingCircle();
breathingCircle.x = 2048 / 2;
breathingCircle.y = 2732 / 2 + 200;
game.addChild(breathingCircle);
// Initialize meditation guide
meditationGuide = new MeditationGuide();
meditationGuide.x = 2048 / 2;
meditationGuide.y = 2732 / 5;
game.addChild(meditationGuide);
// Play meditation music
LK.playMusic('background_music');
// Create a ripple at a position (utility function)
function createRipple(x, y) {
meditationSpace.createRipple(x, y);
}
// Add soul energy
function addSoulEnergy(amount) {
soulOrb.addEnergy(amount);
// Update energy practice
var energyPractice = practices.find(function (practice) {
return practice.id === 'energy';
});
if (energyPractice && !energyPractice.completed) {
energyPractice.count = Math.floor(soulOrb.energy);
if (energyPractice.count >= energyPractice.target) {
energyPractice.completed = true;
LK.effects.flashObject(practiceTexts[2], 0x83de44, 1000);
}
updatePracticeDisplay();
}
}
// Check if meditation level should increase
function checkMeditationProgress() {
// Check if practices are completed to progress meditation level
var completedPractices = practices.filter(function (practice) {
return practice.completed;
}).length;
var newLevel = 1 + Math.floor(completedPractices / 2);
if (newLevel > meditationLevel) {
meditationLevel = newLevel;
levelTxt.setText('Meditation Level: ' + meditationLevel);
// Bonus for reaching new level
addSoulEnergy(10 * meditationLevel);
// Visual feedback
LK.effects.flashScreen(0x83de44, 500);
}
}
// Meditation interaction handling
game.down = function (x, y, obj) {
// Calculate distances to interactive elements
var distToOrb = Math.sqrt(Math.pow(x - soulOrb.x, 2) + Math.pow(y - soulOrb.y, 2));
// If touching the soul orb
if (distToOrb < 100) {
// Add energy to the soul
soulOrb.addEnergy(5);
// Emit a ripple effect from the interaction point
meditationSpace.createRipple(x, y);
// Create visual feedback
LK.effects.flashObject(soulOrb, 0xFFFFFF, 500);
} else {
// Create ripple at touch point
meditationSpace.createRipple(x, y);
}
// Set drag offset for moving the orb
dragOffset.x = soulOrb.x - x;
dragOffset.y = soulOrb.y - y;
};
game.move = function (x, y, obj) {
// Move soul orb with drag
soulOrb.x = x + dragOffset.x;
soulOrb.y = y + dragOffset.y;
// Keep soul orb in bounds
soulOrb.x = Math.max(100, Math.min(2048 - 100, soulOrb.x));
soulOrb.y = Math.max(100, Math.min(2732 - 100, soulOrb.y));
// Create subtle ripple effects during movement
if (Math.random() < 0.1) {
meditationSpace.createRipple(soulOrb.x + (Math.random() * 100 - 50), soulOrb.y + (Math.random() * 100 - 50));
}
};
game.up = function () {
// Create final ripple at release point
meditationSpace.createRipple(soulOrb.x, soulOrb.y);
};
// Game update loop
game.update = function () {
if (!gameActive) return;
// Update meditation space
meditationSpace.update();
// Update soul orb, breathing circle, and guide
soulOrb.update();
breathingCircle.update();
meditationGuide.update();
// Update energy display
energyTxt.setText('Soul Energy: ' + Math.floor(soulOrb.energy / maxSoulEnergy * 100) + '%');
// Track breathing cycles for breathe practice
if (breathingCircle.breathPhase === 3 && breathingCircle.breathTimer === 0) {
// Just completed a full breathing cycle
var breathePractice = practices.find(function (practice) {
return practice.id === 'breathe';
});
if (breathePractice && !breathePractice.completed) {
breathePractice.count++;
if (breathePractice.count >= breathePractice.target) {
breathePractice.completed = true;
LK.effects.flashObject(practiceTexts[0], 0x83de44, 1000);
// Add soul energy when completing breathing practice
soulOrb.addEnergy(20);
}
updatePracticeDisplay();
}
}
// Track focus time for focus practice
meditationTime++;
if (meditationTime % 60 === 0) {
// Every second
var focusPractice = practices.find(function (practice) {
return practice.id === 'focus';
});
if (focusPractice && !focusPractice.completed) {
focusPractice.count++;
if (focusPractice.count >= focusPractice.target) {
focusPractice.completed = true;
LK.effects.flashObject(practiceTexts[1], 0x83de44, 1000);
// Add soul energy when completing focus practice
soulOrb.addEnergy(30);
}
updatePracticeDisplay();
}
}
// Add soul energy over time with active meditation
if (meditationTime % 180 === 0) {
// Every 3 seconds
soulOrb.addEnergy(1);
// Track soul energy for energy practice
var energyPractice = practices.find(function (practice) {
return practice.id === 'energy';
});
if (energyPractice && !energyPractice.completed) {
energyPractice.count = Math.floor(soulOrb.energy);
if (energyPractice.count >= energyPractice.target) {
energyPractice.completed = true;
LK.effects.flashObject(practiceTexts[2], 0x83de44, 1000);
}
updatePracticeDisplay();
}
}
// Check for meditation level up
if (meditationTime % 600 === 0) {
// Every 10 seconds
meditationLevel++;
levelTxt.setText('Meditation Level: ' + meditationLevel);
// Visual feedback for level up
LK.effects.flashScreen(0x83de44, 500);
}
// Check if all practices are completed
var allPracticesCompleted = practices.every(function (practice) {
return practice.completed;
});
if (allPracticesCompleted && gameActive) {
// Show enlightenment message
var enlightenmentMessage = new Text2('ENLIGHTENMENT ACHIEVED!', {
size: 100,
fill: 0xFFFFFF
});
enlightenmentMessage.anchor.set(0.5, 0.5);
enlightenmentMessage.x = 2048 / 2;
enlightenmentMessage.y = 2732 / 2;
game.addChild(enlightenmentMessage);
// Visual effects for enlightenment
LK.effects.flashScreen(0xFFFFFF, 2000);
// Create new practices with higher requirements
practices = [{
id: 'breathe',
text: 'Complete 10 breathing cycles',
count: 0,
target: 10,
completed: false
}, {
id: 'focus',
text: 'Maintain focus for 120 seconds',
count: 0,
target: 120,
completed: false
}, {
id: 'energy',
text: 'Achieve deeper enlightenment',
count: 0,
target: 200,
completed: false
}];
// Update practice display
for (var i = 0; i < practices.length; i++) {
practiceTexts[i].setText('• ' + practices[i].text + ' (0/' + practices[i].target + ')');
practiceTexts[i].fill = 0xCCCCCC;
}
// Increase soul orb capacity
maxSoulEnergy = 200;
// Remove the enlightenment message after 3 seconds
LK.setTimeout(function () {
enlightenmentMessage.destroy();
updatePracticeDisplay();
}, 3000);
}
};