User prompt
ahora vuelve a poner el pajaro al minuto 3 y el primer jefe al primero
User prompt
sigue diciendo purple snake arrives in 60s tiene que ser 35
User prompt
cambia el tiempo de aparicion de la serpiente morada en evento de jefe del pajaro de 60 segundos a 35
User prompt
el modo automatico evitara morir a toda costa
User prompt
la serpiente no es invencible al tomar el poder multicolor
User prompt
el escudo es una vida extra continua que al morir se puede continuar por una sola vez ↪💡 Consider importing and using the following plugins: @upit/tween.v1
User prompt
el escudo no esta funcionando
User prompt
el escudo de la naranja dara una inmortalidad de la serpiente durante 4 segundos luego de eso el escudo desaparece ↪💡 Consider importing and using the following plugins: @upit/tween.v1
User prompt
pon solo por ahora el pajaro a los 30 segundos ↪💡 Consider importing and using the following plugins: @upit/tween.v1
User prompt
solo por ahora haz que el primer jefe sea el pajaro a los 60 segundos ↪💡 Consider importing and using the following plugins: @upit/tween.v1
User prompt
a los 3 minutos crea un nuevo jefe que en este caso será un ave que intentara atrapar a la serpiente moviendose rapido cada 4 segundos avanzando solo hasta el ultimo punto que estuvo la serpiente y se movera asi continuamente hasta que aparezca la serpiente morada a los 60 segundos y el ave se la llevará volando asi derrotando este jefe ↪💡 Consider importing and using the following plugins: @upit/tween.v1
User prompt
3 segundos de inmortalidad con el escudo luego de que se haga daño ↪💡 Consider importing and using the following plugins: @upit/tween.v1
User prompt
repara el escudo de la naranja permitiendo un 2 segundos de inmortalidad luego de que se desactive al tocar daño ↪💡 Consider importing and using the following plugins: @upit/tween.v1
User prompt
Please fix the bug: 'TypeError: Cannot read properties of undefined (reading 'x')' in or related to this line: 'var currentIntersectingBoss = Math.sqrt(Math.pow(rock.x - currentBoss.x, 2) + Math.pow(rock.y - currentBoss.y, 2)) < 190;' Line Number: 1747
User prompt
el radio de las luces intermitentes son circulares al rededor de donde aparecera el jefe
User prompt
las luces intermitentes antes del jefe son circulares en forma no ovaladas
User prompt
repara el escudo
User prompt
el bloque de x2 solo aparecera en un 50% de probabilidad cada 30 segundos
User prompt
añade un tercer evento que sera una serpiente morada que robara los puntos y las frutas, esta serpiente enemiga ignora al jugador pero si se toca el jugador morira ↪💡 Consider importing and using the following plugins: @upit/tween.v1
User prompt
agrega la fruta naranja y si se consume la serpiente tiene un escudo delante su cabeza que le dara una oportunidad para ser dañado sin morir ↪💡 Consider importing and using the following plugins: @upit/tween.v1
User prompt
la colision de la serpiente al ser mas grande por la pera tambien se agranda
User prompt
Please fix the bug: 'TypeError: Cannot read properties of undefined (reading 'x')' in or related to this line: 'var currentIntersectingBoss = Math.sqrt(Math.pow(rock.x - currentBoss.x, 2) + Math.pow(rock.y - currentBoss.y, 2)) < 190;' Line Number: 1421
User prompt
agrega arriba al centro un temporizador y abajo del temporizador el proximo evento que aparecera
User prompt
Please fix the bug: 'TypeError: Cannot read properties of undefined (reading 'x')' in or related to this line: 'var currentIntersectingBoss = Math.sqrt(Math.pow(rock.x - currentBoss.x, 2) + Math.pow(rock.y - currentBoss.y, 2)) < 190;' Line Number: 1371
User prompt
el bloque de x2 se mueve rebotando tambien lentamente ↪💡 Consider importing and using the following plugins: @upit/tween.v1
/****
* Plugins
****/
var tween = LK.import("@upit/tween.v1");
var storage = LK.import("@upit/storage.v1");
/****
* Classes
****/
var BirdBoss = Container.expand(function () {
var self = Container.call(this);
var graphics = self.attachAsset('birdBoss', {
anchorX: 0.5,
anchorY: 0.5
});
self.health = 3;
self.maxHealth = 3;
self.moveTimer = 0;
self.moveInterval = 240; // 4 seconds at 60fps
self.lastTargetX = GAME_WIDTH / 2;
self.lastTargetY = GAME_HEIGHT / 2;
self.speed = 12;
self.isMoving = false;
self.targetX = GAME_WIDTH / 2;
self.targetY = GAME_HEIGHT / 2;
self.update = function () {
self.moveTimer++;
// Every 4 seconds, set new target to snake's current position
if (self.moveTimer >= self.moveInterval) {
self.moveTimer = 0;
if (snake.length > 0) {
var head = snake[0];
self.targetX = head.x;
self.targetY = head.y;
self.isMoving = true;
}
}
// Move towards target if moving
if (self.isMoving) {
var deltaX = self.targetX - self.x;
var deltaY = self.targetY - self.y;
var distance = Math.sqrt(deltaX * deltaX + deltaY * deltaY);
if (distance > 10) {
var moveX = deltaX / distance * self.speed;
var moveY = deltaY / distance * self.speed;
self.x += moveX;
self.y += moveY;
} else {
self.isMoving = false;
}
}
};
self.takeDamage = function () {
self.health--;
if (self.health <= 0) {
self.die();
}
};
self.die = function () {
LK.setScore(LK.getScore() + 150);
scoreTxt.setText('Score: ' + LK.getScore());
birdBossActive = false;
birdBossDefeated = true;
self.destroy();
};
return self;
});
var BossRock = Container.expand(function () {
var self = Container.call(this);
var graphics = self.attachAsset('bossRock', {
anchorX: 0.5,
anchorY: 0.5
});
// Initialize velocity (will be set when rock is created)
self.velocityX = 0;
self.velocityY = 0;
self.bounceCount = 0;
self.maxBounces = 3;
self.lastX = 0;
self.lastY = 0;
self.lastIntersectingBoss = false;
self.setTarget = function (startX, startY, targetX, targetY) {
// Calculate velocity towards target
var angle = Math.atan2(targetY - startY, targetX - startX);
self.velocityX = Math.cos(angle) * 8;
self.velocityY = Math.sin(angle) * 8;
self.lastX = startX;
self.lastY = startY;
};
self.update = function () {
// Store last position
self.lastX = self.x;
self.lastY = self.y;
// Move rock
self.x += self.velocityX;
self.y += self.velocityY;
// Bounce off walls
if (self.x <= 50 || self.x >= GAME_WIDTH - 50) {
self.velocityX = -self.velocityX;
self.x = Math.max(50, Math.min(GAME_WIDTH - 50, self.x));
self.bounceCount++;
self.updateGrayness();
if (self.bounceCount >= self.maxBounces) {
self.destroy();
return;
}
}
if (self.y <= 50 || self.y >= GAME_HEIGHT - 50) {
self.velocityY = -self.velocityY;
self.y = Math.max(50, Math.min(GAME_HEIGHT - 50, self.y));
self.bounceCount++;
self.updateGrayness();
if (self.bounceCount >= self.maxBounces) {
self.destroy();
return;
}
}
};
self.updateGrayness = function () {
// Make rock grayer with each bounce
var grayness = 0.7 + self.bounceCount * 0.1;
var grayColor = Math.floor(0x69 * grayness) << 16 | Math.floor(0x69 * grayness) << 8 | Math.floor(0x69 * grayness);
graphics.tint = grayColor;
};
return self;
});
var CrownDrop = Container.expand(function () {
var self = Container.call(this);
var graphics = self.attachAsset('crownDrop', {
anchorX: 0.5,
anchorY: 0.5
});
// Add gentle pulsing animation
self.animationCounter = 0;
self.baseScale = 1.0;
self.update = function () {
// Gentle pulsing animation
self.animationCounter += 0.08;
var pulseScale = self.baseScale + Math.sin(self.animationCounter) * 0.15;
graphics.scaleX = pulseScale;
graphics.scaleY = pulseScale;
};
return self;
});
var EnemySnake = Container.expand(function () {
var self = Container.call(this);
// Create enemy snake head
var headGraphics = self.attachAsset('enemySnakeHead', {
anchorX: 0.5,
anchorY: 0.5
});
// Enemy snake properties
self.segments = [];
self.direction = {
x: 1,
y: 0
};
self.speed = 6;
self.moveCounter = 0;
self.gridX = 0;
self.gridY = 0;
self.lastTargetTime = 0;
self.targetFruit = null;
self.targetGrowthPoint = null;
// Create initial body segments
for (var i = 0; i < 3; i++) {
var segment = new Container();
var segmentGraphics = segment.attachAsset('enemySnakeBody', {
anchorX: 0.5,
anchorY: 0.5
});
segment.gridX = self.gridX - (i + 1);
segment.gridY = self.gridY;
segment.x = segment.gridX * GRID_SIZE + GRID_SIZE / 2;
segment.y = segment.gridY * GRID_SIZE + GRID_SIZE / 2;
self.segments.push(segment);
game.addChild(segment);
}
self.findNearestTarget = function () {
var targets = [];
// Add fruits as targets
if (currentFruit) {
targets.push({
type: 'fruit',
obj: currentFruit,
x: currentFruit.gridX,
y: currentFruit.gridY,
priority: 2
});
}
// Add growth points as targets
for (var i = 0; i < growthPoints.length; i++) {
targets.push({
type: 'growthPoint',
obj: growthPoints[i],
x: growthPoints[i].gridX,
y: growthPoints[i].gridY,
priority: 1
});
}
if (targets.length === 0) return null;
// Find closest target
var closest = targets[0];
var closestDist = Math.abs(closest.x - self.gridX) + Math.abs(closest.y - self.gridY);
for (var i = 1; i < targets.length; i++) {
var dist = Math.abs(targets[i].x - self.gridX) + Math.abs(targets[i].y - self.gridY);
if (dist < closestDist || dist === closestDist && targets[i].priority > closest.priority) {
closest = targets[i];
closestDist = dist;
}
}
return closest;
};
self.moveTowardsTarget = function () {
var target = self.findNearestTarget();
if (!target) {
// Random movement if no target
var directions = [{
x: 1,
y: 0
}, {
x: -1,
y: 0
}, {
x: 0,
y: 1
}, {
x: 0,
y: -1
}];
self.direction = directions[Math.floor(Math.random() * directions.length)];
return;
}
var deltaX = target.x - self.gridX;
var deltaY = target.y - self.gridY;
// Choose direction based on larger delta
if (Math.abs(deltaX) > Math.abs(deltaY)) {
self.direction = {
x: deltaX > 0 ? 1 : -1,
y: 0
};
} else {
self.direction = {
x: 0,
y: deltaY > 0 ? 1 : -1
};
}
};
self.update = function () {
self.moveCounter++;
var moveInterval = Math.max(3, 15 - self.speed);
if (self.moveCounter >= moveInterval) {
self.moveCounter = 0;
// Update movement direction towards targets
self.moveTowardsTarget();
// Calculate new position
var newGridX = self.gridX + self.direction.x;
var newGridY = self.gridY + self.direction.y;
// Bounce off walls
if (newGridX <= 0 || newGridX >= COLS - 1) {
self.direction.x = -self.direction.x;
newGridX = self.gridX + self.direction.x;
}
if (newGridY <= 0 || newGridY >= ROWS - 1) {
self.direction.y = -self.direction.y;
newGridY = self.gridY + self.direction.y;
}
// Move body segments
for (var i = self.segments.length - 1; i > 0; i--) {
self.segments[i].gridX = self.segments[i - 1].gridX;
self.segments[i].gridY = self.segments[i - 1].gridY;
self.segments[i].x = self.segments[i].gridX * GRID_SIZE + GRID_SIZE / 2;
self.segments[i].y = self.segments[i].gridY * GRID_SIZE + GRID_SIZE / 2;
}
// Move first body segment to old head position
if (self.segments.length > 0) {
self.segments[0].gridX = self.gridX;
self.segments[0].gridY = self.gridY;
self.segments[0].x = self.gridX * GRID_SIZE + GRID_SIZE / 2;
self.segments[0].y = self.gridY * GRID_SIZE + GRID_SIZE / 2;
}
// Move head
self.gridX = newGridX;
self.gridY = newGridY;
self.x = self.gridX * GRID_SIZE + GRID_SIZE / 2;
self.y = self.gridY * GRID_SIZE + GRID_SIZE / 2;
// Check for fruit collision
if (currentFruit && currentFruit.gridX === self.gridX && currentFruit.gridY === self.gridY) {
// Steal points (reduce player score)
var currentScore = LK.getScore();
LK.setScore(Math.max(0, currentScore - 10));
scoreTxt.setText('Score: ' + LK.getScore());
// Remove the fruit
currentFruit.destroy();
currentFruit = null;
spawnFruit();
// Flash screen purple to indicate theft
LK.effects.flashScreen(0x8b008b, 300);
}
// Check for growth point collision
for (var i = growthPoints.length - 1; i >= 0; i--) {
if (growthPoints[i].gridX === self.gridX && growthPoints[i].gridY === self.gridY) {
// Steal points (reduce player score)
var currentScore = LK.getScore();
LK.setScore(Math.max(0, currentScore - 5));
scoreTxt.setText('Score: ' + LK.getScore());
// Remove the growth point
growthPoints[i].destroy();
growthPoints.splice(i, 1);
// Flash screen purple to indicate theft
LK.effects.flashScreen(0x8b008b, 300);
break;
}
}
}
};
self.destroy = function () {
// Destroy all body segments
for (var i = 0; i < self.segments.length; i++) {
if (self.segments[i].parent) {
self.segments[i].destroy();
}
}
self.segments = [];
// Destroy head
if (self.parent) {
Container.prototype.destroy.call(self);
}
};
return self;
});
var Fruit = Container.expand(function (type) {
var self = Container.call(this);
var assetName = 'apple';
if (type === 'pear') assetName = 'pear';else if (type === 'banana') assetName = 'banana';else if (type === 'multicolor') assetName = 'multicolor';else if (type === 'coconut') assetName = 'coconut';else if (type === 'orange') assetName = 'orange';
var graphics = self.attachAsset(assetName, {
anchorX: 0.5,
anchorY: 0.5
});
self.fruitType = type || 'apple';
// Add gentle pulsing animation to all fruits
self.animationCounter = 0;
self.baseScale = 1.0;
// Add color animation for multicolor fruit
if (type === 'multicolor') {
self.colorIndex = 0;
self.colors = [0xff3333, 0x44dd44, 0x3366ff, 0xffdd44, 0xff44dd, 0x44ddff];
self.update = function () {
// Color cycling for multicolor fruit
if (LK.ticks % 15 === 0) {
self.colorIndex = (self.colorIndex + 1) % self.colors.length;
graphics.tint = self.colors[self.colorIndex];
}
// Gentle pulsing animation
self.animationCounter += 0.08;
var pulseScale = self.baseScale + Math.sin(self.animationCounter) * 0.15;
graphics.scaleX = pulseScale;
graphics.scaleY = pulseScale;
};
} else {
self.update = function () {
// Gentle pulsing animation for regular fruits
self.animationCounter += 0.06;
var pulseScale = self.baseScale + Math.sin(self.animationCounter) * 0.1;
graphics.scaleX = pulseScale;
graphics.scaleY = pulseScale;
};
}
return self;
});
var GrowthPoint = Container.expand(function () {
var self = Container.call(this);
var graphics = self.attachAsset('growthPoint', {
anchorX: 0.5,
anchorY: 0.5
});
// Add gentle pulsing animation
self.animationCounter = 0;
self.baseScale = 1.0;
self.update = function () {
// Gentle pulsing animation
self.animationCounter += 0.1;
var pulseScale = self.baseScale + Math.sin(self.animationCounter) * 0.2;
graphics.scaleX = pulseScale;
graphics.scaleY = pulseScale;
};
return self;
});
var LavaArea = Container.expand(function () {
var self = Container.call(this);
var graphics = self.attachAsset('lavaArea', {
anchorX: 0,
anchorY: 0
});
self.isWarning = true;
self.warningTime = 5000; // 5 seconds warning
self.startTime = Date.now();
// Set initial warning appearance
graphics.alpha = 0.3;
graphics.tint = 0xffff00; // Yellow warning
self.update = function () {
var elapsed = Date.now() - self.startTime;
if (self.isWarning && elapsed < self.warningTime) {
// Slower, more intermittent blinking warning effect
var blinkSpeed = 2; // Much slower blinking
var blinkCycle = Math.sin(LK.ticks * blinkSpeed * 0.1);
// More intermittent pattern - only blink when sine wave is positive
if (blinkCycle > 0) {
graphics.alpha = 0.3 + 0.4 * blinkCycle;
} else {
graphics.alpha = 0.1; // Very dim when not blinking
}
} else if (self.isWarning && elapsed >= self.warningTime) {
// Convert to lava
self.isWarning = false;
graphics.alpha = 1.0;
graphics.tint = 0xff4400; // Red lava
}
};
return self;
});
var PotatoBoss = Container.expand(function () {
var self = Container.call(this);
// Create boss body
var body = self.attachAsset('bossBody', {
anchorX: 0.5,
anchorY: 0.5
});
// Create angry eyebrows
var leftEyebrow = self.attachAsset('bossEyebrow', {
anchorX: 0.5,
anchorY: 0.5,
x: -40,
y: -50
});
var rightEyebrow = self.attachAsset('bossEyebrow', {
anchorX: 0.5,
anchorY: 0.5,
x: 40,
y: -50
});
// Angle the eyebrows for angry look
leftEyebrow.rotation = 0.3;
rightEyebrow.rotation = -0.3;
// Create crown
var crown = self.attachAsset('bossCrown', {
anchorX: 0.5,
anchorY: 1,
x: 0,
y: -80
});
self.health = 5;
self.maxHealth = 5;
self.shootTimer = 0;
self.shootInterval = 120; // 2 seconds at 60fps
self.hitFlashTimer = 0;
self.update = function () {
// Shooting logic
self.shootTimer++;
if (self.shootTimer >= self.shootInterval) {
self.shootTimer = 0;
self.shootRock();
}
// Hit flash effect
if (self.hitFlashTimer > 0) {
self.hitFlashTimer--;
var flashIntensity = self.hitFlashTimer / 30;
body.tint = 0xFFFFFF * flashIntensity + 0xD2B48C * (1 - flashIntensity);
} else {
body.tint = 0xFFFFFF;
}
};
self.shootRock = function () {
if (!gameRunning || snake.length === 0) return;
// Shoot towards snake head
var head = snake[0];
var rock = new BossRock();
rock.x = self.x;
rock.y = self.y;
rock.setTarget(self.x, self.y, head.x, head.y);
bossRocks.push(rock);
game.addChild(rock);
LK.getSound('boss_shoot').play();
};
self.takeDamage = function () {
self.health--;
self.hitFlashTimer = 30;
LK.getSound('boss_hit').play();
if (self.health <= 0) {
self.die();
}
};
self.die = function () {
LK.getSound('boss_defeat').play();
LK.setScore(LK.getScore() + 100);
scoreTxt.setText('Score: ' + LK.getScore());
bossActive = false;
bossDefeated = true;
// Drop crown at boss position
crownDrop = new CrownDrop();
crownDrop.x = self.x;
crownDrop.y = self.y;
game.addChild(crownDrop);
// Update missions - boss killed
if (!missions.bossKilled.completed) {
missions.bossKilled.current++;
storage.bossKilled = missions.bossKilled.current;
if (missions.bossKilled.current >= missions.bossKilled.target) {
missions.bossKilled.completed = true;
storage.bossCompleted = true;
}
updateMissionsDisplay();
}
// Clear boss and rocks
for (var i = bossRocks.length - 1; i >= 0; i--) {
bossRocks[i].destroy();
}
bossRocks = [];
self.destroy();
};
return self;
});
var PurpleSnake = Container.expand(function () {
var self = Container.call(this);
var graphics = self.attachAsset('purpleSnake', {
anchorX: 0.5,
anchorY: 0.5
});
self.speed = 8;
self.targetX = GAME_WIDTH / 2;
self.targetY = GAME_HEIGHT / 2;
self.update = function () {
// Move towards center of screen
var deltaX = self.targetX - self.x;
var deltaY = self.targetY - self.y;
var distance = Math.sqrt(deltaX * deltaX + deltaY * deltaY);
if (distance > 5) {
var moveX = deltaX / distance * self.speed;
var moveY = deltaY / distance * self.speed;
self.x += moveX;
self.y += moveY;
}
};
return self;
});
var SnakeHead = Container.expand(function () {
var self = Container.call(this);
var graphics = self.attachAsset('snakeHead', {
anchorX: 0.5,
anchorY: 0.5
});
// Create crown but make it invisible initially
var crown = self.attachAsset('snakeCrown', {
anchorX: 0.5,
anchorY: 1,
x: 0,
y: -20
});
crown.visible = false; // Crown is hidden until collected
// Create shield but make it invisible initially
var shield = self.attachAsset('shield', {
anchorX: 0.5,
anchorY: 0.5,
x: 0,
y: -10
});
shield.visible = false; // Shield is hidden until orange is consumed
shield.alpha = 0.7; // Semi-transparent shield
self.thickness = 1;
self.animationCounter = 0;
self.baseThickness = 1;
self.hasCrown = false; // Track if snake has collected crown
self.hasShield = false; // Track if snake has shield protection
self.immunityActive = false; // Track if snake has immunity after shield removal
self.immunityEndTime = 0; // When immunity period ends
self.setThickness = function (newThickness) {
self.thickness = newThickness;
self.baseThickness = newThickness;
graphics.scaleX = newThickness;
graphics.scaleY = newThickness;
};
self.showCrown = function () {
self.hasCrown = true;
crown.visible = true;
};
self.activateShield = function () {
self.hasShield = true;
shield.visible = true;
shield.alpha = 0.7;
// Add shield pulsing animation
tween(shield, {
scaleX: 1.2,
scaleY: 1.2
}, {
duration: 500,
easing: tween.easeInOut,
onFinish: function onFinish() {
if (shield && shield.visible && self.hasShield) {
tween(shield, {
scaleX: 1,
scaleY: 1
}, {
duration: 500,
easing: tween.easeInOut,
loop: true,
yoyo: true
});
}
}
});
};
self.removeShield = function () {
self.hasShield = false;
shield.visible = false;
// Stop any active tweens on the shield
if (shield && shield.parent) {
tween.stop(shield);
shield.scaleX = 1;
shield.scaleY = 1;
}
// Activate 4 seconds of immunity after shield removal
self.immunityActive = true;
self.immunityEndTime = Date.now() + 4000; // 4 seconds immunity
};
self.update = function () {
// Check immunity expiration
if (self.immunityActive && Date.now() >= self.immunityEndTime) {
self.immunityActive = false;
graphics.alpha = 1.0; // Reset alpha when immunity ends
}
// Subtle breathing animation for snake head
self.animationCounter += 0.05;
var breatheScale = self.baseThickness + Math.sin(self.animationCounter) * 0.05;
graphics.scaleX = breatheScale;
graphics.scaleY = breatheScale;
// Shield pulsing animation when active
if (self.hasShield && shield && shield.visible) {
shield.alpha = 0.5 + Math.sin(self.animationCounter * 3) * 0.2;
}
// Immunity flashing effect
if (self.immunityActive) {
graphics.alpha = 0.5 + Math.sin(self.animationCounter * 8) * 0.3;
}
};
return self;
});
var SnakeSegment = Container.expand(function () {
var self = Container.call(this);
var graphics = self.attachAsset('snakeBody', {
anchorX: 0.5,
anchorY: 0.5
});
self.thickness = 1;
self.setThickness = function (newThickness) {
self.thickness = newThickness;
graphics.scaleX = newThickness;
graphics.scaleY = newThickness;
};
return self;
});
var Spike = Container.expand(function () {
var self = Container.call(this);
var graphics = self.attachAsset('spike', {
anchorX: 0.5,
anchorY: 0.5
});
self.velocityX = 0;
self.velocityY = 0;
self.speed = 3;
// Set random direction
var angle = Math.random() * Math.PI * 2;
self.velocityX = Math.cos(angle) * self.speed;
self.velocityY = Math.sin(angle) * self.speed;
self.update = function () {
// Move spike
self.x += self.velocityX;
self.y += self.velocityY;
// Bounce off walls
if (self.x <= 30 || self.x >= GAME_WIDTH - 30) {
self.velocityX = -self.velocityX;
self.x = Math.max(30, Math.min(GAME_WIDTH - 30, self.x));
LK.getSound('spike_bounce').play();
}
if (self.y <= 30 || self.y >= GAME_HEIGHT - 30) {
self.velocityY = -self.velocityY;
self.y = Math.max(30, Math.min(GAME_HEIGHT - 30, self.y));
LK.getSound('spike_bounce').play();
}
};
return self;
});
var WarningLight = Container.expand(function () {
var self = Container.call(this);
var graphics = self.attachAsset('warningLight', {
anchorX: 0.5,
anchorY: 0.5
});
self.blinkTimer = 0;
self.update = function () {
self.blinkTimer += 0.15;
// Dark intermittent blinking
graphics.alpha = Math.abs(Math.sin(self.blinkTimer)) < 0.3 ? 0.8 : 0.1;
// Ensure circular shape by maintaining equal scale
graphics.scaleX = graphics.scaleY;
};
return self;
});
var X2Powerup = Container.expand(function () {
var self = Container.call(this);
var graphics = self.attachAsset('x2Powerup', {
anchorX: 0.5,
anchorY: 0.5
});
self.lifeTime = 10000; // 10 seconds
self.startTime = Date.now();
self.blinkStartTime = 7000; // Start blinking at 7 seconds (3 seconds before end)
// Add bouncing movement properties
self.velocityX = 0;
self.velocityY = 0;
self.speed = 1.5; // Slow movement speed
// Set random direction
var angle = Math.random() * Math.PI * 2;
self.velocityX = Math.cos(angle) * self.speed;
self.velocityY = Math.sin(angle) * self.speed;
self.update = function () {
var elapsed = Date.now() - self.startTime;
// Check if power-up should be destroyed
if (elapsed >= self.lifeTime) {
self.destroy();
return;
}
// Move X2 powerup
self.x += self.velocityX;
self.y += self.velocityY;
// Bounce off walls
if (self.x <= 60 || self.x >= GAME_WIDTH - 60) {
self.velocityX = -self.velocityX;
self.x = Math.max(60, Math.min(GAME_WIDTH - 60, self.x));
}
if (self.y <= 60 || self.y >= GAME_HEIGHT - 60) {
self.velocityY = -self.velocityY;
self.y = Math.max(60, Math.min(GAME_HEIGHT - 60, self.y));
}
// Blinking effect in last 3 seconds
if (elapsed >= self.blinkStartTime) {
var blinkSpeed = 8; // Fast blinking
graphics.alpha = Math.abs(Math.sin(LK.ticks * blinkSpeed * 0.1)) > 0.5 ? 1.0 : 0.3;
} else {
graphics.alpha = 1.0;
}
};
return self;
});
/****
* Initialize Game
****/
var game = new LK.Game({
backgroundColor: 0x2a4a3a
});
/****
* Game Code
****/
var GRID_SIZE = 40;
var GAME_WIDTH = 2048;
var GAME_HEIGHT = 2732;
var COLS = Math.floor(GAME_WIDTH / GRID_SIZE);
var ROWS = Math.floor(GAME_HEIGHT / GRID_SIZE);
// Snake variables
var snake = [];
var snakeDirection = {
x: 1,
y: 0
};
var nextDirection = {
x: 1,
y: 0
};
var snakeSpeed = 8;
var moveCounter = 0;
var snakeThickness = 1;
// Fruit variables
var currentFruit = null;
var fruits = [];
// Growth points variables
var growthPoints = [];
var coconutPowerActive = false;
var coconutPowerEndTime = 0;
var lastGrowthPointSpawn = 0;
// Game state
var gameRunning = true;
var touchStartX = 0;
var touchStartY = 0;
// Autopilot variables
var autoPilotActive = false;
var autoPilotEndTime = 0;
var countdownText = null;
// Event system variables
var lastEventTime = 0;
var eventInterval = 30000; // 30 seconds
var activeSpikes = [];
var activeLavaAreas = [];
var lastX2EventTime = 0;
var x2EventInterval = 30000; // 30 seconds
var activeX2Powerups = [];
var x2MultiplierActive = false;
var x2MultiplierEndTime = 0;
// Boss battle variables
var gameStartTime = Date.now();
var bossWarningActive = false;
var bossWarningStartTime = 0;
var bossActive = false;
var bossDefeated = false;
var currentBoss = null;
var bossRocks = [];
var warningLights = [];
var bossHealthBar = null;
var bossHealthBarBg = null;
// Reset missions storage at game start
storage.fruitsEaten = 0;
storage.fruitsCompleted = false;
storage.pointsScored = 0;
storage.pointsCompleted = false;
storage.bossKilled = 0;
storage.bossCompleted = false;
storage.eventsLived = 0;
storage.eventsCompleted = false;
// Missions system variables
var missions = {
fruitsEaten: {
target: 5,
current: 0,
completed: false
},
pointsScored: {
target: 300,
current: 0,
completed: false
},
bossKilled: {
target: 1,
current: 0,
completed: false
},
eventsLived: {
target: 4,
current: 0,
completed: false
}
};
var missionsTable = null;
var eventsCounter = 0;
// Crown drop variable
var crownDrop = null;
// Enemy snake variable
var activeEnemySnake = null;
// Bird boss variables
var birdBossActive = false;
var birdBossDefeated = false;
var currentBirdBoss = null;
var birdBossStartTime = 0;
var purpleSnakeActive = false;
var currentPurpleSnake = null;
var purpleSnakeSpawnTime = 0;
// Timer display
var timerTxt = new Text2('Time: 00:00', {
size: 50,
fill: 0xFFFFFF
});
timerTxt.anchor.set(0.5, 0);
timerTxt.x = 0;
timerTxt.y = 20;
LK.gui.top.addChild(timerTxt);
// Next event display
var nextEventTxt = new Text2('Next Event: Spike/Lava in 30s', {
size: 40,
fill: 0xFFFF00
});
nextEventTxt.anchor.set(0.5, 0);
nextEventTxt.x = 0;
nextEventTxt.y = 80;
LK.gui.top.addChild(nextEventTxt);
// Score display
var scoreTxt = new Text2('Score: 0', {
size: 60,
fill: 0xFFFFFF
});
scoreTxt.anchor.set(0, 0);
scoreTxt.x = 120;
scoreTxt.y = 20;
LK.gui.topLeft.addChild(scoreTxt);
// Power-up display
var powerTxt = new Text2('Speed: 1x | Thickness: 1x', {
size: 40,
fill: 0xFFFF00
});
powerTxt.anchor.set(1, 0);
powerTxt.x = -20;
powerTxt.y = 20;
LK.gui.topRight.addChild(powerTxt);
// Boss health bar (initially hidden)
bossHealthBarBg = new LK.getAsset('healthBarBg', {
anchorX: 0.5,
anchorY: 0
});
bossHealthBarBg.x = GAME_WIDTH / 2;
bossHealthBarBg.y = 100;
bossHealthBarBg.visible = false;
game.addChild(bossHealthBarBg);
bossHealthBar = new LK.getAsset('healthBar', {
anchorX: 0.5,
anchorY: 0
});
bossHealthBar.x = GAME_WIDTH / 2;
bossHealthBar.y = 100;
bossHealthBar.visible = false;
game.addChild(bossHealthBar);
// Create missions table
missionsTable = new Text2('MISSIONS:\n' + '• Eat 5 fruits: 0/5\n' + '• Score 300 points: 0/300\n' + '• Kill the boss: 0/1\n' + '• Survive 4 events: 0/4', {
size: 35,
fill: 0xFFFFFF
});
missionsTable.anchor.set(0, 0);
missionsTable.x = 20;
missionsTable.y = 120;
LK.gui.topLeft.addChild(missionsTable);
// Create walls
var topWall = game.addChild(LK.getAsset('wall', {
x: 0,
y: 0,
width: GAME_WIDTH,
height: 20
}));
var bottomWall = game.addChild(LK.getAsset('wall', {
x: 0,
y: GAME_HEIGHT - 20,
width: GAME_WIDTH,
height: 20
}));
var leftWall = game.addChild(LK.getAsset('wall', {
x: 0,
y: 0,
width: 20,
height: GAME_HEIGHT
}));
var rightWall = game.addChild(LK.getAsset('wall', {
x: GAME_WIDTH - 20,
y: 0,
width: 20,
height: GAME_HEIGHT
}));
// Initialize snake
function initSnake() {
// Create initial snake with 3 segments
var startX = Math.floor(COLS / 4);
var startY = Math.floor(ROWS / 2);
for (var i = 0; i < 3; i++) {
var segment;
if (i === 0) {
segment = new SnakeHead();
} else {
segment = new SnakeSegment();
}
segment.gridX = startX - i;
segment.gridY = startY;
segment.x = segment.gridX * GRID_SIZE + GRID_SIZE / 2;
segment.y = segment.gridY * GRID_SIZE + GRID_SIZE / 2;
snake.push(segment);
game.addChild(segment);
}
}
// Spawn growth point
function spawnGrowthPoint() {
// Only spawn if no growth points exist OR coconut power is active
if (growthPoints.length > 0 && !coconutPowerActive) {
return;
}
var validPosition = false;
var gridX, gridY;
while (!validPosition) {
gridX = Math.floor(Math.random() * (COLS - 4)) + 2;
gridY = Math.floor(Math.random() * (ROWS - 4)) + 2;
validPosition = true;
// Check snake collision
for (var i = 0; i < snake.length; i++) {
if (snake[i].gridX === gridX && snake[i].gridY === gridY) {
validPosition = false;
break;
}
}
// Check fruit collision
if (currentFruit && currentFruit.gridX === gridX && currentFruit.gridY === gridY) {
validPosition = false;
}
// Check other growth points collision
for (var i = 0; i < growthPoints.length; i++) {
if (growthPoints[i].gridX === gridX && growthPoints[i].gridY === gridY) {
validPosition = false;
break;
}
}
// Avoid lava areas
var worldX = gridX * GRID_SIZE + GRID_SIZE / 2;
var worldY = gridY * GRID_SIZE + GRID_SIZE / 2;
for (var l = 0; l < activeLavaAreas.length; l++) {
var lavaArea = activeLavaAreas[l];
if (worldX >= lavaArea.x && worldX <= lavaArea.x + 1024 && worldY >= lavaArea.y && worldY <= lavaArea.y + 1366) {
validPosition = false;
break;
}
}
}
var growthPoint = new GrowthPoint();
growthPoint.gridX = gridX;
growthPoint.gridY = gridY;
growthPoint.x = gridX * GRID_SIZE + GRID_SIZE / 2;
growthPoint.y = gridY * GRID_SIZE + GRID_SIZE / 2;
growthPoints.push(growthPoint);
game.addChild(growthPoint);
}
// Spawn fruit
function spawnFruit() {
if (currentFruit) {
currentFruit.destroy();
currentFruit = null;
}
var fruitTypes = ['apple', 'pear', 'banana', 'multicolor', 'coconut', 'orange'];
var randomType = fruitTypes[Math.floor(Math.random() * fruitTypes.length)];
var validPosition = false;
var gridX, gridY;
while (!validPosition) {
gridX = Math.floor(Math.random() * (COLS - 4)) + 2;
gridY = Math.floor(Math.random() * (ROWS - 4)) + 2;
validPosition = true;
for (var i = 0; i < snake.length; i++) {
if (snake[i].gridX === gridX && snake[i].gridY === gridY) {
validPosition = false;
break;
}
}
// Avoid lava areas
var worldX = gridX * GRID_SIZE + GRID_SIZE / 2;
var worldY = gridY * GRID_SIZE + GRID_SIZE / 2;
for (var l = 0; l < activeLavaAreas.length; l++) {
var lavaArea = activeLavaAreas[l];
if (worldX >= lavaArea.x && worldX <= lavaArea.x + 1024 && worldY >= lavaArea.y && worldY <= lavaArea.y + 1366) {
validPosition = false;
break;
}
}
}
currentFruit = new Fruit(randomType);
currentFruit.gridX = gridX;
currentFruit.gridY = gridY;
currentFruit.x = gridX * GRID_SIZE + GRID_SIZE / 2;
currentFruit.y = gridY * GRID_SIZE + GRID_SIZE / 2;
game.addChild(currentFruit);
}
// Move snake
function moveSnake() {
if (!gameRunning) return;
var head = snake[0];
// Autopilot logic
if (autoPilotActive && (growthPoints.length > 0 || currentFruit)) {
// Function to check if a position is safe
var isSafePosition = function isSafePosition(gridX, gridY) {
// Check walls
if (gridX <= 0 || gridX >= COLS - 1 || gridY <= 0 || gridY >= ROWS - 1) {
return false;
}
// Check snake body collision
for (var i = 1; i < snake.length; i++) {
if (snake[i].gridX === gridX && snake[i].gridY === gridY) {
return false;
}
}
// In autopilot mode, avoid spikes and lava areas
if (autoPilotActive) {
var worldX = gridX * GRID_SIZE + GRID_SIZE / 2;
var worldY = gridY * GRID_SIZE + GRID_SIZE / 2;
// Check spike collisions
for (var s = 0; s < activeSpikes.length; s++) {
var spike = activeSpikes[s];
var spikeDistance = Math.sqrt(Math.pow(spike.x - worldX, 2) + Math.pow(spike.y - worldY, 2));
if (spikeDistance < 100) {
// Give extra buffer for autopilot
return false;
}
}
// Check lava area collisions
for (var l = 0; l < activeLavaAreas.length; l++) {
var lavaArea = activeLavaAreas[l];
if (!lavaArea.isWarning) {
// Only avoid active lava
if (worldX >= lavaArea.x - 40 && worldX <= lavaArea.x + 1024 + 40 && worldY >= lavaArea.y - 40 && worldY <= lavaArea.y + 1366 + 40) {
return false;
}
}
}
}
return true;
};
// Priority 1: Target growth points if available
var targetX, targetY;
if (growthPoints.length > 0) {
// Find closest growth point
var closestGrowthPoint = growthPoints[0];
var closestDistance = Math.abs(closestGrowthPoint.gridX - head.gridX) + Math.abs(closestGrowthPoint.gridY - head.gridY);
for (var g = 1; g < growthPoints.length; g++) {
var distance = Math.abs(growthPoints[g].gridX - head.gridX) + Math.abs(growthPoints[g].gridY - head.gridY);
if (distance < closestDistance) {
closestGrowthPoint = growthPoints[g];
closestDistance = distance;
}
}
targetX = closestGrowthPoint.gridX;
targetY = closestGrowthPoint.gridY;
} else {
// Priority 2: Target fruit if no growth points available
targetX = currentFruit.gridX;
targetY = currentFruit.gridY;
}
var deltaX = targetX - head.gridX;
var deltaY = targetY - head.gridY;
var possibleDirections = [];
var currentDirection = snakeDirection;
// Calculate potential moves towards fruit
if (Math.abs(deltaX) > Math.abs(deltaY)) {
// Prioritize horizontal movement
if (deltaX > 0) {
possibleDirections.push({
x: 1,
y: 0
}); // Right
} else if (deltaX < 0) {
possibleDirections.push({
x: -1,
y: 0
}); // Left
}
// Add vertical as backup
if (deltaY > 0) {
possibleDirections.push({
x: 0,
y: 1
}); // Down
} else if (deltaY < 0) {
possibleDirections.push({
x: 0,
y: -1
}); // Up
}
} else {
// Prioritize vertical movement
if (deltaY > 0) {
possibleDirections.push({
x: 0,
y: 1
}); // Down
} else if (deltaY < 0) {
possibleDirections.push({
x: 0,
y: -1
}); // Up
}
// Add horizontal as backup
if (deltaX > 0) {
possibleDirections.push({
x: 1,
y: 0
}); // Right
} else if (deltaX < 0) {
possibleDirections.push({
x: -1,
y: 0
}); // Left
}
}
// Add remaining directions as last resort
var allDirections = [{
x: 1,
y: 0
}, {
x: -1,
y: 0
}, {
x: 0,
y: 1
}, {
x: 0,
y: -1
}];
for (var i = 0; i < allDirections.length; i++) {
var dir = allDirections[i];
var found = false;
for (var j = 0; j < possibleDirections.length; j++) {
if (possibleDirections[j].x === dir.x && possibleDirections[j].y === dir.y) {
found = true;
break;
}
}
if (!found) {
possibleDirections.push(dir);
}
}
// Find first safe direction
var newDirection = currentDirection;
for (var i = 0; i < possibleDirections.length; i++) {
var testDir = possibleDirections[i];
// Don't reverse direction
if (testDir.x === -currentDirection.x && testDir.y === -currentDirection.y) {
continue;
}
var testX = head.gridX + testDir.x;
var testY = head.gridY + testDir.y;
if (isSafePosition(testX, testY)) {
newDirection = testDir;
break;
}
}
snakeDirection = newDirection;
nextDirection = snakeDirection;
}
var newGridX = head.gridX + snakeDirection.x;
var newGridY = head.gridY + snakeDirection.y;
// Check wall collision
if (newGridX <= 0 || newGridX >= COLS - 1 || newGridY <= 0 || newGridY >= ROWS - 1) {
gameOver();
return;
}
// Check self collision
for (var i = 0; i < snake.length; i++) {
if (snake[i].gridX === newGridX && snake[i].gridY === newGridY) {
gameOver();
return;
}
}
// Check fruit collision
var ateFood = false;
if (currentFruit && currentFruit.gridX === newGridX && currentFruit.gridY === newGridY) {
// Only apple makes snake grow, other fruits don't
ateFood = currentFruit.fruitType === 'apple';
handleFruitEaten(currentFruit.fruitType);
}
// Check growth point collision
for (var i = growthPoints.length - 1; i >= 0; i--) {
var growthPoint = growthPoints[i];
if (growthPoint.gridX === newGridX && growthPoint.gridY === newGridY) {
// Apply X2 multiplier for growth (ateFood effect)
if (x2MultiplierActive) {
ateFood = true; // X2 makes growth points also grow the snake
} else {
ateFood = true;
}
LK.getSound('eat').play();
// Apply X2 multiplier for score
var pointsToAdd = x2MultiplierActive ? 2 : 1;
LK.setScore(LK.getScore() + pointsToAdd);
scoreTxt.setText('Score: ' + LK.getScore());
growthPoint.destroy();
growthPoints.splice(i, 1);
break;
}
}
// Move snake
var newHead = new SnakeHead();
newHead.gridX = newGridX;
newHead.gridY = newGridY;
newHead.x = newGridX * GRID_SIZE + GRID_SIZE / 2;
newHead.y = newGridY * GRID_SIZE + GRID_SIZE / 2;
newHead.setThickness(snakeThickness);
// Convert old head to body
var oldHead = snake[0];
// Transfer crown status to new head
if (oldHead.hasCrown) {
newHead.showCrown();
}
// Transfer shield status to new head
if (oldHead.hasShield) {
oldHead.removeShield(); // Remove from old head first
newHead.activateShield(); // Add to new head
}
oldHead.destroy();
var newBody = new SnakeSegment();
newBody.gridX = oldHead.gridX;
newBody.gridY = oldHead.gridY;
newBody.x = oldHead.x;
newBody.y = oldHead.y;
newBody.setThickness(snakeThickness);
game.addChild(newBody);
snake[0] = newBody;
// Add new head
snake.unshift(newHead);
game.addChild(newHead);
if (!ateFood) {
// Remove tail
var tail = snake.pop();
tail.destroy();
}
// Update thickness for all segments
for (var i = 0; i < snake.length; i++) {
snake[i].setThickness(snakeThickness);
}
}
// Handle fruit eaten
function handleFruitEaten(fruitType) {
LK.getSound('eat').play();
// All fruits give 5 points (apply X2 multiplier if active)
var pointsToAdd = x2MultiplierActive ? 10 : 5;
LK.setScore(LK.getScore() + pointsToAdd);
if (fruitType === 'apple') {
// Apple: makes snake grow (ateFood stays true)
LK.getSound('powerup').play();
} else if (fruitType === 'pear') {
snakeThickness += 0.2;
LK.getSound('powerup').play();
} else if (fruitType === 'banana') {
snakeSpeed += 1;
LK.getSound('powerup').play();
} else if (fruitType === 'multicolor') {
// Activate autopilot for 10 seconds
autoPilotActive = true;
autoPilotEndTime = Date.now() + 10000;
LK.getSound('powerup').play();
// Clean up any existing countdown
if (countdownText) {
countdownText.destroy();
countdownText = null;
}
// Show autopilot activation feedback
LK.effects.flashScreen(0x00ff00, 500);
} else if (fruitType === 'coconut') {
// Activate coconut power for 10 seconds - allows multiple growth points
coconutPowerActive = true;
coconutPowerEndTime = Date.now() + 10000;
lastGrowthPointSpawn = Date.now();
LK.getSound('powerup').play();
// Show coconut power activation feedback
LK.effects.flashScreen(0xffffff, 500);
} else if (fruitType === 'orange') {
// Activate shield for one-time protection
var head = snake[0];
head.activateShield();
LK.getSound('powerup').play();
// Show orange power activation feedback
LK.effects.flashScreen(0xff8800, 500);
}
scoreTxt.setText('Score: ' + LK.getScore());
powerTxt.setText('Speed: ' + snakeSpeed + 'x | Thickness: ' + Math.round(snakeThickness * 10) / 10 + 'x');
// Update missions - fruits eaten
if (!missions.fruitsEaten.completed) {
missions.fruitsEaten.current++;
storage.fruitsEaten = missions.fruitsEaten.current;
if (missions.fruitsEaten.current >= missions.fruitsEaten.target) {
missions.fruitsEaten.completed = true;
storage.fruitsCompleted = true;
}
}
// Update missions - points scored
if (!missions.pointsScored.completed && LK.getScore() >= missions.pointsScored.target) {
missions.pointsScored.current = LK.getScore();
missions.pointsScored.completed = true;
storage.pointsScored = missions.pointsScored.current;
storage.pointsCompleted = true;
}
updateMissionsDisplay();
currentFruit.destroy();
currentFruit = null;
spawnFruit();
}
// Update missions display
function updateMissionsDisplay() {
if (missionsTable) {
missionsTable.setText('MISSIONS:\n' + '• Eat 5 fruits: ' + missions.fruitsEaten.current + '/' + missions.fruitsEaten.target + (missions.fruitsEaten.completed ? ' ✓' : '') + '\n' + '• Score 300 points: ' + Math.min(missions.pointsScored.current, LK.getScore()) + '/' + missions.pointsScored.target + (missions.pointsScored.completed ? ' ✓' : '') + '\n' + '• Kill the boss: ' + missions.bossKilled.current + '/' + missions.bossKilled.target + (missions.bossKilled.completed ? ' ✓' : '') + '\n' + '• Survive 4 events: ' + missions.eventsLived.current + '/' + missions.eventsLived.target + (missions.eventsLived.completed ? ' ✓' : ''));
}
}
// Spawn X2 event
function spawnX2Event() {
// 50% probability check - only spawn X2 powerup half the time
if (Math.random() < 0.5) {
// Clear any existing X2 powerups
for (var i = activeX2Powerups.length - 1; i >= 0; i--) {
activeX2Powerups[i].destroy();
}
activeX2Powerups = [];
// Spawn X2 powerup at random location
var x2Powerup = new X2Powerup();
x2Powerup.x = Math.random() * (GAME_WIDTH - 200) + 100;
x2Powerup.y = Math.random() * (GAME_HEIGHT - 200) + 100;
activeX2Powerups.push(x2Powerup);
game.addChild(x2Powerup);
}
}
// Spawn random event
function spawnEvent() {
// Clear any existing events first to ensure only one event at a time
for (var i = activeSpikes.length - 1; i >= 0; i--) {
activeSpikes[i].destroy();
}
activeSpikes = [];
for (var i = activeLavaAreas.length - 1; i >= 0; i--) {
activeLavaAreas[i].destroy();
}
activeLavaAreas = [];
// Clear enemy snake if active
if (activeEnemySnake) {
activeEnemySnake.destroy();
activeEnemySnake = null;
}
// Update events survived mission
eventsCounter++;
if (!missions.eventsLived.completed) {
missions.eventsLived.current = eventsCounter;
storage.eventsLived = missions.eventsLived.current;
if (missions.eventsLived.current >= missions.eventsLived.target) {
missions.eventsLived.completed = true;
storage.eventsCompleted = true;
}
updateMissionsDisplay();
}
var eventType = Math.random();
if (eventType < 0.33) {
// Spawn bouncing spike
var spike = new Spike();
spike.x = Math.random() * (GAME_WIDTH - 100) + 50;
spike.y = Math.random() * (GAME_HEIGHT - 100) + 50;
activeSpikes.push(spike);
game.addChild(spike);
} else if (eventType < 0.66) {
// Spawn lava area in one quarter of the screen
var lavaArea = new LavaArea();
var quarter = Math.floor(Math.random() * 4);
switch (quarter) {
case 0:
// Top-left
lavaArea.x = 20;
lavaArea.y = 20;
break;
case 1:
// Top-right
lavaArea.x = GAME_WIDTH / 2;
lavaArea.y = 20;
break;
case 2:
// Bottom-left
lavaArea.x = 20;
lavaArea.y = GAME_HEIGHT / 2;
break;
case 3:
// Bottom-right
lavaArea.x = GAME_WIDTH / 2;
lavaArea.y = GAME_HEIGHT / 2;
break;
}
activeLavaAreas.push(lavaArea);
game.addChild(lavaArea);
LK.getSound('lava_warning').play();
} else {
// Spawn enemy snake
activeEnemySnake = new EnemySnake();
// Spawn on opposite side from player
var head = snake[0];
var spawnX, spawnY;
if (head.gridX < COLS / 2) {
spawnX = Math.floor(COLS * 0.75);
} else {
spawnX = Math.floor(COLS * 0.25);
}
if (head.gridY < ROWS / 2) {
spawnY = Math.floor(ROWS * 0.75);
} else {
spawnY = Math.floor(ROWS * 0.25);
}
activeEnemySnake.gridX = spawnX;
activeEnemySnake.gridY = spawnY;
activeEnemySnake.x = spawnX * GRID_SIZE + GRID_SIZE / 2;
activeEnemySnake.y = spawnY * GRID_SIZE + GRID_SIZE / 2;
game.addChild(activeEnemySnake);
}
}
// Game over
function gameOver() {
gameRunning = false;
LK.showGameOver();
}
// Touch controls
game.down = function (x, y, obj) {
touchStartX = x;
touchStartY = y;
};
game.up = function (x, y, obj) {
if (!gameRunning) return;
var deltaX = x - touchStartX;
var deltaY = y - touchStartY;
var minSwipeDistance = 50;
if (Math.abs(deltaX) > minSwipeDistance || Math.abs(deltaY) > minSwipeDistance) {
if (Math.abs(deltaX) > Math.abs(deltaY)) {
// Horizontal swipe
if (deltaX > 0 && snakeDirection.x !== -1) {
nextDirection = {
x: 1,
y: 0
}; // Right
} else if (deltaX < 0 && snakeDirection.x !== 1) {
nextDirection = {
x: -1,
y: 0
}; // Left
}
} else {
// Vertical swipe
if (deltaY > 0 && snakeDirection.y !== -1) {
nextDirection = {
x: 0,
y: 1
}; // Down
} else if (deltaY < 0 && snakeDirection.y !== 1) {
nextDirection = {
x: 0,
y: -1
}; // Up
}
}
}
};
// Initialize game
initSnake();
spawnFruit();
// Spawn initial growth points
for (var i = 0; i < 3; i++) {
spawnGrowthPoint();
}
// Main game loop
game.update = function () {
if (!gameRunning) return;
moveCounter++;
// Update timer display
var gameElapsed = Date.now() - gameStartTime;
var minutes = Math.floor(gameElapsed / 60000);
var seconds = Math.floor(gameElapsed % 60000 / 1000);
var timeString = (minutes < 10 ? '0' : '') + minutes + ':' + (seconds < 10 ? '0' : '') + seconds;
timerTxt.setText('Time: ' + timeString);
// Update next event display
var currentTime = Date.now();
if (birdBossActive && purpleSnakeActive) {
nextEventTxt.setText('Purple Snake is capturing the Bird!');
} else if (birdBossActive && !purpleSnakeActive) {
var timeUntilPurple = Math.max(0, 60000 - (currentTime - birdBossStartTime));
var purpleSecondsLeft = Math.ceil(timeUntilPurple / 1000);
nextEventTxt.setText('Purple Snake arrives in ' + purpleSecondsLeft + 's');
} else if (!birdBossActive && !birdBossDefeated) {
var timeUntilBird = Math.max(0, 30000 - (currentTime - gameStartTime));
var birdSecondsLeft = Math.ceil(timeUntilBird / 1000);
nextEventTxt.setText('Bird Boss arrives in ' + birdSecondsLeft + 's');
} else if (!bossActive) {
// Calculate time until next regular event
var timeUntilEvent = Math.max(0, eventInterval - (currentTime - lastEventTime));
var eventSecondsLeft = Math.ceil(timeUntilEvent / 1000);
// Calculate time until next X2 event
var timeUntilX2 = Math.max(0, x2EventInterval - (currentTime - lastX2EventTime));
var x2SecondsLeft = Math.ceil(timeUntilX2 / 1000);
// Show the next event that will happen first
if (timeUntilEvent <= timeUntilX2) {
nextEventTxt.setText('Next Event: Spike/Lava/Enemy in ' + eventSecondsLeft + 's');
} else {
nextEventTxt.setText('Next Event: X2 Power in ' + x2SecondsLeft + 's');
}
} else if (bossWarningActive) {
nextEventTxt.setText('Next Event: BOSS INCOMING!');
} else if (bossActive) {
nextEventTxt.setText('Next Event: BOSS BATTLE!');
} else {
nextEventTxt.setText('Next Event: Boss defeated');
}
// Handle autopilot countdown
if (autoPilotActive) {
var timeLeft = autoPilotEndTime - Date.now();
if (timeLeft <= 0) {
autoPilotActive = false;
if (countdownText) {
countdownText.destroy();
countdownText = null;
}
} else if (timeLeft <= 3000 && !countdownText) {
// Show countdown when 3 seconds left
countdownText = new Text2('3', {
size: 120,
fill: 0xFF0000
});
countdownText.anchor.set(0.5, 0.5);
LK.gui.center.addChild(countdownText);
}
// Update countdown text
if (countdownText) {
var secondsLeft = Math.ceil(timeLeft / 1000);
if (secondsLeft > 0) {
countdownText.setText(secondsLeft.toString());
// Animate countdown
tween(countdownText, {
scaleX: 1.2,
scaleY: 1.2
}, {
duration: 200,
easing: tween.easeOut,
onFinish: function onFinish() {
if (countdownText) {
tween(countdownText, {
scaleX: 1,
scaleY: 1
}, {
duration: 200,
easing: tween.easeIn
});
}
}
});
} else {
countdownText.destroy();
countdownText = null;
}
}
}
// Update direction (only if not in autopilot)
if (!autoPilotActive) {
snakeDirection = nextDirection;
}
// Event spawning timer - only spawn events if boss is not active
var currentTime = Date.now();
if (!bossActive && currentTime - lastEventTime >= eventInterval) {
lastEventTime = currentTime;
spawnEvent();
}
// X2 event spawning timer - independent of regular events
if (!bossActive && currentTime - lastX2EventTime >= x2EventInterval) {
lastX2EventTime = currentTime;
spawnX2Event();
}
// Check spike collisions with snake (skip during autopilot)
if (!autoPilotActive) {
for (var i = activeSpikes.length - 1; i >= 0; i--) {
var spike = activeSpikes[i];
var head = snake[0];
// Check collision with snake head - adjust collision radius based on snake thickness
var distance = Math.sqrt(Math.pow(spike.x - head.x, 2) + Math.pow(spike.y - head.y, 2));
var collisionRadius = 60 * snakeThickness; // Scale collision radius with snake thickness
if (distance < collisionRadius) {
// Check if snake has shield protection
if (head.hasShield) {
// Remove shield and continue playing
head.removeShield();
LK.effects.flashScreen(0x87ceeb, 300);
// Push spike away or destroy it
spike.destroy();
activeSpikes.splice(i, 1);
continue;
}
// Check if snake has immunity after shield removal
if (head.immunityActive) {
continue; // Skip damage during immunity
}
// Increased collision area for larger spike
gameOver();
return;
}
}
}
// Check lava area collisions with snake (skip during autopilot)
if (!autoPilotActive) {
for (var i = activeLavaAreas.length - 1; i >= 0; i--) {
var lavaArea = activeLavaAreas[i];
// Only check collision if lava is active (not warning)
if (!lavaArea.isWarning) {
var head = snake[0];
// Check if snake head is inside lava area (larger quarter-screen area)
if (head.x >= lavaArea.x && head.x <= lavaArea.x + 1024 && head.y >= lavaArea.y && head.y <= lavaArea.y + 1366) {
// Check if snake has shield protection
if (head.hasShield) {
// Remove shield and continue playing
head.removeShield();
LK.effects.flashScreen(0x87ceeb, 300);
continue;
}
// Check if snake has immunity after shield removal
if (head.immunityActive) {
continue; // Skip damage during immunity
}
gameOver();
return;
}
}
}
}
// Handle coconut power and growth point spawning
var currentTime = Date.now();
if (coconutPowerActive) {
// Check if coconut power has expired
if (currentTime >= coconutPowerEndTime) {
coconutPowerActive = false;
}
// Spawn growth points every 2.5 seconds during coconut power
if (currentTime - lastGrowthPointSpawn >= 2500) {
spawnGrowthPoint();
lastGrowthPointSpawn = currentTime;
}
} else {
// Normal mode: spawn growth point only if none exist
if (growthPoints.length === 0) {
spawnGrowthPoint();
}
}
// Bird boss timing and logic
var timeSinceStart = Date.now() - gameStartTime;
// Start bird boss at 30 seconds
if (timeSinceStart >= 30000 && !birdBossActive && !birdBossDefeated) {
birdBossActive = true;
birdBossStartTime = Date.now();
// Spawn bird boss at top of screen
currentBirdBoss = new BirdBoss();
currentBirdBoss.x = GAME_WIDTH / 2;
currentBirdBoss.y = 100;
game.addChild(currentBirdBoss);
}
// Purple snake timing - 60 seconds after bird boss starts
if (birdBossActive && !purpleSnakeActive && Date.now() - birdBossStartTime >= 60000) {
purpleSnakeActive = true;
purpleSnakeSpawnTime = Date.now();
// Spawn purple snake at edge of screen
currentPurpleSnake = new PurpleSnake();
currentPurpleSnake.x = GAME_WIDTH - 100;
currentPurpleSnake.y = GAME_HEIGHT / 2;
game.addChild(currentPurpleSnake);
}
// Check if purple snake reaches bird boss (defeats bird boss)
if (birdBossActive && purpleSnakeActive && currentBirdBoss && currentPurpleSnake) {
var distance = Math.sqrt(Math.pow(currentPurpleSnake.x - currentBirdBoss.x, 2) + Math.pow(currentPurpleSnake.y - currentBirdBoss.y, 2));
if (distance < 150) {
// Purple snake captures bird boss
LK.effects.flashScreen(0x800080, 1000);
// Animate both flying away
tween(currentBirdBoss, {
x: currentBirdBoss.x,
y: -200
}, {
duration: 2000,
easing: tween.easeIn
});
tween(currentPurpleSnake, {
x: currentPurpleSnake.x,
y: -200
}, {
duration: 2000,
easing: tween.easeIn,
onFinish: function onFinish() {
if (currentBirdBoss && currentBirdBoss.parent) {
currentBirdBoss.destroy();
}
if (currentPurpleSnake && currentPurpleSnake.parent) {
currentPurpleSnake.destroy();
}
currentBirdBoss = null;
currentPurpleSnake = null;
}
});
birdBossActive = false;
birdBossDefeated = true;
purpleSnakeActive = false;
LK.setScore(LK.getScore() + 200);
scoreTxt.setText('Score: ' + LK.getScore());
}
}
// Boss battle timing and logic (disabled since bird boss is now first boss)
// Start boss warning at 60 seconds
if (false && timeSinceStart >= 60000 && !bossWarningActive && !bossActive && !bossDefeated) {
bossWarningActive = true;
bossWarningStartTime = Date.now();
// Create warning lights in a perfect circle around boss spawn location
var bossSpawnX = GAME_WIDTH / 2;
var bossSpawnY = GAME_HEIGHT / 2;
var circleRadius = 500; // Distance from boss spawn center
for (var i = 0; i < 12; i++) {
var light = new WarningLight();
var angle = i / 12 * Math.PI * 2;
light.x = bossSpawnX + Math.cos(angle) * circleRadius;
light.y = bossSpawnY + Math.sin(angle) * circleRadius;
warningLights.push(light);
game.addChild(light);
}
}
// End warning phase and spawn boss after 5 seconds
if (bossWarningActive && Date.now() - bossWarningStartTime >= 5000) {
bossWarningActive = false;
bossActive = true;
// Remove warning lights
for (var i = warningLights.length - 1; i >= 0; i--) {
warningLights[i].destroy();
}
warningLights = [];
// Clear all active events when boss spawns
for (var i = activeSpikes.length - 1; i >= 0; i--) {
activeSpikes[i].destroy();
}
activeSpikes = [];
for (var i = activeLavaAreas.length - 1; i >= 0; i--) {
activeLavaAreas[i].destroy();
}
activeLavaAreas = [];
// Spawn boss
currentBoss = new PotatoBoss();
currentBoss.x = GAME_WIDTH / 2;
currentBoss.y = GAME_HEIGHT / 2;
game.addChild(currentBoss);
// Show health bar
bossHealthBarBg.visible = true;
bossHealthBar.visible = true;
}
// Update boss health bar
if (bossActive && currentBoss) {
var healthPercentage = currentBoss.health / currentBoss.maxHealth;
bossHealthBar.scaleX = healthPercentage;
}
// Hide health bar when boss is defeated
if (bossDefeated) {
bossHealthBarBg.visible = false;
bossHealthBar.visible = false;
}
// Check boss rock collisions with snake
if (bossActive && !autoPilotActive) {
for (var i = bossRocks.length - 1; i >= 0; i--) {
var rock = bossRocks[i];
// Remove rocks that have been destroyed due to max bounces
if (!rock.parent) {
bossRocks.splice(i, 1);
continue;
}
var head = snake[0];
var distance = Math.sqrt(Math.pow(rock.x - head.x, 2) + Math.pow(rock.y - head.y, 2));
var collisionRadius = 70 * snakeThickness; // Scale collision radius with snake thickness
if (distance < collisionRadius) {
// Check if snake has shield protection
if (head.hasShield) {
// Remove shield and continue playing
head.removeShield();
LK.effects.flashScreen(0x87ceeb, 300);
// Destroy the rock
rock.destroy();
bossRocks.splice(i, 1);
continue;
}
// Check if snake has immunity after shield removal
if (head.immunityActive) {
// Destroy the rock but don't damage player
rock.destroy();
bossRocks.splice(i, 1);
continue;
}
gameOver();
return;
}
}
}
// Check boss rock collisions with boss (damage boss) - only after bouncing
if (bossActive && currentBoss) {
for (var i = bossRocks.length - 1; i >= 0; i--) {
var rock = bossRocks[i];
// Comprehensive null check for currentBoss before any property access
if (!currentBoss || !currentBoss.parent || currentBoss.x === undefined || currentBoss.y === undefined) {
continue;
}
var currentIntersectingBoss = Math.sqrt(Math.pow(rock.x - currentBoss.x, 2) + Math.pow(rock.y - currentBoss.y, 2)) < 190;
// Only damage boss if rock has bounced at least once and just started intersecting
if (rock.bounceCount > 0 && !rock.lastIntersectingBoss && currentIntersectingBoss) {
// Deal 25% damage (1.25 damage out of 5 total health)
var damage = Math.ceil(currentBoss.maxHealth * 0.25);
for (var d = 0; d < damage; d++) {
if (currentBoss.health > 0) {
currentBoss.takeDamage();
}
}
// Remove the rock
rock.destroy();
bossRocks.splice(i, 1);
continue;
}
// Update last intersecting state
rock.lastIntersectingBoss = currentIntersectingBoss;
}
}
// Check snake collision with boss (damage boss)
if (bossActive && currentBoss && !autoPilotActive) {
var head = snake[0];
var distance = Math.sqrt(Math.pow(currentBoss.x - head.x, 2) + Math.pow(currentBoss.y - head.y, 2));
var collisionRadius = 170 * snakeThickness; // Scale collision radius with snake thickness
if (distance < collisionRadius) {
currentBoss.takeDamage();
// Push snake away to prevent multiple hits
var pushAngle = Math.atan2(head.y - currentBoss.y, head.x - currentBoss.x);
var pushDistance = 150 * snakeThickness; // Scale push distance with snake thickness
var newX = currentBoss.x + Math.cos(pushAngle) * pushDistance;
var newY = currentBoss.y + Math.sin(pushAngle) * pushDistance;
// Convert to grid position
var gridX = Math.round(newX / GRID_SIZE);
var gridY = Math.round(newY / GRID_SIZE);
// Ensure within bounds
gridX = Math.max(1, Math.min(COLS - 2, gridX));
gridY = Math.max(1, Math.min(ROWS - 2, gridY));
head.gridX = gridX;
head.gridY = gridY;
head.x = gridX * GRID_SIZE + GRID_SIZE / 2;
head.y = gridY * GRID_SIZE + GRID_SIZE / 2;
}
}
// Check snake collision with bird boss
if (birdBossActive && currentBirdBoss && !autoPilotActive && !purpleSnakeActive) {
var head = snake[0];
var distance = Math.sqrt(Math.pow(currentBirdBoss.x - head.x, 2) + Math.pow(currentBirdBoss.y - head.y, 2));
var collisionRadius = 140 * snakeThickness;
if (distance < collisionRadius) {
// Check if snake has shield protection
if (head.hasShield) {
// Remove shield and continue playing
head.removeShield();
LK.effects.flashScreen(0x87ceeb, 300);
} else if (head.immunityActive) {
// Skip damage during immunity period
} else {
gameOver();
return;
}
}
}
// Update points mission continuously
if (!missions.pointsScored.completed) {
missions.pointsScored.current = LK.getScore();
storage.pointsScored = missions.pointsScored.current;
if (missions.pointsScored.current >= missions.pointsScored.target) {
missions.pointsScored.completed = true;
storage.pointsCompleted = true;
updateMissionsDisplay();
}
}
// Check X2 powerup collision
if (activeX2Powerups.length > 0 && snake.length > 0) {
var head = snake[0];
for (var i = activeX2Powerups.length - 1; i >= 0; i--) {
var x2Powerup = activeX2Powerups[i];
var distance = Math.sqrt(Math.pow(x2Powerup.x - head.x, 2) + Math.pow(x2Powerup.y - head.y, 2));
var collisionRadius = 80 * snakeThickness; // Scale collision radius with snake thickness
if (distance < collisionRadius) {
// X2 powerup collected
x2MultiplierActive = true;
x2MultiplierEndTime = Date.now() + 10000; // 10 seconds
LK.getSound('powerup').play();
LK.effects.flashScreen(0xff0000, 500);
x2Powerup.destroy();
activeX2Powerups.splice(i, 1);
break;
}
}
}
// Handle X2 multiplier expiration
if (x2MultiplierActive && Date.now() >= x2MultiplierEndTime) {
x2MultiplierActive = false;
}
// Check enemy snake collision with player
if (activeEnemySnake && snake.length > 0 && !autoPilotActive) {
var head = snake[0];
var headDistance = Math.sqrt(Math.pow(activeEnemySnake.x - head.x, 2) + Math.pow(activeEnemySnake.y - head.y, 2));
var collisionRadius = 50 * snakeThickness;
// Check collision with enemy snake head
if (headDistance < collisionRadius) {
// Check if snake has shield protection
if (head.hasShield) {
// Remove shield and continue playing
head.removeShield();
LK.effects.flashScreen(0x87ceeb, 300);
} else if (head.immunityActive) {
// Skip damage during immunity period
} else {
gameOver();
return;
}
}
// Check collision with enemy snake body segments
for (var i = 0; i < activeEnemySnake.segments.length; i++) {
var segment = activeEnemySnake.segments[i];
var segmentDistance = Math.sqrt(Math.pow(segment.x - head.x, 2) + Math.pow(segment.y - head.y, 2));
if (segmentDistance < collisionRadius) {
// Check if snake has shield protection
if (head.hasShield) {
// Remove shield and continue playing
head.removeShield();
LK.effects.flashScreen(0x87ceeb, 300);
break;
} else if (head.immunityActive) {
// Skip damage during immunity period
break;
} else {
gameOver();
return;
}
}
}
}
// Check crown drop collision
if (crownDrop && snake.length > 0) {
var head = snake[0];
var distance = Math.sqrt(Math.pow(crownDrop.x - head.x, 2) + Math.pow(crownDrop.y - head.y, 2));
var collisionRadius = 80 * snakeThickness; // Scale collision radius with snake thickness
if (distance < collisionRadius) {
// Crown collected
LK.setScore(LK.getScore() + 50);
scoreTxt.setText('Score: ' + LK.getScore());
LK.getSound('powerup').play();
// Show crown on snake head
head.showCrown();
crownDrop.destroy();
crownDrop = null;
}
}
// Check if all missions are completed for win condition
if (missions.fruitsEaten.completed && missions.pointsScored.completed && missions.bossKilled.completed && missions.eventsLived.completed) {
LK.showYouWin();
return;
}
// Move snake based on speed
var moveInterval = Math.max(3, 15 - snakeSpeed);
if (moveCounter >= moveInterval) {
moveCounter = 0;
moveSnake();
}
}; ===================================================================
--- original.js
+++ change.js
@@ -617,11 +617,11 @@
tween.stop(shield);
shield.scaleX = 1;
shield.scaleY = 1;
}
- // Activate 3 seconds of immunity after shield removal
+ // Activate 4 seconds of immunity after shield removal
self.immunityActive = true;
- self.immunityEndTime = Date.now() + 3000; // 3 seconds immunity
+ self.immunityEndTime = Date.now() + 4000; // 4 seconds immunity
};
self.update = function () {
// Check immunity expiration
if (self.immunityActive && Date.now() >= self.immunityEndTime) {
cabeza de serpiente morada con x en los ojos. In-Game asset. High contrast. No shadows. 2d draw, kid draw, simple, minimalistic
apple. In-Game asset. High contrast. minimalistic
banana. In-Game asset. 2d. High contrast. No shadows
angry blue bird. no shadow. cartoon. simple. minimalisitc. animated
crown. In-Game asset. 2d. No shadows. cartoon. animate. simple
snake head. In-Game asset. 2d. No shadows. cartoon. animated. simple. funny
spike block with an angry face. In-Game asset. 2d. High contrast. No shadows. cartoon
X2 signal. In-Game asset. 2d. No shadows. cartoon. simple
orange fruit. In-Game asset. 2d. High contrast. No shadows. cartoon. simple. minimalistic
coconout. In-Game asset. 2d. High contrast. No shadows. cartoon
circular green rough skin. In-Game asset. 2d. High contrast. No shadows. cartoon. comic. drawed
pear fruit. In-Game asset. 2d. High contrast. No shadows. animated. cartoon
eyebrow. In-Game asset. 2d. High contrast. No shadows. comic. cartoon
rock. In-Game asset. 2d. High contrast. No shadows. cartoon
orbe de luz. In-Game asset. 2d. High contrast. No shadows
potato. In-Game asset. 2d. High contrast. No shadows. cartoon
baby rat sprite. In-Game asset. 2d. High contrast. No shadows. cartoonm. animated
purple circle of rough skin. In-Game asset. 2d. High contrast. No shadows. animated. comic. cartoon
blue sfere, ball, slime, translucent,. In-Game asset. 2d. High contrast. No shadows. cartoon. simple. draw
rock line. In-Game asset. 2d. High contrast. No shadows. long. cartoon
fire block background. In-Game asset. 2d. High contrast. No shadows. cartoon. draw