User prompt
make it so that plants have a 100% chance of being healthy when placed in summer and after 10 seconds they lose the invulrabilty
User prompt
make it so fungi in the summer will not infect herbivores until the following winter or spring
User prompt
make it so that if pollinators try to pollinate a brown plant they will just move on to a healthy plant
User prompt
make it so that some healthy plants in summer can randomly turn brown
User prompt
make it so brown plants have a shorter lifespan and pollinators will ignore them
User prompt
make it so that in summer there is a small chance that plants will turn brown and in this state they are unable to be pollinated
User prompt
make it so when its a summer state there is a chance that seeds cannot germinate and disappear instead
User prompt
put the season text a bit more to the left
User prompt
put the season text more on the left
User prompt
make it so that the season is displayed as text on the bottom of the screen
User prompt
make it so that when the background is yellow the world is in a summer state
User prompt
make all text black
User prompt
make ALL text black
User prompt
make it so that any plants that are placed when the background is white turn blue and cannot die
User prompt
make it so plants turn blue when the background is white and they cant die until the background is green
User prompt
make it so pollinators stop all movement and actions including death when the background is white in a hibernation state
User prompt
Please fix the bug: 'Uncaught TypeError: Cannot set properties of undefined (setting 'fill')' in or related to this line: 'cycleTxt.style.fill = textColor;' Line Number: 1254
User prompt
make it so that when the background is white and yellow all text on screen is black
User prompt
make it so every 3 cycles the background it goes to green and after 3 cycles it goes to yellow and after 6 cycles it goes to white
User prompt
make a button under the delete button that skips a cycle randomly placing all organisims in a random place excluding fungi plants and lichen
User prompt
move the seasons text under the delete button
User prompt
put the seasons under the delete button green season is the spring yellow is summer and white is winter
User prompt
make sure that when the background is green it says under the delete button its summer
User prompt
make it so on the 9th cycle the background turns green again and every 3 cycles after that it changes into a yellow backgound and then a white one
User prompt
make it so on the 6th cycle the background turns white
/**** * Plugins ****/ var tween = LK.import("@upit/tween.v1"); /**** * Classes ****/ // Carnivore class var Carnivore = Container.expand(function () { var self = Container.call(this); var carnAsset = self.attachAsset('carnivore', { anchorX: 0.5, anchorY: 0.5 }); self.target = null; self.speed = 1.5 + Math.random() * 1.2; self.eaten = false; self._chaseTime = 0; // How long we've been chasing a herbivore self._tired = false; // Are we tired? self._tiredTimer = 0; // How long left to rest // --- State management for wandering/hungry --- self.state = "hungry"; // "wandering" or "hungry" self._eatCooldown = 0; // frames left in wandering after eating self.update = function () { if (self.eaten) return; // Handle tired state if (self._tired) { self._tiredTimer--; if (self._tiredTimer <= 0) { self._tired = false; self._chaseTime = 0; } // While tired, don't chase or wander, just stand still return; } // Handle eat cooldown (wandering after eating) if (self._eatCooldown > 0) { self._eatCooldown--; if (self._eatCooldown === 0) { self.state = "hungry"; } } // State: wandering (ignore prey) if (self.state === "wandering") { self.target = null; // Don't chase // --- Random wandering when not chasing herbivores --- if (!self._wanderTimer || self._wanderTimer <= 0) { var angle = Math.random() * Math.PI * 2; self._wanderAngle = angle; self._wanderTimer = 60 + Math.floor(Math.random() * 60); } if (typeof self._wanderAngle === "number") { self.x += Math.cos(self._wanderAngle) * self.speed * 0.5; self.y += Math.sin(self._wanderAngle) * self.speed * 0.5; self._wanderTimer--; // Keep inside map bounds (strictly) var minX = 124 + 60; var maxX = 124 + 1800 - 60; var minY = paletteY + 320 + 60; var maxY = paletteY + 320 + 2000 - 60; if (self.x < minX) self.x = minX; if (self.x > maxX) self.x = maxX; if (self.y < minY) self.y = minY; if (self.y > maxY) self.y = maxY; } self._chaseTime = 0; // Not chasing, reset chase timer return; } // State: hungry (look for prey) if (self.state === "hungry") { // Find nearest herbivore or pollinator if not already targeting if (!self.target || self.target.eaten) { var minDist = 999999, closest = null; // Check herbivores for (var i = 0; i < herbivores.length; i++) { var h = herbivores[i]; if (h.eaten) continue; var dx = h.x - self.x, dy = h.y - self.y; var dist = dx * dx + dy * dy; if (dist < minDist) { minDist = dist; closest = h; } } // (Carnivores ignore pollinators) self.target = closest; } // --- Random wandering when not chasing herbivores --- if ((!self.target || self.target.eaten) && (!self._wanderTimer || self._wanderTimer <= 0)) { var angle = Math.random() * Math.PI * 2; self._wanderAngle = angle; self._wanderTimer = 60 + Math.floor(Math.random() * 60); } if (!self.target || self.target.eaten) { if (typeof self._wanderAngle === "number") { self.x += Math.cos(self._wanderAngle) * self.speed * 0.5; self.y += Math.sin(self._wanderAngle) * self.speed * 0.5; self._wanderTimer--; var minX = 124 + 60; var maxX = 124 + 1800 - 60; var minY = paletteY + 320 + 60; var maxY = paletteY + 320 + 2000 - 60; if (self.x < minX) self.x = minX; if (self.x > maxX) self.x = maxX; if (self.y < minY) self.y = minY; if (self.y > maxY) self.y = maxY; } self._chaseTime = 0; // Not chasing, reset chase timer } // Move toward target herbivore if (self.target && !self.target.eaten) { var dx = self.target.x - self.x; var dy = self.target.y - self.y; var dist = Math.sqrt(dx * dx + dy * dy); if (dist > 1) { self.x += dx / dist * self.speed; self.y += dy / dist * self.speed; } // Track how long we've been chasing self._chaseTime++; // If we've been chasing for more than 6 seconds (360 frames), get tired if (self._chaseTime > 360) { self._tired = true; self._tiredTimer = 600; // 10 seconds at 60fps self._chaseTime = 0; return; } // Eat herbivore or pollinator if close enough if (dist < 60 && !self.target.eaten) { // Remove from correct array if pollinator if (pollinators.indexOf(self.target) !== -1) { self.target.die(); // Remove from pollinators array in main update loop, not here } else { self.target.die(); } // Move away from the eaten herbivore if (self.target) { var awayDX = self.x - self.target.x; var awayDY = self.y - self.target.y; var awayDist = Math.sqrt(awayDX * awayDX + awayDY * awayDY); if (awayDist > 0) { // Move 100px away in the opposite direction self.x += awayDX / awayDist * 100; self.y += awayDY / awayDist * 100; // Clamp to map area var minX = 124 + 60; var maxX = 124 + 1800 - 60; var minY = paletteY + 320 + 60; var maxY = paletteY + 320 + 2000 - 60; if (self.x < minX) self.x = minX; if (self.x > maxX) self.x = maxX; if (self.y < minY) self.y = minY; if (self.y > maxY) self.y = maxY; } } // Track herbivores eaten for egg laying self._herbivoresEaten = (self._herbivoresEaten || 0) + 1; // Lay an egg if 3 herbivores have been eaten, then reset counter if (self._herbivoresEaten >= 3) { var egg = new Egg(); egg.x = self.x; egg.y = self.y; egg.scaleX = 0.5; egg.scaleY = 0.5; egg.alpha = 1; egg._isCarnivoreEgg = true; egg._carnivoreHatch = true; if (self.parent) self.parent.addChild(egg); if (typeof eggs !== "undefined") eggs.push(egg); self._herbivoresEaten = 0; } self.target = null; self._chaseTime = 0; // Reset chase timer after eating // Animate carnivore "eating" tween(self, { scaleX: 1.2, scaleY: 1.2 }, { duration: 120, easing: tween.easeOut, onFinish: function onFinish() { tween(self, { scaleX: 1, scaleY: 1 }, { duration: 120, easing: tween.easeIn }); } }); // After eating, enter wandering state for 1 minute (3600 frames) self.state = "wandering"; self._eatCooldown = 3600; } } } // end hungry state }; // Carnivores are not eaten in this MVP return self; }); // Egg class var Egg = Container.expand(function () { var self = Container.call(this); // Always use carnivore_egg asset if this is a carnivore egg, pollinator_egg if pollinator, else normal egg var eggAsset; if (self._isCarnivoreEgg === true || self._carnivoreHatch === true) { eggAsset = self.attachAsset('carnivore_egg', { anchorX: 0.5, anchorY: 0.5, scaleX: 1, scaleY: 1 }); } else if (self._isPollinatorEgg === true || self._pollinatorHatch === true) { eggAsset = self.attachAsset('pollinator_egg', { anchorX: 0.5, anchorY: 0.5, scaleX: 1, scaleY: 1 }); } else { eggAsset = self.attachAsset('egg', { anchorX: 0.5, anchorY: 0.5, scaleX: 1, scaleY: 1 }); } self.hatched = false; self._hatchTimer = 420 + Math.floor(Math.random() * 180); // 7-10 seconds self.update = function () { if (self.hatched) return; self._hatchTimer--; if (self._hatchTimer <= 0) { self.hatched = true; // Animate egg hatching tween(self, { scaleX: 1.2, scaleY: 1.2, alpha: 0.5 }, { duration: 200, easing: tween.easeOut, onFinish: function onFinish() { // Spawn a new carnivore if this is a carnivore egg, pollinator if pollinator egg, otherwise herbivore if (self._isCarnivoreEgg && self._carnivoreHatch) { var carn = new Carnivore(); carn.x = self.x; carn.y = self.y; carn.scaleX = 1; carn.scaleY = 1; carn.alpha = 1; if (self.parent) self.parent.addChild(carn); if (typeof carnivores !== "undefined") carnivores.push(carn); } else if (self._isPollinatorEgg && self._pollinatorHatch) { var poll = new Pollinator(); poll.x = self.x; poll.y = self.y; poll.scaleX = 1; poll.scaleY = 1; poll.alpha = 1; if (self.parent) self.parent.addChild(poll); if (typeof pollinators !== "undefined") pollinators.push(poll); } else { // Spawn a new Nummer at this position var herb = new Nummer(); herb.x = self.x; herb.y = self.y; herb.scaleX = 1; herb.scaleY = 1; herb.alpha = 1; if (self.parent) self.parent.addChild(herb); herbivores.push(herb); } self.destroy(); } }); } }; return self; }); // Fungi class var Fungi = Container.expand(function () { var self = Container.call(this); // Use fungi asset var fungiAsset = self.attachAsset('fungi', { anchorX: 0.5, anchorY: 0.5 }); // Fungi AI: shoot spores at nearby herbivores self._sporeCooldown = 0; self.update = function () { // Only shoot if cooldown is 0 if (self._sporeCooldown > 0) { self._sporeCooldown--; return; } // Find nearest herbivore within 400px var minDist = 999999, closest = null; for (var i = 0; i < herbivores.length; i++) { var h = herbivores[i]; if (h.eaten || h.spored) continue; var dx = h.x - self.x, dy = h.y - self.y; var dist = dx * dx + dy * dy; if (dist < minDist && Math.sqrt(dist) < 400) { minDist = dist; closest = h; } } if (closest) { // Shoot a spore at the herbivore var spore = new FungiSpore(); spore.x = self.x; spore.y = self.y; spore.target = closest; game.addChild(spore); if (!fungiSpores) fungiSpores = []; fungiSpores.push(spore); self._sporeCooldown = 120 + Math.floor(Math.random() * 60); // 2-3 seconds cooldown } }; return self; }); // Lichen class (does nothing, unique class) var Lichen = Container.expand(function () { var self = Container.call(this); // Use a unique lichen asset (flower asset as a placeholder for lichen) var lichenAsset = self.attachAsset('flower', { anchorX: 0.5, anchorY: 0.5 }); // Lichen does nothing, no update or interaction return self; }); // Nummer class (formerly Herbivore) var Nummer = Container.expand(function () { var self = Container.call(this); self.spored = false; // Track if this Nummer was hit by a spore var herbAsset = self.attachAsset('herbivore', { anchorX: 0.5, anchorY: 0.5 }); self.target = null; self.speed = 1.2 + Math.random() * 1.0; self.eaten = false; // Track number of plants eaten for egg laying self._plantsEaten = 0; // --- State management for hungry/sleepy --- self.state = "hungry"; // "hungry" or "sleepy" self._sleepTimer = 0; // frames left in sleepy state // --- Starvation timer: die if not eating for 2 cycles (80 seconds = 4800 frames) --- self._starveTimer = 4800; // 80 seconds at 60fps self.update = function () { if (self.eaten) return; // Starvation logic: decrement timer if alive and hungry/wandering if (self.state === "hungry" || self.state === "wandering") { self._starveTimer--; if (self._starveTimer <= 0 && !self.eaten) { // Starve and die self.die(); return; } } // Handle infected state if (self.infected) { self.infectedTimer = (self.infectedTimer || 0) + 1; // Future: add infected behavior here (e.g. slow, animation, etc) } // Handle sleepy state if (self.state === "sleepy") { // Check for nearby carnivore and possibly wake up var nearestCarn = null; var minCarnDist = 999999; for (var ci = 0; ci < carnivores.length; ci++) { var carn = carnivores[ci]; if (carn.eaten) continue; var cdx = carn.x - self.x; var cdy = carn.y - self.y; var cdist = cdx * cdx + cdy * cdy; if (cdist < minCarnDist) { minCarnDist = cdist; nearestCarn = carn; } } // If carnivore is within 300px, 50% chance to wake up and run away if (nearestCarn && Math.sqrt(minCarnDist) < 300) { // Only try to wake up once per frame if still sleepy if (!self._triedWakeThisFrame) { self._triedWakeThisFrame = true; if (Math.random() < 0.5) { // Wake up and run away from carnivore self.state = "hungry"; // Move away from carnivore immediately var dx = self.x - nearestCarn.x; var dy = self.y - nearestCarn.y; var dist = Math.sqrt(dx * dx + dy * dy); if (dist > 1) { // Move a burst away (3x speed for one frame) self.x += dx / dist * (self.speed * 3); self.y += dy / dist * (self.speed * 3); } // Clamp to map area var minX = 124 + 60; var maxX = 124 + 1800 - 60; var minY = paletteY + 320 + 60; var maxY = paletteY + 320 + 2000 - 60; if (self.x < minX) self.x = minX; if (self.x > maxX) self.x = maxX; if (self.y < minY) self.y = minY; if (self.y > maxY) self.y = maxY; // Don't continue sleeping return; } } } else { self._triedWakeThisFrame = false; } self._sleepTimer--; if (self._sleepTimer <= 0) { self.state = "wandering"; self._wanderAfterSleepTimer = 600; // 10 seconds at 60fps } // While sleepy, don't move or seek food return; } // Wandering state after sleep: ignore plants, just wander for 10s, then become hungry if (self.state === "wandering") { if (typeof self._wanderAfterSleepTimer === "undefined") self._wanderAfterSleepTimer = 600; self._wanderAfterSleepTimer--; // --- Random wandering --- if (!self._wanderTimer || self._wanderTimer <= 0) { var angle = Math.random() * Math.PI * 2; self._wanderAngle = angle; self._wanderTimer = 60 + Math.floor(Math.random() * 60); } if (typeof self._wanderAngle === "number") { self.x += Math.cos(self._wanderAngle) * self.speed * 0.5; self.y += Math.sin(self._wanderAngle) * self.speed * 0.5; self._wanderTimer--; // Keep inside map bounds (strictly) var minX = 124 + 60; var maxX = 124 + 1800 - 60; var minY = paletteY + 320 + 60; var maxY = paletteY + 320 + 2000 - 60; if (self.x < minX) self.x = minX; if (self.x > maxX) self.x = maxX; if (self.y < minY) self.y = minY; if (self.y > maxY) self.y = maxY; } if (self._wanderAfterSleepTimer <= 0) { self.state = "hungry"; } return; } // Only seek food if hungry if (self.state === "hungry") { // Find nearest plant if not already targeting if (!self.target || self.target.eaten) { var minDist = 999999, closest = null; for (var i = 0; i < plants.length; i++) { var p = plants[i]; if (p.eaten) continue; var dx = p.x - self.x, dy = p.y - self.y; var dist = dx * dx + dy * dy; if (dist < minDist) { minDist = dist; closest = p; } } self.target = closest; } // Nummer can walk over fungi as if it is not there: do not treat fungi as obstacles, so do not check for collision or avoid them at all in movement logic. // Check for nearest carnivore var nearestCarn = null; var minCarnDist = 999999; var tiredCarnivore = null; var tiredCarnDist = 999999; for (var ci = 0; ci < carnivores.length; ci++) { var carn = carnivores[ci]; if (carn.eaten) continue; var cdx = carn.x - self.x; var cdy = carn.y - self.y; var cdist = cdx * cdx + cdy * cdy; if (cdist < minCarnDist) { minCarnDist = cdist; nearestCarn = carn; } // Track tired carnivore chasing this herbivore if (carn._tired && carn.target === self && cdist < tiredCarnDist) { tiredCarnivore = carn; tiredCarnDist = cdist; } } var carnivoreTooClose = false; var carnDist = 0; var runAwayDX = 0, runAwayDY = 0; if (nearestCarn) { carnDist = Math.sqrt((nearestCarn.x - self.x) * (nearestCarn.x - self.x) + (nearestCarn.y - self.y) * (nearestCarn.y - self.y)); if (carnDist < 300) { // If carnivore is within 300px, run away carnivoreTooClose = true; runAwayDX = self.x - nearestCarn.x; runAwayDY = self.y - nearestCarn.y; } } // --- New: If a tired carnivore was chasing this herbivore, charge away until far enough --- // (Removed barrier logic: herbivores can always run away from tired carnivores) if (carnivoreTooClose && carnDist > 1) { // Run away from carnivore self.x += runAwayDX / carnDist * (self.speed * 1.5); self.y += runAwayDY / carnDist * (self.speed * 1.5); } else { // --- Random wandering when not chasing plant --- if ((!self.target || self.target.eaten) && (!self._wanderTimer || self._wanderTimer <= 0)) { // Pick a new random direction every 60-120 frames var angle = Math.random() * Math.PI * 2; self._wanderAngle = angle; self._wanderTimer = 60 + Math.floor(Math.random() * 60); } if (!self.target || self.target.eaten) { // Wander in the chosen direction if (typeof self._wanderAngle === "number") { self.x += Math.cos(self._wanderAngle) * self.speed * 0.5; self.y += Math.sin(self._wanderAngle) * self.speed * 0.5; self._wanderTimer--; // Keep inside map bounds (strictly) var minX = 124 + 60; var maxX = 124 + 1800 - 60; var minY = paletteY + 320 + 60; var maxY = paletteY + 320 + 2000 - 60; if (self.x < minX) self.x = minX; if (self.x > maxX) self.x = maxX; if (self.y < minY) self.y = minY; if (self.y > maxY) self.y = maxY; } } // Move toward target plant if (self.target && !self.target.eaten) { var dx = self.target.x - self.x; var dy = self.target.y - self.y; var dist = Math.sqrt(dx * dx + dy * dy); if (dist > 1) { self.x += dx / dist * self.speed; self.y += dy / dist * self.speed; } // Eat plant if close enough if (dist < 60 && !self.target.eaten) { var eatenPlant = self.target; self.target.die(); self.target = null; // Animate Nummer "eating" tween(self, { scaleX: 1.2, scaleY: 1.2 }, { duration: 120, easing: tween.easeOut, onFinish: function onFinish() { tween(self, { scaleX: 1, scaleY: 1 }, { duration: 120, easing: tween.easeIn }); } }); // After eating, enter sleepy state for 10 seconds (600 frames) self.state = "sleepy"; self._sleepTimer = 600; // Reset starvation timer after eating self._starveTimer = 4800; // 80 seconds at 60fps // Increment plants eaten counter self._plantsEaten = (self._plantsEaten || 0) + 1; // Lay an egg if 4 plants have been eaten, then reset counter if (self._plantsEaten >= 4) { var egg = new Egg(); egg.x = self.x; egg.y = self.y; egg.scaleX = 0.5; egg.scaleY = 0.5; egg.alpha = 1; if (self.parent) self.parent.addChild(egg); if (typeof eggs !== "undefined") eggs.push(egg); self._plantsEaten = 0; } } } } } }; // Called when eaten by carnivore self.die = function (_onFinish) { if (self.eaten) return; self.eaten = true; // If infected, spawn a fungi at this position if (self.infected) { var newFungi = new Fungi(); newFungi.x = self.x; newFungi.y = self.y; newFungi.scaleX = 1; newFungi.scaleY = 1; newFungi.alpha = 1; if (self.parent) self.parent.addChild(newFungi); if (typeof fungis !== "undefined") fungis.push(newFungi); } tween(self, { scaleX: 0, scaleY: 0, alpha: 0 }, { duration: 400, easing: tween.easeIn, onFinish: function onFinish() { self.destroy(); if (_onFinish) _onFinish(); } }); }; // Called when hit by a spore self.sporeHit = function () { if (self.spored) return; // Only allow once self.spored = true; // Enter infected state self.infected = true; self.infectedTimer = 0; // Tint permanently purple tween(self, { tint: 0xbb88ff }, { duration: 80 }); }; return self; }); // Plant class var Plant = Container.expand(function () { var self = Container.call(this); var plantAsset = self.attachAsset('plant', { anchorX: 0.5, anchorY: 0.5 }); // Plants are static, but we can animate them when eaten self.eaten = false; // Track the cycle the plant was created in self._bornCycle = typeof cycleCount !== "undefined" ? cycleCount : 0; self.die = function (_onFinish2) { if (self.eaten) return; self.eaten = true; tween(self, { scaleX: 0, scaleY: 0, alpha: 0 }, { duration: 400, easing: tween.easeIn, onFinish: function onFinish() { self.destroy(); if (_onFinish2) _onFinish2(); } }); }; // Plants die after 1 cycle self.update = function () { if (self.eaten) return; if (typeof cycleCount !== "undefined" && typeof self._bornCycle !== "undefined") { // Only die if at least one full cycle has passed since birth if (cycleCount > self._bornCycle + 1) { self.die(); } } }; return self; }); // Pollinator class var Pollinator = Container.expand(function () { var self = Container.call(this); var pollAsset = self.attachAsset('pollinator', { anchorX: 0.5, anchorY: 0.5 }); self.state = "seek"; // "seek", "scatter", "planting" self.target = null; self.speed = 2 + Math.random(); self._scatterTimer = 0; self._scatterAngle = 0; self._plantSeedTimer = 0; self._hasSeed = true; self.eaten = false; self.lastWasTouchingPlant = false; // --- Pollination counter for egg laying --- self._pollinations = 0; self._layingEgg = false; self._eggObj = null; // Add a lifetime timer (1 minute = 3600 frames) self._lifetime = 3600; self.update = function () { if (self.eaten) return; // Pollinator dies after 1 minute self._lifetime--; if (self._lifetime <= 0) { // Animate and destroy pollinator tween(self, { scaleX: 0, scaleY: 0, alpha: 0 }, { duration: 400, easing: tween.easeIn, onFinish: function onFinish() { self.destroy(); } }); // Prevent further updates self.update = function () {}; return; } // If currently laying an egg, wait for egg to hatch before continuing if (self._layingEgg && self._eggObj) { // Wait for egg to hatch, then continue pollinating if (self._eggObj.hatched) { // Spawn a new pollinator at egg position var newPoll = new Pollinator(); newPoll.x = self._eggObj.x; newPoll.y = self._eggObj.y; newPoll.scaleX = 1; newPoll.scaleY = 1; newPoll.alpha = 1; if (self.parent) self.parent.addChild(newPoll); if (typeof pollinators !== "undefined") pollinators.push(newPoll); // Remove egg from global eggs array var idx = eggs.indexOf(self._eggObj); if (idx !== -1) eggs.splice(idx, 1); self._eggObj.destroy(); self._eggObj = null; self._layingEgg = false; self._pollinations = 0; // Reset counter } else { // Wait for egg to hatch, do nothing else return; } } // SEEK: Find nearest plant and move to it, but run from carnivores if close if (self.state === "seek") { // Check for nearest carnivore var nearestCarn = null; var minCarnDist = 999999; for (var ci = 0; ci < carnivores.length; ci++) { var carn = carnivores[ci]; if (carn.eaten) continue; var cdx = carn.x - self.x; var cdy = carn.y - self.y; var cdist = cdx * cdx + cdy * cdy; if (cdist < minCarnDist) { minCarnDist = cdist; nearestCarn = carn; } } var carnivoreTooClose = false; var carnDist = 0; var runAwayDX = 0, runAwayDY = 0; if (nearestCarn) { carnDist = Math.sqrt((nearestCarn.x - self.x) * (nearestCarn.x - self.x) + (nearestCarn.y - self.y) * (nearestCarn.y - self.y)); if (carnDist < 220) { // Run if carnivore is within 220px carnivoreTooClose = true; runAwayDX = self.x - nearestCarn.x; runAwayDY = self.y - nearestCarn.y; } } if (carnivoreTooClose && carnDist > 1) { // Run away from carnivore (burst speed) self.x += runAwayDX / carnDist * (self.speed * 2.2); self.y += runAwayDY / carnDist * (self.speed * 2.2); } else { // Find nearest plant if (!self.target || self.target.eaten) { var minDist = 999999, closest = null; for (var i = 0; i < plants.length; i++) { var p = plants[i]; if (p.eaten) continue; var dx = p.x - self.x, dy = p.y - self.y; var dist = dx * dx + dy * dy; if (dist < minDist) { minDist = dist; closest = p; } } self.target = closest; } // Move toward target plant if (self.target && !self.target.eaten) { var dx = self.target.x - self.x; var dy = self.target.y - self.y; var dist = Math.sqrt(dx * dx + dy * dy); if (dist > 1) { self.x += dx / dist * self.speed; self.y += dy / dist * self.speed; } // Check for touching plant (within 60px) var isTouching = dist < 60; if (!self.lastWasTouchingPlant && isTouching) { // Just touched plant self._pollinations = (self._pollinations || 0) + 1; // If pollinated 3 times, lay an egg and wait for it to hatch if (self._pollinations >= 3 && !self._layingEgg) { // Lay a pollinator egg at current position var egg = new Egg(); egg.x = self.x; egg.y = self.y; egg.scaleX = 0.5; egg.scaleY = 0.5; egg.alpha = 1; egg._isPollinatorEgg = true; egg._pollinatorHatch = true; if (self.parent) self.parent.addChild(egg); if (typeof eggs !== "undefined") eggs.push(egg); self._eggObj = egg; self._layingEgg = true; // Wait for egg to hatch before continuing return; } self.state = "scatter"; self._scatterTimer = 60 + Math.floor(Math.random() * 60); // 1-2 seconds self._scatterAngle = Math.random() * Math.PI * 2; } self.lastWasTouchingPlant = isTouching; } else { // No plant to go to, wander randomly if (!self._wanderTimer || self._wanderTimer <= 0) { self._wanderAngle = Math.random() * Math.PI * 2; self._wanderTimer = 60 + Math.floor(Math.random() * 60); } if (typeof self._wanderAngle === "number") { self.x += Math.cos(self._wanderAngle) * self.speed * 0.5; self.y += Math.sin(self._wanderAngle) * self.speed * 0.5; self._wanderTimer--; } } } } // SCATTER: Move in a random direction for a short time else if (self.state === "scatter") { self.x += Math.cos(self._scatterAngle) * self.speed * 2; self.y += Math.sin(self._scatterAngle) * self.speed * 2; self._scatterTimer--; if (self._scatterTimer <= 0) { self.state = "planting"; self._plantSeedTimer = 30 + Math.floor(Math.random() * 30); // short pause before planting } } // PLANTING: Pause, then plant a seed else if (self.state === "planting") { self._plantSeedTimer--; if (self._plantSeedTimer <= 0 && self._hasSeed) { // Place a seed at current position var seed = new Seed(); seed.x = self.x; seed.y = self.y; seed.scaleX = 0.4; seed.scaleY = 0.4; seed.alpha = 1; seeds.push(seed); if (self.parent) self.parent.addChild(seed); self._hasSeed = false; // After planting, look for another plant self.state = "seek"; self.target = null; self._hasSeed = true; } } // Keep inside map bounds var minX = 124 + 60; var maxX = 124 + 1800 - 60; var minY = paletteY + 320 + 60; var maxY = paletteY + 320 + 2000 - 60; if (self.x < minX) self.x = minX; if (self.x > maxX) self.x = maxX; if (self.y < minY) self.y = minY; if (self.y > maxY) self.y = maxY; }; self.die = function () { if (self.eaten) return; self.eaten = true; tween(self, { scaleX: 0, scaleY: 0, alpha: 0 }, { duration: 200, easing: tween.easeIn, onFinish: function onFinish() { self.destroy(); } }); }; return self; }); // Seed class var Seed = Container.expand(function () { var self = Container.call(this); // Use dedicated brown seed asset var seedAsset = self.attachAsset('seed', { anchorX: 0.5, anchorY: 0.5, scaleX: 0.4, scaleY: 0.4 }); self.growing = false; self.eaten = false; self._growTimer = 600; // 10 seconds at 60fps self.update = function () { if (self.eaten) return; if (!self.growing) { self._growTimer--; if (self._growTimer <= 0) { self.growing = true; // Animate seed growing into plant tween(self, { scaleX: 1, scaleY: 1, alpha: 0.7 }, { duration: 300, easing: tween.easeOut, onFinish: function onFinish() { // Replace seed with a new plant at same position var newPlant = new Plant(); newPlant.x = self.x; newPlant.y = self.y; newPlant.scaleX = 1; newPlant.scaleY = 1; newPlant.alpha = 1; // Set the plant's _bornCycle to the current cycleCount so its cycle restarts if (typeof cycleCount !== "undefined") { newPlant._bornCycle = cycleCount; } plants.push(newPlant); if (self.parent) self.parent.addChild(newPlant); self.eaten = true; self.destroy(); } }); } } }; // If something eats the seed (future-proof) self.die = function () { if (self.eaten) return; self.eaten = true; tween(self, { scaleX: 0, scaleY: 0, alpha: 0 }, { duration: 200, easing: tween.easeIn, onFinish: function onFinish() { self.destroy(); } }); }; return self; }); // Spore class (projectile shot by fungi) var Spore = Container.expand(function () { var self = Container.call(this); // Use a simple green circle for the spore var sporeAsset = self.attachAsset('plant', { anchorX: 0.5, anchorY: 0.5, scaleX: 0.25, scaleY: 0.25 }); self.target = null; self.speed = 2.5; self._alive = true; self.update = function () { if (!self.target || self.target.eaten || !self._alive) { self.destroy(); self._alive = false; return; } var dx = self.target.x - self.x; var dy = self.target.y - self.y; var dist = Math.sqrt(dx * dx + dy * dy); if (dist > 1) { self.x += dx / dist * self.speed; self.y += dy / dist * self.speed; } // Check collision with target herbivore if (!self._lastIntersecting && self.intersects(self.target)) { // "Hit" the herbivore: destroy spore, animate herbivore, but do not kill if (self.target && typeof self.target.sporeHit === "function") { self.target.sporeHit(); } self.destroy(); self._alive = false; } self._lastIntersecting = self.intersects(self.target); }; return self; }); // FungiSpore class for future extensibility (could add poison, etc) // Modified: FungiSpore now takes a straight path (direction set at spawn) var FungiSpore = Spore.expand(function () { var self = Spore.call(this); // Store initial direction at spawn self._vx = 0; self._vy = 0; // Set direction only once at spawn, toward target self.setDirection = function () { if (self.target) { var dx = self.target.x - self.x; var dy = self.target.y - self.y; var dist = Math.sqrt(dx * dx + dy * dy); if (dist > 0) { self._vx = dx / dist * self.speed; self._vy = dy / dist * self.speed; } else { self._vx = 0; self._vy = 0; } } else { self._vx = 0; self._vy = 0; } }; // Call setDirection at spawn self.setDirection(); // Override update to move in a straight line self.update = function () { if (!self.target || self.target.eaten || !self._alive) { self.destroy(); self._alive = false; return; } self.x += self._vx; self.y += self._vy; // Check collision with target herbivore if (!self._lastIntersecting && self.intersects(self.target)) { if (self.target && typeof self.target.sporeHit === "function") { self.target.sporeHit(); } self.destroy(); self._alive = false; } self._lastIntersecting = self.intersects(self.target); }; return self; }); /**** * Initialize Game ****/ var game = new LK.Game({ backgroundColor: 0x2ecc40 //{7C} // Set to a green background }); /**** * Game Code ****/ // Add a cycle counter at the bottom of the screen that increments every 50 seconds (3000 frames at 60fps) // --- Cycle Counter --- var cycleCount = 0; var cycleTxt = new Text2("Cycle: 0", { size: 80, fill: "#fff" }); cycleTxt.anchor.set(0.5, 0); // Place at top left, but not in the top 100px reserved area LK.gui.top.addChild(cycleTxt); cycleTxt.x = 500; cycleTxt.y = 120; // --- Cycle Countdown Timer Text --- var cycleDurationMs = 50000; // 50,000 ms = 50 seconds var cycleTimeLeftMs = cycleDurationMs; var cycleTimerTxt = new Text2("Next cycle: 50s", { size: 60, fill: "#fff" }); cycleTimerTxt.anchor.set(0.5, 0); LK.gui.top.addChild(cycleTimerTxt); cycleTimerTxt.x = 500; cycleTimerTxt.y = cycleTxt.y + 80; // Place under the cycle counter // Timer to increment cycle every 50 seconds var cycleInterval = null; // Will be started after first organism is placed var cycleCountdownInterval = null; // For updating the countdown text function startCycleInterval() { if (cycleInterval !== null) return; cycleTimeLeftMs = cycleDurationMs; cycleTimerTxt.setText("Next cycle: " + Math.ceil(cycleTimeLeftMs / 1000) + "s"); cycleInterval = LK.setInterval(function () { cycleCount++; cycleTxt.setText("Cycle: " + cycleCount); cycleTimeLeftMs = cycleDurationMs; cycleTimerTxt.setText("Next cycle: " + Math.ceil(cycleTimeLeftMs / 1000) + "s"); // Change background to yellow on the 3rd cycle if (cycleCount === 3) { game.setBackgroundColor(0xffff00); } // Change background to white on the 6th cycle if (cycleCount === 6) { game.setBackgroundColor(0xffffff); } // Change background to green on the 9th cycle, then alternate yellow/white every 3 cycles after if (cycleCount >= 9) { var mod = (cycleCount - 9) % 3; if (mod === 0) { game.setBackgroundColor(0x2ecc40); // green } else if (mod === 1) { game.setBackgroundColor(0xffff00); // yellow } else if (mod === 2) { game.setBackgroundColor(0xffffff); // white } } }, cycleDurationMs); // Start countdown updater (every 100ms for smoothness) if (cycleCountdownInterval === null) { cycleCountdownInterval = LK.setInterval(function () { if (cycleTimeLeftMs > 0) { cycleTimeLeftMs -= 100; if (cycleTimeLeftMs < 0) cycleTimeLeftMs = 0; cycleTimerTxt.setText("Next cycle: " + Math.ceil(cycleTimeLeftMs / 1000) + "s"); } }, 100); } } // --- End of Game Code ---;; // --- Asset Initialization --- // new carnivore egg texture var plants = []; var herbivores = []; var carnivores = []; var seeds = []; var eggs = []; // Track all eggs globally var pollinators = []; var fungis = []; // Track all fungi globally var fungiSpores = []; // Track all spores shot by fungi // --- Palette UI --- var paletteY = 180; // y position for palette var paletteSpacing = 260; var paletteItems = []; // --- Delete Mode Button --- var deleteMode = false; var deleteBtn = new Container(); var deleteBtnBox = deleteBtn.attachAsset('box', { anchorX: 0.5, anchorY: 0.5, width: 220, height: 100, color: 0xcc3333, shape: 'box' }); var deleteBtnTxt = new Text2("Delete: OFF", { size: 54, fill: "#fff" }); deleteBtnTxt.anchor.set(0.5, 0.5); deleteBtn.addChild(deleteBtnTxt); // Place delete button under the cycle counter and timer deleteBtn.x = 500; deleteBtn.y = cycleTimerTxt.y + 140; // Move further down (was 90px, now 140px below the timer text) deleteBtn.interactive = true; deleteBtn.visible = true; deleteBtn.down = function () { deleteMode = !deleteMode; deleteBtnBox.color = deleteMode ? 0xff4444 : 0xcc3333; deleteBtnTxt.setText(deleteMode ? "Delete: ON" : "Delete: OFF"); }; LK.gui.top.addChild(deleteBtn); // --- Skip Cycle Button --- var skipCycleBtn = new Container(); var skipCycleBtnBox = skipCycleBtn.attachAsset('box', { anchorX: 0.5, anchorY: 0.5, width: 220, height: 100, color: 0x3388cc, shape: 'box' }); var skipCycleBtnTxt = new Text2("Skip Cycle", { size: 54, fill: "#fff" }); skipCycleBtnTxt.anchor.set(0.5, 0.5); skipCycleBtn.addChild(skipCycleBtnTxt); // Place skip button under the delete button skipCycleBtn.x = 500; skipCycleBtn.y = deleteBtn.y + 120; skipCycleBtn.interactive = true; skipCycleBtn.visible = true; skipCycleBtn.down = function () { // Increment cycle and update UI cycleCount++; cycleTxt.setText("Cycle: " + cycleCount); cycleTimeLeftMs = cycleDurationMs; cycleTimerTxt.setText("Next cycle: " + Math.ceil(cycleTimeLeftMs / 1000) + "s"); // Background color logic (same as in cycleInterval) if (cycleCount === 3) { game.setBackgroundColor(0xffff00); } if (cycleCount === 6) { game.setBackgroundColor(0xffffff); } if (cycleCount >= 9) { var mod = (cycleCount - 9) % 3; if (mod === 0) { game.setBackgroundColor(0x2ecc40); // green } else if (mod === 1) { game.setBackgroundColor(0xffff00); // yellow } else if (mod === 2) { game.setBackgroundColor(0xffffff); // white } } // Randomize all organism positions except fungi, plants, and lichen var minX = 124 + 60; var maxX = 124 + 1800 - 60; var minY = paletteY + 320 + 60; var maxY = paletteY + 320 + 2000 - 60; // Helper to randomize array of organisms function randomizeOrganisms(arr) { for (var i = 0; i < arr.length; i++) { var org = arr[i]; if (org && typeof org.x === "number" && typeof org.y === "number" && !org.eaten) { org.x = minX + Math.random() * (maxX - minX); org.y = minY + Math.random() * (maxY - minY); } } } randomizeOrganisms(herbivores); randomizeOrganisms(carnivores); randomizeOrganisms(pollinators); randomizeOrganisms(seeds); randomizeOrganisms(eggs); // Fungi, plants, and lichen are NOT moved // (fungis, plants, window.lichens) }; LK.gui.top.addChild(skipCycleBtn); // Shift the palette even further left so it is not offscreen var paletteTotalWidth = paletteSpacing * 2; var paletteXStart = 2048 / 2 - paletteTotalWidth / 2 - 1300; // Create palette items for drag-and-drop function createPaletteItem(type, x, y) { var assetId, color, label; if (type === 'plant') { assetId = 'plant'; color = 0x6adf60; label = 'Fern'; } else if (type === 'herbivore') { assetId = 'herbivore'; color = 0xf7e26b; label = 'Nummer'; } else if (type === 'pollinator') { assetId = 'pollinator'; color = 0xffc300; label = 'Pollinator'; } else if (type === 'fungi') { assetId = 'fungi'; color = 0xbb88ff; label = 'Shroom'; } else if (type === 'donothing') { assetId = 'flower'; // Use lichen asset for Lichen icon (matches Lichen organism) color = 0x888888; label = 'Lichen'; } else { assetId = 'carnivore'; color = 0xe74c3c; label = 'Hunter'; } ; // Update all eggs for (var i = eggs.length - 1; i >= 0; i--) { var e = eggs[i]; if (!e.parent || e.hatched) { eggs.splice(i, 1); continue; } if (e.update) e.update(); } ; // Update all pollinators for (var i = pollinators.length - 1; i >= 0; i--) { var p = pollinators[i]; if (p.eaten) { pollinators.splice(i, 1); continue; } if (p.update) p.update(); } var node = new Container(); var icon = node.attachAsset(assetId, { anchorX: 0.5, anchorY: 0.5 }); node.x = x; node.y = y; node.type = type; // Add label var txt = new Text2(label, { size: 60, fill: "#fff" }); txt.anchor.set(0.5, 0); txt.y = 60; node.addChild(txt); // Add to GUI overlay (so it stays on top) LK.gui.top.addChild(node); paletteItems.push(node); return node; } // --- Palette Scroll Bar --- // All available organism types in palette var paletteTypes = ['plant', 'herbivore', 'carnivore', 'pollinator', 'fungi', 'donothing']; var paletteScrollOffset = 0; // How much the palette is scrolled (in px) var paletteScrollMin = 0; var paletteScrollMax = Math.max(0, paletteTypes.length * paletteSpacing - paletteSpacing * 3); // Show 3 at a time // Remove old palette items if any for (var i = 0; i < paletteItems.length; i++) { if (paletteItems[i].parent) paletteItems[i].parent.removeChild(paletteItems[i]); } paletteItems = []; // Helper to render palette items based on scroll offset function renderPaletteItems() { // Remove all current palette items from GUI for (var i = 0; i < paletteItems.length; i++) { if (paletteItems[i].parent) paletteItems[i].parent.removeChild(paletteItems[i]); } paletteItems = []; // Only show up to 3 at a time, centered var visibleCount = 3; var startIdx = Math.floor(paletteScrollOffset / paletteSpacing); var offsetPx = paletteScrollOffset % paletteSpacing; for (var i = 0; i < visibleCount; i++) { var idx = startIdx + i; if (idx >= 0 && idx < paletteTypes.length) { var px = paletteXStart + i * paletteSpacing - offsetPx; var node = createPaletteItem(paletteTypes[idx], px, paletteY); paletteItems.push(node); } } // Draw left/right scroll buttons if (!window.paletteLeftBtn) { window.paletteLeftBtn = new Container(); var leftIcon = window.paletteLeftBtn.attachAsset('box', { anchorX: 0.5, anchorY: 0.5, width: 80, height: 120, color: 0x444444, shape: 'box' }); var leftArrow = new Text2("<", { size: 80, fill: "#fff" }); leftArrow.anchor.set(0.5, 0.5); leftArrow.x = 0; leftArrow.y = 0; window.paletteLeftBtn.addChild(leftArrow); window.paletteLeftBtn.x = paletteXStart - 120; window.paletteLeftBtn.y = paletteY; window.paletteLeftBtn.interactive = true; LK.gui.top.addChild(window.paletteLeftBtn); window.paletteLeftBtn.visible = false; } if (!window.paletteRightBtn) { window.paletteRightBtn = new Container(); var rightIcon = window.paletteRightBtn.attachAsset('box', { anchorX: 0.5, anchorY: 0.5, width: 80, height: 120, color: 0x444444, shape: 'box' }); var rightArrow = new Text2(">", { size: 80, fill: "#fff" }); rightArrow.anchor.set(0.5, 0.5); rightArrow.x = 0; rightArrow.y = 0; window.paletteRightBtn.addChild(rightArrow); window.paletteRightBtn.x = paletteXStart + paletteSpacing * visibleCount + 40; window.paletteRightBtn.y = paletteY; window.paletteRightBtn.interactive = true; LK.gui.top.addChild(window.paletteRightBtn); window.paletteRightBtn.visible = false; } // Show/hide buttons window.paletteLeftBtn.visible = paletteScrollOffset > paletteScrollMin; window.paletteRightBtn.visible = paletteScrollOffset < paletteScrollMax; } renderPaletteItems(); // --- Palette Scroll Button Handlers --- window.paletteLeftBtn.down = function () { if (paletteScrollOffset > paletteScrollMin) { paletteScrollOffset -= paletteSpacing; if (paletteScrollOffset < paletteScrollMin) paletteScrollOffset = paletteScrollMin; renderPaletteItems(); } }; window.paletteRightBtn.down = function () { if (paletteScrollOffset < paletteScrollMax) { paletteScrollOffset += paletteSpacing; if (paletteScrollOffset > paletteScrollMax) paletteScrollOffset = paletteScrollMax; renderPaletteItems(); } }; // --- End Palette Scroll Bar --- // --- Drag and Drop Logic --- var dragging = null; // {type, node, paletteRef} var dragOffsetX = 0, dragOffsetY = 0; // Helper: create organism at x,y function createOrganism(type, x, y) { var obj; if (type === 'plant') { obj = new Plant(); plants.push(obj); } else if (type === 'herbivore') { obj = new Nummer(); herbivores.push(obj); } else if (type === 'pollinator') { obj = new Pollinator(); pollinators.push(obj); } else if (type === 'fungi') { obj = new Fungi(); fungis.push(obj); } else if (type === 'donothing') { obj = new Lichen(); if (!window.lichens) window.lichens = []; window.lichens.push(obj); } else { obj = new Carnivore(); carnivores.push(obj); } obj.x = x; obj.y = y; obj.scaleX = 1; obj.scaleY = 1; obj.alpha = 1; game.addChild(obj); // Start the cycle interval if not already started if (typeof startCycleInterval === "function") startCycleInterval(); return obj; } // Helper: check if point is inside a palette item function isInPalette(x, y, node) { var bounds = { x: node.x - 60, y: node.y - 60, w: 120, h: 120 }; return x >= bounds.x && x <= bounds.x + bounds.w && y >= bounds.y && y <= bounds.y + bounds.h; } // --- Event Handlers --- // Down: start drag if on palette game.down = function (x, y, obj) { // If delete mode is ON, check if click is on an organism and delete it if (deleteMode) { // Include lichens in allOrganisms if present var allOrganisms = plants.concat(herbivores, carnivores, pollinators, fungis); if (window.lichens) { allOrganisms = allOrganisms.concat(window.lichens); } for (var i = allOrganisms.length - 1; i >= 0; i--) { var org = allOrganisms[i]; var dx = x - org.x; var dy = y - org.y; var dist = Math.sqrt(dx * dx + dy * dy); var isFungi = fungis.indexOf(org) !== -1; var isLichen = window.lichens && window.lichens.indexOf(org) !== -1; var canDelete = isFungi || isLichen || !org.eaten; if (canDelete && dist < 60) { // Remove from correct array if (plants.indexOf(org) !== -1) { var idx = plants.indexOf(org); if (idx !== -1) plants.splice(idx, 1); } else if (herbivores.indexOf(org) !== -1) { var idx = herbivores.indexOf(org); if (idx !== -1) herbivores.splice(idx, 1); } else if (carnivores.indexOf(org) !== -1) { var idx = carnivores.indexOf(org); if (idx !== -1) carnivores.splice(idx, 1); } else if (pollinators.indexOf(org) !== -1) { var idx = pollinators.indexOf(org); if (idx !== -1) pollinators.splice(idx, 1); } else if (fungis.indexOf(org) !== -1) { var idx = fungis.indexOf(org); if (idx !== -1) fungis.splice(idx, 1); } else if (isLichen) { var idx = window.lichens.indexOf(org); if (idx !== -1) window.lichens.splice(idx, 1); } if (typeof org.die === "function") { org.die(); } else if (typeof org.destroy === "function") { org.destroy(); } return; } } // If not on an organism, do nothing in delete mode return; } // Check if touch/click is on a palette item for (var i = 0; i < paletteItems.length; i++) { var p = paletteItems[i]; // Convert GUI coordinates to game coordinates var guiPos = LK.gui.top.toLocal({ x: x, y: y }, game); if (isInPalette(guiPos.x, guiPos.y, p)) { // Start dragging a new organism dragging = { type: p.type, node: createOrganism(p.type, x, y), paletteRef: p }; dragOffsetX = 0; dragOffsetY = 0; // Make it semi-transparent while dragging dragging.node.alpha = 0.7; return; } } // If not on palette, check if on an organism to move it // Check if touch/click is on an organism to move it var found = false; var allOrganisms = plants.concat(herbivores, carnivores, pollinators, fungis); if (window.lichens) { allOrganisms = allOrganisms.concat(window.lichens); } for (var i = allOrganisms.length - 1; i >= 0; i--) { var org = allOrganisms[i]; // Only allow moving if not eaten and touch is within 60px radius of center var dx = x - org.x; var dy = y - org.y; var dist = Math.sqrt(dx * dx + dy * dy); var isFungi = fungis.indexOf(org) !== -1; var isLichen = window.lichens && window.lichens.indexOf(org) !== -1; var canDrag = isFungi || isLichen || !org.eaten; if (canDrag && dist < 60) { var type; if (plants.indexOf(org) !== -1) type = 'plant';else if (herbivores.indexOf(org) !== -1) type = 'herbivore';else if (carnivores.indexOf(org) !== -1) type = 'carnivore';else if (pollinators.indexOf(org) !== -1) type = 'pollinator';else if (fungis.indexOf(org) !== -1) type = 'fungi';else if (isLichen) type = 'donothing'; // (UI label is handled in createPaletteItem, so no change needed here for type) dragging = { type: type, node: org, paletteRef: null }; dragOffsetX = org.x - x; dragOffsetY = org.y - y; org.alpha = 0.7; found = true; break; } } if (!found) { dragging = null; } }; // Move: update drag position game.move = function (x, y, obj) { if (dragging && dragging.node) { var minX = 124 + 60; var maxX = 124 + 1800 - 60; var minY = paletteY + 320 + 60; var maxY = paletteY + 320 + 2000 - 60; var newX = x + dragOffsetX; var newY = y + dragOffsetY; // Clamp to map area if (newX < minX) newX = minX; if (newX > maxX) newX = maxX; if (newY < minY) newY = minY; if (newY > maxY) newY = maxY; dragging.node.x = newX; dragging.node.y = newY; } }; // Up: drop organism if dragging game.up = function (x, y, obj) { if (dragging && dragging.node) { // If dropped inside palette area, destroy (cancel) var guiPos = LK.gui.top.toLocal({ x: x, y: y }, game); var cancel = false; for (var i = 0; i < paletteItems.length; i++) { if (isInPalette(guiPos.x, guiPos.y, paletteItems[i])) { cancel = true; break; } } if (cancel) { // Remove organism dragging.node.destroy(); if (dragging.type === 'plant') { var idx = plants.indexOf(dragging.node); if (idx !== -1) plants.splice(idx, 1); } else if (dragging.type === 'herbivore') { var idx = herbivores.indexOf(dragging.node); if (idx !== -1) herbivores.splice(idx, 1); } else if (dragging.type === 'carnivore') { var idx = carnivores.indexOf(dragging.node); if (idx !== -1) carnivores.splice(idx, 1); } else if (dragging.type === 'pollinator') { var idx = pollinators.indexOf(dragging.node); if (idx !== -1) pollinators.splice(idx, 1); } else if (dragging.type === 'fungi') { var idx = fungis.indexOf(dragging.node); if (idx !== -1) fungis.splice(idx, 1); } else if (dragging.type === 'donothing' && window.lichens) { var idx = window.lichens.indexOf(dragging.node); if (idx !== -1) window.lichens.splice(idx, 1); } } else { // Place organism: snap alpha to 1 dragging.node.alpha = 1; } dragging = null; } }; // --- Main Update Loop --- game.update = function () { // Update all herbivores for (var i = herbivores.length - 1; i >= 0; i--) { var h = herbivores[i]; if (h.eaten) { herbivores.splice(i, 1); continue; } if (h.update) h.update(); } // Update all carnivores for (var i = carnivores.length - 1; i >= 0; i--) { var c = carnivores[i]; if (c.eaten) { carnivores.splice(i, 1); continue; } if (c.update) c.update(); } // Clean up dead plants for (var i = plants.length - 1; i >= 0; i--) { var p = plants[i]; if (p.eaten) { plants.splice(i, 1); } } // Update all seeds for (var i = seeds.length - 1; i >= 0; i--) { var s = seeds[i]; if (s.eaten) { seeds.splice(i, 1); continue; } if (s.update) s.update(); } ; // Update all fungi for (var i = fungis.length - 1; i >= 0; i--) { var f = fungis[i]; if (f.update) f.update(); } // Update all fungi spores for (var i = fungiSpores.length - 1; i >= 0; i--) { var s = fungiSpores[i]; if (!s.parent || !s._alive) { fungiSpores.splice(i, 1); continue; } if (s.update) s.update(); } }; // --- Instructions Text --- // --- Random seed spawning around the map if there are any plants --- var randomSeedSpawnTimer = null; function startRandomSeedSpawning() { if (randomSeedSpawnTimer !== null) return; randomSeedSpawnTimer = LK.setInterval(function () { // Only spawn if there are any plants if (plants.length > 0) { // 40% chance per interval to spawn a seed if (Math.random() < 0.4) { // Pick a random position inside the map area var minX = 124 + 60; var maxX = 124 + 1800 - 60; var minY = paletteY + 320 + 60; var maxY = paletteY + 320 + 2000 - 60; var sx = minX + Math.random() * (maxX - minX); var sy = minY + Math.random() * (maxY - minY); var seed = new Seed(); seed.x = sx; seed.y = sy; seed.scaleX = 0.4; seed.scaleY = 0.4; seed.alpha = 1; seeds.push(seed); game.addChild(seed); } } // If no plants, stop spawning if (plants.length === 0 && randomSeedSpawnTimer !== null) { LK.clearInterval(randomSeedSpawnTimer); randomSeedSpawnTimer = null; } }, 120); // Try every 2 seconds } // Start random seed spawning at game start startRandomSeedSpawning(); // --- Map Area Border (for visual feedback) --- // Use a simple colored rectangle instead of a plant asset for the map border background var mapBorder = LK.getAsset('box', { anchorX: 0, anchorY: 0, width: 1800, height: 2000, color: 0x2e8b57, shape: 'box' }); mapBorder.alpha = 0.12; game.addChild(mapBorder); mapBorder.x = 124; mapBorder.y = paletteY + 320; // --- Add invisible border walls to prevent creatures from exiting the map area --- var borderThickness = 40; var borderAlpha = 0; // fully invisible // Left border var borderLeft = LK.getAsset('box', { anchorX: 0, anchorY: 0, width: borderThickness, height: 2000, color: 0x000000, shape: 'box' }); borderLeft.alpha = borderAlpha; game.addChild(borderLeft); borderLeft.x = 124 - borderThickness; borderLeft.y = paletteY + 320; // Right border var borderRight = LK.getAsset('box', { anchorX: 0, anchorY: 0, width: borderThickness, height: 2000, color: 0x000000, shape: 'box' }); borderRight.alpha = borderAlpha; game.addChild(borderRight); borderRight.x = 124 + 1800; borderRight.y = paletteY + 320; // Top border var borderTop = LK.getAsset('box', { anchorX: 0, anchorY: 0, width: 1800 + borderThickness * 2, height: borderThickness, color: 0x000000, shape: 'box' }); borderTop.alpha = borderAlpha; game.addChild(borderTop); borderTop.x = 124 - borderThickness; borderTop.y = paletteY + 320 - borderThickness; // Bottom border var borderBottom = LK.getAsset('box', { anchorX: 0, anchorY: 0, width: 1800 + borderThickness * 2, height: borderThickness, color: 0x000000, shape: 'box' }); borderBottom.alpha = borderAlpha; game.addChild(borderBottom); borderBottom.x = 124 - borderThickness; borderBottom.y = paletteY + 320 + 2000; // --- End of Game Code ---;
===================================================================
--- original.js
+++ change.js
@@ -1070,10 +1070,10 @@
/****
* Game Code
****/
-// --- Cycle Counter ---
// Add a cycle counter at the bottom of the screen that increments every 50 seconds (3000 frames at 60fps)
+// --- Cycle Counter ---
var cycleCount = 0;
var cycleTxt = new Text2("Cycle: 0", {
size: 80,
fill: "#fff"
@@ -1108,47 +1108,22 @@
cycleTimerTxt.setText("Next cycle: " + Math.ceil(cycleTimeLeftMs / 1000) + "s");
// Change background to yellow on the 3rd cycle
if (cycleCount === 3) {
game.setBackgroundColor(0xffff00);
- if (typeof seasonLabel !== "undefined") {
- seasonLabel.visible = true;
- seasonLabel.setText("summer");
- seasonLabel.style.fill = 0xffff00;
- }
}
// Change background to white on the 6th cycle
if (cycleCount === 6) {
game.setBackgroundColor(0xffffff);
- if (typeof seasonLabel !== "undefined") {
- seasonLabel.visible = true;
- seasonLabel.setText("winter");
- seasonLabel.style.fill = 0xffffff;
- }
}
// Change background to green on the 9th cycle, then alternate yellow/white every 3 cycles after
if (cycleCount >= 9) {
var mod = (cycleCount - 9) % 3;
if (mod === 0) {
game.setBackgroundColor(0x2ecc40); // green
- if (typeof seasonLabel !== "undefined") {
- seasonLabel.visible = true;
- seasonLabel.setText("spring");
- seasonLabel.style.fill = 0x2ecc40;
- }
} else if (mod === 1) {
game.setBackgroundColor(0xffff00); // yellow
- if (typeof seasonLabel !== "undefined") {
- seasonLabel.visible = true;
- seasonLabel.setText("summer");
- seasonLabel.style.fill = 0xffff00;
- }
} else if (mod === 2) {
game.setBackgroundColor(0xffffff); // white
- if (typeof seasonLabel !== "undefined") {
- seasonLabel.visible = true;
- seasonLabel.setText("winter");
- seasonLabel.style.fill = 0xffffff;
- }
}
}
}, cycleDurationMs);
// Start countdown updater (every 100ms for smoothness)
@@ -1161,14 +1136,8 @@
}
}, 100);
}
}
-// Show correct season label at game start
-if (typeof seasonLabel !== "undefined") {
- seasonLabel.visible = true;
- seasonLabel.setText("spring");
- seasonLabel.style.fill = 0x2ecc40;
-}
// --- End of Game Code ---;;
// --- Asset Initialization ---
// new carnivore egg texture
var plants = [];
@@ -1210,18 +1179,76 @@
deleteBtnBox.color = deleteMode ? 0xff4444 : 0xcc3333;
deleteBtnTxt.setText(deleteMode ? "Delete: ON" : "Delete: OFF");
};
LK.gui.top.addChild(deleteBtn);
-// Add season label under the delete button
-var seasonLabel = new Text2("spring", {
+// --- Skip Cycle Button ---
+var skipCycleBtn = new Container();
+var skipCycleBtnBox = skipCycleBtn.attachAsset('box', {
+ anchorX: 0.5,
+ anchorY: 0.5,
+ width: 220,
+ height: 100,
+ color: 0x3388cc,
+ shape: 'box'
+});
+var skipCycleBtnTxt = new Text2("Skip Cycle", {
size: 54,
- fill: 0x2ECC40 // green for spring
+ fill: "#fff"
});
-seasonLabel.anchor.set(0.5, 0);
-seasonLabel.x = deleteBtn.x;
-seasonLabel.y = deleteBtn.y + deleteBtnBox.height / 2 + 16; // 16px below the delete button
-seasonLabel.visible = true;
-LK.gui.top.addChild(seasonLabel);
+skipCycleBtnTxt.anchor.set(0.5, 0.5);
+skipCycleBtn.addChild(skipCycleBtnTxt);
+// Place skip button under the delete button
+skipCycleBtn.x = 500;
+skipCycleBtn.y = deleteBtn.y + 120;
+skipCycleBtn.interactive = true;
+skipCycleBtn.visible = true;
+skipCycleBtn.down = function () {
+ // Increment cycle and update UI
+ cycleCount++;
+ cycleTxt.setText("Cycle: " + cycleCount);
+ cycleTimeLeftMs = cycleDurationMs;
+ cycleTimerTxt.setText("Next cycle: " + Math.ceil(cycleTimeLeftMs / 1000) + "s");
+ // Background color logic (same as in cycleInterval)
+ if (cycleCount === 3) {
+ game.setBackgroundColor(0xffff00);
+ }
+ if (cycleCount === 6) {
+ game.setBackgroundColor(0xffffff);
+ }
+ if (cycleCount >= 9) {
+ var mod = (cycleCount - 9) % 3;
+ if (mod === 0) {
+ game.setBackgroundColor(0x2ecc40); // green
+ } else if (mod === 1) {
+ game.setBackgroundColor(0xffff00); // yellow
+ } else if (mod === 2) {
+ game.setBackgroundColor(0xffffff); // white
+ }
+ }
+ // Randomize all organism positions except fungi, plants, and lichen
+ var minX = 124 + 60;
+ var maxX = 124 + 1800 - 60;
+ var minY = paletteY + 320 + 60;
+ var maxY = paletteY + 320 + 2000 - 60;
+ // Helper to randomize array of organisms
+ function randomizeOrganisms(arr) {
+ for (var i = 0; i < arr.length; i++) {
+ var org = arr[i];
+ if (org && typeof org.x === "number" && typeof org.y === "number" && !org.eaten) {
+ org.x = minX + Math.random() * (maxX - minX);
+ org.y = minY + Math.random() * (maxY - minY);
+ }
+ }
+ }
+ randomizeOrganisms(herbivores);
+ randomizeOrganisms(carnivores);
+ randomizeOrganisms(pollinators);
+ randomizeOrganisms(seeds);
+ randomizeOrganisms(eggs);
+ // Fungi, plants, and lichen are NOT moved
+ // (fungis, plants, window.lichens)
+};
+LK.gui.top.addChild(skipCycleBtn);
// Shift the palette even further left so it is not offscreen
var paletteTotalWidth = paletteSpacing * 2;
var paletteXStart = 2048 / 2 - paletteTotalWidth / 2 - 1300;
// Create palette items for drag-and-drop
tentacled red circle with a mouth and no eyes. In-Game asset. 2d. High contrast. No shadows. Very simple
A plant. In-Game asset. 2d. High contrast. No shadows. Very simple
Brown Seed. In-Game asset. 2d. High contrast. No shadows. Very simple
A small orange circle with spider legs 1 cute eye and no mouth. In-Game asset. 2d. High contrast. No shadows. Very very simple
Make a red egg with dark red spots. In-Game asset. 2d. High contrast. No shadows
Purple mushroom. In-Game asset. 2d. High contrast. No shadows. Very simple
A green shiny orb with a black circle. In-Game asset. 2d. High contrast. No shadows. Very simple
make a cyan lichen. In-Game asset. 2d. High contrast. No shadows. very simple
Just the color blue filling the entire space. In-Game asset. 2d. High contrast. No shadows
A brown circle with bug like antennas and bug legs with bug jaws and no eyes. In-Game asset. 2d. High contrast. No shadows. Very simple
A venus flytrap with one mouth and is looking up side view. In-Game asset. 2d. High contrast. No shadows VERY SIMPLE
Short brown worm. In-Game asset. 2d. High contrast. No shadows. Very simple
Pile of dirt. In-Game asset. 2d. High contrast. No shadows. Very simple
A yellow circle with 3 eyes no mouth and the eyes are in a triangle orientation. In-Game asset. 2d. High contrast. No shadows
Shrub. In-Game asset. 2d. High contrast. No shadows. Very simple