User prompt
Cuando el perro está sobre el gato, queda el gato asustado y no puede escapar tiene que asustarse solo una vez, y debe pasar 5 segundos para que pueda volver a asustarse ↪💡 Consider importing and using the following plugins: @upit/tween.v1
User prompt
mientras esta en reposo, pecera debe alternar entre pecera y pecera2 ↪💡 Consider importing and using the following plugins: @upit/tween.v1
User prompt
cuando el perro cae, debe alternar entre el asset de perroCae y perroCae2 ↪💡 Consider importing and using the following plugins: @upit/tween.v1
User prompt
puedes replantear completamente el comportamiento del gato cuando toca el jabon sigue reproduciendo el mismo error ↪💡 Consider importing and using the following plugins: @upit/tween.v1
User prompt
sigue apareciendo el asset detras del gato enjabonado
User prompt
cuando el gato choca contra una barrera, debe alejarse siempre lo suficiente para salir de esa zona en la que se señala la barrera, de otro modo, va retrocediendo de a poca distancia y no logra salir de la zona de colision a la primera ↪💡 Consider importing and using the following plugins: @upit/tween.v1
User prompt
el gato solo puede saltar cuando esta caminando, si esta electrocutado asustado o señalando una barrera, debe estar imposibilitado de saltar hasta volver a la normalidad, si un perro lo atrapa, debe alejarse automaticamente unos 80 px ↪💡 Consider importing and using the following plugins: @upit/tween.v1
User prompt
Cuando termina una fase y suena la musica de victoria, deve detenerse main theme, porque lo que pasa es que se reproduce 2 veces cuando empieza la nueva etapa
User prompt
al momento de ser impactado, el perro debe dejar de ladrar inmediatamente
User prompt
el perro debe dejar de ladrar cuando cae y dejar de ocupar los assets dog y dogbark, la pantalla debe ir inmediatamente a la ubicacion del gato cuando se cambia de pantalla
User prompt
puedes controlar que no haya assets superpuestos, pasa tanto con el gato cuando esta en la burbuja, que detras se ve el gato normal unos momentos, y el perro cae con el asset de perro cae y atras esta el perro ladrando
/****
* Plugins
****/
var tween = LK.import("@upit/tween.v1");
var storage = LK.import("@upit/storage.v1");
/****
* Classes
****/
var Cat = Container.expand(function () {
var self = Container.call(this);
var catGraphics = self.attachAsset('cat', {
anchorX: 0.5,
anchorY: 0.5,
scaleX: 2,
scaleY: 2
});
var catStepGraphics = self.attachAsset('Cat-step', {
anchorX: 0.5,
anchorY: 0.5,
scaleX: 2,
scaleY: 2
});
catStepGraphics.visible = false;
self.walkAnimTimer = 0;
self.isWalkAnimStep = false;
self.catElectrocutedGraphics = self.attachAsset('catElectrocuted', {
anchorX: 0.5,
anchorY: 0.5,
scaleX: 2,
scaleY: 2
});
self.catElectrocutedGraphics.visible = false;
self.gatoEnjabonado = self.attachAsset('Gato-enjabonado', {
anchorX: 0.5,
anchorY: 0.5,
scaleX: 2,
scaleY: 2
});
self.gatoEnjabonado.visible = false;
self.catJumpGraphics = self.attachAsset('cat-jump', {
anchorX: 0.5,
anchorY: 0.5,
scaleX: 2,
scaleY: 2
});
self.catJumpGraphics.visible = false;
self.speed = 10; // Much faster cat movement
self.direction = 1; // 1 for right, -1 for left
self.targetShelfLevel = 2; // Start on middle shelf (0-4)
self.currentShelfLevel = 2;
// Laser mode removed
self.normalSpeed = 8;
// Laser speed removed
self.isChasing = false;
self.chaseTarget = null;
self.isHiding = false;
self.hideTarget = null;
self.isJumping = false;
self.isInvulnerable = false;
self.invulnerabilityTimer = 0;
self.isZarpazoMode = false;
self.zarpazoGraphics = null;
self.gatoKissGraphics = self.attachAsset('gato-kiss', {
anchorX: 0.5,
anchorY: 0.5,
scaleX: 2,
scaleY: 2
});
self.gatoKissGraphics.visible = false;
self.isKissMode = false;
self.catHitGraphics = self.attachAsset('cat-hit', {
anchorX: 0.5,
anchorY: 0.5,
scaleX: 2,
scaleY: 2
});
self.catHitGraphics.visible = false;
self.isHitMode = false;
self.hitTimer = 0;
self.catBlockGraphics = self.attachAsset('cat-block', {
anchorX: 0.5,
anchorY: 0.5,
scaleX: 2,
scaleY: 2
});
self.catBlockGraphics.visible = false;
self.isBlockMode = false;
self.blockTimer = 0;
self.isFloating = false;
self.floatingTimer = 0;
self.isRunningFromDog = false;
self.runningTimer = 0;
self.originalSpeed = self.normalSpeed;
self.gatoBailaGraphics = self.attachAsset('gatoBaila', {
anchorX: 0.5,
anchorY: 1,
// Use bottom anchor for proper grounding during dance
scaleX: 2,
scaleY: 2,
y: 200
});
self.gatoBailaGraphics.visible = false;
self.isDancing = false;
// Dance flip variables
self.danceFlipTimer = 0;
self.danceFlipDirection = 1;
self.lastDownwardJumpTime = 0;
self.downwardJumpProtection = 30; // 0.5 seconds at 60fps
self.activateZarpazo = function (skipKiss) {
LK.getSound('zarpazo').play();
if (self.isZarpazoMode || self.isKissMode) {
return;
} // Already in zarpazo or kiss mode
self.isZarpazoMode = true;
// Stop movement during zarpazo
var originalSpeed = self.speed;
self.speed = 0;
// Create zarpazo graphics if not exists
if (!self.zarpazoGraphics) {
self.zarpazoGraphics = self.attachAsset('zarpazo', {
anchorX: 0.5,
anchorY: 0.5,
scaleX: 2,
scaleY: 2
});
}
// Hide all other cat graphics - only show zarpazo
catGraphics.visible = false;
catStepGraphics.visible = false;
self.catJumpGraphics.visible = false;
self.catElectrocutedGraphics.visible = false;
self.gatoEnjabonado.visible = false;
self.gatoKissGraphics.visible = false;
// Show only zarpazo graphics
self.zarpazoGraphics.visible = true;
self.zarpazoGraphics.scaleX = 2 * self.direction;
self.zarpazoGraphics.scaleY = 2;
LK.getSound('zarpazo').play();
// Return to normal after zarpazo
tween.stop(self, {
isZarpazoMode: true
}); // Stop any existing zarpazo tween
LK.setTimeout(function () {
self.isZarpazoMode = false;
// Only show kiss if skipKiss is not true
if (!skipKiss) {
self.isKissMode = true;
// Hide zarpazo and show kiss
if (self.zarpazoGraphics) {
self.zarpazoGraphics.visible = false;
}
self.gatoKissGraphics.visible = true;
self.gatoKissGraphics.scaleX = 2 * self.direction;
self.gatoKissGraphics.scaleY = 2;
// Play kiss sound when entering kiss mode
LK.getSound('gato-kiss').play();
// After kiss, return to normal walking
LK.setTimeout(function () {
self.isKissMode = false;
self.gatoKissGraphics.visible = false;
catGraphics.visible = true;
// Restore movement speed
self.speed = originalSpeed;
}, 330); // Kiss lasts 0.33 seconds (33% less than original)
} else {
// Skip kiss and return directly to normal walking
if (self.zarpazoGraphics) {
self.zarpazoGraphics.visible = false;
}
catGraphics.visible = true;
// Restore movement speed
self.speed = originalSpeed;
}
}, 300); // Reduced zarpazo duration from 500ms to 300ms
};
self.activateBubble = function (duration) {
if (self.isInBubble) {
return; // Already in bubble
}
// Clear all other states first
self.isFloating = false;
self.isSlipping = false;
self.isElectrocuted = false;
self.isZarpazoMode = false;
self.isKissMode = false;
self.isHitMode = false;
self.isBlockMode = false;
self.isJumping = false;
// Set bubble state
self.isInBubble = true;
self.bubbleTimer = duration || 600; // Default 10 seconds at 60fps
self.originalTargetShelf = self.targetShelfLevel;
// Stop any existing movement tweens
tween.stop(self, {
y: true
});
// Initialize bubble movement variables
self.bubbleFloatSpeed = -4;
self.soapWaveTime = 0;
self.soapBaseX = self.x;
self.soapWaveSpeedX = 0.05 + Math.random() * 0.03;
self.soapWaveSpeedY = 0.04 + Math.random() * 0.02;
self.soapAmplitudeX = 20 + Math.random() * 15;
self.soapAmplitudeY = 10 + Math.random() * 8;
// Immediately hide ALL cat assets first to prevent overlap
for (var c = 0; c < self.children.length; c++) {
self.children[c].visible = false;
}
// Then show only gatoEnjabonado
self.gatoEnjabonado.visible = true;
// Visual effect when bubble starts
LK.effects.flashObject(self, 0x87CEEB, 300);
};
self.update = function () {
// Move towards target shelf level with dynamic jumping animation
var targetY = shelfLevels[self.targetShelfLevel] - 208; // Position to stand on shelf - raised by 30px
if (Math.abs(self.y - targetY) > 5) {
// Check if we need to start a new jump animation - but not if electrocuted or hair standing up
// Also prevent consecutive downward jumps within protection period
var isDownwardJump = targetY > self.y;
var timeSinceLastDownwardJump = LK.ticks - self.lastDownwardJumpTime;
var canJumpDown = !isDownwardJump || timeSinceLastDownwardJump >= self.downwardJumpProtection;
if (!self.isJumping && !self.isElectrocuted && !self.isInBubble && canJumpDown) {
self.isJumping = true;
var jumpDistance = targetY - self.y;
var jumpDuration = Math.abs(jumpDistance) * 0.8; // Duration based on distance
// Stop any existing tween
tween.stop(self, {
y: true
});
// Create dynamic jump with bounce effect
if (self.y < targetY) {
// Jumping down - show cat-jump tilted downward
// Record time of downward jump for protection
self.lastDownwardJumpTime = LK.ticks;
catGraphics.visible = false;
self.catJumpGraphics.visible = true;
self.catJumpGraphics.rotation = self.direction > 0 ? 0.5 : -0.5; // Tilt downward for jumping down, consider direction
self.catJumpGraphics.scaleX = self.direction > 0 ? 2 : -2;
// Jumping down - faster with bounce landing
tween(self, {
y: targetY
}, {
duration: jumpDuration,
easing: tween.linear,
onFinish: function onFinish() {
self.y = targetY;
self.currentShelfLevel = self.targetShelfLevel;
// Switch back to normal cat after landing
self.catJumpGraphics.visible = false;
self.catJumpGraphics.rotation = 0;
catGraphics.visible = true;
// Add bounce effect when landing - move down and up a few pixels
tween(self, {
y: self.y + 15
}, {
duration: 150,
easing: tween.easeOut,
onFinish: function onFinish() {
tween(self, {
y: self.y - 15
}, {
duration: 100,
easing: tween.bounceOut
});
}
});
self.isJumping = false;
}
});
} else {
// Jumping up - show cat-jump tilted upward and squeeze first for momentum
catGraphics.visible = false;
self.catJumpGraphics.visible = true;
self.catJumpGraphics.rotation = self.direction > 0 ? -0.5 : 0.5; // Tilt upward for jumping up, consider direction
self.catJumpGraphics.scaleX = self.direction > 0 ? 2 : -2;
// First squeeze to take impulse
tween(self.catJumpGraphics, {
scaleX: (self.direction > 0 ? 2 : -2) * 1.3,
scaleY: 2 * 0.7
}, {
duration: jumpDuration * 0.3,
easing: tween.easeIn,
onFinish: function onFinish() {
// Then jump with normal scale
tween(self.catJumpGraphics, {
scaleX: self.direction > 0 ? 2 : -2,
scaleY: 2
}, {
duration: 100,
easing: tween.easeOut
});
// Actual jump movement
tween(self, {
y: targetY
}, {
duration: jumpDuration * 1.2,
easing: tween.easeOut,
onFinish: function onFinish() {
self.y = targetY;
self.currentShelfLevel = self.targetShelfLevel;
self.isJumping = false;
// Switch back to normal cat after landing
self.catJumpGraphics.visible = false;
self.catJumpGraphics.rotation = 0;
catGraphics.visible = true;
}
});
}
});
}
}
} else {
self.y = targetY;
self.currentShelfLevel = self.targetShelfLevel;
self.isJumping = false;
}
// Laser mode removed
// Handle walking animation - alternate between cat and cat-step every 15 frames (0.25 seconds)
self.walkAnimTimer++;
if (self.walkAnimTimer >= 15) {
self.walkAnimTimer = 0;
self.isWalkAnimStep = !self.isWalkAnimStep;
// Only show walking animation when cat is moving and not in special states (including bubble and floating)
var showWalkAnim = !self.isElectrocuted && !self.isSlipping && !self.isJumping && !self.isZarpazoMode && !self.isInBubble && !self.isFloating;
if (showWalkAnim) {
if (self.isWalkAnimStep) {
catGraphics.visible = false;
catStepGraphics.visible = true;
} else {
catGraphics.visible = true;
catStepGraphics.visible = false;
}
} else if (!self.isJumping && !self.isInBubble && !self.isFloating) {
// Show normal cat when not walking or in special states (but not when jumping, in bubble, or floating)
catGraphics.visible = true;
catStepGraphics.visible = false;
}
// When jumping, ensure only cat-jump is visible
if (self.isJumping) {
catGraphics.visible = false;
catStepGraphics.visible = false;
// cat-jump visibility is handled in the jumping animation logic above
}
// When in bubble, hide ALL other animations - only show gatoEnjabonado
if (self.isInBubble) {
// Hide all assets first to prevent overlap
for (var c = 0; c < self.children.length; c++) {
self.children[c].visible = false;
}
// Only show the soapy/bubble cat
self.gatoEnjabonado.visible = true;
}
// When in zarpazo mode, hide all other animations
if (self.isZarpazoMode) {
// Hide all assets first to prevent overlap
for (var c = 0; c < self.children.length; c++) {
self.children[c].visible = false;
}
// Only show zarpazo graphics
if (self.zarpazoGraphics) {
self.zarpazoGraphics.visible = true;
}
}
// When in kiss mode, hide all other animations
if (self.isKissMode) {
// Hide all assets first to prevent overlap
for (var c = 0; c < self.children.length; c++) {
self.children[c].visible = false;
}
// Only show kiss graphics
self.gatoKissGraphics.visible = true;
}
// When in hit mode, hide all other animations
if (self.isHitMode) {
catGraphics.visible = false;
catStepGraphics.visible = false;
self.catJumpGraphics.visible = false;
if (self.catElectrocutedGraphics) {
self.catElectrocutedGraphics.visible = false;
}
self.gatoEnjabonado.visible = false;
if (self.zarpazoGraphics) {
self.zarpazoGraphics.visible = false;
}
self.gatoKissGraphics.visible = false;
if (self.catBlockGraphics) {
self.catBlockGraphics.visible = false;
}
self.catHitGraphics.visible = true;
}
// When in block mode, hide all other animations
if (self.isBlockMode) {
catGraphics.visible = false;
catStepGraphics.visible = false;
self.catJumpGraphics.visible = false;
if (self.catElectrocutedGraphics) {
self.catElectrocutedGraphics.visible = false;
}
self.gatoEnjabonado.visible = false;
if (self.zarpazoGraphics) {
self.zarpazoGraphics.visible = false;
}
self.gatoKissGraphics.visible = false;
self.catHitGraphics.visible = false;
self.gatoBailaGraphics.visible = false;
self.catBlockGraphics.visible = true;
}
// When dancing, hide all other animations and show dance
if (self.isDancing) {
// Hide all assets first to prevent overlap
for (var c = 0; c < self.children.length; c++) {
self.children[c].visible = false;
}
// Only show dance graphics
self.gatoBailaGraphics.visible = true;
// Advanced dancing animation with multiple dance moves
var beatTime = LK.ticks * 0.15; // Main beat
var fastBeat = LK.ticks * 0.4; // Fast beat for quick movements
var slowBeat = LK.ticks * 0.08; // Slow beat for direction changes
// Multi-layered scale animation for dancing effect
var baseScale = 2;
var bounceScale = Math.sin(beatTime) * 0.4; // Main bounce
var quickPulse = Math.sin(fastBeat) * 0.15; // Quick pulse
var breathe = Math.sin(slowBeat) * 0.1; // Breathing effect
// X and Y scale with different patterns for asymmetric dance
var scaleX = baseScale + bounceScale + quickPulse;
var scaleY = baseScale + bounceScale * 0.7 + breathe; // Different Y movement
// Dance flip animation - follow swipe-like direction changes (right-left-right-left)
self.danceFlipTimer++;
if (self.danceFlipTimer >= 30) {
// Flip every 30 ticks (0.5 seconds) for more rhythmic dancing
self.danceFlipDirection = -self.danceFlipDirection;
self.danceFlipTimer = 0;
// Add directional tween animation when changing direction during dance
tween(self.gatoBailaGraphics, {
scaleX: Math.abs(self.gatoBailaGraphics.scaleX) * self.danceFlipDirection * 1.1
}, {
duration: 150,
easing: tween.bounceOut,
onFinish: function onFinish() {
tween(self.gatoBailaGraphics, {
scaleX: Math.abs(self.gatoBailaGraphics.scaleX) * self.danceFlipDirection
}, {
duration: 100,
easing: tween.easeOut
});
}
});
}
// Add random Y-axis flips during dance
if (LK.ticks % 180 === 0 && Math.random() < 0.4) {
// 40% chance every 3 seconds to do Y-axis flip
tween(self.gatoBailaGraphics, {
scaleY: -self.gatoBailaGraphics.scaleY
}, {
duration: 300,
easing: tween.bounceOut,
onFinish: function onFinish() {
// Flip back after a moment
tween(self.gatoBailaGraphics, {
scaleY: Math.abs(self.gatoBailaGraphics.scaleY)
}, {
duration: 400,
easing: tween.bounceOut
});
}
});
}
// Apply scale with flip direction
self.gatoBailaGraphics.scaleX = scaleX * self.danceFlipDirection;
self.gatoBailaGraphics.scaleY = scaleY;
// No rotation - keep cat upright, only horizontal flips for dancing
self.gatoBailaGraphics.rotation = 0;
// Add slight vertical bobbing for dance effect - positioned 70px lower (20px more than before)
var danceBob = Math.sin(beatTime * 1.8) * 8;
self.gatoBailaGraphics.y = danceBob + 70;
// Occasional dramatic scale changes and Y-axis flips for dance highlights
if (LK.ticks % 240 === 0) {
// Every 4 seconds - perform Y-axis flip
tween(self.gatoBailaGraphics, {
scaleX: scaleX * self.danceFlipDirection * 1.5,
scaleY: -scaleY * 1.3
}, {
duration: 200,
easing: tween.elasticOut,
onFinish: function onFinish() {
// Flip back to normal orientation
tween(self.gatoBailaGraphics, {
scaleX: scaleX * self.danceFlipDirection,
scaleY: scaleY
}, {
duration: 200,
easing: tween.elasticOut
});
}
});
}
}
}
// Update graphics direction based on movement direction
if (self.direction > 0) {
catGraphics.scaleX = 2;
catStepGraphics.scaleX = 2;
if (self.catElectrocutedGraphics) {
self.catElectrocutedGraphics.scaleX = 2;
}
if (self.zarpazoGraphics) {
self.zarpazoGraphics.scaleX = 2;
}
if (self.gatoEnjabonado) {
self.gatoEnjabonado.scaleX = 2;
}
if (self.catJumpGraphics) {
self.catJumpGraphics.scaleX = 2;
}
if (self.gatoKissGraphics) {
self.gatoKissGraphics.scaleX = 2;
}
if (self.catHitGraphics) {
self.catHitGraphics.scaleX = 2;
}
if (self.catBlockGraphics) {
self.catBlockGraphics.scaleX = 2;
}
if (self.gatoBailaGraphics) {
self.gatoBailaGraphics.scaleX = 2;
}
} else {
catGraphics.scaleX = -2;
catStepGraphics.scaleX = -2;
if (self.catElectrocutedGraphics) {
self.catElectrocutedGraphics.scaleX = -2;
}
if (self.zarpazoGraphics) {
self.zarpazoGraphics.scaleX = -2;
}
if (self.gatoEnjabonado) {
self.gatoEnjabonado.scaleX = -2;
}
if (self.catJumpGraphics) {
self.catJumpGraphics.scaleX = -2;
}
if (self.gatoKissGraphics) {
self.gatoKissGraphics.scaleX = -2;
}
if (self.catHitGraphics) {
self.catHitGraphics.scaleX = -2;
}
if (self.catBlockGraphics) {
self.catBlockGraphics.scaleX = -2;
}
if (self.gatoBailaGraphics) {
self.gatoBailaGraphics.scaleX = -2;
}
}
// Handle hit timer countdown
if (self.isHitMode) {
self.hitTimer--;
if (self.hitTimer <= 0) {
// Recover from hit mode
self.isHitMode = false;
self.catHitGraphics.visible = false;
catGraphics.visible = true;
// Restore movement speed
self.speed = self.normalSpeed;
}
}
// Handle block timer countdown
if (self.isBlockMode) {
self.blockTimer--;
if (self.blockTimer <= 0) {
// Recover from block mode
self.isBlockMode = false;
self.catBlockGraphics.visible = false;
catGraphics.visible = true;
// Restore movement speed
self.speed = self.normalSpeed;
}
}
// Handle horizontal movement when not electrocuted, slipping, in bubble, in zarpazo, kiss, hit, block mode, or running from dog
if (!self.isElectrocuted && (!self.isSlipping || self.slipTimer % 30 !== 0) && !self.isInBubble && !self.isZarpazoMode && !self.isKissMode && !self.isHitMode && !self.isBlockMode && !self.isRunningFromDog) {
var newX = self.x + self.speed * self.direction;
// Check if cat reaches right edge of screen (not world boundary)
var rightScreenEdge = cameraX + 2048;
if (newX >= rightScreenEdge) {
// Cat stops responding when reaching right edge of screen
self.speed = 0;
self.x = rightScreenEdge;
return;
}
// Check for barrier blocking before moving
var wouldBeBlocked = false;
for (var i = separators.length - 1; i >= 0; i--) {
var separator = separators[i];
// Calculate which shelf level the separator is on
var sepShelfLevel = -1;
for (var level = 0; level < 5; level++) {
if (Math.abs(separator.y - (shelfLevels[level] - 150)) < 50) {
sepShelfLevel = level;
break;
}
}
// Check if separator would block movement on same shelf level
if (separator.isBlocking && sepShelfLevel === self.currentShelfLevel) {
var distanceToSeparator = Math.abs(newX - separator.x);
// Check collision from both directions with proper blocking distance
if (distanceToSeparator < 120 && (self.direction > 0 && newX > separator.x - 60 && self.x <= separator.x - 60 || self.direction < 0 && newX < separator.x + 60 && self.x >= separator.x + 60)) {
wouldBeBlocked = true;
break;
}
}
}
if (wouldBeBlocked && !self.isBlockMode) {
// Push cat away from barrier by 150 pixels to ensure complete exit from collision zone
var pushDirection = self.x > separator.x ? 1 : -1;
var pushDistance = 150; // Increased from 30 to 150 pixels
var targetX = self.x + pushDistance * pushDirection;
// Ensure target position is within game bounds
targetX = Math.max(200, Math.min(targetX, 9600));
// Stop any existing movement tweens on cat
tween.stop(self, {
x: true
});
// Push cat away from barrier with stronger force
tween(self, {
x: targetX
}, {
duration: 200,
easing: tween.easeOut
});
// Enter block mode when stuck against barrier
self.isBlockMode = true;
self.blockTimer = 180; // 3 seconds at 60fps
// Stop movement during block
self.speed = 0;
// Show only cat-block graphics
catGraphics.visible = false;
catStepGraphics.visible = false;
self.catJumpGraphics.visible = false;
self.catElectrocutedGraphics.visible = false;
self.gatoEnjabonado.visible = false;
self.gatoKissGraphics.visible = false;
self.catHitGraphics.visible = false;
if (self.zarpazoGraphics) {
self.zarpazoGraphics.visible = false;
}
self.catBlockGraphics.visible = true;
self.catBlockGraphics.scaleX = 2 * self.direction;
self.catBlockGraphics.scaleY = 2;
} else if (!wouldBeBlocked) {
// Constrain cat movement within reduced world boundaries (24 sections * 400px = 9600px)
// Allow some buffer on both sides for smooth movement
self.x = Math.max(-50, Math.min(newX, 9650)); // Keep cat within reduced world bounds
}
}
// Handle uncontrolled running movement when fleeing from dog
if (self.isRunningFromDog && !self.isElectrocuted && !self.isInBubble && !self.isZarpazoMode && !self.isKissMode && !self.isHitMode && !self.isBlockMode) {
var newX = self.x + self.speed * self.direction;
// Check if cat reaches right edge of screen (not world boundary)
var rightScreenEdge = cameraX + 2048;
if (newX >= rightScreenEdge) {
// Cat stops running when reaching right edge of screen
self.isRunningFromDog = false;
self.runningTimer = 0;
self.speed = self.originalSpeed || self.normalSpeed;
self.x = rightScreenEdge;
return;
}
// Check for barrier blocking before moving, but continue running with reduced speed
var wouldBeBlocked = false;
for (var i = separators.length - 1; i >= 0; i--) {
var separator = separators[i];
// Calculate which shelf level the separator is on
var sepShelfLevel = -1;
for (var level = 0; level < 5; level++) {
if (Math.abs(separator.y - (shelfLevels[level] - 150)) < 50) {
sepShelfLevel = level;
break;
}
}
// Check if separator would block movement on same shelf level
if (separator.isBlocking && sepShelfLevel === self.currentShelfLevel) {
var distanceToSeparator = Math.abs(newX - separator.x);
// Check collision from both directions with proper blocking distance
if (distanceToSeparator < 120 && (self.direction > 0 && newX > separator.x - 60 && self.x <= separator.x - 60 || self.direction < 0 && newX < separator.x + 60 && self.x >= separator.x + 60)) {
wouldBeBlocked = true;
break;
}
}
}
if (wouldBeBlocked) {
// When running from dog, try to jump over obstacles or change direction
if (Math.random() < 0.3) {
// 30% chance to jump
if (self.currentShelfLevel > 0) {
self.targetShelfLevel = self.currentShelfLevel - 1; // Jump up
} else if (self.currentShelfLevel < 4) {
self.targetShelfLevel = self.currentShelfLevel + 1; // Jump down
}
} else {
// Change running direction when blocked
self.direction = -self.direction;
newX = self.x + self.speed * self.direction;
}
}
// Constrain cat movement within world boundaries when running
self.x = Math.max(-50, Math.min(newX, 9650)); // Keep cat within world bounds
}
for (var i = shelfObjects.length - 1; i >= 0; i--) {
var obj = shelfObjects[i];
if (self.intersects(obj) && !obj.isFalling && !self.isJumping) {
obj.startFalling();
// Update objects knocked down counter based on objects that are NOT falling
var actualObjectsRemaining = 0;
for (var j = 0; j < shelfObjects.length; j++) {
if (!shelfObjects[j].isFalling) {
actualObjectsRemaining++;
}
}
objectsKnockedDown = totalObjectsToKnock - actualObjectsRemaining;
storage.objectsKnockedDown = objectsKnockedDown;
// Check if all objects have been knocked down
if (actualObjectsRemaining <= 0) {
// Calculate stage score based on remaining time and penalties
var remainingSeconds = Math.max(0, Math.ceil((TIME_LIMIT - gameTimer) / 60));
var stageScore = remainingSeconds * 10 - obstaclePenalties; // 10 points per remaining second minus penalties
stageScore = Math.max(stageScore, 0); // Ensure score doesn't go negative
// Add stage score to total
finalScore += stageScore;
LK.setScore(finalScore);
// Stop the game timer to prevent time-based game over
gameTimer = TIME_LIMIT;
// Activate dancing mode for cat
self.isDancing = true;
// Reset dance flip variables for consistent start
self.danceFlipTimer = 0;
self.danceFlipDirection = 1;
// Stop main theme music when dancing starts
LK.stopMusic();
// Stop cat movement during victory dance
self.speed = 0;
// Stop all cat behaviors
self.isElectrocuted = false;
self.isSlipping = false;
self.isFloating = false;
self.isZarpazoMode = false;
self.isKissMode = false;
self.isHitMode = false;
self.isBlockMode = false;
// Drop a bowling ball when dancing starts
var bowlingBall = new ShelfObject(1); // Use object type 1 as bowling ball
bowlingBall.x = self.x;
bowlingBall.y = self.y - 100; // Start above cat
bowlingBall.startFalling();
game.addChild(bowlingBall);
shelfObjects.push(bowlingBall);
// Play success song
LK.getSound('successSong').play();
// Check if this is the final stage
if (currentStage >= maxStages) {
// Final victory - show you win after dance
LK.setTimeout(function () {
// Player wins when all stages completed - reset storage for new game
storage.totalObjectsToKnock = 0;
storage.objectsKnockedDown = 0;
// Show level complete message
LK.showYouWin();
}, 4000); // Wait 4 seconds to let cat dance longer before victory
} else {
// Move to next stage after dance
LK.setTimeout(function () {
// Advance to next stage
currentStage++;
// Reset for next stage
setupStage(currentStage);
}, 4000); // Wait 4 seconds to let cat dance
}
return;
}
// Play random knock sound
var soundId = 'knock' + (Math.floor(Math.random() * 3) + 1);
LK.getSound(soundId).play();
// Activate zarpazo mode when knocking objects
self.activateZarpazo();
}
}
// Check for spider collision when cat passes through upper level
for (var i = dangerousObjects.length - 1; i >= 0; i--) {
var dangerousObj = dangerousObjects[i];
// Calculate which shelf level the dangerous object is on
var objShelfLevel = -1;
for (var level = 0; level < 5; level++) {
if (Math.abs(dangerousObj.y - (shelfLevels[level] - 75)) < 50) {
objShelfLevel = level;
break;
}
}
// Check if cat passes through the upper level above spiders (spiders drop when cat is above)
if (!dangerousObj.isFalling && objShelfLevel > 0 && self.currentShelfLevel === objShelfLevel - 1) {
// Cat is on the shelf level directly above the spider
var horizontalDistance = Math.abs(self.x - dangerousObj.x);
// Check if cat passes horizontally over the spider (within 150px range)
if (horizontalDistance < 150) {
// Trigger spider fall with tween animation
dangerousObj.startFalling();
// Play spider scream sound when it falls
LK.getSound('grito-arania').play();
// Cat does zarpazo when spider falls but no kiss
self.activateZarpazo(true); // Pass true to skip kiss when throwing spider
// Add visual effect for spider drop trigger
tween(dangerousObj, {
scaleX: 1.2,
scaleY: 1.2
}, {
duration: 200,
easing: tween.easeOut,
onFinish: function onFinish() {
tween(dangerousObj, {
scaleX: 1,
scaleY: 1
}, {
duration: 150,
easing: tween.easeOut
});
}
});
}
}
}
// Check for dog proximity and trigger running behavior
var closestDog = null;
var closestDistance = Infinity;
for (var i = dogs.length - 1; i >= 0; i--) {
var dog = dogs[i];
// Calculate which shelf level the dog is on
var dogShelfLevel = -1;
for (var level = 0; level < 5; level++) {
if (Math.abs(dog.y - (shelfLevels[level] - 75)) < 50) {
dogShelfLevel = level;
break;
}
}
// Check distance to dog on same shelf level
if (dogShelfLevel === self.currentShelfLevel) {
var distanceToDog = Math.abs(self.x - dog.x);
if (distanceToDog < closestDistance) {
closestDistance = distanceToDog;
closestDog = dog;
}
}
// Only collide if on same shelf level - no more automatic dog removal
if (self.intersects(dog)) {
if (!self.isHitMode && !self.isInvulnerable && !self.isJumping && dogShelfLevel === self.currentShelfLevel) {
// Dog catches the cat - automatic retreat 80px
LK.getSound('dogBark').play();
LK.getSound('catFall').play();
LK.effects.flashScreen(0xff0000, 500);
obstaclePenalties += 15; // Add penalty for being knocked down by dog
// Automatically retreat cat 80px away from dog
var retreatDirection = self.x > dog.x ? 1 : -1;
var retreatDistance = 80;
var targetX = self.x + retreatDistance * retreatDirection;
// Ensure target position is within game bounds
targetX = Math.max(200, Math.min(targetX, 9600));
// Stop any existing movement tweens on cat
tween.stop(self, {
x: true
});
// Make cat retreat automatically
tween(self, {
x: targetX
}, {
duration: 300,
easing: tween.easeOut
});
// Enter hit mode
self.isHitMode = true;
self.hitTimer = 180; // 3 seconds at 60fps
// Stop movement during hit
self.speed = 0;
// Show only cat-hit graphics
catGraphics.visible = false;
catStepGraphics.visible = false;
self.catJumpGraphics.visible = false;
self.catElectrocutedGraphics.visible = false;
self.gatoEnjabonado.visible = false;
self.gatoKissGraphics.visible = false;
if (self.zarpazoGraphics) {
self.zarpazoGraphics.visible = false;
}
self.catHitGraphics.visible = true;
self.catHitGraphics.scaleX = 2 * self.direction;
self.catHitGraphics.scaleY = 2;
}
}
}
// Trigger uncontrolled running when dog is on same level or nearby
if (closestDog && closestDistance < 600) {
// Initialize running state if not already running
if (!self.isRunningFromDog) {
self.isRunningFromDog = true;
self.runningTimer = 0;
self.originalSpeed = self.speed;
}
// Cat runs uncontrollably away from dog - much more intense when on same level
var dogDirection = closestDog.x > self.x ? 1 : -1;
self.direction = -dogDirection; // Run away from dog
// Check if dog and cat are on same level for more intense running
var dogShelfLevel = -1;
for (var level = 0; level < 5; level++) {
if (Math.abs(closestDog.y - (shelfLevels[level] - 75)) < 50) {
dogShelfLevel = level;
break;
}
}
if (dogShelfLevel === self.currentShelfLevel && closestDistance < 400) {
// Much faster and more uncontrolled when on same level
self.speed = self.normalSpeed * 4.0; // Very fast uncontrolled running
// More frequent and dramatic running animations
if (LK.ticks % 10 === 0) {
// Every 1/6 second - more frequent
tween(self, {
scaleX: Math.abs(self.scaleX || 1) * 1.4,
scaleY: (self.scaleY || 1) * 0.7
}, {
duration: 80,
easing: tween.easeOut,
onFinish: function onFinish() {
tween(self, {
scaleX: Math.abs(self.scaleX || 1) / 1.4,
scaleY: (self.scaleY || 1) / 0.7
}, {
duration: 80,
easing: tween.easeOut
});
}
});
}
} else {
// Normal running speed when not on same level
self.speed = self.normalSpeed * 2.5; // Standard running speed
// Standard running animation
if (LK.ticks % 20 === 0) {
// Every 1/3 second
tween(self, {
scaleX: Math.abs(self.scaleX || 1) * 1.2,
scaleY: (self.scaleY || 1) * 0.9
}, {
duration: 100,
easing: tween.easeOut,
onFinish: function onFinish() {
tween(self, {
scaleX: Math.abs(self.scaleX || 1) / 1.2,
scaleY: (self.scaleY || 1) / 0.9
}, {
duration: 100,
easing: tween.easeOut
});
}
});
}
}
self.runningTimer++;
// Stop running after getting far enough away or after time limit
if (closestDistance > 800 || self.runningTimer > 400) {
// 6.67 seconds max (increased from 5 seconds)
self.isRunningFromDog = false;
self.runningTimer = 0;
self.speed = self.originalSpeed || self.normalSpeed;
}
} else if (self.isRunningFromDog && (!closestDog || closestDistance >= 600)) {
// Stop running if no dog is close enough
self.isRunningFromDog = false;
self.runningTimer = 0;
self.speed = self.originalSpeed || self.normalSpeed;
}
// Check if cat reaches right world boundary and trigger block mode with pushback
if (self.x >= 9500 && !self.isBlockMode) {
// Push cat away from boundary by 150 pixels to ensure complete exit from collision zone
var pushDirection = -1; // Always push left from right boundary
var pushDistance = 150; // Increased from 30 to 150 pixels
var targetX = self.x + pushDistance * pushDirection;
// Ensure target position is within game bounds
targetX = Math.max(200, Math.min(targetX, 9600));
// Stop any existing movement tweens on cat
tween.stop(self, {
x: true
});
// Push cat away from boundary
tween(self, {
x: targetX
}, {
duration: 200,
easing: tween.easeOut
});
// Enter block mode when reaching right boundary barriers
self.isBlockMode = true;
self.blockTimer = 60; // 1 second at 60fps (reduced from 180)
// Stop movement during block
self.speed = 0;
// Show only cat-block graphics
catGraphics.visible = false;
catStepGraphics.visible = false;
self.catJumpGraphics.visible = false;
self.catElectrocutedGraphics.visible = false;
self.gatoEnjabonado.visible = false;
self.gatoKissGraphics.visible = false;
self.catHitGraphics.visible = false;
if (self.zarpazoGraphics) {
self.zarpazoGraphics.visible = false;
}
self.catBlockGraphics.visible = true;
self.catBlockGraphics.scaleX = 2 * self.direction;
self.catBlockGraphics.scaleY = 2;
}
// Check if cat reaches left world boundary and lose life
if (!self.isInvulnerable && self.x <= -150) {
// Cat reaches left world limit and loses a life
self.isInvulnerable = true;
self.invulnerabilityTimer = 120; // 2 seconds of invulnerability
obstaclePenalties += 25; // Add penalty for losing a life
LK.getSound('catFall').play();
LK.effects.flashScreen(0xff0000, 1000);
// Dramatic fall animation
tween(self, {
y: 2732 + 200 // Fall off screen bottom
}, {
duration: 1000,
easing: tween.easeIn,
onFinish: function onFinish() {
// Reset cat position after fall - keep at horizontal center
self.x = 1024;
self.y = shelfLevels[2] - 208;
self.targetShelfLevel = 2;
self.currentShelfLevel = 2;
}
});
}
// Check for collisions with separators and barriers - only on same shelf level
for (var i = separators.length - 1; i >= 0; i--) {
var separator = separators[i];
// Calculate which shelf level the separator is on
var sepShelfLevel = -1;
for (var level = 0; level < 5; level++) {
if (Math.abs(separator.y - (shelfLevels[level] - 150)) < 50) {
sepShelfLevel = level;
break;
}
}
// Only collide if on same shelf level
if (self.intersects(separator) && separator.isBlocking && sepShelfLevel === self.currentShelfLevel && !self.isBlockMode && !self.isJumping) {
// Push cat away from separator by 150 pixels to ensure complete exit from collision zone
var pushDirection = self.x > separator.x ? 1 : -1;
var pushDistance = 150; // Increased from 30 to 150 pixels
var targetX = self.x + pushDistance * pushDirection;
// Ensure target position is within game bounds
targetX = Math.max(200, Math.min(targetX, 9600));
// Stop any existing movement tweens on cat
tween.stop(self, {
x: true
});
// Push cat away from separator
tween(self, {
x: targetX
}, {
duration: 200,
easing: tween.easeOut
});
// Enter block mode when hitting separator
self.isBlockMode = true;
self.blockTimer = 60; // 1 second at 60fps (reduced from 180)
// Stop movement during block
self.speed = 0;
// Show only cat-block graphics
catGraphics.visible = false;
catStepGraphics.visible = false;
self.catJumpGraphics.visible = false;
self.catElectrocutedGraphics.visible = false;
self.gatoEnjabonado.visible = false;
self.gatoKissGraphics.visible = false;
self.catHitGraphics.visible = false;
if (self.zarpazoGraphics) {
self.zarpazoGraphics.visible = false;
}
self.catBlockGraphics.visible = true;
self.catBlockGraphics.scaleX = 2 * self.direction;
self.catBlockGraphics.scaleY = 2;
}
}
// Check for collisions with left barriers - only on same shelf level
for (var i = leftBarriers.length - 1; i >= 0; i--) {
var leftBarrier = leftBarriers[i];
// Calculate which shelf level the left barrier is on
var barrierShelfLevel = -1;
for (var level = 0; level < 5; level++) {
if (Math.abs(leftBarrier.y - (shelfLevels[level] - 150)) < 50) {
barrierShelfLevel = level;
break;
}
}
// Only collide if on same shelf level
if (self.intersects(leftBarrier) && leftBarrier.isBlocking && barrierShelfLevel === self.currentShelfLevel && !self.isBlockMode && !self.isJumping) {
// Push cat away from left barrier by 150 pixels to ensure complete exit from collision zone
var pushDirection = 1; // Always push right from left barrier
var pushDistance = 150; // Increased from 30 to 150 pixels
var targetX = self.x + pushDistance * pushDirection;
// Ensure target position is within game bounds
targetX = Math.max(200, Math.min(targetX, 9600));
// Stop any existing movement tweens on cat
tween.stop(self, {
x: true
});
// Push cat away from barrier
tween(self, {
x: targetX
}, {
duration: 200,
easing: tween.easeOut
});
// Enter block mode when hitting left barrier
self.isBlockMode = true;
self.blockTimer = 60; // 1 second at 60fps
// Stop movement during block
self.speed = 0;
// Show only cat-block graphics
catGraphics.visible = false;
catStepGraphics.visible = false;
self.catJumpGraphics.visible = false;
self.catElectrocutedGraphics.visible = false;
self.gatoEnjabonado.visible = false;
self.gatoKissGraphics.visible = false;
self.catHitGraphics.visible = false;
if (self.zarpazoGraphics) {
self.zarpazoGraphics.visible = false;
}
self.catBlockGraphics.visible = true;
self.catBlockGraphics.scaleX = 2 * self.direction;
self.catBlockGraphics.scaleY = 2;
}
}
// Handle electrocution
if (self.isElectrocuted === undefined) {
self.isElectrocuted = false;
self.electrocutionTimer = 0;
}
if (self.isElectrocuted) {
self.electrocutionTimer--;
// Cat cannot move when electrocuted
self.speed = 0;
// Switch to electrocuted asset
catGraphics.visible = false;
catStepGraphics.visible = false;
self.catElectrocutedGraphics.visible = true;
// Electric flash effect on electrocuted graphics
var electricFlash = Math.sin(LK.ticks * 2) > 0;
self.catElectrocutedGraphics.tint = electricFlash ? 0x00FFFF : 0xFFFFFF;
self.catElectrocutedGraphics.alpha = 0.7 + Math.sin(LK.ticks * 1.5) * 0.3;
// Update scale to match direction
self.catElectrocutedGraphics.scaleX = self.direction > 0 ? 2 : -2;
self.catElectrocutedGraphics.scaleY = 2;
if (self.electrocutionTimer <= 0) {
self.isElectrocuted = false;
self.speed = self.isLaserMode ? self.laserSpeed : self.normalSpeed;
// Switch back to normal cat
catGraphics.visible = true;
catStepGraphics.visible = false;
self.catElectrocutedGraphics.visible = false;
catGraphics.tint = 0xFFFFFF;
catGraphics.alpha = 1;
}
}
// Handle soap slipping
if (self.isSlipping === undefined) {
self.isSlipping = false;
self.slipTimer = 0;
self.originalDirection = self.direction;
}
if (self.isSlipping) {
self.slipTimer--;
// Cat slides uncontrollably in random directions
if (self.slipTimer % 30 === 0) {
// Change direction every 0.5 seconds
self.direction = Math.random() < 0.5 ? 1 : -1;
}
// Slipping animation - cat tilts side to side
var tilt = Math.sin(LK.ticks * 0.4) * 0.3;
catGraphics.rotation = tilt;
catGraphics.alpha = 0.8; // Slightly transparent while slipping
if (self.slipTimer <= 0) {
self.isSlipping = false;
self.direction = self.originalDirection;
catGraphics.rotation = 0;
catGraphics.alpha = 1;
// Switch back to normal cat
self.gatoEnjabonado.visible = false;
catGraphics.visible = true;
catStepGraphics.visible = false;
}
}
// Handle lamp immunity timer
if (self.lampImmunity === undefined) {
self.lampImmunity = false;
self.lampImmunityTimer = 0;
}
if (self.lampImmunity) {
self.lampImmunityTimer--;
if (self.lampImmunityTimer <= 0) {
self.lampImmunity = false;
}
}
// Handle bubble floating mechanics
if (self.isInBubble === undefined) {
self.isInBubble = false;
self.bubbleTimer = 0;
self.bubbleFloatSpeed = -4; // Negative for upward movement - like a helium balloon
self.originalTargetShelf = self.targetShelfLevel;
}
if (self.isInBubble) {
self.bubbleTimer--;
// Complex wavy movement with multiple wave components
self.soapWaveTime += 1;
var primaryWaveX = Math.sin(self.soapWaveTime * self.soapWaveSpeedX) * self.soapAmplitudeX;
var secondaryWaveX = Math.cos(self.soapWaveTime * self.soapWaveSpeedX * 1.7) * (self.soapAmplitudeX * 0.4);
var primaryWaveY = Math.sin(self.soapWaveTime * self.soapWaveSpeedY) * self.soapAmplitudeY;
// Add some randomness for more organic movement
var randomDriftX = (Math.random() - 0.5) * 4;
var randomDriftY = (Math.random() - 0.5) * 2;
var verticalDrift = -2.5 - Math.random() * 1.5; // Upward drift
// Apply the wavy movement with more pronounced vertical oscillation
var targetX = self.soapBaseX + primaryWaveX + secondaryWaveX;
self.x += (targetX - self.x) * 0.02 + randomDriftX * 0.3;
// Increased vertical wave amplitude to about 20px up and down
var verticalWave = Math.sin(self.soapWaveTime * self.soapWaveSpeedY * 0.8) * 20;
self.y += verticalDrift + verticalWave * 0.15 + primaryWaveY * 0.05 + randomDriftY;
// Add rotation for more dramatic soap floating effect
self.gatoEnjabonado.rotation = Math.sin(LK.ticks * 0.05) * 0.3 + Math.cos(LK.ticks * 0.03) * 0.2;
// Ensure only bubble cat is visible
for (var c = 0; c < self.children.length; c++) {
self.children[c].visible = false;
}
self.gatoEnjabonado.visible = true;
// Scaling animation for floating effect
if (LK.ticks % 45 === 0) {
// Every 0.75 seconds
var scaleVariation = 0.9 + Math.random() * 0.2; // Random scale between 0.9-1.1
tween(self.gatoEnjabonado, {
scaleX: Math.abs(self.gatoEnjabonado.scaleX) * scaleVariation,
scaleY: self.gatoEnjabonado.scaleY * (1.1 + Math.random() * 0.1)
}, {
duration: 400 + Math.random() * 200,
easing: tween.easeInOut,
onFinish: function onFinish() {
tween(self.gatoEnjabonado, {
scaleX: self.direction > 0 ? 2 : -2,
scaleY: 2
}, {
duration: 300 + Math.random() * 200,
easing: tween.easeInOut
});
}
});
}
// Check which shelf level we're passing through and update target
for (var level = 4; level >= 0; level--) {
var shelfY = shelfLevels[level] - 208;
if (self.y <= shelfY + 50 && self.y >= shelfY - 50) {
self.targetShelfLevel = level;
break;
}
}
// Bubble bursts after timer expires
if (self.bubbleTimer <= 0) {
self.isInBubble = false;
// Stop all bubble tweens
tween.stop(self, {
y: true,
x: true
});
tween.stop(self.gatoEnjabonado, {
scaleX: true,
scaleY: true,
rotation: true
});
// Reset bubble asset
self.gatoEnjabonado.rotation = 0;
self.gatoEnjabonado.scaleX = self.direction > 0 ? 2 : -2;
self.gatoEnjabonado.scaleY = 2;
self.gatoEnjabonado.visible = false;
// Find nearest shelf level to current position
var nearestShelf = 0;
var minDistance = Math.abs(self.y - (shelfLevels[0] - 208));
for (var level = 1; level < 5; level++) {
var distance = Math.abs(self.y - (shelfLevels[level] - 208));
if (distance < minDistance) {
minDistance = distance;
nearestShelf = level;
}
}
// Land on nearest shelf with bounce effect
self.targetShelfLevel = nearestShelf;
self.currentShelfLevel = nearestShelf;
tween(self, {
y: shelfLevels[nearestShelf] - 208
}, {
duration: 800,
easing: tween.bounceOut,
onFinish: function onFinish() {
// Show normal cat
catGraphics.visible = true;
catGraphics.scaleY = Math.abs(catGraphics.scaleY);
catGraphics.scaleX = self.direction > 0 ? 2 : -2;
// Flash effect when landing
LK.effects.flashObject(self, 0x87CEEB, 500);
}
});
}
}
// Handle invulnerability timer
if (self.isInvulnerable) {
self.invulnerabilityTimer--;
// Flash effect during invulnerability (only if not electrocuted)
if (!self.isElectrocuted) {
catGraphics.alpha = Math.sin(LK.ticks * 0.5) * 0.5 + 0.5;
if (self.catElectrocutedGraphics) {
self.catElectrocutedGraphics.alpha = Math.sin(LK.ticks * 0.5) * 0.5 + 0.5;
}
}
if (self.invulnerabilityTimer <= 0) {
self.isInvulnerable = false;
if (!self.isElectrocuted) {
catGraphics.alpha = 1;
if (self.catElectrocutedGraphics) {
self.catElectrocutedGraphics.alpha = 1;
}
}
}
}
// Check for collisions with lamps - only on same shelf level
for (var i = lamps.length - 1; i >= 0; i--) {
var lamp = lamps[i];
// Calculate which shelf level the lamp is on
var lampShelfLevel = -1;
for (var level = 0; level < 5; level++) {
if (Math.abs(lamp.y - shelfLevels[level]) < 50) {
lampShelfLevel = level;
break;
}
}
// Only collide if on same shelf level and cat is not immune to lamp electrocution
if (self.intersects(lamp) && lampShelfLevel === self.currentShelfLevel && !self.isElectrocuted && !self.isJumping) {
// Electrocute cat for 2 seconds
self.isElectrocuted = true;
self.electrocutionTimer = 120; // 2 seconds at 60fps
obstaclePenalties += 15; // Add penalty for lamp electrocution
// Play electric shock sound
LK.getSound('electricShock').play();
// Flash screen blue/white for electric effect
LK.effects.flashScreen(0x00FFFF, 1000);
// Push cat away from lamp with stronger force to prevent getting stuck
var pushDirection = self.x > lamp.x ? 1 : -1;
var pushDistance = 250;
var targetX = self.x + pushDistance * pushDirection;
// Ensure target position is within game bounds
targetX = Math.max(200, Math.min(targetX, 9600));
// Stop any existing movement tweens on cat
tween.stop(self, {
x: true
});
// Make cat get pushed away with stronger force
tween(self, {
x: targetX
}, {
duration: 200,
easing: tween.easeOut,
onFinish: function onFinish() {
// Additional push to ensure separation
var secondPushX = targetX + pushDirection * 100;
secondPushX = Math.max(200, Math.min(secondPushX, 9600));
tween(self, {
x: secondPushX
}, {
duration: 150,
easing: tween.easeOut
});
}
});
}
}
// Check for soap collision - only on same shelf level and causes bubble floating
for (var i = soaps.length - 1; i >= 0; i--) {
var soap = soaps[i];
// Calculate which shelf level the soap is on
var soapShelfLevel = -1;
for (var level = 0; level < 5; level++) {
if (Math.abs(soap.y - (shelfLevels[level] - 20)) < 50) {
soapShelfLevel = level;
break;
}
}
// Only collide if on same shelf level
if (self.intersects(soap) && !soap.hasBeenUsed && !self.isInBubble && soapShelfLevel === self.currentShelfLevel && !self.isJumping) {
soap.hasBeenUsed = true;
// Play sounds
LK.getSound('soapSlip').play();
LK.getSound('bubble').play();
// Activate bubble mode
self.activateBubble(300); // 5 seconds at 60fps
// Visual effect - soap disappears with tween
tween(soap, {
alpha: 0,
scaleX: 0.1,
scaleY: 0.1
}, {
duration: 500,
easing: tween.easeOut,
onFinish: function onFinish() {
soap.destroy();
var index = soaps.indexOf(soap);
if (index > -1) {
soaps.splice(index, 1);
}
}
});
// Flash screen light blue for soap effect
LK.effects.flashScreen(0x87CEEB, 800);
break;
}
}
// Check for collisions with dangerous objects (spiders) - cat takes damage
for (var i = dangerousObjects.length - 1; i >= 0; i--) {
var dangerousObj = dangerousObjects[i];
// Calculate which shelf level the dangerous object is on
var dangerousObjShelfLevel = -1;
for (var level = 0; level < 5; level++) {
if (Math.abs(dangerousObj.y - (shelfLevels[level] - 75)) < 50) {
dangerousObjShelfLevel = level;
break;
}
}
// Only collide if on same shelf level and spider is not falling and cat is not in hit mode
if (self.intersects(dangerousObj) && !dangerousObj.isFalling && dangerousObjShelfLevel === self.currentShelfLevel && !self.isHitMode && !self.isInvulnerable && !self.isJumping) {
// Cat takes damage from spider
LK.getSound('catFall').play();
LK.effects.flashScreen(0xff0000, 500);
obstaclePenalties += 15; // Add penalty for being hit by spider
// Push cat away from spider to prevent getting stuck
var pushDirection = self.x > dangerousObj.x ? 1 : -1;
var pushDistance = 80; // Distance to retreat
var targetX = self.x + pushDistance * pushDirection;
// Ensure target position is within game bounds
targetX = Math.max(200, Math.min(targetX, 9600));
// Stop any existing movement tweens on cat
tween.stop(self, {
x: true
});
// Make cat retreat from spider
tween(self, {
x: targetX
}, {
duration: 300,
easing: tween.easeOut
});
// Enter hit mode
self.isHitMode = true;
self.hitTimer = 180; // 3 seconds at 60fps
// Stop movement during hit
self.speed = 0;
// Show only cat-hit graphics
catGraphics.visible = false;
catStepGraphics.visible = false;
self.catJumpGraphics.visible = false;
self.catElectrocutedGraphics.visible = false;
self.gatoEnjabonado.visible = false;
self.gatoKissGraphics.visible = false;
if (self.zarpazoGraphics) {
self.zarpazoGraphics.visible = false;
}
self.catHitGraphics.visible = true;
self.catHitGraphics.scaleX = 2 * self.direction;
self.catHitGraphics.scaleY = 2;
}
}
// Check for collisions with mice - cat can eat mouse
for (var i = mice.length - 1; i >= 0; i--) {
var mouse = mice[i];
// Calculate which shelf level the mouse is on
var mouseShelfLevel = -1;
for (var level = 0; level < 5; level++) {
if (Math.abs(mouse.y - (shelfLevels[level] - 75)) < 50) {
mouseShelfLevel = level;
break;
}
}
// Only collide if on same shelf level
if (self.intersects(mouse) && mouseShelfLevel === self.currentShelfLevel && !self.isJumping) {
// Cat eats mouse
LK.getSound('mouseSqueak').play();
LK.effects.flashObject(self, 0x00ff00, 500);
// Activate zarpazo mode when eating mouse
self.activateZarpazo();
// Remove mouse from game
mouse.destroy();
mice.splice(i, 1);
// Stop chasing behavior if this was the chase target
if (mouse === self.chaseTarget) {
self.isChasing = false;
self.chaseTarget = null;
}
}
}
// Laser system removed
};
return self;
});
var DangerousObject = Container.expand(function () {
var self = Container.call(this);
var dangerousGraphics = self.attachAsset('dangerousObject', {
anchorX: 0.5,
anchorY: 0,
scaleX: 4,
scaleY: 4,
y: -500
});
// Hitbox en la base para mantener colisión al nivel de repisa
var dangerousHitbox = self.attachAsset('dangerousHitbox', {
anchorX: 0.5,
anchorY: 1,
scaleX: 4,
scaleY: 4,
y: 0
});
dangerousHitbox.alpha = 0; // invisible
// Exponer hitbox para colisiones precisas
self.hitbox = dangerousHitbox;
self.isFalling = false;
self.fallSpeed = 0;
self.isDangerous = true;
self.pulseTimer = 0;
self.startFalling = function () {
self.isFalling = true;
self.fallSpeed = 2;
self.isDangerous = false; // Not dangerous when falling
// Change to falling asset
dangerousGraphics.visible = false;
// Create falling graphics if not exists
if (!self.fallingGraphics) {
self.fallingGraphics = self.attachAsset('dangerousObjectFall', {
anchorX: 0.5,
anchorY: 0.5,
scaleX: 4,
scaleY: 4
});
}
self.fallingGraphics.visible = true;
};
self.update = function () {
if (!self.isFalling) {
// Pulse effect to show it's dangerous
self.pulseTimer++;
var scale = 1 + Math.sin(self.pulseTimer * 0.15) * 0.1;
dangerousGraphics.scaleY = scale;
dangerousGraphics.scaleX = 1;
} else {
self.y += self.fallSpeed;
self.fallSpeed += 0.2; // Gravity
self.rotation += 0.1;
if (self.y > 2732 + 50) {
self.destroy();
var index = dangerousObjects.indexOf(self);
if (index > -1) {
dangerousObjects.splice(index, 1);
}
}
}
};
return self;
});
var Dog = Container.expand(function () {
var self = Container.call(this);
var dogGraphics = self.attachAsset('dog', {
anchorX: 0.5,
anchorY: 1,
scaleX: 4,
scaleY: 4
});
self.speed = 8; // Much faster dog movement
self.direction = 1;
self.alertRadius = 200;
self.pulseTimer = 0;
self.barkTimer = 0;
self.isBarkingOpen = false;
self.dogCloseGraphics = null;
self.isTweening = false; // Flag for smooth movement
self.update = function () {
// Check if dog is on screen for bark sound trigger
var isOnScreen = self.x >= cameraX - 100 && self.x <= cameraX + 2148;
var wasOnScreen = self.wasOnScreen !== undefined ? self.wasOnScreen : false;
// Play bark sound only when dog first appears on screen
if (!wasOnScreen && isOnScreen) {
LK.getSound('dogBark').play();
}
self.wasOnScreen = isOnScreen;
// Pulse effect to show dog is dangerous
self.pulseTimer++;
var scale = 1 + Math.sin(self.pulseTimer * 0.15) * 0.2;
dogGraphics.scaleX = scale * self.direction;
dogGraphics.scaleY = scale;
// Dog follows cat behavior
var distanceToCat = Math.abs(self.x - cat.x);
var catDirection = cat.x > self.x ? 1 : -1;
// Follow cat if within following range (500px) but maintain some distance (100px)
if (distanceToCat > 100 && distanceToCat < 500) {
self.direction = catDirection;
// Move towards cat with smooth tweening
if (!self.isTweening) {
var followSpeed = Math.min(self.speed, distanceToCat / 50); // Slower when closer
var targetX = self.x + followSpeed * self.direction * 20;
tween(self, {
x: targetX
}, {
duration: 400,
easing: tween.easeInOut,
onFinish: function onFinish() {
self.isTweening = false;
}
});
self.isTweening = true;
}
} else {
// Regular movement when not following
if (!self.isTweening) {
var targetX = self.x + self.speed * self.direction * 30; // Move distance over 0.5 seconds
tween(self, {
x: targetX
}, {
duration: 500,
easing: tween.easeInOut,
onFinish: function onFinish() {
self.isTweening = false;
}
});
self.isTweening = true;
}
// Change direction randomly or when hitting boundaries with bounce animation
if (Math.random() < 0.008) {
self.direction *= -1;
tween(dogGraphics, {
scaleX: scale * self.direction * 1.3
}, {
duration: 200,
easing: tween.bounceOut,
onFinish: function onFinish() {
tween(dogGraphics, {
scaleX: scale * self.direction
}, {
duration: 100,
easing: tween.easeOut
});
}
});
}
}
// Handle barking animation - 2 times per second (every 15 ticks = 4 times per second, so every 30 ticks = 2 times per second)
self.barkTimer++;
if (self.barkTimer >= 30) {
// Change every 0.5 seconds (30 ticks) for 2 times per second
self.barkTimer = 0;
if (self.isBarkingOpen) {
// Switch to normal dog with smooth tween
tween(dogGraphics, {
alpha: 1
}, {
duration: 100,
easing: tween.easeOut,
onFinish: function onFinish() {
dogGraphics.visible = true;
if (self.dogCloseGraphics) {
self.dogCloseGraphics.visible = false;
}
self.isBarkingOpen = false;
}
});
} else {
// Switch to barking dog (close mouth) with smooth tween
if (!self.dogCloseGraphics) {
self.dogCloseGraphics = self.attachAsset('Dog-close', {
anchorX: 0.5,
anchorY: 1,
scaleX: 4,
scaleY: 4
});
}
tween(self.dogCloseGraphics, {
alpha: 1
}, {
duration: 10,
easing: tween.easeOut,
onFinish: function onFinish() {
dogGraphics.visible = false;
self.dogCloseGraphics.visible = true;
self.dogCloseGraphics.scaleX = scale * self.direction;
self.dogCloseGraphics.scaleY = scale;
self.isBarkingOpen = true;
}
});
}
}
// Sync dog-close graphics scale with regular graphics
if (self.dogCloseGraphics && self.dogCloseGraphics.visible) {
self.dogCloseGraphics.scaleX = scale * self.direction;
self.dogCloseGraphics.scaleY = scale;
}
// Check if cat is within alert radius for barking only (but only when dog is on screen)
var distance = Math.abs(self.x - cat.x) + Math.abs(self.y - cat.y);
if (distance < self.alertRadius && isOnScreen) {
if (Math.random() < 0.08) {
// Increased from 0.02 to 0.08 for more frequent barking
LK.getSound('dogBark').play();
}
}
// Additional barking when mouth opens (barking animation) - only when on screen
if (self.barkTimer === 0 && !self.isBarkingOpen && Math.random() < 0.7 && isOnScreen) {
// 70% chance to bark when switching to open mouth
LK.getSound('dogBark').play();
}
// Handle falling behavior if dog was hit
if (self.isFalling) {
// Stop barking and hide all dog graphics when falling
for (var c = 0; c < self.children.length; c++) {
if (self.children[c] !== self.fallenGraphics && self.children[c] !== self.fallenGraphics2) {
self.children[c].visible = false;
}
}
// Handle alternating animation between perroCae and perroCae2
if (self.fallAnimTimer !== undefined) {
self.fallAnimTimer++;
if (self.fallAnimTimer >= 15) {
// Switch every 15 frames (0.25 seconds)
self.fallAnimTimer = 0;
self.showingFirstAsset = !self.showingFirstAsset;
if (self.fallenGraphics && self.fallenGraphics2) {
if (self.showingFirstAsset) {
self.fallenGraphics.visible = true;
self.fallenGraphics2.visible = false;
} else {
self.fallenGraphics.visible = false;
self.fallenGraphics2.visible = true;
}
}
}
}
self.y += self.fallSpeed;
self.fallSpeed += 0.3; // Gravity
// No rotation when falling - fall straight down
// Check collision with barriers while falling
for (var b = 0; b < separators.length; b++) {
var separator = separators[b];
if (self.intersects(separator) && separator.isBlocking) {
// Dog hits barrier and bounces
LK.getSound('objectHit').play();
self.fallSpeed = -self.fallSpeed * 0.5; // Bounce upward with reduced speed
self.x += self.direction * 50; // Move away from barrier
break;
}
}
// Remove if fallen off screen
if (self.y > 2732 + 100) {
self.destroy();
var dogIndex = dogs.indexOf(self);
if (dogIndex > -1) {
dogs.splice(dogIndex, 1);
}
}
return; // Don't do normal dog behavior when falling
}
// Check collision with barriers during normal movement
if (!self.isTweening) {
for (var b = 0; b < separators.length; b++) {
var separator = separators[b];
// Calculate which shelf level the separator is on
var sepShelfLevel = -1;
for (var level = 0; level < 5; level++) {
if (Math.abs(separator.y - (shelfLevels[level] - 150)) < 50) {
sepShelfLevel = level;
break;
}
}
// Calculate which shelf level the dog is on
var dogShelfLevel = -1;
for (var level = 0; level < 5; level++) {
if (Math.abs(self.y - (shelfLevels[level] - 75)) < 50) {
dogShelfLevel = level;
break;
}
}
// Check collision if on same shelf level
if (self.intersects(separator) && separator.isBlocking && sepShelfLevel === dogShelfLevel) {
// Dog hits barrier - change direction and bounce back
self.direction = -self.direction;
LK.getSound('dogBark').play();
// Push dog away from barrier
var pushDistance = 100;
var targetX = self.x + self.direction * pushDistance;
targetX = Math.max(200, Math.min(targetX, 9600)); // Keep within bounds
tween(self, {
x: targetX
}, {
duration: 300,
easing: tween.bounceOut
});
break;
}
}
}
};
return self;
});
var Lamp = Container.expand(function () {
var self = Container.call(this);
// Create visible light bulb first (behind)
var lightBulbGraphics = self.attachAsset('lightbulb', {
anchorX: 0.5,
anchorY: 1,
scaleX: 2.5,
scaleY: 2.5
});
lightBulbGraphics.y = -130; // Position higher above lamp base
// Create lamp base second (in front)
var lampGraphics = self.attachAsset('lamp', {
anchorX: 0.5,
anchorY: 1,
scaleX: 3,
scaleY: 3
});
self.isFalling = false;
self.fallSpeed = 0;
self.pulseTimer = 0;
self.hasElectrocuted = false;
self.flickerTimer = 0;
self.isFlickering = false;
self.flickerInterval = 60 + Math.random() * 120; // Random flicker every 1-3 seconds
self.startFalling = function () {
if (self.isFalling) {
return;
}
self.isFalling = true;
self.fallSpeed = 2;
// Play lamp falling sound
LK.getSound('objectHit').play();
// Add falling animation with rotation
tween(self, {
rotation: self.rotation + Math.PI * 2
}, {
duration: 1500,
easing: tween.easeOut
});
};
self.update = function () {
if (!self.isFalling) {
// Handle bulb flickering like electrical fault
self.flickerTimer++;
if (self.flickerTimer >= self.flickerInterval) {
self.flickerTimer = 0;
self.flickerInterval = 60 + Math.random() * 120; // New random interval
self.isFlickering = true;
// Quick flicker sequence - on/off/on rapidly
tween(lightBulbGraphics, {
alpha: 0.1 // Almost off
}, {
duration: 80,
easing: tween.linear,
onFinish: function onFinish() {
tween(lightBulbGraphics, {
alpha: 1 // Bright on
}, {
duration: 60,
easing: tween.linear,
onFinish: function onFinish() {
tween(lightBulbGraphics, {
alpha: 0.2 // Dim again
}, {
duration: 100,
easing: tween.linear,
onFinish: function onFinish() {
tween(lightBulbGraphics, {
alpha: 1 // Back to normal
}, {
duration: 120,
easing: tween.easeOut,
onFinish: function onFinish() {
self.isFlickering = false;
}
});
}
});
}
});
}
});
}
// Create pulsing glow effect with tint when not flickering
if (!self.isFlickering && self.flickerTimer % 120 === 0) {
// Every 2 seconds, create a glow pulse
tween(lightBulbGraphics, {
tint: 0xFFFF88 // Bright yellow glow
}, {
duration: 1000,
easing: tween.easeInOut,
onFinish: function onFinished() {
tween(lightBulbGraphics, {
tint: 0xFFFFFF // Back to white
}, {
duration: 1000,
easing: tween.easeInOut
});
}
});
}
} else {
self.y += self.fallSpeed;
self.fallSpeed += 0.3; // Gravity
// Check for collision with cat when falling
if (!self.hasElectrocuted && self.intersects(cat)) {
self.hasElectrocuted = true;
// Electrocute cat for 2 seconds (reduced from 3)
cat.isElectrocuted = true;
LK.getSound('electricShock').play();
cat.electrocutionTimer = 120; // 2 seconds at 60fps
// Play electric shock sound
LK.getSound('electricShock').play();
// Flash screen blue/white for electric effect
LK.effects.flashScreen(0x00FFFF, 1000);
// Push cat away from lamp with stronger force to prevent getting stuck
var pushDirection = cat.x > self.x ? 1 : -1;
var pushDistance = 250; // Increased from 150 to 250
var targetX = cat.x + pushDistance * pushDirection;
// Ensure target position is within game bounds
targetX = Math.max(200, Math.min(targetX, 3800));
// Stop any existing movement tweens on cat
tween.stop(cat, {
x: true
});
// Make cat get pushed away with stronger force
tween(cat, {
x: targetX
}, {
duration: 200,
// Faster push
easing: tween.easeOut,
onFinish: function onFinish() {
// Additional push to ensure separation
var secondPushX = targetX + pushDirection * 100;
secondPushX = Math.max(200, Math.min(secondPushX, 3800));
tween(cat, {
x: secondPushX
}, {
duration: 150,
easing: tween.easeOut
});
}
});
}
// Remove when off screen
if (self.y > 2732 + 100) {
// Emit sound when lamp falls off screen
LK.getSound('electricShock').play();
self.destroy();
var index = lamps.indexOf(self);
if (index > -1) {
lamps.splice(index, 1);
}
}
}
};
return self;
});
var Mouse = Container.expand(function () {
var self = Container.call(this);
var mouseGraphics = self.attachAsset('mouse', {
anchorX: 0.5,
anchorY: 0.5,
scaleX: 4,
scaleY: 4
});
self.speed = 12; // Much faster mouse movement
self.direction = 1;
self.isBeingChased = false;
self.pulseTimer = 0;
self.isTweening = false; // Flag for smooth movement
self.update = function () {
// Pulse effect to make mouse visible
self.pulseTimer++;
var scale = 1 + Math.sin(self.pulseTimer * 0.2) * 0.3;
mouseGraphics.scaleX = scale * self.direction;
mouseGraphics.scaleY = scale;
// Move mouse
self.x += self.speed * self.direction;
// Change direction randomly or when hitting boundaries
if (Math.random() < 0.01 || self.x < cat.x - 600 || self.x > cat.x + 600) {
self.direction *= -1;
// Add dynamic bounce effect when changing direction
tween(mouseGraphics, {
scaleX: scale * self.direction * 1.5,
scaleY: scale * 1.2
}, {
duration: 300,
easing: tween.elasticOut,
onFinish: function onFinish() {
tween(mouseGraphics, {
scaleX: scale * self.direction,
scaleY: scale
}, {
duration: 200,
easing: tween.easeOut
});
}
});
}
// Mouse squeaks when cat gets close
var distance = Math.abs(self.x - cat.x) + Math.abs(self.y - cat.y);
if (distance < 100 && !self.isBeingChased) {
self.isBeingChased = true;
LK.getSound('mouseSqueak').play();
}
};
return self;
});
var Separator = Container.expand(function () {
var self = Container.call(this);
var separatorGraphics = self.attachAsset('separator', {
anchorX: 0.5,
anchorY: 0.7,
scaleX: 4,
scaleY: 4
});
self.isBlocking = true;
return self;
});
var ShelfObject = Container.expand(function (objectType) {
var self = Container.call(this);
var assetName;
// Map object types to their asset names
switch (objectType) {
case 1:
case 2:
case 3:
assetName = 'object' + objectType;
break;
case 4:
assetName = 'pecera';
break;
case 5:
assetName = 'movil';
break;
case 6:
assetName = 'portatil';
break;
default:
assetName = 'object1';
}
var objectGraphics = self.attachAsset(assetName, {
anchorX: 0.5,
anchorY: 0.5,
scaleX: 4,
scaleY: 4
});
self.isFalling = false;
self.fallSpeed = 0;
self.startFalling = function () {
self.isFalling = true;
self.fallSpeed = 2;
// Change to falling asset if this is a pecera (fish tank)
if (objectType === 4) {
objectGraphics.visible = false;
// Create falling fish graphics if not exists
if (!self.fallingGraphics) {
self.fallingGraphics = self.attachAsset('pezCayendo', {
anchorX: 0.5,
anchorY: 0.5,
scaleX: 4,
scaleY: 4
});
}
self.fallingGraphics.visible = true;
// Apply falling animation to falling graphics instead
tween(self.fallingGraphics, {
scaleX: 6,
scaleY: 6
}, {
duration: 800,
easing: tween.bounceOut
});
} else {
// Add dynamic falling animation with scaling and rotation for other objects
tween(objectGraphics, {
scaleX: 6,
scaleY: 6
}, {
duration: 800,
easing: tween.bounceOut
});
}
// Play sound based on object type
var soundId = 'objectFall' + (objectType || 1);
LK.getSound(soundId).play();
// Add spinning effect while falling
var spinDirection = Math.random() < 0.5 ? 1 : -1;
tween(self, {
rotation: self.rotation + Math.PI * 4 * spinDirection
}, {
duration: 2000,
easing: tween.easeOut
});
};
self.update = function () {
if (self.isFalling) {
self.y += self.fallSpeed;
self.fallSpeed += 0.2; // Gravity
self.rotation += 0.1;
// Check for collisions with dogs when falling
for (var i = dogs.length - 1; i >= 0; i--) {
var dog = dogs[i];
if (self.intersects(dog)) {
// Object hits dog - dog falls down with perroCae asset
LK.getSound('perroCae').play();
LK.effects.flashObject(dog, 0xFF0000, 300);
// Stop dog barking immediately when hit
dog.wasOnScreen = false; // Reset screen detection to prevent further barking
// Change dog to hit/fallen state
dog.isHit = true;
dog.isFalling = true;
dog.fallSpeed = 3;
// Hide ALL existing dog graphics - ensure only perroCae is visible
for (var c = 0; c < dog.children.length; c++) {
dog.children[c].visible = false;
}
// Create both fallen dog graphics if they don't exist
if (!dog.fallenGraphics) {
dog.fallenGraphics = dog.attachAsset('perroCae', {
anchorX: 0.5,
anchorY: 1,
scaleX: 4,
scaleY: 4
});
}
if (!dog.fallenGraphics2) {
dog.fallenGraphics2 = dog.attachAsset('perroCae2', {
anchorX: 0.5,
anchorY: 1,
scaleX: 4,
scaleY: 4
});
}
// Initialize alternation timer and state
dog.fallAnimTimer = 0;
dog.showingFirstAsset = true;
// Start with perroCae visible
dog.fallenGraphics.visible = true;
dog.fallenGraphics2.visible = false;
// Remove the object that hit the dog
self.destroy();
var index = shelfObjects.indexOf(self);
if (index > -1) {
shelfObjects.splice(index, 1);
}
return; // Exit early since object is destroyed
}
}
if (self.y > 2732 + 50) {
// Emit sound when object falls off screen
LK.getSound('objectHit').play();
self.destroy();
var index = shelfObjects.indexOf(self);
if (index > -1) {
shelfObjects.splice(index, 1);
}
}
}
};
return self;
});
var Soap = Container.expand(function () {
var self = Container.call(this);
var soapGraphics = self.attachAsset('soap', {
anchorX: 0.5,
anchorY: 1,
scaleX: 1.8,
scaleY: 1.8
});
self.hasBeenUsed = false;
return self;
});
/****
* Initialize Game
****/
var game = new LK.Game({
backgroundColor: 0x87CEEB
});
/****
* Game Code
****/
var cat;
var shelfObjects = [];
var dangerousObjects = [];
// Laser removed
var mice = [];
var dogs = [];
var separators = [];
var lamps = [];
var soaps = [];
var nextMouseSpawn = 0;
var nextDogSpawn = 0;
var nextSeparatorSpawn = 0;
var nextLampSpawn = 0;
var nextSoapSpawn = 0;
var shelfLevels = [500, 1000, 1500, 2000, 2500]; // Y positions for 5 shelf levels aligned with object feet
var shelves = [];
var nextObjectSpawn = 0;
var nextDangerousSpawn = 0;
// Laser removed
var cameraX = 0;
var gameTimer = 0;
var TIME_LIMIT = 9600; // 160 seconds at 60fps (9600 ticks)
// Stage system variables
var currentStage = 1;
var maxStages = 20; // Increased to 20 stages
var baseTimeLimit = 9600; // Base time limit for stage 1
// Countdown system variables
var isCountingDown = false;
var countdownTimer = 0;
var countdownValue = 3;
var countdownText = null;
var catStartSpeed = 0; // Store cat's original speed to restore after countdown
// Always start fresh - ignore storage values to ensure correct initialization
var totalObjectsToKnock = 15;
var objectsKnockedDown = 0;
var obstaclePenalties = 0; // Track penalties from hitting obstacles
var finalScore = 0;
// Score display removed - game now uses timer-based gameplay
// Create HUD background first (so it appears behind the text)
var hudBackground = LK.getAsset('ui', {
anchorX: 0.5,
anchorY: 0,
scaleX: 26,
// Scale to cover the full width of HUD elements
scaleY: 2.5 // Scale to appropriate height for text elements
});
LK.gui.top.addChild(hudBackground);
hudBackground.x = 0; // Center horizontally
hudBackground.y = 10; // Position slightly above text elements
// Create progress display with initial values
var progressText = new Text2('Objects: 0/15', {
size: 50,
fill: 0x000000
});
progressText.anchor.set(0.5, 0);
LK.gui.top.addChild(progressText);
progressText.x = -160; // Position left of center
progressText.y = 20;
// Create timer display
var timerText = new Text2('Time: 60', {
size: 50,
fill: 0x000000
});
timerText.anchor.set(0.5, 0);
LK.gui.top.addChild(timerText);
timerText.x = 230; // Position right of center
timerText.y = 20;
// Create score display
var scoreText = new Text2('Score: 0', {
size: 50,
fill: 0x000000
});
scoreText.anchor.set(1, 0);
LK.gui.top.addChild(scoreText);
scoreText.x = 650; // Position on right side
scoreText.y = 20;
// Create countdown background first (so it appears behind the text)
var countdownBackground = LK.getAsset('fondo_number', {
anchorX: 0.5,
anchorY: 0.5,
scaleX: 5,
scaleY: 5
});
countdownBackground.visible = false;
LK.gui.center.addChild(countdownBackground);
// Create countdown text (initially hidden)
countdownText = new Text2('3', {
size: 80,
fill: 0xFAC21C
});
countdownText.anchor.set(0.5, 0.5);
countdownText.visible = false;
LK.gui.center.addChild(countdownText);
// Claw button removed - zarpazo is now automatic when picking up objects
// Create shelves first - reduced to 96 shelves wide (24 sections per level)
for (var level = 0; level < 5; level++) {
for (var section = 0; section < 24; section++) {
var shelf = game.addChild(LK.getAsset('shelf', {
anchorX: 0,
anchorY: 1
}));
shelf.x = section * 400;
shelf.y = shelfLevels[level];
shelves.push(shelf);
}
}
// Initialize objects at the beginning of the game with persistence
// Reset counters at game start to ensure proper initialization
totalObjectsToKnock = 15; // Always start with 15 objects
objectsKnockedDown = 0; // Always start with 0 knocked down
storage.totalObjectsToKnock = totalObjectsToKnock;
storage.objectsKnockedDown = objectsKnockedDown;
// Clear any existing objects from previous games
shelfObjects = [];
// Pre-define object positions ensuring proper spacing (minimum 500px apart) within shelf boundaries (400-9200px)
var objectPositions = [{
x: 600,
level: 0,
type: 1
},
// Object 1
{
x: 1600,
level: 1,
type: 4
},
// Object 2 - pecera
{
x: 1800,
level: 2,
type: 3
},
// Object 3
{
x: 2400,
level: 3,
type: 5
},
// Object 4 - movil
{
x: 3000,
level: 4,
type: 2
},
// Object 5
{
x: 3600,
level: 0,
type: 6
},
// Object 6 - portatil
{
x: 4200,
level: 1,
type: 1
},
// Object 7
{
x: 4800,
level: 2,
type: 4
},
// Object 8 - pecera
{
x: 5400,
level: 3,
type: 3
},
// Object 9
{
x: 6000,
level: 4,
type: 5
},
// Object 10 - movil
{
x: 6800,
level: 0,
type: 2
},
// Object 11
{
x: 7300,
level: 1,
type: 6
},
// Object 12 - portatil
{
x: 7800,
level: 2,
type: 1
},
// Object 13
{
x: 8500,
level: 3,
type: 4
},
// Object 14 - pecera
{
x: 9100,
level: 4,
type: 3
} // Object 15
];
// Create all 15 objects at game start with proper spacing
for (var i = 0; i < totalObjectsToKnock; i++) {
var pos = objectPositions[i];
var obj = new ShelfObject(pos.type);
obj.x = pos.x;
obj.y = shelfLevels[pos.level] - 155; // Position much higher on top of shelf (60px higher)
obj.objectNumber = i + 1; // Add numbering for identification
game.addChild(obj);
shelfObjects.push(obj);
}
// Create barrier columns at start and end of game world
var leftBarriers = [];
var rightBarriers = [];
// Create left barrier column (at the beginning)
for (var level = 0; level < 5; level++) {
var leftBarrier = game.addChild(LK.getAsset('cubos', {
anchorX: 0.5,
anchorY: 0,
scaleX: 4,
scaleY: 4
}));
leftBarrier.x = -100; // Position at the very start
leftBarrier.y = shelfLevels[level] - 150; // Position on each shelf level
leftBarrier.isBlocking = true;
leftBarriers.push(leftBarrier);
}
// Create right barrier column (at the end) - positioned for 96 shelves wide
for (var level = 0; level < 5; level++) {
var rightBarrier = game.addChild(LK.getAsset('cubos', {
anchorX: 0.5,
anchorY: 0,
scaleX: 4,
scaleY: 4
}));
rightBarrier.x = 9700; // Position at end of 24 sections (24 * 400 = 9600)
rightBarrier.y = shelfLevels[level] - 150; // Position on each shelf level
rightBarrier.isBlocking = true;
rightBarriers.push(rightBarrier);
}
// Pre-define separator positions ensuring proper spacing (minimum 60px from other elements)
var separatorPositions = [{
x: 1900,
level: 0
}, {
x: 2600,
level: 2
}, {
x: 3600,
level: 1
}, {
x: 4600,
level: 4
}, {
x: 5600,
level: 3
}, {
x: 6700,
level: 0
}, {
x: 7600,
level: 2
}, {
x: 8600,
level: 1
}];
// Create all separators at game start with proper spacing
for (var i = 0; i < separatorPositions.length; i++) {
var sepPos = separatorPositions[i];
var separator = new Separator();
separator.x = sepPos.x;
separator.y = shelfLevels[sepPos.level] - 150; // Position higher above shelf
separator.isBlocking = true;
game.addChild(separator);
separators.push(separator);
}
// Pre-define dangerous object positions ensuring proper spacing from other elements (minimum 60px spacing)
// Note: No spiders on level 0 (upper level) since they cannot fall when cat passes above
var dangerousObjectPositions = [{
x: 2000,
level: 1
}, {
x: 2300,
level: 1
}, {
x: 3900,
level: 3
}, {
x: 5300,
level: 2
}, {
x: 6900,
level: 4
}, {
x: 8300,
level: 1
}];
// Create all dangerous objects at game start
for (var i = 0; i < dangerousObjectPositions.length; i++) {
var dangerPos = dangerousObjectPositions[i];
var dangerousObj = new DangerousObject();
dangerousObj.x = dangerPos.x;
dangerousObj.y = shelfLevels[dangerPos.level] - 75; // Position on top of shelf (match shelf-level detection)
game.addChild(dangerousObj);
dangerousObjects.push(dangerousObj);
}
// Pre-define dog positions ensuring proper spacing (minimum 60px from other elements)
var dogPositions = [{
x: 2700,
level: 4
}, {
x: 4100,
level: 0
}, {
x: 7100,
level: 3
}];
// Create all dogs at game start
for (var i = 0; i < dogPositions.length; i++) {
var dogPos = dogPositions[i];
var dog = new Dog();
dog.x = dogPos.x;
dog.y = shelfLevels[dogPos.level] - 75; // Position on top of shelf
game.addChild(dog);
dogs.push(dog);
}
// Pre-define mouse positions ensuring proper spacing (far from cat start position)
var mousePositions = [{
x: 3300,
level: 4
}, {
x: 3400,
level: 1
}, {
x: 5900,
level: 0
}, {
x: 8700,
level: 2
}];
// Create all mice at game start
for (var i = 0; i < mousePositions.length; i++) {
var mousePos = mousePositions[i];
var mouse = new Mouse();
mouse.x = mousePos.x;
mouse.y = shelfLevels[mousePos.level] - 75; // Position on top of shelf
game.addChild(mouse);
mice.push(mouse);
}
// Pre-define lamp positions ensuring proper spacing (minimum 60px from other elements)
var lampPositions = [{
x: 1750,
level: 1
}, {
x: 4700,
level: 3
}, {
x: 6300,
level: 0
}, {
x: 8900,
level: 4
}];
// Create all lamps at game start
for (var i = 0; i < lampPositions.length; i++) {
var lampPos = lampPositions[i];
var lamp = new Lamp();
lamp.x = lampPos.x;
lamp.y = shelfLevels[lampPos.level]; // Position on shelf
game.addChild(lamp);
lamps.push(lamp);
}
// Pre-define soap positions ensuring proper spacing (minimum 60px from other elements)
var soapPositions = [{
x: 2100,
level: 4
}, {
x: 4500,
level: 1
}, {
x: 6500,
level: 2
}];
// Create all soaps at game start
for (var i = 0; i < soapPositions.length; i++) {
var soapPos = soapPositions[i];
var soap = new Soap();
soap.x = soapPos.x;
soap.y = shelfLevels[soapPos.level] - 40; // Position on shelf
game.addChild(soap);
soaps.push(soap);
}
// Create cat after shelves so it appears in front
cat = game.addChild(new Cat());
// Position cat at horizontal center of screen
cat.x = 1024; // Center of screen horizontally (2048/2 = 1024)
cat.targetShelfLevel = 2; // Start on middle shelf
cat.currentShelfLevel = cat.targetShelfLevel;
cat.y = shelfLevels[cat.targetShelfLevel] - 208; // Position cat to stand on shelf (accounting for cat height and anchor) - raised by 30px
// Initialize countdown for stage 1
setupStage(1);
// Handle swipe controls
var swipeStartX = 0;
var swipeStartY = 0;
var isDragging = false;
game.down = function (x, y, obj) {
swipeStartX = x;
swipeStartY = y;
isDragging = true;
// Laser removed
};
game.move = function (x, y, obj) {
// Laser removed
};
game.up = function (x, y, obj) {
if (!isDragging) {
return;
}
isDragging = false;
// Don't respond to swipe controls when in bubble
if (cat.isInBubble) {
return;
}
var deltaX = x - swipeStartX;
var deltaY = y - swipeStartY;
var swipeDistance = Math.sqrt(deltaX * deltaX + deltaY * deltaY);
if (swipeDistance < 50) {
return;
} // Minimum swipe distance
if (Math.abs(deltaY) > Math.abs(deltaX)) {
// Vertical swipe - change shelf level
// Prevent jumping when electrocuted, scared, blocking barriers, hit, or in special modes
if (!cat.isElectrocuted && !cat.isInBubble && !cat.isBlockMode && !cat.isHitMode && !cat.isZarpazoMode && !cat.isKissMode) {
if (deltaY < 0 && cat.targetShelfLevel > 0) {
cat.targetShelfLevel--; // Swipe up
} else if (deltaY > 0 && cat.targetShelfLevel < 4) {
// Check downward jump protection
var timeSinceLastDownwardJump = LK.ticks - cat.lastDownwardJumpTime;
if (timeSinceLastDownwardJump >= cat.downwardJumpProtection) {
cat.targetShelfLevel++; // Swipe down
}
}
}
} else {
// Horizontal swipe - change direction
if (!cat.isLaserMode) {
if (deltaX > 0) {
cat.direction = 1; // Right
} else {
cat.direction = -1; // Left
}
// If cat is in block mode, immediately exit it when direction changes
if (cat.isBlockMode) {
cat.isBlockMode = false;
cat.blockTimer = 0;
// Restore movement speed
cat.speed = cat.normalSpeed;
// Hide block graphics and show normal cat
cat.catBlockGraphics.visible = false;
var catGraphics = cat.children.find(function (child) {
return child.texture && child.texture.baseTexture && child.texture.baseTexture.resource && child.texture.baseTexture.resource.url && child.texture.baseTexture.resource.url.includes('cat') && !child.texture.baseTexture.resource.url.includes('step') && !child.texture.baseTexture.resource.url.includes('jump') && !child.texture.baseTexture.resource.url.includes('hit') && !child.texture.baseTexture.resource.url.includes('block');
});
if (catGraphics) {
catGraphics.visible = true;
}
}
}
}
};
// Spawn objects and laser pointers
function spawnObject() {
// Objects are distributed at the beginning and remain persistent
// No automatic spawning during gameplay
return;
}
function spawnDangerousObject() {
// Dangerous objects are now pre-defined at game start - no dynamic spawning
return;
}
// Laser spawn removed
function spawnMouse() {
// Mice are now pre-defined at game start - no dynamic spawning
return;
}
function spawnDog() {
// Dogs are now pre-defined at game start - no dynamic spawning
return;
}
function spawnSeparator() {
// Separators are now pre-defined at game start - no dynamic spawning
return;
}
function spawnLamp() {
// Lamps are now pre-defined at game start - no dynamic spawning
return;
}
function spawnSoap() {
// Soaps are now pre-defined at game start - no dynamic spawning
return;
}
// Camera follow with smooth tweening
function updateCamera() {
var targetCameraX = cat.x - 1024; // Center cat on screen (2048/2 = 1024)
// Smooth camera movement with easing
if (Math.abs(cameraX - targetCameraX) > 5) {
tween.stop(game, {
x: true
}); // Stop any existing camera tween
tween(game, {
x: -targetCameraX
}, {
duration: 300,
easing: tween.easeOut,
onFinish: function onFinish() {
cameraX = targetCameraX;
}
});
} else {
cameraX = targetCameraX;
game.x = -cameraX;
}
// Keep world size limited to 96 shelves - no dynamic expansion
var rightmostShelf = Math.max.apply(Math, shelves.map(function (s) {
return s.x;
}));
// No shelf expansion - world stays at fixed 96 shelves wide (9600px)
}
// Stage setup function
function setupStage(stage) {
// Reset game state
gameTimer = 0;
obstaclePenalties = 0;
// Adjust time limit - reduce by 10 seconds (600 ticks) each stage up to stage 10, then 4 seconds (240 ticks) each stage after 10
if (stage <= 10) {
TIME_LIMIT = baseTimeLimit - (stage - 1) * 600; // 10 seconds reduction per stage up to stage 10
} else {
// After stage 10: base time reduced by 9*600 for first 9 stages, then 4 seconds per additional stage
TIME_LIMIT = baseTimeLimit - 9 * 600 - (stage - 10) * 240; // 4 seconds reduction per stage after 10
}
// Clear existing objects
for (var i = shelfObjects.length - 1; i >= 0; i--) {
shelfObjects[i].destroy();
}
shelfObjects = [];
// Clear existing dangerous objects
for (var i = dangerousObjects.length - 1; i >= 0; i--) {
dangerousObjects[i].destroy();
}
dangerousObjects = [];
// Clear existing dogs (will be respawned for stage 2+)
for (var i = dogs.length - 1; i >= 0; i--) {
dogs[i].destroy();
}
dogs = [];
// Reset cat state
cat.isDancing = false;
// Apply stage-based speed increase for stages 10+
if (stage >= 10) {
var speedIncrease = (stage - 9) * 0.1; // 10% increase per stage after 10
cat.normalSpeed = cat.normalSpeed * (1 + speedIncrease);
cat.speed = cat.normalSpeed;
} else {
cat.speed = cat.normalSpeed;
}
// Start countdown at beginning of stage
isCountingDown = true;
countdownTimer = 0;
countdownValue = 3;
catStartSpeed = cat.speed; // Store original speed
cat.speed = 0; // Stop cat movement during countdown
countdownBackground.visible = true;
countdownText.visible = true;
countdownText.setText('3');
// Find safe spawn position for cat (away from obstacles and dogs)
var safeCatX = 1024; // Default center position
var minSafeDistance = 200; // Minimum distance from obstacles
// Check if center position is safe
var isCenterSafe = true;
// Check distance from objects
for (var i = 0; i < shelfObjects.length; i++) {
if (Math.abs(shelfObjects[i].x - 1024) < minSafeDistance && Math.abs(shelfObjects[i].y - (shelfLevels[2] - 155)) < 100) {
isCenterSafe = false;
break;
}
}
// Check distance from dogs
for (var i = 0; i < dogs.length; i++) {
if (Math.abs(dogs[i].x - 1024) < minSafeDistance && Math.abs(dogs[i].y - (shelfLevels[2] - 75)) < 100) {
isCenterSafe = false;
break;
}
}
// Check distance from dangerous objects
for (var i = 0; i < dangerousObjects.length; i++) {
if (Math.abs(dangerousObjects[i].x - 1024) < minSafeDistance && Math.abs(dangerousObjects[i].y - (shelfLevels[2] - 75)) < 100) {
isCenterSafe = false;
break;
}
}
// If center isn't safe, find alternative safe position
if (!isCenterSafe) {
var potentialPositions = [800, 600, 1200, 1400]; // Alternative spawn positions
for (var p = 0; p < potentialPositions.length; p++) {
var testX = potentialPositions[p];
var positionSafe = true;
// Check all obstacles for this position
for (var i = 0; i < shelfObjects.length; i++) {
if (Math.abs(shelfObjects[i].x - testX) < minSafeDistance && Math.abs(shelfObjects[i].y - (shelfLevels[2] - 155)) < 100) {
positionSafe = false;
break;
}
}
if (!positionSafe) {
continue;
}
for (var i = 0; i < dogs.length; i++) {
if (Math.abs(dogs[i].x - testX) < minSafeDistance && Math.abs(dogs[i].y - (shelfLevels[2] - 75)) < 100) {
positionSafe = false;
break;
}
}
if (!positionSafe) {
continue;
}
for (var i = 0; i < dangerousObjects.length; i++) {
if (Math.abs(dangerousObjects[i].x - testX) < minSafeDistance && Math.abs(dangerousObjects[i].y - (shelfLevels[2] - 75)) < 100) {
positionSafe = false;
break;
}
}
if (positionSafe) {
safeCatX = testX;
break;
}
}
}
cat.x = safeCatX; // Use safe position
cat.targetShelfLevel = 2;
cat.currentShelfLevel = 2;
cat.y = shelfLevels[2] - 208;
cat.direction = 1;
// Immediately move camera to cat's position
cameraX = cat.x - 1024; // Center cat on screen
game.x = -cameraX;
// Hide dance graphics and show normal cat
cat.gatoBailaGraphics.visible = false;
var catGraphics = cat.children.find(function (child) {
return child.texture && child.texture.baseTexture && child.texture.baseTexture.resource && child.texture.baseTexture.resource.url && child.texture.baseTexture.resource.url.includes('cat') && !child.texture.baseTexture.resource.url.includes('step');
});
if (catGraphics) {
catGraphics.visible = true;
}
// Create new object positions for the stage (randomized but properly spaced)
var newObjectPositions = [];
if (stage === 1) {
// Stage 1 positions (updated with new object types)
newObjectPositions = [{
x: 600,
level: 0,
type: 1
}, {
x: 1600,
level: 1,
type: 4
}, {
x: 1800,
level: 2,
type: 3
}, {
x: 2400,
level: 3,
type: 5
}, {
x: 3000,
level: 4,
type: 2
}, {
x: 3600,
level: 0,
type: 6
}, {
x: 4200,
level: 1,
type: 1
}, {
x: 4800,
level: 2,
type: 4
}, {
x: 5400,
level: 3,
type: 3
}, {
x: 6000,
level: 4,
type: 5
}, {
x: 6800,
level: 0,
type: 2
}, {
x: 7300,
level: 1,
type: 6
}, {
x: 7800,
level: 2,
type: 1
}, {
x: 8500,
level: 3,
type: 4
}, {
x: 9100,
level: 4,
type: 3
}];
} else if (stage === 2) {
// Stage 2 positions (reorganized)
newObjectPositions = [{
x: 800,
level: 4,
type: 2
}, {
x: 1400,
level: 0,
type: 1
}, {
x: 2000,
level: 2,
type: 3
}, {
x: 2800,
level: 1,
type: 2
}, {
x: 3400,
level: 3,
type: 1
}, {
x: 4000,
level: 4,
type: 3
}, {
x: 4600,
level: 0,
type: 2
}, {
x: 5200,
level: 2,
type: 1
}, {
x: 5800,
level: 1,
type: 3
}, {
x: 6400,
level: 3,
type: 2
}, {
x: 7000,
level: 4,
type: 1
}, {
x: 7600,
level: 0,
type: 3
}, {
x: 8200,
level: 2,
type: 2
}, {
x: 8800,
level: 1,
type: 1
}, {
x: 9200,
level: 3,
type: 3
}];
} else if (stage === 3) {
// Stage 3 positions
newObjectPositions = [{
x: 700,
level: 2,
type: 3
}, {
x: 1300,
level: 4,
type: 1
}, {
x: 1900,
level: 1,
type: 2
}, {
x: 2500,
level: 0,
type: 3
}, {
x: 3100,
level: 3,
type: 1
}, {
x: 3700,
level: 2,
type: 2
}, {
x: 4300,
level: 4,
type: 3
}, {
x: 4900,
level: 1,
type: 1
}, {
x: 5500,
level: 0,
type: 2
}, {
x: 6100,
level: 3,
type: 3
}, {
x: 6700,
level: 2,
type: 1
}, {
x: 7300,
level: 4,
type: 2
}, {
x: 7900,
level: 1,
type: 3
}, {
x: 8500,
level: 0,
type: 1
}, {
x: 9000,
level: 3,
type: 2
}];
} else if (stage === 4) {
// Stage 4 positions
newObjectPositions = [{
x: 900,
level: 1,
type: 1
}, {
x: 1500,
level: 3,
type: 2
}, {
x: 2100,
level: 0,
type: 3
}, {
x: 2700,
level: 4,
type: 1
}, {
x: 3300,
level: 2,
type: 2
}, {
x: 3900,
level: 1,
type: 3
}, {
x: 4500,
level: 3,
type: 1
}, {
x: 5100,
level: 0,
type: 2
}, {
x: 5700,
level: 4,
type: 3
}, {
x: 6300,
level: 2,
type: 1
}, {
x: 6900,
level: 1,
type: 2
}, {
x: 7500,
level: 3,
type: 3
}, {
x: 8100,
level: 0,
type: 1
}, {
x: 8700,
level: 4,
type: 2
}, {
x: 9300,
level: 2,
type: 3
}];
} else if (stage === 5) {
// Stage 5 positions
newObjectPositions = [{
x: 600,
level: 3,
type: 2
}, {
x: 1200,
level: 1,
type: 3
}, {
x: 1800,
level: 4,
type: 1
}, {
x: 2400,
level: 2,
type: 2
}, {
x: 3000,
level: 0,
type: 3
}, {
x: 3600,
level: 3,
type: 1
}, {
x: 4200,
level: 1,
type: 2
}, {
x: 4800,
level: 4,
type: 3
}, {
x: 5400,
level: 2,
type: 1
}, {
x: 6000,
level: 0,
type: 2
}, {
x: 6600,
level: 3,
type: 3
}, {
x: 7200,
level: 1,
type: 1
}, {
x: 7800,
level: 4,
type: 2
}, {
x: 8400,
level: 2,
type: 3
}, {
x: 9000,
level: 0,
type: 1
}];
} else if (stage === 6) {
// Stage 6 positions
newObjectPositions = [{
x: 800,
level: 0,
type: 3
}, {
x: 1400,
level: 2,
type: 1
}, {
x: 2000,
level: 4,
type: 2
}, {
x: 2600,
level: 1,
type: 3
}, {
x: 3200,
level: 3,
type: 1
}, {
x: 3800,
level: 0,
type: 2
}, {
x: 4400,
level: 2,
type: 3
}, {
x: 5000,
level: 4,
type: 1
}, {
x: 5600,
level: 1,
type: 2
}, {
x: 6200,
level: 3,
type: 3
}, {
x: 6800,
level: 0,
type: 1
}, {
x: 7400,
level: 2,
type: 2
}, {
x: 8000,
level: 4,
type: 3
}, {
x: 8600,
level: 1,
type: 1
}, {
x: 9200,
level: 3,
type: 2
}];
} else if (stage === 7) {
// Stage 7 positions
newObjectPositions = [{
x: 1000,
level: 4,
type: 1
}, {
x: 1600,
level: 2,
type: 3
}, {
x: 2200,
level: 0,
type: 2
}, {
x: 2800,
level: 3,
type: 1
}, {
x: 3400,
level: 1,
type: 3
}, {
x: 4000,
level: 4,
type: 2
}, {
x: 4600,
level: 2,
type: 1
}, {
x: 5200,
level: 0,
type: 3
}, {
x: 5800,
level: 3,
type: 2
}, {
x: 6400,
level: 1,
type: 1
}, {
x: 7000,
level: 4,
type: 3
}, {
x: 7600,
level: 2,
type: 2
}, {
x: 8200,
level: 0,
type: 1
}, {
x: 8800,
level: 3,
type: 3
}, {
x: 9400,
level: 1,
type: 2
}];
} else if (stage === 8) {
// Stage 8 positions
newObjectPositions = [{
x: 650,
level: 1,
type: 2
}, {
x: 1250,
level: 4,
type: 1
}, {
x: 1850,
level: 2,
type: 3
}, {
x: 2450,
level: 0,
type: 2
}, {
x: 3050,
level: 3,
type: 1
}, {
x: 3650,
level: 1,
type: 3
}, {
x: 4250,
level: 4,
type: 2
}, {
x: 4850,
level: 2,
type: 1
}, {
x: 5450,
level: 0,
type: 3
}, {
x: 6050,
level: 3,
type: 2
}, {
x: 6650,
level: 1,
type: 1
}, {
x: 7250,
level: 4,
type: 3
}, {
x: 7850,
level: 2,
type: 2
}, {
x: 8450,
level: 0,
type: 1
}, {
x: 9050,
level: 3,
type: 3
}];
} else if (stage === 9) {
// Stage 9 positions
newObjectPositions = [{
x: 750,
level: 3,
type: 3
}, {
x: 1350,
level: 1,
type: 2
}, {
x: 1950,
level: 4,
type: 1
}, {
x: 2550,
level: 2,
type: 3
}, {
x: 3150,
level: 0,
type: 2
}, {
x: 3750,
level: 3,
type: 1
}, {
x: 4350,
level: 1,
type: 3
}, {
x: 4950,
level: 4,
type: 2
}, {
x: 5550,
level: 2,
type: 1
}, {
x: 6150,
level: 0,
type: 3
}, {
x: 6750,
level: 3,
type: 2
}, {
x: 7350,
level: 1,
type: 1
}, {
x: 7950,
level: 4,
type: 3
}, {
x: 8550,
level: 2,
type: 2
}, {
x: 9150,
level: 0,
type: 1
}];
} else if (stage === 10) {
// Stage 10 positions (final stage)
newObjectPositions = [{
x: 850,
level: 2,
type: 1
}, {
x: 1450,
level: 0,
type: 3
}, {
x: 2050,
level: 3,
type: 2
}, {
x: 2650,
level: 1,
type: 1
}, {
x: 3250,
level: 4,
type: 3
}, {
x: 3850,
level: 2,
type: 2
}, {
x: 4450,
level: 0,
type: 1
}, {
x: 5050,
level: 3,
type: 3
}, {
x: 5650,
level: 1,
type: 2
}, {
x: 6250,
level: 4,
type: 1
}, {
x: 6850,
level: 2,
type: 3
}, {
x: 7450,
level: 0,
type: 2
}, {
x: 8050,
level: 3,
type: 1
}, {
x: 8650,
level: 1,
type: 3
}, {
x: 9250,
level: 4,
type: 2
}];
} else {
// For stages 11-20, generate randomized but properly spaced positions
newObjectPositions = [];
var usedPositions = [];
var minDistance = 500;
for (var objCount = 0; objCount < totalObjectsToKnock; objCount++) {
var attempts = 0;
var validPosition = false;
var newPos;
while (!validPosition && attempts < 50) {
newPos = {
x: 600 + Math.floor(Math.random() * 8500),
// Random X between 600-9100
level: Math.floor(Math.random() * 5),
// Random level 0-4
type: objCount % 6 + 1 // Cycle through types 1,2,3,4,5,6
};
validPosition = true;
// Check distance from existing positions
for (var u = 0; u < usedPositions.length; u++) {
if (Math.abs(newPos.x - usedPositions[u].x) < minDistance && Math.abs(newPos.level - usedPositions[u].level) <= 1) {
validPosition = false;
break;
}
}
attempts++;
}
if (validPosition) {
newObjectPositions.push(newPos);
usedPositions.push(newPos);
} else {
// Fallback to spread positions
newObjectPositions.push({
x: 700 + objCount * 550,
level: objCount % 5,
type: objCount % 6 + 1
});
}
}
}
// Create objects for the stage
for (var i = 0; i < totalObjectsToKnock; i++) {
var pos = newObjectPositions[i];
var obj = new ShelfObject(pos.type);
obj.x = pos.x;
obj.y = shelfLevels[pos.level] - 155;
obj.objectNumber = i + 1;
game.addChild(obj);
shelfObjects.push(obj);
}
// Recreate dangerous objects for the stage
var newDangerousPositions = [];
if (stage === 1) {
newDangerousPositions = [{
x: 2000,
level: 1
}, {
x: 2300,
level: 1
}, {
x: 3900,
level: 3
}, {
x: 5300,
level: 2
}, {
x: 6900,
level: 4
}, {
x: 8300,
level: 1
}];
} else if (stage === 2) {
newDangerousPositions = [{
x: 1200,
level: 2
}, {
x: 2600,
level: 4
}, {
x: 3800,
level: 0
}, {
x: 5000,
level: 1
}, {
x: 6600,
level: 3
}, {
x: 8000,
level: 2
}];
} else if (stage === 3) {
newDangerousPositions = [{
x: 1100,
level: 1
}, {
x: 2400,
level: 3
}, {
x: 3700,
level: 0
}, {
x: 5200,
level: 4
}, {
x: 6800,
level: 2
}, {
x: 8100,
level: 3
}];
} else if (stage === 4) {
newDangerousPositions = [{
x: 1400,
level: 1
}, {
x: 2800,
level: 2
}, {
x: 4100,
level: 4
}, {
x: 5600,
level: 1
}, {
x: 7000,
level: 3
}, {
x: 8400,
level: 2
}];
} else if (stage === 5) {
newDangerousPositions = [{
x: 1300,
level: 3
}, {
x: 2700,
level: 1
}, {
x: 4200,
level: 2
}, {
x: 5800,
level: 4
}, {
x: 7300,
level: 2
}, {
x: 8600,
level: 3
}];
} else if (stage === 6) {
newDangerousPositions = [{
x: 1100,
level: 2
}, {
x: 2500,
level: 4
}, {
x: 3900,
level: 1
}, {
x: 5300,
level: 2
}, {
x: 6700,
level: 3
}, {
x: 8200,
level: 2
}];
} else if (stage === 7) {
newDangerousPositions = [{
x: 1500,
level: 1
}, {
x: 2900,
level: 3
}, {
x: 4300,
level: 2
}, {
x: 5700,
level: 4
}, {
x: 7100,
level: 2
}, {
x: 8500,
level: 1
}];
} else if (stage === 8) {
newDangerousPositions = [{
x: 1200,
level: 4
}, {
x: 2600,
level: 2
}, {
x: 4000,
level: 3
}, {
x: 5400,
level: 3
}, {
x: 6800,
level: 1
}, {
x: 8300,
level: 4
}];
} else if (stage === 9) {
newDangerousPositions = [{
x: 1000,
level: 1
}, {
x: 2400,
level: 2
}, {
x: 3800,
level: 4
}, {
x: 5200,
level: 1
}, {
x: 6600,
level: 3
}, {
x: 8000,
level: 2
}];
} else if (stage === 10) {
newDangerousPositions = [{
x: 1300,
level: 3
}, {
x: 2700,
level: 1
}, {
x: 4100,
level: 4
}, {
x: 5500,
level: 2
}, {
x: 6900,
level: 3
}, {
x: 8400,
level: 3
}];
} else {
// For stages 11-20, generate randomized dangerous object positions
// Avoid level 0 since spiders cannot fall when cat passes above
newDangerousPositions = [];
var dangerCount = Math.min(8, 4 + Math.floor(stage / 3)); // Increase danger objects as stages progress
for (var d = 0; d < dangerCount; d++) {
newDangerousPositions.push({
x: 1000 + Math.floor(Math.random() * 8000),
// Random X between 1000-9000
level: 1 + Math.floor(Math.random() * 4) // Random level 1-4 (avoid level 0)
});
}
}
for (var i = 0; i < newDangerousPositions.length; i++) {
var dangerPos = newDangerousPositions[i];
var dangerousObj = new DangerousObject();
dangerousObj.x = dangerPos.x;
dangerousObj.y = shelfLevels[dangerPos.level] - 75;
game.addChild(dangerousObj);
dangerousObjects.push(dangerousObj);
}
// Add dogs starting from stage 2 with stage-based limits
if (stage >= 2) {
var maxDogs;
if (stage <= 5) {
maxDogs = 1; // First 5 stages: maximum 1 dog
} else if (stage <= 18) {
maxDogs = 2; // Stages 6-18: maximum 2 dogs
} else {
maxDogs = 3; // Stages 19-20: maximum 3 dogs
}
var newDogPositions = [];
// Generate dog positions ensuring they are away from cat safe spawn area
var baseDogPositions = [{
x: 1500,
level: 2
}, {
x: 3200,
level: 4
}, {
x: 4800,
level: 1
}, {
x: 6400,
level: 0
}, {
x: 7800,
level: 3
}];
var dogsAdded = 0;
for (var d = 0; d < baseDogPositions.length && dogsAdded < maxDogs; d++) {
var dogPos = baseDogPositions[d];
// Ensure dogs are at least 400px away from cat spawn area (safeCatX)
if (Math.abs(dogPos.x - safeCatX) >= 400) {
newDogPositions.push(dogPos);
dogsAdded++;
} else {
// Adjust position to be further away
var adjustedX = dogPos.x < safeCatX ? dogPos.x - 400 : dogPos.x + 400;
adjustedX = Math.max(600, Math.min(adjustedX, 9000)); // Keep within bounds
newDogPositions.push({
x: adjustedX,
level: dogPos.level
});
dogsAdded++;
}
}
for (var i = 0; i < newDogPositions.length; i++) {
var dogPos = newDogPositions[i];
var dog = new Dog();
dog.x = dogPos.x;
// Ensure dog appears on different shelf level than cat's starting level (2)
var dogLevel = dogPos.level;
if (dogLevel === 2) {
// If dog would spawn on same level as cat, move to adjacent level
dogLevel = Math.random() < 0.5 ? 1 : 3; // Move to level 1 or 3
}
dog.y = shelfLevels[dogLevel] - 75;
game.addChild(dog);
dogs.push(dog);
}
}
// Reset counters
totalObjectsToKnock = 15;
objectsKnockedDown = 0;
storage.totalObjectsToKnock = totalObjectsToKnock;
storage.objectsKnockedDown = objectsKnockedDown;
// Resume music
LK.playMusic('mainTheme');
}
// Play main theme music
LK.playMusic('mainTheme');
game.update = function () {
// Handle countdown before normal game logic
if (isCountingDown) {
countdownTimer++;
// Change countdown number every 60 ticks (1 second)
if (countdownTimer === 60) {
countdownValue = 2;
countdownText.setText('2');
// Scale animation for countdown number
tween(countdownText, {
scaleX: 1.2,
scaleY: 1.2
}, {
duration: 200,
easing: tween.bounceOut,
onFinish: function onFinish() {
tween(countdownText, {
scaleX: 1,
scaleY: 1
}, {
duration: 200,
easing: tween.easeOut
});
}
});
} else if (countdownTimer === 120) {
countdownValue = 1;
countdownText.setText('1');
// Scale animation for countdown number
tween(countdownText, {
scaleX: 1.2,
scaleY: 1.2
}, {
duration: 200,
easing: tween.bounceOut,
onFinish: function onFinish() {
tween(countdownText, {
scaleX: 1,
scaleY: 1
}, {
duration: 200,
easing: tween.easeOut
});
}
});
} else if (countdownTimer === 180) {
countdownText.setText('START');
// Bigger scale animation for START
tween(countdownText, {
scaleX: 1.5,
scaleY: 1.5
}, {
duration: 300,
easing: tween.bounceOut,
onFinish: function onFinish() {
tween(countdownText, {
scaleX: 1,
scaleY: 1
}, {
duration: 300,
easing: tween.easeOut
});
}
});
} else if (countdownTimer >= 240) {
// End countdown and start game
isCountingDown = false;
countdownBackground.visible = false;
countdownText.visible = false;
cat.speed = catStartSpeed; // Restore cat movement speed
}
// Don't update game timer or other game logic during countdown
return;
}
gameTimer++;
var remainingTime = Math.max(0, Math.ceil((TIME_LIMIT - gameTimer) / 60));
timerText.setText('Time: ' + remainingTime);
// Update progress display based on objects that are NOT falling
var actualObjectsRemaining = 0;
for (var j = 0; j < shelfObjects.length; j++) {
if (!shelfObjects[j].isFalling) {
actualObjectsRemaining++;
}
}
var actualObjectsKnockedDown = totalObjectsToKnock - actualObjectsRemaining;
progressText.setText('Stage ' + currentStage + ' - Objects: ' + actualObjectsKnockedDown + '/' + totalObjectsToKnock);
// Update score display with current calculated score
var currentRemainingSeconds = Math.max(0, Math.ceil((TIME_LIMIT - gameTimer) / 60));
var currentScore = Math.max(0, currentRemainingSeconds * 10 - obstaclePenalties);
scoreText.setText('Score: ' + currentScore);
// Check if time limit reached (only if cat is not dancing - i.e., game hasn't been won)
if (gameTimer >= TIME_LIMIT && !cat.isDancing) {
// Time's up - player loses regardless of objects remaining
LK.showGameOver();
return;
}
spawnObject();
spawnDangerousObject();
// Laser removed
spawnMouse();
spawnDog();
spawnLamp();
spawnSoap();
updateCamera();
// Keep all objects persistent - no cleanup during gameplay
// Objects remain in their positions until knocked down by the cat
// Only clean up non-persistent objects that spawn dynamically
for (var i = dangerousObjects.length - 1; i >= 0; i--) {
var dangerousObj = dangerousObjects[i];
if (dangerousObj.x < cameraX - 500) {
dangerousObj.destroy();
dangerousObjects.splice(i, 1);
}
}
// Laser cleanup removed
// Separators are now persistent and don't need cleanup
// Clean up lamps only if they have fallen off screen, not just off camera
for (var i = lamps.length - 1; i >= 0; i--) {
var lamp = lamps[i];
if (lamp.y > 2732 + 100 && lamp.isFalling) {
lamp.destroy();
lamps.splice(i, 1);
}
}
// Clean up soaps only if they have been used and destroyed
for (var i = soaps.length - 1; i >= 0; i--) {
var soap = soaps[i];
if (soap.alpha <= 0 || soap.destroyed) {
soaps.splice(i, 1);
}
}
// Clean up mice
for (var i = mice.length - 1; i >= 0; i--) {
var mouse = mice[i];
if (mouse.x < cameraX - 600 || mouse.x > cameraX + 2500) {
if (mouse === cat.chaseTarget) {
cat.isChasing = false;
cat.chaseTarget = null;
}
mouse.destroy();
mice.splice(i, 1);
}
}
// Dogs no longer disappear automatically - only when hit by falling objects
// Keep dogs persistent in the game world
}; ===================================================================
--- original.js
+++ change.js
@@ -1728,12 +1728,30 @@
// Handle falling behavior if dog was hit
if (self.isFalling) {
// Stop barking and hide all dog graphics when falling
for (var c = 0; c < self.children.length; c++) {
- if (self.children[c] !== self.fallenGraphics) {
+ if (self.children[c] !== self.fallenGraphics && self.children[c] !== self.fallenGraphics2) {
self.children[c].visible = false;
}
}
+ // Handle alternating animation between perroCae and perroCae2
+ if (self.fallAnimTimer !== undefined) {
+ self.fallAnimTimer++;
+ if (self.fallAnimTimer >= 15) {
+ // Switch every 15 frames (0.25 seconds)
+ self.fallAnimTimer = 0;
+ self.showingFirstAsset = !self.showingFirstAsset;
+ if (self.fallenGraphics && self.fallenGraphics2) {
+ if (self.showingFirstAsset) {
+ self.fallenGraphics.visible = true;
+ self.fallenGraphics2.visible = false;
+ } else {
+ self.fallenGraphics.visible = false;
+ self.fallenGraphics2.visible = true;
+ }
+ }
+ }
+ }
self.y += self.fallSpeed;
self.fallSpeed += 0.3; // Gravity
// No rotation when falling - fall straight down
// Check collision with barriers while falling
@@ -2117,19 +2135,31 @@
// Hide ALL existing dog graphics - ensure only perroCae is visible
for (var c = 0; c < dog.children.length; c++) {
dog.children[c].visible = false;
}
- // Create fallen dog graphics with perroCae asset if not exists
+ // Create both fallen dog graphics if they don't exist
if (!dog.fallenGraphics) {
dog.fallenGraphics = dog.attachAsset('perroCae', {
anchorX: 0.5,
anchorY: 1,
scaleX: 4,
scaleY: 4
});
}
- // Ensure only perroCae is visible
+ if (!dog.fallenGraphics2) {
+ dog.fallenGraphics2 = dog.attachAsset('perroCae2', {
+ anchorX: 0.5,
+ anchorY: 1,
+ scaleX: 4,
+ scaleY: 4
+ });
+ }
+ // Initialize alternation timer and state
+ dog.fallAnimTimer = 0;
+ dog.showingFirstAsset = true;
+ // Start with perroCae visible
dog.fallenGraphics.visible = true;
+ dog.fallenGraphics2.visible = false;
// Remove the object that hit the dog
self.destroy();
var index = shelfObjects.indexOf(self);
if (index > -1) {
Tabla de madera vista de costado, muy fina. Pixel art. In-Game asset. 2d. High contrast. No shadows
Raton tipo pixel art earthworm jim, la personalidad del ratón debe ser frenética asustadizo como la de ten de ten y stimpy, debe estar en cuatro patas. In-Game asset. 2d. High contrast. No shadows
Un perro bobo ladrando con los ojos cerrados pixel art dientes grandes, estilo earthworm jim. In-Game asset. 2d. High contrast. No shadows
Una madera separadora de estantería pixel art estilo metal slug vista de perfil In-Game asset. 2d. High contrast. No shadows
plato con decoraciones de oro pixel art metal slug style. In-Game asset. 2d. High contrast. No shadows
un vaso con agua estilo pixel art metal slug. In-Game asset. 2d. High contrast. No shadows
Un jabon con espuma, pixel art, metal slug. In-Game asset. 2d. High contrast. No shadows
hazlo con fondo verde, con el mismo estilo dando un sarpazo con mirada burlona a la camara
hazlo con fondo verde, con el mismo estilo cerrando los dientes con fuerza y bronca
Con el mismo estilo, modo cauteloso con la boca cerrada
Un foco pixel art tipo metal slug. In-Game asset. 2d. High contrast. No shadows
Un velador con base muy simple, sin lampara, tipo pixel art meta slug. In-Game asset. 2d. High contrast. No shadows
El mudo gato con el mismo estilo pero electrocutado con fondo verde
puedes cambiar la posicion de las patas, es decir las que estan atras pasan adelante y viceversa, con el mismo estilo pixel art de la foto original y fondo azul
cambia la posicion de las piernas como si hubiese dado un paso con el mismo estilo pixel art
Maceta con una flor, pixel art metal slug. In-Game asset. 2d. High contrast. No shadows
Puedes encerrarlo en una burbuja
En medio de un salto con el mismo estilo pixel art y fondo verde
con cara arrogante tiene que tirar un beso a camara y mostrar un corazon, la imagen sarcastica y graciosa, con fondo verde
El gato de estar sentado sobre sus dos patas traseras señalando hacia adelante y mirando a la cámara como irónicamente porque no puedes seguir avanzando
una pecera con un pez durmiendo, con estilo pixel art de metal slug con fondo verde. In-Game asset. 2d. High contrast. No shadows
el gato asustado arqueado con los pelos parados con el mismo estilo pixel art
un iphone en pixel art que tenga en la pantalla un ninja con una estrella y un rollo de papel higienico estilo comico. In-Game asset. 2d. High contrast. No shadows
el pez asustadisimo con estilo comico sin sombra con fondo verde
imagina un portatil que tenga en la pantalla la imagen actual, debe ser pixel art y con estilo comico
quiero construir una columa cilindrica muy larga de madera, para eso tengo que recurrir a repetir assets uno arriba del otro , puedes crear un segmento que pueda repetirse en pixel art?. In-Game asset. 2d. High contrast. No shadows
necesito construir un background para un hud, color madera clarito con 2 tornillos en los extremos bien en los bordes, con un borde viselado pixel art, muchisimo mas ancho que alto (relacion 5 - 20 aprox). In-Game asset. 2d. High contrast. No shadows
imagina un fondo con el mismo estilo del juego, debe decir arriba, Catatack y tener un estilo gatuno, siempre en pixel art, en el medio de la imagen, pondre texto variable, debes dejar ese espacio libre.. In-Game asset. 2d. High contrast. No shadows
reimaginalo bailando como tony manero en fiebre de sabado por la noche con fondo verde
una bola de espejos tipo fiebre de sabado por la noche con estilo pixel art con el cable de donde cuelga largo, con fondo verde . In-Game asset. 2d. High contrast. No shadows
perro cayendo de mucha altura asustadisimo con el mismo estilo con fondo verde, muy gracioso
dibuja 3 zetas en vez de 2, manten el mismo estilo pixel art