User prompt
the wendigo doenst walk throught during twisted blood moon/full moon
User prompt
can you add 2 more emotions AND can you make an aura for mouse thats 150 pixels big (and is able to show) and when that aura touches the cabin OR campfire the mouse isnt able to get targeted by everything except shadows and spiders dont move can you make spiders move (also shadows dont spawn can you fix that to) ↪💡 Consider importing and using the following plugins: @upit/tween.v1
User prompt
can you also make it so that the npcs dont get a speedboost when they are going to the cabin (and get slowness in bloodmoon) and also add emotion tints (for fear/stress(they are more likely to get targeted) angry (get slowness) hapiness(cooldown reduced 1.5x speedboost but theyre hitbox becomes bigger and get slowed if theyre close to save spaces) sadness(doesnt get targeted by wendigo,zombie or vampires but cant enter safe spaces) normal (they dont gain any debuffs nor bufs) these emotions can come from certain thins (also let all npcs being able to interact with eachother) pretty please ↪💡 Consider importing and using the following plugins: @upit/tween.v1
User prompt
uhm can you add a bird npc (whos based on surviving and YOU can choos the abillities) and an enemy (a spider and a shadow monster) also the hedgehog charge has to be ALOT longer ↪💡 Consider importing and using the following plugins: @upit/tween.v1
User prompt
can you also when an npc spawns play that npcs sound and let them come from either the bottem,left or right side and going to the campfire ↪💡 Consider importing and using the following plugins: @upit/tween.v1
User prompt
also can you make a different campfire thats out when its day
User prompt
can you make it so that during full moon the wendigo does apear but doesnt attack
User prompt
can you add a way where zombies are able to mutate and become better ↪💡 Consider importing and using the following plugins: @upit/tween.v1
User prompt
can you also add a robot touch and kill sound aswell as a hedgehog touch and kill sound
User prompt
can you fix that the robot doesnt place down the makeshif cabin and also that the fennec can pick up berries
User prompt
can you fix Compilation error[L4760]: TypeError: npcs[i].exitCabin is not a function
User prompt
can you fix that the fennec fox doesnt pick up berries and can you let berries despawn
User prompt
the hedgehog need a touch kill spindash and a recharge sound and the makeshift cabin from the robot has to be in the assets (it will look different than the normal cabin) can you please do that pretty please
User prompt
also the robot doesnt place down the "makeshift" cabin (also only 1 npc can go into the "makeshift" cabin) and the deer/bunny can also throw the berrys in the "makeshift cabin/generator" to upgrade their berrys (the deers berry reduces 40% of the cooldown and the bunny reduces 20% of the cooldown) also the deer still wont collec berries (and most of the auras dont apear until the next day) can you please please fix that and also the shield only apears when the robot is CLOSE to the campfire and the hedgehog and robot dont have touch and kill sounds please ↪💡 Consider importing and using the following plugins: @upit/tween.v1
User prompt
Please fix the bug: 'TypeError: npcs[i].enterCabin is not a function' in or related to this line: 'npcs[i].enterCabin();' Line Number: 4504
User prompt
Please fix the bug: 'TypeError: npc.setRarityVisual is not a function' in or related to this line: 'npc.setRarityVisual(); // Apply visual indication based on rarity' Line Number: 4328
User prompt
the deer doesnt collect berries during the day and the fennec fox has to actually move around and not stay at the campfire ↪💡 Consider importing and using the following plugins: @upit/tween.v1
User prompt
can you make 2 new npc classes a hedgehog and a robot HEDGEHOG(uncommon) he has a 20% to go in a kind of sleeping state both day and night (it detects every 5 seconds) but he charges up a "spindash" (kinda like sonic) that he can use for enemys he has an aura around him the more he charges it the bigger it grows(it starts at 50 pixels but each time he charges he it increases by 50 pixels) also only him,mouse AND fennec get speed in blood moon(2x) the rest gets slowed down(divided by 2) hedgehog can also CARRY targeted npcs (thoughts carrying targeted npc>stunning>recharging) also if hes recharging/charging closeby berries (100 pixels) are dragged to the hedgehog wich doesnt increase the score but makes his range 20 pixels bigger (after charging) Robot: has 2 abbilitys and 1 passive hes a very slow character the SLOWEST of them all but has and aura of 200 pixels (during all night stages) he has an electric shield that only activates when hes close to the fire and it makes him unable to move(hes able to willingly turn it off but after turning it off he gets stunned for 5 seconds) the shield kills 2 enemys and then the shield breaks haveing a 20 second cooldown and he has 4 HP (the highest in the game) after that he is the only one that can actually change the environment (for now) as he can technichly make a make shift cabin but it only stays for 1 night after also when he gets hit hes he stuns all the enemys for 3 seconds LONGER than normal (except wendigo) when he dies he also explodes letting every enemy get scared of (so bloodmoon,full moon and night turn into peacefull night when he dies) his rarity is uncommon but he has a 30% chance of spawning instead of 35% ↪💡 Consider importing and using the following plugins: @upit/tween.v1
User prompt
the aura doesnt apear around the bunn or deer
User prompt
also can you make it so that the deer AND the bunny are able to hold berries and GIVE berries to other npcs reducing their abbility cooldowns by 20% for deer and 10% for bunny (it doesnt give points and you can SEE the deer/bunny holding onto the berry) ↪💡 Consider importing and using the following plugins: @upit/tween.v1
User prompt
hey can i rework the bunny AND the deer okay so the bunny collects a bigger range (100 pixels) but gets a 8x speed boost for 3 seconds also she loses her abbillity to collect wood(she can still multiply wood) for another abbity DASH that activates during both DAY and night where the bunny jumps over 200 PIXELS (has a cooldown of 15 seconds) the bunny will use it in differen situations (when targeted>escaping enemy> for collecting berries) (also can you give her an aura in assets) the deer also needs an aura in assets BUT she doesnt collect berries during the day (can you fix that so she does collect berries during the day and actively searches for them) ↪💡 Consider importing and using the following plugins: @upit/tween.v1
User prompt
hey the nights and days are still affected by score/ berries
User prompt
can you also delet the old display (the one that takes up the screen)
User prompt
can you make it apear at the left bottom of the screen an also make it bigger
User prompt
can you make the gui white and only apear if the player is ontop/touching the cabin
/**** * Plugins ****/ var tween = LK.import("@upit/tween.v1"); var storage = LK.import("@upit/storage.v1"); /**** * Classes ****/ var Bunny = Container.expand(function () { var self = Container.call(this); var bunnyGraphics = self.attachAsset('bunny', { anchorX: 0.5, anchorY: 0.5, scaleX: 1.2, scaleY: 1.0 }); // Add aura for bunny self.bunnyAura = self.addChild(LK.getAsset('bunnyAura', { anchorX: 0.5, anchorY: 0.5, alpha: 0.3, tint: 0xFFB6C1 })); // Make sure aura is visible immediately self.bunnyAura.visible = true; self.berriesGiven = 0; self.hasSpeedBoost = false; self.speedBoostUntil = 0; self.dashCooldown = 0; // Track dash cooldown self.lastDashTime = 0; // Track when last dash was used self.heldBerry = null; // Berry being held self.berryVisual = null; // Visual representation of held berry self.update = function () { // Update bunny aura position to follow bunny if (self.bunnyAura) { self.bunnyAura.x = 0; // Keep relative to bunny center self.bunnyAura.y = 0; // Keep relative to bunny center } // Gentle bouncing animation self.y += Math.sin(LK.ticks * 0.15) * 0.3; // Reduce dash cooldown if (self.dashCooldown > 0) { self.dashCooldown--; } // Check for berries within 100 pixel range (increased from 50) for (var b = normalBerries.length - 1; b >= 0; b--) { var berry = normalBerries[b]; var berryDist = Math.sqrt(Math.pow(berry.x - self.x, 2) + Math.pow(berry.y - self.y, 2)); if (berryDist <= 100) { // Increased from 50 to 100 if (!self.heldBerry) { // Hold berry instead of consuming it self.heldBerry = true; self.berryVisual = self.addChild(LK.getAsset('normalBerry', { anchorX: 0.5, anchorY: 0.5, x: 0, y: -60 // Position above bunny })); normalBerries.splice(b, 1); berry.destroy(); LK.getSound('berryCollect').play(); } else { // Already holding berry, consume normally normalBerries.splice(b, 1); berry.destroy(); berriesCollectedInCycle++; // Give score when bunny collects berry var scoreGain = 1 * scoreMultiplier; LK.setScore(LK.getScore() + scoreGain); updateScoreDisplay(); LK.getSound('berryCollect').play(); // Activate 8x speed boost for 3 seconds (changed from 10x for 5 seconds) self.hasSpeedBoost = true; self.speedBoostUntil = LK.ticks + 180; // 3 seconds at 60fps (changed from 300) // Use dash ability after collecting berry if available if (self.dashCooldown === 0) { self.useDash('berry_collection'); } } break; } } // Check for nearby NPCs to give berry to if (self.heldBerry && self.berryVisual) { for (var n = 0; n < npcs.length; n++) { var npc = npcs[n]; if (npc !== self && !npc.inCabin && !npc.killed) { var npcDist = Math.sqrt(Math.pow(npc.x - self.x, 2) + Math.pow(npc.y - self.y, 2)); if (npcDist <= 80) { // Close range for giving // Give berry to NPC - reduce cooldowns by 10% if (npc.dashCooldown) { npc.dashCooldown = Math.floor(npc.dashCooldown * 0.9); } if (npc.stunCooldown) { npc.stunCooldown = Math.floor(npc.stunCooldown * 0.9); } // Remove berry visual self.berryVisual.destroy(); self.berryVisual = null; self.heldBerry = null; // Visual feedback tween(npc, { tint: 0x90EE90 }, { duration: 300, onFinish: function onFinish() { tween(npc, { tint: 0xFFFFFF }, { duration: 300 }); } }); break; } } } } // Check if speed boost has expired if (self.hasSpeedBoost && LK.ticks >= self.speedBoostUntil) { self.hasSpeedBoost = false; } // Check for enemies near bunny for dash usage var nearbyEnemies = []; // Check wolves for (var w = 0; w < wolves.length; w++) { var wolfDist = Math.sqrt(Math.pow(wolves[w].x - self.x, 2) + Math.pow(wolves[w].y - self.y, 2)); if (wolfDist < 300) { // 300 pixel detection range nearbyEnemies.push(wolves[w]); } } // Check wendigo if (wendigo) { var wendigoDist = Math.sqrt(Math.pow(wendigo.x - self.x, 2) + Math.pow(wendigo.y - self.y, 2)); if (wendigoDist < 300) { nearbyEnemies.push(wendigo); } } // Check vampires for (var v = 0; v < vampires.length; v++) { var vampireDist = Math.sqrt(Math.pow(vampires[v].x - self.x, 2) + Math.pow(vampires[v].y - self.y, 2)); if (vampireDist < 300) { nearbyEnemies.push(vampires[v]); } } // Check zombies for (var z = 0; z < zombies.length; z++) { var zombieDist = Math.sqrt(Math.pow(zombies[z].x - self.x, 2) + Math.pow(zombies[z].y - self.y, 2)); if (zombieDist < 300) { nearbyEnemies.push(zombies[z]); } } // Use dash to escape if enemies nearby and dash available if (nearbyEnemies.length > 0 && self.dashCooldown === 0) { self.useDash('escape_enemy'); } // Apply movement speed based on targeting and speed boost if (self.isTargeted) { // Bunny can move when targeted but is drastically slowed var moveSpeed = 0.3; // Use dash if available when targeted if (self.dashCooldown === 0) { self.useDash('targeted'); } // Move very slowly towards a random direction when targeted if (LK.ticks % 300 === 0) { // Every 5 seconds instead of 2 var newX = Math.random() * (1800 - 200) + 200; var newY = Math.random() * (2400 - 200) + 200; tween(self, { x: newX, y: newY }, { duration: 6000, // Much slower movement - 6 seconds instead of 2 easing: tween.easeInOut }); } } else { // Normal movement when not targeted var moveDuration = self.hasSpeedBoost ? 375 : 2000; // 8x faster when boosted (changed from 200 to 375) if (LK.ticks % 120 === 0) { // Every 2 seconds, move to a new position var newX = Math.random() * (1800 - 200) + 200; var newY = Math.random() * (2400 - 200) + 200; tween(self, { x: newX, y: newY }, { duration: moveDuration, easing: tween.easeInOut }); } } }; // DASH ability - jumps 200 pixels in direction away from threats or towards berries self.useDash = function (reason) { if (self.dashCooldown > 0) return; // Can't dash if on cooldown var dashDistance = 200; var dashX = 0; var dashY = 0; if (reason === 'escape_enemy') { // Dash away from nearest enemy var nearestEnemy = null; var closestDist = Infinity; // Find nearest enemy for (var w = 0; w < wolves.length; w++) { var dist = Math.sqrt(Math.pow(wolves[w].x - self.x, 2) + Math.pow(wolves[w].y - self.y, 2)); if (dist < closestDist) { closestDist = dist; nearestEnemy = wolves[w]; } } if (wendigo) { var dist = Math.sqrt(Math.pow(wendigo.x - self.x, 2) + Math.pow(wendigo.y - self.y, 2)); if (dist < closestDist) { nearestEnemy = wendigo; } } if (nearestEnemy) { // Dash away from enemy var dx = self.x - nearestEnemy.x; var dy = self.y - nearestEnemy.y; var distance = Math.sqrt(dx * dx + dy * dy); if (distance > 0) { dashX = self.x + dx / distance * dashDistance; dashY = self.y + dy / distance * dashDistance; } } } else if (reason === 'berry_collection') { // Dash towards nearest berry if available var nearestBerry = null; var closestDist = Infinity; for (var b = 0; b < normalBerries.length; b++) { var dist = Math.sqrt(Math.pow(normalBerries[b].x - self.x, 2) + Math.pow(normalBerries[b].y - self.y, 2)); if (dist < closestDist) { closestDist = dist; nearestBerry = normalBerries[b]; } } if (nearestBerry) { var dx = nearestBerry.x - self.x; var dy = nearestBerry.y - self.y; var distance = Math.sqrt(dx * dx + dy * dy); if (distance > 0) { dashX = self.x + dx / distance * Math.min(dashDistance, distance); dashY = self.y + dy / distance * Math.min(dashDistance, distance); } } else { // No berries, dash to random safe location dashX = self.x + (Math.random() - 0.5) * dashDistance * 2; dashY = self.y + (Math.random() - 0.5) * dashDistance * 2; } } else { // Default dash to random direction dashX = self.x + (Math.random() - 0.5) * dashDistance * 2; dashY = self.y + (Math.random() - 0.5) * dashDistance * 2; } // Keep within bounds dashX = Math.max(100, Math.min(1900, dashX)); dashY = Math.max(100, Math.min(2600, dashY)); // Perform dash with visual effect tween(self, { x: dashX, y: dashY, scaleX: 1.5, scaleY: 1.5 }, { duration: 200, easing: tween.easeOut, onFinish: function onFinish() { tween(self, { scaleX: 1.2, scaleY: 1.0 }, { duration: 200 }); } }); // Set cooldown (15 seconds = 900 frames at 60fps) self.dashCooldown = 900; self.lastDashTime = LK.ticks; }; return self; }); var Campfire = Container.expand(function () { var self = Container.call(this); var campfireGraphics = self.attachAsset('campfire', { anchorX: 0.5, anchorY: 0.5 }); self.wood = 5; // Start with 5 wood self.burnRate = 1; // Wood burns every 60 frames (1 second) self.lastBurnTime = 0; self.nextBurnIn = Math.floor(Math.random() * 120) + 120; // Random 2-4 seconds (120-240 frames) self.addWood = function (amount) { self.wood += amount; updateCampfireDisplay(); }; self.update = function () { if (isNight || isPeacefulNight) { // Burn wood during night at random intervals if (LK.ticks - self.lastBurnTime >= self.nextBurnIn) { if (self.wood > 0) { self.wood--; self.lastBurnTime = LK.ticks; self.nextBurnIn = Math.floor(Math.random() * 120) + 120; // Random 2-4 seconds updateCampfireDisplay(); } else { // No wood left, start twisted blood moon only if not already in blood moon AND no wood available if (!isBloodMoon && campfire.wood === 0) { isTwistedBloodMoon = true; isNight = false; isBloodMoon = true; // Set blood moon as true for proper night detection LK.stopMusic(); LK.playMusic('twistedBloodMoonTheme'); dayNightTxt.setText('Full Moon'); dayNightTxt.fill = 0xCCCCCC; game.setBackgroundColor(0x111111); tween(background, { tint: 0x444444, alpha: 0.9 }, { duration: 1000 }); // Move all NPCs to cabin during twisted blood moon for (var i = 0; i < npcs.length; i++) { npcs[i].enterCabin(); } // Spawn vampires from bottom during twisted blood moon with cutscene var vampire1 = new Vampire(); vampire1.x = Math.random() * (1800 - 200) + 200; vampire1.y = 2800; // Start from bottom vampires.push(vampire1); game.addChild(vampire1); var vampire2 = new Vampire(); vampire2.x = Math.random() * (1800 - 200) + 200; vampire2.y = 2800; // Start from bottom vampires.push(vampire2); game.addChild(vampire2); var vampire2_1 = new Vampire2(); vampire2_1.x = Math.random() * (1800 - 200) + 200; vampire2_1.y = 2800; // Start from bottom vampires2.push(vampire2_1); game.addChild(vampire2_1); var vampire2_2 = new Vampire2(); vampire2_2.x = Math.random() * (1800 - 200) + 200; vampire2_2.y = 2800; // Start from bottom vampires2.push(vampire2_2); game.addChild(vampire2_2); self.wood = 0; // Set wood to 0 when full moon starts // Spawn 4 wood when full moon starts for (var fw = 0; fw < 4; fw++) { spawnWood(); } updateCampfireDisplay(); } } } // Fire animation effect campfireGraphics.scaleX = 1 + Math.sin(LK.ticks * 0.3) * 0.2; campfireGraphics.scaleY = 1 + Math.cos(LK.ticks * 0.25) * 0.15; } }; return self; }); var CultistVampire = Container.expand(function () { var self = Container.call(this); var cultistVampireGraphics = self.attachAsset('cultistVampire', { anchorX: 0.5, anchorY: 0.5, scaleX: 1.2, scaleY: 1.0 }); // Apply distinctive purple tint for cultist vampire tween(cultistVampireGraphics, { tint: 0x660066 }, { duration: 100 }); self.speed = 7; // Fastest entity in the game self.update = function () { if (!isNight && !isTwistedBloodMoon && !isBloodMoon) return; // Check if stunned if (self.stunned && LK.ticks < self.stunnedUntil) { return; // Can't move when stunned } else if (self.stunned) { // Stun expired, remove stun self.stunned = false; tween(cultistVampireGraphics, { tint: 0x660066 }, { duration: 300 }); } // Cultist vampires prioritize NPCs not in cabin over fox during blood moon var closestTarget = null; var closestDistance = Infinity; var detectionRange = 1200; // Very high detection range // Initialize cultist vampire aura if not set if (!self.cultistAura) { self.cultistAura = self.addChild(LK.getAsset('vampireCultistAura', { anchorX: 0.5, anchorY: 0.5, alpha: 0.0 // Invisible aura })); } // First priority: Check for NPCs that are not in cabin (excluding only bat) for (var n = 0; n < npcs.length; n++) { if (!npcs[n].inCabin && !npcs[n].killed && npcs[n].type !== 'bat') { var npcDx = npcs[n].x - self.x; var npcDy = npcs[n].y - self.y; var npcDistance = Math.sqrt(npcDx * npcDx + npcDy * npcDy); if (npcDistance < detectionRange && npcDistance < closestDistance) { closestTarget = npcs[n]; closestDistance = npcDistance; } } } // Second priority: Check distance to fox only if no NPCs available if (!closestTarget) { var foxDx = fox.x - self.x; var foxDy = fox.y - self.y; var foxDistance = Math.sqrt(foxDx * foxDx + foxDy * foxDy); if (foxDistance < detectionRange) { closestTarget = fox; closestDistance = foxDistance; } } // Only chase if there's a target within range if (closestTarget && closestDistance < detectionRange) { // Start cultist chase music if not already playing and cultist is chasing fox if (!isCultistChaseThemePlaying && closestTarget === fox) { isCultistChaseThemePlaying = true; LK.stopMusic(); LK.playMusic('cultistVampireChaseTheme'); } var dx = closestTarget.x - self.x; var dy = closestTarget.y - self.y; var distance = Math.sqrt(dx * dx + dy * dy); if (distance > 0) { self.x += dx / distance * self.speed; self.y += dy / distance * self.speed; } } else { // Check if we should stop chase music if (isCultistChaseThemePlaying) { var anyCultistChasing = false; for (var cc = 0; cc < cultistVampires.length; cc++) { if (cultistVampires[cc] !== self) { var foxDist = Math.sqrt(Math.pow(fox.x - cultistVampires[cc].x, 2) + Math.pow(fox.y - cultistVampires[cc].y, 2)); if (foxDist < detectionRange) { anyCultistChasing = true; break; } } } if (!anyCultistChasing) { isCultistChaseThemePlaying = false; LK.stopMusic(); if (isTwistedBloodMoon) { LK.playMusic('twistedBloodMoonTheme'); } else if (isBloodMoon) { LK.playMusic('bloodMoonMusic'); } else if (isPeacefulNight) { LK.playMusic('peacefulNightAmbience'); } else if (isNight) { LK.playMusic('nightMusic'); } } } // Add prowling animation when not chasing cultistVampireGraphics.scaleX = 1.2 + Math.sin(LK.ticks * 0.1) * 0.05; } // Check collision with NPCs first (higher priority than fox) for (var n = 0; n < npcs.length; n++) { if (!npcs[n].inCabin && !npcs[n].killed && npcs[n].type !== 'bat' && self.intersects(npcs[n])) { // Cultist vampire attacks NPC var isKilled = npcs[n].takeDamage(self); if (isKilled) { npcs[n].killed = true; tween(npcs[n], { alpha: 0, scaleX: 0, scaleY: 0 }, { duration: 500, onFinish: function onFinish() { npcs[n].destroy(); npcs.splice(npcs.indexOf(npcs[n]), 1); } }); } break; } } // Check collision with fox if (self.intersects(fox)) { // Cultist vampire caught fox LK.effects.flashScreen(0x660066, 300); // Create and show vampire jumpscare (different from zombie) var vampireJumpscare = new JumpscareDisplay('vampireJumpscare'); game.addChild(vampireJumpscare); vampireJumpscare.showJumpscare(); // Play jumpscare stinger immediately LK.getSound('jumpscareStinger').play(); // Play vampire sound slightly delayed LK.setTimeout(function () { LK.getSound('vampireJumpscare').play(); }, 100); // Stun ALL enemies, but kill only this cultist vampire // Stun all wolves for (var w = 0; w < wolves.length; w++) { wolves[w].stunned = true; wolves[w].stunnedUntil = LK.ticks + 180; // 3 seconds at 60fps if (wolves[w].children[0]) { tween(wolves[w].children[0], { tint: 0x4444FF }, { duration: 500 }); } } // Stun all vampires for (var v = 0; v < vampires.length; v++) { vampires[v].stunned = true; vampires[v].stunnedUntil = LK.ticks + 180; // 3 seconds at 60fps if (vampires[v].children[0]) { tween(vampires[v].children[0], { tint: 0x4444FF }, { duration: 500 }); } } // Stun all vampires2 for (var v2 = 0; v2 < vampires2.length; v2++) { vampires2[v2].stunned = true; vampires2[v2].stunnedUntil = LK.ticks + 180; // 3 seconds at 60fps if (vampires2[v2].children[0]) { tween(vampires2[v2].children[0], { tint: 0x4444FF }, { duration: 500 }); } } // Stun all zombies for (var z = 0; z < zombies.length; z++) { zombies[z].stunned = true; zombies[z].stunnedUntil = LK.ticks + 180; // 3 seconds at 60fps if (zombies[z].children[0]) { tween(zombies[z].children[0], { tint: 0x4444FF }, { duration: 500 }); } } // Stun all other cultist vampires for (var cv = 0; cv < cultistVampires.length; cv++) { cultistVampires[cv].stunned = true; cultistVampires[cv].stunnedUntil = LK.ticks + 180; // 3 seconds at 60fps if (cultistVampires[cv].children[0]) { tween(cultistVampires[cv].children[0], { tint: 0x4444FF }, { duration: 500 }); } } // Stun wendigo if it exists if (wendigo) { wendigo.stunned = true; wendigo.stunnedUntil = LK.ticks + 180; // 3 seconds at 60fps if (wendigo.wendigoGraphics) { tween(wendigo.wendigoGraphics, { tint: 0x4444FF }, { duration: 500 }); } } // Kill only this cultist vampire that hit the player self.destroy(); cultistVampires.splice(cultistVampires.indexOf(self), 1); playerLives--; updateLivesDisplay(); LK.setTimeout(function () { if (playerLives <= 0) { LK.showGameOver(); } else { // Respawn fox at safe location fox.x = 1024; fox.y = 1366; } }, 800); return; } // Cultist vampire animation cultistVampireGraphics.scaleY = 1.0 + Math.cos(LK.ticks * 0.15) * 0.05; }; return self; }); var Fox = Container.expand(function () { var self = Container.call(this); var foxGraphics = self.attachAsset('fox', { anchorX: 0.5, anchorY: 0.5 }); return self; }); var Heart = Container.expand(function () { var self = Container.call(this); var heartGraphics = self.attachAsset('heart', { anchorX: 0.5, anchorY: 0.5 }); self.targetNPC = null; // NPC this heart follows self.gaveExtraLife = false; // Track if extra life was given self.update = function () { // Gentle floating animation with glow effect self.y += Math.sin(LK.ticks * 0.15) * 0.8; heartGraphics.scaleX = 1 + Math.sin(LK.ticks * 0.2) * 0.1; heartGraphics.scaleY = 1 + Math.cos(LK.ticks * 0.2) * 0.1; // Follow assigned NPC if exists and still alive if (self.targetNPC && !self.targetNPC.killed && !self.targetNPC.inCabin) { // Position heart above NPC self.x = self.targetNPC.x; self.y = self.targetNPC.y - 80; // 80 pixels above NPC // Give extra life to target NPC when first assigned if (!self.gaveExtraLife) { self.targetNPC.hitPoints++; self.gaveExtraLife = true; } } else if (self.targetNPC && (self.targetNPC.killed || self.targetNPC.inCabin)) { // If target NPC is killed or in cabin, find new target self.assignNewTarget(); } }; self.assignNewTarget = function () { // Find alive NPC not in cabin without a heart following them var availableNPCs = []; for (var n = 0; n < npcs.length; n++) { if (!npcs[n].killed && !npcs[n].inCabin) { // Check if this NPC already has a heart following var hasHeart = false; for (var h = 0; h < hearts.length; h++) { if (hearts[h] !== self && hearts[h].targetNPC === npcs[n]) { hasHeart = true; break; } } if (!hasHeart) { availableNPCs.push(npcs[n]); } } } if (availableNPCs.length > 0) { self.targetNPC = availableNPCs[Math.floor(Math.random() * availableNPCs.length)]; self.gaveExtraLife = false; // Reset to give extra life to new target } else { self.targetNPC = null; // No available NPCs } }; return self; }); var Hedgehog = Container.expand(function () { var self = Container.call(this); var hedgehogGraphics = self.attachAsset('hedgehog', { anchorX: 0.5, anchorY: 0.5, scaleX: 1.2, scaleY: 1.0 }); // Initialize hedgehog aura that grows with charging self.hedgehogAura = self.addChild(LK.getAsset('hedgehogAura', { anchorX: 0.5, anchorY: 0.5, alpha: 0.4, tint: 0x4169E1, scaleX: 0.5, scaleY: 0.5 })); // Make sure aura is visible immediately self.hedgehogAura.visible = true; // Hedgehog properties self.isCharging = false; self.chargingTime = 0; self.maxChargeTime = 300; // 5 seconds at 60fps self.chargeLevel = 0; // 0-5 charge levels self.auraBaseSize = 50; // Starting aura size in pixels self.isSleeping = false; self.sleepCheckTimer = 0; self.sleepCheckInterval = 300; // Check every 5 seconds self.spindashCooldown = 0; self.isCarrying = null; // NPC being carried self.nightSlowness = false; // Track if affected by blood moon slowness self.update = function () { // Update hedgehog aura position if (self.hedgehogAura) { self.hedgehogAura.x = 0; self.hedgehogAura.y = 0; } // Handle sleep check timer self.sleepCheckTimer++; if (self.sleepCheckTimer >= self.sleepCheckInterval) { self.sleepCheckTimer = 0; // 20% chance to enter sleeping state if (!self.isCharging && !self.isSleeping && Math.random() < 0.2) { self.enterSleepingState(); } } // Handle spindash cooldown if (self.spindashCooldown > 0) { self.spindashCooldown--; } // Apply blood moon speed effects - only hedgehog, mouse, and fennec get speed boost var moveSpeed = 1; if (isBloodMoon || isTwistedBloodMoon) { if (self.type === 'hedgehog' || self.type === 'mouse' || self.type === 'fennec') { moveSpeed = 2; // 2x speed boost } else { moveSpeed = 0.5; // Others get slowed down self.nightSlowness = true; } } else { self.nightSlowness = false; } // Handle sleeping state if (self.isSleeping) { // Start charging spindash while sleeping if (!self.isCharging) { self.isCharging = true; self.chargingTime = 0; self.chargeLevel = 0; } // Increment charging self.chargingTime++; var newChargeLevel = Math.min(5, Math.floor(self.chargingTime / 60)); // 1 level per second if (newChargeLevel !== self.chargeLevel) { self.chargeLevel = newChargeLevel; self.updateAuraSize(); } // Berry magnetism during charging if (self.isCharging) { for (var b = normalBerries.length - 1; b >= 0; b--) { var berry = normalBerries[b]; var berryDist = Math.sqrt(Math.pow(berry.x - self.x, 2) + Math.pow(berry.y - self.y, 2)); var magnetRange = self.auraBaseSize + self.chargeLevel * 50 + 20; // Extra 20 pixels for magnetism if (berryDist <= magnetRange) { // Pull berry towards hedgehog var dx = self.x - berry.x; var dy = self.y - berry.y; var distance = Math.sqrt(dx * dx + dy * dy); if (distance > 0) { berry.x += dx / distance * 3; // Magnetism speed berry.y += dy / distance * 3; } // Collect berry if close enough if (berryDist < 30) { normalBerries.splice(b, 1); berry.destroy(); // Increase range by 20 pixels permanently for this charge session self.chargeLevel += 0.4; // Slight boost to charge level self.updateAuraSize(); LK.getSound('berryCollect').play(); } } } } // Check for enemies to attack with spindash self.checkForEnemyAttack(); // Gentle sleeping animation hedgehogGraphics.scaleX = 1.2 + Math.sin(LK.ticks * 0.1) * 0.1; hedgehogGraphics.scaleY = 1.0 + Math.cos(LK.ticks * 0.1) * 0.05; return; } // Check for targeted NPCs to carry if (!self.isCarrying) { for (var n = 0; n < npcs.length; n++) { var npc = npcs[n]; if (npc !== self && npc.isTargeted && !npc.inCabin && !npc.killed) { var npcDist = Math.sqrt(Math.pow(npc.x - self.x, 2) + Math.pow(npc.y - self.y, 2)); if (npcDist <= 80) { self.carryNPC(npc); break; } } } } // Handle carrying behavior if (self.isCarrying) { // Move carried NPC with hedgehog self.isCarrying.x = self.x; self.isCarrying.y = self.y - 40; // Position above hedgehog // Check if carried NPC is safe (no longer targeted or threats nearby) var threatsNearby = self.checkThreatsNearby(); if (!self.isCarrying.isTargeted || !threatsNearby) { self.releaseNPC(); } } // Normal movement when not sleeping or carrying if (!self.isCarrying) { // Apply targeting slowdown if (self.isTargeted) { moveSpeed *= 0.3; // Heavily slowed when targeted } // Random movement if (LK.ticks % 120 === 0) { // Every 2 seconds var newX = Math.random() * (1800 - 200) + 200; var newY = Math.random() * (2400 - 200) + 200; tween(self, { x: newX, y: newY }, { duration: 2000 / moveSpeed, easing: tween.easeInOut }); } } }; self.updateAuraSize = function () { if (self.hedgehogAura) { var newSize = (self.auraBaseSize + self.chargeLevel * 50) / 50; // Convert to scale tween(self.hedgehogAura, { scaleX: newSize, scaleY: newSize }, { duration: 200 }); } }; self.enterSleepingState = function () { self.isSleeping = true; // Play recharge sound LK.getSound('hedgehogRecharge').play(); // Visual effect for sleeping tween(hedgehogGraphics, { tint: 0xADD8E6 }, { duration: 500 }); }; self.checkForEnemyAttack = function () { var attackRange = self.auraBaseSize + self.chargeLevel * 50; var enemies = []; // Collect all enemies in range for (var w = 0; w < wolves.length; w++) { var dist = Math.sqrt(Math.pow(wolves[w].x - self.x, 2) + Math.pow(wolves[w].y - self.y, 2)); if (dist <= attackRange) { enemies.push(wolves[w]); } } for (var v = 0; v < vampires.length; v++) { var dist = Math.sqrt(Math.pow(vampires[v].x - self.x, 2) + Math.pow(vampires[v].y - self.y, 2)); if (dist <= attackRange) { enemies.push(vampires[v]); } } for (var z = 0; z < zombies.length; z++) { var dist = Math.sqrt(Math.pow(zombies[z].x - self.x, 2) + Math.pow(zombies[z].y - self.y, 2)); if (dist <= attackRange) { enemies.push(zombies[z]); } } if (wendigo) { var dist = Math.sqrt(Math.pow(wendigo.x - self.x, 2) + Math.pow(wendigo.y - self.y, 2)); if (dist <= attackRange) { enemies.push(wendigo); } } // Attack enemies if any found if (enemies.length > 0 && self.chargeLevel >= 3) { // Need at least level 3 charge self.performSpindash(enemies); } }; self.performSpindash = function (enemies) { // Kill all enemies in range for (var e = 0; e < enemies.length; e++) { var enemy = enemies[e]; if (enemy === wendigo) { wendigo.destroy(); wendigo = null; } else if (wolves.indexOf(enemy) !== -1) { enemy.destroy(); wolves.splice(wolves.indexOf(enemy), 1); } else if (vampires.indexOf(enemy) !== -1) { enemy.destroy(); vampires.splice(vampires.indexOf(enemy), 1); } else if (zombies.indexOf(enemy) !== -1) { enemy.destroy(); zombies.splice(zombies.indexOf(enemy), 1); } } // Play hedgehog spindash sound LK.getSound('hedgehogSpindash').play(); // Reset charge and exit sleeping state self.isCharging = false; self.chargingTime = 0; self.chargeLevel = 0; self.isSleeping = false; self.spindashCooldown = 900; // 15 second cooldown // Reset visuals self.updateAuraSize(); tween(hedgehogGraphics, { tint: 0xFFFFFF }, { duration: 300 }); // Visual effect for spindash tween(self, { scaleX: 2.0, scaleY: 2.0 }, { duration: 200, onFinish: function onFinish() { tween(self, { scaleX: 1.2, scaleY: 1.0 }, { duration: 300 }); } }); // Enter recharge state (stunned for 3 seconds) self.isTargeted = true; LK.setTimeout(function () { self.isTargeted = false; }, 180); // 3 seconds }; self.carryNPC = function (npc) { self.isCarrying = npc; npc.isTargeted = false; // Remove targeting // Visual effect tween(npc, { tint: 0x90EE90 }, { duration: 300 }); }; self.releaseNPC = function () { if (self.isCarrying) { // Reset NPC visuals tween(self.isCarrying, { tint: 0xFFFFFF }, { duration: 300 }); self.isCarrying = null; } }; self.checkThreatsNearby = function () { var threatRange = 300; // Check for wolves for (var w = 0; w < wolves.length; w++) { var dist = Math.sqrt(Math.pow(wolves[w].x - self.x, 2) + Math.pow(wolves[w].y - self.y, 2)); if (dist <= threatRange) return true; } // Check for other enemies... if (wendigo) { var dist = Math.sqrt(Math.pow(wendigo.x - self.x, 2) + Math.pow(wendigo.y - self.y, 2)); if (dist <= threatRange) return true; } return false; }; self.enterCabin = function () { var targetX, targetY; // Check for any enemies nearby (within 400 pixels) var enemyNear = false; // Check for wolves for (var w = 0; w < wolves.length; w++) { var wolfDist = Math.sqrt(Math.pow(wolves[w].x - self.x, 2) + Math.pow(wolves[w].y - self.y, 2)); if (wolfDist < 400) { enemyNear = true; break; } } // Check for wendigo if (!enemyNear && wendigo) { var wendigoDist = Math.sqrt(Math.pow(wendigo.x - self.x, 2) + Math.pow(wendigo.y - self.y, 2)); if (wendigoDist < 400) { enemyNear = true; } } // Check for vampires if (!enemyNear) { for (var v = 0; v < vampires.length; v++) { var vampireDist = Math.sqrt(Math.pow(vampires[v].x - self.x, 2) + Math.pow(vampires[v].y - self.y, 2)); if (vampireDist < 400) { enemyNear = true; break; } } } // Check for zombies if (!enemyNear) { for (var z = 0; z < zombies.length; z++) { var zombieDist = Math.sqrt(Math.pow(zombies[z].x - self.x, 2) + Math.pow(zombies[z].y - self.y, 2)); if (zombieDist < 400) { enemyNear = true; break; } } } // Determine where to go based on conditions var shouldGoCabin = isTwistedBloodMoon || isBloodMoon || enemyNear; if (shouldGoCabin) { // Go to cabin when there's danger self.inCabin = true; targetX = cabin.x; targetY = cabin.y; } else { // Go to campfire during normal times self.inCabin = false; targetX = campfire.x + (Math.random() - 0.5) * 200; targetY = campfire.y + (Math.random() - 0.5) * 200; } tween(self, { x: targetX, y: targetY, alpha: self.inCabin ? 0.3 : 1 }, { duration: 1000 }); }; // Add rarity visual indicator method for consistency with NPC class self.setRarityVisual = function () { // All animals keep their natural colors - no tinting applied // Rarity can be indicated through other means like size or behavior }; return self; }); var JumpscareDisplay = Container.expand(function (assetName) { var self = Container.call(this); var jumpscareGraphics = self.attachAsset(assetName, { anchorX: 0.5, anchorY: 0.5, scaleX: 0.1, scaleY: 0.1, alpha: 0 }); self.showJumpscare = function () { // Position at center of screen self.x = 1024; self.y = 1366; // Rapid scale up with flash effect tween(jumpscareGraphics, { scaleX: 3, scaleY: 3, alpha: 1 }, { duration: 100, onFinish: function onFinish() { // Hold for a moment LK.setTimeout(function () { // Quick fade out tween(jumpscareGraphics, { alpha: 0, scaleX: 0.5, scaleY: 0.5 }, { duration: 200, onFinish: function onFinish() { self.destroy(); } }); }, 300); } }); }; return self; }); var NPC = Container.expand(function (type) { var self = Container.call(this); self.type = type; // Set multiplier based on type: mouse gives 4x, cat/bunny/squirrel give 2x, bat gives 2x, others give no multiplier if (type === 'mouse') { self.multiplier = 4; } else if (type === 'cat' || type === 'bunny' || type === 'squirrel' || type === 'bat') { self.multiplier = 2; } else { self.multiplier = 0; // deer, fennec, dog don't give multipliers } self.inCabin = false; self.frozen = false; // Set hit points: deer has 2 lives, dog has 3 lives, others have 1 if (type === 'deer') { self.hitPoints = 2; } else if (type === 'dog') { self.hitPoints = 3; } else { self.hitPoints = 1; } self.isTargeted = false; self.rarity = 'common'; // Default rarity, will be set when spawned // Deer-specific properties for berry detection if (type === 'deer') { self.berryTarget = null; self.hasSpeedBoost = false; self.baseSpeed = 2; self.boostedSpeed = 8; // 4x speed boost during day self.nightBoostedSpeed = 4; // 2x speed boost during night/full moon/peaceful night self.heldBerry = null; // Berry being held self.berryVisual = null; // Visual representation of held berry } // Cat-specific properties for wood detection if (type === 'cat') { self.woodTarget = null; self.hasSpeedBoost = false; self.baseSpeed = 2; self.boostedSpeed = 8; // 4x speed boost during day self.nightBoostedSpeed = 4; // 2x speed boost during night/full moon/peaceful night } var npcGraphics = self.attachAsset(type, { anchorX: 0.5, anchorY: 0.5, scaleX: type === 'mouse' ? 2.0 : 1.2, scaleY: type === 'mouse' ? 1.8 : 1.0 }); // Add aura effect for squirrel if (type === 'squirrel') { self.auraEffect = self.addChild(LK.getAsset('campfire', { anchorX: 0.5, anchorY: 0.5, scaleX: 1.5, scaleY: 1.5, alpha: 0.3, tint: 0x00FF00 })); // Update aura size based on campfire proximity self.updateAuraSize = function () { if (self.auraEffect) { var distanceToCampfire = Math.sqrt(Math.pow(campfire.x - self.x, 2) + Math.pow(campfire.y - self.y, 2)); var isAtCampfire = distanceToCampfire <= 200; var targetScale = isAtCampfire ? 3.0 : 1.5; // 200px range = 3.0 scale, 100px range = 1.5 scale tween(self.auraEffect, { scaleX: targetScale, scaleY: targetScale }, { duration: 500 }); } }; // Animate the aura with gentle pulsing var _animateAura = function animateAura() { if (self.auraEffect) { var currentScale = self.auraEffect.scaleX; var pulseScale = currentScale + 0.3; tween(self.auraEffect, { scaleX: pulseScale, scaleY: pulseScale, alpha: 0.1 }, { duration: 2000, onFinish: function onFinish() { if (self.auraEffect) { tween(self.auraEffect, { scaleX: currentScale, scaleY: currentScale, alpha: 0.3 }, { duration: 2000, onFinish: _animateAura }); } } }); } }; _animateAura(); } // Add rarity visual indicator after graphics are created self.setRarityVisual = function () { // All animals keep their natural colors - no tinting applied // Rarity can be indicated through other means like size or behavior }; self.update = function () { if (self.frozen || self.inCabin) return; // Apply movement speed based on targeting and type if (self.isTargeted) { if (self.type === 'bunny') { // Bunny can move when targeted but is drastically slowed self.targetedSpeed = 0.3; } else if (self.type === 'cat' || self.type === 'squirrel') { // Cat and squirrel are more drastically slowed than deer self.targetedSpeed = 0.1; } else if (self.type === 'deer') { // Deer is slowed but not as much as commons self.targetedSpeed = 0.5; } else if (self.type === 'mouse') { // Mouse gets speed boost when targeted self.targetedSpeed = 4; } else if (self.type === 'fennec') { // Fennec can't enter cabin when targeted self.canEnterCabin = false; self.targetedSpeed = 1; } else if (self.type === 'dog') { // Dog is slowed drastically when targeted self.targetedSpeed = 0.2; } } // Check for nearby enemies that would cause NPCs to run to cabin var enemyNear = false; var shouldRunToCabin = false; // Check for wolves near this NPC for (var wf = 0; wf < wolves.length; wf++) { var wolfDist = Math.sqrt(Math.pow(wolves[wf].x - self.x, 2) + Math.pow(wolves[wf].y - self.y, 2)); if (wolfDist < 400) { enemyNear = true; break; } } // Check for wendigo near this NPC if (wendigo && !enemyNear) { var wendigoDist = Math.sqrt(Math.pow(wendigo.x - self.x, 2) + Math.pow(wendigo.y - self.y, 2)); if (wendigoDist < 400) { enemyNear = true; } } // Check for vampires near this NPC if (!enemyNear) { for (var v = 0; v < vampires.length; v++) { var vampireDist = Math.sqrt(Math.pow(vampires[v].x - self.x, 2) + Math.pow(vampires[v].y - self.y, 2)); if (vampireDist < 400) { enemyNear = true; break; } } } // Check for vampires2 near this NPC if (!enemyNear) { for (var v2 = 0; v2 < vampires2.length; v2++) { var vampire2Dist = Math.sqrt(Math.pow(vampires2[v2].x - self.x, 2) + Math.pow(vampires2[v2].y - self.y, 2)); if (vampire2Dist < 400) { enemyNear = true; break; } } } // Check for zombies near this NPC if (!enemyNear) { for (var z = 0; z < zombies.length; z++) { var zombieDist = Math.sqrt(Math.pow(zombies[z].x - self.x, 2) + Math.pow(zombies[z].y - self.y, 2)); if (zombieDist < 400) { enemyNear = true; break; } } } // Determine if NPC should run to cabin shouldRunToCabin = isTwistedBloodMoon || isBloodMoon || enemyNear; // Special behavior during day - NPCs go to campfire and move around freely if (!isNight && !isPeacefulNight && !isBloodMoon && !isTwistedBloodMoon && !enemyNear) { // Move to campfire area during day var campfireDx = campfire.x - self.x; var campfireDy = campfire.y - self.y; var campfireDistance = Math.sqrt(campfireDx * campfireDx + campfireDy * campfireDy); if (campfireDistance > 200) { // Move towards campfire if too far var moveSpeed = self.isTargeted ? self.targetedSpeed || 1 : 1; self.x += campfireDx / campfireDistance * moveSpeed; self.y += campfireDy / campfireDistance * moveSpeed; } else { // Already near campfire, do gentle movement around it self.y += Math.sin(LK.ticks * 0.1 + self.x * 0.01) * 0.3; if (LK.ticks % 200 === 0) { var newX = campfire.x + (Math.random() - 0.5) * 300; var newY = campfire.y + (Math.random() - 0.5) * 300; // Keep within reasonable bounds newX = Math.max(200, Math.min(1800, newX)); newY = Math.max(200, Math.min(2400, newY)); tween(self, { x: newX, y: newY }, { duration: 3000, easing: tween.easeInOut }); } } return; } // If enemies are near or it's bloodmoon, run to cabin if (shouldRunToCabin) { self.enterCabin(); return; } // Cat behavior - collect wood with detection range and speed boost during night if (self.type === 'cat' && !self.inCabin) { // Wood detection with dynamic range and speed boost var detectionRange; var speedBoost; // Determine detection range and speed boost based on time of day if (isNight || isTwistedBloodMoon || isPeacefulNight || isBloodMoon) { // Night/full moon/peaceful night: same range as day, 2x speed boost detectionRange = 600; speedBoost = self.nightBoostedSpeed; } else { // Day: same range as night, 4x speed boost detectionRange = 600; speedBoost = self.boostedSpeed; } // Find wood within detection range var woodInRange = []; for (var w = 0; w < woodItems.length; w++) { var wood = woodItems[w]; var woodDist = Math.sqrt(Math.pow(wood.x - self.x, 2) + Math.pow(wood.y - self.y, 2)); if (woodDist <= detectionRange) { woodInRange.push({ wood: wood, distance: woodDist }); } } // If wood is in range, activate speed boost and target nearest one if (woodInRange.length > 0) { self.hasSpeedBoost = true; // Find nearest wood in range woodInRange.sort(function (a, b) { return a.distance - b.distance; }); var targetWood = woodInRange[0].wood; var targetDistance = woodInRange[0].distance; // Move towards target wood with speed boost var dx = targetWood.x - self.x; var dy = targetWood.y - self.y; var distance = Math.sqrt(dx * dx + dy * dy); if (distance > 0) { var moveSpeed = self.isTargeted ? self.targetedSpeed || speedBoost : speedBoost; self.x += dx / distance * moveSpeed; self.y += dy / distance * moveSpeed; } // Collect wood if close enough if (targetDistance < 50) { for (var w = woodItems.length - 1; w >= 0; w--) { if (woodItems[w] === targetWood) { campfire.addWood(1 * self.multiplier); // Cat uses 2x multiplier LK.getSound('catWoodCollect').play(); woodItems.splice(w, 1); targetWood.destroy(); break; } } } return; } else { // No wood in range, remove speed boost and move towards nearest wood self.hasSpeedBoost = false; // Find nearest wood anywhere on the map var nearestWood = null; var nearestDistance = Infinity; for (var w = 0; w < woodItems.length; w++) { var wood = woodItems[w]; var woodDist = Math.sqrt(Math.pow(wood.x - self.x, 2) + Math.pow(wood.y - self.y, 2)); if (woodDist < nearestDistance) { nearestDistance = woodDist; nearestWood = wood; } } if (nearestWood) { var dx = nearestWood.x - self.x; var dy = nearestWood.y - self.y; var distance = Math.sqrt(dx * dx + dy * dy); if (distance > 0) { var moveSpeed = self.isTargeted ? self.targetedSpeed || self.baseSpeed : self.baseSpeed; self.x += dx / distance * moveSpeed; self.y += dy / distance * moveSpeed; } return; } } } // Squirrel special behavior - moves around with aura that gives speed boosts if (self.type === 'squirrel' && !self.inCabin) { // Initialize squirrel speed boost properties if not set if (!self.squirrelSpeedBoosts) { self.squirrelSpeedBoosts = {}; // Track which NPCs have boosts from this squirrel } // Check for enemies near squirrel during night var squirrelEnemyNear = false; var squirrelDistanceToCampfire = Math.sqrt(Math.pow(campfire.x - self.x, 2) + Math.pow(campfire.y - self.y, 2)); var isSquirrelAtCampfire = squirrelDistanceToCampfire <= 200; if (isNight || isBloodMoon || isTwistedBloodMoon || isPeacefulNight) { // Check for enemies near squirrel for (var wf = 0; wf < wolves.length; wf++) { var wolfDist = Math.sqrt(Math.pow(wolves[wf].x - self.x, 2) + Math.pow(wolves[wf].y - self.y, 2)); if (wolfDist < 400) { squirrelEnemyNear = true; break; } } if (wendigo && !squirrelEnemyNear) { var wendigoDist = Math.sqrt(Math.pow(wendigo.x - self.x, 2) + Math.pow(wendigo.y - self.y, 2)); if (wendigoDist < 400) { squirrelEnemyNear = true; } } if (!squirrelEnemyNear) { for (var v = 0; v < vampires.length; v++) { var vampireDist = Math.sqrt(Math.pow(vampires[v].x - self.x, 2) + Math.pow(vampires[v].y - self.y, 2)); if (vampireDist < 400) { squirrelEnemyNear = true; break; } } } if (!squirrelEnemyNear) { for (var v2 = 0; v2 < vampires2.length; v2++) { var vampire2Dist = Math.sqrt(Math.pow(vampires2[v2].x - self.x, 2) + Math.pow(vampires2[v2].y - self.y, 2)); if (vampire2Dist < 400) { squirrelEnemyNear = true; break; } } } if (!squirrelEnemyNear) { for (var z = 0; z < zombies.length; z++) { var zombieDist = Math.sqrt(Math.pow(zombies[z].x - self.x, 2) + Math.pow(zombies[z].y - self.y, 2)); if (zombieDist < 400) { squirrelEnemyNear = true; break; } } } } // Handle squirrel retreat behavior if (squirrelEnemyNear && (isNight || isBloodMoon || isTwistedBloodMoon || isPeacefulNight)) { if (!isSquirrelAtCampfire) { // First priority: retreat to campfire var moveSpeed = self.isTargeted ? 0.5 : 1; var campfireDx = campfire.x - self.x; var campfireDy = campfire.y - self.y; var campfireDistance = Math.sqrt(campfireDx * campfireDx + campfireDy * campfireDy); if (campfireDistance > 0) { self.x += campfireDx / campfireDistance * moveSpeed; self.y += campfireDy / campfireDistance * moveSpeed; } } else { // Second priority: already at campfire and enemy still near, go to cabin self.enterCabin(); return; } } else { // Normal movement behavior when no enemies near if (LK.ticks % 180 === 0) { // Every 3 seconds, move to a new position var newX = Math.random() * (1800 - 200) + 200; var newY = Math.random() * (2400 - 200) + 200; var moveSpeed = self.isTargeted ? 0.5 : 1; // Slower when targeted, running to cabin tween(self, { x: newX, y: newY }, { duration: 3000, easing: tween.easeInOut }); } } // Speed boost aura active during both day and night if (true) { // Dynamic aura range based on distance to campfire var auraRange = isSquirrelAtCampfire ? 200 : 100; // Update aura visual size based on proximity to campfire if (self.updateAuraSize) { self.updateAuraSize(); } // Check for NPCs within dynamic aura range for speed boost for (var n = 0; n < npcs.length; n++) { var otherNPC = npcs[n]; if (otherNPC !== self && !otherNPC.inCabin && !otherNPC.killed) { var npcDist = Math.sqrt(Math.pow(otherNPC.x - self.x, 2) + Math.pow(otherNPC.y - self.y, 2)); var npcId = npcs.indexOf(otherNPC); if (npcDist <= auraRange) { // NPC is in aura range - give 2x speed boost if (!self.squirrelSpeedBoosts[npcId]) { self.squirrelSpeedBoosts[npcId] = { active: true, exitTime: 0, currentBoost: 2 }; // Visual effect for NPC in aura tween(otherNPC, { tint: 0xFFFF99 }, { duration: 300 }); } } else if (self.squirrelSpeedBoosts[npcId] && self.squirrelSpeedBoosts[npcId].active) { // NPC left aura - start decay process self.squirrelSpeedBoosts[npcId].active = false; self.squirrelSpeedBoosts[npcId].exitTime = LK.ticks; self.squirrelSpeedBoosts[npcId].currentBoost = 5; // Start at 5x // Remove visual effect tween(otherNPC, { tint: 0xFFFFFF }, { duration: 300 }); } } } // Update decay for NPCs that left the aura for (var npcId in self.squirrelSpeedBoosts) { var boostData = self.squirrelSpeedBoosts[npcId]; if (!boostData.active && boostData.currentBoost > 1) { var timeSinceExit = LK.ticks - boostData.exitTime; var decaySteps = Math.floor(timeSinceExit / 120); // Every 2 seconds (120 frames) boostData.currentBoost = Math.max(1, 5 - decaySteps); if (boostData.currentBoost === 1) { // Boost expired, remove tracking delete self.squirrelSpeedBoosts[npcId]; } } } } else { // During day, clear all speed boosts and visual effects for (var npcId in self.squirrelSpeedBoosts) { var npcIndex = parseInt(npcId); if (npcs[npcIndex]) { // Remove visual effect tween(npcs[npcIndex], { tint: 0xFFFFFF }, { duration: 300 }); } } // Clear all speed boost tracking during day self.squirrelSpeedBoosts = {}; } return; // Skip normal movement behavior } // Bunny no longer collects wood automatically but still provides 2x multiplier for fox collection // Fennec-specific properties for stunning and cabin access if (self.type === 'fennec') { self.canEnterCabin = false; // Fennec can never enter cabin self.stunCooldown = 0; // Cooldown timer for stunning ability self.isStunned = false; // Whether fennec is currently stunned self.stunnedUntil = 0; // When stun effect ends } // Fennec fox behavior - collect berries and kill wolves/zombies if (self.type === 'fennec') { // Initialize fennec aura if not set if (!self.fennecAura) { self.fennecAura = self.addChild(LK.getAsset('fennecAura', { anchorX: 0.5, anchorY: 0.5, alpha: 0.4, tint: 0xFF4500 })); } // Apply speed modifications based on moon phase var fennecSpeed = 2; // Base speed if (isBloodMoon || isTwistedBloodMoon) { fennecSpeed = 3; // Speed boost during blood moon/full moon - can move during blood moon } else if (isPeacefulNight || isNight) { fennecSpeed = 1; // Slowness during other nights } // Show/hide aura based on cooldown and stunning state if (self.fennecAura) { self.fennecAura.visible = self.stunCooldown === 0 && !self.isStunned; } // Handle stunning effects if (self.isStunned && LK.ticks < self.stunnedUntil) { return; // Can't move when stunned } else if (self.isStunned) { self.isStunned = false; // Remove stun effect } // Reduce cooldown if (self.stunCooldown > 0) { self.stunCooldown--; } // Check for wolves and zombies to kill within aura range (150 pixels) var auraRange = 150; var targetEnemy = null; var closestEnemyDistance = Infinity; // Check for wolves within aura for (var w = 0; w < wolves.length; w++) { var wolfDist = Math.sqrt(Math.pow(wolves[w].x - self.x, 2) + Math.pow(wolves[w].y - self.y, 2)); if (wolfDist <= auraRange && wolfDist < closestEnemyDistance) { targetEnemy = wolves[w]; closestEnemyDistance = wolfDist; } } // Check for zombies within aura for (var z = 0; z < zombies.length; z++) { var zombieDist = Math.sqrt(Math.pow(zombies[z].x - self.x, 2) + Math.pow(zombies[z].y - self.y, 2)); if (zombieDist <= auraRange && zombieDist < closestEnemyDistance) { targetEnemy = zombies[z]; closestEnemyDistance = zombieDist; } } // Kill enemy if within aura and cooldown is ready if (targetEnemy && closestEnemyDistance <= auraRange && self.stunCooldown === 0) { // Remove enemy from appropriate array if (targetEnemy.constructor.name === 'Wolf') { targetEnemy.destroy(); wolves.splice(wolves.indexOf(targetEnemy), 1); } else if (targetEnemy.constructor.name === 'Zombie') { targetEnemy.destroy(); zombies.splice(zombies.indexOf(targetEnemy), 1); } // Stun fennec for 3 seconds (180 frames at 60fps) self.isStunned = true; self.stunnedUntil = LK.ticks + 180; // Set cooldown for 10 seconds (600 frames at 60fps) self.stunCooldown = 600; // Hide aura after killing if (self.fennecAura) { self.fennecAura.visible = false; } return; // Skip other behavior while stunned } // Check for nearby berries to collect (150 pixel range) var foundNearbyBerry = false; for (var b = normalBerries.length - 1; b >= 0; b--) { var berry = normalBerries[b]; var berryDist = Math.sqrt(Math.pow(berry.x - self.x, 2) + Math.pow(berry.y - self.y, 2)); if (berryDist <= 150) { foundNearbyBerry = true; // Move towards berry var dx = berry.x - self.x; var dy = berry.y - self.y; var distance = Math.sqrt(dx * dx + dy * dy); if (distance > 0) { var moveSpeed = self.isTargeted ? self.targetedSpeed || fennecSpeed : fennecSpeed; self.x += dx / distance * moveSpeed; self.y += dy / distance * moveSpeed; } // Collect berry if close enough if (berryDist < 50) { normalBerries.splice(b, 1); berry.destroy(); berriesCollectedInCycle += 2; // Fennec collects 2 berries instead of 1 LK.getSound('berryCollect').play(); break; } break; // Only target one berry at a time } } // Normal movement when not collecting berries or killing enemies if (!foundNearbyBerry && LK.ticks % 180 === 0) { // Every 3 seconds, move to a new position var newX = Math.random() * (1800 - 200) + 200; var newY = Math.random() * (2400 - 200) + 200; var moveSpeed = self.isTargeted ? self.targetedSpeed || fennecSpeed : fennecSpeed; tween(self, { x: newX, y: newY }, { duration: 3000 / moveSpeed, easing: tween.easeInOut }); } } // Deer behavior - collect berries with detection range and speed boost if (self.type === 'deer') { // Initialize deer aura if not set if (!self.deerAura) { self.deerAura = self.addChild(LK.getAsset('deerAura', { anchorX: 0.5, anchorY: 0.5, alpha: 0.4, tint: 0x8FBC8F })); } // Update deer aura position to follow deer if (self.deerAura) { self.deerAura.x = 0; // Keep relative to deer center self.deerAura.y = 0; // Keep relative to deer center // Make sure aura is visible during day self.deerAura.visible = true; } // First priority: if targeted and at 1 life during blood moon, run to cabin if (isBloodMoon && self.isTargeted && self.hitPoints === 1) { self.enterCabin(); return; } // Second priority: run from wendigo if present if (isBloodMoon && wendigo) { var wendigoDist = Math.sqrt(Math.pow(wendigo.x - self.x, 2) + Math.pow(wendigo.y - self.y, 2)); if (wendigoDist < 400) { // Run away from wendigo - use targetedSpeed if targeted, otherwise normal speed var speed = self.isTargeted ? self.targetedSpeed : 3; var dx = self.x - wendigo.x; var dy = self.y - wendigo.y; var distance = Math.sqrt(dx * dx + dy * dy); if (distance > 0) { self.x += dx / distance * speed; self.y += dy / distance * speed; } return; } } // Berry detection with dynamic range and speed boost - NOW WORKS DURING DAY TOO var detectionRange; var speedBoost; // Determine detection range and speed boost based on time of day if (isNight || isTwistedBloodMoon || isPeacefulNight || isBloodMoon) { // Night/full moon/peaceful night: shorter range, 2x speed boost detectionRange = 200; speedBoost = self.nightBoostedSpeed; } else { // Day: longer range, 4x speed boost - DEER NOW ACTIVELY COLLECTS DURING DAY detectionRange = 400; speedBoost = self.boostedSpeed; } // Find berries within detection range var berriesInRange = []; for (var b = 0; b < normalBerries.length; b++) { var berry = normalBerries[b]; var berryDist = Math.sqrt(Math.pow(berry.x - self.x, 2) + Math.pow(berry.y - self.y, 2)); if (berryDist <= detectionRange) { berriesInRange.push({ berry: berry, distance: berryDist }); } } // If berries are in range, activate speed boost and target nearest one if (berriesInRange.length > 0) { self.hasSpeedBoost = true; // Find nearest berry in range berriesInRange.sort(function (a, b) { return a.distance - b.distance; }); var targetBerry = berriesInRange[0].berry; var targetDistance = berriesInRange[0].distance; // Move towards target berry with speed boost var dx = targetBerry.x - self.x; var dy = targetBerry.y - self.y; var distance = Math.sqrt(dx * dx + dy * dy); if (distance > 0) { var moveSpeed = self.isTargeted ? self.targetedSpeed || speedBoost : speedBoost; self.x += dx / distance * moveSpeed; self.y += dy / distance * moveSpeed; } // Collect berry if close enough if (targetDistance < 50) { for (var b = normalBerries.length - 1; b >= 0; b--) { if (normalBerries[b] === targetBerry) { if (!self.heldBerry) { // Hold berry instead of consuming it self.heldBerry = true; self.berryVisual = self.addChild(LK.getAsset('normalBerry', { anchorX: 0.5, anchorY: 0.5, x: 0, y: -80 // Position above deer })); normalBerries.splice(b, 1); targetBerry.destroy(); LK.getSound('berryCollect').play(); } else { // Already holding berry, consume normally normalBerries.splice(b, 1); targetBerry.destroy(); berriesCollectedInCycle++; // Give score when deer collects berry var scoreGain = 1 * scoreMultiplier; LK.setScore(LK.getScore() + scoreGain); updateScoreDisplay(); LK.getSound('berryCollect').play(); } break; } } } return; } else { // No berries in range, remove speed boost and move towards nearest berry - ACTIVE DURING DAY self.hasSpeedBoost = false; // Find nearest berry anywhere on the map var nearestBerry = null; var nearestDistance = Infinity; for (var b = 0; b < normalBerries.length; b++) { var berry = normalBerries[b]; var berryDist = Math.sqrt(Math.pow(berry.x - self.x, 2) + Math.pow(berry.y - self.y, 2)); if (berryDist < nearestDistance) { nearestDistance = berryDist; nearestBerry = berry; } } if (nearestBerry) { var dx = nearestBerry.x - self.x; var dy = nearestBerry.y - self.y; var distance = Math.sqrt(dx * dx + dy * dy); if (distance > 0) { var moveSpeed = self.isTargeted ? self.targetedSpeed || self.baseSpeed : self.baseSpeed; self.x += dx / distance * moveSpeed; self.y += dy / distance * moveSpeed; } return; } } // Check for nearby NPCs to give berry to (deer specific) if (self.type === 'deer' && self.heldBerry && self.berryVisual) { for (var n = 0; n < npcs.length; n++) { var npc = npcs[n]; if (npc !== self && !npc.inCabin && !npc.killed) { var npcDist = Math.sqrt(Math.pow(npc.x - self.x, 2) + Math.pow(npc.y - self.y, 2)); if (npcDist <= 120) { // Slightly larger range for deer // Give berry to NPC - reduce cooldowns by 20% if (npc.dashCooldown) { npc.dashCooldown = Math.floor(npc.dashCooldown * 0.8); } if (npc.stunCooldown) { npc.stunCooldown = Math.floor(npc.stunCooldown * 0.8); } // Remove berry visual self.berryVisual.destroy(); self.berryVisual = null; self.heldBerry = null; // Visual feedback tween(npc, { tint: 0xFFD700 }, { duration: 400, onFinish: function onFinish() { tween(npc, { tint: 0xFFFFFF }, { duration: 400 }); } }); break; } } } } } // Mouse behavior - moves when targeted, gets invisible/safe near cabin, multiplier changes in cabin if (self.type === 'mouse') { // Mouse movement when targeted (remove previous non-movement behavior) if (self.isTargeted) { // Move away from threats when targeted (instead of staying still) var moveSpeed = 4; // Speed boost when targeted // Find nearest threat to move away from var nearestThreat = null; var closestThreatDistance = Infinity; // Check for wolves for (var w = 0; w < wolves.length; w++) { var wolfDist = Math.sqrt(Math.pow(wolves[w].x - self.x, 2) + Math.pow(wolves[w].y - self.y, 2)); if (wolfDist < closestThreatDistance) { closestThreatDistance = wolfDist; nearestThreat = wolves[w]; } } // Check for wendigo if (wendigo) { var wendigoDist = Math.sqrt(Math.pow(wendigo.x - self.x, 2) + Math.pow(wendigo.y - self.y, 2)); if (wendigoDist < closestThreatDistance) { closestThreatDistance = wendigoDist; nearestThreat = wendigo; } } if (nearestThreat) { // Move away from nearest threat var dx = self.x - nearestThreat.x; var dy = self.y - nearestThreat.y; var distance = Math.sqrt(dx * dx + dy * dy); if (distance > 0) { self.x += dx / distance * moveSpeed; self.y += dy / distance * moveSpeed; } } } // Check distance to cabin for safety behavior var cabinDistance = Math.sqrt(Math.pow(cabin.x - self.x, 2) + Math.pow(cabin.y - self.y, 2)); // Get invisible/safe when within 100 pixels of cabin if (cabinDistance <= 100) { self.mouseNearCabin = true; // Reduce visibility when near cabin if (self.alpha > 0.3) { tween(self, { alpha: 0.3 }, { duration: 500 }); } } else { self.mouseNearCabin = false; // Restore visibility when away from cabin if (self.alpha < 1.0) { tween(self, { alpha: 1.0 }, { duration: 500 }); } } if ((isNight || isBloodMoon || isPeacefulNight) && !self.inCabin) { // Mouse goes to cabin during night/bloodmoon var targetSpeed = isNight || isBloodMoon ? 5 : 3; // Apply slowness if affected by night slowness if (self.nightSlowness) { targetSpeed *= 0.5; // Reduce speed when slowed } var dx = cabin.x - self.x; var dy = cabin.y - self.y; var distance = Math.sqrt(dx * dx + dy * dy); if (distance > 50) { self.x += dx / distance * targetSpeed; self.y += dy / distance * targetSpeed; } else { self.enterCabin(); } return; } } // Bat behavior - flying animation, cultist vampire transformation during full moon and blood moon, wood collection if (self.type === 'bat') { // Transform into cultist vampire during blood moon or twisted blood moon if ((isBloodMoon || isTwistedBloodMoon) && !self.isCultistVampire) { self.isCultistVampire = true; // Hide the bat NPC self.alpha = 0; self.inCabin = true; // Mark as hidden // Create cultist vampire at bat's position var cultistVampire = new CultistVampire(); cultistVampire.x = self.x; cultistVampire.y = self.y; cultistVampires.push(cultistVampire); game.addChild(cultistVampire); } else if (!isBloodMoon && !isTwistedBloodMoon && self.isCultistVampire) { // Transform back to bat during day self.isCultistVampire = false; // Show the bat again self.alpha = 1; self.inCabin = false; // Remove all cultist vampires (they hide when day comes) for (var cv = cultistVampires.length - 1; cv >= 0; cv--) { cultistVampires[cv].destroy(); cultistVampires.splice(cv, 1); } } // Wood collection behavior with 4x multiplier if (!self.inCabin) { // Check for nearby wood to collect for (var w = woodItems.length - 1; w >= 0; w--) { var wood = woodItems[w]; var woodDist = Math.sqrt(Math.pow(wood.x - self.x, 2) + Math.pow(wood.y - self.y, 2)); if (woodDist <= 150) { // Move towards wood var dx = wood.x - self.x; var dy = wood.y - self.y; var distance = Math.sqrt(dx * dx + dy * dy); if (distance > 0) { var moveSpeed = self.isTargeted ? self.targetedSpeed || 2 : 2; self.x += dx / distance * moveSpeed; self.y += dy / distance * moveSpeed; } // Collect wood if close enough (4x collection) if (woodDist < 50) { woodItems.splice(w, 1); wood.destroy(); campfire.addWood(1 * self.multiplier); // Bat uses 4x multiplier LK.getSound('woodCollect').play(); break; } return; } } } // Flying animation - gentle up and down movement self.y += Math.sin(LK.ticks * 0.2 + self.x * 0.02) * 1.5; // Go to campfire area when not targeted if (!self.isTargeted) { var campfireDx = campfire.x - self.x; var campfireDy = campfire.y - self.y; var campfireDistance = Math.sqrt(campfireDx * campfireDx + campfireDy * campfireDy); if (campfireDistance > 300) { tween(self, { x: campfire.x + (Math.random() - 0.5) * 400, y: campfire.y + (Math.random() - 0.5) * 400 }, { duration: 2500, easing: tween.easeInOut }); } } } // Dog behavior during night/blood moon with aura system if (self.type === 'dog' && (isNight || isBloodMoon)) { // Initialize dog aura properties if not set if (!self.dogAura) { self.dogAura = self.addChild(LK.getAsset('dogAura', { anchorX: 0.5, anchorY: 0.5, alpha: 0.3 })); self.hasShot = false; // Track if dog has used its shot self.slowed = false; // Track if dog is slowed after shooting self.stunnedEnemies = []; // Track enemies stunned by this dog } // Show/hide aura based on shot availability and night status if (self.dogAura) { self.dogAura.visible = !self.hasShot && (isNight || isBloodMoon); } // Update stunned enemies timers for (var se = self.stunnedEnemies.length - 1; se >= 0; se--) { var stunnedEnemy = self.stunnedEnemies[se]; if (LK.ticks >= stunnedEnemy.deathTime) { // Time to kill the enemy (10 seconds after stun) if (stunnedEnemy.enemy === wendigo && wendigo) { wendigo.destroy(); wendigo = null; } else if (wolves.indexOf(stunnedEnemy.enemy) !== -1) { stunnedEnemy.enemy.destroy(); wolves.splice(wolves.indexOf(stunnedEnemy.enemy), 1); } else if (vampires.indexOf(stunnedEnemy.enemy) !== -1) { stunnedEnemy.enemy.destroy(); vampires.splice(vampires.indexOf(stunnedEnemy.enemy), 1); } else if (vampires2.indexOf(stunnedEnemy.enemy) !== -1) { stunnedEnemy.enemy.destroy(); vampires2.splice(vampires2.indexOf(stunnedEnemy.enemy), 1); } else if (zombies.indexOf(stunnedEnemy.enemy) !== -1) { stunnedEnemy.enemy.destroy(); zombies.splice(zombies.indexOf(stunnedEnemy.enemy), 1); } else if (cultistVampires.indexOf(stunnedEnemy.enemy) !== -1) { stunnedEnemy.enemy.destroy(); cultistVampires.splice(cultistVampires.indexOf(stunnedEnemy.enemy), 1); } // Remove from stunned enemies list self.stunnedEnemies.splice(se, 1); } else if (LK.ticks >= stunnedEnemy.unstunTime && stunnedEnemy.enemy.dogStunned) { // Remove stun effect after 5 seconds stunnedEnemy.enemy.dogStunned = false; stunnedEnemy.enemy.stunned = false; // Remove blue tint if (stunnedEnemy.enemy.children && stunnedEnemy.enemy.children[0]) { tween(stunnedEnemy.enemy.children[0], { tint: 0xFFFFFF }, { duration: 300 }); } else if (stunnedEnemy.enemy.wendigoGraphics) { tween(stunnedEnemy.enemy.wendigoGraphics, { tint: 0xFFFFFF }, { duration: 300 }); } } } if (!self.isTargeted && !self.hasShot) { // Check for enemies within 333 pixel aura range var nearestThreat = null; var minDistance = Infinity; var auraRange = 333; // Check wolves for (var w = 0; w < wolves.length; w++) { if (!wolves[w].stunned && !wolves[w].dogStunned) { var dist = Math.sqrt(Math.pow(wolves[w].x - self.x, 2) + Math.pow(wolves[w].y - self.y, 2)); if (dist <= auraRange && dist < minDistance) { minDistance = dist; nearestThreat = wolves[w]; } } } // Check wendigo if (wendigo && !wendigo.stunned && !wendigo.dogStunned) { var wendigoDist = Math.sqrt(Math.pow(wendigo.x - self.x, 2) + Math.pow(wendigo.y - self.y, 2)); if (wendigoDist <= auraRange && wendigoDist < minDistance) { minDistance = wendigoDist; nearestThreat = wendigo; } } // Check vampires for (var v = 0; v < vampires.length; v++) { if (!vampires[v].stunned && !vampires[v].dogStunned) { var vDist = Math.sqrt(Math.pow(vampires[v].x - self.x, 2) + Math.pow(vampires[v].y - self.y, 2)); if (vDist <= auraRange && vDist < minDistance) { minDistance = vDist; nearestThreat = vampires[v]; } } } // Check vampires2 for (var v2 = 0; v2 < vampires2.length; v2++) { if (!vampires2[v2].stunned && !vampires2[v2].dogStunned) { var v2Dist = Math.sqrt(Math.pow(vampires2[v2].x - self.x, 2) + Math.pow(vampires2[v2].y - self.y, 2)); if (v2Dist <= auraRange && v2Dist < minDistance) { minDistance = v2Dist; nearestThreat = vampires2[v2]; } } } // Check zombies for (var z = 0; z < zombies.length; z++) { if (!zombies[z].stunned && !zombies[z].dogStunned) { var zDist = Math.sqrt(Math.pow(zombies[z].x - self.x, 2) + Math.pow(zombies[z].y - self.y, 2)); if (zDist <= auraRange && zDist < minDistance) { minDistance = zDist; nearestThreat = zombies[z]; } } } // Check cultist vampires for (var cv = 0; cv < cultistVampires.length; cv++) { if (!cultistVampires[cv].stunned && !cultistVampires[cv].dogStunned) { var cvDist = Math.sqrt(Math.pow(cultistVampires[cv].x - self.x, 2) + Math.pow(cultistVampires[cv].y - self.y, 2)); if (cvDist <= auraRange && cvDist < minDistance) { minDistance = cvDist; nearestThreat = cultistVampires[cv]; } } } // If threat enters aura, stun it for 5 seconds and mark for death after 10 seconds if (nearestThreat && minDistance <= auraRange) { // Stun the enemy nearestThreat.dogStunned = true; nearestThreat.stunned = true; nearestThreat.stunnedUntil = LK.ticks + 300; // 5 seconds // Add to stunned enemies list with death timer self.stunnedEnemies.push({ enemy: nearestThreat, unstunTime: LK.ticks + 300, // 5 seconds to unstun deathTime: LK.ticks + 600 // 10 seconds to die }); // Apply blue tint to show stun if (nearestThreat.children && nearestThreat.children[0]) { tween(nearestThreat.children[0], { tint: 0x4444FF }, { duration: 300 }); } else if (nearestThreat.wendigoGraphics) { tween(nearestThreat.wendigoGraphics, { tint: 0x4444FF }, { duration: 300 }); } // Use up the shot self.hasShot = true; self.slowed = true; self.isTargeted = true; // Hide aura after shooting if (self.dogAura) { self.dogAura.visible = false; } // Move to cabin with slowed speed self.enterCabin(); return; } } } // Default behavior: move to campfire if not already there var campfireDx = campfire.x - self.x; var campfireDy = campfire.y - self.y; var campfireDistance = Math.sqrt(campfireDx * campfireDx + campfireDy * campfireDy); if (campfireDistance > 200) { // Move towards campfire if too far var moveSpeed = self.isTargeted ? self.targetedSpeed || 1 : 1; self.x += campfireDx / campfireDistance * moveSpeed; self.y += campfireDy / campfireDistance * moveSpeed; } else if (!self.isTargeted) { // Already near campfire, do gentle movement around it self.y += Math.sin(LK.ticks * 0.1 + self.x * 0.01) * 0.3; if (LK.ticks % 200 === 0) { var newX = campfire.x + (Math.random() - 0.5) * 300; var newY = campfire.y + (Math.random() - 0.5) * 300; // Keep within reasonable bounds newX = Math.max(200, Math.min(1800, newX)); newY = Math.max(200, Math.min(2400, newY)); tween(self, { x: newX, y: newY }, { duration: 3000, easing: tween.easeInOut }); } } }; self.enterCabin = function () { var targetX, targetY; // Check for any enemies nearby (within 400 pixels) var enemyNear = false; // Check for wolves for (var w = 0; w < wolves.length; w++) { var wolfDist = Math.sqrt(Math.pow(wolves[w].x - self.x, 2) + Math.pow(wolves[w].y - self.y, 2)); if (wolfDist < 400) { enemyNear = true; break; } } // Check for wendigo if (!enemyNear && wendigo) { var wendigoDist = Math.sqrt(Math.pow(wendigo.x - self.x, 2) + Math.pow(wendigo.y - self.y, 2)); if (wendigoDist < 400) { enemyNear = true; } } // Check for vampires if (!enemyNear) { for (var v = 0; v < vampires.length; v++) { var vampireDist = Math.sqrt(Math.pow(vampires[v].x - self.x, 2) + Math.pow(vampires[v].y - self.y, 2)); if (vampireDist < 400) { enemyNear = true; break; } } } // Check for vampires2 if (!enemyNear) { for (var v2 = 0; v2 < vampires2.length; v2++) { var vampire2Dist = Math.sqrt(Math.pow(vampires2[v2].x - self.x, 2) + Math.pow(vampires2[v2].y - self.y, 2)); if (vampire2Dist < 400) { enemyNear = true; break; } } } // Check for zombies if (!enemyNear) { for (var z = 0; z < zombies.length; z++) { var zombieDist = Math.sqrt(Math.pow(zombies[z].x - self.x, 2) + Math.pow(zombies[z].y - self.y, 2)); if (zombieDist < 400) { enemyNear = true; break; } } } // Fennec can never enter cabin if (self.type === 'fennec') { self.inCabin = false; targetX = campfire.x + (Math.random() - 0.5) * 200; targetY = campfire.y + (Math.random() - 0.5) * 200; } else { // Determine where to go based on conditions for other NPCs // Special case: dog stays out during blood moon and full moon var shouldGoCabin = isTwistedBloodMoon || isBloodMoon || enemyNear; if (self.type === 'dog' && (isBloodMoon || isTwistedBloodMoon)) { // Dog stays out during blood moon and full moon self.inCabin = false; targetX = campfire.x + (Math.random() - 0.5) * 200; targetY = campfire.y + (Math.random() - 0.5) * 200; } else if (self.type === 'mouse' && shouldGoCabin) { // Special mouse behavior in cabin self.inCabin = true; targetX = cabin.x; targetY = cabin.y; // Mouse multiplier goes down to 2x when in cabin (from 4x) self.cabinMultiplier = 2; } else if (shouldGoCabin) { // Go to cabin when there's danger self.inCabin = true; targetX = cabin.x; targetY = cabin.y; } else { // Go to campfire during normal times self.inCabin = false; targetX = campfire.x + (Math.random() - 0.5) * 200; targetY = campfire.y + (Math.random() - 0.5) * 200; } } tween(self, { x: targetX, y: targetY, alpha: self.inCabin ? 0.3 : 1 }, { duration: 1000 }); }; self.exitCabin = function () { self.inCabin = false; var newX = Math.random() * (1800 - 200) + 200; var newY = Math.random() * (2400 - 200) + 200; tween(self, { x: newX, y: newY, alpha: 1 }, { duration: 1000 }); }; self.freeze = function () { self.frozen = true; npcGraphics.tint = 0x4444ff; }; self.takeDamage = function (attacker) { // Special behavior for mouse: hit points and slowness system if (self.type === 'mouse') { // Mouse has 2 lives during night ONLY, 1 life other times var maxLives = isNight ? 2 : 1; // During night, mouse takes 0.5 damage (but not during blood moon, full moon, peaceful night) if (isNight && !isBloodMoon && !isTwistedBloodMoon && !isPeacefulNight) { // Take 0.5 damage during regular night self.hitPoints -= 0.5; // Apply slowness effect when hit during night until blood moon if (!self.nightSlowness) { self.nightSlowness = true; self.slownessDuration = 0; // Will be removed when blood moon starts } } else { // Take full damage during day, blood moon, full moon, peaceful night self.hitPoints -= 1; } } else { // Special behavior for deer: unfreeze if targeted and hit by wendigo if (self.type === 'deer' && self.isTargeted && self.frozen && attacker === wendigo) { self.frozen = false; self.isTargeted = false; npcGraphics.tint = 0xFFFFFF; // Remove freeze tint // Don't take damage, just unfreeze return false; } // Special behavior for deer: remove targeting when hit by any enemy if (self.type === 'deer' && self.isTargeted) { self.isTargeted = false; } } // Special behavior for deer: teleport to cabin when hit (unless already in cabin) if (self.type === 'deer' && !self.inCabin) { self.inCabin = true; tween(self, { x: cabin.x, y: cabin.y, alpha: 0.3 }, { duration: 500 }); } // Special behavior for dog: teleport to cabin when hit (unless already in cabin) if (self.type === 'dog' && !self.inCabin) { self.inCabin = true; tween(self, { x: cabin.x, y: cabin.y, alpha: 0.3 }, { duration: 500 }); } self.hitPoints--; // Always play kill sound when NPC gets hit LK.getSound(self.type + 'Kill').play(); // Stun the attacker for 3 seconds if provided // Clear targeting status if targeted NPC survives if (self.isTargeted) { self.isTargeted = false; // Remove blue tint from the NPC tween(npcGraphics, { tint: 0xFFFFFF }, { duration: 300 }); } if (attacker) { // Special case for wendigo: stun for 7 seconds instead of the normal 3 var stunDuration = attacker === wendigo ? 420 : 180; // 7 seconds for wendigo, 3 for others attacker.stunned = true; attacker.stunnedUntil = LK.ticks + stunDuration; // Find the graphics object to tint var graphicsToTint = null; if (attacker.children && attacker.children[0]) { graphicsToTint = attacker.children[0]; } else if (attacker.wendigoGraphics) { graphicsToTint = attacker.wendigoGraphics; } if (graphicsToTint) { tween(graphicsToTint, { tint: 0x4444FF }, { duration: 500 }); } } if (self.hitPoints <= 0) { // If it's a bat being killed, spawn cultist vampire that kills the attacker if (self.type === 'bat' && attacker) { // Create cultist vampire at bat's position var cultistVampire = new CultistVampire(); cultistVampire.x = self.x; cultistVampire.y = self.y; cultistVampires.push(cultistVampire); game.addChild(cultistVampire); // Mark the attacker for immediate death by cultist cultistVampire.targetToKill = attacker; // Kill the attacker immediately LK.setTimeout(function () { if (attacker && cultistVampire.targetToKill === attacker) { // Remove attacker from appropriate array if (attacker === wendigo) { wendigo.destroy(); wendigo = null; } else if (wolves.indexOf(attacker) !== -1) { attacker.destroy(); wolves.splice(wolves.indexOf(attacker), 1); } else if (vampires.indexOf(attacker) !== -1) { attacker.destroy(); vampires.splice(vampires.indexOf(attacker), 1); } else if (vampires2.indexOf(attacker) !== -1) { attacker.destroy(); vampires2.splice(vampires2.indexOf(attacker), 1); } else if (zombies.indexOf(attacker) !== -1) { attacker.destroy(); zombies.splice(zombies.indexOf(attacker), 1); } cultistVampire.targetToKill = null; } }, 100); } // If it's a deer being killed, spawn 20 berries (can be multiplied) if (self.type === 'deer') { for (var i = 0; i < 20; i++) { LK.setTimeout(function () { spawnNormalBerry(); }, i * 100); // Stagger berry spawning } } return true; // NPC is killed } else { // Flash red to show damage tween(npcGraphics, { tint: 0xFF0000 }, { duration: 200, onFinish: function onFinish() { tween(npcGraphics, { tint: 0xFFFFFF }, { duration: 200 }); } }); return false; } }; self.stunThreat = function (threat) { // Determine stun duration based on threat type var stunDuration = 300; // Default 5 seconds for most enemies if (threat === wendigo) { stunDuration = 180; // 3 seconds for wendigo } else if (threat.children && threat.children[0] && threat.children[0].texture.baseTexture.imageUrl.indexOf('vampire') !== -1) { stunDuration = 360; // 6 seconds for vampires } threat.stunned = true; threat.stunnedUntil = LK.ticks + stunDuration; // Play stun sound LK.getSound('dogStun').play(); // Make threat flash blue to show it's stunned tween(threat.children[0], { tint: 0x4444FF }, { duration: 300 }); // Dog gets slowed after stunning and retreats self.isTargeted = true; self.slowedUntil = LK.ticks + 300; // Slowed for 5 seconds var retreatX = Math.random() * (1800 - 200) + 200; var retreatY = Math.random() * (2400 - 200) + 200; tween(self, { x: retreatX, y: retreatY }, { duration: 2000, // Slower retreat due to being slowed onFinish: function onFinish() { self.isTargeted = false; } }); }; return self; }); var NormalBerry = Container.expand(function () { var self = Container.call(this); var berryGraphics = self.attachAsset('normalBerry', { anchorX: 0.5, anchorY: 0.5 }); // Initialize berry lifespan if not set if (!self.spawnTime) { self.spawnTime = LK.ticks; self.lifespan = 1800; // 30 seconds at 60fps } self.update = function () { // Gentle floating animation self.y += Math.sin(LK.ticks * 0.1 + self.x * 0.01) * 0.5; }; return self; }); var Robot = Container.expand(function () { var self = Container.call(this); var robotGraphics = self.attachAsset('robot', { anchorX: 0.5, anchorY: 0.5, scaleX: 1.0, scaleY: 1.0 }); // Initialize robot aura (electric field) self.robotAura = self.addChild(LK.getAsset('robotAura', { anchorX: 0.5, anchorY: 0.5, alpha: 0.3, tint: 0x00FFFF, scaleX: 2.0, scaleY: 2.0 })); // Aura visibility will be controlled by update method based on proximity to campfire // Robot properties self.hitPoints = 4; // Highest HP in game self.isElectricShieldActive = false; self.shieldCooldown = 0; self.shieldKillCount = 0; self.maxShieldKills = 2; self.isStunnedAfterShield = false; self.stunnedUntil = 0; self.makeshiftCabin = null; self.makeshiftCabinDuration = 0; self.baseSpeed = 0.5; // Slowest character self.nightSlowness = false; self.update = function () { // Update robot aura position and visibility if (self.robotAura) { self.robotAura.x = 0; self.robotAura.y = 0; // Check if near campfire for shield visibility var campfireDist = Math.sqrt(Math.pow(campfire.x - self.x, 2) + Math.pow(campfire.y - self.y, 2)); var nearCampfire = campfireDist <= 150; // Only show aura during night stages, when close to campfire, and when not stunned self.robotAura.visible = (isNight || isBloodMoon || isTwistedBloodMoon || isPeacefulNight) && nearCampfire && !self.isStunnedAfterShield; } // Handle shield cooldown if (self.shieldCooldown > 0) { self.shieldCooldown--; } // Handle post-shield stun if (self.isStunnedAfterShield && LK.ticks < self.stunnedUntil) { return; // Can't move when stunned } else if (self.isStunnedAfterShield) { self.isStunnedAfterShield = false; } // Apply blood moon speed effects - robots get slowed down var moveSpeed = self.baseSpeed; if (isBloodMoon || isTwistedBloodMoon) { if (self.type !== 'hedgehog' && self.type !== 'mouse' && self.type !== 'fennec') { moveSpeed *= 0.5; // Slowed down during blood moon self.nightSlowness = true; } } else { self.nightSlowness = false; } // Check if near campfire for shield activation var campfireDist = Math.sqrt(Math.pow(campfire.x - self.x, 2) + Math.pow(campfire.y - self.y, 2)); var nearCampfire = campfireDist <= 150; // Electric shield logic if (nearCampfire && !self.isElectricShieldActive && self.shieldCooldown === 0 && (isNight || isBloodMoon || isTwistedBloodMoon || isPeacefulNight)) { self.activateElectricShield(); } // Handle electric shield behavior if (self.isElectricShieldActive) { // Robot cannot move when shield is active self.checkShieldKills(); // Visual shield effect robotGraphics.scaleX = 1.0 + Math.sin(LK.ticks * 0.3) * 0.1; robotGraphics.scaleY = 1.0 + Math.cos(LK.ticks * 0.3) * 0.1; // Electric tint if (LK.ticks % 30 === 0) { // Flash every 0.5 seconds tween(robotGraphics, { tint: 0x00FFFF }, { duration: 100, onFinish: function onFinish() { tween(robotGraphics, { tint: 0xFFFFFF }, { duration: 100 }); } }); } return; // Don't move when shield is active } // Handle makeshift cabin duration if (self.makeshiftCabin) { self.makeshiftCabinDuration--; if (self.makeshiftCabinDuration <= 0) { self.destroyMakeshiftCabin(); } } // Create makeshift cabin during night phases if ((isNight || isBloodMoon || isTwistedBloodMoon || isPeacefulNight) && !self.makeshiftCabin && Math.random() < 0.01) { self.createMakeshiftCabin(); } // Normal movement (very slow) if (LK.ticks % 180 === 0) { // Every 3 seconds var newX = Math.random() * (1800 - 200) + 200; var newY = Math.random() * (2400 - 200) + 200; tween(self, { x: newX, y: newY }, { duration: 4000 / moveSpeed, // Very slow movement easing: tween.easeInOut }); } }; self.activateElectricShield = function () { self.isElectricShieldActive = true; self.shieldKillCount = 0; // Visual effect for shield activation tween(self.robotAura, { alpha: 0.8, scaleX: 2.5, scaleY: 2.5 }, { duration: 300 }); }; self.checkShieldKills = function () { var shieldRange = 200; // 200 pixel aura range var enemies = []; // Collect enemies in range for (var w = 0; w < wolves.length; w++) { var dist = Math.sqrt(Math.pow(wolves[w].x - self.x, 2) + Math.pow(wolves[w].y - self.y, 2)); if (dist <= shieldRange) { enemies.push({ enemy: wolves[w], array: wolves, index: w }); } } for (var v = 0; v < vampires.length; v++) { var dist = Math.sqrt(Math.pow(vampires[v].x - self.x, 2) + Math.pow(vampires[v].y - self.y, 2)); if (dist <= shieldRange) { enemies.push({ enemy: vampires[v], array: vampires, index: v }); } } for (var z = 0; z < zombies.length; z++) { var dist = Math.sqrt(Math.pow(zombies[z].x - self.x, 2) + Math.pow(zombies[z].y - self.y, 2)); if (dist <= shieldRange) { enemies.push({ enemy: zombies[z], array: zombies, index: z }); } } // Kill enemies and count kills for (var e = 0; e < enemies.length && self.shieldKillCount < self.maxShieldKills; e++) { var enemyData = enemies[e]; enemyData.enemy.destroy(); enemyData.array.splice(enemyData.array.indexOf(enemyData.enemy), 1); self.shieldKillCount++; } // Deactivate shield after 2 kills if (self.shieldKillCount >= self.maxShieldKills) { self.deactivateElectricShield(); } }; self.deactivateElectricShield = function () { self.isElectricShieldActive = false; self.shieldCooldown = 1200; // 20 second cooldown self.isStunnedAfterShield = true; self.stunnedUntil = LK.ticks + 300; // 5 second stun // Reset aura visual tween(self.robotAura, { alpha: 0.3, scaleX: 2.0, scaleY: 2.0 }, { duration: 300 }); }; self.createMakeshiftCabin = function () { if (!self.makeshiftCabin) { // Create makeshift cabin at robot's location self.makeshiftCabin = LK.getAsset('makeshiftCabin', { anchorX: 0.5, anchorY: 0.5, alpha: 0.8 }); self.makeshiftCabin.x = self.x; self.makeshiftCabin.y = self.y; self.makeshiftCabin.occupant = null; // Track single occupant self.makeshiftCabin.bunnyBerryUpgrade = 0; // Track bunny berry upgrades (20% each) self.makeshiftCabin.deerBerryUpgrade = 0; // Track deer berry upgrades (40% each) game.addChild(self.makeshiftCabin); // Cabin lasts for 1 night (duration varies by night type) if (isBloodMoon || isTwistedBloodMoon) { self.makeshiftCabinDuration = 1800; // 30 seconds for blood moon } else { self.makeshiftCabinDuration = 900; // 15 seconds for regular night } } }; self.destroyMakeshiftCabin = function () { if (self.makeshiftCabin) { self.makeshiftCabin.destroy(); self.makeshiftCabin = null; } }; self.takeDamage = function (attacker) { self.hitPoints--; // Play robot kill sound (use cat kill sound as substitute) LK.getSound('catKill').play(); // Robot stuns all enemies for 3 seconds LONGER when hit (except wendigo) var stunDuration = attacker === wendigo ? 180 : 540; // 9 seconds for non-wendigo, 3 for wendigo // Stun all enemies for (var w = 0; w < wolves.length; w++) { wolves[w].stunned = true; wolves[w].stunnedUntil = LK.ticks + stunDuration; if (wolves[w].children[0]) { tween(wolves[w].children[0], { tint: 0x4444FF }, { duration: 500 }); } } for (var v = 0; v < vampires.length; v++) { vampires[v].stunned = true; vampires[v].stunnedUntil = LK.ticks + stunDuration; if (vampires[v].children[0]) { tween(vampires[v].children[0], { tint: 0x4444FF }, { duration: 500 }); } } for (var z = 0; z < zombies.length; z++) { zombies[z].stunned = true; zombies[z].stunnedUntil = LK.ticks + stunDuration; if (zombies[z].children[0]) { tween(zombies[z].children[0], { tint: 0x4444FF }, { duration: 500 }); } } // Flash red to show damage tween(robotGraphics, { tint: 0xFF0000 }, { duration: 200, onFinish: function onFinish() { tween(robotGraphics, { tint: 0xFFFFFF }, { duration: 200 }); } }); if (self.hitPoints <= 0) { // Robot death explosion - turn night into peaceful night self.explode(); return true; } return false; }; self.explode = function () { // Massive visual explosion effect LK.effects.flashScreen(0xFFFF00, 1000); // Scale up dramatically tween(self, { scaleX: 5.0, scaleY: 5.0, alpha: 0 }, { duration: 1000 }); // Convert current night state to peaceful night if (isBloodMoon) { isBloodMoon = false; isPeacefulNight = true; LK.stopMusic(); LK.playMusic('peacefulNightAmbience'); dayNightTxt.setText('Peaceful Night'); dayNightTxt.fill = 0x99CCFF; } else if (isTwistedBloodMoon) { isTwistedBloodMoon = false; isPeacefulNight = true; LK.stopMusic(); LK.playMusic('peacefulNightAmbience'); dayNightTxt.setText('Peaceful Night'); dayNightTxt.fill = 0x99CCFF; } else if (isNight) { isPeacefulNight = true; LK.stopMusic(); LK.playMusic('peacefulNightAmbience'); dayNightTxt.setText('Peaceful Night'); dayNightTxt.fill = 0x99CCFF; } // Remove all enemies for (var w = wolves.length - 1; w >= 0; w--) { wolves[w].destroy(); wolves.splice(w, 1); } if (wendigo) { wendigo.destroy(); wendigo = null; } for (var v = vampires.length - 1; v >= 0; v--) { vampires[v].destroy(); vampires.splice(v, 1); } for (var z = zombies.length - 1; z >= 0; z--) { zombies[z].destroy(); zombies.splice(z, 1); } }; self.enterCabin = function () { var targetX, targetY; // Check for any enemies nearby (within 400 pixels) var enemyNear = false; // Check for wolves for (var w = 0; w < wolves.length; w++) { var wolfDist = Math.sqrt(Math.pow(wolves[w].x - self.x, 2) + Math.pow(wolves[w].y - self.y, 2)); if (wolfDist < 400) { enemyNear = true; break; } } // Check for wendigo if (!enemyNear && wendigo) { var wendigoDist = Math.sqrt(Math.pow(wendigo.x - self.x, 2) + Math.pow(wendigo.y - self.y, 2)); if (wendigoDist < 400) { enemyNear = true; } } // Check for vampires if (!enemyNear) { for (var v = 0; v < vampires.length; v++) { var vampireDist = Math.sqrt(Math.pow(vampires[v].x - self.x, 2) + Math.pow(vampires[v].y - self.y, 2)); if (vampireDist < 400) { enemyNear = true; break; } } } // Check for zombies if (!enemyNear) { for (var z = 0; z < zombies.length; z++) { var zombieDist = Math.sqrt(Math.pow(zombies[z].x - self.x, 2) + Math.pow(zombies[z].y - self.y, 2)); if (zombieDist < 400) { enemyNear = true; break; } } } // Determine where to go based on conditions var shouldGoCabin = isTwistedBloodMoon || isBloodMoon || enemyNear; if (shouldGoCabin) { // Go to cabin when there's danger self.inCabin = true; targetX = cabin.x; targetY = cabin.y; } else { // Go to campfire during normal times self.inCabin = false; targetX = campfire.x + (Math.random() - 0.5) * 200; targetY = campfire.y + (Math.random() - 0.5) * 200; } tween(self, { x: targetX, y: targetY, alpha: self.inCabin ? 0.3 : 1 }, { duration: 1000 }); }; // Add rarity visual indicator method for consistency with NPC class self.setRarityVisual = function () { // All animals keep their natural colors - no tinting applied // Rarity can be indicated through other means like size or behavior }; return self; }); var Vampire = Container.expand(function () { var self = Container.call(this); var vampireGraphics = self.attachAsset('vampire', { anchorX: 0.5, anchorY: 0.5 }); self.speed = 4; // Base speed self.update = function () { // Update speed based on current state self.speed = isTwistedBloodMoon ? 6 : 4; // Faster during full moon if (!isTwistedBloodMoon) return; // During twisted blood moon cutscene, vampires move from bottom to campfire if (isBloodMoonCutscene && isTwistedBloodMoon) { // Spawn vampire from bottom if not already positioned if (self.y > 2600) { // Vampire starts from bottom, move to campfire tween(self, { x: campfire.x + (Math.random() - 0.5) * 300, y: campfire.y + (Math.random() - 0.5) * 300 }, { duration: 3000, easing: tween.easeInOut }); } // Scare nearby NPCs into cabin for (var i = 0; i < npcs.length; i++) { if (!npcs[i].inCabin && !npcs[i].killed) { var npcDist = Math.sqrt(Math.pow(npcs[i].x - self.x, 2) + Math.pow(npcs[i].y - self.y, 2)); if (npcDist < 300) { npcs[i].enterCabin(); } } } return; } // Check if stunned if (self.stunned && LK.ticks < self.stunnedUntil) { return; // Can't move when stunned } else if (self.stunned) { // Stun expired, remove stun self.stunned = false; tween(vampireGraphics, { tint: 0xFFFFFF }, { duration: 300 }); } // Find fox to attack first, then NPCs var target = null; var closestDistance = Infinity; // Check distance to fox var foxDx = fox.x - self.x; var foxDy = fox.y - self.y; var foxDistance = Math.sqrt(foxDx * foxDx + foxDy * foxDy); if (foxDistance < closestDistance) { closestDistance = foxDistance; target = fox; } // Find nearest NPC if fox is too far (excluding only bat) var closestNPC = null; var closestNPCDistance = Infinity; for (var i = 0; i < npcs.length; i++) { if (!npcs[i].inCabin && !npcs[i].killed && npcs[i].type !== 'bat') { var dx = npcs[i].x - self.x; var dy = npcs[i].y - self.y; var distance = Math.sqrt(dx * dx + dy * dy); if (distance < closestNPCDistance) { closestNPCDistance = distance; closestNPC = npcs[i]; } } } // Choose closest target between fox and NPCs if (closestNPCDistance < closestDistance) { target = closestNPC; closestDistance = closestNPCDistance; } // Add random offset to movement to prevent grouping var randomOffsetX = (Math.random() - 0.5) * 100; var randomOffsetY = (Math.random() - 0.5) * 100; // Move towards target with random offset if (target) { var dx = target.x + randomOffsetX - self.x; var dy = target.y + randomOffsetY - self.y; var distance = Math.sqrt(dx * dx + dy * dy); if (distance > 0) { self.x += dx / distance * self.speed; self.y += dy / distance * self.speed; } // Attack if close enough if (target === fox && distance < 50) { // Vampire caught fox LK.effects.flashScreen(0xFF0000, 500); // Create and show vampire jumpscare var vampireJumpscare = new JumpscareDisplay('vampireJumpscare'); game.addChild(vampireJumpscare); vampireJumpscare.showJumpscare(); // Play jumpscare stinger immediately LK.getSound('jumpscareStinger').play(); // Play vampire sound slightly delayed LK.setTimeout(function () { LK.getSound('vampireJumpscare').play(); }, 100); // Stun ALL enemies, but kill only this vampire // Stun all wolves for (var w = 0; w < wolves.length; w++) { wolves[w].stunned = true; wolves[w].stunnedUntil = LK.ticks + 180; // 3 seconds at 60fps if (wolves[w].children[0]) { tween(wolves[w].children[0], { tint: 0x4444FF }, { duration: 500 }); } } // Stun all other vampires for (var v = 0; v < vampires.length; v++) { vampires[v].stunned = true; vampires[v].stunnedUntil = LK.ticks + 180; // 3 seconds at 60fps if (vampires[v].children[0]) { tween(vampires[v].children[0], { tint: 0x4444FF }, { duration: 500 }); } } // Stun all vampires2 for (var v2 = 0; v2 < vampires2.length; v2++) { vampires2[v2].stunned = true; vampires2[v2].stunnedUntil = LK.ticks + 180; // 3 seconds at 60fps if (vampires2[v2].children[0]) { tween(vampires2[v2].children[0], { tint: 0x4444FF }, { duration: 500 }); } } // Stun all zombies for (var z = 0; z < zombies.length; z++) { zombies[z].stunned = true; zombies[z].stunnedUntil = LK.ticks + 180; // 3 seconds at 60fps if (zombies[z].children[0]) { tween(zombies[z].children[0], { tint: 0x4444FF }, { duration: 500 }); } } // Stun wendigo if it exists if (wendigo) { wendigo.stunned = true; wendigo.stunnedUntil = LK.ticks + 180; // 3 seconds at 60fps if (wendigo.wendigoGraphics) { tween(wendigo.wendigoGraphics, { tint: 0x4444FF }, { duration: 500 }); } } // Kill only this vampire that hit the player self.destroy(); vampires.splice(vampires.indexOf(self), 1); playerLives--; updateLivesDisplay(); LK.setTimeout(function () { if (playerLives <= 0) { LK.showGameOver(); } else { // Respawn fox at safe location fox.x = 1024; fox.y = 1366; } }, 1000); } else if (target !== fox && distance < 50) { // Attack NPC var isKilled = target.takeDamage(self); if (isKilled) { target.killed = true; tween(target, { alpha: 0, scaleX: 0, scaleY: 0 }, { duration: 500, onFinish: function onFinish() { target.destroy(); npcs.splice(npcs.indexOf(target), 1); } }); } } } // Vampire animation vampireGraphics.scaleX = 0.8 + Math.sin(LK.ticks * 0.4) * 0.1; vampireGraphics.scaleY = 0.8 + Math.cos(LK.ticks * 0.3) * 0.1; }; return self; }); var Vampire2 = Container.expand(function () { var self = Container.call(this); var vampire2Graphics = self.attachAsset('vampire2', { anchorX: 0.5, anchorY: 0.5 }); self.speed = 4; // Base speed self.update = function () { // Update speed based on current state self.speed = isTwistedBloodMoon ? 6 : 4; // Faster during full moon if (!isTwistedBloodMoon) return; // During twisted blood moon cutscene, vampire2 move from bottom to campfire if (isBloodMoonCutscene && isTwistedBloodMoon) { // Spawn vampire2 from bottom if not already positioned if (self.y > 2600) { // Vampire2 starts from bottom, move to campfire tween(self, { x: campfire.x + (Math.random() - 0.5) * 350, y: campfire.y + (Math.random() - 0.5) * 350 }, { duration: 3500, easing: tween.easeInOut }); } // Scare nearby NPCs into cabin for (var i = 0; i < npcs.length; i++) { if (!npcs[i].inCabin && !npcs[i].killed) { var npcDist = Math.sqrt(Math.pow(npcs[i].x - self.x, 2) + Math.pow(npcs[i].y - self.y, 2)); if (npcDist < 300) { npcs[i].enterCabin(); } } } return; } // Check if stunned if (self.stunned && LK.ticks < self.stunnedUntil) { return; // Can't move when stunned } else if (self.stunned) { // Stun expired, remove stun self.stunned = false; tween(vampire2Graphics, { tint: 0xFFFFFF }, { duration: 300 }); } // Find fox to attack first, then NPCs var target = null; var closestDistance = Infinity; // Check distance to fox var foxDx = fox.x - self.x; var foxDy = fox.y - self.y; var foxDistance = Math.sqrt(foxDx * foxDx + foxDy * foxDy); if (foxDistance < closestDistance) { closestDistance = foxDistance; target = fox; } // Find nearest NPC if fox is too far (excluding only bat) var closestNPC = null; var closestNPCDistance = Infinity; for (var i = 0; i < npcs.length; i++) { if (!npcs[i].inCabin && !npcs[i].killed && npcs[i].type !== 'bat') { var dx = npcs[i].x - self.x; var dy = npcs[i].y - self.y; var distance = Math.sqrt(dx * dx + dy * dy); if (distance < closestNPCDistance) { closestNPCDistance = distance; closestNPC = npcs[i]; } } } // Choose closest target between fox and NPCs if (closestNPCDistance < closestDistance) { target = closestNPC; closestDistance = closestNPCDistance; } // Add different random offset for vampire2 to prevent grouping var randomOffsetX = (Math.random() - 0.5) * 150; var randomOffsetY = (Math.random() - 0.5) * 150; // Move towards target with random offset if (target) { var dx = target.x + randomOffsetX - self.x; var dy = target.y + randomOffsetY - self.y; var distance = Math.sqrt(dx * dx + dy * dy); if (distance > 0) { self.x += dx / distance * self.speed; self.y += dy / distance * self.speed; } // Attack if close enough if (target === fox && distance < 50) { // Vampire caught fox LK.effects.flashScreen(0xFF0000, 500); // Create and show vampire jumpscare var vampireJumpscare = new JumpscareDisplay('vampireJumpscare'); game.addChild(vampireJumpscare); vampireJumpscare.showJumpscare(); // Play jumpscare stinger immediately LK.getSound('jumpscareStinger').play(); // Play vampire sound slightly delayed LK.setTimeout(function () { LK.getSound('vampireJumpscare').play(); }, 100); // Stun ALL enemies, but kill only this vampire2 // Stun all wolves for (var w = 0; w < wolves.length; w++) { wolves[w].stunned = true; wolves[w].stunnedUntil = LK.ticks + 180; // 3 seconds at 60fps if (wolves[w].children[0]) { tween(wolves[w].children[0], { tint: 0x4444FF }, { duration: 500 }); } } // Stun all vampires for (var v = 0; v < vampires.length; v++) { vampires[v].stunned = true; vampires[v].stunnedUntil = LK.ticks + 180; // 3 seconds at 60fps if (vampires[v].children[0]) { tween(vampires[v].children[0], { tint: 0x4444FF }, { duration: 500 }); } } // Stun all other vampires2 for (var v2 = 0; v2 < vampires2.length; v2++) { vampires2[v2].stunned = true; vampires2[v2].stunnedUntil = LK.ticks + 180; // 3 seconds at 60fps if (vampires2[v2].children[0]) { tween(vampires2[v2].children[0], { tint: 0x4444FF }, { duration: 500 }); } } // Stun all zombies for (var z = 0; z < zombies.length; z++) { zombies[z].stunned = true; zombies[z].stunnedUntil = LK.ticks + 180; // 3 seconds at 60fps if (zombies[z].children[0]) { tween(zombies[z].children[0], { tint: 0x4444FF }, { duration: 500 }); } } // Stun wendigo if it exists if (wendigo) { wendigo.stunned = true; wendigo.stunnedUntil = LK.ticks + 180; // 3 seconds at 60fps if (wendigo.wendigoGraphics) { tween(wendigo.wendigoGraphics, { tint: 0x4444FF }, { duration: 500 }); } } // Kill only this vampire2 that hit the player self.destroy(); vampires2.splice(vampires2.indexOf(self), 1); playerLives--; updateLivesDisplay(); LK.setTimeout(function () { if (playerLives <= 0) { LK.showGameOver(); } else { // Respawn fox at safe location fox.x = 1024; fox.y = 1366; } }, 1000); } else if (target !== fox && distance < 50) { // Attack NPC var isKilled = target.takeDamage(self); if (isKilled) { target.killed = true; tween(target, { alpha: 0, scaleX: 0, scaleY: 0 }, { duration: 500, onFinish: function onFinish() { target.destroy(); npcs.splice(npcs.indexOf(target), 1); } }); } } } // Vampire animation vampire2Graphics.scaleX = 0.8 + Math.sin(LK.ticks * 0.4) * 0.1; vampire2Graphics.scaleY = 0.8 + Math.cos(LK.ticks * 0.3) * 0.1; }; return self; }); var Wendigo = Container.expand(function () { var self = Container.call(this); // Create a scary looking wendigo using a dark red box shape var wendigoGraphics = self.attachAsset('wendigoBody', { anchorX: 0.5, anchorY: 0.5 }); self.wendigoGraphics = wendigoGraphics; // Store reference for stunning self.speed = 3; self.lastFoxX = 0; self.lastFoxY = 0; self.update = function () { // Wendigo appears during blood moon or twisted blood moon if (!isBloodMoon && !isTwistedBloodMoon) return; if (isTwistedBloodMoon) { // During full moon, wendigo runs through but doesn't attack // Simple movement animation without targeting wendigoGraphics.scaleX = 1 + Math.sin(LK.ticks * 0.2) * 0.1; wendigoGraphics.scaleY = 1 + Math.cos(LK.ticks * 0.2) * 0.1; // Move wendigo across screen self.x += 2; if (self.x > 2200) { self.x = -200; } return; } if (self.stunned && LK.ticks < self.stunnedUntil) { // Wendigo is stunned, can't move return; } else if (self.stunned) { // Stun expired, remove stun self.stunned = false; tween(wendigoGraphics, { tint: 0xFFFFFF }, { duration: 300 }); } // Check for dog collision for stunning for (var d = 0; d < npcs.length; d++) { if (npcs[d].type === 'dog' && npcs[d].isTargeted && self.intersects(npcs[d])) { npcs[d].stunThreat(self); break; } } // Calculate survival time and increase speed accordingly var survivalTime = (LK.ticks - bloodMoonStartTime) / 60; // Convert to seconds var currentSpeed = self.speed + survivalTime * wendigoSpeedIncreaseRate; // Wendigo targeting with probability system var target = null; var availableTargets = []; // Check for frozen NPC first (always highest priority) for (var i = 0; i < npcs.length; i++) { if (npcs[i].frozen && !npcs[i].killed) { target = npcs[i]; break; } } // If no frozen NPC, use probability system (excluding mouse, bat, and fennec from targeting) if (!target) { // Create weighted target list based on probabilities for (var i = 0; i < npcs.length; i++) { var npc = npcs[i]; if (!npc.inCabin && !npc.killed && npc.type !== 'mouse' && npc.type !== 'bat' && npc.type !== 'fennec') { var weight = 0; if (npc.type === 'cat' || npc.type === 'bunny' || npc.type === 'squirrel') { weight = 25; // Common NPCs 25% } else if (npc.type === 'dog') { weight = 50; // Dog 50% } else if (npc.type === 'deer') { weight = 30; // Deer 30% } // Add multiple entries based on weight for probability for (var w = 0; w < weight; w++) { availableTargets.push(npc); } } } // Select random target from weighted list if (availableTargets.length > 0) { target = availableTargets[Math.floor(Math.random() * availableTargets.length)]; target.isTargeted = true; // Mark target as targeted } } if (!target) { target = fox; } if (!target) return; // Move towards target var dx = target.x - self.x; var dy = target.y - self.y; var distance = Math.sqrt(dx * dx + dy * dy); // Start wendigo chase music if targeting fox and close enough if (target === fox && distance < 400 && !isWendigoChaseThemePlaying) { isWendigoChaseThemePlaying = true; LK.stopMusic(); LK.playMusic('wendigoChaseTheme'); } else if ((target !== fox || distance >= 500) && isWendigoChaseThemePlaying) { // Stop chase music if not targeting fox or far away isWendigoChaseThemePlaying = false; LK.stopMusic(); LK.playMusic('bloodMoonMusic'); } if (distance > 0) { // Normalize direction and apply increasing speed self.x += dx / distance * currentSpeed; self.y += dy / distance * currentSpeed; } // Check if wendigo caught frozen NPC for (var i = 0; i < npcs.length; i++) { var npc = npcs[i]; if (npc.frozen && !npc.killed && self.intersects(npc)) { // Attack the NPC (dogs take 2 hits, others die in 1) var isKilled = npc.takeDamage(self); if (isKilled) { npc.killed = true; // During blood moon cutscene, mark NPC for delayed removal if (isBloodMoonCutscene) { cutsceneNPCKilled = npc; cutsceneNPCKillTime = LK.ticks; // Make NPC fade but don't remove immediately tween(npc, { alpha: 0.3, tint: 0x888888 }, { duration: 500 }); } else { // Normal behavior - make NPC disappear with death effect tween(npc, { alpha: 0, scaleX: 0, scaleY: 0 }, { duration: 500, onFinish: function onFinish() { npc.destroy(); npcs.splice(npcs.indexOf(npc), 1); } }); } } // Play kill sound LK.getSound('wendigoGrowl').play(); break; } } // Check if wendigo caught the fox if (self.intersects(fox)) { // Fox is caught - create jumpscare effect LK.effects.flashScreen(0x000000, 700); // Create and show wendigo jumpscare var wendigoJumpscare = new JumpscareDisplay('wendigoJumpscare'); game.addChild(wendigoJumpscare); wendigoJumpscare.showJumpscare(); // Play jumpscare stinger immediately LK.getSound('jumpscareStinger').play(); // Scale wendigo up for additional effect tween(wendigo, { scaleX: 2.5, scaleY: 2.5 }, { duration: 150 }); // Play wendigo growl slightly delayed LK.setTimeout(function () { LK.getSound('wendigoGrowl').play(); }, 150); // Stun ALL enemies, but kill only this wendigo // Stun all wolves for (var w = 0; w < wolves.length; w++) { wolves[w].stunned = true; wolves[w].stunnedUntil = LK.ticks + 180; // 3 seconds at 60fps if (wolves[w].children[0]) { tween(wolves[w].children[0], { tint: 0x4444FF }, { duration: 500 }); } } // Stun all vampires for (var v = 0; v < vampires.length; v++) { vampires[v].stunned = true; vampires[v].stunnedUntil = LK.ticks + 180; // 3 seconds at 60fps if (vampires[v].children[0]) { tween(vampires[v].children[0], { tint: 0x4444FF }, { duration: 500 }); } } // Stun all vampires2 for (var v2 = 0; v2 < vampires2.length; v2++) { vampires2[v2].stunned = true; vampires2[v2].stunnedUntil = LK.ticks + 180; // 3 seconds at 60fps if (vampires2[v2].children[0]) { tween(vampires2[v2].children[0], { tint: 0x4444FF }, { duration: 500 }); } } // Stun all zombies for (var z = 0; z < zombies.length; z++) { zombies[z].stunned = true; zombies[z].stunnedUntil = LK.ticks + 180; // 3 seconds at 60fps if (zombies[z].children[0]) { tween(zombies[z].children[0], { tint: 0x4444FF }, { duration: 500 }); } } // Kill only this wendigo that hit the player self.destroy(); wendigo = null; // Decrease player lives playerLives--; updateLivesDisplay(); // Show scary game over after jumpscare LK.setTimeout(function () { if (playerLives <= 0) { LK.showGameOver(); } else { // Respawn fox at safe location fox.x = 1024; fox.y = 1366; // End blood moon early when player gets caught isBloodMoon = false; startDay(); } }, 1200); return; } // Add scary breathing/pulsing effect wendigoGraphics.scaleX = 1 + Math.sin(LK.ticks * 0.2) * 0.1; wendigoGraphics.scaleY = 1 + Math.cos(LK.ticks * 0.2) * 0.1; }; return self; }); var Wolf = Container.expand(function () { var self = Container.call(this); var wolfGraphics = self.attachAsset('wolf', { anchorX: 0.5, anchorY: 0.5 }); self.speed = 2; self.update = function () { if (!isNight) return; if (self.stunned && LK.ticks < self.stunnedUntil) { // Wolf is stunned, can't move - stop chase music if this wolf was chasing if (isChaseThemePlaying) { var anyOtherWolfChasing = false; for (var wc = 0; wc < wolves.length; wc++) { var wolf = wolves[wc]; if (wolf !== self && wolf && !wolf.stunned) { var foxDist = Math.sqrt(Math.pow(fox.x - wolf.x, 2) + Math.pow(fox.y - wolf.y, 2)); if (foxDist < 800) { anyOtherWolfChasing = true; break; } } } if (!anyOtherWolfChasing) { isChaseThemePlaying = false; LK.stopMusic(); if (isPeacefulNight) { LK.playMusic('peacefulNightAmbience'); } else { LK.playMusic('nightMusic'); } } } return; } else if (self.stunned) { // Stun expired, remove stun self.stunned = false; tween(wolfGraphics, { tint: 0xFFFFFF }, { duration: 300 }); } // Check for dog collision for stunning for (var d = 0; d < npcs.length; d++) { if (npcs[d].type === 'dog' && npcs[d].isTargeted && self.intersects(npcs[d])) { npcs[d].stunThreat(self); break; } } // Find closest target (fox or NPCs) var closestTarget = null; var closestDistance = Infinity; var detectionRange = 800; // Bigger detection range for wolves // Check distance to fox var foxDx = fox.x - self.x; var foxDy = fox.y - self.y; var foxDistance = Math.sqrt(foxDx * foxDx + foxDy * foxDy); if (foxDistance < detectionRange && foxDistance < closestDistance) { closestTarget = fox; closestDistance = foxDistance; } // Check distance to NPCs near campfire (excluding bats) for (var n = 0; n < npcs.length; n++) { if (!npcs[n].inCabin && !npcs[n].killed && npcs[n].type !== 'bat') { var npcDx = npcs[n].x - self.x; var npcDy = npcs[n].y - self.y; var npcDistance = Math.sqrt(npcDx * npcDx + npcDy * npcDy); // Check if NPC is near campfire (within 300 pixels of campfire) var npcToCampfireDist = Math.sqrt(Math.pow(npcs[n].x - campfire.x, 2) + Math.pow(npcs[n].y - campfire.y, 2)); if (npcToCampfireDist < 300 && npcDistance < detectionRange && npcDistance < closestDistance) { closestTarget = npcs[n]; closestDistance = npcDistance; } } } // If no high priority target found, go to campfire if (!closestTarget) { var campfireDx = campfire.x - self.x; var campfireDy = campfire.y - self.y; var campfireDistance = Math.sqrt(campfireDx * campfireDx + campfireDy * campfireDy); if (campfireDistance > 200) { // Stay around campfire area closestTarget = campfire; closestDistance = campfireDistance; } } // Only chase if there's a target within range if (closestTarget && (closestDistance < detectionRange || closestTarget === campfire)) { // Start chase music if not already playing and wolf is chasing fox if (!isChaseThemePlaying && closestTarget === fox && closestDistance < detectionRange) { isChaseThemePlaying = true; LK.stopMusic(); LK.playMusic('chaseTheme'); } var dx = closestTarget.x - self.x; var dy = closestTarget.y - self.y; var distance = Math.sqrt(dx * dx + dy * dy); if (distance > 0) { // Use slower speed when going to campfire, normal speed for other targets var moveSpeed = closestTarget === campfire ? self.speed * 0.5 : self.speed; self.x += dx / distance * moveSpeed; self.y += dy / distance * moveSpeed; } } else { // No valid target - check if we should stop chase music if (isChaseThemePlaying) { // Check if ANY wolf is actively chasing fox within detection range var anyWolfChasing = false; for (var wc = 0; wc < wolves.length; wc++) { var wolf = wolves[wc]; if (wolf && !wolf.stunned) { var foxDist = Math.sqrt(Math.pow(fox.x - wolf.x, 2) + Math.pow(fox.y - wolf.y, 2)); if (foxDist < detectionRange) { anyWolfChasing = true; break; } } } if (!anyWolfChasing) { isChaseThemePlaying = false; LK.stopMusic(); if (isPeacefulNight) { LK.playMusic('peacefulNightAmbience'); } else { LK.playMusic('nightMusic'); } } } // Add prowling animation when not chasing wolfGraphics.scaleX = 1 + Math.sin(LK.ticks * 0.1) * 0.1; // 50% chance to target a berry and wait there if (!self.berryTarget && !self.wanderTarget && Math.random() < 0.01) { if (Math.random() < 0.5 && normalBerries.length > 0) { // 50% chance to target a berry self.berryTarget = normalBerries[Math.floor(Math.random() * normalBerries.length)]; } else { // Otherwise wander normally self.wanderTarget = { x: Math.random() * (1800 - 200) + 200, y: Math.random() * (2400 - 200) + 200 }; } } // Move towards berry target and wait there if (self.berryTarget) { // Check if berry still exists var berryExists = false; for (var b = 0; b < normalBerries.length; b++) { if (normalBerries[b] === self.berryTarget) { berryExists = true; break; } } if (!berryExists) { // Berry was collected, pick a new target self.berryTarget = null; } else { var berryDx = self.berryTarget.x - self.x; var berryDy = self.berryTarget.y - self.y; var berryDistance = Math.sqrt(berryDx * berryDx + berryDy * berryDy); if (berryDistance > 100) { // Move towards berry var berrySpeed = self.speed * 0.4; self.x += berryDx / berryDistance * berrySpeed; self.y += berryDy / berryDistance * berrySpeed; } // If close enough to berry (within 100 pixels), just wait there } } // Wandering behavior when not targeting berry or chasing if (!self.berryTarget && self.wanderTarget) { var wanderDx = self.wanderTarget.x - self.x; var wanderDy = self.wanderTarget.y - self.y; var wanderDistance = Math.sqrt(wanderDx * wanderDx + wanderDy * wanderDy); if (wanderDistance > 50) { // Only move if not close to target var wanderSpeed = self.speed * 0.3; // Slower wandering speed self.x += wanderDx / wanderDistance * wanderSpeed; self.y += wanderDy / wanderDistance * wanderSpeed; } else { // Reached wander target, pick a new one self.wanderTarget = null; } } } // Check if wolf caught an NPC near campfire (excluding bats) for (var n = 0; n < npcs.length; n++) { if (!npcs[n].inCabin && !npcs[n].killed && npcs[n].type !== 'bat' && self.intersects(npcs[n])) { var npcToCampfireDist = Math.sqrt(Math.pow(npcs[n].x - campfire.x, 2) + Math.pow(npcs[n].y - campfire.y, 2)); if (npcToCampfireDist < 300) { // Wolf attacks NPC near campfire var isKilled = npcs[n].takeDamage(self); if (isKilled) { npcs[n].killed = true; tween(npcs[n], { alpha: 0, scaleX: 0, scaleY: 0 }, { duration: 500, onFinish: function onFinish() { npcs[n].destroy(); npcs.splice(npcs.indexOf(npcs[n]), 1); } }); } else { // NPC runs around briefly then returns to campfire npcs[n].runFromWolf = true; npcs[n].runStartTime = LK.ticks; var runX = Math.random() * (1800 - 200) + 200; var runY = Math.random() * (2400 - 200) + 200; tween(npcs[n], { x: runX, y: runY }, { duration: 2000, onFinish: function onFinish() { // Return to campfire area var campfireReturnX = campfire.x + (Math.random() - 0.5) * 200; var campfireReturnY = campfire.y + (Math.random() - 0.5) * 200; tween(npcs[n], { x: campfireReturnX, y: campfireReturnY }, { duration: 1500, onFinish: function onFinish() { npcs[n].runFromWolf = false; } }); } }); } break; } } } // Check if wolf caught the fox for jumpscare if (self.intersects(fox)) { // Wolf jumpscare effect LK.effects.flashScreen(0xFFFFFF, 400); // Create and show wolf jumpscare var wolfJumpscare = new JumpscareDisplay('wolfJumpscare'); game.addChild(wolfJumpscare); wolfJumpscare.showJumpscare(); // Play jumpscare stinger immediately LK.getSound('jumpscareStinger').play(); // Scale wolf up for additional effect tween(self, { scaleX: 2, scaleY: 2 }, { duration: 120 }); // Play wolf roar slightly delayed LK.setTimeout(function () { LK.getSound('wolfRoar').play(); }, 120); // Stun ALL enemies, but kill only this wolf // Stun all other wolves for (var w = 0; w < wolves.length; w++) { wolves[w].stunned = true; wolves[w].stunnedUntil = LK.ticks + 180; // 3 seconds at 60fps if (wolves[w].children[0]) { tween(wolves[w].children[0], { tint: 0x4444FF }, { duration: 500 }); } } // Stun all vampires for (var v = 0; v < vampires.length; v++) { vampires[v].stunned = true; vampires[v].stunnedUntil = LK.ticks + 180; // 3 seconds at 60fps if (vampires[v].children[0]) { tween(vampires[v].children[0], { tint: 0x4444FF }, { duration: 500 }); } } // Stun all vampires2 for (var v2 = 0; v2 < vampires2.length; v2++) { vampires2[v2].stunned = true; vampires2[v2].stunnedUntil = LK.ticks + 180; // 3 seconds at 60fps if (vampires2[v2].children[0]) { tween(vampires2[v2].children[0], { tint: 0x4444FF }, { duration: 500 }); } } // Stun all zombies for (var z = 0; z < zombies.length; z++) { zombies[z].stunned = true; zombies[z].stunnedUntil = LK.ticks + 180; // 3 seconds at 60fps if (zombies[z].children[0]) { tween(zombies[z].children[0], { tint: 0x4444FF }, { duration: 500 }); } } // Stun wendigo if it exists if (wendigo) { wendigo.stunned = true; wendigo.stunnedUntil = LK.ticks + 180; // 3 seconds at 60fps if (wendigo.wendigoGraphics) { tween(wendigo.wendigoGraphics, { tint: 0x4444FF }, { duration: 500 }); } } // Kill only this wolf that hit the player self.destroy(); wolves.splice(wolves.indexOf(self), 1); // Decrease player lives playerLives--; updateLivesDisplay(); // Check if game over or respawn LK.setTimeout(function () { if (playerLives <= 0) { LK.showGameOver(); } else { // Respawn fox at safe location fox.x = 1024; fox.y = 1366; } }, 1000); return; } }; return self; }); var Wood = Container.expand(function () { var self = Container.call(this); var woodGraphics = self.attachAsset('wood', { anchorX: 0.5, anchorY: 0.5 }); self.update = function () { // Gentle floating animation self.y += Math.sin(LK.ticks * 0.1 + self.x * 0.01) * 0.5; }; return self; }); var Zombie = Container.expand(function () { var self = Container.call(this); var zombieGraphics = self.attachAsset('zombie', { anchorX: 0.5, anchorY: 0.5 }); self.speed = 1; // Slow zombie self.update = function () { if (!isNight && !isTwistedBloodMoon && !isBloodMoon) return; // During blood moon cutscene, wait at campfire but don't follow wendigo if (isBloodMoonCutscene) { // If wendigo is at campfire and no NPCs around, zombies wait at campfire if (cutsceneWendigoAtCampfire && cutsceneZombiesWaiting) { var campfireDx = campfire.x - self.x; var campfireDy = campfire.y - self.y; var campfireDistance = Math.sqrt(campfireDx * campfireDx + campfireDy * campfireDy); if (campfireDistance > 150) { // Move to campfire area self.x += campfireDx / campfireDistance * (self.speed * 0.5); self.y += campfireDy / campfireDistance * (self.speed * 0.5); } return; } // If wendigo killed an NPC, stay still for 5 seconds if (cutsceneNPCKilled && LK.ticks - cutsceneNPCKillTime < 300) { return; // Stay still } // Allow normal zombie behavior during blood moon cutscene when not waiting } // Check if stunned if (self.stunned && LK.ticks < self.stunnedUntil) { return; // Can't move when stunned } else if (self.stunned) { // Stun expired, remove stun self.stunned = false; tween(zombieGraphics, { tint: 0xFFFFFF }, { duration: 300 }); } // Zombies prioritize NPCs not in cabin over fox during blood moon var closestTarget = null; var closestDistance = Infinity; var detectionRange = 600; // Increased detection range for better chasing // First priority: Check for NPCs that are not in cabin (excluding only bat) for (var n = 0; n < npcs.length; n++) { if (!npcs[n].inCabin && !npcs[n].killed && npcs[n].type !== 'bat') { var npcDx = npcs[n].x - self.x; var npcDy = npcs[n].y - self.y; var npcDistance = Math.sqrt(npcDx * npcDx + npcDy * npcDy); if (npcDistance < detectionRange && npcDistance < closestDistance) { closestTarget = npcs[n]; closestDistance = npcDistance; } } } // Second priority: Check distance to fox only if no NPCs available if (!closestTarget) { var foxDx = fox.x - self.x; var foxDy = fox.y - self.y; var foxDistance = Math.sqrt(foxDx * foxDx + foxDy * foxDy); if (foxDistance < detectionRange) { closestTarget = fox; closestDistance = foxDistance; } } // Only chase if there's a target within range if (closestTarget && closestDistance < detectionRange) { // Start chase music if not already playing and zombie is chasing fox if (!isZombieChaseThemePlaying && closestTarget === fox) { isZombieChaseThemePlaying = true; LK.stopMusic(); LK.playMusic('zombieChaseTheme'); } var dx = closestTarget.x - self.x; var dy = closestTarget.y - self.y; var distance = Math.sqrt(dx * dx + dy * dy); if (distance > 0) { self.x += dx / distance * self.speed; self.y += dy / distance * self.speed; } } else { // Check if we should stop chase music if (isZombieChaseThemePlaying) { var anyZombieChasing = false; for (var zc = 0; zc < zombies.length; zc++) { if (zombies[zc] !== self) { var foxDist = Math.sqrt(Math.pow(fox.x - zombies[zc].x, 2) + Math.pow(fox.y - zombies[zc].y, 2)); if (foxDist < detectionRange) { anyZombieChasing = true; break; } } } if (!anyZombieChasing) { isZombieChaseThemePlaying = false; LK.stopMusic(); if (isTwistedBloodMoon) { LK.playMusic('twistedBloodMoonTheme'); } else if (isBloodMoon) { LK.playMusic('bloodMoonMusic'); } else if (isPeacefulNight) { LK.playMusic('peacefulNightAmbience'); } else if (isNight) { LK.playMusic('nightMusic'); } } } // Add prowling animation when not chasing zombieGraphics.scaleX = 0.7 + Math.sin(LK.ticks * 0.1) * 0.05; // Simplified movement - no berry targeting, focus on chasing } // Check collision with NPCs first (higher priority than fox) for (var n = 0; n < npcs.length; n++) { if (!npcs[n].inCabin && !npcs[n].killed && npcs[n].type !== 'bat' && self.intersects(npcs[n])) { // Zombie attacks NPC var isKilled = npcs[n].takeDamage(self); if (isKilled) { npcs[n].killed = true; tween(npcs[n], { alpha: 0, scaleX: 0, scaleY: 0 }, { duration: 500, onFinish: function onFinish() { npcs[n].destroy(); npcs.splice(npcs.indexOf(npcs[n]), 1); } }); } break; } } // Check collision with fox if (self.intersects(fox)) { // Zombie caught fox LK.effects.flashScreen(0x00FF00, 300); // Create and show zombie jumpscare var zombieJumpscare = new JumpscareDisplay('zombieJumpscare'); game.addChild(zombieJumpscare); zombieJumpscare.showJumpscare(); // Play jumpscare stinger immediately LK.getSound('jumpscareStinger').play(); // Play zombie sound slightly delayed LK.setTimeout(function () { LK.getSound('glitchSound').play(); }, 100); // Stun ALL enemies, but kill only this zombie // Stun all wolves for (var w = 0; w < wolves.length; w++) { wolves[w].stunned = true; wolves[w].stunnedUntil = LK.ticks + 180; // 3 seconds at 60fps if (wolves[w].children[0]) { tween(wolves[w].children[0], { tint: 0x4444FF }, { duration: 500 }); } } // Stun all vampires for (var v = 0; v < vampires.length; v++) { vampires[v].stunned = true; vampires[v].stunnedUntil = LK.ticks + 180; // 3 seconds at 60fps if (vampires[v].children[0]) { tween(vampires[v].children[0], { tint: 0x4444FF }, { duration: 500 }); } } // Stun all vampires2 for (var v2 = 0; v2 < vampires2.length; v2++) { vampires2[v2].stunned = true; vampires2[v2].stunnedUntil = LK.ticks + 180; // 3 seconds at 60fps if (vampires2[v2].children[0]) { tween(vampires2[v2].children[0], { tint: 0x4444FF }, { duration: 500 }); } } // Stun all other zombies for (var z = 0; z < zombies.length; z++) { zombies[z].stunned = true; zombies[z].stunnedUntil = LK.ticks + 180; // 3 seconds at 60fps if (zombies[z].children[0]) { tween(zombies[z].children[0], { tint: 0x4444FF }, { duration: 500 }); } } // Stun wendigo if it exists if (wendigo) { wendigo.stunned = true; wendigo.stunnedUntil = LK.ticks + 180; // 3 seconds at 60fps if (wendigo.wendigoGraphics) { tween(wendigo.wendigoGraphics, { tint: 0x4444FF }, { duration: 500 }); } } // Kill only this zombie that hit the player self.destroy(); zombies.splice(zombies.indexOf(self), 1); playerLives--; updateLivesDisplay(); LK.setTimeout(function () { if (playerLives <= 0) { LK.showGameOver(); } else { // Respawn fox at safe location fox.x = 1024; fox.y = 1366; } }, 800); return; } // Zombie animation zombieGraphics.scaleY = 0.7 + Math.cos(LK.ticks * 0.15) * 0.05; }; return self; }); /**** * Initialize Game ****/ var game = new LK.Game({ backgroundColor: 0x228b22 }); /**** * Game Code ****/ // Game state variables function _typeof(o) { "@babel/helpers - typeof"; return _typeof = "function" == typeof Symbol && "symbol" == typeof Symbol.iterator ? function (o) { return typeof o; } : function (o) { return o && "function" == typeof Symbol && o.constructor === Symbol && o !== Symbol.prototype ? "symbol" : typeof o; }, _typeof(o); } var fox; var normalBerries = []; var wolves = []; var npcs = []; var dragNode = null; var berrySpawnTimer = 0; var wendigo; var wendigoSpeedIncreaseRate = 0.02; var bunny; var cabin; // Cutscene variables var isIntroCutscene = true; var introCutsceneTimer = 0; var introCutsceneDelay = 120; // 2 seconds delay before cutscene starts var foxAppearedSoundPlayed = false; var doorSoundPlayed = false; var isBloodMoonCutscene = false; var bloodMoonCutsceneTimer = 0; var cutsceneNPCKilled = null; var cutsceneNPCKillTime = 0; var cutsceneWendigoAtCampfire = false; var cutsceneZombiesWaiting = false; var cutsceneZombiesWaitStartTime = 0; var cutsceneNPCSpawned = false; // Day/Night cycle variables var isNight = false; var isBloodMoon = false; var isPeacefulNight = false; var isTwistedBloodMoon = false; var vampires = []; var vampires2 = []; var zombies = []; var nightCount = 0; var dayCount = 1; var berriesCollectedInCycle = 0; var scoreMultiplier = 1; var bloodMoonStartTime = 0; var bloodMoonCount = 0; var dayLengthMultiplier = 1; var isChaseThemePlaying = false; var isZombieChaseThemePlaying = false; var isWendigoChaseThemePlaying = false; var isCultistChaseThemePlaying = false; var cultistVampires = []; var hearts = []; var playerLives = 3; var campfire; var woodItems = []; var twistedBloodMoonWoodCollected = 0; // Track wood collected during full moon var lastBloodMoonNight = -1; // Track when last blood moon occurred var woodSpawnTimer = 0; // Timer for wood spawning during different phases // NPC types organized by rarity var commonNPCs = ['cat', 'bunny', 'squirrel']; var uncommonNPCs = ['deer', 'fennec', 'hedgehog']; var rareNPCs = ['dog', 'mouse', 'bat', 'robot']; // Add forest background var background = game.attachAsset('forestBackground', { x: 0, y: 0 }); // Create score display var scoreTxt = new Text2('Score: 0 (x1)', { size: 80, fill: 0xFFFFFF }); scoreTxt.anchor.set(0.5, 0); LK.gui.top.addChild(scoreTxt); // Create day/night indicator var dayNightTxt = new Text2('Day', { size: 60, fill: 0xFFFF00 }); dayNightTxt.anchor.set(0.5, 0); dayNightTxt.y = 100; LK.gui.top.addChild(dayNightTxt); // Create day counter display var dayCounterTxt = new Text2('Day 1', { size: 60, fill: 0xFFFFFF }); dayCounterTxt.anchor.set(0.5, 0); dayCounterTxt.y = 170; LK.gui.top.addChild(dayCounterTxt); // Create night counter display var nightCounterTxt = new Text2('Night 1', { size: 60, fill: 0xFFFFFF }); nightCounterTxt.anchor.set(0.5, 0); nightCounterTxt.y = 170; nightCounterTxt.visible = false; // Hidden by default during day LK.gui.top.addChild(nightCounterTxt); // Create lives counter display var livesTxt = new Text2('Lives: 3', { size: 60, fill: 0xFF0000 }); livesTxt.anchor.set(0.5, 0); livesTxt.y = 240; LK.gui.top.addChild(livesTxt); // Create campfire wood counter display var campfireTxt = new Text2('Campfire: 0 wood', { size: 50, fill: 0xFFFFFF }); campfireTxt.anchor.set(0.5, 0); campfireTxt.y = 310; campfireTxt.visible = false; // Hidden by default LK.gui.top.addChild(campfireTxt); // Create wood multiplier display var woodMultiplierTxt = new Text2('Wood Multiplier: Cat 2x, Bunny 2x, Bat 4x', { size: 45, fill: 0x90EE90 }); woodMultiplierTxt.anchor.set(0.5, 0); woodMultiplierTxt.y = 370; woodMultiplierTxt.visible = false; // Hidden by default LK.gui.top.addChild(woodMultiplierTxt); // Create NPC class display var npcClassTxt = new Text2('NPC CLASSES:\n\nSurvivors: Mouse, Bunny\nStunners: Dog, Fennec, Hedgehog\nCollectors: Bunny, Deer\nSupports: Bat, Squirrel, Robot', { size: 55, fill: 0xFFFFFF }); npcClassTxt.anchor.set(0, 1); // Left-aligned, bottom-anchored npcClassTxt.x = 20; // Small margin from left edge npcClassTxt.y = -20; // Small margin from bottom edge npcClassTxt.visible = false; // Initially hidden LK.gui.bottomLeft.addChild(npcClassTxt); // Add cabin for NPCs cabin = game.attachAsset('cabin', { anchorX: 0.5, anchorY: 0.5, x: 1650, y: 450 }); // Add campfire campfire = game.addChild(new Campfire()); campfire.x = 1024; campfire.y = 1000; // Bunny removed from initial spawn // Initialize fox fox = game.addChild(new Fox()); // Start fox at cabin for intro cutscene fox.x = cabin.x; fox.y = cabin.y; // Spawn normal berry function function spawnNormalBerry() { // Spawn single berry - no duplication var berry = new NormalBerry(); berry.x = Math.random() * (2048 - 120) + 60; berry.y = Math.random() * (2732 - 120) + 60; normalBerries.push(berry); game.addChild(berry); } // Spawn wolf function function spawnWolf() { var wolf = new Wolf(); wolf.x = Math.random() * (2048 - 120) + 60; wolf.y = Math.random() * (2732 - 120) + 60; wolves.push(wolf); game.addChild(wolf); } // Spawn wood function function spawnWood() { var wood = new Wood(); wood.x = Math.random() * (2048 - 120) + 60; wood.y = Math.random() * (2732 - 120) + 60; woodItems.push(wood); game.addChild(wood); } // Spawn zombie function function spawnZombie() { var zombie = new Zombie(); // During blood moon, scatter zombies in random locations across the map if (isBloodMoon) { // Scatter zombies randomly across the entire map during blood moon zombie.x = Math.random() * (1800 - 200) + 200; // Random X position zombie.y = Math.random() * (2200 - 400) + 400; // Random Y position } else { // Default spawn behavior for non-blood moon scenarios zombie.x = Math.random() * (2048 - 120) + 60; zombie.y = Math.random() * (2732 - 120) + 60; } zombies.push(zombie); game.addChild(zombie); } // Spawn vampire function function spawnVampire() { var vampire = new Vampire(); vampire.x = Math.random() * (2048 - 120) + 60; vampire.y = Math.random() * (2732 - 120) + 60; vampires.push(vampire); game.addChild(vampire); } // Spawn vampire2 function function spawnVampire2() { var vampire2 = new Vampire2(); vampire2.x = Math.random() * (2048 - 120) + 60; vampire2.y = Math.random() * (2732 - 120) + 60; vampires2.push(vampire2); game.addChild(vampire2); } // Update campfire display function updateCampfireDisplay() { campfireTxt.setText('Campfire: ' + campfire.wood + ' wood'); } // Spawn NPC function function spawnNPC() { // Determine rarity first with updated probabilities var rarity; var selectedType; var rarityRand = Math.random(); // Check for robot special case first (30% instead of 15%) if (rarityRand <= 0.3) { // 30% chance for robot specifically selectedType = 'robot'; rarity = 'rare'; } else if (rarityRand <= 0.5) { // Common NPCs: 20% chance (reduced from 50% due to robot) rarity = 'common'; selectedType = commonNPCs[Math.floor(Math.random() * commonNPCs.length)]; } else if (rarityRand <= 0.85) { // Uncommon NPCs: 35% chance (includes hedgehog) rarity = 'uncommon'; selectedType = uncommonNPCs[Math.floor(Math.random() * uncommonNPCs.length)]; } else { // Other Rare NPCs: 15% chance (excluding robot) rarity = 'rare'; var otherRareNPCs = ['dog', 'mouse', 'bat']; // Exclude robot selectedType = otherRareNPCs[Math.floor(Math.random() * otherRareNPCs.length)]; } var npc; if (selectedType === 'hedgehog') { npc = new Hedgehog(); npc.type = 'hedgehog'; } else if (selectedType === 'robot') { npc = new Robot(); npc.type = 'robot'; } else { npc = new NPC(selectedType); } npc.rarity = rarity; npc.setRarityVisual(); // Apply visual indication based on rarity npc.x = Math.random() * (1800 - 200) + 200; npc.y = Math.random() * (2400 - 200) + 200; npcs.push(npc); game.addChild(npc); // If bat spawns, give extra life immediately if (selectedType === 'bat') { playerLives++; updateLivesDisplay(); LK.getSound('batTouch').play(); } // Apply multiplier immediately when NPC spawns if (npc.multiplier > 0) { scoreMultiplier = npc.multiplier; updateScoreDisplay(); } } // Transition to night function startNight() { isNight = true; nightCount++; berriesCollectedInCycle = 0; // Reset but not used for transitions // Check for blood moon - 3rd night is guaranteed, then 25% chance (but not consecutive) var shouldBeBloodMoon = false; if (nightCount === 3) { // 3rd night is always a blood moon shouldBeBloodMoon = true; } else if (nightCount > 3 && nightCount !== lastBloodMoonNight + 1) { // After 3rd night, 25% chance for blood moon, but not if last night was blood moon shouldBeBloodMoon = Math.random() < 0.25; } // Check for peaceful night - 25% base chance, 100% chance before blood moon, forced on night 2 var peacefulChance = 0.25; if (nightCount === 2) { // Night 2 is always peaceful since night 3 is guaranteed blood moon peacefulChance = 1.0; } else if (nightCount > 3) { // For nights after 3, check if NEXT night could be blood moon var nextNightCouldBeBloodMoon = nightCount + 1 !== lastBloodMoonNight + 1 && Math.random() < 0.25; if (nextNightCouldBeBloodMoon) { // If next night could be blood moon, make this night peaceful peacefulChance = 1.0; } } isPeacefulNight = Math.random() < peacefulChance && !shouldBeBloodMoon; // Only play howl if not peaceful night if (!isPeacefulNight) { LK.getSound('howl').play(); } // Stop any currently playing music and switch to appropriate night music LK.stopMusic(); if (isPeacefulNight) { LK.playMusic('peacefulNightAmbience'); } else { LK.playMusic('nightMusic'); } if (shouldBeBloodMoon) { bloodMoonCount++; lastBloodMoonNight = nightCount; // Track when blood moon occurred // Add 5 berries to requirement for each blood moon dayLengthMultiplier = 1 + bloodMoonCount * 0.5; // Each blood moon adds 5 berries (0.5 * 10 = 5) isBloodMoon = true; bloodMoonStartTime = LK.ticks; // Start blood moon cutscene isBloodMoonCutscene = true; bloodMoonCutsceneTimer = 0; cutsceneWendigoAtCampfire = false; cutsceneZombiesWaiting = false; cutsceneZombiesWaitStartTime = 0; cutsceneNPCSpawned = false; // Reset multiplier during blood moon scoreMultiplier = 1; updateScoreDisplay(); // Stop current music and play blood moon music LK.stopMusic(); LK.playMusic('bloodMoonMusic'); // Freeze one random NPC if (npcs.length > 0) { var randomNPC = npcs[Math.floor(Math.random() * npcs.length)]; randomNPC.freeze(); } // Remove night slowness from mice when blood moon starts for (var m = 0; m < npcs.length; m++) { if (npcs[m].type === 'mouse' && npcs[m].nightSlowness) { npcs[m].nightSlowness = false; } } // Move other NPCs to cabin for (var i = 0; i < npcs.length; i++) { if (!npcs[i].frozen) { npcs[i].enterCabin(); } } // Always spawn wendigo during blood moon (twisted or normal) wendigo = new Wendigo(); wendigo.x = -100; wendigo.y = Math.random() * 2000 + 300; game.addChild(wendigo); // Always spawn zombies during blood moon (3 zombies) spawnZombie(); spawnZombie(); spawnZombie(); // Vampires are spawned when twisted blood moon is triggered in campfire // Spawn extra berries during blood moon (2-4 additional berries) var extraBerries = Math.floor(Math.random() * 3) + 2; for (var b = 0; b < extraBerries; b++) { spawnNormalBerry(); } // Change background to blood red game.setBackgroundColor(0x330000); tween(background, { tint: 0x660000, alpha: 0.8 }, { duration: 1500 }); dayNightTxt.setText('Blood Moon'); dayNightTxt.fill = 0xFF0000; // Hide day counter and show night counter dayCounterTxt.visible = false; nightCounterTxt.visible = true; nightCounterTxt.setText('Night ' + nightCount); } else { // Regular night if (!isPeacefulNight && nightCount !== 2) { // Spawn wolves - 3 by default, wolf count increases after each completed blood moon // Don't spawn wolves on night 2 var baseWolves = 3 + bloodMoonCount; // Add 1 wolf for each completed blood moon var fennecPresent = false; for (var f = 0; f < npcs.length; f++) { if (npcs[f].type === 'fennec') { fennecPresent = true; break; } } var wolvesToSpawn = fennecPresent ? baseWolves - 1 : baseWolves; // Additional check: explicitly prevent wolf spawning on night 2 if (nightCount === 2) { wolvesToSpawn = 0; } for (var w = 0; w < wolvesToSpawn; w++) { var wolf = new Wolf(); // Spawn wolves from both sides alternating if (w % 2 === 0) { // Even wolves spawn from left side wolf.x = -100; } else { // Odd wolves spawn from right side wolf.x = 2148; } wolf.y = Math.random() * (2200 - 400) + 400; wolves.push(wolf); game.addChild(wolf); } } // Despawn any existing wolves during peaceful nights (especially night 2) if (isPeacefulNight || nightCount === 2) { // Immediately destroy all existing wolves for (var w = wolves.length - 1; w >= 0; w--) { var wolf = wolves[w]; wolf.destroy(); wolves.splice(w, 1); } } // Move NPCs to campfire (even during peaceful nights) for (var i = 0; i < npcs.length; i++) { npcs[i].enterCabin(); } // Change background to dark blue night game.setBackgroundColor(0x001122); tween(background, { tint: 0x223355, alpha: 0.7 }, { duration: 1500 }); if (isPeacefulNight) { dayNightTxt.setText('Peaceful Night'); dayNightTxt.fill = 0x99CCFF; // Hide day counter and show night counter dayCounterTxt.visible = false; nightCounterTxt.visible = true; nightCounterTxt.setText('Night ' + nightCount); } else { dayNightTxt.setText('Night'); dayNightTxt.fill = 0x6666FF; } // Hide day counter and show night counter dayCounterTxt.visible = false; nightCounterTxt.visible = true; nightCounterTxt.setText('Night ' + nightCount); // Show wood counter during night campfireTxt.visible = true; woodMultiplierTxt.visible = true; updateCampfireDisplay(); // Spawn wood during night (3-5 pieces, but only 10% chance during full moon) if (!isTwistedBloodMoon || Math.random() < 0.1) { var woodToSpawn = Math.floor(Math.random() * 3) + 3; for (var w = 0; w < woodToSpawn; w++) { spawnWood(); } } // Spawn zombies (25% chance for 2 zombies, but not during peaceful nights) if (!isPeacefulNight && Math.random() < 0.25) { spawnZombie(); spawnZombie(); } } } // Transition to day function startDay() { isNight = false; isBloodMoon = false; isPeacefulNight = false; isChaseThemePlaying = false; isZombieChaseThemePlaying = false; isWendigoChaseThemePlaying = false; isCultistChaseThemePlaying = false; berriesCollectedInCycle = 0; // Reset but not used for transitions // Stop any currently playing music and switch to day music LK.stopMusic(); LK.playMusic('dayMusic'); // Immediately destroy all wolves when day starts for (var i = 0; i < wolves.length; i++) { var wolf = wolves[i]; wolf.destroy(); } wolves = []; // Remove wendigo if exists if (wendigo) { wendigo.destroy(); wendigo = null; } // Hide wood counter during day campfireTxt.visible = false; woodMultiplierTxt.visible = false; // Remove remaining wood items for (var i = 0; i < woodItems.length; i++) { woodItems[i].destroy(); } woodItems = []; // Remove zombies for (var i = 0; i < zombies.length; i++) { zombies[i].destroy(); } zombies = []; // Remove vampires for (var i = 0; i < vampires.length; i++) { vampires[i].destroy(); } vampires = []; // Remove vampires2 for (var i = 0; i < vampires2.length; i++) { vampires2[i].destroy(); } vampires2 = []; // Remove cultist vampires and spawn hearts for (var i = 0; i < cultistVampires.length; i++) { // Spawn heart at cultist vampire location var heart = new Heart(); heart.x = cultistVampires[i].x; heart.y = cultistVampires[i].y; // Assign target NPC for heart to follow heart.assignNewTarget(); // Give player extra life when heart spawns playerLives++; updateLivesDisplay(); hearts.push(heart); game.addChild(heart); cultistVampires[i].destroy(); } cultistVampires = []; // Reset full moon state isTwistedBloodMoon = false; twistedBloodMoonWoodCollected = 0; // Reset wood counter // Bring NPCs out of cabin and reset dog abilities for (var i = 0; i < npcs.length; i++) { if (!npcs[i].killed) { npcs[i].exitCabin(); // Reset dog abilities for new night if (npcs[i].type === 'dog') { npcs[i].hasShot = false; npcs[i].slowed = false; npcs[i].isTargeted = false; } } } // Spawn new NPC with 25% chance, but force spawn after night 1 or after blood moon var shouldSpawnNPC = Math.random() < 0.25; if (nightCount === 1 || shouldSpawnNPC) { spawnNPC(); } // Always spawn NPC after blood moon (100% chance) if (lastBloodMoonNight === nightCount) { spawnNPC(); } // Change background back to day game.setBackgroundColor(0x228b22); tween(background, { tint: 0xFFFFFF, alpha: 1 }, { duration: 1500 }); dayNightTxt.setText('Day'); dayNightTxt.fill = 0xFFFF00; // Update day counter dayCount++; dayCounterTxt.setText('Day ' + dayCount); // Show day counter and hide night counter dayCounterTxt.visible = true; nightCounterTxt.visible = false; } // Update score display with multiplier function updateScoreDisplay() { scoreTxt.setText('Score: ' + LK.getScore() + ' (x' + scoreMultiplier + ')'); } // Update lives display function updateLivesDisplay() { livesTxt.setText('Lives: ' + playerLives); } // Keyboard state tracking var keys = { left: false, right: false, up: false, down: false }; // Handle mouse/touch move function handleMove(x, y, obj) { // Disable input during intro cutscene if (isIntroCutscene) return; if (dragNode) { dragNode.x = x; dragNode.y = y; // Keep fox within bounds if (dragNode.x < 60) dragNode.x = 60; if (dragNode.x > 1988) dragNode.x = 1988; if (dragNode.y < 60) dragNode.y = 60; if (dragNode.y > 2672) dragNode.y = 2672; } } // Mouse/touch events game.move = handleMove; game.down = function (x, y, obj) { // Disable input during intro cutscene if (isIntroCutscene) return; dragNode = fox; handleMove(x, y, obj); }; game.up = function (x, y, obj) { dragNode = null; }; // Start with day music LK.playMusic('dayMusic'); // Initial berry spawning spawnNormalBerry(); spawnNormalBerry(); spawnNormalBerry(); // Removed forced bat spawning - bats will spawn naturally through normal NPC spawning system // Create light effect for twisted blood moon var foxLight = null; // Hide player initially for 1 second fox.alpha = 0; tween(fox, { alpha: 1 }, { duration: 1000 }); // Main game update loop game.update = function () { // Handle fox light during twisted blood moon if (isTwistedBloodMoon && !foxLight) { // Create a glowing light around fox foxLight = LK.getAsset('campfire', { anchorX: 0.5, anchorY: 0.5, scaleX: 0.5, scaleY: 0.5, alpha: 0.7 }); game.addChild(foxLight); // Animate light with gentle glow tween(foxLight, { alpha: 0.4 }, { duration: 1000, onFinish: function onFinish() { tween(foxLight, { alpha: 0.7 }, { duration: 1000 }); } }); } else if (!isTwistedBloodMoon && foxLight) { // Remove light when not in twisted blood moon foxLight.destroy(); foxLight = null; } // Update light position to follow fox if (foxLight) { foxLight.x = fox.x; foxLight.y = fox.y; } // Handle intro cutscene if (isIntroCutscene) { introCutsceneTimer++; // Wait for delay before starting cutscene if (introCutsceneTimer <= introCutsceneDelay) { return; // Wait before starting cutscene } if (introCutsceneTimer === introCutsceneDelay + 1 && !foxAppearedSoundPlayed) { // Play fox appear sound when fox appears LK.getSound('foxAppear').play(); foxAppearedSoundPlayed = true; } if (introCutsceneTimer === introCutsceneDelay + 30 && !doorSoundPlayed) { // Play door sound 0.5 seconds after fox appears LK.getSound('doorOpen').play(); doorSoundPlayed = true; } // Find nearest berry for target var targetBerry = null; var closestDistance = Infinity; for (var b = 0; b < normalBerries.length; b++) { var dx = normalBerries[b].x - cabin.x; var dy = normalBerries[b].y - cabin.y; var distance = Math.sqrt(dx * dx + dy * dy); if (distance < closestDistance) { closestDistance = distance; targetBerry = normalBerries[b]; } } // Move fox from cabin to nearest berry over 3 seconds after delay if (introCutsceneTimer <= introCutsceneDelay + 180 && targetBerry) { // 3 seconds at 60fps after delay var progress = (introCutsceneTimer - introCutsceneDelay) / 180; var startX = cabin.x; var startY = cabin.y; var endX = targetBerry.x; var endY = targetBerry.y; fox.x = tween.easeInOut(progress) * (endX - startX) + startX; fox.y = tween.easeInOut(progress) * (endY - startY) + startY; } else { // Cutscene finished isIntroCutscene = false; if (targetBerry) { fox.x = targetBerry.x; fox.y = targetBerry.y; } else { fox.x = 1024; fox.y = 1366; } } return; // Don't process other game logic during intro } // Handle blood moon cutscene if (isBloodMoonCutscene) { bloodMoonCutsceneTimer++; // Check if NPC was killed and 5 seconds have passed if (cutsceneNPCKilled && LK.ticks - cutsceneNPCKillTime >= 300) { // 5 seconds at 60fps // Remove the killed NPC body tween(cutsceneNPCKilled, { alpha: 0, scaleX: 0, scaleY: 0 }, { duration: 500, onFinish: function onFinish() { if (cutsceneNPCKilled) { cutsceneNPCKilled.destroy(); npcs.splice(npcs.indexOf(cutsceneNPCKilled), 1); cutsceneNPCKilled = null; } } }); // End cutscene isBloodMoonCutscene = false; bloodMoonCutsceneTimer = 0; // Reset cutscene variables to allow fox movement again cutsceneNPCKilled = null; cutsceneNPCKillTime = 0; } } // Spawn berries over time with random intervals - 1.5-3 seconds berrySpawnTimer++; var baseSpawnTime = 90; // 1.5 seconds at 60fps var maxSpawnTime = 180; // 3 seconds at 60fps var randomSpawnTime = Math.random() * (maxSpawnTime - baseSpawnTime) + baseSpawnTime; if (berrySpawnTimer >= randomSpawnTime) { spawnNormalBerry(); berrySpawnTimer = 0; } // Wood spawning during specific phases woodSpawnTimer++; if (woodSpawnTimer >= 180) { // Every 3 seconds (180 frames at 60fps) woodSpawnTimer = 0; if (isTwistedBloodMoon) { // 25% chance during full moon if (Math.random() < 0.25) { spawnWood(); } } else if (isPeacefulNight || isNight) { // 20% chance during peaceful night and regular night (not blood moon) if (!isBloodMoon && Math.random() < 0.2) { spawnWood(); } } } // Check berry despawn and collisions for (var i = normalBerries.length - 1; i >= 0; i--) { var berry = normalBerries[i]; // Check if berry should despawn after 30 seconds if (berry.spawnTime && LK.ticks - berry.spawnTime >= berry.lifespan) { // Berry despawns after 30 seconds normalBerries.splice(i, 1); berry.destroy(); continue; } if (fox.intersects(berry)) { // Calculate score multiplier considering mouse cabin behavior var currentMultiplier = scoreMultiplier; for (var m = 0; m < npcs.length; m++) { if (npcs[m].type === 'mouse' && npcs[m].inCabin && npcs[m].cabinMultiplier) { // Mouse in cabin provides 2x multiplier instead of 4x currentMultiplier = npcs[m].cabinMultiplier; break; } } // Collect berry and increase score with multiplier var scoreGain = 1 * currentMultiplier; LK.setScore(LK.getScore() + scoreGain); berriesCollectedInCycle++; updateScoreDisplay(); LK.getSound('berryCollect').play(); // Remove berry from array first, then destroy normalBerries.splice(i, 1); berry.destroy(); // Time-based day/night transitions (not affected by berries/score) if (!isTwistedBloodMoon) { // Use LK.ticks for time-based transitions // Day lasts 20 seconds (1200 ticks), night lasts 15 seconds (900 ticks) var dayLength = 1200; // 20 seconds at 60fps var nightLength = isBloodMoon ? 1800 : 900; // Blood moon: 30 seconds, regular night: 15 seconds var currentCycleLength = isNight ? nightLength : dayLength; var cycleStartTick = LK.ticks % (dayLength + nightLength); if (!isNight && cycleStartTick >= dayLength) { startNight(); } else if (isNight && cycleStartTick < dayLength) { startDay(); } } } } // Check collisions with wood items for (var i = woodItems.length - 1; i >= 0; i--) { var wood = woodItems[i]; if (fox.intersects(wood)) { // Only apply multiplier system during night if (isNight || isBloodMoon || isTwistedBloodMoon || isPeacefulNight) { // Check which NPCs are present and not in cabin var hasCat = false; var hasBunny = false; var hasBat = false; for (var n = 0; n < npcs.length; n++) { if (!npcs[n].inCabin && !npcs[n].killed) { if (npcs[n].type === 'cat') hasCat = true; if (npcs[n].type === 'bunny') hasBunny = true; if (npcs[n].type === 'bat') hasBat = true; } } // Calculate wood to spawn based on NPCs present var woodToSpawn = 1; // Default 1 wood if (hasBat && (hasCat || hasBunny)) { // Bat + cat/bunny = 5 wood woodToSpawn = 5; } else if (hasCat && hasBunny && hasBat) { // All three = 10 wood woodToSpawn = 10; } else if (hasBat) { // Bat only = 4 wood woodToSpawn = 4; } else if (hasCat && hasBunny) { // Cat + bunny = 3 wood woodToSpawn = 3; } else if (hasCat || hasBunny) { // Cat or bunny only = 2 wood woodToSpawn = 2; } // Add calculated wood to campfire campfire.addWood(woodToSpawn); } else { // During day, collect normal 1 wood campfire.addWood(1); } // Play different sound based on game state if (isTwistedBloodMoon) { LK.getSound('foxTwistedWoodCollect').play(); } else { LK.getSound('woodCollect').play(); } // Track wood collected during full moon if (isTwistedBloodMoon) { twistedBloodMoonWoodCollected++; // End full moon when 5 wood collected if (twistedBloodMoonWoodCollected >= 5) { isTwistedBloodMoon = false; twistedBloodMoonWoodCollected = 0; // Reset counter startDay(); // End full moon and start day } } // Remove wood from array first, then destroy woodItems.splice(i, 1); wood.destroy(); } } // Check collisions with hearts for extra lives for (var i = hearts.length - 1; i >= 0; i--) { var heart = hearts[i]; if (fox.intersects(heart)) { // Give extra life to player playerLives++; updateLivesDisplay(); // Visual effect for heart collection LK.effects.flashScreen(0xFF69B4, 500); // Remove heart hearts.splice(i, 1); heart.destroy(); } } // Check makeshift cabin interactions for (var r = 0; r < npcs.length; r++) { var robot = npcs[r]; if (robot.type === 'robot' && robot.makeshiftCabin) { var makeshiftCabin = robot.makeshiftCabin; // Check for NPCs wanting to enter makeshift cabin for (var n = 0; n < npcs.length; n++) { var npc = npcs[n]; if (npc !== robot && !npc.inCabin && !npc.killed) { var cabinDist = Math.sqrt(Math.pow(makeshiftCabin.x - npc.x, 2) + Math.pow(makeshiftCabin.y - npc.y, 2)); // Only one NPC can enter makeshift cabin if (cabinDist <= 100 && !makeshiftCabin.occupant) { makeshiftCabin.occupant = npc; npc.inMakeshiftCabin = true; tween(npc, { x: makeshiftCabin.x, y: makeshiftCabin.y, alpha: 0.3 }, { duration: 1000 }); } } } // Check for deer/bunny throwing berries into makeshift cabin for (var n = 0; n < npcs.length; n++) { var npc = npcs[n]; if ((npc.type === 'deer' || npc.type === 'bunny') && npc.heldBerry && npc.berryVisual) { var cabinDist = Math.sqrt(Math.pow(makeshiftCabin.x - npc.x, 2) + Math.pow(makeshiftCabin.y - npc.y, 2)); if (cabinDist <= 120) { // Throw berry into makeshift cabin for upgrades if (npc.type === 'deer') { makeshiftCabin.deerBerryUpgrade++; // Each deer berry reduces robot's cooldowns by 40% if (robot.shieldCooldown > 0) { robot.shieldCooldown = Math.floor(robot.shieldCooldown * 0.6); } } else if (npc.type === 'bunny') { makeshiftCabin.bunnyBerryUpgrade++; // Each bunny berry reduces robot's cooldowns by 20% if (robot.shieldCooldown > 0) { robot.shieldCooldown = Math.floor(robot.shieldCooldown * 0.8); } } // Remove berry visual npc.berryVisual.destroy(); npc.berryVisual = null; npc.heldBerry = null; // Visual feedback tween(makeshiftCabin, { tint: 0x00FF00 }, { duration: 300, onFinish: function onFinish() { tween(makeshiftCabin, { tint: 0xFFFFFF }, { duration: 300 }); } }); break; } } } } } // Check collisions with NPCs for sound and visual feedback only for (var i = 0; i < npcs.length; i++) { var npc = npcs[i]; if (!npc.inCabin && !npc.frozen && fox.intersects(npc)) { // Play touch sound for the specific animal type var soundName = npc.type + 'Touch'; // Handle special cases for hedgehog and robot sounds if (npc.type === 'hedgehog') { soundName = 'squirrelTouch'; // Use squirrel sound for hedgehog } else if (npc.type === 'robot') { soundName = 'catTouch'; // Use cat sound for robot } LK.getSound(soundName).play(); // Give visual feedback for all animals tween(npc, { scaleX: 1.5, scaleY: 1.5 }, { duration: 200, onFinish: function onFinish() { tween(npc, { scaleX: 1, scaleY: 1 }, { duration: 200 }); } }); } } // Check if fox is touching cabin to show/hide NPC class display var foxTouchingCabin = fox.intersects(cabin); if (foxTouchingCabin && !npcClassTxt.visible) { npcClassTxt.visible = true; } else if (!foxTouchingCabin && npcClassTxt.visible) { npcClassTxt.visible = false; } // Wolf collision is now handled in Wolf class update method }; // NPC and Enemy Classification System var NPCClassification = { // NPC Behavioral Classes SURVIVORS: ['mouse', 'bunny'], // NPCs focused on survival and safety STUNNERS: ['dog', 'fennec', 'hedgehog'], // NPCs that can stun or disable enemies COLLECTORS: ['bunny', 'deer'], // NPCs that collect berries as primary function SUPPORTS: ['bat', 'squirrel', 'robot'], // NPCs that provide support abilities to others GATHERERS: ['bunny', 'deer'], // NPCs that collect berries WOOD_COLLECTORS: ['cat', 'bunny', 'bat'], // NPCs that collect wood BERRY_COLLECTORS: ['bunny', 'deer', 'fennec'], // NPCs that collect berries CABIN_SEEKERS: ['cat', 'bunny', 'squirrel', 'deer', 'dog', 'mouse', 'bat', 'hedgehog', 'robot'], // NPCs that seek cabin safety CAMPFIRE_DWELLERS: ['cat', 'bunny', 'squirrel', 'deer', 'dog', 'mouse', 'bat', 'hedgehog', 'robot'], // NPCs that stay at campfire during day DEFENDERS: ['dog', 'fennec', 'hedgehog'], // NPCs that can fight enemies MULTIPLIER_PROVIDERS: ['mouse', 'cat', 'bunny', 'squirrel', 'bat'], // NPCs that provide score multipliers AURA_BEARERS: ['squirrel', 'dog', 'fennec', 'hedgehog', 'robot'], // NPCs with special aura abilities TRANSFORMERS: ['bat'], // NPCs that can transform into other entities ROAMERS: ['fennec'], // NPCs that cannot enter cabin // Enemy Behavioral Classes CHASERS: ['wolf', 'vampire', 'vampire2', 'zombie', 'wendigo', 'cultistVampire'], // Enemies that chase targets HUNTERS: ['wolf', 'wendigo'], // Enemies that actively hunt NPCs STUNNABLE: ['wolf', 'vampire', 'vampire2', 'zombie', 'wendigo', 'cultistVampire'], // Enemies that can be stunned NIGHT_SPAWNERS: ['wolf', 'zombie'], // Enemies that spawn during night BLOODMOON_SPAWNERS: ['vampire', 'vampire2', 'wendigo', 'zombie', 'cultistVampire'], // Enemies that spawn during blood moon CAMPFIRE_ATTACKERS: ['wolf'], // Enemies that attack NPCs near campfire CABIN_ATTACKERS: ['vampire', 'vampire2', 'zombie', 'cultistVampire'], // Enemies that attack NPCs not in cabin TRANSFORMATIONS: ['cultistVampire'], // Enemies created by transformation PRIORITY_TARGETERS: ['wendigo'], // Enemies with special targeting priorities MUSIC_TRIGGERS: ['wolf', 'zombie', 'wendigo', 'cultistVampire'], // Enemies that trigger chase music // Utility functions for classification isCollector: function isCollector(npcType) { return this.COLLECTORS.indexOf(npcType) !== -1; }, isDefender: function isDefender(npcType) { return this.DEFENDERS.indexOf(npcType) !== -1; }, isChaser: function isChaser(enemyType) { return this.CHASERS.indexOf(enemyType) !== -1; }, isHunter: function isHunter(enemyType) { return this.HUNTERS.indexOf(enemyType) !== -1; }, getMultiplierValue: function getMultiplierValue(npcType) { if (npcType === 'mouse') return 4; if (['cat', 'bunny', 'squirrel', 'bat'].indexOf(npcType) !== -1) return 2; return 0; }, getWoodMultiplier: function getWoodMultiplier(npcType) { if (npcType === 'bat') return 4; if (['cat', 'bunny'].indexOf(npcType) !== -1) return 2; return 1; }, canEnterCabin: function canEnterCabin(npcType) { return npcType !== 'fennec'; }, getHitPoints: function getHitPoints(npcType) { if (npcType === 'deer') return 2; if (npcType === 'dog') return 3; return 1; }, getSpawnProbability: function getSpawnProbability(npcType) { if (['cat', 'bunny', 'squirrel'].indexOf(npcType) !== -1) return 0.5; // Common: 50% if (['deer', 'fennec'].indexOf(npcType) !== -1) return 0.35; // Uncommon: 35% if (['dog', 'mouse', 'bat'].indexOf(npcType) !== -1) return 0.15; // Rare: 15% return 0; }, getEnemySpeed: function getEnemySpeed(enemyType) { if (enemyType === 'zombie') return 1; if (enemyType === 'wolf') return 2; if (enemyType === 'wendigo') return 3; if (['vampire', 'vampire2'].indexOf(enemyType) !== -1) return 4; if (enemyType === 'cultistVampire') return 7; return 1; }, getDetectionRange: function getDetectionRange(enemyType) { if (enemyType === 'wolf') return 800; if (['vampire', 'vampire2', 'zombie'].indexOf(enemyType) !== -1) return 600; if (enemyType === 'cultistVampire') return 1200; if (enemyType === 'wendigo') return 400; return 400; }, // Get all NPCs of a specific class getNPCsByClass: function getNPCsByClass(className) { return this[className] || []; }, // Get all enemies of a specific class getEnemiesByClass: function getEnemiesByClass(className) { return this[className] || []; }, // Check if NPC belongs to specific behavioral class npcHasClass: function npcHasClass(npcType, className) { var classArray = this[className]; return classArray && classArray.indexOf(npcType) !== -1; }, // Check if enemy belongs to specific behavioral class enemyHasClass: function enemyHasClass(enemyType, className) { var classArray = this[className]; return classArray && classArray.indexOf(enemyType) !== -1; } };
===================================================================
--- original.js
+++ change.js
@@ -1619,12 +1619,14 @@
}
return; // Skip other behavior while stunned
}
// Check for nearby berries to collect (150 pixel range)
+ var foundNearbyBerry = false;
for (var b = normalBerries.length - 1; b >= 0; b--) {
var berry = normalBerries[b];
var berryDist = Math.sqrt(Math.pow(berry.x - self.x, 2) + Math.pow(berry.y - self.y, 2));
if (berryDist <= 150) {
+ foundNearbyBerry = true;
// Move towards berry
var dx = berry.x - self.x;
var dy = berry.y - self.y;
var distance = Math.sqrt(dx * dx + dy * dy);
@@ -1637,15 +1639,16 @@
if (berryDist < 50) {
normalBerries.splice(b, 1);
berry.destroy();
berriesCollectedInCycle += 2; // Fennec collects 2 berries instead of 1
+ LK.getSound('berryCollect').play();
break;
}
- return;
+ break; // Only target one berry at a time
}
}
// Normal movement when not collecting berries or killing enemies
- if (LK.ticks % 180 === 0) {
+ if (!foundNearbyBerry && LK.ticks % 180 === 0) {
// Every 3 seconds, move to a new position
var newX = Math.random() * (1800 - 200) + 200;
var newY = Math.random() * (2400 - 200) + 200;
var moveSpeed = self.isTargeted ? self.targetedSpeed || fennecSpeed : fennecSpeed;
@@ -2478,8 +2481,13 @@
var berryGraphics = self.attachAsset('normalBerry', {
anchorX: 0.5,
anchorY: 0.5
});
+ // Initialize berry lifespan if not set
+ if (!self.spawnTime) {
+ self.spawnTime = LK.ticks;
+ self.lifespan = 1800; // 30 seconds at 60fps
+ }
self.update = function () {
// Gentle floating animation
self.y += Math.sin(LK.ticks * 0.1 + self.x * 0.01) * 0.5;
};
@@ -4888,11 +4896,18 @@
spawnWood();
}
}
}
- // Check collisions with normal berries
+ // Check berry despawn and collisions
for (var i = normalBerries.length - 1; i >= 0; i--) {
var berry = normalBerries[i];
+ // Check if berry should despawn after 30 seconds
+ if (berry.spawnTime && LK.ticks - berry.spawnTime >= berry.lifespan) {
+ // Berry despawns after 30 seconds
+ normalBerries.splice(i, 1);
+ berry.destroy();
+ continue;
+ }
if (fox.intersects(berry)) {
// Calculate score multiplier considering mouse cabin behavior
var currentMultiplier = scoreMultiplier;
for (var m = 0; m < npcs.length; m++) {
a cute fox with a basket. In-Game asset. 2d. High contrast. No shadows
a berry bush with a phew yummy berries on it. In-Game asset. 2d. High contrast. No shadows
a top view of a grass field with a cabin and some trees. In-Game asset. 2d. High contrast. No shadows
a cute little bunny. In-Game asset. 2d. High contrast. No shadows
cabin. In-Game asset. 2d. High contrast. No shadows
a angry wolve thats in 2d. In-Game asset. 2d. High contrast. No shadows
a cute cat with a bow. In-Game asset. 2d. High contrast. No shadows
a cute dear with an axe. In-Game asset. 2d. High contrast. No shadows
a dog cute dog with a hat and a shotgun. In-Game asset. 2d. High contrast. No shadows
a cute mouse with a hoodie on. In-Game asset. 2d. High contrast. No shadows
a cute fennec fox with a backbag. In-Game asset. 2d. High contrast. No shadows
a cute squirrel with a gutair. In-Game asset. 2d. High contrast. No shadows
a campfire. In-Game asset. 2d. High contrast. No shadows
sticks. In-Game asset. 2d. High contrast. No shadows
zombie duck. In-Game asset. 2d. High contrast. No shadows
cultists animal. In-Game asset. 2d. High contrast. No shadows
cultist girrafe. In-Game asset. 2d. High contrast. No shadows
cute nice bat cultist. In-Game asset. 2d. High contrast. No shadows
glitchSound
Sound effect
berryCollect
Sound effect
wendigoGrowl
Sound effect
wolfRoar
Sound effect
howl
Sound effect
dayMusic
Music
nightMusic
Music
bloodMoonMusic
Music
chaseTheme
Music
bunnyTouch
Sound effect
bunnyKill
Sound effect
catTouch
Sound effect
catKill
Sound effect
deerTouch
Sound effect
deerKill
Sound effect
dogTouch
Sound effect
dogKill
Sound effect
fennecTouch
Sound effect
fennecKill
Sound effect
mouseTouch
Sound effect
mouseKill
Sound effect
squirrelTouch
Sound effect
squirrelKill
Sound effect
peacefulNightAmbience
Music
twistedBloodMoonTheme
Music
wendigoChaseTheme
Music
zombieChaseTheme
Music
woodCollect
Sound effect
vampireJumpscare
Sound effect
dogStun
Sound effect
catWoodCollect
Sound effect
foxTwistedWoodCollect
Sound effect
batTouch
Sound effect
batKill
Sound effect