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.isScared = false; self.scareTimer = 0; self.lastScareTime = 0; self.scareCooldown = 300; // 5 seconds at 60fps 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, running from dog, or scared if (!self.isElectrocuted && (!self.isSlipping || self.slipTimer % 30 !== 0) && !self.isInBubble && !self.isZarpazoMode && !self.isKissMode && !self.isHitMode && !self.isBlockMode && !self.isRunningFromDog && !self.isScared) { 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 && !self.isScared) { 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 scared state timer if (self.isScared) { self.scareTimer++; // Flash effect during scared state catGraphics.alpha = Math.sin(LK.ticks * 0.8) * 0.3 + 0.7; // Scared state lasts for 3 seconds (180 ticks) if (self.scareTimer >= 180) { self.isScared = false; self.scareTimer = 0; self.speed = self.normalSpeed; // Restore movement catGraphics.alpha = 1; // Restore normal opacity } } // 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 if dog is directly on top of cat (scared behavior) if (!self.isFalling && !self.isScared) { var dogShelfLevel = -1; for (var level = 0; level < 5; level++) { if (Math.abs(self.y - (shelfLevels[level] - 75)) < 50) { dogShelfLevel = level; break; } } // Check if cat is on the same shelf and dog is close enough to be "on top" if (dogShelfLevel === cat.currentShelfLevel) { var horizontalDistance = Math.abs(self.x - cat.x); var verticalDistance = Math.abs(self.y - cat.y); // Dog is "on top" if very close horizontally and vertically aligned if (horizontalDistance < 80 && verticalDistance < 50) { var timeSinceLastScare = LK.ticks - cat.lastScareTime; // Only scare if cooldown has passed if (timeSinceLastScare >= cat.scareCooldown) { cat.isScared = true; cat.scareTimer = 0; cat.lastScareTime = LK.ticks; cat.speed = 0; // Cat cannot move when scared LK.getSound('dogBark').play(); LK.effects.flashObject(cat, 0xFFFF00, 500); // Yellow flash for scared } } } } // 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 () { // Handle alternating animation for pecera (fish tank) when at rest if (objectType === 4 && !self.isFalling) { // Initialize animation timer if not exists if (self.peceraAnimTimer === undefined) { self.peceraAnimTimer = 0; self.showingPecera1 = true; // Create pecera2 graphics if not exists if (!self.pecera2Graphics) { self.pecera2Graphics = self.attachAsset('pecera2', { anchorX: 0.5, anchorY: 0.5, scaleX: 4, scaleY: 4 }); self.pecera2Graphics.visible = false; } } self.peceraAnimTimer++; if (self.peceraAnimTimer >= 30) { // Switch every 30 frames (0.5 seconds) self.peceraAnimTimer = 0; self.showingPecera1 = !self.showingPecera1; if (self.showingPecera1) { objectGraphics.visible = true; // Show pecera if (self.pecera2Graphics) { self.pecera2Graphics.visible = false; // Hide pecera2 } } else { objectGraphics.visible = false; // Hide pecera if (self.pecera2Graphics) { self.pecera2Graphics.visible = true; // Show pecera2 } } } } 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
@@ -91,8 +91,12 @@
self.floatingTimer = 0;
self.isRunningFromDog = false;
self.runningTimer = 0;
self.originalSpeed = self.normalSpeed;
+ self.isScared = false;
+ self.scareTimer = 0;
+ self.lastScareTime = 0;
+ self.scareCooldown = 300; // 5 seconds at 60fps
self.gatoBailaGraphics = self.attachAsset('gatoBaila', {
anchorX: 0.5,
anchorY: 1,
// Use bottom anchor for proper grounding during dance
@@ -578,10 +582,10 @@
// 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) {
+ // Handle horizontal movement when not electrocuted, slipping, in bubble, in zarpazo, kiss, hit, block mode, running from dog, or scared
+ if (!self.isElectrocuted && (!self.isSlipping || self.slipTimer % 30 !== 0) && !self.isInBubble && !self.isZarpazoMode && !self.isKissMode && !self.isHitMode && !self.isBlockMode && !self.isRunningFromDog && !self.isScared) {
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) {
@@ -655,9 +659,9 @@
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) {
+ if (self.isRunningFromDog && !self.isElectrocuted && !self.isInBubble && !self.isZarpazoMode && !self.isKissMode && !self.isHitMode && !self.isBlockMode && !self.isScared) {
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) {
@@ -1316,8 +1320,21 @@
}
});
}
}
+ // Handle scared state timer
+ if (self.isScared) {
+ self.scareTimer++;
+ // Flash effect during scared state
+ catGraphics.alpha = Math.sin(LK.ticks * 0.8) * 0.3 + 0.7;
+ // Scared state lasts for 3 seconds (180 ticks)
+ if (self.scareTimer >= 180) {
+ self.isScared = false;
+ self.scareTimer = 0;
+ self.speed = self.normalSpeed; // Restore movement
+ catGraphics.alpha = 1; // Restore normal opacity
+ }
+ }
// Handle invulnerability timer
if (self.isInvulnerable) {
self.invulnerabilityTimer--;
// Flash effect during invulnerability (only if not electrocuted)
@@ -1753,8 +1770,36 @@
}
self.y += self.fallSpeed;
self.fallSpeed += 0.3; // Gravity
// No rotation when falling - fall straight down
+ // Check if dog is directly on top of cat (scared behavior)
+ if (!self.isFalling && !self.isScared) {
+ var dogShelfLevel = -1;
+ for (var level = 0; level < 5; level++) {
+ if (Math.abs(self.y - (shelfLevels[level] - 75)) < 50) {
+ dogShelfLevel = level;
+ break;
+ }
+ }
+ // Check if cat is on the same shelf and dog is close enough to be "on top"
+ if (dogShelfLevel === cat.currentShelfLevel) {
+ var horizontalDistance = Math.abs(self.x - cat.x);
+ var verticalDistance = Math.abs(self.y - cat.y);
+ // Dog is "on top" if very close horizontally and vertically aligned
+ if (horizontalDistance < 80 && verticalDistance < 50) {
+ var timeSinceLastScare = LK.ticks - cat.lastScareTime;
+ // Only scare if cooldown has passed
+ if (timeSinceLastScare >= cat.scareCooldown) {
+ cat.isScared = true;
+ cat.scareTimer = 0;
+ cat.lastScareTime = LK.ticks;
+ cat.speed = 0; // Cat cannot move when scared
+ LK.getSound('dogBark').play();
+ LK.effects.flashObject(cat, 0xFFFF00, 500); // Yellow flash for scared
+ }
+ }
+ }
+ }
// Check collision with barriers while falling
for (var b = 0; b < separators.length; b++) {
var separator = separators[b];
if (self.intersects(separator) && separator.isBlocking) {
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