User prompt
lets do it ava for darkspiritsound than yes for level3 and 4.
User prompt
lets do it ava for darkspiritsound than yes for level3 and 4.
Code edit (1 edits merged)
Please save this source code
User prompt
add shadowspiritsound for shadowspirit and darkspiritsound for darkspirit.
User prompt
add level3music for level3, level4music for level4
User prompt
Add level2music for level2
User prompt
Make level1music for level1, remove bathhouse music.
User prompt
Remove Shadowspiritsound asset from music list
User prompt
Remove Shadowspiritsound asset from music list
User prompt
Add pollutedspirit6 pollutedspirit7 pollutedspirit8 for level4, respawn only this 3 pollutedspirits in showerareas for level4
User prompt
Add level4 with showerareas 2x3 and 500px spacing.
User prompt
Add pollutedspirit3 pollutedspirit4 pollutedspirit5 for level3.
User prompt
Add level3 have 6 showerareas 3x2 in the middle of the screen same spacing 500px.
User prompt
Do the respawning time for bluespirits to respawn in the game each 20sec and turning to dark after 10sec
User prompt
Respawn bluespirit each 20sec in level2 not just for level1!
User prompt
Respawn 1 bluespirit each 20sec not 10sec
User prompt
don't respawn shadowspirit when pollutedspirit is respawned!
User prompt
the darkspirit are appearing behind pollutedspirit. don't respawn darkspirit only if pollutedspirit is respawned!
User prompt
Respawn max 2 darkspirit in level1 and max 4 darkspirit in level2 when pollutedspirit is respawned not by showerarea or by time.
User prompt
Respawn max 2 darkspirit in level1 and max 4 darkspirit in level2 by cleaned pollutedspirit not by showerarea or by time.
User prompt
Respawn darkspirit one each showerarea, cleaning pollutedspirit remove one darkspirit.
/**** * Plugins ****/ var tween = LK.import("@upit/tween.v1"); /**** * Classes ****/ var BlueSpirit = Container.expand(function () { var self = Container.call(this); var spiritGraphics = self.attachAsset('blueSpirit', { anchorX: 0.5, anchorY: 0.5 }); self.waitTime = 0; self.maxWaitTime = 600; // 10 seconds at 60fps self.isDark = false; self.speed = 1; self.update = function () { self.waitTime++; if (!self.isDark && self.waitTime >= self.maxWaitTime) { self.turnDark(); } if (self.isDark) { self.y += self.speed; } }; self.turnDark = function () { self.isDark = true; spiritGraphics.tint = 0x2a0845; tween(spiritGraphics, { scaleX: 1.2, scaleY: 1.2 }, { duration: 500 }); }; return self; }); var DarkSpirit = Container.expand(function () { var self = Container.call(this); var darkGraphics = self.attachAsset('darkSpirit', { anchorX: 0.5, anchorY: 0.5 }); self.speed = 1.5; self.targetPlayer = null; self.update = function () { if (self.targetPlayer) { var dx = self.targetPlayer.x - self.x; var dy = self.targetPlayer.y - self.y; var distance = Math.sqrt(dx * dx + dy * dy); if (distance > 5) { self.x += dx / distance * self.speed; self.y += dy / distance * self.speed; } // Change direction based on position relative to screen middle var screenMiddle = 1024; if (self.x < screenMiddle) { // Dark spirit is on left side, face right towards middle self.scaleX = 1; } else { // Dark spirit is on right side, face left towards middle self.scaleX = -1; } } }; return self; }); var HealthBar = Container.expand(function () { var self = Container.call(this); // Background bar self.bgBar = self.attachAsset('healthBarBg', { anchorX: 0, anchorY: 0.5 }); // Health bar self.healthBar = self.attachAsset('healthBarFill', { anchorX: 0, anchorY: 0.5 }); self.maxWidth = 300; self.updateHealth = function (healthPercent) { self.healthBar.scaleX = healthPercent / 100; }; return self; }); var Player = Container.expand(function () { var self = Container.call(this); var playerGraphics = self.attachAsset('player', { anchorX: 0.5, anchorY: 0.5 }); self.tokens = 0; self.health = 100; self.maxHealth = 100; self.collectToken = function () { self.tokens++; }; self.deliverTokens = function () { var delivered = self.tokens; self.tokens = 0; return delivered; }; self.takeDamage = function () { var damage = Math.random() * 7 + 3; // Random between 3-10 self.health -= damage; self.health = Math.max(0, self.health); // Ensure health doesn't go below 0 LK.effects.flashObject(self, 0xff0000, 500); return self.health <= 0; }; return self; }); var PollutedSpirit = Container.expand(function () { var self = Container.call(this); var pollutedGraphics = self.attachAsset('pollutedspirit1', { anchorX: 0.5, anchorY: 0.5 }); self.tokensNeeded = 3; self.isCleansed = false; self.cleanse = function () { self.isCleansed = true; tween(pollutedGraphics, { tint: 0x98fb98 }, { duration: 1000, onFinish: function onFinish() { self.destroy(); } }); }; return self; }); var PollutedSpirit2 = Container.expand(function () { var self = Container.call(this); var pollutedGraphics = self.attachAsset('pollutedspirit2', { anchorX: 0.5, anchorY: 0.5 }); self.tokensNeeded = 3; self.isCleansed = false; self.cleanse = function () { self.isCleansed = true; tween(pollutedGraphics, { tint: 0x98fb98 }, { duration: 1000, onFinish: function onFinish() { self.destroy(); } }); }; return self; }); var RiverSpirit = Container.expand(function () { var self = Container.call(this); var riverGraphics = self.attachAsset('riverSpirit', { anchorX: 0.5, anchorY: 0.5 }); self.bonusValue = 20; self.speed = 0.5; self.update = function () { self.x += self.speed; self.rotation += 0.01; }; return self; }); var ShadowSpirit = Container.expand(function () { var self = Container.call(this); var shadowGraphics = self.attachAsset('shadowSpirit', { anchorX: 0.5, anchorY: 0.5 }); self.speed = 2; self.targetPlayer = null; self.update = function () { if (self.targetPlayer) { var dx = self.targetPlayer.x - self.x; var dy = self.targetPlayer.y - self.y; var distance = Math.sqrt(dx * dx + dy * dy); if (distance > 5) { self.x += dx / distance * self.speed; self.y += dy / distance * self.speed; } // Change direction based on position relative to screen middle var screenMiddle = 1024; if (self.x < screenMiddle) { // Shadow is on left side, face right towards middle self.scaleX = 1; } else { // Shadow is on right side, face left towards middle self.scaleX = -1; } } }; return self; }); var Token = Container.expand(function () { var self = Container.call(this); var tokenGraphics = self.attachAsset('token', { anchorX: 0.5, anchorY: 0.5 }); self.collected = false; self.update = function () { if (!self.collected) { self.rotation += 0.02; } }; return self; }); /**** * Initialize Game ****/ var game = new LK.Game({ backgroundColor: 0x1a1a2e }); /**** * Game Code ****/ var gameStarted = false; var introBackground = null; var startButton = null; var currentLevel = 'level1'; var gameBackground = null; // Declare game variables in global scope var player, tokens, blueSpirits, shadowSpirits, pollutedSpirits, riverSpirit, darkSpirits; var spawnTimer, spawnInterval, shadowSpawnTimer, shadowSpawnInterval; var scoreTxt, tokenTxt, healthBar; var brushSprite = null; var showerAreas = [], pollutedSpawnTimer, pollutedSpawnInterval; var maxShadowSpirits = 2; // Level 1: 2, Level 2: 4 var shadowRespawnTimer = 0; var shadowRespawnInterval = 180; // 3 seconds to respawn var lastMovementSoundTime = 0; var movementSoundCooldown = 1000; // Milliseconds between sound plays // Show intro screen function showIntroScreen() { introBackground = game.addChild(LK.getAsset('introbackground', { anchorX: 0, anchorY: 0, x: 0, y: 0 })); startButton = game.addChild(LK.getAsset('startbutton', { anchorX: 0.5, anchorY: 0.5, x: 1024, y: 2400 })); // Only play intro music if game hasn't started and we're actually showing intro screen if (!gameStarted && introBackground && startButton) { LK.playMusic('intromusic'); } } // Start the actual game function startGame() { gameStarted = true; if (introBackground) { introBackground.destroy(); introBackground = null; } if (startButton) { startButton.destroy(); startButton = null; } LK.stopMusic(); LK.playMusic('bathhouse'); initializeGame(); } // Spawn functions in global scope function spawnToken() { var token = new Token(); token.x = Math.random() * 1848 + 100; token.y = Math.random() * 2332 + 300; tokens.push(token); game.addChild(token); } function spawnSpirit() { var spirit = new BlueSpirit(); spirit.x = Math.random() * 1848 + 100; spirit.y = 300; blueSpirits.push(spirit); game.addChild(spirit); } function spawnShadowSpirit() { // Only spawn if under the limit if (shadowSpirits.length < maxShadowSpirits) { var shadow = new ShadowSpirit(); shadow.x = Math.random() * 1848 + 100; shadow.y = Math.random() * 400 + 300; shadow.targetPlayer = player; shadowSpirits.push(shadow); game.addChild(shadow); } } function spawnPollutedSpirit() { // Find an empty shower area var emptyAreas = []; for (var i = 0; i < showerAreas.length; i++) { if (!showerAreas[i].occupied) { emptyAreas.push(showerAreas[i]); } } // Spawn one darkspirit per shower area that doesn't already have one for (var a = 0; a < showerAreas.length; a++) { var hasExistingDark = false; for (var d = 0; d < darkSpirits.length; d++) { if (Math.abs(darkSpirits[d].x - showerAreas[a].x) < 100 && Math.abs(darkSpirits[d].y - showerAreas[a].y) < 100) { hasExistingDark = true; break; } } if (!hasExistingDark) { var darkSpirit = new DarkSpirit(); darkSpirit.x = showerAreas[a].x + 50; darkSpirit.y = showerAreas[a].y + 30; darkSpirit.targetPlayer = player; darkSpirits.push(darkSpirit); game.addChild(darkSpirit); } } // Only spawn if there's an empty area if (emptyAreas.length > 0) { if (currentLevel === 'level2') { // Level 2: Spawn both types if we have at least 2 empty areas if (emptyAreas.length >= 2) { // Spawn PollutedSpirit (pollutedspirit1) var selectedArea1 = emptyAreas[Math.floor(Math.random() * emptyAreas.length)]; var polluted1 = new PollutedSpirit(); polluted1.x = selectedArea1.x; polluted1.y = selectedArea1.y; polluted1.assignedShowerArea = selectedArea1; selectedArea1.occupied = true; pollutedSpirits.push(polluted1); game.addChild(polluted1); // Spawn ShadowSpirit behind polluted1 var shadow1 = new ShadowSpirit(); shadow1.x = polluted1.x - 50; shadow1.y = polluted1.y + 30; shadow1.targetPlayer = player; shadowSpirits.push(shadow1); game.addChild(shadow1); // Remove the used area from available areas emptyAreas.splice(emptyAreas.indexOf(selectedArea1), 1); // Spawn PollutedSpirit2 (pollutedspirit2) var selectedArea2 = emptyAreas[Math.floor(Math.random() * emptyAreas.length)]; var polluted2 = new PollutedSpirit2(); polluted2.x = selectedArea2.x; polluted2.y = selectedArea2.y; polluted2.assignedShowerArea = selectedArea2; selectedArea2.occupied = true; pollutedSpirits.push(polluted2); game.addChild(polluted2); } else { // Only one empty area, spawn randomly either type var selectedArea = emptyAreas[0]; var polluted = Math.random() < 0.5 ? new PollutedSpirit() : new PollutedSpirit2(); polluted.x = selectedArea.x; polluted.y = selectedArea.y; polluted.assignedShowerArea = selectedArea; selectedArea.occupied = true; pollutedSpirits.push(polluted); game.addChild(polluted); // Spawn appropriate spirit behind the polluted spirit if (polluted instanceof PollutedSpirit) { var shadow = new ShadowSpirit(); shadow.x = polluted.x - 50; shadow.y = polluted.y + 30; shadow.targetPlayer = player; shadowSpirits.push(shadow); game.addChild(shadow); } } } else { // Level 1: Spawn only PollutedSpirit (pollutedspirit1) var selectedArea = emptyAreas[Math.floor(Math.random() * emptyAreas.length)]; var polluted = new PollutedSpirit(); polluted.x = selectedArea.x; polluted.y = selectedArea.y; polluted.assignedShowerArea = selectedArea; selectedArea.occupied = true; pollutedSpirits.push(polluted); game.addChild(polluted); // Spawn ShadowSpirit behind polluted spirit in level1 var shadow = new ShadowSpirit(); shadow.x = polluted.x - 50; shadow.y = polluted.y + 30; shadow.targetPlayer = player; shadowSpirits.push(shadow); game.addChild(shadow); } // Move brush sprite to render on top of polluted spirits if (brushSprite) { game.removeChild(brushSprite); game.addChild(brushSprite); } // Ensure player renders on top of polluted spirits if (player) { game.removeChild(player); game.addChild(player); } } } function spawnRiverSpirit() { if (!riverSpirit) { riverSpirit = new RiverSpirit(); riverSpirit.x = -100; riverSpirit.y = Math.random() * 1000 + 1066; game.addChild(riverSpirit); } } function startLevel2() { currentLevel = 'level2'; // Remove current background if (gameBackground) { gameBackground.destroy(); gameBackground = null; } // Clear all existing enemies from level1 for (var i = blueSpirits.length - 1; i >= 0; i--) { blueSpirits[i].destroy(); } blueSpirits = []; for (var j = shadowSpirits.length - 1; j >= 0; j--) { shadowSpirits[j].destroy(); } shadowSpirits = []; for (var d = darkSpirits.length - 1; d >= 0; d--) { darkSpirits[d].destroy(); } darkSpirits = []; for (var k = pollutedSpirits.length - 1; k >= 0; k--) { if (pollutedSpirits[k].assignedShowerArea) { pollutedSpirits[k].assignedShowerArea.occupied = false; } pollutedSpirits[k].destroy(); } pollutedSpirits = []; if (riverSpirit) { riverSpirit.destroy(); riverSpirit = null; } // Remove existing shower areas for (var i = 0; i < showerAreas.length; i++) { showerAreas[i].destroy(); } showerAreas = []; // Add level2 background gameBackground = game.addChild(LK.getAsset('background02', { anchorX: 0, anchorY: 0, x: 0, y: 0, visible: true })); // Add 4 shower areas for level2 in 2x2 grid var screenMiddle = 1024; var spacing = 500; // 500px spacing between shower areas var positions = [{ x: screenMiddle - spacing / 2, y: 1366 - spacing / 2 }, { x: screenMiddle + spacing / 2, y: 1366 - spacing / 2 }, { x: screenMiddle - spacing / 2, y: 1366 + spacing / 2 }, { x: screenMiddle + spacing / 2, y: 1366 + spacing / 2 }]; for (var p = 0; p < positions.length; p++) { var showerArea = game.addChild(LK.getAsset('Showerarea', { anchorX: 0.5, anchorY: 0.5, x: positions[p].x, y: positions[p].y })); showerArea.occupied = false; showerAreas.push(showerArea); } // Move player to front to ensure it renders above the new background game.removeChild(player); game.addChild(player); // Reset game state for new level player.health = player.maxHealth; healthBar.updateHealth(player.health); spawnInterval = 120; // Make level2 slightly harder shadowSpawnInterval = 240; maxShadowSpirits = 4; // Increase limit for level2 } function initializeGame() { game.setBackgroundColor(0x16213e); currentLevel = 'level1'; // Add level1 game background gameBackground = game.addChild(LK.getAsset('gamebackground', { anchorX: 0, anchorY: 0, x: 0, y: 0 })); player = game.addChild(new Player()); player.x = 1024; player.y = 2200; tokens = []; blueSpirits = []; shadowSpirits = []; pollutedSpirits = []; darkSpirits = []; riverSpirit = null; spawnTimer = 0; spawnInterval = 180; // Level1 difficulty shadowSpawnTimer = 0; shadowSpawnInterval = 360; // Level1 difficulty maxShadowSpirits = 2; // Level 1 limit shadowRespawnTimer = 0; scoreTxt = new Text2('Score: 0', { size: 80, fill: 0xFFFFFF }); scoreTxt.anchor.set(0.5, 0); LK.gui.top.addChild(scoreTxt); tokenTxt = new Text2('Tokens: 0', { size: 60, fill: 0xFFD700 }); tokenTxt.anchor.set(1, 0); tokenTxt.x = -20; LK.gui.topRight.addChild(tokenTxt); healthBar = new HealthBar(); healthBar.x = 20; healthBar.y = 30; LK.gui.topLeft.addChild(healthBar); // Initial spawns for (var i = 0; i < 5; i++) { spawnToken(); } spawnSpirit(); spawnPollutedSpirit(); // Initialize brush sprite (initially hidden) brushSprite = LK.getAsset('brush', { anchorX: 0.5, anchorY: 0.5 }); brushSprite.visible = false; game.addChild(brushSprite); // Initialize shower area system showerAreas = []; pollutedSpawnTimer = 0; pollutedSpawnInterval = 600; // 10 seconds at 60fps // Add shower areas based on level var screenMiddle = 1024; var spacing = 200; var showerAreaWidth = 300; // Based on asset width if (currentLevel === 'level1') { // Level 1: 2 shower areas var leftShowerArea = game.addChild(LK.getAsset('Showerarea', { anchorX: 0.5, anchorY: 0.5, x: screenMiddle - spacing / 2 - showerAreaWidth / 2, y: 1366 // Middle of screen height })); leftShowerArea.occupied = false; showerAreas.push(leftShowerArea); var rightShowerArea = game.addChild(LK.getAsset('Showerarea', { anchorX: 0.5, anchorY: 0.5, x: screenMiddle + spacing / 2 + showerAreaWidth / 2, y: 1366 // Middle of screen height })); rightShowerArea.occupied = false; showerAreas.push(rightShowerArea); } else if (currentLevel === 'level2') { // Level 2: 4 shower areas in 2x2 grid var spacing = 500; // 500px spacing between shower areas var positions = [{ x: screenMiddle - spacing / 2, y: 1366 - spacing / 2 }, { x: screenMiddle + spacing / 2, y: 1366 - spacing / 2 }, { x: screenMiddle - spacing / 2, y: 1366 + spacing / 2 }, { x: screenMiddle + spacing / 2, y: 1366 + spacing / 2 }]; for (var p = 0; p < positions.length; p++) { var showerArea = game.addChild(LK.getAsset('Showerarea', { anchorX: 0.5, anchorY: 0.5, x: positions[p].x, y: positions[p].y })); showerArea.occupied = false; showerAreas.push(showerArea); } } // Move player to front to ensure it renders above shower areas game.removeChild(player); game.addChild(player); } var dragActive = false; var currentMovementSprite = 'player'; var movementAnimationTimer = 0; var movementAnimationInterval = 15; // Switch every 15 frames (quarter second at 60fps) game.down = function (x, y, obj) { if (!gameStarted && startButton) { // Check if click is within start button bounds var buttonLeft = startButton.x - startButton.width * startButton.anchor.x; var buttonRight = startButton.x + startButton.width * (1 - startButton.anchor.x); var buttonTop = startButton.y - startButton.height * startButton.anchor.y; var buttonBottom = startButton.y + startButton.height * (1 - startButton.anchor.y); if (x >= buttonLeft && x <= buttonRight && y >= buttonTop && y <= buttonBottom) { startGame(); return; } } if (gameStarted) { dragActive = true; } }; game.up = function (x, y, obj) { if (gameStarted) { dragActive = false; } }; game.move = function (x, y, obj) { if (gameStarted && dragActive && player) { player.x = x; player.y = y; // Throttle movement sound to prevent too frequent playback var currentTime = Date.now(); if (currentTime - lastMovementSoundTime >= movementSoundCooldown) { LK.getSound('playermovment').play(); lastMovementSoundTime = currentTime; } } }; game.update = function () { if (!gameStarted) { return; } // Update spawn timers spawnTimer++; shadowSpawnTimer++; if (spawnTimer >= spawnInterval) { spawnSpirit(); spawnTimer = 0; // Increase difficulty if (spawnInterval > 60) { spawnInterval -= 2; } } if (shadowSpawnTimer >= shadowSpawnInterval) { spawnShadowSpirit(); shadowSpawnTimer = 0; } // Shadow spirit respawn timer shadowRespawnTimer++; if (shadowRespawnTimer >= shadowRespawnInterval && shadowSpirits.length < maxShadowSpirits) { spawnShadowSpirit(); shadowRespawnTimer = 0; } // Token spawning if (LK.ticks % 120 === 0) { spawnToken(); } // Polluted spirit spawning every 10 seconds pollutedSpawnTimer++; if (pollutedSpawnTimer >= pollutedSpawnInterval) { spawnPollutedSpirit(); pollutedSpawnTimer = 0; } // River spirit spawning if (LK.getScore() > 0 && LK.getScore() % 50 === 0 && !riverSpirit) { spawnRiverSpirit(); } // Check token collection for (var i = tokens.length - 1; i >= 0; i--) { var token = tokens[i]; if (!token.collected && player.intersects(token)) { token.collected = true; player.collectToken(); tokenTxt.setText('Tokens: ' + player.tokens); LK.getSound('collect').play(); token.destroy(); tokens.splice(i, 1); } } // Check spirit interactions for (var j = blueSpirits.length - 1; j >= 0; j--) { var spirit = blueSpirits[j]; if (!spirit.isDark && player.intersects(spirit) && player.tokens > 0) { player.tokens -= 1; // Only consume 1 token per spirit LK.setScore(LK.getScore() + 5); // Award 5 points per spirit freed scoreTxt.setText('Score: ' + LK.getScore()); tokenTxt.setText('Tokens: ' + player.tokens); LK.getSound('deliver').play(); // Remove one shadow spirit when blue spirit is freed if (shadowSpirits.length > 0) { var shadowToRemove = shadowSpirits[0]; shadowToRemove.destroy(); shadowSpirits.splice(0, 1); } spirit.destroy(); blueSpirits.splice(j, 1); } if (spirit.isDark && spirit.y > 2932) { spirit.destroy(); blueSpirits.splice(j, 1); } } // Check shadow spirit collisions for (var k = shadowSpirits.length - 1; k >= 0; k--) { var shadow = shadowSpirits[k]; if (shadow.lastIntersecting === undefined) { shadow.lastIntersecting = false; } var currentIntersecting = player.intersects(shadow); if (!shadow.lastIntersecting && currentIntersecting) { LK.getSound('damage').play(); var gameOver = player.takeDamage(); healthBar.updateHealth(player.health); if (gameOver) { LK.showGameOver(); } shadow.destroy(); shadowSpirits.splice(k, 1); continue; } shadow.lastIntersecting = currentIntersecting; } // Check dark spirit collisions for (var d = darkSpirits.length - 1; d >= 0; d--) { var darkSpirit = darkSpirits[d]; if (darkSpirit.lastIntersecting === undefined) { darkSpirit.lastIntersecting = false; } var currentDarkIntersecting = player.intersects(darkSpirit); if (!darkSpirit.lastIntersecting && currentDarkIntersecting) { LK.getSound('damage').play(); var gameOver = player.takeDamage(); healthBar.updateHealth(player.health); if (gameOver) { LK.showGameOver(); } darkSpirit.destroy(); darkSpirits.splice(d, 1); continue; } darkSpirit.lastIntersecting = currentDarkIntersecting; } // Check polluted spirit cleansing for (var l = pollutedSpirits.length - 1; l >= 0; l--) { var polluted = pollutedSpirits[l]; if (!polluted.isCleansed && player.intersects(polluted) && player.tokens >= polluted.tokensNeeded) { player.tokens -= polluted.tokensNeeded; tokenTxt.setText('Tokens: ' + player.tokens); LK.setScore(LK.getScore() + 15); scoreTxt.setText('Score: ' + LK.getScore()); LK.getSound('cleanse').play(); // Remove one darkspirit when polluted spirit is cleansed if (darkSpirits.length > 0) { var darkToRemove = darkSpirits[0]; darkToRemove.destroy(); darkSpirits.splice(0, 1); } // Show and animate brush if (brushSprite) { brushSprite.visible = true; brushSprite.x = polluted.x; brushSprite.y = polluted.y; // Stop any existing brush animations tween.stop(brushSprite); // Animate brush left and right to simulate brushing tween(brushSprite, { x: polluted.x - 30 }, { duration: 200, easing: tween.easeInOut, onFinish: function onFinish() { tween(brushSprite, { x: polluted.x + 30 }, { duration: 200, easing: tween.easeInOut, onFinish: function onFinish() { tween(brushSprite, { x: polluted.x - 20 }, { duration: 150, easing: tween.easeInOut, onFinish: function onFinish() { tween(brushSprite, { x: polluted.x + 20 }, { duration: 150, easing: tween.easeInOut, onFinish: function onFinish() { tween(brushSprite, { x: polluted.x }, { duration: 100, easing: tween.easeInOut, onFinish: function onFinish() { brushSprite.visible = false; } }); } }); } }); } }); } }); } // Free up the shower area if (polluted.assignedShowerArea) { polluted.assignedShowerArea.occupied = false; } polluted.cleanse(); pollutedSpirits.splice(l, 1); } } // Check river spirit collection if (riverSpirit) { if (riverSpirit.lastIntersecting === undefined) { riverSpirit.lastIntersecting = false; } var riverIntersecting = player.intersects(riverSpirit); if (!riverSpirit.lastIntersecting && riverIntersecting) { LK.setScore(LK.getScore() + riverSpirit.bonusValue); scoreTxt.setText('Score: ' + LK.getScore()); // Regenerate health by 30% player.health += player.maxHealth * 0.3; player.health = Math.min(player.health, player.maxHealth); // Cap at max health healthBar.updateHealth(player.health); LK.effects.flashObject(player, 0x87ceeb, 1000); // Flash blue to indicate healing riverSpirit.destroy(); riverSpirit = null; } else if (riverSpirit && riverSpirit.x > 2200) { riverSpirit.destroy(); riverSpirit = null; } if (riverSpirit) { riverSpirit.lastIntersecting = riverIntersecting; } } // Handle movement animation when dragging if (dragActive && player) { movementAnimationTimer++; if (movementAnimationTimer >= movementAnimationInterval) { // Switch between movement sprites if (currentMovementSprite === 'player') { currentMovementSprite = 'playermovement1'; } else if (currentMovementSprite === 'playermovement1') { currentMovementSprite = 'playermovement2'; } else { currentMovementSprite = 'playermovement1'; } // Update player sprite player.removeChildren(); var newPlayerGraphics = player.attachAsset(currentMovementSprite, { anchorX: 0.5, anchorY: 0.5 }); movementAnimationTimer = 0; } } else if (!dragActive && currentMovementSprite !== 'player') { // Reset to normal player sprite when not dragging currentMovementSprite = 'player'; player.removeChildren(); var normalPlayerGraphics = player.attachAsset('player', { anchorX: 0.5, anchorY: 0.5 }); } // Player direction based on position var screenMiddle = 1024; if (player.x < screenMiddle) { // Player is on left side, face left (flip horizontally) player.scaleX = -1; } else { // Player is on right side, face right (normal orientation) player.scaleX = 1; } // Level progression if (currentLevel === 'level1' && LK.getScore() >= 250) { startLevel2(); } // Win condition if (currentLevel === 'level2' && LK.getScore() >= 500) { LK.showYouWin(); } }; // Show intro screen initially showIntroScreen();
/****
* Plugins
****/
var tween = LK.import("@upit/tween.v1");
/****
* Classes
****/
var BlueSpirit = Container.expand(function () {
var self = Container.call(this);
var spiritGraphics = self.attachAsset('blueSpirit', {
anchorX: 0.5,
anchorY: 0.5
});
self.waitTime = 0;
self.maxWaitTime = 600; // 10 seconds at 60fps
self.isDark = false;
self.speed = 1;
self.update = function () {
self.waitTime++;
if (!self.isDark && self.waitTime >= self.maxWaitTime) {
self.turnDark();
}
if (self.isDark) {
self.y += self.speed;
}
};
self.turnDark = function () {
self.isDark = true;
spiritGraphics.tint = 0x2a0845;
tween(spiritGraphics, {
scaleX: 1.2,
scaleY: 1.2
}, {
duration: 500
});
};
return self;
});
var DarkSpirit = Container.expand(function () {
var self = Container.call(this);
var darkGraphics = self.attachAsset('darkSpirit', {
anchorX: 0.5,
anchorY: 0.5
});
self.speed = 1.5;
self.targetPlayer = null;
self.update = function () {
if (self.targetPlayer) {
var dx = self.targetPlayer.x - self.x;
var dy = self.targetPlayer.y - self.y;
var distance = Math.sqrt(dx * dx + dy * dy);
if (distance > 5) {
self.x += dx / distance * self.speed;
self.y += dy / distance * self.speed;
}
// Change direction based on position relative to screen middle
var screenMiddle = 1024;
if (self.x < screenMiddle) {
// Dark spirit is on left side, face right towards middle
self.scaleX = 1;
} else {
// Dark spirit is on right side, face left towards middle
self.scaleX = -1;
}
}
};
return self;
});
var HealthBar = Container.expand(function () {
var self = Container.call(this);
// Background bar
self.bgBar = self.attachAsset('healthBarBg', {
anchorX: 0,
anchorY: 0.5
});
// Health bar
self.healthBar = self.attachAsset('healthBarFill', {
anchorX: 0,
anchorY: 0.5
});
self.maxWidth = 300;
self.updateHealth = function (healthPercent) {
self.healthBar.scaleX = healthPercent / 100;
};
return self;
});
var Player = Container.expand(function () {
var self = Container.call(this);
var playerGraphics = self.attachAsset('player', {
anchorX: 0.5,
anchorY: 0.5
});
self.tokens = 0;
self.health = 100;
self.maxHealth = 100;
self.collectToken = function () {
self.tokens++;
};
self.deliverTokens = function () {
var delivered = self.tokens;
self.tokens = 0;
return delivered;
};
self.takeDamage = function () {
var damage = Math.random() * 7 + 3; // Random between 3-10
self.health -= damage;
self.health = Math.max(0, self.health); // Ensure health doesn't go below 0
LK.effects.flashObject(self, 0xff0000, 500);
return self.health <= 0;
};
return self;
});
var PollutedSpirit = Container.expand(function () {
var self = Container.call(this);
var pollutedGraphics = self.attachAsset('pollutedspirit1', {
anchorX: 0.5,
anchorY: 0.5
});
self.tokensNeeded = 3;
self.isCleansed = false;
self.cleanse = function () {
self.isCleansed = true;
tween(pollutedGraphics, {
tint: 0x98fb98
}, {
duration: 1000,
onFinish: function onFinish() {
self.destroy();
}
});
};
return self;
});
var PollutedSpirit2 = Container.expand(function () {
var self = Container.call(this);
var pollutedGraphics = self.attachAsset('pollutedspirit2', {
anchorX: 0.5,
anchorY: 0.5
});
self.tokensNeeded = 3;
self.isCleansed = false;
self.cleanse = function () {
self.isCleansed = true;
tween(pollutedGraphics, {
tint: 0x98fb98
}, {
duration: 1000,
onFinish: function onFinish() {
self.destroy();
}
});
};
return self;
});
var RiverSpirit = Container.expand(function () {
var self = Container.call(this);
var riverGraphics = self.attachAsset('riverSpirit', {
anchorX: 0.5,
anchorY: 0.5
});
self.bonusValue = 20;
self.speed = 0.5;
self.update = function () {
self.x += self.speed;
self.rotation += 0.01;
};
return self;
});
var ShadowSpirit = Container.expand(function () {
var self = Container.call(this);
var shadowGraphics = self.attachAsset('shadowSpirit', {
anchorX: 0.5,
anchorY: 0.5
});
self.speed = 2;
self.targetPlayer = null;
self.update = function () {
if (self.targetPlayer) {
var dx = self.targetPlayer.x - self.x;
var dy = self.targetPlayer.y - self.y;
var distance = Math.sqrt(dx * dx + dy * dy);
if (distance > 5) {
self.x += dx / distance * self.speed;
self.y += dy / distance * self.speed;
}
// Change direction based on position relative to screen middle
var screenMiddle = 1024;
if (self.x < screenMiddle) {
// Shadow is on left side, face right towards middle
self.scaleX = 1;
} else {
// Shadow is on right side, face left towards middle
self.scaleX = -1;
}
}
};
return self;
});
var Token = Container.expand(function () {
var self = Container.call(this);
var tokenGraphics = self.attachAsset('token', {
anchorX: 0.5,
anchorY: 0.5
});
self.collected = false;
self.update = function () {
if (!self.collected) {
self.rotation += 0.02;
}
};
return self;
});
/****
* Initialize Game
****/
var game = new LK.Game({
backgroundColor: 0x1a1a2e
});
/****
* Game Code
****/
var gameStarted = false;
var introBackground = null;
var startButton = null;
var currentLevel = 'level1';
var gameBackground = null;
// Declare game variables in global scope
var player, tokens, blueSpirits, shadowSpirits, pollutedSpirits, riverSpirit, darkSpirits;
var spawnTimer, spawnInterval, shadowSpawnTimer, shadowSpawnInterval;
var scoreTxt, tokenTxt, healthBar;
var brushSprite = null;
var showerAreas = [],
pollutedSpawnTimer,
pollutedSpawnInterval;
var maxShadowSpirits = 2; // Level 1: 2, Level 2: 4
var shadowRespawnTimer = 0;
var shadowRespawnInterval = 180; // 3 seconds to respawn
var lastMovementSoundTime = 0;
var movementSoundCooldown = 1000; // Milliseconds between sound plays
// Show intro screen
function showIntroScreen() {
introBackground = game.addChild(LK.getAsset('introbackground', {
anchorX: 0,
anchorY: 0,
x: 0,
y: 0
}));
startButton = game.addChild(LK.getAsset('startbutton', {
anchorX: 0.5,
anchorY: 0.5,
x: 1024,
y: 2400
}));
// Only play intro music if game hasn't started and we're actually showing intro screen
if (!gameStarted && introBackground && startButton) {
LK.playMusic('intromusic');
}
}
// Start the actual game
function startGame() {
gameStarted = true;
if (introBackground) {
introBackground.destroy();
introBackground = null;
}
if (startButton) {
startButton.destroy();
startButton = null;
}
LK.stopMusic();
LK.playMusic('bathhouse');
initializeGame();
}
// Spawn functions in global scope
function spawnToken() {
var token = new Token();
token.x = Math.random() * 1848 + 100;
token.y = Math.random() * 2332 + 300;
tokens.push(token);
game.addChild(token);
}
function spawnSpirit() {
var spirit = new BlueSpirit();
spirit.x = Math.random() * 1848 + 100;
spirit.y = 300;
blueSpirits.push(spirit);
game.addChild(spirit);
}
function spawnShadowSpirit() {
// Only spawn if under the limit
if (shadowSpirits.length < maxShadowSpirits) {
var shadow = new ShadowSpirit();
shadow.x = Math.random() * 1848 + 100;
shadow.y = Math.random() * 400 + 300;
shadow.targetPlayer = player;
shadowSpirits.push(shadow);
game.addChild(shadow);
}
}
function spawnPollutedSpirit() {
// Find an empty shower area
var emptyAreas = [];
for (var i = 0; i < showerAreas.length; i++) {
if (!showerAreas[i].occupied) {
emptyAreas.push(showerAreas[i]);
}
}
// Spawn one darkspirit per shower area that doesn't already have one
for (var a = 0; a < showerAreas.length; a++) {
var hasExistingDark = false;
for (var d = 0; d < darkSpirits.length; d++) {
if (Math.abs(darkSpirits[d].x - showerAreas[a].x) < 100 && Math.abs(darkSpirits[d].y - showerAreas[a].y) < 100) {
hasExistingDark = true;
break;
}
}
if (!hasExistingDark) {
var darkSpirit = new DarkSpirit();
darkSpirit.x = showerAreas[a].x + 50;
darkSpirit.y = showerAreas[a].y + 30;
darkSpirit.targetPlayer = player;
darkSpirits.push(darkSpirit);
game.addChild(darkSpirit);
}
}
// Only spawn if there's an empty area
if (emptyAreas.length > 0) {
if (currentLevel === 'level2') {
// Level 2: Spawn both types if we have at least 2 empty areas
if (emptyAreas.length >= 2) {
// Spawn PollutedSpirit (pollutedspirit1)
var selectedArea1 = emptyAreas[Math.floor(Math.random() * emptyAreas.length)];
var polluted1 = new PollutedSpirit();
polluted1.x = selectedArea1.x;
polluted1.y = selectedArea1.y;
polluted1.assignedShowerArea = selectedArea1;
selectedArea1.occupied = true;
pollutedSpirits.push(polluted1);
game.addChild(polluted1);
// Spawn ShadowSpirit behind polluted1
var shadow1 = new ShadowSpirit();
shadow1.x = polluted1.x - 50;
shadow1.y = polluted1.y + 30;
shadow1.targetPlayer = player;
shadowSpirits.push(shadow1);
game.addChild(shadow1);
// Remove the used area from available areas
emptyAreas.splice(emptyAreas.indexOf(selectedArea1), 1);
// Spawn PollutedSpirit2 (pollutedspirit2)
var selectedArea2 = emptyAreas[Math.floor(Math.random() * emptyAreas.length)];
var polluted2 = new PollutedSpirit2();
polluted2.x = selectedArea2.x;
polluted2.y = selectedArea2.y;
polluted2.assignedShowerArea = selectedArea2;
selectedArea2.occupied = true;
pollutedSpirits.push(polluted2);
game.addChild(polluted2);
} else {
// Only one empty area, spawn randomly either type
var selectedArea = emptyAreas[0];
var polluted = Math.random() < 0.5 ? new PollutedSpirit() : new PollutedSpirit2();
polluted.x = selectedArea.x;
polluted.y = selectedArea.y;
polluted.assignedShowerArea = selectedArea;
selectedArea.occupied = true;
pollutedSpirits.push(polluted);
game.addChild(polluted);
// Spawn appropriate spirit behind the polluted spirit
if (polluted instanceof PollutedSpirit) {
var shadow = new ShadowSpirit();
shadow.x = polluted.x - 50;
shadow.y = polluted.y + 30;
shadow.targetPlayer = player;
shadowSpirits.push(shadow);
game.addChild(shadow);
}
}
} else {
// Level 1: Spawn only PollutedSpirit (pollutedspirit1)
var selectedArea = emptyAreas[Math.floor(Math.random() * emptyAreas.length)];
var polluted = new PollutedSpirit();
polluted.x = selectedArea.x;
polluted.y = selectedArea.y;
polluted.assignedShowerArea = selectedArea;
selectedArea.occupied = true;
pollutedSpirits.push(polluted);
game.addChild(polluted);
// Spawn ShadowSpirit behind polluted spirit in level1
var shadow = new ShadowSpirit();
shadow.x = polluted.x - 50;
shadow.y = polluted.y + 30;
shadow.targetPlayer = player;
shadowSpirits.push(shadow);
game.addChild(shadow);
}
// Move brush sprite to render on top of polluted spirits
if (brushSprite) {
game.removeChild(brushSprite);
game.addChild(brushSprite);
}
// Ensure player renders on top of polluted spirits
if (player) {
game.removeChild(player);
game.addChild(player);
}
}
}
function spawnRiverSpirit() {
if (!riverSpirit) {
riverSpirit = new RiverSpirit();
riverSpirit.x = -100;
riverSpirit.y = Math.random() * 1000 + 1066;
game.addChild(riverSpirit);
}
}
function startLevel2() {
currentLevel = 'level2';
// Remove current background
if (gameBackground) {
gameBackground.destroy();
gameBackground = null;
}
// Clear all existing enemies from level1
for (var i = blueSpirits.length - 1; i >= 0; i--) {
blueSpirits[i].destroy();
}
blueSpirits = [];
for (var j = shadowSpirits.length - 1; j >= 0; j--) {
shadowSpirits[j].destroy();
}
shadowSpirits = [];
for (var d = darkSpirits.length - 1; d >= 0; d--) {
darkSpirits[d].destroy();
}
darkSpirits = [];
for (var k = pollutedSpirits.length - 1; k >= 0; k--) {
if (pollutedSpirits[k].assignedShowerArea) {
pollutedSpirits[k].assignedShowerArea.occupied = false;
}
pollutedSpirits[k].destroy();
}
pollutedSpirits = [];
if (riverSpirit) {
riverSpirit.destroy();
riverSpirit = null;
}
// Remove existing shower areas
for (var i = 0; i < showerAreas.length; i++) {
showerAreas[i].destroy();
}
showerAreas = [];
// Add level2 background
gameBackground = game.addChild(LK.getAsset('background02', {
anchorX: 0,
anchorY: 0,
x: 0,
y: 0,
visible: true
}));
// Add 4 shower areas for level2 in 2x2 grid
var screenMiddle = 1024;
var spacing = 500; // 500px spacing between shower areas
var positions = [{
x: screenMiddle - spacing / 2,
y: 1366 - spacing / 2
}, {
x: screenMiddle + spacing / 2,
y: 1366 - spacing / 2
}, {
x: screenMiddle - spacing / 2,
y: 1366 + spacing / 2
}, {
x: screenMiddle + spacing / 2,
y: 1366 + spacing / 2
}];
for (var p = 0; p < positions.length; p++) {
var showerArea = game.addChild(LK.getAsset('Showerarea', {
anchorX: 0.5,
anchorY: 0.5,
x: positions[p].x,
y: positions[p].y
}));
showerArea.occupied = false;
showerAreas.push(showerArea);
}
// Move player to front to ensure it renders above the new background
game.removeChild(player);
game.addChild(player);
// Reset game state for new level
player.health = player.maxHealth;
healthBar.updateHealth(player.health);
spawnInterval = 120; // Make level2 slightly harder
shadowSpawnInterval = 240;
maxShadowSpirits = 4; // Increase limit for level2
}
function initializeGame() {
game.setBackgroundColor(0x16213e);
currentLevel = 'level1';
// Add level1 game background
gameBackground = game.addChild(LK.getAsset('gamebackground', {
anchorX: 0,
anchorY: 0,
x: 0,
y: 0
}));
player = game.addChild(new Player());
player.x = 1024;
player.y = 2200;
tokens = [];
blueSpirits = [];
shadowSpirits = [];
pollutedSpirits = [];
darkSpirits = [];
riverSpirit = null;
spawnTimer = 0;
spawnInterval = 180; // Level1 difficulty
shadowSpawnTimer = 0;
shadowSpawnInterval = 360; // Level1 difficulty
maxShadowSpirits = 2; // Level 1 limit
shadowRespawnTimer = 0;
scoreTxt = new Text2('Score: 0', {
size: 80,
fill: 0xFFFFFF
});
scoreTxt.anchor.set(0.5, 0);
LK.gui.top.addChild(scoreTxt);
tokenTxt = new Text2('Tokens: 0', {
size: 60,
fill: 0xFFD700
});
tokenTxt.anchor.set(1, 0);
tokenTxt.x = -20;
LK.gui.topRight.addChild(tokenTxt);
healthBar = new HealthBar();
healthBar.x = 20;
healthBar.y = 30;
LK.gui.topLeft.addChild(healthBar);
// Initial spawns
for (var i = 0; i < 5; i++) {
spawnToken();
}
spawnSpirit();
spawnPollutedSpirit();
// Initialize brush sprite (initially hidden)
brushSprite = LK.getAsset('brush', {
anchorX: 0.5,
anchorY: 0.5
});
brushSprite.visible = false;
game.addChild(brushSprite);
// Initialize shower area system
showerAreas = [];
pollutedSpawnTimer = 0;
pollutedSpawnInterval = 600; // 10 seconds at 60fps
// Add shower areas based on level
var screenMiddle = 1024;
var spacing = 200;
var showerAreaWidth = 300; // Based on asset width
if (currentLevel === 'level1') {
// Level 1: 2 shower areas
var leftShowerArea = game.addChild(LK.getAsset('Showerarea', {
anchorX: 0.5,
anchorY: 0.5,
x: screenMiddle - spacing / 2 - showerAreaWidth / 2,
y: 1366 // Middle of screen height
}));
leftShowerArea.occupied = false;
showerAreas.push(leftShowerArea);
var rightShowerArea = game.addChild(LK.getAsset('Showerarea', {
anchorX: 0.5,
anchorY: 0.5,
x: screenMiddle + spacing / 2 + showerAreaWidth / 2,
y: 1366 // Middle of screen height
}));
rightShowerArea.occupied = false;
showerAreas.push(rightShowerArea);
} else if (currentLevel === 'level2') {
// Level 2: 4 shower areas in 2x2 grid
var spacing = 500; // 500px spacing between shower areas
var positions = [{
x: screenMiddle - spacing / 2,
y: 1366 - spacing / 2
}, {
x: screenMiddle + spacing / 2,
y: 1366 - spacing / 2
}, {
x: screenMiddle - spacing / 2,
y: 1366 + spacing / 2
}, {
x: screenMiddle + spacing / 2,
y: 1366 + spacing / 2
}];
for (var p = 0; p < positions.length; p++) {
var showerArea = game.addChild(LK.getAsset('Showerarea', {
anchorX: 0.5,
anchorY: 0.5,
x: positions[p].x,
y: positions[p].y
}));
showerArea.occupied = false;
showerAreas.push(showerArea);
}
}
// Move player to front to ensure it renders above shower areas
game.removeChild(player);
game.addChild(player);
}
var dragActive = false;
var currentMovementSprite = 'player';
var movementAnimationTimer = 0;
var movementAnimationInterval = 15; // Switch every 15 frames (quarter second at 60fps)
game.down = function (x, y, obj) {
if (!gameStarted && startButton) {
// Check if click is within start button bounds
var buttonLeft = startButton.x - startButton.width * startButton.anchor.x;
var buttonRight = startButton.x + startButton.width * (1 - startButton.anchor.x);
var buttonTop = startButton.y - startButton.height * startButton.anchor.y;
var buttonBottom = startButton.y + startButton.height * (1 - startButton.anchor.y);
if (x >= buttonLeft && x <= buttonRight && y >= buttonTop && y <= buttonBottom) {
startGame();
return;
}
}
if (gameStarted) {
dragActive = true;
}
};
game.up = function (x, y, obj) {
if (gameStarted) {
dragActive = false;
}
};
game.move = function (x, y, obj) {
if (gameStarted && dragActive && player) {
player.x = x;
player.y = y;
// Throttle movement sound to prevent too frequent playback
var currentTime = Date.now();
if (currentTime - lastMovementSoundTime >= movementSoundCooldown) {
LK.getSound('playermovment').play();
lastMovementSoundTime = currentTime;
}
}
};
game.update = function () {
if (!gameStarted) {
return;
}
// Update spawn timers
spawnTimer++;
shadowSpawnTimer++;
if (spawnTimer >= spawnInterval) {
spawnSpirit();
spawnTimer = 0;
// Increase difficulty
if (spawnInterval > 60) {
spawnInterval -= 2;
}
}
if (shadowSpawnTimer >= shadowSpawnInterval) {
spawnShadowSpirit();
shadowSpawnTimer = 0;
}
// Shadow spirit respawn timer
shadowRespawnTimer++;
if (shadowRespawnTimer >= shadowRespawnInterval && shadowSpirits.length < maxShadowSpirits) {
spawnShadowSpirit();
shadowRespawnTimer = 0;
}
// Token spawning
if (LK.ticks % 120 === 0) {
spawnToken();
}
// Polluted spirit spawning every 10 seconds
pollutedSpawnTimer++;
if (pollutedSpawnTimer >= pollutedSpawnInterval) {
spawnPollutedSpirit();
pollutedSpawnTimer = 0;
}
// River spirit spawning
if (LK.getScore() > 0 && LK.getScore() % 50 === 0 && !riverSpirit) {
spawnRiverSpirit();
}
// Check token collection
for (var i = tokens.length - 1; i >= 0; i--) {
var token = tokens[i];
if (!token.collected && player.intersects(token)) {
token.collected = true;
player.collectToken();
tokenTxt.setText('Tokens: ' + player.tokens);
LK.getSound('collect').play();
token.destroy();
tokens.splice(i, 1);
}
}
// Check spirit interactions
for (var j = blueSpirits.length - 1; j >= 0; j--) {
var spirit = blueSpirits[j];
if (!spirit.isDark && player.intersects(spirit) && player.tokens > 0) {
player.tokens -= 1; // Only consume 1 token per spirit
LK.setScore(LK.getScore() + 5); // Award 5 points per spirit freed
scoreTxt.setText('Score: ' + LK.getScore());
tokenTxt.setText('Tokens: ' + player.tokens);
LK.getSound('deliver').play();
// Remove one shadow spirit when blue spirit is freed
if (shadowSpirits.length > 0) {
var shadowToRemove = shadowSpirits[0];
shadowToRemove.destroy();
shadowSpirits.splice(0, 1);
}
spirit.destroy();
blueSpirits.splice(j, 1);
}
if (spirit.isDark && spirit.y > 2932) {
spirit.destroy();
blueSpirits.splice(j, 1);
}
}
// Check shadow spirit collisions
for (var k = shadowSpirits.length - 1; k >= 0; k--) {
var shadow = shadowSpirits[k];
if (shadow.lastIntersecting === undefined) {
shadow.lastIntersecting = false;
}
var currentIntersecting = player.intersects(shadow);
if (!shadow.lastIntersecting && currentIntersecting) {
LK.getSound('damage').play();
var gameOver = player.takeDamage();
healthBar.updateHealth(player.health);
if (gameOver) {
LK.showGameOver();
}
shadow.destroy();
shadowSpirits.splice(k, 1);
continue;
}
shadow.lastIntersecting = currentIntersecting;
}
// Check dark spirit collisions
for (var d = darkSpirits.length - 1; d >= 0; d--) {
var darkSpirit = darkSpirits[d];
if (darkSpirit.lastIntersecting === undefined) {
darkSpirit.lastIntersecting = false;
}
var currentDarkIntersecting = player.intersects(darkSpirit);
if (!darkSpirit.lastIntersecting && currentDarkIntersecting) {
LK.getSound('damage').play();
var gameOver = player.takeDamage();
healthBar.updateHealth(player.health);
if (gameOver) {
LK.showGameOver();
}
darkSpirit.destroy();
darkSpirits.splice(d, 1);
continue;
}
darkSpirit.lastIntersecting = currentDarkIntersecting;
}
// Check polluted spirit cleansing
for (var l = pollutedSpirits.length - 1; l >= 0; l--) {
var polluted = pollutedSpirits[l];
if (!polluted.isCleansed && player.intersects(polluted) && player.tokens >= polluted.tokensNeeded) {
player.tokens -= polluted.tokensNeeded;
tokenTxt.setText('Tokens: ' + player.tokens);
LK.setScore(LK.getScore() + 15);
scoreTxt.setText('Score: ' + LK.getScore());
LK.getSound('cleanse').play();
// Remove one darkspirit when polluted spirit is cleansed
if (darkSpirits.length > 0) {
var darkToRemove = darkSpirits[0];
darkToRemove.destroy();
darkSpirits.splice(0, 1);
}
// Show and animate brush
if (brushSprite) {
brushSprite.visible = true;
brushSprite.x = polluted.x;
brushSprite.y = polluted.y;
// Stop any existing brush animations
tween.stop(brushSprite);
// Animate brush left and right to simulate brushing
tween(brushSprite, {
x: polluted.x - 30
}, {
duration: 200,
easing: tween.easeInOut,
onFinish: function onFinish() {
tween(brushSprite, {
x: polluted.x + 30
}, {
duration: 200,
easing: tween.easeInOut,
onFinish: function onFinish() {
tween(brushSprite, {
x: polluted.x - 20
}, {
duration: 150,
easing: tween.easeInOut,
onFinish: function onFinish() {
tween(brushSprite, {
x: polluted.x + 20
}, {
duration: 150,
easing: tween.easeInOut,
onFinish: function onFinish() {
tween(brushSprite, {
x: polluted.x
}, {
duration: 100,
easing: tween.easeInOut,
onFinish: function onFinish() {
brushSprite.visible = false;
}
});
}
});
}
});
}
});
}
});
}
// Free up the shower area
if (polluted.assignedShowerArea) {
polluted.assignedShowerArea.occupied = false;
}
polluted.cleanse();
pollutedSpirits.splice(l, 1);
}
}
// Check river spirit collection
if (riverSpirit) {
if (riverSpirit.lastIntersecting === undefined) {
riverSpirit.lastIntersecting = false;
}
var riverIntersecting = player.intersects(riverSpirit);
if (!riverSpirit.lastIntersecting && riverIntersecting) {
LK.setScore(LK.getScore() + riverSpirit.bonusValue);
scoreTxt.setText('Score: ' + LK.getScore());
// Regenerate health by 30%
player.health += player.maxHealth * 0.3;
player.health = Math.min(player.health, player.maxHealth); // Cap at max health
healthBar.updateHealth(player.health);
LK.effects.flashObject(player, 0x87ceeb, 1000); // Flash blue to indicate healing
riverSpirit.destroy();
riverSpirit = null;
} else if (riverSpirit && riverSpirit.x > 2200) {
riverSpirit.destroy();
riverSpirit = null;
}
if (riverSpirit) {
riverSpirit.lastIntersecting = riverIntersecting;
}
}
// Handle movement animation when dragging
if (dragActive && player) {
movementAnimationTimer++;
if (movementAnimationTimer >= movementAnimationInterval) {
// Switch between movement sprites
if (currentMovementSprite === 'player') {
currentMovementSprite = 'playermovement1';
} else if (currentMovementSprite === 'playermovement1') {
currentMovementSprite = 'playermovement2';
} else {
currentMovementSprite = 'playermovement1';
}
// Update player sprite
player.removeChildren();
var newPlayerGraphics = player.attachAsset(currentMovementSprite, {
anchorX: 0.5,
anchorY: 0.5
});
movementAnimationTimer = 0;
}
} else if (!dragActive && currentMovementSprite !== 'player') {
// Reset to normal player sprite when not dragging
currentMovementSprite = 'player';
player.removeChildren();
var normalPlayerGraphics = player.attachAsset('player', {
anchorX: 0.5,
anchorY: 0.5
});
}
// Player direction based on position
var screenMiddle = 1024;
if (player.x < screenMiddle) {
// Player is on left side, face left (flip horizontally)
player.scaleX = -1;
} else {
// Player is on right side, face right (normal orientation)
player.scaleX = 1;
}
// Level progression
if (currentLevel === 'level1' && LK.getScore() >= 250) {
startLevel2();
}
// Win condition
if (currentLevel === 'level2' && LK.getScore() >= 500) {
LK.showYouWin();
}
};
// Show intro screen initially
showIntroScreen();