/**** * Plugins ****/ var tween = LK.import("@upit/tween.v1"); /**** * Classes ****/ var AlienHealthBar = Container.expand(function (initialHealth, maxHealth) { var self = Container.call(this); self.currentHealth = initialHealth; self.maxHealth = maxHealth; // Define frame dimensions if dynamic retrieval isn't available var frameWidth = LK.getAsset('LK_Health_Bar', {}).width; // Create filler (health bar inner part) var filler = self.attachAsset('LK_Inner_Health_Bar', { anchorX: 0, anchorY: 0.5, x: -frameWidth / 2, y: 0, scaleX: 1 // Fully filled initially }); // Create frame (health bar outer part) var frame = self.attachAsset('LK_Health_Bar', { anchorX: 0.5, anchorY: 0.5, x: 0, y: 0 }); // Update the visual representation of the health bar self.updateHealth = function () { filler.scaleX = Math.max(0, self.currentHealth / self.maxHealth); }; // Change health value self.setHealth = function (newHealth) { self.currentHealth = Math.max(0, Math.min(newHealth, self.maxHealth)); self.updateHealth(); if (self.currentHealth === 0 && typeof self.onDeath === 'function') { self.onDeath(); } }; // Change maximum health and adjust health proportionally self.setMaxHealth = function (newMaxHealth) { var healthRatio = self.currentHealth / self.maxHealth; self.maxHealth = Math.max(1, newMaxHealth); self.currentHealth = Math.min(self.currentHealth, self.maxHealth); self.updateHealth(); }; // Initialize the health bar self.setHealth(initialHealth); return self; }); // Blood Splash Class var BloodSplash = Container.expand(function (x, y, isFinal) { var self = Container.call(this); var bloodGraphics = self.attachAsset('Blood_Splash_1', { anchorX: 0.5, anchorY: 0.5, alpha: 0, rotation: Math.random() * Math.PI * 2, scaleX: 0, scaleY: 0 }); self.x = x; self.y = y; var growSpeed = isFinal ? 0.1 : 0.05; self.update = function () { bloodGraphics.alpha += 0.05; bloodGraphics.scaleX += growSpeed; bloodGraphics.scaleY += growSpeed; if (bloodGraphics && bloodGraphics.alpha >= 1) { game.removeChild(self); } }; return self; }); var Bone = Container.expand(function (startX, startY, targetX, targetY) { var self = Container.call(this); var boneType = Math.random() < 0.8 ? 'bone_1' : 'Bone_2'; // 80% chance for bone_1, 20% for Bone_2 var boneGraphics = self.attachAsset(boneType, { anchorX: 0.5, anchorY: 0.5, scaleX: boneType === 'bone_1' ? 0.7 : 1.0, scaleY: boneType === 'bone_1' ? 0.7 : 1.0 }); self.x = startX; self.y = startY; var speed = 15; var dx = targetX - startX; var dy = targetY - startY; var distance = Math.sqrt(dx * dx + dy * dy); var velocityX = dx / distance * speed; var velocityY = dy / distance * speed; var spinSpeed = 0.2; // Initial spin speed // Emit stars effect function emitStars() { var star = new Container(); // Create a new star container var starGraphics = star.attachAsset('Stars', { scaleX: 0.2, scaleY: 0.2, tint: 0xFF0000 // Red tint for stars }); star.x = self.x; star.y = self.y; game.addChild(star); // Star fade and removal var starFadeInterval = LK.setInterval(function () { starGraphics.alpha -= 0.1; if (starGraphics.alpha <= 0) { LK.clearInterval(starFadeInterval); game.removeChild(star); } }, 100); } self.update = function () { // Start a timer to fade out the bone after 6 seconds if (!self.fadeOutTimer) { self.fadeOutTimer = LK.setTimeout(function () { tween(boneGraphics, { alpha: 0 }, { duration: 2000, onFinish: function onFinish() { game.removeChild(self); bones.splice(bones.indexOf(self), 1); // Remove bone from the array } }); }, 6000); } self.x += velocityX; self.y += velocityY - 0.5; // Arching effect velocityX *= 0.99; // Slightly decrease speed over time velocityY *= 0.99; boneGraphics.rotation += spinSpeed; spinSpeed *= 0.98; // Decrease spin speed over time // Emit stars periodically if (Math.random() < 0.2) { emitStars(); } // Check for collision with the boss if (boss && !self.lastIntersecting && self.intersects(boss) && boss.alienHealthBar) { boss.alienHealthBar.setHealth(boss.alienHealthBar.currentHealth - 1); if (boss) { // Check if boss is still valid boss.alienHealthBar.updateHealth(); // Explicitly update the health bar visual getRandomSound(['Boss_Hit', 'Boss_Hit_2', 'Boss_Hit_3']).play(); flashGreyMask([boss.bossGraphics, boss.radiusGraphics, boss.alienHealthBar], 400, 3); // Add flashing effect } game.removeChild(self); bones.splice(bones.indexOf(self), 1); } // Update last intersecting state self.lastIntersecting = self.intersects(boss); // Remove bone if it leaves the viewport if (!self.isInViewport()) { game.removeChild(self); } }; // Check if the bone is within the viewport self.isInViewport = function () { return self.x >= -50 && self.x <= 2048 + 50 && self.y >= -50 && self.y <= 2432 + 50; }; // Check if the bone intersects with another object (e.g., the boss) self.intersects = function (target) { if (target) { var dx = self.x - target.x; var dy = self.y - target.y; var distance = Math.sqrt(dx * dx + dy * dy); return distance < 70; // Increased radius for larger hitbox } return false; }; return self; }); var Booster = Container.expand(function (type) { var self = Container.call(this); // Define boosters with adjusted colors and rarity levels var colors = [{ color: 0x30a330, // Adjusted green effect: 'increaseHealth', text: '+1 Health', rarity: 0.25 // Relatively common }, { color: 0xd93838, // Adjusted red effect: 'increaseHarvestSpeed', text: '+10% Harvest Speed', rarity: 0.5 // Relatively common }, { color: 0x2f53b4, // Adjusted blue effect: 'increaseMaxCargo', text: '+5 Max Cargo', rarity: 0.15 // Neutral rarity }, { color: 0xe9d735, // Adjusted yellow effect: 'increaseMovementSpeed', text: '+10% Movement Speed', rarity: 0.15 // Neutral rarity }, { color: 0xb733b7, // Adjusted purple effect: 'increaseProductionSpeed', text: '+10% Production Speed', rarity: 0.15 // Neutral rarity }, { color: 0x676767, // Adjusted grey effect: 'fillCargo', text: 'Cargo Filled!', rarity: 0.05 // Extremely rare }]; // Weighted random selection based on rarity function selectBooster() { var totalWeight = colors.reduce(function (sum, booster) { return sum + booster.rarity; }, 0); var randomWeight = Math.random() * totalWeight; var cumulativeWeight = 0; for (var i = 0; i < colors.length; i++) { cumulativeWeight += colors[i].rarity; if (randomWeight <= cumulativeWeight) { return colors[i]; } } } var selected = selectBooster(); // Sparkle effect container var sparkleContainer = new Container(); self.addChild(sparkleContainer); // Add sparkles first // Attach booster graphics var boosterGraphics = self.attachAsset('Booster', { anchorX: 0.5, anchorY: 0.5, tint: selected.color, scaleX: 0.75 * 1.15, scaleY: 0.75 * 1.15 }); // Start position (bottom-middle of the screen) self.x = 2048 / 2; self.y = 2432 - 200; // Target position (random on the screen with boundaries) var margin = 150; var targetX = margin + Math.random() * (2048 - 2 * margin); var targetY = margin + Math.random() * (2432 - 300 - 2 * margin); // Rotation and sparkle effects var rotationSpeed = 0.01; function emitSparkles() { var angle = Math.random() * Math.PI * 2; var distance = boosterGraphics.width / 2 + 10; if (Math.random() < 0.5) { // Reduce sparkles by half var sparkle = sparkleContainer.attachAsset('Stars', { anchorX: 0.5, anchorY: 0.5, scaleX: Math.random() * 1 + 0.15, scaleY: Math.random() * 1 + 0.15, alpha: 0.8, tint: 0x808080, x: Math.cos(angle) * distance, y: Math.sin(angle) * distance }); var lifetime = Math.random() * 400 + 200; var elapsed = 0; var interval = LK.setInterval(function () { elapsed += 16; sparkle.y -= 0.5; sparkle.alpha = Math.max(0, 1 - elapsed / lifetime); if (elapsed >= lifetime) { LK.clearInterval(interval); sparkleContainer.removeChild(sparkle); } }, 16); } } // Propulsion animation var elapsedTime = 0; var duration = 1000; LK.getSound('woosh').play(); self.update = function () { elapsedTime += 16; var t = Math.min(1, elapsedTime / duration); self.x = (1 - t) * (2048 / 2) + t * targetX; self.y = (1 - t) * (2432 - 200) + t * targetY - 100 * Math.sin(t * Math.PI); if (t >= 1) { LK.getSound('can').play(); self.update = function () { boosterGraphics.rotation += rotationSpeed; emitSparkles(); }; } }; // Handle pickup and apply effect self.pickUp = function () { LK.getSound('Booster_Sound').play(); // Floating text with canvas var canvas = self.attachAsset('Booster_Text_Canvas', { anchorX: 0.5, anchorY: 0.5, scaleX: 1.5, scaleY: 1, alpha: 1 }); var floatingText = new Text2(selected.text, { size: 80, fill: 0xFFFFFF, align: 'center' }); floatingText.anchor.set(0.5, 0.5); var textYOffset = 150; canvas.x = 2048 / 2; canvas.y = 2732 / 2; floatingText.x = canvas.x; floatingText.y = canvas.y; game.addChild(canvas); game.addChild(floatingText); var elapsed = 0; var textDuration = 1000; var fadeInterval = LK.setInterval(function () { elapsed += 16; canvas.y -= 1.5; floatingText.y -= 1.5; canvas.alpha = Math.max(0, 1 - elapsed / textDuration); floatingText.alpha = Math.max(0, 1 - elapsed / textDuration); if (elapsed >= textDuration) { LK.clearInterval(fadeInterval); game.removeChild(canvas); game.removeChild(floatingText); } }, 16); // Apply effect based on booster type switch (selected.effect) { case 'increaseHealth': if (globalHealthBar.currentHealth < globalHealthBar.maxHealth) { globalHealthBar.setHealth(globalHealthBar.currentHealth + 1); } break; case 'increaseHarvestSpeed': mishnu.harvestSpeed *= 1.1; break; case 'increaseMaxCargo': mishnu.cargoMax = Math.round(mishnu.cargoMax + 5); mishnu.initialCargoMax = mishnu.cargoMax; // Ensure cargoMax is persistent break; case 'increaseMovementSpeed': mishnu.speed *= 1.1; break; case 'increaseProductionSpeed': factory.processInterval = Math.max(1000, factory.processInterval * 0.9); break; case 'fillCargo': mishnu.humansHarvested = mishnu.cargoMax; break; default: console.error('Unknown booster effect:', selected.effect); } // Quick removal effect for booster var fadeOutInterval = LK.setInterval(function () { boosterGraphics.alpha -= 0.1; if (boosterGraphics.alpha <= 0) { LK.clearInterval(fadeOutInterval); game.removeChild(self); } }, 16); }; return self; }); // Boss Class var Boss = Container.expand(function () { var self = Container.call(this); // Boss attributes var bossGraphics = self.attachAsset('Alien', { anchorX: 0.5, anchorY: 0.5, scaleX: 1.5, scaleY: 1.5, zIndex: 2 }); var radiusGraphics = self.attachAsset('Boss_Radius', { anchorX: 0.5, anchorY: 0.5, scaleX: 10, scaleY: 10, tint: 0x66FF66, // Brighter green tint for radius // Green tint for radius alpha: 0.3 }); self.addChild(radiusGraphics); bossGraphics.zIndex = 3; // Ensure Alien is above radius self.addChild(bossGraphics); self.x = 2048 / 2; // Spawn at top-center of the viewport self.y = -100; self.speed = 2; // Boss movement speed self.radiusSize = 300; // Harvest radius size var laserCooldown = Math.random() * 2000 + 1000; // Randomize time (ms) between laser shots var laserElapsedTime = 0; self.alienHealthBar = new AlienHealthBar(factory.level * 2, factory.level * 2); self.alienHealthBar.scaleX = 0.5; // Scale down by half self.alienHealthBar.scaleY = 0.5; self.alienHealthBar.y = -200; // Position higher above the boss // Ensure 'self' is defined self.die = function () { self.speed = 0; radiusGraphics.rotation = 0; lasers.forEach(function (laser) { game.removeChild(laser); }); lasers = []; bossGraphics.tint = 0x808080; // Spawn boosters when the boss dies if (!self.boostersSpawned) { for (var i = 0; i < 3; i++) { var booster = new Booster(); booster.x = self.x; booster.y = self.y; boosters.push(booster); game.addChild(booster); } self.boostersSpawned = true; } // Remove the boss and reset the spawn flag game.removeChild(self); boss = null; // Ensure the boss reference is cleared bossSpawned = false; // Reset spawn flag bossDefeated = true; // Mark boss as defeated }; self.alienHealthBar.onDeath = self.die; self.addChild(self.alienHealthBar); var lasers = []; // Update boss behavior self.update = function () { radiusGraphics.rotation += 0.001; // Rotate radius to the right slowly // Check for bone collisions bones.forEach(function (bone) { if (!bone.lastIntersecting && bone.intersects(self)) { // Check for collision // Reduce boss health alienHealthBar.setHealth(alienHealthBar.currentHealth - 1); alienHealthBar.updateHealth(); // Update the visual representation of the health bar // Play a random boss hit sound getRandomSound(['Boss_Hit', 'Boss_Hit_2', 'Boss_Hit_3']).play(); // Flash the boss, radius, and health bar flashGreyMask([bossGraphics, radiusGraphics, self.alienHealthBar], 400, 3); // Ensure correct components are passed tween(bossGraphics, { alpha: 0.5 }, { duration: 100, yoyo: true, repeat: 3, onComplete: function onComplete() { bossGraphics.alpha = 1; // Reset alpha after flashing } }); // Remove the bone game.removeChild(bone); bones.splice(bones.indexOf(bone), 1); } // Update last intersecting state bone.lastIntersecting = bone.intersects(self); }); // Move towards Mishnu var dx = mishnu.x - self.x; var dy = mishnu.y - self.y; var distance = Math.sqrt(dx * dx + dy * dy); if (distance > 1) { self.x += dx / distance * self.speed; self.y += dy / distance * self.speed; } // Check for humans within radius humans.forEach(function (human) { var humanDx = human.x - self.x; var humanDy = human.y - self.y; var humanDistance = Math.sqrt(humanDx * humanDx + humanDy * humanDy); if (humanDistance < self.radiusSize) { game.removeChild(human); humans.splice(humans.indexOf(human), 1); // Add blood splash effect for harvested humans game.addChild(new BloodSplash(human.x, human.y, true)); // Play a random squish sound getRandomSound(['Squish_1', 'Squish_2', 'Squish_3', 'Squish_4']).play(); } }); // Handle laser shooting laserElapsedTime += 16; // Assume 16ms per frame if (laserElapsedTime >= laserCooldown) { shootLaser(); laserElapsedTime = 0; laserCooldown = Math.random() * 2000 + 1000; // Reset to a new random cooldown } // Update lasers lasers.forEach(function (laser) { laser.update(); }); // Remove off-screen lasers lasers = lasers.filter(function (laser) { return laser.isInViewport(); }); }; // Laser shooting logic function shootLaser() { var laser = new Laser(self.x, self.y, mishnu.x, mishnu.y); var laserSounds = ['laser', 'laser_2', 'Laser_3', 'Laser_4']; var randomLaserSound = LK.getSound(laserSounds[Math.floor(Math.random() * laserSounds.length)]); randomLaserSound.play(); lasers.push(laser); game.addChild(laser); } return self; }); // Factory Class var Factory = Container.expand(function () { var self = Container.call(this); var factoryGraphics = self.attachAsset('Factory', { anchorX: 0.5, anchorY: 0.5, zIndex: 3 }); self.x = 950; self.y = 2432 - 100; // Position factory in the text box area self.meat = 0; self.dogFood = 0; self.processing = false; self.processInterval = null; self.rumbleTimer = 0; // Timer for rumble effect self.level = 1; // Current level self.nextLevelRequirement = 5; // Starting requirement for level 2 // Start processing meat into dog food self.startProcessing = function () { if (!self.processing && self.meat >= 5) { self.processing = true; if (!isFactorySoundPlaying) { LK.getSound('Factory_Operation').play({ loop: true }); isFactorySoundPlaying = true; // Set flag to true } self.processInterval = LK.setInterval(function () { if (self.meat >= 5) { self.meat -= 5; self.dogFood++; updateFactoryText(); checkLevelProgression(); spawnZombies(1, maxZombiesOnScreen); if (Math.random() < 1 / (1 + factory.level * 0.2)) { spawnBooster(); // Reduce booster frequency } } else { self.stopProcessing(); } }, Math.max(3000, 5000 + factory.level * (factory.level > 5 ? 100 : 200))); // Reduce spawn rate increase after level 5 } }; // Stop processing self.stopProcessing = function () { if (self.processing) { self.processing = false; LK.clearInterval(self.processInterval); LK.getSound('Factory_Operation').stop(); isFactorySoundPlaying = false; // Reset flag to false } }; // Update the factory self.update = function () { // Check for Mishnu depositing cargo if (mishnu.humansHarvested > 0 && self.intersects(mishnu)) { // Mishnu deposits cargo self.meat += mishnu.humansHarvested; mishnu.humansHarvested = 0; LK.getSound('Factory_Deposit').play(); // Play deposit sound updateFactoryText(); self.startProcessing(); } // Add rumble effect when processing if (self.processing) { if (!isFactorySoundPlaying) { LK.getSound('Factory_Operation').play({ loop: true }); isFactorySoundPlaying = true; } self.rumbleTimer += 16; // Assume 16ms per frame if (self.rumbleTimer >= 100) { // Rumble every 100ms factoryGraphics.x = Math.random() * 6 - 3; // Horizontal rumble factoryGraphics.y = Math.random() * 6 - 3; // Vertical rumble self.rumbleTimer = 0; } } else { // Reset position when not processing factoryGraphics.x = 0; factoryGraphics.y = 0; } // Stop processing if out of meat if (self.meat < 5 && self.processing) { self.stopProcessing(); } }; function triggerLevelTextShake() { var shakeIntensity = 5; // Maximum shake offset in pixels var shakeDuration = 500; // Duration of the shake in milliseconds var elapsedTime = 0; // Tracks elapsed time var originalX = factoryText.x; // Save the original x position var originalY = factoryText.y; // Save the original y position // Function to perform shaking var shakeInterval = LK.setInterval(function () { if (elapsedTime >= shakeDuration) { LK.clearInterval(shakeInterval); factoryText.x = originalX; // Reset to original position factoryText.y = originalY; return; } // Apply random offset for shaking factoryText.x = originalX + (Math.random() * shakeIntensity * 2 - shakeIntensity); factoryText.y = originalY + (Math.random() * shakeIntensity * 2 - shakeIntensity); elapsedTime += 16; // Assume 16ms per frame (60 FPS) }, 16); } function checkLevelProgression() { if (self.dogFood >= self.nextLevelRequirement) { checkForBossSpawn(); // Ensure boss spawns at every increment of 4 levels self.level++; if (self.level % 5 === 0) { mishnu.harvestSpeed *= 0.75; // Increase harvest time by 60% every 5 levels mishnu.speed *= 1.15; // Increase Mishnu's speed by 15% humans.forEach(function (human) { human.speedX *= 1.15; // Increase human speed by 15% human.speedY *= 1.15; }); zombies.forEach(function (zombie) { zombie.speed *= 1.15; // Increase zombie speed by 15% }); } bossDefeated = false; // Reset bossDefeated for the new level LK.getSound('Level_Up').play(); // Play level-up sound self.nextLevelRequirement += Math.round(self.level * 1.5 + 5); // Further adjusted to reduce Mishnu Snax requirements // Reset spawn counter and calculate new spawn limit humansSpawnedThisLevel = 0; humanSpawnLimit = self.nextLevelRequirement * 5; // Trigger level-up animation triggerLevelTextShake(); updateFactoryText(); spawnZombies(1, maxZombiesOnScreen); // Spawn a zombie when leveling up } } }); // GlobalHealthBar Class var GlobalHealthBar = Container.expand(function (initialHealth, maxHealth) { var self = Container.call(this); self.currentHealth = initialHealth; self.maxHealth = maxHealth; // Define frame dimensions if dynamic retrieval isn't available var frameWidth = LK.getAsset('LK_Health_Bar', {}).width; // Create filler (health bar inner part) var filler = self.attachAsset('LK_Inner_Health_Bar', { anchorX: 0, // Anchor to the left anchorY: 0.5, // Center vertically x: -frameWidth / 2, // Align with the outer frame // Start from the left edge of the frame y: 0, // Center vertically scaleX: 1 // Fully filled initially }); // Create frame (health bar outer part) var frame = self.attachAsset('LK_Health_Bar', { anchorX: 0.5, // Center horizontally anchorY: 0.5, // Center vertically x: 0, // Centered relative to the container y: 0 // Center vertically }); // Update the visual representation of the health bar self.updateHealth = function () { // Ensure filler width matches current health filler.scaleX = Math.max(0, self.currentHealth / self.maxHealth); // Scale proportionally }; // Change health value self.setHealth = function (newHealth) { self.currentHealth = Math.max(0, Math.min(newHealth, self.maxHealth)); // Clamp between 0 and maxHealth self.updateHealth(); if (self.currentHealth === 0) { triggerGameOver(); } }; // Change maximum health and adjust health proportionally self.setMaxHealth = function (newMaxHealth) { var healthRatio = self.currentHealth / self.maxHealth; self.maxHealth = Math.max(1, newMaxHealth); // Ensure at least 1 max health self.currentHealth = Math.min(self.currentHealth, self.maxHealth); self.updateHealth(); }; // Initialize the health bar self.setHealth(initialHealth); return self; }); // Declare healthBar globally for accessibility // Assuming initial and max health are both 100 // Class for Mishnu's harvest radius var HarvestRadius = Container.expand(function () { var self = Container.call(this); var radiusGraphics = self.attachAsset('radius', { anchorX: 0.5, anchorY: 0.5, scaleX: 10, scaleY: 10 }); self.radiusSize = 300; // Effective radius size var rotationSpeed = 0.001; // Extremely slow rotation speed self.update = function () { self.x = mishnu.x; self.y = mishnu.y; // Apply slow rotation to the radius radiusGraphics.rotation -= rotationSpeed; }; return self; }); // Define ColorMatrixFilter to fix 'filters is not defined' error // Class for Humans // Class for Humans // Class for Humans var Human = Container.expand(function () { var self = Container.call(this); var humanImages = ['Human_1', 'Human_2', 'Human_3', 'Human_4', 'Human_5', 'Human_6', 'Human_7', 'Human_8', 'human_9', 'Human_10', 'Human_11', 'Human_12', 'Human_13', 'Human_14', 'Human_15', 'Human_16', 'Human_17']; var randomHumanImage = humanImages[Math.floor(Math.random() * humanImages.length)]; // Attach asset for the human graphic var humanGraphics = self.attachAsset(randomHumanImage, { anchorX: 0.5, anchorY: 0.5 }); // Randomly generate a tint color avoiding too dark or too bright colors function getRandomTint() { var red = Math.floor(Math.random() * 156) + 50; // Between 50 and 205 var green = Math.floor(Math.random() * 156) + 50; // Between 50 and 205 var blue = Math.floor(Math.random() * 156) + 50; // Between 50 and 205 return red << 16 | green << 8 | blue; } var originalTint = getRandomTint(); humanGraphics.tint = originalTint; // Apply random tint // 50/50 chance to flip horizontally if (Math.random() < 0.5) { humanGraphics.scale.x *= -1; // Flip horizontally } var bloodSplashes = []; self.speedX = (Math.random() * 2 - 1) * 2; self.speedY = (Math.random() * 2 - 1) * 2; self.isBeingHarvested = false; self.inRadiusStartTime = null; self.currentAgonySound = null; self.currentCrunchSound = null; self.yellStarted = false; // Tracks if the yell has started self.yellShouldPlay = Math.random() < 1 / 6; // 1-in-6 chance for yelling self.crunchShouldPlay = Math.random() < 1 / 6; // 1-in-6 chance for crunch sound self.flashTimer = 0; // Timer for red flashing self.flashInterval = 500; // Initial interval for flashing self.update = function () { // Escape logic self.x += self.speedX; self.y += self.speedY; // Keep humans within the viewport margins var margin = 50; var bottomMargin = 300; // Extra margin for bottom text box if (self.x <= margin) { self.x = margin; self.speedX *= -1; } else if (self.x >= 2048 - margin) { self.x = 2048 - margin; self.speedX *= -1; } if (self.y <= margin) { self.y = margin; self.speedY *= -1; } else if (self.y >= 2432 - margin) { self.y = 2432 - margin; self.speedY *= -1; } // Check distance to Mishnu var dx = self.x - mishnu.x; var dy = self.y - mishnu.y; var distance = Math.sqrt(dx * dx + dy * dy); if (mishnu.humansHarvested >= mishnu.cargoMax * 1.5) { // Stop all sounds when cargo exceeds 150% capacity if (self.currentAgonySound !== null) { fadeOutSound(self.currentAgonySound, 500); } if (self.currentCrunchSound) { self.currentCrunchSound.stop(); } self.isBeingHarvested = false; return; } if (distance < radius.radiusSize - 2) { if (!self.isBeingHarvested) { var _self$currentCrunchSo; self.isBeingHarvested = true; self.inRadiusStartTime = Date.now(); self.flashTimer = 0; bloodSplashes = []; self.yellStarted = false; // Play crunch sound if applicable if (self.crunchShouldPlay) { if (self.currentCrunchSound) { self.currentCrunchSound.stop(); // Stop any currently playing crunch sound } self.currentCrunchSound = getRandomSound(['Dog_Crunch', 'Dog_Crunch_2', 'Dog_Crunch_3']); self.currentCrunchSound.volume = 0.3; self.currentCrunchSound.play(); } } else { // Calculate vibration intensity based on time in the radius var elapsedTime = Date.now() - self.inRadiusStartTime; var intensity = Math.min(1, elapsedTime / 3000); // Max intensity at 3 seconds // Add vibration effect humanGraphics.x = Math.random() * intensity * 10 - intensity * 5; humanGraphics.y = Math.random() * intensity * 10 - intensity * 5; // Escape logic during vibration var runSpeed = 2; // Speed humans try to escape the radius self.x += dx / distance * runSpeed; self.y += dy / distance * runSpeed; // Flash red effect self.flashTimer += 16; // Assume a fixed delta of 16ms per frame if (self.flashTimer >= self.flashInterval) { self.flashTimer = 0; // Toggle between red and the original tint if (humanGraphics.tint === 0xeb0909) { humanGraphics.tint = originalTint; // Reset to original tint } else { humanGraphics.tint = 0xeb0909; // Flash red } // Emit blood splash var bloodSplash = game.addChild(new BloodSplash(self.x, self.y)); bloodSplashes.push(bloodSplash); } // Increase flash frequency closer to harvest self.flashInterval = Math.max(100, 500 - elapsedTime / 3000 * 400); // Start agony yell after 1 second of harvesting if (elapsedTime > 1000 && !self.yellStarted && self.yellShouldPlay) { self.yellStarted = true; self.currentAgonySound = getRandomSound(['Agony_Yell_1', 'Agony_Yell_2', 'Agony_Yell_3', 'Agony_Yell_4', 'Agony_Yell_5', 'Agony_Yell_6', 'Agony_Yell_7', 'Agony_Yell_8', 'Agony_Yell_9', 'Agony_Yell_10']); self.currentAgonySound.volume = 0.05; self.currentAgonySound.play(); } if (elapsedTime >= 3000 / mishnu.harvestSpeed) { // Harvest after 3 seconds if (mishnu.humansHarvested < mishnu.cargoMax * 1.5) { game.removeChild(self); // Remove human from the game humans.splice(humans.indexOf(self), 1); // Remove from array mishnu.humansHarvested++; // Stop yelling abruptly if (self.currentAgonySound) { self.currentAgonySound.stop(); } // Play ding and squish sounds on harvest LK.getSound('Ding_1').play(); getRandomSound(['Squish_1', 'Squish_2', 'Squish_3', 'Squish_4']).play(); // Final blood splashes for (var i = 0; i < 10; i++) { var bloodSplash = game.addChild(new BloodSplash(self.x, self.y, true)); bloodSplashes.push(bloodSplash); } } } } } else { // Reset harvesting state if outside the radius if (self.isBeingHarvested) { if (self.currentAgonySound && self.yellStarted) { self.currentAgonySound.loop = false; } if (self.currentCrunchSound) { self.currentCrunchSound.stop(); } } self.isBeingHarvested = false; self.inRadiusStartTime = null; self.flashTimer = 0; humanGraphics.tint = originalTint; // Reset to original tint bloodSplashes.forEach(function (splash) { game.removeChild(splash); }); } }; return self; }); // Laser Class var Laser = Container.expand(function (startX, startY, targetX, targetY) { var self = Container.call(this); var laserGraphics = self.attachAsset('Laser', { anchorX: 0.5, anchorY: 0.5, scaleX: 0.5, scaleY: 0.5, tint: 0xFF0000 // Red tint for lasers }); self.x = startX; self.y = startY; var speed = 10; var dx = targetX - startX; var dy = targetY - startY; var distance = Math.sqrt(dx * dx + dy * dy); var velocityX = dx / distance * speed; var velocityY = dy / distance * speed; // Function to emit stars around the laser self.emitStars = function () { var sparkle = self.attachAsset('Stars', { anchorX: 0.5, anchorY: 0.5, scaleX: Math.random() * 0.3 + 0.1, scaleY: Math.random() * 0.3 + 0.1, alpha: 1, tint: 0xFFFFFF // Bright white sparkles }); // Position sparkle randomly around the laser var angle = Math.random() * Math.PI * 2; var radius = (laserGraphics.width / 2 + Math.random() * 20 + 10) * (1 / 3); // Reduced radius by 2/3rds sparkle.x = Math.cos(angle) * radius; sparkle.y = Math.sin(angle) * radius; // Set sparkle lifetime var lifetime = Math.random() * 200 + 100; // Short lifespan var elapsed = 0; // Animate the sparkle var interval = LK.setInterval(function () { elapsed += 16; // Assume 16ms per frame sparkle.y -= 0.2; // Subtle upward motion sparkle.alpha = Math.max(0, 1 - elapsed / lifetime); // Gradual fade-out if (elapsed >= lifetime) { LK.clearInterval(interval); self.removeChild(sparkle); // Remove sparkle after its lifetime } }, 16); }; // Update laser behavior self.update = function () { self.x += velocityX; self.y += velocityY; // Emit stars around the laser self.emitStars(); // Check collision with Mishnu var mishnuDx = mishnu.x - self.x; var mishnuDy = mishnu.y - self.y; var mishnuDistance = Math.sqrt(mishnuDx * mishnuDx + mishnuDy * mishnuDy); if (mishnuDistance < 50 && !self.hasHitMishnu) { self.hasHitMishnu = true; // Mark as hit if (self.isInViewport()) { game.removeChild(self); lasers.splice(lasers.indexOf(self), 1); } // Deduct 2hp from globalHealthBar and update its visual representation globalHealthBar.setHealth(globalHealthBar.currentHealth - 2); globalHealthBar.updateHealth(); flashGreyMask([mishnu, radius, globalHealthBar], 400, 3); LK.getSound('searing').play(); if (!self.barkPlaying) { self.barkPlaying = true; LK.setTimeout(function () { var barks = ['Bark', 'Bark_2', 'Bark_3']; var barkSound = LK.getSound(barks[Math.floor(Math.random() * barks.length)]); barkSound.play(); barkSound.on('end', function () { self.barkPlaying = false; }); }, 200); } } // Remove if out of viewport if (!self.isInViewport()) { game.removeChild(self); } }; // Check if laser is within the viewport self.isInViewport = function () { return self.x >= -50 && self.x <= 2048 + 50 && self.y >= -50 && self.y <= 2432 + 50; }; self.hasHitMishnu = false; // Initialize hit flag return self; }); // Add boss spawning at level 2 // Class for Mishnu var Mishnu = Container.expand(function () { var self = Container.call(this); var mishnuGraphics = self.attachAsset('mishnu', { anchorX: 0.5, anchorY: 0.5, zIndex: 1 }); self.speed = 4; self.humansHarvested = 0; self.cargoMax = 10; self.targetX = 2048 / 2; self.targetY = 2432 - 200; self.update = function () { var dx = self.targetX - self.x; var dy = self.targetY - self.y; var distance = Math.sqrt(dx * dx + dy * dy); // Adjust speed based on cargo if (self.humansHarvested > self.cargoMax) { var overCapacityFactor = (self.humansHarvested - self.cargoMax) / (self.cargoMax * 0.5); self.speed = Math.max(1, 4 - 3 * overCapacityFactor); // Minimum speed of 1 } else { self.speed = 4; // Full speed } if (distance > 0) { self.x += dx / distance * self.speed; self.y += dy / distance * self.speed; } // Keep Mishnu within viewport margins var margin = 50; var bottomMargin = 300; // Extra margin for bottom text box self.x = Math.max(margin, Math.min(2048 - margin, self.x)); self.y = Math.max(margin, Math.min(2432 - bottomMargin, self.y)); // Shoot bones if a boss is present if (boss && boss.alienHealthBar.currentHealth > 0 && Math.random() < 0.01) { // Random chance to shoot var oppositeX = self.x - (self.targetX - self.x); var oppositeY = self.y - (self.targetY - self.y); var bone = new Bone(self.x, self.y, oppositeX, oppositeY); game.addChild(bone); } }; // Create and position the health bar at the top center of the viewport globalHealthBar.x = 1820; // Center horizontally globalHealthBar.y = 2560; // Position at the top center uiLayer.addChild(globalHealthBar); // Add to the UI layer to ensure visibility return self; }); var Zombie = Container.expand(function () { var self = Container.call(this); // Add the zombie graphics var zombieGraphics = self.attachAsset('Zombie', { anchorX: 0.5, anchorY: 0.5 }); // Helper function to get a color based on the level function getColorForLevel(level) { var colors = [0xFF0000, // Bright red 0x00FF00, // Bright green 0x0000FF, // Bright blue 0xFFFF00, // Bright yellow 0xFF00FF, // Bright magenta 0x00FFFF, // Bright cyan 0xFFA500, // Bright orange 0x800080, // Bright purple 0xFFFFFF, // Bright white 0xFFC0CB // Bright pink ]; return colors[level % colors.length]; // Cycle through colors } // Set zombie attributes dynamically based on factory level function initializeZombie(level) { zombieGraphics.tint = getColorForLevel(level); // Set vivid color self.harvestTime = 4000 + level * 500; // Increase harvest time with level } // Call the initializer with the current factory level initializeZombie(factory.level); // Attributes self.speed = 2; self.attackCooldown = 3000; // Cooldown (ms) between attacks self.lastAttackTime = 0; // Tracks the last attack time self.state = 'roaming'; // Initial state self.targetX = Math.random() * 2048; // Random initial roaming target self.targetY = Math.random() * 2432; self.inRadiusStartTime = null; // Time zombie entered Mishnu's radius var agonySound = null; var harvestSoundPlayed = false; var flashingInterval = null; // Interval for flashing effect var vibratingInterval = null; // Interval for vibrating effect var flashTimer = 0; // Timer for red flashing var flashInterval = 500; // Initial interval for flashing // Helper function: Generate a random roaming target function setRandomTarget() { self.targetX = Math.random() * 2048; self.targetY = Math.random() * 2432; } // Helper function: Move to a target function moveToTarget(targetX, targetY) { var speedMultiplier = arguments.length > 2 && arguments[2] !== undefined ? arguments[2] : 1; var dx = targetX - self.x; var dy = targetY - self.y; var distance = Math.sqrt(dx * dx + dy * dy); if (distance > 1) { self.x += dx / distance * self.speed * speedMultiplier; self.y += dy / distance * self.speed * speedMultiplier; } else { setRandomTarget(); } } // Add flashing red effect function startFlashing() { var flashing = false; flashingInterval = LK.setInterval(function () { zombieGraphics.tint = flashing ? 0xFF0000 : getColorForLevel(factory.level); flashing = !flashing; }, 100); } function stopFlashing() { if (flashingInterval) { LK.clearInterval(flashingInterval); flashingInterval = null; zombieGraphics.tint = getColorForLevel(factory.level); } } // Add vibrating effect function startVibrating() { vibratingInterval = LK.setInterval(function () { self.x += Math.random() * 4 - 2; // Vibrate by a small random offset self.y += Math.random() * 4 - 2; }, 16); } function stopVibrating() { if (vibratingInterval) { LK.clearInterval(vibratingInterval); vibratingInterval = null; } } // Add sparkles function emitStars() { var sparkle = self.attachAsset('Stars', { anchorX: 0.5, anchorY: 0.5, scaleX: Math.random() * 0.3 + 0.1, scaleY: Math.random() * 0.3 + 0.1, alpha: 1, tint: 0xFFFFFF // Bright white sparkles }); var angle = Math.random() * Math.PI * 2; var radius = zombieGraphics.width / 2 + Math.random() * 20 + 10; sparkle.x = Math.cos(angle) * radius; sparkle.y = Math.sin(angle) * radius; var lifetime = Math.random() * 200 + 100; var elapsed = 0; var interval = LK.setInterval(function () { elapsed += 16; sparkle.y -= 0.2; sparkle.alpha = Math.max(0, 1 - elapsed / lifetime); if (elapsed >= lifetime) { LK.clearInterval(interval); self.removeChild(sparkle); } }, 16); } // Emit sparkles periodically LK.setInterval(emitStars, 200); // Add blood splashes function addBloodSplashes() { var isFinal = arguments.length > 0 && arguments[0] !== undefined ? arguments[0] : false; var count = isFinal ? 10 : 1; for (var i = 0; i < count; i++) { game.addChild(new BloodSplash(self.x, self.y, isFinal)); } } // Update behavior self.update = function () { var dx = mishnu.x - self.x; var dy = mishnu.y - self.y; var distanceToMishnu = Math.sqrt(dx * dx + dy * dy); switch (self.state) { case 'roaming': moveToTarget(self.targetX, self.targetY); if (distanceToMishnu < radius.radiusSize) { self.state = 'attacking'; self.inRadiusStartTime = Date.now(); startFlashing(); startVibrating(); flashTimer = 0; flashInterval = 500; if (Math.random() < 1 / 5) { agonySound = getRandomSound(['GiggleMan_1', 'GiggleMan_2', 'GiggleMan_3', 'GiggleMan_4', 'GiggleMan_5']); agonySound.volume = 0.3; agonySound.play(); } } break; case 'attacking': moveToTarget(mishnu.x, mishnu.y, 1.5); if (distanceToMishnu < radius.radiusSize) { var elapsedTime = Date.now() - self.inRadiusStartTime; var intensity = Math.min(1, elapsedTime / 3000); // Vibration effect zombieGraphics.x = Math.random() * intensity * 10 - intensity * 5; zombieGraphics.y = Math.random() * intensity * 10 - intensity * 5; // Flash red effect flashTimer += 16; if (flashTimer >= flashInterval) { flashTimer = 0; zombieGraphics.tint = zombieGraphics.tint === 0xFF0000 ? getColorForLevel(factory.level) : 0xFF0000; flashInterval = Math.max(100, 500 - elapsedTime / 3000 * 400); } if (elapsedTime >= self.harvestTime / mishnu.harvestSpeed) { self.state = 'harvested'; game.removeChild(self); zombies.splice(zombies.indexOf(self), 1); mishnu.humansHarvested += 2; if (!harvestSoundPlayed) { LK.getSound('Ding_1').play(); getRandomSound(['Squish_1', 'Squish_2', 'Squish_3', 'Squish_4']).play(); harvestSoundPlayed = true; } addBloodSplashes(true); stopFlashing(); stopVibrating(); return; } if (distanceToMishnu < 50 && Date.now() - self.lastAttackTime > self.attackCooldown) { globalHealthBar.setHealth(globalHealthBar.currentHealth - 1); self.lastAttackTime = Date.now(); self.state = 'fleeing'; var fleeAngle = Math.random() * Math.PI * 2; self.targetX = mishnu.x + Math.cos(fleeAngle) * (radius.radiusSize + 50); self.targetY = mishnu.y + Math.sin(fleeAngle) * (radius.radiusSize + 50); addBloodSplashes(); flashGreyMask([mishnu, radius, globalHealthBar], 400, 3); LK.getSound('Hit').play(); LK.setTimeout(function () { var barks = ['Bark', 'Bark_1', 'Bark_2']; LK.getSound(barks[Math.floor(Math.random() * barks.length)]).play(); }, 200); } } else { self.state = 'roaming'; setRandomTarget(); stopFlashing(); stopVibrating(); } break; case 'fleeing': moveToTarget(self.targetX, self.targetY, 2); if (distanceToMishnu > radius.radiusSize + 50) { self.state = 'roaming'; setRandomTarget(); stopFlashing(); stopVibrating(); } break; case 'harvested': break; default: console.error("Zombie in unknown state: ".concat(self.state)); self.state = 'roaming'; setRandomTarget(); stopFlashing(); stopVibrating(); break; } }; // Set initial target setRandomTarget(); return self; }); /**** * Initialize Game ****/ // Modify game logic to include zombie spawning // Declare healthBar globally for accessibility var game = new LK.Game({ backgroundColor: 0x1d1d1d }); /**** * Game Code ****/ function triggerGameOver() { // Freeze all game elements LK.showGameOver(); // Create a black mask over the entire viewport var blackMask = new Container(); var maskGraphics = blackMask.attachAsset('Blue_Mask', { anchorX: 0.5, anchorY: 0.5, scaleX: 2048 / 100, scaleY: 2732 / 100, tint: 0x000000, alpha: 0.7 }); blackMask.x = 2048 / 2; blackMask.y = 2732 / 2; game.addChild(blackMask); // Display Game Over image much larger and positioned higher var gameOverImage = LK.getAsset('Game_Over', { anchorX: 0.5, anchorY: 0.5 }); gameOverImage.scaleX = 8; // Scale up the image 5 times gameOverImage.scaleY = 8; // Maintain proportional scaling gameOverImage.x = 2048 / 2; gameOverImage.y = 2732 / 3 - 400; // Position about 800 pixels higher game.addChild(gameOverImage); } var bossDefeated = false; var isFactorySoundPlaying = false; // Flag to track if factory sound is playing var lasers = []; var bones = []; // Initialize bones array to store bone objects // Initialize lastIntersecting property for each bone bones.forEach(function (bone) { bone.lastIntersecting = false; bone.fadeOutTimer = null; // Initialize fadeOutTimer for each bone bone.update = function () { // Check for collision with the boss if (!bone.lastIntersecting && bone.intersects(boss)) { // Reduce boss health alienHealthBar.setHealth(alienHealthBar.currentHealth - 1); // Play a random boss hit sound getRandomSound(['Boss_Hit', 'Boss_Hit_2', 'Boss_Hit_3']).play(); // Remove the bone game.removeChild(bone); bones.splice(bones.indexOf(bone), 1); } // Update last intersecting state bone.lastIntersecting = bone.intersects(boss); }; }); // Add boss spawning at level 2 // Define ColorMatrixFilter to fix 'filters is not defined' error // Booster spawning logic // Booster spawning logic // Declare healthBar globally for accessibility // Modify game logic to include zombie spawning var bossSpawned = false; var boss; // Define boss globally // Removed global alienHealthBar initialization and rendering function isMultipleOfFour(level) { return level % 4 === 0; } function checkForBossSpawn() { if (isMultipleOfFour(factory.level) && !bossSpawned && !bossDefeated && (!boss || boss.alienHealthBar.currentHealth === 0)) { boss = new Boss(); game.addChild(boss); bossSpawned = true; // Set bossSpawned flag } } // Update game loop to include boss logic var originalGameUpdate = game.update; game.update = function () { originalGameUpdate.call(this); checkForBossSpawn(); if (boss && boss.alienHealthBar.currentHealth === 0) { // Ensure boss is removed from the game game.removeChild(boss); boss = null; bossSpawned = false; // Reset bossSpawned flag // Disable further interactions with the boss bones.forEach(function (bone) { if (bone.intersects(boss)) { game.removeChild(bone); bones.splice(bones.indexOf(bone), 1); } }); // Clear any remaining boss-related sounds or effects lasers.forEach(function (laser) { game.removeChild(laser); }); lasers = []; } }; var boosters = []; function spawnBooster() { var booster = new Booster(); boosters.push(booster); game.addChild(booster); } // Integrate boosters with Mishnu Snax increase var uiLayer = new Container(); uiLayer.zIndex = 10; // Ensure it's above the background and mask game.addChild(uiLayer); var factory = uiLayer.addChild(new Factory()); var originalIncreaseDogFood = factory.startProcessing; factory.startProcessing = function () { originalIncreaseDogFood.call(factory); // Reduce booster spawn rate as levels increase if (factory.level % Math.max(1, Math.floor(factory.level / 3)) === 0) { spawnBooster(); // Spawn boosters less frequently as level increases } }; // Mishnu pickup logic function checkBoosterPickup() { boosters.forEach(function (booster) { var dx = booster.x - mishnu.x; var dy = booster.y - mishnu.y; if (Math.sqrt(dx * dx + dy * dy) < 50) { booster.pickUp(); game.removeChild(booster); // Ensure booster is removed from the game boosters.splice(boosters.indexOf(booster), 1); } }); } // Add to game update loop var originalGameUpdate = game.update; game.update = function () { originalGameUpdate.call(this); boosters.forEach(function (booster) { booster.update(); }); checkBoosterPickup(); }; var globalHealthBar = new GlobalHealthBar(100, 100); function spawnZombies(count, maxZombiesOnScreen) { for (var i = 0; i < count; i++) { if (boss && boss.alienHealthBar.currentHealth > 0) { return; // Do not spawn zombies if the boss is present and alive } if (zombies.length >= maxZombiesOnScreen) { break; } var spawnEdge = Math.floor(Math.random() * 3); // 0: top, 1: left, 2: right var spawnX, spawnY; switch (spawnEdge) { case 0: spawnX = Math.random() * 2048; spawnY = -50; break; case 1: spawnX = -50; spawnY = Math.random() * (2432 - 300); break; case 2: spawnX = 2048 + 50; spawnY = Math.random() * (2432 - 300); break; } var newZombie = new Zombie(); newZombie.x = spawnX; newZombie.y = spawnY; zombies.push(newZombie); game.addChild(newZombie); } } // Initialize zombies var zombies = []; var zombieSpawnCooldown = 3000; // Time (ms) between zombie spawn attempts var zombieSpawnElapsedTime = 0; var maxZombiesOnScreen = 10; // Update game loop to handle zombies var originalGameUpdate = game.update; game.update = function () { originalGameUpdate.call(this); // Update zombies zombies.forEach(function (zombie) { zombie.update(); }); // Spawn zombies if needed zombieSpawnElapsedTime += 16; // Assume 16ms per frame if (zombieSpawnElapsedTime >= zombieSpawnCooldown && zombies.length < maxZombiesOnScreen) { spawnZombies(1, maxZombiesOnScreen); // Spawn one zombie at a time zombieSpawnElapsedTime = 0; } // Ensure zombie count does not exceed maximum if (zombies.length > maxZombiesOnScreen) { while (zombies.length > maxZombiesOnScreen) { var zombieToRemove = zombies.pop(); game.removeChild(zombieToRemove); } } }; var isMusicPlaying = { 'Music_Level_1_4': false, 'Music_Level_1_5': false }; // Update factory text function updateFactoryText() { factoryText.setText("Level: " + factory.level + "\nMeat: " + factory.meat + "\nMishnu Snax: " + factory.dogFood + "\nNext level at: " + factory.nextLevelRequirement); } // Function to randomly select a sound from a list ; // Add a UI layer to ensure factory is rendered above the background and mask var uiLayer = new Container(); uiLayer.zIndex = 10; // Ensure it's above the background and mask game.addChild(uiLayer); // Create and position the health bar at the top center of the viewport var globalHealthBar = new GlobalHealthBar(5, 5); // Initialize with initial and max health of 5 globalHealthBar.x = 1820; // Center horizontally globalHealthBar.y = 2560; // Position at the top center // Add text label 'Health' above the global health bar var healthLabel = new Text2('Health', { size: 50, fill: 0xFFFFFF }); healthLabel.anchor.set(0.5, 1); healthLabel.x = globalHealthBar.x; healthLabel.y = globalHealthBar.y - 60; // Position above the health bar uiLayer.addChild(healthLabel); uiLayer.addChild(globalHealthBar); // Add to the UI layer to ensure visibility // Add the factory to the UI layer var factory = uiLayer.addChild(new Factory()); // Initialize factory text var factoryText = new Text2('Meat: 0\nMishnu Snax: 0\nNext level at: ', { size: 50, fill: 0xFFFFFF, align: 'left' }); factoryText.anchor.set(0, 1); LK.gui.bottomLeft.addChild(factoryText); var nextLevel = 100; // Placeholder for next level goal // Function to randomly spawn a human at the edges of the viewport function spawnHumans(count, maxHumansOnScreen) { var hardCap = 100; // Maximum number of humans allowed if (boss && boss.alienHealthBar.currentHealth > 0) { return; // Do not spawn humans if the boss is present and alive } if (factory.level % 4 === 0 && boss && boss.alienHealthBar.currentHealth > 0) { return; // Wait for boss to be defeated before spawning humans } for (var i = 0; i < count; i++) { if (humans.length >= maxHumansOnScreen || humans.length >= hardCap) { break; } // Randomly select a spawn edge (excluding the bottom) var spawnEdge = Math.floor(Math.random() * 3); // 0: top, 1: left, 2: right var spawnX, spawnY; switch (spawnEdge) { case 0: // Top spawnX = Math.random() * 2048; spawnY = -50; // Just outside the top boundary break; case 1: // Left spawnX = -50; // Just outside the left boundary spawnY = Math.random() * (2432 - 300); // Exclude bottom UI area break; case 2: // Right spawnX = 2048 + 50; // Just outside the right boundary spawnY = Math.random() * (2432 - 300); // Exclude bottom UI area break; } // Create a new human and add it to the game var newHuman = new Human(); newHuman.x = spawnX; newHuman.y = spawnY; humans.push(newHuman); game.addChild(newHuman); } } // Update game loop var originalUpdate = game.update; game.update = function () { originalUpdate.call(this); // Update factory factory.update(); // Check for level progression if (factory.dogFood >= nextLevel) { // Handle level progression logic here nextLevel += 100; // Example: increase next level goal updateFactoryText(); } }; function flashGreyMask(targets, duration, flashes) { var flashInterval = duration / (flashes * 2); // Time for each flash on/off var flashCount = 0; var interval = LK.setInterval(function () { if (flashCount >= flashes * 2) { // End the flashing effect targets.forEach(function (target) { if (target && typeof target.tint !== 'undefined') { target.tint = 0xFFFFFF; } }); // Reset tint LK.clearInterval(interval); } else { var isOn = flashCount % 2 === 0; // Toggle between grey and normal var tintColor = isOn ? 0x808080 : 0xFFFFFF; // Grey tint or original targets.forEach(function (target) { if (target && typeof target.tint !== 'undefined') { target.tint = tintColor; } }); // Apply tint flashCount++; } }, flashInterval); } function getRandomSound(soundList) { return LK.getSound(soundList[Math.floor(Math.random() * soundList.length)]); } // Function to fade out a sound function fadeOutSound(sound, duration) { var initialVolume = sound.volume; var fadeStep = initialVolume / (duration / 100); var fadeInterval = LK.setInterval(function () { if (sound.volume > 0) { sound.volume = Math.max(0, sound.volume - fadeStep); } else { LK.clearInterval(fadeInterval); sound.stop(); } }, 100); } var radius = game.addChild(new HarvestRadius()); var mishnu = game.addChild(new Mishnu()); mishnu.harvestSpeed = 1; // Initialize harvest speed mishnu.x = 2048 / 2; mishnu.y = 2432 - 200; radius.x = mishnu.x; radius.y = mishnu.y; // Initialize humans var humans = []; for (var i = 0; i < 50; i++) { var human = new Human(); human.x = Math.random() * 2048; human.y = Math.random() * (2432 - 100); humans.push(human); game.addChild(human); var humansSpawnedThisLevel = 0; // Tracks how many humans have spawned in the current level var humanSpawnLimit = factory.nextLevelRequirement * 7; // Set minimum spawn limit to nextLevelRequirement * 7 } var spawnCooldown = 20; // Reduced time (in ms) between spawn attempts for faster spawning var spawnElapsedTime = 0; // Tracks time elapsed since the last spawn attempt // Play looping Dog Panting sound LK.getSound('Dog_panting').play({ loop: true }); // Handle mouse movement game.move = function (x, y, obj) { mishnu.targetX = x; mishnu.targetY = y; }; // Display cargo count var cargoText = new Text2('Cargo: 0 / 10', { size: 50, fill: 0xFFFFFF }); cargoText.anchor.set(1, 1); LK.gui.bottomRight.addChild(cargoText); // Music alternation logic var currentMusic = 'Music_Level_1_5'; game.update = function () { humans.forEach(function (human) { human.update(); }); mishnu.update(); zombies.forEach(function (zombie) { zombie.update(); }); radius.update(); boosters.forEach(function (booster) { booster.update(); }); checkBoosterPickup(); checkForBossSpawn(); // Calculate dynamic minimum and maximum humans on screen var minHumansOnScreen = Math.max((factory.nextLevelRequirement - factory.dogFood) * 7, 20); // Ensure a minimum of 20 var maxHumansOnScreen = Math.ceil(minHumansOnScreen * 1.5); // Scale max to 150% of min // Ensure minimum number of humans on screen if (humans.length < minHumansOnScreen) { spawnElapsedTime += 16; // Assume 16ms per frame if (spawnElapsedTime >= spawnCooldown) { spawnHumans(minHumansOnScreen - humans.length, maxHumansOnScreen); // Pass the maxHumansOnScreen value spawnElapsedTime = 0; // Reset spawn elapsed time } } // Cap the number of humans to maxHumansOnScreen if (humans.length > maxHumansOnScreen) { // Remove excess humans from the game while (humans.length > maxHumansOnScreen) { var humanToRemove = humans.pop(); game.removeChild(humanToRemove); } } // Update cargo text var textColor = mishnu.humansHarvested > mishnu.cargoMax ? 0xFF0000 : 0xFFFFFF; if (cargoText.fill !== textColor) { LK.gui.bottomRight.removeChild(cargoText); cargoText = new Text2('Cargo: ' + mishnu.humansHarvested + ' / ' + mishnu.cargoMax, { size: 50, fill: textColor }); cargoText.anchor.set(1, 1); LK.gui.bottomRight.addChild(cargoText); } else { cargoText.setText('Cargo: ' + mishnu.humansHarvested + ' / ' + mishnu.cargoMax); } // Play Music_Level_1_4 in a loop if (!isMusicPlaying['Music_Level_1_4']) { LK.playMusic('Music_Level_1_4', { loop: true }); isMusicPlaying['Music_Level_1_4'] = true; // Track music state } // Play Music_Level_1_5 in a loop if (!isMusicPlaying['Music_Level_1_5']) { LK.playMusic('Music_Level_1_5', { loop: true }); isMusicPlaying['Music_Level_1_5'] = true; // Track music state } // Update factory factory.update(); }; // Function to emit stars around the laser function emitStars() { var sparkle = self.attachAsset('Stars', { anchorX: 0.5, anchorY: 0.5, scaleX: Math.random() * 0.3 + 0.1, scaleY: Math.random() * 0.3 + 0.1, alpha: 1, tint: 0xFFFFFF // Bright white sparkles }); // Position sparkle randomly around the laser var angle = Math.random() * Math.PI * 2; var radius = laserGraphics.width / 2 + Math.random() * 20 + 10; // Moderate radius sparkle.x = Math.cos(angle) * radius; sparkle.y = Math.sin(angle) * radius; // Set sparkle lifetime var lifetime = Math.random() * 200 + 100; // Short lifespan var elapsed = 0; // Animate the sparkle var interval = LK.setInterval(function () { elapsed += 16; // Assume 16ms per frame sparkle.y -= 0.2; // Subtle upward motion sparkle.alpha = Math.max(0, 1 - elapsed / lifetime); // Gradual fade-out if (elapsed >= lifetime) { LK.clearInterval(interval); self.removeChild(sparkle); // Remove sparkle after its lifetime } }, 16); } // --------------------------- // End of game initialization code // Now add the tips overlay so it loads last // --------------------------- // Create a container that covers the entire viewport var tipsOverlay = new Container(); tipsOverlay.interactive = true; // Enable interaction // Set a hit area covering the full screen (2048×2732) tipsOverlay.hitArea = new Rectangle(0, 0, 2048, 2732); tipsOverlay.x = 0; tipsOverlay.y = 0; // Attach the first tip image (Tips_1) using LK.init/attachAsset // Since Tips_1 is 1024x1366, doubling it (scale factor 2) fills the screen. var tipsGraphics = tipsOverlay.attachAsset('Tips_1', { anchorX: 0, anchorY: 0, scaleX: 2, scaleY: 2, alpha: 1 }); var tipState = 1; // Use the engine's built-in 'down' event handler for the container tipsOverlay.down = function (x, y, event) { console.log("Down event triggered, tipState:", tipState); if (tipState === 1) { // First tap: switch from Tips_1 to Tips_2 by removing the current asset and attaching the new one. tipsOverlay.removeChild(tipsGraphics); tipsGraphics = tipsOverlay.attachAsset('Tips_2', { anchorX: 0, anchorY: 0, scaleX: 2, scaleY: 2, alpha: 1 }); tipState = 2; } else { // Second tap: remove the overlay and start the game game.removeChild(tipsOverlay); startGame(); } }; // Add the overlay last so it appears on top game.addChild(tipsOverlay); function startGame() { console.log("Game started!"); // Insert your game-start logic here. }
/****
* Plugins
****/
var tween = LK.import("@upit/tween.v1");
/****
* Classes
****/
var AlienHealthBar = Container.expand(function (initialHealth, maxHealth) {
var self = Container.call(this);
self.currentHealth = initialHealth;
self.maxHealth = maxHealth;
// Define frame dimensions if dynamic retrieval isn't available
var frameWidth = LK.getAsset('LK_Health_Bar', {}).width;
// Create filler (health bar inner part)
var filler = self.attachAsset('LK_Inner_Health_Bar', {
anchorX: 0,
anchorY: 0.5,
x: -frameWidth / 2,
y: 0,
scaleX: 1 // Fully filled initially
});
// Create frame (health bar outer part)
var frame = self.attachAsset('LK_Health_Bar', {
anchorX: 0.5,
anchorY: 0.5,
x: 0,
y: 0
});
// Update the visual representation of the health bar
self.updateHealth = function () {
filler.scaleX = Math.max(0, self.currentHealth / self.maxHealth);
};
// Change health value
self.setHealth = function (newHealth) {
self.currentHealth = Math.max(0, Math.min(newHealth, self.maxHealth));
self.updateHealth();
if (self.currentHealth === 0 && typeof self.onDeath === 'function') {
self.onDeath();
}
};
// Change maximum health and adjust health proportionally
self.setMaxHealth = function (newMaxHealth) {
var healthRatio = self.currentHealth / self.maxHealth;
self.maxHealth = Math.max(1, newMaxHealth);
self.currentHealth = Math.min(self.currentHealth, self.maxHealth);
self.updateHealth();
};
// Initialize the health bar
self.setHealth(initialHealth);
return self;
});
// Blood Splash Class
var BloodSplash = Container.expand(function (x, y, isFinal) {
var self = Container.call(this);
var bloodGraphics = self.attachAsset('Blood_Splash_1', {
anchorX: 0.5,
anchorY: 0.5,
alpha: 0,
rotation: Math.random() * Math.PI * 2,
scaleX: 0,
scaleY: 0
});
self.x = x;
self.y = y;
var growSpeed = isFinal ? 0.1 : 0.05;
self.update = function () {
bloodGraphics.alpha += 0.05;
bloodGraphics.scaleX += growSpeed;
bloodGraphics.scaleY += growSpeed;
if (bloodGraphics && bloodGraphics.alpha >= 1) {
game.removeChild(self);
}
};
return self;
});
var Bone = Container.expand(function (startX, startY, targetX, targetY) {
var self = Container.call(this);
var boneType = Math.random() < 0.8 ? 'bone_1' : 'Bone_2'; // 80% chance for bone_1, 20% for Bone_2
var boneGraphics = self.attachAsset(boneType, {
anchorX: 0.5,
anchorY: 0.5,
scaleX: boneType === 'bone_1' ? 0.7 : 1.0,
scaleY: boneType === 'bone_1' ? 0.7 : 1.0
});
self.x = startX;
self.y = startY;
var speed = 15;
var dx = targetX - startX;
var dy = targetY - startY;
var distance = Math.sqrt(dx * dx + dy * dy);
var velocityX = dx / distance * speed;
var velocityY = dy / distance * speed;
var spinSpeed = 0.2; // Initial spin speed
// Emit stars effect
function emitStars() {
var star = new Container(); // Create a new star container
var starGraphics = star.attachAsset('Stars', {
scaleX: 0.2,
scaleY: 0.2,
tint: 0xFF0000 // Red tint for stars
});
star.x = self.x;
star.y = self.y;
game.addChild(star);
// Star fade and removal
var starFadeInterval = LK.setInterval(function () {
starGraphics.alpha -= 0.1;
if (starGraphics.alpha <= 0) {
LK.clearInterval(starFadeInterval);
game.removeChild(star);
}
}, 100);
}
self.update = function () {
// Start a timer to fade out the bone after 6 seconds
if (!self.fadeOutTimer) {
self.fadeOutTimer = LK.setTimeout(function () {
tween(boneGraphics, {
alpha: 0
}, {
duration: 2000,
onFinish: function onFinish() {
game.removeChild(self);
bones.splice(bones.indexOf(self), 1); // Remove bone from the array
}
});
}, 6000);
}
self.x += velocityX;
self.y += velocityY - 0.5; // Arching effect
velocityX *= 0.99; // Slightly decrease speed over time
velocityY *= 0.99;
boneGraphics.rotation += spinSpeed;
spinSpeed *= 0.98; // Decrease spin speed over time
// Emit stars periodically
if (Math.random() < 0.2) {
emitStars();
}
// Check for collision with the boss
if (boss && !self.lastIntersecting && self.intersects(boss) && boss.alienHealthBar) {
boss.alienHealthBar.setHealth(boss.alienHealthBar.currentHealth - 1);
if (boss) {
// Check if boss is still valid
boss.alienHealthBar.updateHealth(); // Explicitly update the health bar visual
getRandomSound(['Boss_Hit', 'Boss_Hit_2', 'Boss_Hit_3']).play();
flashGreyMask([boss.bossGraphics, boss.radiusGraphics, boss.alienHealthBar], 400, 3); // Add flashing effect
}
game.removeChild(self);
bones.splice(bones.indexOf(self), 1);
}
// Update last intersecting state
self.lastIntersecting = self.intersects(boss);
// Remove bone if it leaves the viewport
if (!self.isInViewport()) {
game.removeChild(self);
}
};
// Check if the bone is within the viewport
self.isInViewport = function () {
return self.x >= -50 && self.x <= 2048 + 50 && self.y >= -50 && self.y <= 2432 + 50;
};
// Check if the bone intersects with another object (e.g., the boss)
self.intersects = function (target) {
if (target) {
var dx = self.x - target.x;
var dy = self.y - target.y;
var distance = Math.sqrt(dx * dx + dy * dy);
return distance < 70; // Increased radius for larger hitbox
}
return false;
};
return self;
});
var Booster = Container.expand(function (type) {
var self = Container.call(this);
// Define boosters with adjusted colors and rarity levels
var colors = [{
color: 0x30a330,
// Adjusted green
effect: 'increaseHealth',
text: '+1 Health',
rarity: 0.25 // Relatively common
}, {
color: 0xd93838,
// Adjusted red
effect: 'increaseHarvestSpeed',
text: '+10% Harvest Speed',
rarity: 0.5 // Relatively common
}, {
color: 0x2f53b4,
// Adjusted blue
effect: 'increaseMaxCargo',
text: '+5 Max Cargo',
rarity: 0.15 // Neutral rarity
}, {
color: 0xe9d735,
// Adjusted yellow
effect: 'increaseMovementSpeed',
text: '+10% Movement Speed',
rarity: 0.15 // Neutral rarity
}, {
color: 0xb733b7,
// Adjusted purple
effect: 'increaseProductionSpeed',
text: '+10% Production Speed',
rarity: 0.15 // Neutral rarity
}, {
color: 0x676767,
// Adjusted grey
effect: 'fillCargo',
text: 'Cargo Filled!',
rarity: 0.05 // Extremely rare
}];
// Weighted random selection based on rarity
function selectBooster() {
var totalWeight = colors.reduce(function (sum, booster) {
return sum + booster.rarity;
}, 0);
var randomWeight = Math.random() * totalWeight;
var cumulativeWeight = 0;
for (var i = 0; i < colors.length; i++) {
cumulativeWeight += colors[i].rarity;
if (randomWeight <= cumulativeWeight) {
return colors[i];
}
}
}
var selected = selectBooster();
// Sparkle effect container
var sparkleContainer = new Container();
self.addChild(sparkleContainer); // Add sparkles first
// Attach booster graphics
var boosterGraphics = self.attachAsset('Booster', {
anchorX: 0.5,
anchorY: 0.5,
tint: selected.color,
scaleX: 0.75 * 1.15,
scaleY: 0.75 * 1.15
});
// Start position (bottom-middle of the screen)
self.x = 2048 / 2;
self.y = 2432 - 200;
// Target position (random on the screen with boundaries)
var margin = 150;
var targetX = margin + Math.random() * (2048 - 2 * margin);
var targetY = margin + Math.random() * (2432 - 300 - 2 * margin);
// Rotation and sparkle effects
var rotationSpeed = 0.01;
function emitSparkles() {
var angle = Math.random() * Math.PI * 2;
var distance = boosterGraphics.width / 2 + 10;
if (Math.random() < 0.5) {
// Reduce sparkles by half
var sparkle = sparkleContainer.attachAsset('Stars', {
anchorX: 0.5,
anchorY: 0.5,
scaleX: Math.random() * 1 + 0.15,
scaleY: Math.random() * 1 + 0.15,
alpha: 0.8,
tint: 0x808080,
x: Math.cos(angle) * distance,
y: Math.sin(angle) * distance
});
var lifetime = Math.random() * 400 + 200;
var elapsed = 0;
var interval = LK.setInterval(function () {
elapsed += 16;
sparkle.y -= 0.5;
sparkle.alpha = Math.max(0, 1 - elapsed / lifetime);
if (elapsed >= lifetime) {
LK.clearInterval(interval);
sparkleContainer.removeChild(sparkle);
}
}, 16);
}
}
// Propulsion animation
var elapsedTime = 0;
var duration = 1000;
LK.getSound('woosh').play();
self.update = function () {
elapsedTime += 16;
var t = Math.min(1, elapsedTime / duration);
self.x = (1 - t) * (2048 / 2) + t * targetX;
self.y = (1 - t) * (2432 - 200) + t * targetY - 100 * Math.sin(t * Math.PI);
if (t >= 1) {
LK.getSound('can').play();
self.update = function () {
boosterGraphics.rotation += rotationSpeed;
emitSparkles();
};
}
};
// Handle pickup and apply effect
self.pickUp = function () {
LK.getSound('Booster_Sound').play();
// Floating text with canvas
var canvas = self.attachAsset('Booster_Text_Canvas', {
anchorX: 0.5,
anchorY: 0.5,
scaleX: 1.5,
scaleY: 1,
alpha: 1
});
var floatingText = new Text2(selected.text, {
size: 80,
fill: 0xFFFFFF,
align: 'center'
});
floatingText.anchor.set(0.5, 0.5);
var textYOffset = 150;
canvas.x = 2048 / 2;
canvas.y = 2732 / 2;
floatingText.x = canvas.x;
floatingText.y = canvas.y;
game.addChild(canvas);
game.addChild(floatingText);
var elapsed = 0;
var textDuration = 1000;
var fadeInterval = LK.setInterval(function () {
elapsed += 16;
canvas.y -= 1.5;
floatingText.y -= 1.5;
canvas.alpha = Math.max(0, 1 - elapsed / textDuration);
floatingText.alpha = Math.max(0, 1 - elapsed / textDuration);
if (elapsed >= textDuration) {
LK.clearInterval(fadeInterval);
game.removeChild(canvas);
game.removeChild(floatingText);
}
}, 16);
// Apply effect based on booster type
switch (selected.effect) {
case 'increaseHealth':
if (globalHealthBar.currentHealth < globalHealthBar.maxHealth) {
globalHealthBar.setHealth(globalHealthBar.currentHealth + 1);
}
break;
case 'increaseHarvestSpeed':
mishnu.harvestSpeed *= 1.1;
break;
case 'increaseMaxCargo':
mishnu.cargoMax = Math.round(mishnu.cargoMax + 5);
mishnu.initialCargoMax = mishnu.cargoMax; // Ensure cargoMax is persistent
break;
case 'increaseMovementSpeed':
mishnu.speed *= 1.1;
break;
case 'increaseProductionSpeed':
factory.processInterval = Math.max(1000, factory.processInterval * 0.9);
break;
case 'fillCargo':
mishnu.humansHarvested = mishnu.cargoMax;
break;
default:
console.error('Unknown booster effect:', selected.effect);
}
// Quick removal effect for booster
var fadeOutInterval = LK.setInterval(function () {
boosterGraphics.alpha -= 0.1;
if (boosterGraphics.alpha <= 0) {
LK.clearInterval(fadeOutInterval);
game.removeChild(self);
}
}, 16);
};
return self;
});
// Boss Class
var Boss = Container.expand(function () {
var self = Container.call(this);
// Boss attributes
var bossGraphics = self.attachAsset('Alien', {
anchorX: 0.5,
anchorY: 0.5,
scaleX: 1.5,
scaleY: 1.5,
zIndex: 2
});
var radiusGraphics = self.attachAsset('Boss_Radius', {
anchorX: 0.5,
anchorY: 0.5,
scaleX: 10,
scaleY: 10,
tint: 0x66FF66,
// Brighter green tint for radius
// Green tint for radius
alpha: 0.3
});
self.addChild(radiusGraphics);
bossGraphics.zIndex = 3; // Ensure Alien is above radius
self.addChild(bossGraphics);
self.x = 2048 / 2; // Spawn at top-center of the viewport
self.y = -100;
self.speed = 2; // Boss movement speed
self.radiusSize = 300; // Harvest radius size
var laserCooldown = Math.random() * 2000 + 1000; // Randomize time (ms) between laser shots
var laserElapsedTime = 0;
self.alienHealthBar = new AlienHealthBar(factory.level * 2, factory.level * 2);
self.alienHealthBar.scaleX = 0.5; // Scale down by half
self.alienHealthBar.scaleY = 0.5;
self.alienHealthBar.y = -200; // Position higher above the boss
// Ensure 'self' is defined
self.die = function () {
self.speed = 0;
radiusGraphics.rotation = 0;
lasers.forEach(function (laser) {
game.removeChild(laser);
});
lasers = [];
bossGraphics.tint = 0x808080;
// Spawn boosters when the boss dies
if (!self.boostersSpawned) {
for (var i = 0; i < 3; i++) {
var booster = new Booster();
booster.x = self.x;
booster.y = self.y;
boosters.push(booster);
game.addChild(booster);
}
self.boostersSpawned = true;
}
// Remove the boss and reset the spawn flag
game.removeChild(self);
boss = null; // Ensure the boss reference is cleared
bossSpawned = false; // Reset spawn flag
bossDefeated = true; // Mark boss as defeated
};
self.alienHealthBar.onDeath = self.die;
self.addChild(self.alienHealthBar);
var lasers = [];
// Update boss behavior
self.update = function () {
radiusGraphics.rotation += 0.001; // Rotate radius to the right slowly
// Check for bone collisions
bones.forEach(function (bone) {
if (!bone.lastIntersecting && bone.intersects(self)) {
// Check for collision
// Reduce boss health
alienHealthBar.setHealth(alienHealthBar.currentHealth - 1);
alienHealthBar.updateHealth(); // Update the visual representation of the health bar
// Play a random boss hit sound
getRandomSound(['Boss_Hit', 'Boss_Hit_2', 'Boss_Hit_3']).play();
// Flash the boss, radius, and health bar
flashGreyMask([bossGraphics, radiusGraphics, self.alienHealthBar], 400, 3); // Ensure correct components are passed
tween(bossGraphics, {
alpha: 0.5
}, {
duration: 100,
yoyo: true,
repeat: 3,
onComplete: function onComplete() {
bossGraphics.alpha = 1; // Reset alpha after flashing
}
});
// Remove the bone
game.removeChild(bone);
bones.splice(bones.indexOf(bone), 1);
}
// Update last intersecting state
bone.lastIntersecting = bone.intersects(self);
});
// Move towards Mishnu
var dx = mishnu.x - self.x;
var dy = mishnu.y - self.y;
var distance = Math.sqrt(dx * dx + dy * dy);
if (distance > 1) {
self.x += dx / distance * self.speed;
self.y += dy / distance * self.speed;
}
// Check for humans within radius
humans.forEach(function (human) {
var humanDx = human.x - self.x;
var humanDy = human.y - self.y;
var humanDistance = Math.sqrt(humanDx * humanDx + humanDy * humanDy);
if (humanDistance < self.radiusSize) {
game.removeChild(human);
humans.splice(humans.indexOf(human), 1);
// Add blood splash effect for harvested humans
game.addChild(new BloodSplash(human.x, human.y, true));
// Play a random squish sound
getRandomSound(['Squish_1', 'Squish_2', 'Squish_3', 'Squish_4']).play();
}
});
// Handle laser shooting
laserElapsedTime += 16; // Assume 16ms per frame
if (laserElapsedTime >= laserCooldown) {
shootLaser();
laserElapsedTime = 0;
laserCooldown = Math.random() * 2000 + 1000; // Reset to a new random cooldown
}
// Update lasers
lasers.forEach(function (laser) {
laser.update();
});
// Remove off-screen lasers
lasers = lasers.filter(function (laser) {
return laser.isInViewport();
});
};
// Laser shooting logic
function shootLaser() {
var laser = new Laser(self.x, self.y, mishnu.x, mishnu.y);
var laserSounds = ['laser', 'laser_2', 'Laser_3', 'Laser_4'];
var randomLaserSound = LK.getSound(laserSounds[Math.floor(Math.random() * laserSounds.length)]);
randomLaserSound.play();
lasers.push(laser);
game.addChild(laser);
}
return self;
});
// Factory Class
var Factory = Container.expand(function () {
var self = Container.call(this);
var factoryGraphics = self.attachAsset('Factory', {
anchorX: 0.5,
anchorY: 0.5,
zIndex: 3
});
self.x = 950;
self.y = 2432 - 100; // Position factory in the text box area
self.meat = 0;
self.dogFood = 0;
self.processing = false;
self.processInterval = null;
self.rumbleTimer = 0; // Timer for rumble effect
self.level = 1; // Current level
self.nextLevelRequirement = 5; // Starting requirement for level 2
// Start processing meat into dog food
self.startProcessing = function () {
if (!self.processing && self.meat >= 5) {
self.processing = true;
if (!isFactorySoundPlaying) {
LK.getSound('Factory_Operation').play({
loop: true
});
isFactorySoundPlaying = true; // Set flag to true
}
self.processInterval = LK.setInterval(function () {
if (self.meat >= 5) {
self.meat -= 5;
self.dogFood++;
updateFactoryText();
checkLevelProgression();
spawnZombies(1, maxZombiesOnScreen);
if (Math.random() < 1 / (1 + factory.level * 0.2)) {
spawnBooster(); // Reduce booster frequency
}
} else {
self.stopProcessing();
}
}, Math.max(3000, 5000 + factory.level * (factory.level > 5 ? 100 : 200))); // Reduce spawn rate increase after level 5
}
};
// Stop processing
self.stopProcessing = function () {
if (self.processing) {
self.processing = false;
LK.clearInterval(self.processInterval);
LK.getSound('Factory_Operation').stop();
isFactorySoundPlaying = false; // Reset flag to false
}
};
// Update the factory
self.update = function () {
// Check for Mishnu depositing cargo
if (mishnu.humansHarvested > 0 && self.intersects(mishnu)) {
// Mishnu deposits cargo
self.meat += mishnu.humansHarvested;
mishnu.humansHarvested = 0;
LK.getSound('Factory_Deposit').play(); // Play deposit sound
updateFactoryText();
self.startProcessing();
}
// Add rumble effect when processing
if (self.processing) {
if (!isFactorySoundPlaying) {
LK.getSound('Factory_Operation').play({
loop: true
});
isFactorySoundPlaying = true;
}
self.rumbleTimer += 16; // Assume 16ms per frame
if (self.rumbleTimer >= 100) {
// Rumble every 100ms
factoryGraphics.x = Math.random() * 6 - 3; // Horizontal rumble
factoryGraphics.y = Math.random() * 6 - 3; // Vertical rumble
self.rumbleTimer = 0;
}
} else {
// Reset position when not processing
factoryGraphics.x = 0;
factoryGraphics.y = 0;
}
// Stop processing if out of meat
if (self.meat < 5 && self.processing) {
self.stopProcessing();
}
};
function triggerLevelTextShake() {
var shakeIntensity = 5; // Maximum shake offset in pixels
var shakeDuration = 500; // Duration of the shake in milliseconds
var elapsedTime = 0; // Tracks elapsed time
var originalX = factoryText.x; // Save the original x position
var originalY = factoryText.y; // Save the original y position
// Function to perform shaking
var shakeInterval = LK.setInterval(function () {
if (elapsedTime >= shakeDuration) {
LK.clearInterval(shakeInterval);
factoryText.x = originalX; // Reset to original position
factoryText.y = originalY;
return;
}
// Apply random offset for shaking
factoryText.x = originalX + (Math.random() * shakeIntensity * 2 - shakeIntensity);
factoryText.y = originalY + (Math.random() * shakeIntensity * 2 - shakeIntensity);
elapsedTime += 16; // Assume 16ms per frame (60 FPS)
}, 16);
}
function checkLevelProgression() {
if (self.dogFood >= self.nextLevelRequirement) {
checkForBossSpawn(); // Ensure boss spawns at every increment of 4 levels
self.level++;
if (self.level % 5 === 0) {
mishnu.harvestSpeed *= 0.75; // Increase harvest time by 60% every 5 levels
mishnu.speed *= 1.15; // Increase Mishnu's speed by 15%
humans.forEach(function (human) {
human.speedX *= 1.15; // Increase human speed by 15%
human.speedY *= 1.15;
});
zombies.forEach(function (zombie) {
zombie.speed *= 1.15; // Increase zombie speed by 15%
});
}
bossDefeated = false; // Reset bossDefeated for the new level
LK.getSound('Level_Up').play(); // Play level-up sound
self.nextLevelRequirement += Math.round(self.level * 1.5 + 5); // Further adjusted to reduce Mishnu Snax requirements
// Reset spawn counter and calculate new spawn limit
humansSpawnedThisLevel = 0;
humanSpawnLimit = self.nextLevelRequirement * 5;
// Trigger level-up animation
triggerLevelTextShake();
updateFactoryText();
spawnZombies(1, maxZombiesOnScreen); // Spawn a zombie when leveling up
}
}
});
// GlobalHealthBar Class
var GlobalHealthBar = Container.expand(function (initialHealth, maxHealth) {
var self = Container.call(this);
self.currentHealth = initialHealth;
self.maxHealth = maxHealth;
// Define frame dimensions if dynamic retrieval isn't available
var frameWidth = LK.getAsset('LK_Health_Bar', {}).width;
// Create filler (health bar inner part)
var filler = self.attachAsset('LK_Inner_Health_Bar', {
anchorX: 0,
// Anchor to the left
anchorY: 0.5,
// Center vertically
x: -frameWidth / 2,
// Align with the outer frame
// Start from the left edge of the frame
y: 0,
// Center vertically
scaleX: 1 // Fully filled initially
});
// Create frame (health bar outer part)
var frame = self.attachAsset('LK_Health_Bar', {
anchorX: 0.5,
// Center horizontally
anchorY: 0.5,
// Center vertically
x: 0,
// Centered relative to the container
y: 0 // Center vertically
});
// Update the visual representation of the health bar
self.updateHealth = function () {
// Ensure filler width matches current health
filler.scaleX = Math.max(0, self.currentHealth / self.maxHealth); // Scale proportionally
};
// Change health value
self.setHealth = function (newHealth) {
self.currentHealth = Math.max(0, Math.min(newHealth, self.maxHealth)); // Clamp between 0 and maxHealth
self.updateHealth();
if (self.currentHealth === 0) {
triggerGameOver();
}
};
// Change maximum health and adjust health proportionally
self.setMaxHealth = function (newMaxHealth) {
var healthRatio = self.currentHealth / self.maxHealth;
self.maxHealth = Math.max(1, newMaxHealth); // Ensure at least 1 max health
self.currentHealth = Math.min(self.currentHealth, self.maxHealth);
self.updateHealth();
};
// Initialize the health bar
self.setHealth(initialHealth);
return self;
});
// Declare healthBar globally for accessibility
// Assuming initial and max health are both 100
// Class for Mishnu's harvest radius
var HarvestRadius = Container.expand(function () {
var self = Container.call(this);
var radiusGraphics = self.attachAsset('radius', {
anchorX: 0.5,
anchorY: 0.5,
scaleX: 10,
scaleY: 10
});
self.radiusSize = 300; // Effective radius size
var rotationSpeed = 0.001; // Extremely slow rotation speed
self.update = function () {
self.x = mishnu.x;
self.y = mishnu.y;
// Apply slow rotation to the radius
radiusGraphics.rotation -= rotationSpeed;
};
return self;
});
// Define ColorMatrixFilter to fix 'filters is not defined' error
// Class for Humans
// Class for Humans
// Class for Humans
var Human = Container.expand(function () {
var self = Container.call(this);
var humanImages = ['Human_1', 'Human_2', 'Human_3', 'Human_4', 'Human_5', 'Human_6', 'Human_7', 'Human_8', 'human_9', 'Human_10', 'Human_11', 'Human_12', 'Human_13', 'Human_14', 'Human_15', 'Human_16', 'Human_17'];
var randomHumanImage = humanImages[Math.floor(Math.random() * humanImages.length)];
// Attach asset for the human graphic
var humanGraphics = self.attachAsset(randomHumanImage, {
anchorX: 0.5,
anchorY: 0.5
});
// Randomly generate a tint color avoiding too dark or too bright colors
function getRandomTint() {
var red = Math.floor(Math.random() * 156) + 50; // Between 50 and 205
var green = Math.floor(Math.random() * 156) + 50; // Between 50 and 205
var blue = Math.floor(Math.random() * 156) + 50; // Between 50 and 205
return red << 16 | green << 8 | blue;
}
var originalTint = getRandomTint();
humanGraphics.tint = originalTint; // Apply random tint
// 50/50 chance to flip horizontally
if (Math.random() < 0.5) {
humanGraphics.scale.x *= -1; // Flip horizontally
}
var bloodSplashes = [];
self.speedX = (Math.random() * 2 - 1) * 2;
self.speedY = (Math.random() * 2 - 1) * 2;
self.isBeingHarvested = false;
self.inRadiusStartTime = null;
self.currentAgonySound = null;
self.currentCrunchSound = null;
self.yellStarted = false; // Tracks if the yell has started
self.yellShouldPlay = Math.random() < 1 / 6; // 1-in-6 chance for yelling
self.crunchShouldPlay = Math.random() < 1 / 6; // 1-in-6 chance for crunch sound
self.flashTimer = 0; // Timer for red flashing
self.flashInterval = 500; // Initial interval for flashing
self.update = function () {
// Escape logic
self.x += self.speedX;
self.y += self.speedY;
// Keep humans within the viewport margins
var margin = 50;
var bottomMargin = 300; // Extra margin for bottom text box
if (self.x <= margin) {
self.x = margin;
self.speedX *= -1;
} else if (self.x >= 2048 - margin) {
self.x = 2048 - margin;
self.speedX *= -1;
}
if (self.y <= margin) {
self.y = margin;
self.speedY *= -1;
} else if (self.y >= 2432 - margin) {
self.y = 2432 - margin;
self.speedY *= -1;
}
// Check distance to Mishnu
var dx = self.x - mishnu.x;
var dy = self.y - mishnu.y;
var distance = Math.sqrt(dx * dx + dy * dy);
if (mishnu.humansHarvested >= mishnu.cargoMax * 1.5) {
// Stop all sounds when cargo exceeds 150% capacity
if (self.currentAgonySound !== null) {
fadeOutSound(self.currentAgonySound, 500);
}
if (self.currentCrunchSound) {
self.currentCrunchSound.stop();
}
self.isBeingHarvested = false;
return;
}
if (distance < radius.radiusSize - 2) {
if (!self.isBeingHarvested) {
var _self$currentCrunchSo;
self.isBeingHarvested = true;
self.inRadiusStartTime = Date.now();
self.flashTimer = 0;
bloodSplashes = [];
self.yellStarted = false;
// Play crunch sound if applicable
if (self.crunchShouldPlay) {
if (self.currentCrunchSound) {
self.currentCrunchSound.stop(); // Stop any currently playing crunch sound
}
self.currentCrunchSound = getRandomSound(['Dog_Crunch', 'Dog_Crunch_2', 'Dog_Crunch_3']);
self.currentCrunchSound.volume = 0.3;
self.currentCrunchSound.play();
}
} else {
// Calculate vibration intensity based on time in the radius
var elapsedTime = Date.now() - self.inRadiusStartTime;
var intensity = Math.min(1, elapsedTime / 3000); // Max intensity at 3 seconds
// Add vibration effect
humanGraphics.x = Math.random() * intensity * 10 - intensity * 5;
humanGraphics.y = Math.random() * intensity * 10 - intensity * 5;
// Escape logic during vibration
var runSpeed = 2; // Speed humans try to escape the radius
self.x += dx / distance * runSpeed;
self.y += dy / distance * runSpeed;
// Flash red effect
self.flashTimer += 16; // Assume a fixed delta of 16ms per frame
if (self.flashTimer >= self.flashInterval) {
self.flashTimer = 0;
// Toggle between red and the original tint
if (humanGraphics.tint === 0xeb0909) {
humanGraphics.tint = originalTint; // Reset to original tint
} else {
humanGraphics.tint = 0xeb0909; // Flash red
}
// Emit blood splash
var bloodSplash = game.addChild(new BloodSplash(self.x, self.y));
bloodSplashes.push(bloodSplash);
}
// Increase flash frequency closer to harvest
self.flashInterval = Math.max(100, 500 - elapsedTime / 3000 * 400);
// Start agony yell after 1 second of harvesting
if (elapsedTime > 1000 && !self.yellStarted && self.yellShouldPlay) {
self.yellStarted = true;
self.currentAgonySound = getRandomSound(['Agony_Yell_1', 'Agony_Yell_2', 'Agony_Yell_3', 'Agony_Yell_4', 'Agony_Yell_5', 'Agony_Yell_6', 'Agony_Yell_7', 'Agony_Yell_8', 'Agony_Yell_9', 'Agony_Yell_10']);
self.currentAgonySound.volume = 0.05;
self.currentAgonySound.play();
}
if (elapsedTime >= 3000 / mishnu.harvestSpeed) {
// Harvest after 3 seconds
if (mishnu.humansHarvested < mishnu.cargoMax * 1.5) {
game.removeChild(self); // Remove human from the game
humans.splice(humans.indexOf(self), 1); // Remove from array
mishnu.humansHarvested++;
// Stop yelling abruptly
if (self.currentAgonySound) {
self.currentAgonySound.stop();
}
// Play ding and squish sounds on harvest
LK.getSound('Ding_1').play();
getRandomSound(['Squish_1', 'Squish_2', 'Squish_3', 'Squish_4']).play();
// Final blood splashes
for (var i = 0; i < 10; i++) {
var bloodSplash = game.addChild(new BloodSplash(self.x, self.y, true));
bloodSplashes.push(bloodSplash);
}
}
}
}
} else {
// Reset harvesting state if outside the radius
if (self.isBeingHarvested) {
if (self.currentAgonySound && self.yellStarted) {
self.currentAgonySound.loop = false;
}
if (self.currentCrunchSound) {
self.currentCrunchSound.stop();
}
}
self.isBeingHarvested = false;
self.inRadiusStartTime = null;
self.flashTimer = 0;
humanGraphics.tint = originalTint; // Reset to original tint
bloodSplashes.forEach(function (splash) {
game.removeChild(splash);
});
}
};
return self;
});
// Laser Class
var Laser = Container.expand(function (startX, startY, targetX, targetY) {
var self = Container.call(this);
var laserGraphics = self.attachAsset('Laser', {
anchorX: 0.5,
anchorY: 0.5,
scaleX: 0.5,
scaleY: 0.5,
tint: 0xFF0000 // Red tint for lasers
});
self.x = startX;
self.y = startY;
var speed = 10;
var dx = targetX - startX;
var dy = targetY - startY;
var distance = Math.sqrt(dx * dx + dy * dy);
var velocityX = dx / distance * speed;
var velocityY = dy / distance * speed;
// Function to emit stars around the laser
self.emitStars = function () {
var sparkle = self.attachAsset('Stars', {
anchorX: 0.5,
anchorY: 0.5,
scaleX: Math.random() * 0.3 + 0.1,
scaleY: Math.random() * 0.3 + 0.1,
alpha: 1,
tint: 0xFFFFFF // Bright white sparkles
});
// Position sparkle randomly around the laser
var angle = Math.random() * Math.PI * 2;
var radius = (laserGraphics.width / 2 + Math.random() * 20 + 10) * (1 / 3); // Reduced radius by 2/3rds
sparkle.x = Math.cos(angle) * radius;
sparkle.y = Math.sin(angle) * radius;
// Set sparkle lifetime
var lifetime = Math.random() * 200 + 100; // Short lifespan
var elapsed = 0;
// Animate the sparkle
var interval = LK.setInterval(function () {
elapsed += 16; // Assume 16ms per frame
sparkle.y -= 0.2; // Subtle upward motion
sparkle.alpha = Math.max(0, 1 - elapsed / lifetime); // Gradual fade-out
if (elapsed >= lifetime) {
LK.clearInterval(interval);
self.removeChild(sparkle); // Remove sparkle after its lifetime
}
}, 16);
};
// Update laser behavior
self.update = function () {
self.x += velocityX;
self.y += velocityY;
// Emit stars around the laser
self.emitStars();
// Check collision with Mishnu
var mishnuDx = mishnu.x - self.x;
var mishnuDy = mishnu.y - self.y;
var mishnuDistance = Math.sqrt(mishnuDx * mishnuDx + mishnuDy * mishnuDy);
if (mishnuDistance < 50 && !self.hasHitMishnu) {
self.hasHitMishnu = true; // Mark as hit
if (self.isInViewport()) {
game.removeChild(self);
lasers.splice(lasers.indexOf(self), 1);
}
// Deduct 2hp from globalHealthBar and update its visual representation
globalHealthBar.setHealth(globalHealthBar.currentHealth - 2);
globalHealthBar.updateHealth();
flashGreyMask([mishnu, radius, globalHealthBar], 400, 3);
LK.getSound('searing').play();
if (!self.barkPlaying) {
self.barkPlaying = true;
LK.setTimeout(function () {
var barks = ['Bark', 'Bark_2', 'Bark_3'];
var barkSound = LK.getSound(barks[Math.floor(Math.random() * barks.length)]);
barkSound.play();
barkSound.on('end', function () {
self.barkPlaying = false;
});
}, 200);
}
}
// Remove if out of viewport
if (!self.isInViewport()) {
game.removeChild(self);
}
};
// Check if laser is within the viewport
self.isInViewport = function () {
return self.x >= -50 && self.x <= 2048 + 50 && self.y >= -50 && self.y <= 2432 + 50;
};
self.hasHitMishnu = false; // Initialize hit flag
return self;
});
// Add boss spawning at level 2
// Class for Mishnu
var Mishnu = Container.expand(function () {
var self = Container.call(this);
var mishnuGraphics = self.attachAsset('mishnu', {
anchorX: 0.5,
anchorY: 0.5,
zIndex: 1
});
self.speed = 4;
self.humansHarvested = 0;
self.cargoMax = 10;
self.targetX = 2048 / 2;
self.targetY = 2432 - 200;
self.update = function () {
var dx = self.targetX - self.x;
var dy = self.targetY - self.y;
var distance = Math.sqrt(dx * dx + dy * dy);
// Adjust speed based on cargo
if (self.humansHarvested > self.cargoMax) {
var overCapacityFactor = (self.humansHarvested - self.cargoMax) / (self.cargoMax * 0.5);
self.speed = Math.max(1, 4 - 3 * overCapacityFactor); // Minimum speed of 1
} else {
self.speed = 4; // Full speed
}
if (distance > 0) {
self.x += dx / distance * self.speed;
self.y += dy / distance * self.speed;
}
// Keep Mishnu within viewport margins
var margin = 50;
var bottomMargin = 300; // Extra margin for bottom text box
self.x = Math.max(margin, Math.min(2048 - margin, self.x));
self.y = Math.max(margin, Math.min(2432 - bottomMargin, self.y));
// Shoot bones if a boss is present
if (boss && boss.alienHealthBar.currentHealth > 0 && Math.random() < 0.01) {
// Random chance to shoot
var oppositeX = self.x - (self.targetX - self.x);
var oppositeY = self.y - (self.targetY - self.y);
var bone = new Bone(self.x, self.y, oppositeX, oppositeY);
game.addChild(bone);
}
};
// Create and position the health bar at the top center of the viewport
globalHealthBar.x = 1820; // Center horizontally
globalHealthBar.y = 2560; // Position at the top center
uiLayer.addChild(globalHealthBar); // Add to the UI layer to ensure visibility
return self;
});
var Zombie = Container.expand(function () {
var self = Container.call(this);
// Add the zombie graphics
var zombieGraphics = self.attachAsset('Zombie', {
anchorX: 0.5,
anchorY: 0.5
});
// Helper function to get a color based on the level
function getColorForLevel(level) {
var colors = [0xFF0000,
// Bright red
0x00FF00,
// Bright green
0x0000FF,
// Bright blue
0xFFFF00,
// Bright yellow
0xFF00FF,
// Bright magenta
0x00FFFF,
// Bright cyan
0xFFA500,
// Bright orange
0x800080,
// Bright purple
0xFFFFFF,
// Bright white
0xFFC0CB // Bright pink
];
return colors[level % colors.length]; // Cycle through colors
}
// Set zombie attributes dynamically based on factory level
function initializeZombie(level) {
zombieGraphics.tint = getColorForLevel(level); // Set vivid color
self.harvestTime = 4000 + level * 500; // Increase harvest time with level
}
// Call the initializer with the current factory level
initializeZombie(factory.level);
// Attributes
self.speed = 2;
self.attackCooldown = 3000; // Cooldown (ms) between attacks
self.lastAttackTime = 0; // Tracks the last attack time
self.state = 'roaming'; // Initial state
self.targetX = Math.random() * 2048; // Random initial roaming target
self.targetY = Math.random() * 2432;
self.inRadiusStartTime = null; // Time zombie entered Mishnu's radius
var agonySound = null;
var harvestSoundPlayed = false;
var flashingInterval = null; // Interval for flashing effect
var vibratingInterval = null; // Interval for vibrating effect
var flashTimer = 0; // Timer for red flashing
var flashInterval = 500; // Initial interval for flashing
// Helper function: Generate a random roaming target
function setRandomTarget() {
self.targetX = Math.random() * 2048;
self.targetY = Math.random() * 2432;
}
// Helper function: Move to a target
function moveToTarget(targetX, targetY) {
var speedMultiplier = arguments.length > 2 && arguments[2] !== undefined ? arguments[2] : 1;
var dx = targetX - self.x;
var dy = targetY - self.y;
var distance = Math.sqrt(dx * dx + dy * dy);
if (distance > 1) {
self.x += dx / distance * self.speed * speedMultiplier;
self.y += dy / distance * self.speed * speedMultiplier;
} else {
setRandomTarget();
}
}
// Add flashing red effect
function startFlashing() {
var flashing = false;
flashingInterval = LK.setInterval(function () {
zombieGraphics.tint = flashing ? 0xFF0000 : getColorForLevel(factory.level);
flashing = !flashing;
}, 100);
}
function stopFlashing() {
if (flashingInterval) {
LK.clearInterval(flashingInterval);
flashingInterval = null;
zombieGraphics.tint = getColorForLevel(factory.level);
}
}
// Add vibrating effect
function startVibrating() {
vibratingInterval = LK.setInterval(function () {
self.x += Math.random() * 4 - 2; // Vibrate by a small random offset
self.y += Math.random() * 4 - 2;
}, 16);
}
function stopVibrating() {
if (vibratingInterval) {
LK.clearInterval(vibratingInterval);
vibratingInterval = null;
}
}
// Add sparkles
function emitStars() {
var sparkle = self.attachAsset('Stars', {
anchorX: 0.5,
anchorY: 0.5,
scaleX: Math.random() * 0.3 + 0.1,
scaleY: Math.random() * 0.3 + 0.1,
alpha: 1,
tint: 0xFFFFFF // Bright white sparkles
});
var angle = Math.random() * Math.PI * 2;
var radius = zombieGraphics.width / 2 + Math.random() * 20 + 10;
sparkle.x = Math.cos(angle) * radius;
sparkle.y = Math.sin(angle) * radius;
var lifetime = Math.random() * 200 + 100;
var elapsed = 0;
var interval = LK.setInterval(function () {
elapsed += 16;
sparkle.y -= 0.2;
sparkle.alpha = Math.max(0, 1 - elapsed / lifetime);
if (elapsed >= lifetime) {
LK.clearInterval(interval);
self.removeChild(sparkle);
}
}, 16);
}
// Emit sparkles periodically
LK.setInterval(emitStars, 200);
// Add blood splashes
function addBloodSplashes() {
var isFinal = arguments.length > 0 && arguments[0] !== undefined ? arguments[0] : false;
var count = isFinal ? 10 : 1;
for (var i = 0; i < count; i++) {
game.addChild(new BloodSplash(self.x, self.y, isFinal));
}
}
// Update behavior
self.update = function () {
var dx = mishnu.x - self.x;
var dy = mishnu.y - self.y;
var distanceToMishnu = Math.sqrt(dx * dx + dy * dy);
switch (self.state) {
case 'roaming':
moveToTarget(self.targetX, self.targetY);
if (distanceToMishnu < radius.radiusSize) {
self.state = 'attacking';
self.inRadiusStartTime = Date.now();
startFlashing();
startVibrating();
flashTimer = 0;
flashInterval = 500;
if (Math.random() < 1 / 5) {
agonySound = getRandomSound(['GiggleMan_1', 'GiggleMan_2', 'GiggleMan_3', 'GiggleMan_4', 'GiggleMan_5']);
agonySound.volume = 0.3;
agonySound.play();
}
}
break;
case 'attacking':
moveToTarget(mishnu.x, mishnu.y, 1.5);
if (distanceToMishnu < radius.radiusSize) {
var elapsedTime = Date.now() - self.inRadiusStartTime;
var intensity = Math.min(1, elapsedTime / 3000);
// Vibration effect
zombieGraphics.x = Math.random() * intensity * 10 - intensity * 5;
zombieGraphics.y = Math.random() * intensity * 10 - intensity * 5;
// Flash red effect
flashTimer += 16;
if (flashTimer >= flashInterval) {
flashTimer = 0;
zombieGraphics.tint = zombieGraphics.tint === 0xFF0000 ? getColorForLevel(factory.level) : 0xFF0000;
flashInterval = Math.max(100, 500 - elapsedTime / 3000 * 400);
}
if (elapsedTime >= self.harvestTime / mishnu.harvestSpeed) {
self.state = 'harvested';
game.removeChild(self);
zombies.splice(zombies.indexOf(self), 1);
mishnu.humansHarvested += 2;
if (!harvestSoundPlayed) {
LK.getSound('Ding_1').play();
getRandomSound(['Squish_1', 'Squish_2', 'Squish_3', 'Squish_4']).play();
harvestSoundPlayed = true;
}
addBloodSplashes(true);
stopFlashing();
stopVibrating();
return;
}
if (distanceToMishnu < 50 && Date.now() - self.lastAttackTime > self.attackCooldown) {
globalHealthBar.setHealth(globalHealthBar.currentHealth - 1);
self.lastAttackTime = Date.now();
self.state = 'fleeing';
var fleeAngle = Math.random() * Math.PI * 2;
self.targetX = mishnu.x + Math.cos(fleeAngle) * (radius.radiusSize + 50);
self.targetY = mishnu.y + Math.sin(fleeAngle) * (radius.radiusSize + 50);
addBloodSplashes();
flashGreyMask([mishnu, radius, globalHealthBar], 400, 3);
LK.getSound('Hit').play();
LK.setTimeout(function () {
var barks = ['Bark', 'Bark_1', 'Bark_2'];
LK.getSound(barks[Math.floor(Math.random() * barks.length)]).play();
}, 200);
}
} else {
self.state = 'roaming';
setRandomTarget();
stopFlashing();
stopVibrating();
}
break;
case 'fleeing':
moveToTarget(self.targetX, self.targetY, 2);
if (distanceToMishnu > radius.radiusSize + 50) {
self.state = 'roaming';
setRandomTarget();
stopFlashing();
stopVibrating();
}
break;
case 'harvested':
break;
default:
console.error("Zombie in unknown state: ".concat(self.state));
self.state = 'roaming';
setRandomTarget();
stopFlashing();
stopVibrating();
break;
}
};
// Set initial target
setRandomTarget();
return self;
});
/****
* Initialize Game
****/
// Modify game logic to include zombie spawning
// Declare healthBar globally for accessibility
var game = new LK.Game({
backgroundColor: 0x1d1d1d
});
/****
* Game Code
****/
function triggerGameOver() {
// Freeze all game elements
LK.showGameOver();
// Create a black mask over the entire viewport
var blackMask = new Container();
var maskGraphics = blackMask.attachAsset('Blue_Mask', {
anchorX: 0.5,
anchorY: 0.5,
scaleX: 2048 / 100,
scaleY: 2732 / 100,
tint: 0x000000,
alpha: 0.7
});
blackMask.x = 2048 / 2;
blackMask.y = 2732 / 2;
game.addChild(blackMask);
// Display Game Over image much larger and positioned higher
var gameOverImage = LK.getAsset('Game_Over', {
anchorX: 0.5,
anchorY: 0.5
});
gameOverImage.scaleX = 8; // Scale up the image 5 times
gameOverImage.scaleY = 8; // Maintain proportional scaling
gameOverImage.x = 2048 / 2;
gameOverImage.y = 2732 / 3 - 400; // Position about 800 pixels higher
game.addChild(gameOverImage);
}
var bossDefeated = false;
var isFactorySoundPlaying = false; // Flag to track if factory sound is playing
var lasers = [];
var bones = []; // Initialize bones array to store bone objects
// Initialize lastIntersecting property for each bone
bones.forEach(function (bone) {
bone.lastIntersecting = false;
bone.fadeOutTimer = null; // Initialize fadeOutTimer for each bone
bone.update = function () {
// Check for collision with the boss
if (!bone.lastIntersecting && bone.intersects(boss)) {
// Reduce boss health
alienHealthBar.setHealth(alienHealthBar.currentHealth - 1);
// Play a random boss hit sound
getRandomSound(['Boss_Hit', 'Boss_Hit_2', 'Boss_Hit_3']).play();
// Remove the bone
game.removeChild(bone);
bones.splice(bones.indexOf(bone), 1);
}
// Update last intersecting state
bone.lastIntersecting = bone.intersects(boss);
};
});
// Add boss spawning at level 2
// Define ColorMatrixFilter to fix 'filters is not defined' error
// Booster spawning logic
// Booster spawning logic
// Declare healthBar globally for accessibility
// Modify game logic to include zombie spawning
var bossSpawned = false;
var boss; // Define boss globally
// Removed global alienHealthBar initialization and rendering
function isMultipleOfFour(level) {
return level % 4 === 0;
}
function checkForBossSpawn() {
if (isMultipleOfFour(factory.level) && !bossSpawned && !bossDefeated && (!boss || boss.alienHealthBar.currentHealth === 0)) {
boss = new Boss();
game.addChild(boss);
bossSpawned = true; // Set bossSpawned flag
}
}
// Update game loop to include boss logic
var originalGameUpdate = game.update;
game.update = function () {
originalGameUpdate.call(this);
checkForBossSpawn();
if (boss && boss.alienHealthBar.currentHealth === 0) {
// Ensure boss is removed from the game
game.removeChild(boss);
boss = null;
bossSpawned = false; // Reset bossSpawned flag
// Disable further interactions with the boss
bones.forEach(function (bone) {
if (bone.intersects(boss)) {
game.removeChild(bone);
bones.splice(bones.indexOf(bone), 1);
}
});
// Clear any remaining boss-related sounds or effects
lasers.forEach(function (laser) {
game.removeChild(laser);
});
lasers = [];
}
};
var boosters = [];
function spawnBooster() {
var booster = new Booster();
boosters.push(booster);
game.addChild(booster);
}
// Integrate boosters with Mishnu Snax increase
var uiLayer = new Container();
uiLayer.zIndex = 10; // Ensure it's above the background and mask
game.addChild(uiLayer);
var factory = uiLayer.addChild(new Factory());
var originalIncreaseDogFood = factory.startProcessing;
factory.startProcessing = function () {
originalIncreaseDogFood.call(factory);
// Reduce booster spawn rate as levels increase
if (factory.level % Math.max(1, Math.floor(factory.level / 3)) === 0) {
spawnBooster(); // Spawn boosters less frequently as level increases
}
};
// Mishnu pickup logic
function checkBoosterPickup() {
boosters.forEach(function (booster) {
var dx = booster.x - mishnu.x;
var dy = booster.y - mishnu.y;
if (Math.sqrt(dx * dx + dy * dy) < 50) {
booster.pickUp();
game.removeChild(booster); // Ensure booster is removed from the game
boosters.splice(boosters.indexOf(booster), 1);
}
});
}
// Add to game update loop
var originalGameUpdate = game.update;
game.update = function () {
originalGameUpdate.call(this);
boosters.forEach(function (booster) {
booster.update();
});
checkBoosterPickup();
};
var globalHealthBar = new GlobalHealthBar(100, 100);
function spawnZombies(count, maxZombiesOnScreen) {
for (var i = 0; i < count; i++) {
if (boss && boss.alienHealthBar.currentHealth > 0) {
return; // Do not spawn zombies if the boss is present and alive
}
if (zombies.length >= maxZombiesOnScreen) {
break;
}
var spawnEdge = Math.floor(Math.random() * 3); // 0: top, 1: left, 2: right
var spawnX, spawnY;
switch (spawnEdge) {
case 0:
spawnX = Math.random() * 2048;
spawnY = -50;
break;
case 1:
spawnX = -50;
spawnY = Math.random() * (2432 - 300);
break;
case 2:
spawnX = 2048 + 50;
spawnY = Math.random() * (2432 - 300);
break;
}
var newZombie = new Zombie();
newZombie.x = spawnX;
newZombie.y = spawnY;
zombies.push(newZombie);
game.addChild(newZombie);
}
}
// Initialize zombies
var zombies = [];
var zombieSpawnCooldown = 3000; // Time (ms) between zombie spawn attempts
var zombieSpawnElapsedTime = 0;
var maxZombiesOnScreen = 10;
// Update game loop to handle zombies
var originalGameUpdate = game.update;
game.update = function () {
originalGameUpdate.call(this);
// Update zombies
zombies.forEach(function (zombie) {
zombie.update();
});
// Spawn zombies if needed
zombieSpawnElapsedTime += 16; // Assume 16ms per frame
if (zombieSpawnElapsedTime >= zombieSpawnCooldown && zombies.length < maxZombiesOnScreen) {
spawnZombies(1, maxZombiesOnScreen); // Spawn one zombie at a time
zombieSpawnElapsedTime = 0;
}
// Ensure zombie count does not exceed maximum
if (zombies.length > maxZombiesOnScreen) {
while (zombies.length > maxZombiesOnScreen) {
var zombieToRemove = zombies.pop();
game.removeChild(zombieToRemove);
}
}
};
var isMusicPlaying = {
'Music_Level_1_4': false,
'Music_Level_1_5': false
};
// Update factory text
function updateFactoryText() {
factoryText.setText("Level: " + factory.level + "\nMeat: " + factory.meat + "\nMishnu Snax: " + factory.dogFood + "\nNext level at: " + factory.nextLevelRequirement);
}
// Function to randomly select a sound from a list
;
// Add a UI layer to ensure factory is rendered above the background and mask
var uiLayer = new Container();
uiLayer.zIndex = 10; // Ensure it's above the background and mask
game.addChild(uiLayer);
// Create and position the health bar at the top center of the viewport
var globalHealthBar = new GlobalHealthBar(5, 5); // Initialize with initial and max health of 5
globalHealthBar.x = 1820; // Center horizontally
globalHealthBar.y = 2560; // Position at the top center
// Add text label 'Health' above the global health bar
var healthLabel = new Text2('Health', {
size: 50,
fill: 0xFFFFFF
});
healthLabel.anchor.set(0.5, 1);
healthLabel.x = globalHealthBar.x;
healthLabel.y = globalHealthBar.y - 60; // Position above the health bar
uiLayer.addChild(healthLabel);
uiLayer.addChild(globalHealthBar); // Add to the UI layer to ensure visibility
// Add the factory to the UI layer
var factory = uiLayer.addChild(new Factory());
// Initialize factory text
var factoryText = new Text2('Meat: 0\nMishnu Snax: 0\nNext level at: ', {
size: 50,
fill: 0xFFFFFF,
align: 'left'
});
factoryText.anchor.set(0, 1);
LK.gui.bottomLeft.addChild(factoryText);
var nextLevel = 100; // Placeholder for next level goal
// Function to randomly spawn a human at the edges of the viewport
function spawnHumans(count, maxHumansOnScreen) {
var hardCap = 100; // Maximum number of humans allowed
if (boss && boss.alienHealthBar.currentHealth > 0) {
return; // Do not spawn humans if the boss is present and alive
}
if (factory.level % 4 === 0 && boss && boss.alienHealthBar.currentHealth > 0) {
return; // Wait for boss to be defeated before spawning humans
}
for (var i = 0; i < count; i++) {
if (humans.length >= maxHumansOnScreen || humans.length >= hardCap) {
break;
}
// Randomly select a spawn edge (excluding the bottom)
var spawnEdge = Math.floor(Math.random() * 3); // 0: top, 1: left, 2: right
var spawnX, spawnY;
switch (spawnEdge) {
case 0:
// Top
spawnX = Math.random() * 2048;
spawnY = -50; // Just outside the top boundary
break;
case 1:
// Left
spawnX = -50; // Just outside the left boundary
spawnY = Math.random() * (2432 - 300); // Exclude bottom UI area
break;
case 2:
// Right
spawnX = 2048 + 50; // Just outside the right boundary
spawnY = Math.random() * (2432 - 300); // Exclude bottom UI area
break;
}
// Create a new human and add it to the game
var newHuman = new Human();
newHuman.x = spawnX;
newHuman.y = spawnY;
humans.push(newHuman);
game.addChild(newHuman);
}
}
// Update game loop
var originalUpdate = game.update;
game.update = function () {
originalUpdate.call(this);
// Update factory
factory.update();
// Check for level progression
if (factory.dogFood >= nextLevel) {
// Handle level progression logic here
nextLevel += 100; // Example: increase next level goal
updateFactoryText();
}
};
function flashGreyMask(targets, duration, flashes) {
var flashInterval = duration / (flashes * 2); // Time for each flash on/off
var flashCount = 0;
var interval = LK.setInterval(function () {
if (flashCount >= flashes * 2) {
// End the flashing effect
targets.forEach(function (target) {
if (target && typeof target.tint !== 'undefined') {
target.tint = 0xFFFFFF;
}
}); // Reset tint
LK.clearInterval(interval);
} else {
var isOn = flashCount % 2 === 0; // Toggle between grey and normal
var tintColor = isOn ? 0x808080 : 0xFFFFFF; // Grey tint or original
targets.forEach(function (target) {
if (target && typeof target.tint !== 'undefined') {
target.tint = tintColor;
}
}); // Apply tint
flashCount++;
}
}, flashInterval);
}
function getRandomSound(soundList) {
return LK.getSound(soundList[Math.floor(Math.random() * soundList.length)]);
}
// Function to fade out a sound
function fadeOutSound(sound, duration) {
var initialVolume = sound.volume;
var fadeStep = initialVolume / (duration / 100);
var fadeInterval = LK.setInterval(function () {
if (sound.volume > 0) {
sound.volume = Math.max(0, sound.volume - fadeStep);
} else {
LK.clearInterval(fadeInterval);
sound.stop();
}
}, 100);
}
var radius = game.addChild(new HarvestRadius());
var mishnu = game.addChild(new Mishnu());
mishnu.harvestSpeed = 1; // Initialize harvest speed
mishnu.x = 2048 / 2;
mishnu.y = 2432 - 200;
radius.x = mishnu.x;
radius.y = mishnu.y;
// Initialize humans
var humans = [];
for (var i = 0; i < 50; i++) {
var human = new Human();
human.x = Math.random() * 2048;
human.y = Math.random() * (2432 - 100);
humans.push(human);
game.addChild(human);
var humansSpawnedThisLevel = 0; // Tracks how many humans have spawned in the current level
var humanSpawnLimit = factory.nextLevelRequirement * 7; // Set minimum spawn limit to nextLevelRequirement * 7
}
var spawnCooldown = 20; // Reduced time (in ms) between spawn attempts for faster spawning
var spawnElapsedTime = 0; // Tracks time elapsed since the last spawn attempt
// Play looping Dog Panting sound
LK.getSound('Dog_panting').play({
loop: true
});
// Handle mouse movement
game.move = function (x, y, obj) {
mishnu.targetX = x;
mishnu.targetY = y;
};
// Display cargo count
var cargoText = new Text2('Cargo: 0 / 10', {
size: 50,
fill: 0xFFFFFF
});
cargoText.anchor.set(1, 1);
LK.gui.bottomRight.addChild(cargoText);
// Music alternation logic
var currentMusic = 'Music_Level_1_5';
game.update = function () {
humans.forEach(function (human) {
human.update();
});
mishnu.update();
zombies.forEach(function (zombie) {
zombie.update();
});
radius.update();
boosters.forEach(function (booster) {
booster.update();
});
checkBoosterPickup();
checkForBossSpawn();
// Calculate dynamic minimum and maximum humans on screen
var minHumansOnScreen = Math.max((factory.nextLevelRequirement - factory.dogFood) * 7, 20); // Ensure a minimum of 20
var maxHumansOnScreen = Math.ceil(minHumansOnScreen * 1.5); // Scale max to 150% of min
// Ensure minimum number of humans on screen
if (humans.length < minHumansOnScreen) {
spawnElapsedTime += 16; // Assume 16ms per frame
if (spawnElapsedTime >= spawnCooldown) {
spawnHumans(minHumansOnScreen - humans.length, maxHumansOnScreen); // Pass the maxHumansOnScreen value
spawnElapsedTime = 0; // Reset spawn elapsed time
}
}
// Cap the number of humans to maxHumansOnScreen
if (humans.length > maxHumansOnScreen) {
// Remove excess humans from the game
while (humans.length > maxHumansOnScreen) {
var humanToRemove = humans.pop();
game.removeChild(humanToRemove);
}
}
// Update cargo text
var textColor = mishnu.humansHarvested > mishnu.cargoMax ? 0xFF0000 : 0xFFFFFF;
if (cargoText.fill !== textColor) {
LK.gui.bottomRight.removeChild(cargoText);
cargoText = new Text2('Cargo: ' + mishnu.humansHarvested + ' / ' + mishnu.cargoMax, {
size: 50,
fill: textColor
});
cargoText.anchor.set(1, 1);
LK.gui.bottomRight.addChild(cargoText);
} else {
cargoText.setText('Cargo: ' + mishnu.humansHarvested + ' / ' + mishnu.cargoMax);
}
// Play Music_Level_1_4 in a loop
if (!isMusicPlaying['Music_Level_1_4']) {
LK.playMusic('Music_Level_1_4', {
loop: true
});
isMusicPlaying['Music_Level_1_4'] = true; // Track music state
}
// Play Music_Level_1_5 in a loop
if (!isMusicPlaying['Music_Level_1_5']) {
LK.playMusic('Music_Level_1_5', {
loop: true
});
isMusicPlaying['Music_Level_1_5'] = true; // Track music state
}
// Update factory
factory.update();
};
// Function to emit stars around the laser
function emitStars() {
var sparkle = self.attachAsset('Stars', {
anchorX: 0.5,
anchorY: 0.5,
scaleX: Math.random() * 0.3 + 0.1,
scaleY: Math.random() * 0.3 + 0.1,
alpha: 1,
tint: 0xFFFFFF // Bright white sparkles
});
// Position sparkle randomly around the laser
var angle = Math.random() * Math.PI * 2;
var radius = laserGraphics.width / 2 + Math.random() * 20 + 10; // Moderate radius
sparkle.x = Math.cos(angle) * radius;
sparkle.y = Math.sin(angle) * radius;
// Set sparkle lifetime
var lifetime = Math.random() * 200 + 100; // Short lifespan
var elapsed = 0;
// Animate the sparkle
var interval = LK.setInterval(function () {
elapsed += 16; // Assume 16ms per frame
sparkle.y -= 0.2; // Subtle upward motion
sparkle.alpha = Math.max(0, 1 - elapsed / lifetime); // Gradual fade-out
if (elapsed >= lifetime) {
LK.clearInterval(interval);
self.removeChild(sparkle); // Remove sparkle after its lifetime
}
}, 16);
}
// ---------------------------
// End of game initialization code
// Now add the tips overlay so it loads last
// ---------------------------
// Create a container that covers the entire viewport
var tipsOverlay = new Container();
tipsOverlay.interactive = true; // Enable interaction
// Set a hit area covering the full screen (2048×2732)
tipsOverlay.hitArea = new Rectangle(0, 0, 2048, 2732);
tipsOverlay.x = 0;
tipsOverlay.y = 0;
// Attach the first tip image (Tips_1) using LK.init/attachAsset
// Since Tips_1 is 1024x1366, doubling it (scale factor 2) fills the screen.
var tipsGraphics = tipsOverlay.attachAsset('Tips_1', {
anchorX: 0,
anchorY: 0,
scaleX: 2,
scaleY: 2,
alpha: 1
});
var tipState = 1;
// Use the engine's built-in 'down' event handler for the container
tipsOverlay.down = function (x, y, event) {
console.log("Down event triggered, tipState:", tipState);
if (tipState === 1) {
// First tap: switch from Tips_1 to Tips_2 by removing the current asset and attaching the new one.
tipsOverlay.removeChild(tipsGraphics);
tipsGraphics = tipsOverlay.attachAsset('Tips_2', {
anchorX: 0,
anchorY: 0,
scaleX: 2,
scaleY: 2,
alpha: 1
});
tipState = 2;
} else {
// Second tap: remove the overlay and start the game
game.removeChild(tipsOverlay);
startGame();
}
};
// Add the overlay last so it appears on top
game.addChild(tipsOverlay);
function startGame() {
console.log("Game started!");
// Insert your game-start logic here.
}
blurry texture background 4k black and white
can of Dog Food. Game asset. 3d clipart. Blank background. High contrast. No shadows..
black capsule. Game asset. 3d clipart. Blank background. High contrast. No shadows..
woman in short shorts. mobile game art. pixel art. full body. front facing. Blank background. High contrast. No shadows.
laser beam cartoon game asset. Single Game Texture. In-Game asset. 2d. Blank background. High contrast. No shadows.
bone. clipart. cartoon. Blank background. High contrast. No shadows..
Game Over. Red game letters, dripping. Single Game Texture. In-Game asset. 2d. Blank background. High contrast. No shadows.
Dog_panting
Sound effect
Agony_Yell_1
Sound effect
Music_Level_1_5
Music
Music_Level_1_4
Music
Agony_Yell_2
Sound effect
Agony_Yell_3
Sound effect
Agony_Yell_4
Sound effect
Agony_Yell_5
Sound effect
Agony_Yell_6
Sound effect
Agony_Yell_7
Sound effect
Dog_Crunch
Sound effect
Dog_Crunch_2
Sound effect
Dog_Crunch_3
Sound effect
Ding_1
Sound effect
Squish_1
Sound effect
Squish_2
Sound effect
Squish_4
Sound effect
Squish_3
Sound effect
Factory_Deposit
Sound effect
Factory_Operation
Sound effect
Level_Up
Sound effect
Bark
Sound effect
Hit
Sound effect
Agony_Yell_8
Sound effect
Agony_Yell_9
Sound effect
GiggleMan_1
Sound effect
GiggleMan_2
Sound effect
GiggleMan_3
Sound effect
GiggleMan_4
Sound effect
Booster_Sound
Sound effect
Can
Sound effect
woosh
Sound effect
Agony_Yell_10
Sound effect
Bark_2
Sound effect
Bark_3
Sound effect
laser
Sound effect
searing
Sound effect
laser_2
Sound effect
Laser_3
Sound effect
Laser_4
Sound effect
Boss_Hit
Sound effect
Boss_Hit_2
Sound effect
Boss_Hit_3
Sound effect
GiggleMan_5
Sound effect
GiggleMan_6
Sound effect
hip_hop_loop
Sound effect