User prompt
Al perder el modo gatito, volver a hacer visible el rango de los guardias
User prompt
As que la hitbox de arresto del guardia sea más pequeño que el rango de detección
User prompt
Al alertar a un guardia que el guardia no haga daño por 1 segundo y luego si sea ostil ↪💡 Consider importing and using the following plugins: @upit/tween.v1
User prompt
Mostrar el rango de detección de los guardias con una textura como aura ↪💡 Consider importing and using the following plugins: @upit/tween.v1
User prompt
Al entrar en modo gatito las físicas de la roca lunar se bloquean por las coliciones , arreglarlo por favor
User prompt
El jugador al detenerse siempre mira a la derecha, arreglarlo por favor
User prompt
Desactiva la piedra dorada
User prompt
Al caer una piedra lunar, dejar un rastro azul brillante ↪💡 Consider importing and using the following plugins: @upit/tween.v1
User prompt
Al caer una piedra lunar , que deje un pequeño rastro de brillo ↪💡 Consider importing and using the following plugins: @upit/tween.v1
User prompt
Si estás en modo gigante no podrás obtener piedras lunares
User prompt
Si el modo gigante está activo, no podrá obtenerse el modo gatito
User prompt
Si el modo gatito está activo, no podrá activarse ni acumularse ningún otro modo al igual que el modo gigante
User prompt
Que la piedra lunar dorada aparezca cada 30 segundos
User prompt
Poner las texturas del modo gatito al modo gigante
User prompt
Al entrar en modo gigante los guardias no harán daño
User prompt
Al entrar en modo gigante, desactiva el límite de tamaño
User prompt
Que el efecto de modo gigante aumente el límite de tamaño
User prompt
Crea una nueva roca luna dorada, que aparezca cada 20 segundos , que haga lo mismo que el modo gatito pero que en vez de hacer al jugador pequeño su tamaño se multiplique x10 ↪💡 Consider importing and using the following plugins: @upit/tween.v1
User prompt
Agrega texturas de caminata al modo gatito ↪💡 Consider importing and using the following plugins: @upit/tween.v1
User prompt
Al cambiar de fase las texturas se duplican, solucionalo por favor
User prompt
Volver a la textura de quieto cuando el jugador no se mueve ↪💡 Consider importing and using the following plugins: @upit/tween.v1
User prompt
Agrega una segunda textura al jugador de cada fase, y cambia cuando camines ↪💡 Consider importing and using the following plugins: @upit/tween.v1
User prompt
Agrega dos tipos de textura de árbol, una la clásica, y la otra la nueva
User prompt
Que las piedras estén por debajo de los guardias
User prompt
Reduce el aumento de tamaño del jugador al obtener una piedra lunar ↪💡 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 Dog = Container.expand(function () {
var self = Container.call(this);
self.speed = 2.5;
self.chaseSpeed = 5;
self.detectionRadius = 300;
self.isChasing = false;
self.trailFollowDistance = 150;
self.alertRadius = 400;
self.hasAlertedGuards = false;
self.isResting = false;
self.restTimer = 0;
self.restDuration = 300; // 5 seconds at 60fps
self.chaseTimer = 0;
self.chaseDuration = 180; // 3 seconds at 60fps
self.stopTimer = 0;
self.stopDuration = 120; // 2 seconds at 60fps
self.isStopped = false;
self.isInKittenMode = false;
self.normalSpeed = self.speed;
self.normalChaseSpeed = self.chaseSpeed;
var dogGraphics = self.attachAsset('dog_normal', {
anchorX: 0.5,
anchorY: 0.5,
alpha: 0.7
});
self.update = function () {
// Handle kitten mode changes
if (isKittenMode && !self.isInKittenMode) {
// Entering kitten mode - multiply speed and change to run texture
self.isInKittenMode = true;
self.speed = self.normalSpeed * 2;
self.chaseSpeed = self.normalChaseSpeed * 2;
// Change to run texture
self.removeChild(dogGraphics);
dogGraphics = self.attachAsset('dog_run', {
anchorX: 0.5,
anchorY: 0.5,
alpha: 0.7
});
self.addChild(dogGraphics);
} else if (!isKittenMode && self.isInKittenMode) {
// Exiting kitten mode - restore normal speed and texture
self.isInKittenMode = false;
self.speed = self.normalSpeed;
self.chaseSpeed = self.normalChaseSpeed;
// Change back to normal texture
self.removeChild(dogGraphics);
dogGraphics = self.attachAsset('dog_normal', {
anchorX: 0.5,
anchorY: 0.5,
alpha: 0.7
});
self.addChild(dogGraphics);
}
// Handle rest mode
if (self.isResting) {
self.restTimer++;
// Change to passive texture after 1 second (60 frames)
if (self.restTimer === 60) {
self.removeChild(dogGraphics);
dogGraphics = self.attachAsset('dog_rest', {
anchorX: 0.5,
anchorY: 0.5,
alpha: 0.5
});
self.addChild(dogGraphics);
}
if (self.restTimer >= self.restDuration) {
// Exit rest mode
self.isResting = false;
self.restTimer = 0;
self.hasAlertedGuards = false; // Reset so dog can alert again
// Change back to normal texture
self.removeChild(dogGraphics);
dogGraphics = self.attachAsset('dog_normal', {
anchorX: 0.5,
anchorY: 0.5,
alpha: 0.7
});
self.addChild(dogGraphics);
}
// Dog doesn't move or detect during rest mode
return;
}
// Check if player is in detection range and not in kitten mode
var dx = player.x - self.x;
var dy = player.y - self.y;
var distance = Math.sqrt(dx * dx + dy * dy);
var canDetectPlayer = distance < self.detectionRadius && !player.isHiding && !isKittenMode;
if (canDetectPlayer) {
if (!self.isChasing && !self.isStopped) {
// Start chasing
self.isChasing = true;
self.chaseTimer = 0;
self.hasAlertedGuards = false;
dogGraphics.tint = 0xFF4444; // Red when chasing
// Play dog alert sound when detecting player
LK.getSound('dog_alert').play();
}
// Handle chase duration
if (self.isChasing) {
self.chaseTimer++;
if (self.chaseTimer >= self.chaseDuration) {
// Stop chasing after 3 seconds and enter stop mode
self.isChasing = false;
self.isStopped = true;
self.stopTimer = 0;
dogGraphics.tint = 0xFFFFFF; // Remove red tint when stopping
}
}
// Handle stop duration
if (self.isStopped) {
self.stopTimer++;
if (self.stopTimer >= self.stopDuration) {
// End stop mode after 2 seconds
self.isStopped = false;
self.stopTimer = 0;
}
}
// Alert all guards when close enough during chase
if (self.isChasing && distance < self.alertRadius && !self.hasAlertedGuards) {
self.hasAlertedGuards = true;
// Alert all guards
for (var i = 0; i < guards.length; i++) {
var guard = guards[i];
if (!guard.isAlerted) {
guard.isAlerted = true;
guard.alertState = 'chase_player';
guard.chaseTimer = 0;
guard.alertSpeed = 6;
// Change guard to chase texture
var currentGraphics = guard.children[0];
guard.removeChild(currentGraphics);
var chaseGraphics = guard.attachAsset('guard_chase', {
anchorX: 0.5,
anchorY: 0.5,
alpha: 0.5
});
guard.addChild(chaseGraphics);
}
}
// Enter rest mode for 5 seconds after alerting guards
self.isResting = true;
self.restTimer = 0;
// Change to rest texture
self.removeChild(dogGraphics);
dogGraphics = self.attachAsset('dog_rest', {
anchorX: 0.5,
anchorY: 0.5,
alpha: 0.3
});
self.addChild(dogGraphics);
}
// Chase player directly only if chasing and not stopped
if (self.isChasing && !self.isStopped) {
var angle = Math.atan2(dy, dx);
self.x += Math.cos(angle) * self.chaseSpeed;
self.y += Math.sin(angle) * self.chaseSpeed;
}
} else if (self.isChasing && distance > self.detectionRadius * 1.5) {
// Stop chasing if player gets too far
self.isChasing = false;
self.isStopped = false;
self.chaseTimer = 0;
self.stopTimer = 0;
self.hasAlertedGuards = false;
dogGraphics.tint = 0xFFFFFF; // Remove tint when not chasing
} else if (!self.isChasing && !self.isStopped) {
// Follow player trail when not actively chasing and not stopped
var trailDistance = Math.sqrt(dx * dx + dy * dy);
if (trailDistance > self.trailFollowDistance) {
var angle = Math.atan2(dy, dx);
self.x += Math.cos(angle) * self.speed;
self.y += Math.sin(angle) * self.speed;
}
}
// Keep dog within bounds
if (self.x < 100) self.x = 100;
if (self.x > 1948) self.x = 1948;
if (self.y < 100) self.y = 100;
if (self.y > 2632) self.y = 2632;
// Update dog flip based on movement direction
if (dx > 0) {
dogGraphics.scaleX = Math.abs(dogGraphics.scaleX);
} else {
dogGraphics.scaleX = -Math.abs(dogGraphics.scaleX);
}
};
return self;
});
var GoldenMoonRock = Container.expand(function () {
var self = Container.call(this);
var rockGraphics = self.attachAsset('golden_moon_rock', {
anchorX: 0.5,
anchorY: 0.5,
alpha: 0.9
});
rockGraphics.tint = 0xFFD700; // Golden color
self.moveTimer = 0;
self.moveDirection = Math.random() * Math.PI * 2;
self.speed = 1.5;
self.lifeTimer = 0;
self.maxLifetime = 1800; // 30 seconds at 60fps
self.update = function () {
// Golden glow animation - more intense than moonbeam
rockGraphics.alpha = 0.7 + Math.sin(LK.ticks * 0.2) * 0.3;
rockGraphics.scaleX = 1.2 + Math.sin(LK.ticks * 0.12) * 0.2;
rockGraphics.scaleY = 1.2 + Math.sin(LK.ticks * 0.12) * 0.2;
rockGraphics.rotation += 0.03;
// Slow random movement
self.moveTimer++;
if (self.moveTimer % 90 == 0) {
// Change direction every 1.5 seconds
self.moveDirection = Math.random() * Math.PI * 2;
}
self.x += Math.cos(self.moveDirection) * self.speed;
self.y += Math.sin(self.moveDirection) * self.speed;
// Keep within bounds
if (self.x < 80) {
self.x = 80;
self.moveDirection = Math.random() * Math.PI;
}
if (self.x > 1968) {
self.x = 1968;
self.moveDirection = Math.PI + Math.random() * Math.PI;
}
if (self.y < 80) {
self.y = 80;
self.moveDirection = Math.PI * 0.5 + Math.random() * Math.PI;
}
if (self.y > 2652) {
self.y = 2652;
self.moveDirection = Math.PI * 1.5 + Math.random() * Math.PI;
}
// Handle lifetime
self.lifeTimer++;
if (self.lifeTimer >= self.maxLifetime) {
// Fade out effect before disappearing
tween(rockGraphics, {
alpha: 0
}, {
duration: 1500,
onFinish: function onFinish() {
self.destroy();
// Remove from goldenMoonRocks array
for (var i = goldenMoonRocks.length - 1; i >= 0; i--) {
if (goldenMoonRocks[i] === self) {
goldenMoonRocks.splice(i, 1);
break;
}
}
}
});
}
};
return self;
});
var Guard = Container.expand(function () {
var self = Container.call(this);
self.patrolSpeed = 1.5;
self.alertSpeed = 4;
self.detectionRadius = 250;
self.isAlerted = false;
self.alertState = 'none'; // 'none', 'chase_player', 'move_to_moonstone'
self.chaseTimer = 0;
self.chaseDuration = 180; // 3 seconds at 60fps
self.patrolDirection = Math.random() * Math.PI * 2;
self.patrolTimer = 0;
self.lastInDetectionRange = false;
var guardGraphics = self.attachAsset('guard', {
anchorX: 0.5,
anchorY: 0.5,
alpha: 0.5
});
self.update = function () {
self.patrolTimer++;
// Check if player is in detection range and not hiding (and not in kitten mode)
var dx = player.x - self.x;
var dy = player.y - self.y;
var distance = Math.sqrt(dx * dx + dy * dy);
var currentInDetectionRange = distance < self.detectionRadius + player.detectionRadius && !player.isHiding && !isKittenMode;
if (currentInDetectionRange) {
// Check if player just entered detection range (transition from false to true)
if (!self.lastInDetectionRange && currentInDetectionRange) {
var guardSounds = ['stop', 'hey', 'dont_run'];
var randomSound = guardSounds[Math.floor(Math.random() * guardSounds.length)];
LK.getSound(randomSound).play();
// Double player speed when alerting a guard
player.speed *= 2;
// If "don't run" sound is played, alert 3 random guards
if (randomSound === 'dont_run') {
var availableGuards = [];
for (var i = 0; i < guards.length; i++) {
if (guards[i] !== self && !guards[i].isAlerted) {
availableGuards.push(guards[i]);
}
}
// Alert up to 3 random guards
var guardsToAlert = Math.min(3, availableGuards.length);
for (var j = 0; j < guardsToAlert; j++) {
var randomIndex = Math.floor(Math.random() * availableGuards.length);
var guardToAlert = availableGuards[randomIndex];
guardToAlert.isAlerted = true;
guardToAlert.alertState = 'move_to_moonstone';
guardToAlert.chaseTimer = 0;
guardToAlert.alertSpeed = 6; // Set increased speed for alerted guards
// Remove from available list to avoid double selection
availableGuards.splice(randomIndex, 1);
}
}
}
if (!self.isAlerted) {
// Start chasing - reset timer
self.chaseTimer = 0;
// Increase speed for chase mode
self.alertSpeed = 6; // Increased from 4
// Change to chase texture
self.removeChild(guardGraphics);
guardGraphics = self.attachAsset('guard_chase', {
anchorX: 0.5,
anchorY: 0.5,
alpha: 0.5
});
self.addChild(guardGraphics);
}
self.isAlerted = true;
self.alertState = 'chase_player';
guardGraphics.tint = 0xFF4444;
} else if (self.isAlerted) {
// Continue chasing for the duration even if player is out of range
self.chaseTimer++;
if (self.chaseTimer >= self.chaseDuration) {
self.isAlerted = false;
self.alertState = 'none';
guardGraphics.tint = 0xFFFFFF;
self.chaseTimer = 0;
// Reset speed to normal patrol speed
self.alertSpeed = 4; // Reset to original speed
// Revert to normal texture
self.removeChild(guardGraphics);
guardGraphics = self.attachAsset('guard', {
anchorX: 0.5,
anchorY: 0.5,
alpha: 0.5
});
self.addChild(guardGraphics);
}
} else {
guardGraphics.tint = 0xFFFFFF;
}
if (self.isAlerted) {
var targetX, targetY;
if (self.alertState === 'chase_player') {
// Target only player (bot disabled)
targetX = player.x;
targetY = player.y;
guardGraphics.tint = 0xFF4444; // Red tint for chasing player
} else if (self.alertState === 'move_to_moonstone') {
// Move towards moonstone drop position
targetX = lastMoonstoneDropX;
targetY = lastMoonstoneDropY;
guardGraphics.tint = 0x44FF44; // Green tint for moving to moonstone
} else {
// Default behavior (shouldn't happen when alerted)
targetX = player.x;
targetY = player.y;
}
var angle = Math.atan2(targetY - self.y, targetX - self.x);
self.x += Math.cos(angle) * self.alertSpeed;
self.y += Math.sin(angle) * self.alertSpeed;
} else {
// Patrol behavior
if (self.patrolTimer % 120 == 0) {
self.patrolDirection = Math.random() * Math.PI * 2;
}
self.x += Math.cos(self.patrolDirection) * self.patrolSpeed;
self.y += Math.sin(self.patrolDirection) * self.patrolSpeed;
// Keep guards within bounds
if (self.x < 100) {
self.x = 100;
self.patrolDirection = Math.random() * Math.PI;
}
if (self.x > 1948) {
self.x = 1948;
self.patrolDirection = Math.PI + Math.random() * Math.PI;
}
if (self.y < 100) {
self.y = 100;
self.patrolDirection = Math.PI * 0.5 + Math.random() * Math.PI;
}
if (self.y > 2632) {
self.y = 2632;
self.patrolDirection = Math.PI * 1.5 + Math.random() * Math.PI;
}
}
// Update guard flip based on movement direction
if (self.isAlerted) {
// In chase mode, flip based on direction to player
if (dx > 0) {
guardGraphics.scaleX = Math.abs(guardGraphics.scaleX); // Face right
} else {
guardGraphics.scaleX = -Math.abs(guardGraphics.scaleX); // Face left
}
} else {
// In patrol mode, flip based on patrol direction
var movementX = Math.cos(self.patrolDirection);
if (movementX > 0) {
guardGraphics.scaleX = Math.abs(guardGraphics.scaleX); // Face right
} else {
guardGraphics.scaleX = -Math.abs(guardGraphics.scaleX); // Face left
}
}
// Update last detection state
self.lastInDetectionRange = distance < self.detectionRadius + player.detectionRadius && !player.isHiding;
};
return self;
});
var MoonBeam = Container.expand(function () {
var self = Container.call(this);
var moonbeamGraphics = self.attachAsset('golden_moonstone', {
anchorX: 0.5,
anchorY: 0.5,
alpha: 0.8
});
moonbeamGraphics.tint = 0xFFD700; // Golden color
self.moveTimer = 0;
self.moveDirection = Math.random() * Math.PI * 2;
self.speed = 2;
self.lifeTimer = 0;
self.maxLifetime = 900; // 15 seconds at 60fps
self.update = function () {
// Golden glow animation
moonbeamGraphics.alpha = 0.6 + Math.sin(LK.ticks * 0.15) * 0.2;
moonbeamGraphics.scaleX = 1 + Math.sin(LK.ticks * 0.1) * 0.15;
moonbeamGraphics.scaleY = 1 + Math.sin(LK.ticks * 0.1) * 0.15;
moonbeamGraphics.rotation += 0.02;
// Random movement
self.moveTimer++;
if (self.moveTimer % 60 == 0) {
// Change direction every second
self.moveDirection = Math.random() * Math.PI * 2;
}
self.x += Math.cos(self.moveDirection) * self.speed;
self.y += Math.sin(self.moveDirection) * self.speed;
// Keep within bounds
if (self.x < 60) {
self.x = 60;
self.moveDirection = Math.random() * Math.PI;
}
if (self.x > 1988) {
self.x = 1988;
self.moveDirection = Math.PI + Math.random() * Math.PI;
}
if (self.y < 60) {
self.y = 60;
self.moveDirection = Math.PI * 0.5 + Math.random() * Math.PI;
}
if (self.y > 2672) {
self.y = 2672;
self.moveDirection = Math.PI * 1.5 + Math.random() * Math.PI;
}
// Handle lifetime
self.lifeTimer++;
if (self.lifeTimer >= self.maxLifetime) {
// Fade out effect before disappearing
tween(moonbeamGraphics, {
alpha: 0
}, {
duration: 1000,
onFinish: function onFinish() {
self.destroy();
// Remove from moonbeams array
for (var i = moonbeams.length - 1; i >= 0; i--) {
if (moonbeams[i] === self) {
moonbeams.splice(i, 1);
break;
}
}
}
});
}
};
return self;
});
var Moonstone = Container.expand(function () {
var self = Container.call(this);
var moonstoneGraphics = self.attachAsset('moonstone', {
anchorX: 0.5,
anchorY: 0.5
});
self.velocityX = 0;
self.velocityY = 0;
self.gravity = 0.5;
self.bounce = 0.7;
self.friction = 0.98;
self.isPhysicsActive = false;
self.isZigzagBouncing = false;
self.zigzagTimer = 0;
self.zigzagSpeed = 8;
self.zigzagDirection = 0;
self.activatePhysics = function () {
self.isPhysicsActive = true;
// Give initial random velocity when physics activates
self.velocityX = (Math.random() - 0.5) * 10;
self.velocityY = (Math.random() - 0.5) * 10;
};
self.update = function () {
// Gentle glow animation
moonstoneGraphics.alpha = 0.7 + Math.sin(LK.ticks * 0.1) * 0.3;
moonstoneGraphics.rotation += 0.02;
// Zigzag bouncing behavior
if (self.isZigzagBouncing) {
self.zigzagTimer++;
// Change direction every 30 frames (0.5 seconds) for zigzag effect
if (self.zigzagTimer % 30 === 0) {
// Create zigzag pattern by alternating direction
var zigzagAngle = self.zigzagDirection + Math.PI / 3 * (Math.random() - 0.5);
self.velocityX = Math.cos(zigzagAngle) * self.zigzagSpeed;
self.velocityY = Math.sin(zigzagAngle) * self.zigzagSpeed;
self.zigzagDirection = zigzagAngle;
}
// Update position with zigzag movement
self.x += self.velocityX;
self.y += self.velocityY;
// Check collision with obstacles during zigzag
for (var o = 0; o < obstacles.length; o++) {
var obstacle = obstacles[o];
var isColliding = false;
if (obstacle.hasCircularHitbox) {
// Use circular collision detection for rocks
var dx = self.x - obstacle.x;
var dy = self.y - obstacle.y;
var distance = Math.sqrt(dx * dx + dy * dy);
isColliding = distance < obstacle.hitboxRadius + 45; // 45 is moonstone radius
} else {
// Use default rectangular collision for trees
isColliding = self.intersects(obstacle);
}
if (isColliding) {
// Bounce off obstacle by reversing direction
if (obstacle.hasCircularHitbox) {
// For rocks, calculate proper bounce direction
var dx = self.x - obstacle.x;
var dy = self.y - obstacle.y;
var distance = Math.sqrt(dx * dx + dy * dy);
if (distance > 0) {
var normalX = dx / distance;
var normalY = dy / distance;
// Reflect velocity based on collision normal
var dotProduct = self.velocityX * normalX + self.velocityY * normalY;
self.velocityX = self.velocityX - 2 * dotProduct * normalX;
self.velocityY = self.velocityY - 2 * dotProduct * normalY;
// Push moonstone away from rock wall
var pushDistance = obstacle.hitboxRadius + 50;
self.x = obstacle.x + normalX * pushDistance;
self.y = obstacle.y + normalY * pushDistance;
}
} else {
// For trees, use simple velocity reversal
self.velocityX = -self.velocityX;
self.velocityY = -self.velocityY;
self.zigzagDirection += Math.PI; // Reverse direction
// Move away from obstacle to prevent sticking
self.x -= self.velocityX;
self.y -= self.velocityY;
}
break;
}
}
// Bounce off boundaries with direction change for zigzag
if (self.x <= 45) {
self.x = 45;
self.velocityX = Math.abs(self.velocityX);
self.zigzagDirection = Math.random() * Math.PI / 2; // Random right direction
}
if (self.x >= 2003) {
self.x = 2003;
self.velocityX = -Math.abs(self.velocityX);
self.zigzagDirection = Math.PI / 2 + Math.random() * Math.PI / 2; // Random left direction
}
if (self.y <= 45) {
self.y = 45;
self.velocityY = Math.abs(self.velocityY);
self.zigzagDirection = Math.random() * Math.PI; // Random down direction
}
if (self.y >= 2687) {
self.y = 2687;
self.velocityY = -Math.abs(self.velocityY);
self.zigzagDirection = Math.PI + Math.random() * Math.PI; // Random up direction
}
// Stop zigzag after 5 seconds
if (self.zigzagTimer >= 300) {
self.isZigzagBouncing = false;
self.zigzagTimer = 0;
}
}
// Ball physics when in kitten mode and not zigzag bouncing
else if (self.isPhysicsActive && isKittenMode) {
// Apply gravity
self.velocityY += self.gravity;
// Apply friction
self.velocityX *= self.friction;
self.velocityY *= self.friction;
// Update position
self.x += self.velocityX;
self.y += self.velocityY;
// Check collision with obstacles during physics mode
for (var o = 0; o < obstacles.length; o++) {
var obstacle = obstacles[o];
var isColliding = false;
var dx = self.x - obstacle.x;
var dy = self.y - obstacle.y;
var distance = Math.sqrt(dx * dx + dy * dy);
if (obstacle.hasCircularHitbox) {
// Use circular collision detection for rocks
isColliding = distance < obstacle.hitboxRadius + 45; // 45 is moonstone radius
} else {
// Use default rectangular collision for trees
isColliding = self.intersects(obstacle);
}
if (isColliding) {
// Bounce off obstacle
if (distance > 0) {
// Normalize collision direction
var normalX = dx / distance;
var normalY = dy / distance;
// Reflect velocity based on collision normal
var dotProduct = self.velocityX * normalX + self.velocityY * normalY;
self.velocityX = (self.velocityX - 2 * dotProduct * normalX) * self.bounce;
self.velocityY = (self.velocityY - 2 * dotProduct * normalY) * self.bounce;
// Move moonstone away from obstacle to prevent sticking
if (obstacle.hasCircularHitbox) {
self.x = obstacle.x + normalX * (obstacle.hitboxRadius + 50);
self.y = obstacle.y + normalY * (obstacle.hitboxRadius + 50);
} else {
self.x = obstacle.x + normalX * 100;
self.y = obstacle.y + normalY * 100;
}
}
break;
}
}
// Bounce off boundaries
if (self.x <= 45) {
self.x = 45;
self.velocityX = -self.velocityX * self.bounce;
}
if (self.x >= 2003) {
self.x = 2003;
self.velocityX = -self.velocityX * self.bounce;
}
if (self.y <= 45) {
self.y = 45;
self.velocityY = -self.velocityY * self.bounce;
}
if (self.y >= 2687) {
self.y = 2687;
self.velocityY = -self.velocityY * self.bounce;
}
}
};
return self;
});
var Obstacle = Container.expand(function (assetType) {
var self = Container.call(this);
var obstacleGraphics = self.attachAsset(assetType, {
anchorX: 0.5,
anchorY: 0.5
});
// Add circular hitbox for rocks
if (assetType === 'rock') {
self.hitboxRadius = 90; // Circular hitbox radius for rocks
self.hasCircularHitbox = true;
} else {
self.hasCircularHitbox = false;
}
// Add transparency tracking for trees
self.isPlayerTouching = false;
self.lastPlayerTouching = false;
return self;
});
var Player = Container.expand(function () {
var self = Container.call(this);
self.transformationLevel = 0;
self.speed = 3;
self.isHiding = false;
self.detectionRadius = 120;
self.lastX = 0;
self.lastY = 0;
self.footstepTimer = 0;
self.footstepInterval = 15; // Play footstep every 15 frames when moving
self.isWalking = false;
self.lastWalkingState = false;
var playerGraphics = self.attachAsset('texture_phase0', {
anchorX: 0.5,
anchorY: 0.5,
scaleX: 0.05,
scaleY: 0.05
});
self.transform = function () {
self.transformationLevel++;
// Remove all current graphics to prevent duplication
while (self.children.length > 0) {
self.removeChild(self.children[0]);
}
// Update appearance based on transformation level
if (self.transformationLevel >= 7) {
// Full werewolf
playerGraphics = self.attachAsset('werewolf', {
anchorX: 0.5,
anchorY: 0.5
});
self.speed = 8;
self.detectionRadius = 80;
} else {
// Use phase-specific texture with walking state
var textureId = 'texture_phase' + self.transformationLevel;
if (self.isWalking) {
textureId += '_walk';
}
playerGraphics = self.attachAsset(textureId, {
anchorX: 0.5,
anchorY: 0.5,
scaleX: 0.05,
scaleY: 0.05
});
// Adjust speed and detection based on transformation
self.speed = 3 + self.transformationLevel * 0.7;
self.detectionRadius = 120 - self.transformationLevel * 5;
}
LK.getSound('transformation').play();
LK.effects.flashObject(self, 0xE6E6FA, 1000);
};
self.updateTexture = function () {
// Check if walking state changed
if (self.lastWalkingState !== self.isWalking) {
self.lastWalkingState = self.isWalking;
// Remove current graphics
var currentGraphics = self.children[0];
self.removeChild(currentGraphics);
var newGraphics;
if (isKittenMode) {
// Handle kitten mode textures
var kittenTextureId = 'kitten';
if (self.isWalking) {
kittenTextureId += '_walk';
}
newGraphics = self.attachAsset(kittenTextureId, {
anchorX: 0.5,
anchorY: 0.5
});
} else if (self.transformationLevel >= 7) {
// Werewolf doesn't change texture when walking
newGraphics = self.attachAsset('werewolf', {
anchorX: 0.5,
anchorY: 0.5
});
} else {
// Choose texture based on walking state and transformation level
var textureId = 'texture_phase' + self.transformationLevel;
if (self.isWalking) {
textureId += '_walk';
}
newGraphics = self.attachAsset(textureId, {
anchorX: 0.5,
anchorY: 0.5,
scaleX: 0.05,
scaleY: 0.05
});
}
self.addChild(newGraphics);
}
};
self.checkHiding = function () {
self.isHiding = false;
// Check if player is behind any obstacle
for (var i = 0; i < obstacles.length; i++) {
var obstacle = obstacles[i];
var dx = self.x - obstacle.x;
var dy = self.y - obstacle.y;
var distance = Math.sqrt(dx * dx + dy * dy);
if (distance < 70) {
self.isHiding = true;
break;
}
}
};
return self;
});
var PlayerBot = Container.expand(function () {
var self = Container.call(this);
self.transformationLevel = 0;
self.botTransformationLevel = 0; // Independent transformation level for bot
self.speed = 2.5; // Slightly slower than player
self.isHiding = false;
self.detectionRadius = 120;
self.followDistance = 150; // Distance to maintain from player
self.targetX = 0;
self.targetY = 0;
self.moveTimer = 0;
self.footstepTimer = 0;
self.footstepInterval = 20; // Slightly different timing than player
self.lastX = 0;
self.lastY = 0;
self.isInBotKittenMode = false; // Independent kitten mode for bot
self.botKittenModeTimer = 0;
self.botKittenModeDuration = 1200; // 20 seconds at 60fps - longer than player
self.botEffectTimer = 0;
self.botEffectInterval = 480; // 8 seconds - bot activates effects more frequently
self.canAlertGuards = true; // Bot can alert guards
self.hasAlertedGuards = false; // Track if bot has alerted guards
self.alertCooldown = 0; // Cooldown before bot can alert again
self.alertCooldownDuration = 600; // 10 seconds at 60fps
self.maintainDistance = false; // Whether bot should maintain distance from player
self.distanceFromPlayer = 300; // Distance to maintain when keeping away
self.isCaught = false; // Whether bot has been caught by guards
self.canMove = true; // Whether bot can move (disabled when caught)
self.mode = 'normal'; // Bot mode: 'normal' or 'caught'
var botGraphics = self.attachAsset('texture_phase0', {
anchorX: 0.5,
anchorY: 0.5,
scaleX: 0.04,
// Slightly smaller than player
scaleY: 0.04,
alpha: 0.8 // Slightly transparent to distinguish from player
});
// Apply a slight blue tint to distinguish from player
botGraphics.tint = 0xADD8E6;
self.transform = function () {
self.transformationLevel++;
// Remove current graphics
self.removeChild(botGraphics);
// Update appearance based on transformation level
if (self.transformationLevel >= 7) {
// Full werewolf
botGraphics = self.attachAsset('werewolf', {
anchorX: 0.5,
anchorY: 0.5,
alpha: 0.8
});
self.speed = 7; // Slightly slower than player werewolf
self.detectionRadius = 80;
} else {
// Use phase-specific texture
var textureId = 'texture_phase' + self.transformationLevel;
botGraphics = self.attachAsset(textureId, {
anchorX: 0.5,
anchorY: 0.5,
scaleX: 0.04,
scaleY: 0.04,
alpha: 0.8
});
// Adjust speed and detection based on transformation
self.speed = 2.5 + self.transformationLevel * 0.6;
self.detectionRadius = 120 - self.transformationLevel * 5;
}
// Apply blue tint to distinguish from player
botGraphics.tint = 0xADD8E6;
// Re-add the updated graphics
self.addChild(botGraphics);
LK.effects.flashObject(self, 0xADD8E6, 800);
};
self.botTransform = function () {
self.botTransformationLevel++;
// Remove current graphics
self.removeChild(botGraphics);
// Update appearance based on bot's independent transformation level
if (self.botTransformationLevel >= 7) {
// Full werewolf
botGraphics = self.attachAsset('werewolf', {
anchorX: 0.5,
anchorY: 0.5,
alpha: 0.8
});
self.speed = 8; // Bot werewolf is faster than regular bot
self.detectionRadius = 70;
} else {
// Use phase-specific texture
var textureId = 'texture_phase' + self.botTransformationLevel;
botGraphics = self.attachAsset(textureId, {
anchorX: 0.5,
anchorY: 0.5,
scaleX: 0.04,
scaleY: 0.04,
alpha: 0.8
});
// Adjust speed and detection based on bot's transformation
self.speed = 2.5 + self.botTransformationLevel * 0.8;
self.detectionRadius = 120 - self.botTransformationLevel * 6;
}
// Apply purple tint to distinguish bot transformations
botGraphics.tint = 0x9370DB;
// Re-add the updated graphics
self.addChild(botGraphics);
LK.effects.flashObject(self, 0x9370DB, 1000);
// Bot transformation effect
tween(self, {
scaleX: (self.scaleX || 1) + 0.15,
scaleY: (self.scaleY || 1) + 0.15
}, {
duration: 800,
easing: tween.easeOut
});
};
self.activateBotKittenMode = function () {
if (!self.isInBotKittenMode) {
self.isInBotKittenMode = true;
self.botKittenModeTimer = 0;
// Transform to kitten with unique bot styling
var currentBotGraphics = self.children[0];
self.removeChild(currentBotGraphics);
var botKittenGraphics = self.attachAsset('kitten', {
anchorX: 0.5,
anchorY: 0.5,
alpha: 0.9
});
// Apply unique purple-blue tint for bot kitten mode
botKittenGraphics.tint = 0x6A5ACD;
self.addChild(botKittenGraphics);
// Unique scaling for bot kitten mode
tween(self, {
scaleX: (self.scaleX || 1) * 0.4,
scaleY: (self.scaleY || 1) * 0.4
}, {
duration: 600,
easing: tween.easeOut
});
// Play unique bot meow with different pitch
var botMeow = LK.getSound('meow');
botMeow.volume = 0.6;
botMeow.play();
LK.effects.flashObject(self, 0x6A5ACD, 1200);
}
};
self.checkHiding = function () {
self.isHiding = false;
// Check if bot is behind any obstacle
for (var i = 0; i < obstacles.length; i++) {
var obstacle = obstacles[i];
var dx = self.x - obstacle.x;
var dy = self.y - obstacle.y;
var distance = Math.sqrt(dx * dx + dy * dy);
if (distance < 70) {
self.isHiding = true;
break;
}
}
};
self.update = function () {
// Handle bot's independent kitten mode timer
if (self.isInBotKittenMode) {
self.botKittenModeTimer++;
if (self.botKittenModeTimer >= self.botKittenModeDuration) {
// Revert from bot kitten mode
self.isInBotKittenMode = false;
self.botKittenModeTimer = 0;
// Change bot back to current bot transformation level
var currentBotGraphics = self.children[0];
self.removeChild(currentBotGraphics);
var revertGraphics;
if (self.botTransformationLevel >= 7) {
revertGraphics = self.attachAsset('werewolf', {
anchorX: 0.5,
anchorY: 0.5,
alpha: 0.8
});
} else {
var textureId = 'texture_phase' + self.botTransformationLevel;
revertGraphics = self.attachAsset(textureId, {
anchorX: 0.5,
anchorY: 0.5,
scaleX: 0.04,
scaleY: 0.04,
alpha: 0.8
});
}
revertGraphics.tint = 0x9370DB; // Purple tint for bot transformations
self.addChild(revertGraphics);
// Restore bot size when reverting from kitten mode
tween(self, {
scaleX: 1,
scaleY: 1
}, {
duration: 600,
easing: tween.easeOut
});
LK.effects.flashObject(self, 0x9370DB, 900);
}
}
// Bot independent effect timer
self.botEffectTimer++;
if (self.botEffectTimer >= self.botEffectInterval) {
self.botEffectTimer = 0;
// Bot has 30% chance to transform independently
if (Math.random() < 0.3 && self.botTransformationLevel < 7) {
self.botTransform();
}
// Bot has 25% chance to activate kitten mode independently
else if (Math.random() < 0.25 && !self.isInBotKittenMode) {
self.activateBotKittenMode();
}
}
// Handle alert cooldown
if (self.alertCooldown > 0) {
self.alertCooldown--;
if (self.alertCooldown <= 0) {
self.canAlertGuards = true;
self.hasAlertedGuards = false;
self.maintainDistance = false; // Stop maintaining distance after cooldown
}
}
// Check if bot should alert guards (only when bot enters a guard's detection range)
var shouldAlert = false;
if (self.canAlertGuards && !self.hasAlertedGuards && !isKittenMode) {
// Check if bot is within any guard's detection range
for (var g = 0; g < guards.length; g++) {
var guard = guards[g];
var guardDx = self.x - guard.x;
var guardDy = self.y - guard.y;
var guardDistance = Math.sqrt(guardDx * guardDx + guardDy * guardDy);
// Check if bot is within this guard's detection radius
if (guardDistance < guard.detectionRadius + self.detectionRadius) {
shouldAlert = true;
break;
}
}
}
if (shouldAlert) {
// Bot enters guard detection range - alert only the specific guard
self.hasAlertedGuards = true;
self.canAlertGuards = false;
self.alertCooldown = self.alertCooldownDuration;
self.maintainDistance = true; // Start maintaining distance
// Alert only the guard whose zone the bot entered
for (var g = 0; g < guards.length; g++) {
var guard = guards[g];
var guardDx = self.x - guard.x;
var guardDy = self.y - guard.y;
var guardDistance = Math.sqrt(guardDx * guardDx + guardDy * guardDy);
// Only alert this specific guard if bot is in its detection range
if (guardDistance < guard.detectionRadius + self.detectionRadius && !guard.isAlerted) {
guard.isAlerted = true;
guard.alertState = 'chase_player';
guard.chaseTimer = 0;
guard.alertSpeed = 6;
// Change guard to chase texture
var currentGraphics = guard.children[0];
guard.removeChild(currentGraphics);
var chaseGraphics = guard.attachAsset('guard_chase', {
anchorX: 0.5,
anchorY: 0.5,
alpha: 0.5
});
guard.addChild(chaseGraphics);
break; // Only alert one guard - the one whose zone was entered
}
}
// Play alert sound
LK.getSound('dog_alert').play();
// Flash bot to indicate it alerted guards
LK.effects.flashObject(self, 0xFF4444, 800);
}
// Store last position for movement detection
self.lastX = self.x;
self.lastY = self.y;
// Skip movement and other behaviors if bot is caught
if (self.isCaught || !self.canMove) {
return;
}
// Free movement behavior - check for moonstones first
var nearestMoonstone = null;
var shortestDistance = Infinity;
// Find nearest moonstone
for (var m = 0; m < moonstones.length; m++) {
var moonstone = moonstones[m];
var mstoneDx = moonstone.x - self.x;
var mstoneDy = moonstone.y - self.y;
var mstoneDistance = Math.sqrt(mstoneDx * mstoneDx + mstoneDy * mstoneDy);
if (mstoneDistance < shortestDistance) {
shortestDistance = mstoneDistance;
nearestMoonstone = moonstone;
}
}
// Calculate distance to player for bot logic
var playerDistance = Math.sqrt((player.x - self.x) * (player.x - self.x) + (player.y - self.y) * (player.y - self.y));
// Determine target based on bot state
if (self.maintainDistance) {
// Maintain distance from player when bot has alerted guards
if (playerDistance < self.distanceFromPlayer) {
// Move away from player
var awayAngle = Math.atan2(self.y - player.y, self.x - player.x);
self.targetX = self.x + Math.cos(awayAngle) * self.speed * 2; // Move away faster
self.targetY = self.y + Math.sin(awayAngle) * self.speed * 2;
} else {
// Maintain current position if far enough
self.targetX = self.x;
self.targetY = self.y;
}
} else if (nearestMoonstone && shortestDistance < 600) {
// Move towards nearest moonstone
var mstoneDx = nearestMoonstone.x - self.x;
var mstoneDy = nearestMoonstone.y - self.y;
var mstoneAngle = Math.atan2(mstoneDy, mstoneDx);
self.targetX = self.x + Math.cos(mstoneAngle) * self.speed * 1.5; // Faster when seeking moonstone
self.targetY = self.y + Math.sin(mstoneAngle) * self.speed * 1.5;
} else {
// Free roaming movement when no moonstone nearby
self.moveTimer++;
if (self.moveTimer % 120 === 0) {
// Change direction every 2 seconds for more freedom
var randomAngle = Math.random() * Math.PI * 2;
var roamDistance = 80 + Math.random() * 120; // Vary roaming distance
self.targetX = self.x + Math.cos(randomAngle) * roamDistance;
self.targetY = self.y + Math.sin(randomAngle) * roamDistance;
}
}
// Move towards target position
var targetDx = self.targetX - self.x;
var targetDy = self.targetY - self.y;
var targetDistance = Math.sqrt(targetDx * targetDx + targetDy * targetDy);
if (targetDistance > 1) {
var moveX = targetDx / targetDistance * self.speed;
var moveY = targetDy / targetDistance * self.speed;
self.x += moveX;
self.y += moveY;
}
// Keep bot within bounds
if (self.x < 40) self.x = 40;
if (self.x > 2008) self.x = 2008;
if (self.y < 40) self.y = 40;
if (self.y > 2692) self.y = 2692;
// Check collision with rock obstacles (walls)
for (var o = 0; o < obstacles.length; o++) {
var obstacle = obstacles[o];
if (obstacle.hasCircularHitbox) {
// Only check rocks as walls
var obstacleDx = self.x - obstacle.x;
var obstacleDy = self.y - obstacle.y;
var obstacleDistance = Math.sqrt(obstacleDx * obstacleDx + obstacleDy * obstacleDy);
var botRadius = 35; // Bot collision radius
if (obstacleDistance < obstacle.hitboxRadius + botRadius) {
// Bot is colliding with rock wall - push back
if (obstacleDistance > 0) {
var normalX = obstacleDx / obstacleDistance;
var normalY = obstacleDy / obstacleDistance;
var pushDistance = obstacle.hitboxRadius + botRadius;
self.x = obstacle.x + normalX * pushDistance;
self.y = obstacle.y + normalY * pushDistance;
}
}
}
}
// Play footstep sounds when bot is moving
var movementX = self.x - self.lastX;
var movementY = self.y - self.lastY;
var isMoving = Math.sqrt(movementX * movementX + movementY * movementY) > 0.5;
if (isMoving) {
self.footstepTimer++;
if (self.footstepTimer >= self.footstepInterval) {
// Play footstep at lower volume for bot
var footstepSound = LK.getSound('footsteps');
footstepSound.volume = 0.3;
footstepSound.play();
self.footstepTimer = 0;
}
} else {
self.footstepTimer = 0;
}
// Flip bot based on movement direction
if (self.children.length > 0 && self.children[0]) {
if (movementX > 0) {
// Moving right - face right
self.children[0].scaleX = Math.abs(self.children[0].scaleX);
} else if (movementX < 0) {
// Moving left - face left
self.children[0].scaleX = -Math.abs(self.children[0].scaleX);
}
}
// Update hiding status
self.checkHiding();
};
return self;
});
/****
* Initialize Game
****/
var game = new LK.Game({
backgroundColor: 0x191970
});
/****
* Game Code
****/
// Game variables
var player;
var playerBot;
var moonstones = [];
var guards = [];
var obstacles = [];
var moonbeams = [];
var goldenMoonRocks = [];
var dragNode = null;
var moonstonesCollected = 0;
var playerLevel = 0; // Independent level counter for player transformations
var botLevel = 0; // Independent level counter for bot transformations
var totalMoonstones = 7;
var lastMoonstoneDropX = 0;
var lastMoonstoneDropY = 0;
var moonbeamEventTimer = 0;
var moonbeamEventInterval = 900; // 15 seconds at 60fps
var goldenRockTimer = 0;
var goldenRockInterval = 1200; // 20 seconds at 60fps
var isGiantMode = false;
var giantModeTimer = 0;
var giantModeDuration = 900; // 15 seconds at 60fps
var hasTransformedToKitten = storage.hasTransformedToKitten || false;
var isKittenMode = false;
var kittenModeTimer = 0;
var kittenModeDuration = 900; // 15 seconds at 60fps
var dog = null;
var dogSpawned = false;
// Create UI
var scoreText = new Text2('Moonstones: 0/7', {
size: 60,
fill: 0xFFFFFF
});
scoreText.anchor.set(0.5, 0);
LK.gui.top.addChild(scoreText);
var transformationText = new Text2('Human Child', {
size: 50,
fill: 0xE6E6FA
});
transformationText.anchor.set(0.5, 0);
transformationText.y = 80;
LK.gui.top.addChild(transformationText);
// Create loading screen that covers the entire game
var loadingScreen = LK.gui.center.addChild(LK.getAsset('loadingScreen', {
anchorX: 0.5,
anchorY: 0.5,
x: 0,
y: 0,
width: 2048,
height: 2732
}));
// Keep loading screen visible for exactly 3 seconds, then fade out
LK.setTimeout(function () {
tween(loadingScreen, {
alpha: 0
}, {
duration: 1000,
easing: tween.easeOut,
onFinish: function onFinish() {
// Remove loading screen from GUI and destroy to free memory
LK.gui.center.removeChild(loadingScreen);
loadingScreen.destroy();
loadingScreen = null; // Clear reference for garbage collection
}
});
}, 3000);
// Create grass ground
var grass = game.addChild(LK.getAsset('grass', {
anchorX: 0,
anchorY: 0,
x: 0,
y: 0,
scaleX: 0.82,
scaleY: 1.16
}));
// Create player
player = game.addChild(new Player());
player.x = 1024;
player.y = 1366;
// Bot spawning disabled
playerBot = null;
// Generate only one moonstone initially
var moonstone = game.addChild(new Moonstone());
moonstone.x = 150 + Math.random() * 1748;
moonstone.y = 150 + Math.random() * 2432;
moonstones.push(moonstone);
// Function to spawn moonbeam at random location
function spawnMoonbeam() {
var moonbeam = game.addChild(new MoonBeam());
moonbeam.x = 60 + Math.random() * 1928;
moonbeam.y = 60 + Math.random() * 2612;
moonbeams.push(moonbeam);
// Add entrance effect
moonbeam.children[0].alpha = 0;
tween(moonbeam.children[0], {
alpha: 0.8
}, {
duration: 1000,
easing: tween.easeOut
});
}
// Function to spawn golden moon rock at random location
function spawnGoldenMoonRock() {
var goldenRock = game.addChild(new GoldenMoonRock());
goldenRock.x = 80 + Math.random() * 1888;
goldenRock.y = 80 + Math.random() * 2572;
goldenMoonRocks.push(goldenRock);
// Add dramatic entrance effect
goldenRock.children[0].alpha = 0;
goldenRock.children[0].scaleX = 0;
goldenRock.children[0].scaleY = 0;
tween(goldenRock.children[0], {
alpha: 0.9,
scaleX: 1.2,
scaleY: 1.2
}, {
duration: 1200,
easing: tween.easeOut
});
}
// Function to spawn new moonstone from the sky
function spawnMoonstoneFromSky() {
var newMoonstone = game.addChild(new Moonstone());
newMoonstone.x = 150 + Math.random() * 1748;
newMoonstone.y = -100; // Start above the screen
var finalY = 150 + Math.random() * 2432;
// Store the drop position for guard alerting
lastMoonstoneDropX = newMoonstone.x;
lastMoonstoneDropY = finalY;
moonstones.push(newMoonstone);
// Activate physics if player is in kitten mode
if (isKittenMode) {
newMoonstone.activatePhysics();
}
// Animate falling from sky
tween(newMoonstone, {
y: finalY
}, {
duration: 2000,
easing: tween.easeOut,
onComplete: function onComplete() {
// Alert all guards to move towards the dropped moonstone
for (var i = 0; i < guards.length; i++) {
var guard = guards[i];
guard.isAlerted = true;
guard.alertState = 'move_to_moonstone';
guard.chaseTimer = 0;
guard.alertSpeed = 6;
// Change to chase texture
var currentGraphics = guard.children[0];
guard.removeChild(currentGraphics);
var chaseGraphics = guard.attachAsset('guard_chase', {
anchorX: 0.5,
anchorY: 0.5,
alpha: 0.5
});
guard.addChild(chaseGraphics);
}
}
});
}
// Generate obstacles for hiding - rocks first, then guards, then trees (so trees appear above guards and guards above rocks)
// Generate rocks first (lowest z-index)
for (var i = 0; i < 7; i++) {
var rock = game.addChild(new Obstacle('rock'));
rock.x = 200 + Math.random() * 1648;
rock.y = 200 + Math.random() * 2332;
obstacles.push(rock);
}
// Generate guards second so they appear above rocks but below trees
for (var i = 0; i < 1; i++) {
var guard = game.addChild(new Guard());
// Spawn guards far from player spawn (1024, 1366)
var angle = Math.random() * Math.PI * 2;
var distance = 1200 + Math.random() * 800; // 1200-2000 pixels away from center
guard.x = 1024 + Math.cos(angle) * distance;
guard.y = 1366 + Math.sin(angle) * distance;
// Keep guards within game bounds
if (guard.x < 100) guard.x = 100;
if (guard.x > 1948) guard.x = 1948;
if (guard.y < 100) guard.y = 100;
if (guard.y > 2632) guard.y = 2632;
guards.push(guard);
}
// Generate trees second (higher z-index, appear above rocks)
for (var i = 0; i < 8; i++) {
// Randomly choose between classic and new tree texture
var treeType = Math.random() < 0.5 ? 'tree' : 'tree_new';
var tree = game.addChild(new Obstacle(treeType));
tree.x = 200 + Math.random() * 1648;
tree.y = 200 + Math.random() * 2332;
obstacles.push(tree);
}
// Start ambient music
LK.playMusic('ambient');
function updateTransformationUI() {
var transformationNames = ['Human Child', 'Growing Tail', 'Wolf Ears', 'Sharp Claws', 'Wolf Paws', 'Wolf Snout', 'Growing Fur', 'Full Werewolf'];
transformationText.setText(transformationNames[player.transformationLevel] || 'Full Werewolf');
}
function handleMove(x, y, obj) {
if (dragNode) {
// Track previous position for flip detection
var previousX = dragNode.x;
var previousY = dragNode.y;
// Calculate desired movement
var deltaX = x - dragNode.x;
var deltaY = y - dragNode.y;
var distance = Math.sqrt(deltaX * deltaX + deltaY * deltaY);
// Check if player is actually moving
var isMoving = distance > 0.5; // Only consider significant movement
// Update player walking state and texture
if (dragNode === player) {
player.isWalking = isMoving;
player.updateTexture();
// If player stops moving, set a timeout to return to idle texture
if (!isMoving && player.isWalking !== false) {
LK.setTimeout(function () {
// Check if player is still not moving after timeout
if (!player.isWalking) {
player.isWalking = false;
player.updateTexture();
}
}, 200); // 200ms delay before returning to idle texture
}
}
// Apply speed limit to prevent teleportation
var maxSpeed = 15; // Maximum pixels per frame
if (distance > maxSpeed) {
// Normalize the movement vector and apply speed limit
var normalizedX = deltaX / distance;
var normalizedY = deltaY / distance;
dragNode.x += normalizedX * maxSpeed;
dragNode.y += normalizedY * maxSpeed;
} else {
dragNode.x = x;
dragNode.y = y;
}
// Keep player within bounds
if (dragNode.x < 40) dragNode.x = 40;
if (dragNode.x > 2008) dragNode.x = 2008;
if (dragNode.y < 40) dragNode.y = 40;
if (dragNode.y > 2692) dragNode.y = 2692;
// Check collision with rock obstacles (walls)
if (dragNode === player) {
for (var o = 0; o < obstacles.length; o++) {
var obstacle = obstacles[o];
if (obstacle.hasCircularHitbox) {
// Only check rocks as walls
var dx = dragNode.x - obstacle.x;
var dy = dragNode.y - obstacle.y;
var distance = Math.sqrt(dx * dx + dy * dy);
var playerRadius = 40; // Player collision radius
if (distance < obstacle.hitboxRadius + playerRadius) {
// Player is colliding with rock wall - push back
if (distance > 0) {
var normalX = dx / distance;
var normalY = dy / distance;
var pushDistance = obstacle.hitboxRadius + playerRadius;
dragNode.x = obstacle.x + normalX * pushDistance;
dragNode.y = obstacle.y + normalY * pushDistance;
}
}
}
}
}
// Play footstep sounds when player is moving
if (dragNode === player && isMoving) {
dragNode.footstepTimer++;
if (dragNode.footstepTimer >= dragNode.footstepInterval) {
LK.getSound('footsteps').play();
dragNode.footstepTimer = 0;
}
} else if (dragNode === player && !isMoving) {
// Reset footstep timer when not moving
dragNode.footstepTimer = 0;
}
// Flip player based on movement direction
if (dragNode === player && player.children.length > 0 && player.children[0]) {
var movementX = dragNode.x - previousX;
if (movementX > 0) {
// Moving right - face right
player.children[0].scaleX = Math.abs(player.children[0].scaleX);
} else if (movementX < 0) {
// Moving left - face left
player.children[0].scaleX = -Math.abs(player.children[0].scaleX);
}
}
}
}
game.move = handleMove;
game.down = function (x, y, obj) {
dragNode = player;
handleMove(x, y, obj);
};
game.up = function (x, y, obj) {
dragNode = null;
// When player stops being dragged, return to idle texture after short delay
if (player) {
LK.setTimeout(function () {
player.isWalking = false;
player.updateTexture();
}, 100); // 100ms delay to return to idle texture
}
};
game.update = function () {
// Spawn moonbeam only once per game (only if not already spawned)
if (!hasTransformedToKitten && moonbeams.length === 0) {
moonbeamEventTimer++;
if (moonbeamEventTimer >= moonbeamEventInterval) {
spawnMoonbeam();
moonbeamEventTimer = 0;
}
}
// Spawn golden moon rock every 20 seconds
goldenRockTimer++;
if (goldenRockTimer >= goldenRockInterval) {
spawnGoldenMoonRock();
goldenRockTimer = 0;
}
// Update kitten mode timer
if (isKittenMode) {
kittenModeTimer++;
if (kittenModeTimer >= kittenModeDuration) {
// Revert from kitten mode
isKittenMode = false;
kittenModeTimer = 0;
// Update player texture back to normal transformation (respecting walking state)
player.updateTexture();
// Restore player size when reverting from kitten mode
tween(player, {
scaleX: 1,
scaleY: 1
}, {
duration: 500,
easing: tween.easeOut
});
LK.effects.flashObject(player, 0xE6E6FA, 1000);
// Bot kitten mode revert disabled
}
}
// Update giant mode timer
if (isGiantMode) {
giantModeTimer++;
if (giantModeTimer >= giantModeDuration) {
// Revert from giant mode
isGiantMode = false;
giantModeTimer = 0;
// Restore player size when reverting from giant mode
tween(player, {
scaleX: 1,
scaleY: 1
}, {
duration: 800,
easing: tween.easeOut
});
LK.effects.flashObject(player, 0xFFD700, 1000);
}
}
// Check golden moon rock collision
for (var gr = goldenMoonRocks.length - 1; gr >= 0; gr--) {
var goldenRock = goldenMoonRocks[gr];
if (player.intersects(goldenRock)) {
// Transform player to giant mode
isGiantMode = true;
giantModeTimer = 0;
// Multiply player size by 20 (increased limit)
tween(player, {
scaleX: (player.scaleX || 1) * 20,
scaleY: (player.scaleY || 1) * 20
}, {
duration: 800,
easing: tween.easeOut
});
// Play transformation sound and effects
LK.getSound('transformation').play();
LK.effects.flashObject(player, 0xFFD700, 1500);
// Remove the golden moon rock that was touched
goldenRock.destroy();
goldenMoonRocks.splice(gr, 1);
break;
}
}
// Update player hiding status
player.checkHiding();
// Check moonbeam collision
for (var m = moonbeams.length - 1; m >= 0; m--) {
var moonbeam = moonbeams[m];
if (player.intersects(moonbeam)) {
// Transform player to kitten temporarily
isKittenMode = true;
kittenModeTimer = 0;
// Update player texture to kitten mode (respecting walking state)
player.updateTexture();
// Reduce player size by half when entering kitten mode
tween(player, {
scaleX: (player.scaleX || 1) * 0.5,
scaleY: (player.scaleY || 1) * 0.5
}, {
duration: 500,
easing: tween.easeOut
});
// Play meow sound for kitten transformation
LK.getSound('meow').play();
// Activate physics for all existing moonstones
for (var p = 0; p < moonstones.length; p++) {
moonstones[p].activatePhysics();
}
// Make all guards passive
for (var k = 0; k < guards.length; k++) {
var guard = guards[k];
guard.isAlerted = false;
guard.alertState = 'none';
guard.chaseTimer = 0;
// Reset guard graphics to normal
var currentGuardGraphics = guard.children[0];
guard.removeChild(currentGuardGraphics);
var normalGraphics = guard.attachAsset('guard', {
anchorX: 0.5,
anchorY: 0.5,
alpha: 0.5
});
guard.addChild(normalGraphics);
normalGraphics.tint = 0xFFFFFF;
}
// Remove the moonbeam that was touched
moonbeam.destroy();
moonbeams.splice(m, 1);
LK.effects.flashObject(player, 0xffa500, 1000);
break;
}
}
// Check moonstone interactions
if (!isKittenMode) {
// Normal collection when not in kitten mode
for (var i = moonstones.length - 1; i >= 0; i--) {
var moonstone = moonstones[i];
var collected = false;
// Check player collection
if (player.intersects(moonstone)) {
moonstone.destroy();
moonstones.splice(i, 1);
moonstonesCollected++;
playerLevel++; // Player collected - increment player level
player.transformationLevel = Math.min(playerLevel - 1, 7); // Set player transformation level
player.transform();
LK.getSound('collect').play();
LK.setScore(moonstonesCollected);
scoreText.setText('Moonstones: ' + moonstonesCollected + '/' + totalMoonstones);
updateTransformationUI();
}
// Bot collection disabled
// Spawn dog when collecting 4th moonstone
if (moonstonesCollected === 4 && !dogSpawned) {
dogSpawned = true;
dog = game.addChild(new Dog());
// Spawn dog far from player
var angle = Math.random() * Math.PI * 2;
var distance = 800 + Math.random() * 400;
dog.x = player.x + Math.cos(angle) * distance;
dog.y = player.y + Math.sin(angle) * distance;
// Keep dog within bounds
if (dog.x < 100) dog.x = 100;
if (dog.x > 1948) dog.x = 1948;
if (dog.y < 100) dog.y = 100;
if (dog.y > 2632) dog.y = 2632;
}
// Increase player size slightly with smooth animation when player collects
if (playerLevel > 0 && playerLevel <= 7) {
var newScale;
if (isGiantMode) {
// No size limit in giant mode
newScale = (player.scaleX || 1) + 0.05;
} else {
// Limited growth when not in giant mode
newScale = Math.min((player.scaleX || 1) + 0.05, 1.35); // Cap maximum scale at 1.35
}
tween(player, {
scaleX: newScale,
scaleY: newScale
}, {
duration: 500,
easing: tween.easeOut
});
}
// Spawn new moonstone from sky if there are none on screen and haven't won yet
if (moonstones.length === 0 && moonstonesCollected < totalMoonstones) {
spawnMoonstoneFromSky();
}
// Check win condition
if (moonstonesCollected >= totalMoonstones) {
LK.showYouWin();
return;
}
// Add more guards as player transforms - insert at lower z-index to appear below trees
if (moonstonesCollected % 2 == 0 && guards.length < 8) {
var newGuard = new Guard();
// Find the index where obstacles start to insert guard before them
var obstacleIndex = -1;
for (var idx = 0; idx < game.children.length; idx++) {
if (obstacles.indexOf(game.children[idx]) !== -1) {
obstacleIndex = idx;
break;
}
}
// Insert guard before obstacles if found, otherwise add normally
if (obstacleIndex !== -1) {
game.addChildAt(newGuard, obstacleIndex);
} else {
game.addChild(newGuard);
}
// Spawn new guards far from current player position
var angle = Math.random() * Math.PI * 2;
var distance = 1000 + Math.random() * 600; // 1000-1600 pixels away from player
newGuard.x = player.x + Math.cos(angle) * distance;
newGuard.y = player.y + Math.sin(angle) * distance;
// Keep guards within game bounds
if (newGuard.x < 100) newGuard.x = 100;
if (newGuard.x > 1948) newGuard.x = 1948;
if (newGuard.y < 100) newGuard.y = 100;
if (newGuard.y > 2632) newGuard.y = 2632;
guards.push(newGuard);
}
}
} else {
// Collision detection in kitten mode - trigger zigzag bouncing
for (var i = 0; i < moonstones.length; i++) {
var moonstone = moonstones[i];
if (moonstone.lastWasColliding === undefined) moonstone.lastWasColliding = false;
var currentColliding = player.intersects(moonstone);
// Check if collision just started (transition from false to true)
if (!moonstone.lastWasColliding && currentColliding) {
// Start zigzag bouncing behavior
moonstone.isZigzagBouncing = true;
moonstone.zigzagTimer = 0;
moonstone.zigzagSpeed = 8;
moonstone.zigzagDirection = Math.random() * Math.PI * 2;
// Override physics with zigzag movement
moonstone.velocityX = Math.cos(moonstone.zigzagDirection) * moonstone.zigzagSpeed;
moonstone.velocityY = Math.sin(moonstone.zigzagDirection) * moonstone.zigzagSpeed;
}
moonstone.lastWasColliding = currentColliding;
}
}
// Check guard capture (only if not in kitten mode)
if (!isKittenMode) {
for (var g = 0; g < guards.length; g++) {
var guard = guards[g];
// Check player capture
if (player.intersects(guard)) {
// Change player texture to caught state
var currentPlayerGraphics = player.children[0];
player.removeChild(currentPlayerGraphics);
var caughtGraphics = player.attachAsset('player_caught', {
anchorX: 0.5,
anchorY: 0.5,
scaleX: 0.1,
scaleY: 0.1
});
player.addChild(caughtGraphics);
LK.getSound('caught').play();
LK.effects.flashScreen(0xFF0000, 1000);
LK.showGameOver();
return;
}
// Bot capture and rescue mechanics disabled
}
// Check dog capture
if (dog && player.intersects(dog)) {
// Change player texture to caught state
var currentPlayerGraphics = player.children[0];
player.removeChild(currentPlayerGraphics);
var caughtGraphics = player.attachAsset('player_caught', {
anchorX: 0.5,
anchorY: 0.5,
scaleX: 0.1,
scaleY: 0.1
});
player.addChild(caughtGraphics);
LK.getSound('caught').play();
LK.effects.flashScreen(0xFF0000, 1000);
LK.showGameOver();
return;
}
}
// Handle tree transparency when player touches them
for (var t = 0; t < obstacles.length; t++) {
var obstacle = obstacles[t];
// Only apply transparency to trees, not rocks
if (!obstacle.hasCircularHitbox) {
obstacle.lastPlayerTouching = obstacle.isPlayerTouching;
obstacle.isPlayerTouching = player.intersects(obstacle);
// Check if player just started touching the tree
if (!obstacle.lastPlayerTouching && obstacle.isPlayerTouching) {
// Make tree semi-transparent
tween(obstacle.children[0], {
alpha: 0.3
}, {
duration: 300,
easing: tween.easeOut
});
}
// Check if player stopped touching the tree
else if (obstacle.lastPlayerTouching && !obstacle.isPlayerTouching) {
// Make tree fully opaque again
tween(obstacle.children[0], {
alpha: 1.0
}, {
duration: 500,
easing: tween.easeOut
});
}
}
}
}; ===================================================================
--- original.js
+++ change.js
@@ -1666,11 +1666,18 @@
if (dog.x > 1948) dog.x = 1948;
if (dog.y < 100) dog.y = 100;
if (dog.y > 2632) dog.y = 2632;
}
- // Increase player size slightly with smooth animation when player collects (limited growth)
+ // Increase player size slightly with smooth animation when player collects
if (playerLevel > 0 && playerLevel <= 7) {
- var newScale = Math.min((player.scaleX || 1) + 0.05, 1.35); // Cap maximum scale at 1.35
+ var newScale;
+ if (isGiantMode) {
+ // No size limit in giant mode
+ newScale = (player.scaleX || 1) + 0.05;
+ } else {
+ // Limited growth when not in giant mode
+ newScale = Math.min((player.scaleX || 1) + 0.05, 1.35); // Cap maximum scale at 1.35
+ }
tween(player, {
scaleX: newScale,
scaleY: newScale
}, {
Pixel art de árbol pero de noche. In-Game asset. 2d. High contrast. No shadows
Piedra lunar brillante pixelart. In-Game asset. 2d. High contrast. No shadows
Guardia completamente negro con linterna iluminando con un circulo de aura pixelart. In-Game asset. 2d. High contrast. No shadows
Cesped oscuro de noche pixel art. In-Game asset. 2d. High contrast. No shadows
Niño pero de noche pixelart. In-Game asset. 2d. High contrast. No shadows
Cola de lobo, pixelart
Garras de lobo, pixelart
Nariz de lobo, pixel art
Silueta corriendo
Jaula de metal oscura , pixel art. In-Game asset. 2d. High contrast. No shadows
Transformalo en un gatito
Elimina los cristales y agrega árboles , estilo pixelart
Ahora que el perro esté ladrando
Silueta de perro corriendo
Corriendo
Corriendo pixelart
Gatito corriendo pixelart
Corriendo , pixelart
Corriendo, pixelart
Corriendo, pixelart
Corriendo, pixelart
Quítale la camisa, aslo más grande y peludo, que este en cuatro patas , pixelart