User prompt
haz que al tocar el high score zen mode 2 veces, seek mode 1 y fast mode 3 salga un easter egg 3 durante 5 segundos
User prompt
Please fix the bug: 'Uncaught ReferenceError: showEasterEgg3 is not defined' in or related to this line: 'showEasterEgg3();' Line Number: 990
User prompt
haz que al tocar el high score zen mode 2 veces, seek mode 1 y fast mode 3 salga un easter egg 3 durante 5 segundos ↪💡 Consider importing and using the following plugins: @upit/tween.v1
User prompt
cuando se toque 10 veces el titulo este cambia su asset por el de easter egg 2
User prompt
Please fix the bug: 'Uncaught TypeError: Cannot read properties of undefined (reading 'addChildAt')' in or related to this line: 'title.parent.addChildAt(newTitle, idx);' Line Number: 623
User prompt
cuando se toque 10 veces el titulo este cambia su asset por el de easter egg 2
User prompt
cuando se toque 10 veces el titulo este cambia por easter egg 2
User prompt
cuando se toque 100 veces el titulo este cambia por easter egg 2
User prompt
Haz que el easter egg dure 10 segundos y tenga un sonido
User prompt
Haz que las canciones cambien al finalizar
User prompt
Arregla el error que al regresar al menú inicial se crean múltiples particulas de memes
User prompt
Haz que los memes especiales que se producen al mezclar un meme especial verde con bomba/clear salgan con el asset adecuado encima
User prompt
Al entrar al juego la opción de Bg color parece estar desactivada aunque se haya guardado como on
User prompt
Arregla el error que have que bg no cambie de color, aunque este activo, a menos que desactives y actives la opción
User prompt
Arregla el error que al iniciar el juego bg no cambia de color aunque este activado
User prompt
Baja los botones en el eje Y, agrega más espaciado, el texto de Bg color animación cámbialo a BG Color
User prompt
Mejora la separación y posición de todos los botones del menu de configuración (ten en cuenta el botón de reinicio)
User prompt
Mejora la separación de las opciones de configuración y su ubicación
User prompt
Agrega una opción para desactivar las partículas
User prompt
Agrega un botón para desactivar el cambio de color del fondo
User prompt
Haz que las configuraciones se guarden y carguen ↪💡 Consider importing and using the following plugins: @upit/storage.v1
User prompt
Agrega una opción para desactivar la introducción
/****
* Plugins
****/
var tween = LK.import("@upit/tween.v1");
var storage = LK.import("@upit/storage.v1", {
highScoreClassic: 0,
highScoreFast: 0,
highScoreSeek: 0
});
/****
* Classes
****/
var CosmeticsScreen = Container.expand(function () {
var self = Container.call(this);
var title = new Text2("Cosmetics", {
size: 150,
fill: 0x000000
});
title.anchor.set(0.5, 0);
title.x = 2048 / 2;
title.y = 300;
self.addChild(title);
title.y = 200;
self.cosmeticsGrid = new Container();
self.addChild(self.cosmeticsGrid);
var cosmeticSets = [{
id: 1,
name: "Default",
memePrefix: 'meme'
}, {
id: 2,
name: "Variant 1",
memePrefix: 'meme1-2'
}, {
id: 3,
name: "Variant 2",
memePrefix: 'meme1-3'
}];
var cardWidth = 550;
var cardHeight = 680;
var cardsPerRow = 3;
var cardSpacing = 50;
var startX = (2048 - (cardsPerRow * cardWidth + (cardsPerRow - 1) * cardSpacing)) / 2 + cardWidth / 2;
var startY = 700;
cosmeticSets.forEach(function (set, index) {
var row = Math.floor(index / cardsPerRow);
var col = index % cardsPerRow;
var card = new Container();
card.x = startX + col * (cardWidth + cardSpacing);
card.y = startY + row * (cardHeight + 80);
var cardShadow = LK.getAsset('button', {
anchorX: 0.5,
anchorY: 0.5,
scaleX: 2.6,
scaleY: 3.6
});
cardShadow.tint = 0x000000;
cardShadow.alpha = 0.3;
cardShadow.x = 10;
cardShadow.y = 10;
var cardBg = LK.getAsset('button', {
anchorX: 0.5,
anchorY: 0.5,
scaleX: 2.5,
scaleY: 3.5
});
cardBg.tint = 0xFFFFFF;
var nameText = new Text2(set.name, {
size: 70,
fill: 0x000000
});
nameText.anchor.set(0.5, 0);
nameText.y = -cardHeight / 2 + 80;
var setLabel = new Text2("MEME SET", {
size: 40,
fill: 0x555555
});
setLabel.anchor.set(0.5, 1);
setLabel.y = cardHeight / 2 - 40;
function animateCard() {
tween(card, {
y: card.y - 10
}, {
duration: 800,
easing: tween.easeInOutQuad,
onComplete: function onComplete() {
tween(card, {
y: card.y + 10
}, {
duration: 800,
easing: tween.easeInOutQuad,
onComplete: animateCard
});
}
});
}
LK.setTimeout(animateCard, Math.random() * 1000);
var previewContainer = new Container();
var previewSize = 120;
var previewSpacing = 20;
var previewScale = 0.6;
var previewsPerRow = 3;
var previewGridWidth = previewsPerRow * previewSize + (previewsPerRow - 1) * previewSpacing;
var previewStartX = -previewGridWidth / 2 + previewSize / 2;
var previewStartY = -40;
for (var i = 1; i <= 5; i++) {
var row = Math.floor((i - 1) / previewsPerRow);
var col = (i - 1) % previewsPerRow;
var preview;
if (set.id === 1) {
preview = LK.getAsset('meme' + i, {
anchorX: 0.5,
anchorY: 0.5,
scaleX: previewScale,
scaleY: previewScale
});
} else if (set.id === 2) {
preview = LK.getAsset('meme' + i + '-2', {
anchorX: 0.5,
anchorY: 0.5,
scaleX: previewScale,
scaleY: previewScale
});
} else {
preview = LK.getAsset('meme' + i + '-3', {
anchorX: 0.5,
anchorY: 0.5,
scaleX: previewScale,
scaleY: previewScale
});
}
preview.x = previewStartX + col * (previewSize + previewSpacing);
preview.y = previewStartY + row * (previewSize + previewSpacing);
var previewBg = LK.getAsset('button', {
anchorX: 0.5,
anchorY: 0.5,
scaleX: 0.6,
scaleY: 0.6,
alpha: 0.1
});
previewBg.tint = 0x888888;
previewBg.x = preview.x;
previewBg.y = preview.y;
previewContainer.addChild(previewBg);
previewContainer.addChild(preview);
}
var statusOverlay = new Container();
card.statusOverlay = statusOverlay;
var isSelected = set.id === 1; // Default always to set 1
if (isSelected) {
var _pulseBorder = function pulseBorder() {
tween(selectedBorder, {
alpha: 0.2
}, {
duration: 700,
easing: tween.easeInOutQuad,
onComplete: function onComplete() {
tween(selectedBorder, {
alpha: 0.5
}, {
duration: 700,
easing: tween.easeInOutQuad,
onComplete: _pulseBorder
});
}
});
};
var selectedBorder = LK.getAsset('button', {
anchorX: 0.5,
anchorY: 0.5,
scaleX: 2.6,
scaleY: 3.6
});
selectedBorder.tint = 0x00FF00;
selectedBorder.alpha = 0.5;
_pulseBorder();
var checkmark = LK.getAsset('check', {
anchorX: 0.5,
anchorY: 0.5,
scaleX: 1,
scaleY: 1
});
checkmark.x = cardWidth / 2 - 70;
checkmark.y = -cardHeight / 2 + 70;
card.addChildAt(selectedBorder, 0);
statusOverlay.addChild(checkmark);
}
card.addChild(cardShadow);
card.addChild(cardBg);
card.addChild(nameText);
card.addChild(setLabel);
card.addChild(previewContainer);
card.addChild(statusOverlay);
card.interactive = true;
card.setId = set.id;
card.isUnlocked = true;
card.price = set.price;
card.down = function (x, y, obj) {
LK.effects.flashObject(cardBg, 0xFFFFFF, 200);
LK.getSound('ButtonSound').play();
// Update selectedSet and persist to storage
selectedSet = card.setId;
storage.selectedSet = selectedSet;
self.cosmeticsGrid.children.forEach(function (otherCard) {
otherCard.children.forEach(function (child) {
if (child.tint === 0x00FF00 && child !== cardBg) {
otherCard.removeChild(child);
}
});
if (otherCard.statusOverlay) {
while (otherCard.statusOverlay.children.length > 0) {
otherCard.statusOverlay.removeChild(otherCard.statusOverlay.children[0]);
}
}
});
var selectedBorder = LK.getAsset('button', {
anchorX: 0.5,
anchorY: 0.5,
scaleX: 2.6,
scaleY: 3.6
});
selectedBorder.tint = 0x00FF00;
var checkmark = LK.getAsset('check', {
anchorX: 0.5,
anchorY: 0.5,
scaleX: 1,
scaleY: 1
});
checkmark.x = cardWidth / 2 - 70;
checkmark.y = -cardHeight / 2 + 70;
checkmark.isCheckmark = true;
card.addChildAt(selectedBorder, 0);
statusOverlay.addChild(checkmark);
};
self.cosmeticsGrid.addChild(card);
});
var backButton = createButton("BACK TO MENU", 0xFF5500, 3, 1.5, function () {
game.removeChild(self);
initializeMenu();
}, 2048 / 2, 2732 - 200);
self.addChild(backButton);
return self;
});
var GridCell = Container.expand(function () {
var self = Container.call(this);
self.init = function () {
self.value = 0;
self.sprite = null;
self.row = -1;
self.col = -1;
self.isSpecial = false;
self.specialType = null;
return self;
};
self.setValue = function (newValue) {
if (self.value === newValue) {
return;
}
self.value = newValue;
if (self.sprite) {
self.removeChild(self.sprite);
}
var spriteId;
if (game && game.gameMode === 'seekmode' && game.seekModeForceSeekSprite) {
spriteId = 'seek';
} else {
// Default to meme set 1
// Use global selectedSet for cosmetics
if (typeof selectedSet !== "number") selectedSet = 1;
if (selectedSet === 1) {
spriteId = 'meme' + newValue;
} else if (selectedSet === 2) {
spriteId = 'meme' + newValue + '-2';
} else if (selectedSet === 3) {
spriteId = 'meme' + newValue + '-3';
} else {
spriteId = 'meme' + newValue;
}
}
self.sprite = LK.getAsset(spriteId, {
anchorX: 0.5,
anchorY: 0.5
});
var padding = 20;
var maxWidth = cellSize - padding * 2;
var maxHeight = cellSize - padding * 2;
var scaleX = maxWidth / self.sprite.width;
var scaleY = maxHeight / self.sprite.height;
var scale = Math.min(scaleX, scaleY);
self.sprite.scale.set(scale, scale);
self.addChild(self.sprite);
if (self.isSpecial) {
// Remove any previous overlays
if (self.specialOverlay && self.children.indexOf(self.specialOverlay) !== -1) {
self.removeChild(self.specialOverlay);
self.specialOverlay = null;
}
// --- Special overlays for green+bomb and green+clear/line combos ---
// If this cell was created as a result of a green+bomb or green+clear/line combo, show the overlay on top of the meme asset
if (self.specialType === 'bomb') {
// Overlay habilidadBomba sprite
self.specialOverlay = LK.getAsset('habilidadBomba', {
anchorX: 0.5,
anchorY: 0.5
});
// Scale overlay to fit cell
var padding = 20;
var maxWidth = cellSize - padding * 2;
var maxHeight = cellSize - padding * 2;
var scaleX = maxWidth / self.specialOverlay.width;
var scaleY = maxHeight / self.specialOverlay.height;
var scale = Math.min(scaleX, scaleY);
self.specialOverlay.scale.set(scale, scale);
self.addChild(self.specialOverlay);
// --- Color sync: animate overlay tint with background ---
if (typeof colorTweenTargets !== "undefined" && typeof currentColorIndex !== "undefined") {
var _tweenBombOverlayColor = function tweenBombOverlayColor() {
if (!self.specialOverlay) {
return;
}
var nextIndex = (currentColorIndex + 1) % colorTweenTargets.length;
var nextColor = colorTweenTargets[nextIndex];
self._specialOverlayTween = tween(self.specialOverlay, {
tint: nextColor
}, {
duration: 14000,
easing: tween.easeInOutQuad,
onFinish: function onFinish() {
if (self.specialOverlay) {
_tweenBombOverlayColor();
}
}
});
};
// Remove any previous color tween
if (self._specialOverlayTween) {
self._specialOverlayTween.stop && self._specialOverlayTween.stop();
self._specialOverlayTween = null;
}
self.specialOverlay.tint = colorTweenTargets[currentColorIndex];
_tweenBombOverlayColor();
}
} else if (self.specialType === 'green') {
// Use the 'habilidadVerde' asset for green special ability
if (self.sprite) {
self.removeChild(self.sprite);
}
self.sprite = LK.getAsset('habilidadVerde', {
anchorX: 0.5,
anchorY: 0.5
});
// Scale to fit cell
var padding = 20;
var maxWidth = cellSize - padding * 2;
var maxHeight = cellSize - padding * 2;
var scaleX = maxWidth / self.sprite.width;
var scaleY = maxHeight / self.sprite.height;
var scale = Math.min(scaleX, scaleY);
self.sprite.scale.set(scale, scale);
self.addChild(self.sprite);
} else if (self.specialType === 'clear' || self.specialType === 'vertical' || self.specialType === 'horizontal') {
// Overlay habilidadClear sprite for clear/line specials
self.specialOverlay = LK.getAsset('HabilidadClear', {
anchorX: 0.5,
anchorY: 0.5
});
// Rotate overlay to match direction
if (self.specialType === 'horizontal') {
self.specialOverlay.rotation = 0; // Horizontal: no rotation
} else if (self.specialType === 'vertical') {
self.specialOverlay.rotation = Math.PI / 2; // Vertical: 90 degrees
} else {
self.specialOverlay.rotation = 0; // Default for 'clear'
}
// Scale overlay to fit cell
var padding = 20;
var maxWidth = cellSize - padding * 2;
var maxHeight = cellSize - padding * 2;
var scaleX = maxWidth / self.specialOverlay.width;
var scaleY = maxHeight / self.specialOverlay.height;
var scale = Math.min(scaleX, scaleY);
self.specialOverlay.scale.set(scale, scale);
self.addChild(self.specialOverlay);
// --- Color sync: animate overlay tint with background ---
if (typeof colorTweenTargets !== "undefined" && typeof currentColorIndex !== "undefined") {
var _tweenClearOverlayColor = function tweenClearOverlayColor() {
if (!self.specialOverlay) {
return;
}
var nextIndex = (currentColorIndex + 1) % colorTweenTargets.length;
var nextColor = colorTweenTargets[nextIndex];
self._specialOverlayTween = tween(self.specialOverlay, {
tint: nextColor
}, {
duration: 14000,
easing: tween.easeInOutQuad,
onFinish: function onFinish() {
if (self.specialOverlay) {
_tweenClearOverlayColor();
}
}
});
};
// Remove any previous color tween
if (self._specialOverlayTween) {
self._specialOverlayTween.stop && self._specialOverlayTween.stop();
self._specialOverlayTween = null;
}
self.specialOverlay.tint = colorTweenTargets[currentColorIndex];
_tweenClearOverlayColor();
}
} else {
self.sprite.tint = 0xFF8800;
}
}
};
self.activateSpecialPower = function () {
if (!self.isSpecial) {
return;
}
var cellsToDestroy = [];
var bonusPoints = 0;
if (self.specialType === 'horizontal') {
for (var row = extraRows; row < gridSize + extraRows; row++) {
if (gridCells[row][self.col] && gridCells[row][self.col] !== self) {
cellsToDestroy.push(gridCells[row][self.col]);
}
}
bonusPoints = 100;
} else if (self.specialType === 'vertical') {
for (var col = 0; col < gridSize; col++) {
if (gridCells[self.row][col] && gridCells[self.row][col] !== self) {
cellsToDestroy.push(gridCells[self.row][col]);
}
}
bonusPoints = 100;
} else if (self.specialType === 'bomb') {
for (var row = Math.max(extraRows, self.row - 1); row <= Math.min(gridSize + extraRows - 1, self.row + 1); row++) {
for (var col = Math.max(0, self.col - 1); col <= Math.min(gridSize - 1, self.col + 1); col++) {
if (gridCells[row][col] && gridCells[row][col] !== self) {
cellsToDestroy.push(gridCells[row][col]);
}
}
}
bonusPoints = 150;
} else if (self.specialType === 'green') {
self.value = 99; // Ensure green special always has value 99
bonusPoints = 200;
}
// No score pop-up needed
if (cellsToDestroy.length > 0) {
destroyCells(cellsToDestroy);
self.beingDestroyed = true;
LK.getSound('Explosion').play();
LK.effects.flashObject(self, 0xFFFFFF, 200);
gridContainer.removeChild(self);
self.destroy();
gridCells[self.row][self.col] = null;
}
};
self.showSelection = function () {
if (self.selectionHighlight) {
return;
}
self.selectionHighlight = new Container();
var highlight = LK.getAsset('cuadricula', {
anchorX: 0.5,
anchorY: 0.5,
scaleX: 1.15,
scaleY: 1.15,
alpha: 0.6
});
highlight.tint = 0x00FFFF;
self.selectionHighlight.addChild(highlight);
self.addChildAt(self.selectionHighlight, 0);
function pulseAnimation() {
tween(highlight, {
alpha: 0.3,
scaleX: 1.2,
scaleY: 1.2
}, {
duration: 500,
easing: tween.easeInOutQuad,
onComplete: function onComplete() {
tween(highlight, {
alpha: 0.6,
scaleX: 1.15,
scaleY: 1.15
}, {
duration: 500,
easing: tween.easeInOutQuad,
onComplete: pulseAnimation
});
}
});
}
pulseAnimation();
};
self.hideSelection = function () {
if (self.selectionHighlight) {
self.removeChild(self.selectionHighlight);
self.selectionHighlight = null;
}
};
self.down = function (x, y, obj) {
handleCellTap(self);
};
self.init();
return self;
});
var MemeParticle = Container.expand(function () {
var self = Container.call(this);
self.init = function (textureId) {
self.textureId = textureId;
if (self.sprite) {
self.removeChild(self.sprite);
}
self.sprite = self.attachAsset(self.textureId, {
anchorX: 0.5,
anchorY: 0.5
});
self.alpha = 0.8;
// Aumenta el tamaño un 20%
self.scale.set(0.6);
// Aumenta la velocidad (dobla la velocidad base)
self.speedX = (Math.random() - 0.5) * 2;
self.speedY = 1.0 + Math.random() * 1.0;
self.rotationSpeed = (Math.random() - 0.5) * 0.05;
return self;
};
self.update = function () {
self.x += self.speedX;
self.y += self.speedY;
self.rotation += self.rotationSpeed;
if (self.y > 2732 + 100 || self.x < -100 || self.x > 2048 + 100) {
self.destroy();
}
};
return self;
});
var MenuScreen = Container.expand(function () {
var self = Container.call(this);
// Initialize title touch counter
self.titleTouchCount = 0;
var title = self.attachAsset('titulo', {
anchorX: 0.5,
anchorY: 0,
scaleX: 3,
scaleY: 3
});
title.x = 2048 / 2;
title.y = 300;
title.interactive = true;
// Add touch functionality to title
title.down = function (x, y, obj) {
self.titleTouchCount++;
// Flash title when touched
LK.effects.flashObject(title, 0xFFFFFF, 200);
// After 10 touches, change title to easter egg 2
if (self.titleTouchCount >= 10) {
// Remove the current title
self.removeChild(title);
// Create new title with easterEgg2 asset
title = self.attachAsset('easterEgg2', {
anchorX: 0.5,
anchorY: 0,
scaleX: 3,
scaleY: 3
});
title.x = 2048 / 2;
title.y = 300;
// Play a sound effect for the easter egg
LK.getSound('Explosion').play();
}
};
function pulseTitle() {
tween(title, {
scaleX: 3.2,
scaleY: 3.4,
y: 200
}, {
duration: 400,
easing: tween.easeOutQuad,
onFinish: function onFinish() {
tween(title, {
scaleX: 3.5,
scaleY: 2.7,
y: 350
}, {
duration: 300,
easing: tween.easeInQuad,
onFinish: function onFinish() {
tween(title, {
rotation: -0.05,
scaleX: 3.1,
scaleY: 3.2,
y: 320
}, {
duration: 180,
easing: tween.easeOutQuad,
onFinish: function onFinish() {
tween(title, {
rotation: 0.05,
scaleX: 3.2,
scaleY: 3.1
}, {
duration: 180,
easing: tween.easeInOutQuad,
onFinish: function onFinish() {
tween(title, {
rotation: 0,
scaleX: 3,
scaleY: 3,
y: 300
}, {
duration: 250,
easing: tween.easeOutElastic,
onFinish: function onFinish() {
LK.setTimeout(pulseTitle, 800);
}
});
}
});
}
});
}
});
}
});
}
pulseTitle();
// First column
var classicButton = createButton("ZEN MODE", 0x00AA00, 3, 1.5, function () {
self.startGame('classic');
}, 2048 / 4, 2732 / 2 + 400);
self.addChild(classicButton);
var seekModeButton = createButton("SEEK MODE", 0xDD5500, 3, 1.5, function () {
self.startGame('seekmode');
}, 2048 / 4, 2732 / 2 + 700);
self.addChild(seekModeButton);
var fastButton = createButton("FAST MODE", 0x0088FF, 3, 1.5, function () {
self.startGame('fast');
}, 2048 / 4, 2732 / 2 + 1000);
self.addChild(fastButton);
// Second column
var cosmeticsButton = createButton("COSMETICS", 0x9932CC, 3, 1.5, function () {
game.removeChild(self);
showCosmeticsScreen();
}, 2048 * 3 / 4, 2732 / 2 + 400);
self.addChild(cosmeticsButton);
var recordsButton = createButton("RECORDS", 0xFFA500, 3, 1.5, function () {
game.removeChild(self);
showRecordsScreen();
}, 2048 * 3 / 4, 2732 / 2 + 700);
self.addChild(recordsButton);
var settingsButton = createButton("SETTINGS", 0x800080, 3, 1.5, function () {
game.removeChild(self);
showSettingsScreen();
}, 2048 * 3 / 4, 2732 / 2 + 1000);
self.addChild(settingsButton);
self.startGame = function (mode) {
game.gameMode = mode || 'classic';
game.removeChild(self);
game.initializeGame();
};
self.particleContainer = new Container();
self.addChildAt(self.particleContainer, 0);
self.memeParticles = ['meme1', 'meme2', 'meme3', 'meme4', 'meme5', 'meme1-2', 'meme2-2', 'meme3-2', 'meme4-2', 'meme5-2', 'meme1-3', 'meme2-3', 'meme3-3', 'meme4-3', 'meme5-3'];
self.particleTimer = LK.setInterval(function () {
self.emitParticle();
}, 500);
self.emitParticle = function () {
if (!particlesEnabled) return;
var randomMemeId = self.memeParticles[Math.floor(Math.random() * self.memeParticles.length)];
var particle = new MemeParticle().init(randomMemeId);
particle.x = Math.random() * 2048;
particle.y = -50;
self.particleContainer.addChild(particle);
};
self.update = function () {
self.particleContainer.children.forEach(function (particle) {
if (particle && particle.update) {
// Check collision with pointerSprite (global)
if (typeof pointerSprite !== "undefined" && pointerSprite.visible && particle.x !== undefined && particle.y !== undefined && pointerSprite.x !== undefined && pointerSprite.y !== undefined) {
// Use simple distance check (circle collision)
var dx = particle.x - pointerSprite.x;
var dy = particle.y - pointerSprite.y;
var dist = Math.sqrt(dx * dx + dy * dy);
// Use average radius (particle is 100x100, pointer is 10x10)
if (dist < 55) {
// Trigger explosion: emit particles at this position
if (particlesEnabled) {
var numParticles = 10 + Math.floor(Math.random() * 5);
for (var p = 0; p < numParticles; p++) {
var part = LK.getAsset('particula', {
anchorX: 0.5,
anchorY: 0.5
});
// Randomize color (RGB)
var r = Math.floor(128 + Math.random() * 127);
var g = Math.floor(128 + Math.random() * 127);
var b = Math.floor(128 + Math.random() * 127);
var rgb = r << 16 | g << 8 | b;
part.tint = rgb;
part.x = particle.x;
part.y = particle.y;
// Random velocity and direction
var angle = Math.random() * Math.PI * 2;
var speed = 7 + Math.random() * 7;
var vx = Math.cos(angle) * speed;
var vy = Math.sin(angle) * speed;
// Animate particle
(function (part, vx, vy) {
var lifetime = 180 + Math.random() * 120;
var startAlpha = 0.9 + Math.random() * 0.1;
part.alpha = startAlpha;
self.particleContainer.addChild(part);
var elapsed = 0;
var updateFn = function updateFn() {
part.x += vx;
part.y += vy;
part.alpha -= 0.05 + Math.random() * 0.03;
part.scale.x *= 0.92;
part.scale.y *= 0.92;
elapsed += 16;
if (elapsed > lifetime || part.alpha <= 0.05) {
if (part.parent) {
part.parent.removeChild(part);
}
LK.clearInterval(intervalId);
}
};
var intervalId = LK.setInterval(updateFn, 16);
})(part, vx, vy);
}
}
// Play explosion sound
LK.getSound('Explosion').play();
// --- Easter Egg: cuenta partículas meme destruidas en menú ---
if (!easterEggActive) {
memeParticlesDestroyedInMenu++;
if (memeParticlesDestroyedInMenu >= 20) {
// Mostrar easter egg solo si no está activo
easterEggActive = true;
memeParticlesDestroyedInMenu = 0;
// Crear contenedor del easter egg
easterEggContainer = new Container();
var egg = LK.getAsset('easterEgg', {
anchorX: 0.5,
anchorY: 0.5,
x: 2048 / 2,
y: 2732 / 2,
scaleX: 1.1,
scaleY: 1.1,
alpha: 0.0
});
easterEggContainer.addChild(egg);
// Fade in
tween(egg, {
alpha: 1
}, {
duration: 600
});
// Añadir al menú
self.addChild(easterEggContainer);
easterEggTimeout = LK.setTimeout(function () {
if (easterEggContainer && easterEggContainer.parent) {
// Fade out
tween(egg, {
alpha: 0
}, {
duration: 500
});
// Removed tween on eggText (no eggText exists)
LK.setTimeout(function () {
if (easterEggContainer.parent) {
self.removeChild(easterEggContainer);
}
easterEggContainer = null;
easterEggActive = false;
}, 600);
} else {
easterEggActive = false;
easterEggContainer = null;
}
}, 5000);
}
}
// Remove the meme particle
if (particle.parent) {
particle.parent.removeChild(particle);
}
if (typeof particle.destroy === "function") {
particle.destroy();
}
return; // Only destroy one per frame
}
}
particle.update();
}
});
};
self.destroy = function () {
LK.clearInterval(self.particleTimer);
self.particleTimer = null;
self.particleContainer.destroy({
children: true
});
self.particleContainer = null;
Container.prototype.destroy.call(self);
};
return self;
});
var PauseButton = Container.expand(function () {
var self = Container.call(this);
var pauseIcon = self.attachAsset('Pause', {
anchorX: 0.5,
anchorY: 0.5,
scaleX: 1.2,
// 0.8 * 1.5 = 1.2
scaleY: 1.2
});
var background = LK.getAsset('button', {
anchorX: 0.5,
anchorY: 0.5,
scaleX: 1.05,
// 0.7 * 1.5 = 1.05
scaleY: 1.05
});
background.tint = 0x444444;
background.alpha = 0.7;
self.addChildAt(background, 0);
self.down = function (x, y, obj) {
LK.effects.flashObject(self, 0xFFFFFF, 200);
LK.getSound('ButtonSound').play();
showPausePopup();
};
return self;
});
var PausePopup = Container.expand(function () {
var self = Container.call(this);
var popupBg = self.attachAsset('button', {
anchorX: 0.5,
anchorY: 0.5,
scaleX: 3.5,
scaleY: 4.5
});
popupBg.tint = 0x222222;
popupBg.alpha = 0.9;
var popupTitle = new Text2("PAUSED", {
size: 100,
fill: 0xFFFFFF
});
popupTitle.anchor.set(0.5, 0);
popupTitle.y = -250;
self.addChild(popupTitle);
var continueButton = createButton("CONTINUE", 0x00AA00, 2.5, 1.2, function () {
game.removeChild(self);
}, 0, -20);
self.addChild(continueButton);
var surrenderButton = createButton("SURRENDER", 0xFF0000, 2.5, 1.2, function () {
game.removeChild(self);
game.onGameOver();
}, 0, 200);
self.addChild(surrenderButton);
return self;
});
var RecordsScreen = Container.expand(function () {
var self = Container.call(this);
// Create title
var title = new Text2("High Scores", {
size: 150,
fill: 0x000000
});
title.anchor.set(0.5, 0);
title.x = 2048 / 2;
title.y = 300;
self.addChild(title);
// Refresh high scores when shown
self.refreshHighScores = function () {
// Clear existing score texts if any
if (self.classicScoreText) {
self.removeChild(self.classicScoreText);
self.classicScoreText = null;
}
if (self.fastScoreText) {
self.removeChild(self.fastScoreText);
self.fastScoreText = null;
}
if (self.seekScoreText) {
self.removeChild(self.seekScoreText);
self.seekScoreText = null;
}
// Create mode buttons with high scores
function createModeButton(modeName, score, color, posY) {
var button = new Container();
var buttonBg = LK.getAsset('button', {
anchorX: 0.5,
anchorY: 0.5,
scaleX: 4,
scaleY: 1.5
});
buttonBg.tint = color;
var modeText = new Text2(modeName, {
size: 90,
fill: 0xFFFFFF
});
modeText.anchor.set(0.5, 0);
modeText.y = -100;
var scoreText = new Text2(score.toString(), {
size: 70,
fill: 0xFFFFFF
});
scoreText.anchor.set(0.5, 0);
scoreText.y = 10;
button.addChild(buttonBg);
button.addChild(modeText);
button.addChild(scoreText);
button.x = 2048 / 2;
button.y = posY;
// --- Easter Egg 3 logic ---
if (typeof window.easterEgg3Counters === "undefined") {
window.easterEgg3Counters = {
zen: 0,
fast: 0,
seek: 0
};
}
if (typeof window.easterEgg3Active === "undefined") {
window.easterEgg3Active = false;
}
if (typeof window.easterEgg3Container === "undefined") {
window.easterEgg3Container = null;
}
button.interactive = true;
button.down = function (x, y, obj) {
// Identify which button was pressed by modeName
if (modeName === "Zen Mode") {
window.easterEgg3Counters.zen++;
if (window.easterEgg3Counters.zen > 2) window.easterEgg3Counters.zen = 2;
} else if (modeName === "Fast Mode") {
window.easterEgg3Counters.fast++;
if (window.easterEgg3Counters.fast > 3) window.easterEgg3Counters.fast = 3;
} else if (modeName === "Seek Mode") {
window.easterEgg3Counters.seek++;
if (window.easterEgg3Counters.seek > 1) window.easterEgg3Counters.seek = 1;
}
// Check if all conditions are met
if (window.easterEgg3Counters.zen === 2 && window.easterEgg3Counters.fast === 3 && window.easterEgg3Counters.seek === 1 && !window.easterEgg3Active) {
window.easterEgg3Active = true;
// Show easterEgg3 asset centered and above all
if (window.easterEgg3Container && window.easterEgg3Container.parent) {
window.easterEgg3Container.parent.removeChild(window.easterEgg3Container);
}
window.easterEgg3Container = new Container();
var egg3 = LK.getAsset('easterEgg3', {
anchorX: 0.5,
anchorY: 0.5,
x: 2048 / 2,
y: 2732 / 2,
scaleX: 1,
scaleY: 1,
alpha: 0
});
window.easterEgg3Container.addChild(egg3);
// Fade in
tween(egg3, {
alpha: 1
}, {
duration: 600
});
// Add to records screen
if (typeof game !== "undefined" && game.children && game.children.indexOf(self) !== -1) {
self.addChild(window.easterEgg3Container);
} else if (typeof game !== "undefined") {
game.addChild(window.easterEgg3Container);
}
// Fade out and remove after 5 seconds
LK.setTimeout(function () {
tween(egg3, {
alpha: 0
}, {
duration: 500
});
LK.setTimeout(function () {
if (window.easterEgg3Container && window.easterEgg3Container.parent) {
window.easterEgg3Container.parent.removeChild(window.easterEgg3Container);
}
window.easterEgg3Container = null;
window.easterEgg3Active = false;
// Reset counters so it can be triggered again
window.easterEgg3Counters.zen = 0;
window.easterEgg3Counters.fast = 0;
window.easterEgg3Counters.seek = 0;
}, 600);
}, 5000);
}
};
return button;
}
self.addChild(createModeButton("Zen Mode", highScoreClassic, 0x00AA00, 800));
self.addChild(createModeButton("Fast Mode", highScoreFast, 0x0088FF, 1100));
self.addChild(createModeButton("Seek Mode", highScoreSeek, 0xDD5500, 1400));
};
// Refresh scores when created
self.refreshHighScores();
// Back button
var backButton = createButton("BACK TO MENU", 0xFF5500, 3, 1.5, function () {
game.removeChild(self);
initializeMenu();
}, 2048 / 2, 2732 - 200);
self.addChild(backButton);
return self;
});
var SeekMode = Container.expand(function () {
var self = Container.call(this);
// Similar to classic mode logic
var gridContainer = new Container();
self.addChild(gridContainer);
return self;
});
var SettingsScreen = Container.expand(function () {
var self = Container.call(this);
var title = new Text2("Settings", {
size: 150,
fill: 0x000000
});
title.anchor.set(0.5, 0);
title.x = 2048 / 2;
title.y = 300;
self.addChild(title);
// --- Improved vertical separation and position for all settings buttons ---
var settingsButtonSpacing = 320; // Increased spacing
var firstButtonY = 800; // Lowered starting Y
// RESET PROGRESS button (first, red, prominent)
var resetButton = createButton("RESET PROGRESS", 0xFF0000, 3.7, 1.5, function () {
// Show confirmation popup
var confirmPopup = new Container();
// Enlarged popup background
var popupBg = LK.getAsset('button', {
anchorX: 0.5,
anchorY: 0.5,
scaleX: 5.5,
scaleY: 5.7
});
popupBg.tint = 0x222222;
popupBg.alpha = 0.9;
var popupTitle = new Text2("Reset all progress?", {
size: 80,
fill: 0xFFFFFF
});
popupTitle.anchor.set(0.5, 0);
popupTitle.y = -440;
var popupText = new Text2("This will reset all high scores\nThis cannot be undone.", {
size: 60,
fill: 0xFFFFFF
});
popupText.anchor.set(0.5, 0);
popupText.y = -300;
// Confirm and Cancel buttons, separated vertically
var confirmButton = createButton("CONFIRM", 0xFF0000, 2.5, 1.2, function () {
// Reset high scores
highScoreClassic = 0;
highScoreFast = 0;
highScoreSeek = 0;
storage.highScoreClassic = 0;
storage.highScoreFast = 0;
storage.highScoreSeek = 0;
// Show confirmation message
var messagePopup = new Container();
var messageBg = LK.getAsset('button', {
anchorX: 0.5,
anchorY: 0.5,
scaleX: 5.5,
scaleY: 1.5
});
messageBg.tint = 0x00AA00;
var messageText = new Text2("Progress reset successfully", {
size: 80,
fill: 0xFFFFFF
});
messageText.anchor.set(0.5, 0.5);
messagePopup.addChild(messageBg);
messagePopup.addChild(messageText);
messagePopup.x = 2048 / 2;
messagePopup.y = 2732 / 2;
game.addChild(messagePopup);
// Remove message after 2 seconds
LK.setTimeout(function () {
game.removeChild(messagePopup);
}, 2000);
// Remove confirmation popup
game.removeChild(confirmPopup);
}, 0, 60);
var cancelButton = createButton("CANCEL", 0x00AA00, 2.5, 1.2, function () {
game.removeChild(confirmPopup);
}, 0, 280); // Increased vertical separation
confirmPopup.addChild(popupBg);
confirmPopup.addChild(popupTitle);
confirmPopup.addChild(popupText);
confirmPopup.addChild(confirmButton);
confirmPopup.addChild(cancelButton);
confirmPopup.x = 2048 / 2;
confirmPopup.y = 2732 / 2;
game.addChild(confirmPopup);
}, 2048 / 2, firstButtonY);
self.addChild(resetButton);
// DRAG MEME button
var dragButtonLabel = function dragButtonLabel() {
return dragMemeEnabled ? "DRAG MEME: ON" : "DRAG MEME: OFF";
};
var dragButton = createButton(dragButtonLabel(), 0x0088FF, 3.7, 1.5, function () {
dragMemeEnabled = !dragMemeEnabled;
storage.dragMemeEnabled = dragMemeEnabled;
dragButton.label.setText(dragButtonLabel());
}, 2048 / 2, firstButtonY + settingsButtonSpacing * 1);
self.addChild(dragButton);
// INTRO ENABLE/DISABLE button
var introButtonLabel = function introButtonLabel() {
return introEnabled ? "SHOW INTRO: ON" : "SHOW INTRO: OFF";
};
var introButton = createButton(introButtonLabel(), 0x222222, 3.7, 1.5, function () {
introEnabled = !introEnabled;
storage.introEnabled = introEnabled;
introButton.label.setText(introButtonLabel());
}, 2048 / 2, firstButtonY + settingsButtonSpacing * 2);
self.addChild(introButton);
// BACKGROUND COLOR ANIMATION button
var bgColorAnimButtonLabel = function bgColorAnimButtonLabel() {
return backgroundColorAnimEnabled ? "BG COLOR: ON" : "BG COLOR: OFF";
};
var bgColorAnimButton = createButton(bgColorAnimButtonLabel(), 0x7ec8e3, 3.7, 1.5, function () {
backgroundColorAnimEnabled = !backgroundColorAnimEnabled;
storage.backgroundColorAnimEnabled = backgroundColorAnimEnabled;
bgColorAnimButton.label.setText(bgColorAnimButtonLabel());
// If disabling, set background and UiBar to static color
if (!backgroundColorAnimEnabled) {
if (typeof backgroundAsset !== "undefined" && backgroundAsset) {
backgroundAsset.tint = colorTweenTargets[0];
}
if (game.uiBarBg) {
game.uiBarBg.tint = colorTweenTargets[0];
}
} else {
// If enabling, restart color tween
if (typeof tweenBackgroundToNextColor === "function") {
tweenBackgroundToNextColor();
}
if (typeof _tweenUiBarToNextColor === "function") {
_tweenUiBarToNextColor();
}
}
}, 2048 / 2, firstButtonY + settingsButtonSpacing * 3);
self.addChild(bgColorAnimButton);
// PARTICLES ENABLE/DISABLE button
var particlesEnabledLabel = function particlesEnabledLabel() {
return particlesEnabled ? "PARTICLES: ON" : "PARTICLES: OFF";
};
var particlesButton = createButton(particlesEnabledLabel(), 0x00bfff, 3.7, 1.5, function () {
particlesEnabled = !particlesEnabled;
storage.particlesEnabled = particlesEnabled;
particlesButton.label.setText(particlesEnabledLabel());
}, 2048 / 2, firstButtonY + settingsButtonSpacing * 4);
self.addChild(particlesButton);
// BACK TO MENU button (bottom, with extra margin)
var backButton = createButton("BACK TO MENU", 0xFF5500, 3, 1.5, function () {
game.removeChild(self);
initializeMenu();
}, 2048 / 2, 2732 - 200);
self.addChild(backButton);
return self;
});
/****
* Initialize Game
****/
var game = new LK.Game({
backgroundColor: 0x000000
});
/****
* Game Code
****/
// --- PARTICULAS AL COLISIONAR checkPointer CON UN MEME ---
game.update = function () {
// Solo si la grilla está inicializada y checkPointers existen
if (typeof gridCells !== "undefined" && Array.isArray(checkPointers) && checkPointers.length > 0) {
// Recorre solo la zona visible
for (var row = extraRows; row < gridSize + extraRows; row++) {
for (var col = 0; col < gridSize; col++) {
if (!gridCells[row]) {
continue;
}
var cell = gridCells[row][col];
if (cell && cell.sprite && !cell.beingDestroyed) {
// Chequea colisión simple (círculo) entre cada checkPointer y el centro de la celda
for (var i = 0; i < checkPointers.length; i++) {
var checkPointer = checkPointers[i];
if (!checkPointer.visible) {
continue;
}
var dx = checkPointer.x - cell.x;
var dy = checkPointer.y - cell.y;
var dist = Math.sqrt(dx * dx + dy * dy);
// Usa radio generoso (meme ~100, checkPointer ~20)
if (dist < 80) {
// Solo una vez por colisión: marca la celda como "siendo destruida por check"
if (!cell._checkCollisionActive) {
cell._checkCollisionActive = true;
// Efecto de partículas: 10-16 partículas
if (particlesEnabled) {
var numParticles = 10 + Math.floor(Math.random() * 7);
for (var p = 0; p < numParticles; p++) {
var part = LK.getAsset('particula', {
anchorX: 0.5,
anchorY: 0.5
});
// Color aleatorio
// Usa el color actual del fondo para las partículas
var bgColor = backgroundAsset.tint;
part.tint = bgColor;
part.x = cell.x;
part.y = cell.y;
// Aumenta el tamaño un 10%
part.scale.x = 1.7;
part.scale.y = 1.7;
// Velocidad y dirección aleatoria, pero nunca hacia arriba (vy >= 0), y velocidad reducida
var angle = Math.random() * Math.PI; // Solo de 0 a PI (derecha a izquierda, abajo)
var speed = 5.5 + Math.random() * 2.5; // Más lento que antes
var vx = Math.cos(angle) * speed;
var vy = Math.abs(Math.sin(angle) * speed); // Siempre hacia abajo o lateral
// Animación de partícula
(function (part, vx, vy) {
var lifetime = 180 + Math.random() * 120;
var startAlpha = 0.9 + Math.random() * 0.1;
part.alpha = startAlpha;
if (gridContainer && typeof gridContainer.addChild === "function") {
gridContainer.addChild(part);
} else {
game.addChild(part);
}
var elapsed = 0;
var updateFn = function updateFn() {
part.x += vx;
part.y += vy;
part.alpha -= 0.05 + Math.random() * 0.03;
part.scale.x *= 0.92;
part.scale.y *= 0.92;
elapsed += 16;
if (elapsed > lifetime || part.alpha <= 0.05) {
if (part.parent) {
part.parent.removeChild(part);
}
LK.clearInterval(intervalId);
}
};
var intervalId = LK.setInterval(updateFn, 16);
})(part, vx, vy);
}
}
// Efecto visual (sin sonido)
LK.effects.flashObject(cell, 0xFFFFFF, 200);
// (Eliminado sonido de explosión)
// Opcional: puedes marcar la celda para que no repita el efecto hasta que se mueva el checkPointer
// Elimina la marca después de un breve tiempo para permitir nuevas colisiones
LK.setTimeout(function () {
cell._checkCollisionActive = false;
}, 400);
}
}
}
}
}
}
}
};
// --- INTRO OPTION: persistently store intro enabled/disabled ---
// Load dragMemeEnabled from storage if available, otherwise default to true
var dragMemeEnabled = typeof storage.dragMemeEnabled === "boolean" ? storage.dragMemeEnabled : true;
storage.dragMemeEnabled = dragMemeEnabled;
// Load introEnabled from storage if available, otherwise default to true
var introEnabled = typeof storage.introEnabled === "boolean" ? storage.introEnabled : true;
storage.introEnabled = introEnabled;
// Load backgroundColorAnimEnabled from storage if available, otherwise default to true
var backgroundColorAnimEnabled = typeof storage.backgroundColorAnimEnabled === "boolean" ? storage.backgroundColorAnimEnabled : true;
storage.backgroundColorAnimEnabled = backgroundColorAnimEnabled;
// Load particlesEnabled from storage if available, otherwise default to true
var particlesEnabled = typeof storage.particlesEnabled === "boolean" ? storage.particlesEnabled : true;
storage.particlesEnabled = particlesEnabled;
var backgroundAsset = LK.getAsset('background', {
anchorX: 0.5,
anchorY: 0.5,
x: 2048 / 2,
y: 2732 / 2
});
game.addChildAt(backgroundAsset, 0);
// --- Easter Egg: contador de partículas meme destruidas en menú ---
var memeParticlesDestroyedInMenu = 0;
var easterEggActive = false;
var easterEggTimeout = null;
var easterEggContainer = null;
// --- Smoothly tween background color forever ---
var colorTweenTargets = [0xffb347, 0x7ec8e3, 0x8aff80, 0xff80c0, 0xf9ff80, 0x80ffd9, 0xd1b3ff, 0xffffff, 0xffe066, 0x6ec6ff, 0xff6ec7, 0x6effb3, 0xff6666, 0x66ffea, 0x9d66ff, 0x66ff66, 0xffe6b3, 0xb3e6ff, 0xe6b3ff, 0xb3ffb3];
var currentColorIndex = 0;
function tweenBackgroundToNextColor() {
var nextIndex = (currentColorIndex + 1) % colorTweenTargets.length;
var nextColor = colorTweenTargets[nextIndex];
if (!backgroundColorAnimEnabled) {
// If disabled, set to static color and do not continue tweening
backgroundAsset.tint = colorTweenTargets[0];
return;
}
tween(backgroundAsset, {
tint: nextColor
}, {
duration: 14000,
// much slower and smoother (was 7000)
easing: tween.easeInOutQuad,
onFinish: function onFinish() {
currentColorIndex = nextIndex;
tweenBackgroundToNextColor();
}
});
}
// Start the color tween loop
backgroundAsset.tint = colorTweenTargets[0];
if (backgroundColorAnimEnabled) {
tweenBackgroundToNextColor();
}
// Game state and initialization
var menuScreen;
var cosmeticsScreen;
var recordsScreen;
var settingsScreen;
var pausePopup;
var gameInitialized = false;
var score = 0;
var scoreText;
var gridContainer;
var gameMode = 'classic'; // Track current game mode
var timerText;
var timerSeconds = 10; // 10 seconds timer for Fast Mode
var timerInterval;
var saveScoreInterval; // Interval for saving classic mode high score
var seekMode; // Reference to seek mode instance
// Game tracks scores in local variables, no global persistence
var highScoreClassic = typeof storage.highScoreClassic === "number" ? storage.highScoreClassic : 0; // Zen Mode high score
var highScoreFast = typeof storage.highScoreFast === "number" ? storage.highScoreFast : 0; // Fast Mode high score
var highScoreSeek = typeof storage.highScoreSeek === "number" ? storage.highScoreSeek : 0; // Seek Mode high score
// --- SEEK MODE: Block meme movement for 5 seconds and show countdown ---
var seekModeBlockActive = false;
var seekModeBlockTimer = null;
var seekModeBlockSeconds = 5;
var seekModeBlockText = null;
// --- SEEK MODE: Combo tracking and visualization ---
var seekModeComboCount = 0;
var seekModeComboText = null;
var seekModeShowAllTimer = null;
// Function to show settings screen
function showSettingsScreen() {
if (!settingsScreen) {
settingsScreen = new SettingsScreen();
}
game.addChild(settingsScreen);
}
// Create a reusable button function
function createButton(text, bgColor, width, height, callback, buttonX, buttonY) {
var button = new Container();
var buttonBg = LK.getAsset('button', {
anchorX: 0.5,
anchorY: 0.5,
scaleX: width || 3,
scaleY: height || 1.5
});
buttonBg.tint = bgColor || 0x00AA00;
var buttonText = new Text2(text, {
size: 70,
fill: 0xFFFFFF
});
buttonText.anchor.set(0.5, 0.5);
button.addChild(buttonBg);
button.addChild(buttonText);
// Add button interaction
button.interactive = true;
button.down = function (x, y, obj) {
LK.effects.flashObject(buttonBg, 0xFFFFFF, 200);
LK.getSound('ButtonSound').play();
if (callback) {
LK.setTimeout(function () {
callback();
}, 300);
}
};
// Store references for later access
button.background = buttonBg;
button.label = buttonText;
// Set position if provided
if (buttonX !== undefined) {
button.x = buttonX;
}
if (buttonY !== undefined) {
button.y = buttonY;
}
return button;
}
// --- UiBar initialization: always present, not just in game modes ---
if (!game.uiBarBg) {
var _tweenUiBarToNextColor = function tweenUiBarToNextColor() {
var nextIndex = (currentColorIndex + 1) % colorTweenTargets.length;
var nextColor = colorTweenTargets[nextIndex];
if (!backgroundColorAnimEnabled) {
// If disabled, set to static color and do not continue tweening
uiBar.tint = colorTweenTargets[0];
return;
}
tween(uiBar, {
tint: nextColor
}, {
duration: 14000,
easing: tween.easeInOutQuad,
onFinish: function onFinish() {
// No need to update currentColorIndex here, backgroundAsset already does it
_tweenUiBarToNextColor();
}
});
};
// Calculate bar height as 1/6 of screen height
var barHeight = Math.floor(2732 / 6);
var barWidth = 2400;
// Get UiBar asset and scale to fit width and height
var uiBar = LK.getAsset('UiBar', {
anchorX: 0,
anchorY: 0,
x: -30,
y: -30,
scaleX: barWidth / 100,
scaleY: barHeight / 100,
alpha: 1
});
// Place at top of screen, behind score text
game.uiBarBg = uiBar;
// Insert at zIndex 1 (above background, below score text)
game.addChildAt(uiBar, 1);
// --- Smoothly tween UiBar color forever, synchronized with backgroundAsset ---
uiBar.tint = colorTweenTargets[0];
if (backgroundColorAnimEnabled) {
_tweenUiBarToNextColor();
}
}
// Centralized initialization function for adding elements to the game
function initializeGameElements() {
// Create and add grid container if it doesn't exist
if (!gridContainer) {
gridContainer = new Container();
game.addChild(gridContainer);
}
// --- Move UiBar and UI texts above memes ---
// Remove and re-add UiBar to ensure it's above memes
if (game.uiBarBg && game.uiBarBg.parent) {
game.uiBarBg.parent.removeChild(game.uiBarBg);
}
if (game.uiBarBg) {
game.addChild(game.uiBarBg);
}
// Create score text for all modes
if (!scoreText) {
scoreText = new Text2("Score: 0", {
size: 120,
fill: 0x222222
});
scoreText.anchor.set(0.5, 0);
scoreText.x = 2048 / 2;
scoreText.y = 80;
}
game.addChild(scoreText);
// Create timer text for fast mode if needed
if (game.gameMode === 'fast' && !timerText) {
timerText = new Text2("Time: " + timerSeconds.toFixed(1), {
size: 140,
fill: 0xFF0000
});
timerText.anchor.set(0.5, 1);
timerText.x = 2048 / 2;
timerText.y = 2732 - 100;
}
if (timerText) {
game.addChild(timerText);
}
// Add mode indicator text
var modeTextContent = "Zen Mode";
var modeTextColor = 0x00AA00;
if (game.gameMode === 'fast') {
modeTextContent = "Fast Mode";
modeTextColor = 0x0088FF;
} else if (game.gameMode === 'seekmode') {
modeTextContent = "Seek Mode";
modeTextColor = 0xDD5500;
}
if (game.modeText && game.modeText.parent) {
game.modeText.parent.removeChild(game.modeText);
}
game.modeText = new Text2(modeTextContent, {
size: 80,
fill: modeTextColor
});
game.modeText.anchor.set(0.5, 0);
game.modeText.x = 2048 / 2;
game.modeText.y = 180;
game.addChild(game.modeText);
// Add pause button to the top right corner in zen mode and seek mode
if (game.gameMode === 'classic' || game.gameMode === 'seekmode') {
if (game.pauseButton && game.pauseButton.parent) {
game.pauseButton.parent.removeChild(game.pauseButton);
}
game.pauseButton = new PauseButton();
// Add a 20px margin from the top and right edges
game.pauseButton.x = 2048 - 100 - 45;
game.pauseButton.y = 100 + 45;
game.pauseButton.interactive = true;
game.addChild(game.pauseButton);
}
}
// Function to show pause popup
function showPausePopup() {
if (!pausePopup) {
pausePopup = new PausePopup();
pausePopup.x = 2048 / 2;
pausePopup.y = 2732 / 2;
}
game.addChild(pausePopup);
// Fast Mode doesn't have pause functionality, so no need to pause the timer
}
// Show records screen
function showRecordsScreen() {
if (!recordsScreen) {
recordsScreen = new RecordsScreen();
}
// Make sure to refresh high scores every time the screen is shown
if (recordsScreen.refreshHighScores) {
recordsScreen.refreshHighScores();
}
game.addChild(recordsScreen);
}
// --- COSMETICS: Track selected cosmetic set globally and persistently ---
// Load selectedSet from storage if available, otherwise default to 1
var selectedSet = typeof storage.selectedSet === "number" ? storage.selectedSet : 1;
storage.selectedSet = selectedSet; // Ensure it's always persisted on load
// Show cosmetics screen
function showCosmeticsScreen() {
if (!cosmeticsScreen) {
cosmeticsScreen = new CosmeticsScreen();
}
game.addChild(cosmeticsScreen);
}
// Initialize the menu
function initializeMenu() {
if (menuScreen) {
// Clean up meme particles and intervals to prevent duplicates
if (typeof menuScreen.destroy === "function") {
menuScreen.destroy();
}
menuScreen = null;
}
menuScreen = new MenuScreen();
game.addChild(menuScreen);
}
// Function to periodically save high score and manage music
function startPeriodicSave() {
// Clear any existing save interval
if (saveScoreInterval) {
LK.clearInterval(saveScoreInterval);
saveScoreInterval = null;
}
// Save high score every second if it's better
saveScoreInterval = LK.setInterval(function () {
if (game.gameMode === 'classic' && score > highScoreClassic) {
highScoreClassic = score;
storage.highScoreClassic = highScoreClassic;
} else if (game.gameMode === 'seekmode' && score > highScoreSeek) {
highScoreSeek = score;
storage.highScoreSeek = highScoreSeek;
}
}, 1000);
// Start background music
startBackgroundMusic();
}
// Function to manage background music
function startBackgroundMusic() {
// Clear existing music interval if it exists
if (game.musicInterval) {
LK.clearInterval(game.musicInterval);
game.musicInterval = null;
}
// Array of available music tracks
var musicTracks = ['Backgroundmusic', 'backgroundmusic2'];
// Track the last played track to avoid repeats
var lastTrackIndex = -1;
// Function to play the next track (not repeating the same one)
function playNextTrack() {
var nextIndex;
if (musicTracks.length === 1) {
nextIndex = 0;
} else {
// Pick a different track than the last one
do {
nextIndex = Math.floor(Math.random() * musicTracks.length);
} while (nextIndex === lastTrackIndex);
}
var selectedTrack = musicTracks[nextIndex];
lastTrackIndex = nextIndex;
// Play the selected track, and set up onFinish to play the next one
LK.playMusic(selectedTrack, {
loop: false,
onFinish: function onFinish() {
// When the song finishes, play the next one
playNextTrack();
}
});
console.log("Now playing: " + selectedTrack);
}
// Play the first track
playNextTrack();
// Remove the old interval-based music change (not needed anymore)
}
// Initialize the game
game.initializeGame = function () {
// Initialize score system
score = 0;
// Clear existing grid container if it exists
if (gridContainer) {
while (gridContainer.children.length > 0) {
var child = gridContainer.children[0];
gridContainer.removeChild(child);
child.destroy();
}
}
// Initialize timer for Fast Mode
if (game.gameMode === 'fast') {
// Clear any existing timer
if (timerInterval) {
LK.clearInterval(timerInterval);
timerInterval = null;
}
// Calculate initial max timer value based on score
var maxTimer = 10;
// Use exponential thresholds for slower decrease
if (score >= 100) {
maxTimer = 9;
}
if (score >= 500) {
maxTimer = 8;
}
if (score >= 1000) {
maxTimer = 7;
}
if (score >= 3500) {
maxTimer = 6;
}
if (score >= 10000) {
maxTimer = 5;
}
if (score >= 25000) {
maxTimer = 4;
}
if (score >= 50000) {
maxTimer = 3;
}
// Reset timer value
timerSeconds = maxTimer;
if (timerText) {
timerText.setText("Time: " + maxTimer.toFixed(1));
}
// Start timer countdown
startTimer();
}
// Centralize initialization of all game elements
initializeGameElements();
// Initialize score
initializeScore();
// Initialize the game grid
initializeGrid();
ensureNoInitialMatches();
gameInitialized = true;
// Start periodic save of high score for classic mode
startPeriodicSave();
// --- SEEK MODE: Block meme movement for 5 seconds and show countdown ---
if (game.gameMode === 'seekmode') {
// Block meme movement
seekModeBlockActive = true;
seekModeBlockSeconds = 5;
// Reset combo counter
seekModeComboCount = 0;
// Remove previous combo text if any
if (seekModeComboText) {
game.removeChild(seekModeComboText);
seekModeComboText.destroy();
seekModeComboText = null;
}
// Remove previous block text if any
if (seekModeBlockText) {
game.removeChild(seekModeBlockText);
seekModeBlockText.destroy();
seekModeBlockText = null;
}
// Create and show countdown text at bottom center, but a bit higher to leave space for combo text below
seekModeBlockText = new Text2("Wait: " + seekModeBlockSeconds, {
size: 120,
fill: 0xDD5500,
font: "'GillSans-Bold',Impact,'Arial Black',Tahoma"
});
seekModeBlockText.anchor.set(0.5, 1);
seekModeBlockText.x = 2048 / 2;
seekModeBlockText.y = 2732 - 220; // Move up to leave space for combo text below
game.addChild(seekModeBlockText);
// Start countdown timer
if (seekModeBlockTimer) {
LK.clearInterval(seekModeBlockTimer);
seekModeBlockTimer = null;
}
seekModeBlockTimer = LK.setInterval(function () {
seekModeBlockSeconds--;
if (seekModeBlockText) {
seekModeBlockText.setText("Wait: " + seekModeBlockSeconds);
}
if (seekModeBlockSeconds <= 0) {
seekModeBlockActive = false;
if (seekModeBlockTimer) {
LK.clearInterval(seekModeBlockTimer);
seekModeBlockTimer = null;
}
if (seekModeBlockText) {
game.removeChild(seekModeBlockText);
seekModeBlockText.destroy();
seekModeBlockText = null;
}
// --- Set all current memes to use the 'seek' sprite ---
for (var row = 0; row < gridSize + extraRows; row++) {
for (var col = 0; col < gridSize; col++) {
var cell = gridCells[row][col];
if (cell && cell.sprite) {
// Remove old sprite
cell.removeChild(cell.sprite);
// Attach new 'seek' sprite
cell.sprite = LK.getAsset('seek', {
anchorX: 0.5,
anchorY: 0.5
});
// Scale to fit cell
var padding = 20;
var maxWidth = cellSize - padding * 2;
var maxHeight = cellSize - padding * 2;
var scaleX = maxWidth / cell.sprite.width;
var scaleY = maxHeight / cell.sprite.height;
var scale = Math.min(scaleX, scaleY);
cell.sprite.scale.set(scale, scale);
cell.addChild(cell.sprite);
}
}
}
// --- Mark that new memes should use 'seek' sprite ---
game.seekModeForceSeekSprite = true;
// Create combo counter text
seekModeComboCount = 0;
if (seekModeComboText) {
game.removeChild(seekModeComboText);
seekModeComboText.destroy();
}
seekModeComboText = new Text2("Combos: 0/3", {
size: 120,
fill: 0xDD5500,
font: "'GillSans-Bold',Impact,'Arial Black',Tahoma"
});
seekModeComboText.anchor.set(0.5, 0);
seekModeComboText.x = 2048 / 2;
seekModeComboText.y = 2732 - 120; // Place just below the wait text
game.addChild(seekModeComboText);
}
}, 1000);
} else {
// Clean up if not in seek mode
seekModeBlockActive = false;
if (seekModeBlockTimer) {
LK.clearInterval(seekModeBlockTimer);
seekModeBlockTimer = null;
}
if (seekModeBlockText) {
game.removeChild(seekModeBlockText);
seekModeBlockText.destroy();
seekModeBlockText = null;
}
// --- FIX: Reset seekModeForceSeekSprite so memes use correct sprite on re-enter ---
game.seekModeForceSeekSprite = false;
}
};
// Create and position score text
function initializeScore() {
score = 0;
if (scoreText) {
scoreText.setText("Score: 0");
}
}
// Update score and score text
function updateScore(points) {
if (typeof points === "number" && points > 0) {
score += points;
if (scoreText) {
scoreText.setText("Score: " + score);
}
}
}
var cellPool = [];
function getGridCell() {
if (cellPool.length > 0) {
return cellPool.pop().init();
}
return new GridCell();
}
function recycleGridCell(cell) {
if (cell) {
cellPool.push(cell);
}
}
var selectedCell = null;
var isAnimating = false;
window.gravityInProgress = false;
window.fillInProgress = false;
// Track combo counts for sound effects
var comboCounter = 0;
var comboInProgress = false;
function handleCellTap(tappedCell) {
// Bloquea romper y mover memes durante el periodo visible en seekmode
if (isAnimating || window.gravityInProgress || window.fillInProgress || pausePopup && game.children.includes(pausePopup) || game.gameMode === 'seekmode' && (seekModeBlockActive || game.seekModeForceSeekSprite && seekModeComboText && seekModeComboText.text && seekModeComboText.text.indexOf('MEMES VISIBLE') === 0)) {
return;
}
if (!tappedCell || !gridCells[tappedCell.row] || gridCells[tappedCell.row][tappedCell.col] !== tappedCell || tappedCell.beingDestroyed) {
return;
}
if (selectedCell !== null) {
// If it's valid
if (selectedCell && gridCells[selectedCell.row] && gridCells[selectedCell.row][selectedCell.col] === selectedCell) {
// If we tap the same cell, deselect it
if (selectedCell === tappedCell) {
selectedCell.hideSelection();
selectedCell = null;
return;
}
// Check if they're adjacent
var isAdjacent = Math.abs(selectedCell.row - tappedCell.row) === 1 && selectedCell.col === tappedCell.col || Math.abs(selectedCell.col - tappedCell.col) === 1 && selectedCell.row === tappedCell.row;
if (!isAdjacent) {
// Not adjacent, switch selection
selectedCell.hideSelection();
selectedCell = tappedCell;
selectedCell.showSelection();
return;
}
// They are adjacent, continue with swap
var cell1 = selectedCell;
var cell2 = tappedCell;
// Hide selection before swap
cell1.hideSelection();
selectedCell = null;
var isAdjacent = Math.abs(cell1.row - cell2.row) === 1 && cell1.col === cell2.col || Math.abs(cell1.col - cell2.col) === 1 && cell1.row === cell2.row;
if (!isAdjacent) {
return;
}
} else {
// Invalid selected cell, select the new one
if (selectedCell) {
selectedCell.hideSelection();
}
selectedCell = tappedCell;
selectedCell.showSelection();
return;
}
} else {
// No selection yet, select this cell
selectedCell = tappedCell;
selectedCell.showSelection();
return;
}
isAnimating = true;
var pos1_x = cell1.x;
var pos1_y = cell1.y;
var pos2_x = cell2.x;
var pos2_y = cell2.y;
var row1 = cell1.row;
var col1 = cell1.col;
var row2 = cell2.row;
var col2 = cell2.col;
// Check if cells are special memes
var greenSpecialCell = null;
var regularCell = null;
var lineSpecialCells = [];
var twoGreenSpecials = false;
// Check for two green special memes
if (cell1.isSpecial && cell1.specialType === 'green' && cell2.isSpecial && cell2.specialType === 'green') {
twoGreenSpecials = true;
}
// Check for green special meme
else if (cell1.isSpecial && cell1.specialType === 'green') {
greenSpecialCell = cell1;
regularCell = cell2;
} else if (cell2.isSpecial && cell2.specialType === 'green') {
greenSpecialCell = cell2;
regularCell = cell1;
}
// Assign a unique value to green special so it doesn't break when combined
if (greenSpecialCell) {
greenSpecialCell.value = 99; // Use a value outside the normal meme range (1-5)
}
if (twoGreenSpecials) {
cell1.value = 99;
cell2.value = 99;
}
// Check for line-clearing special memes (horizontal/vertical)
if (cell1.isSpecial && (cell1.specialType === 'horizontal' || cell1.specialType === 'vertical')) {
lineSpecialCells.push(cell1);
}
if (cell2.isSpecial && (cell2.specialType === 'horizontal' || cell2.specialType === 'vertical')) {
lineSpecialCells.push(cell2);
}
gridCells[row1][col1] = cell2;
gridCells[row2][col2] = cell1;
cell1.row = row2;
cell1.col = col2;
cell2.row = row1;
cell2.col = col1;
// Make sure any selection highlights are removed
if (cell1.selectionHighlight) {
cell1.hideSelection();
}
if (cell2.selectionHighlight) {
cell2.hideSelection();
}
// Check for special combinations: two green special memes, two bombs, line-clearing + bomb, or two line special memes
if (twoGreenSpecials) {
// Two green special memes combination - destroys all visible memes
var cellsToDestroy = [];
// Collect all visible cells on the board
for (var row = extraRows; row < gridSize + extraRows; row++) {
for (var col = 0; col < gridSize; col++) {
if (gridCells[row][col] && gridCells[row][col] !== cell1 && gridCells[row][col] !== cell2) {
cellsToDestroy.push(gridCells[row][col]);
}
}
}
// Award massive bonus for two green special meme combination
updateScore(1000);
// Show mega score popup
var megaScorePopup = new Text2("+1000", {
size: 100,
fill: 0x00FF00
});
megaScorePopup.anchor.set(0.5, 0.5);
megaScorePopup.x = 2048 / 2;
megaScorePopup.y = 2732 / 2;
game.addChild(megaScorePopup);
// Animate mega score popup
tween(megaScorePopup, {
scaleX: 1.5,
scaleY: 1.5,
alpha: 0
}, {
duration: 1000,
onComplete: function onComplete() {
game.removeChild(megaScorePopup);
megaScorePopup.destroy();
}
});
// Mark special memes for destruction
cell1.beingDestroyed = true;
cell2.beingDestroyed = true;
// Schedule destruction after the swap animation completes
LK.setTimeout(function () {
LK.getSound('Explosion').play();
// Flash screen effect for this powerful combination
LK.effects.flashScreen(0x00FF00, 500);
// Destroy the collected cells
if (cellsToDestroy.length > 0) {
destroyCells(cellsToDestroy);
}
// Destroy the special memes
LK.effects.flashObject(cell1, 0xFFFFFF, 200);
LK.effects.flashObject(cell2, 0xFFFFFF, 200);
gridContainer.removeChild(cell1);
gridContainer.removeChild(cell2);
cell1.destroy();
cell2.destroy();
gridCells[cell1.row][cell1.col] = null;
gridCells[cell2.row][cell2.col] = null;
}, 250);
} else if (cell1.isSpecial && cell1.specialType === 'bomb' && cell2.isSpecial && cell2.specialType === 'bomb') {
// Two bomb special memes combination - creates a 5x5 explosion
var cellsToDestroy = [];
// Determine which cell was moved by the player
var activatedCell = cell1;
// Create a 5x5 area effect centered on the first bomb
for (var r = Math.max(extraRows, cell1.row - 2); r <= Math.min(gridSize + extraRows - 1, cell1.row + 2); r++) {
for (var c = Math.max(0, cell1.col - 2); c <= Math.min(gridSize - 1, cell1.col + 2); c++) {
if (gridCells[r][c] && gridCells[r][c] !== cell1 && gridCells[r][c] !== cell2) {
cellsToDestroy.push(gridCells[r][c]);
}
}
}
// Mark special memes for destruction
cell1.beingDestroyed = true;
cell2.beingDestroyed = true;
// Schedule destruction after the swap animation completes
LK.setTimeout(function () {
LK.getSound('Explosion').play();
// Destroy the collected cells
if (cellsToDestroy.length > 0) {
destroyCells(cellsToDestroy);
}
// Destroy the special memes
LK.effects.flashObject(cell1, 0xFFFFFF, 200);
LK.effects.flashObject(cell2, 0xFFFFFF, 200);
gridContainer.removeChild(cell1);
gridContainer.removeChild(cell2);
cell1.destroy();
cell2.destroy();
gridCells[cell1.row][cell1.col] = null;
gridCells[cell2.row][cell2.col] = null;
}, 250);
} else if (cell1.isSpecial && cell1.specialType === 'bomb' && cell2.isSpecial && (cell2.specialType === 'horizontal' || cell2.specialType === 'vertical') || cell2.isSpecial && cell2.specialType === 'bomb' && cell1.isSpecial && (cell1.specialType === 'horizontal' || cell1.specialType === 'vertical')) {
// Line-clearing + bomb special combination
var bombCell = cell1.specialType === 'bomb' ? cell1 : cell2;
var lineCell = cell1.specialType === 'horizontal' || cell1.specialType === 'vertical' ? cell1 : cell2;
var cellsToDestroy = [];
var affectedRows = [];
// Determine which cell was moved by the player
var activatedCell = cell1;
// Enhanced effect: destroy 3 rows or columns based on the line special type
if (lineCell.specialType === 'horizontal') {
// Destroy 3 rows centered on the bomb's row
for (var r = Math.max(extraRows, bombCell.row - 1); r <= Math.min(gridSize + extraRows - 1, bombCell.row + 1); r++) {
affectedRows.push(r);
for (var c = 0; c < gridSize; c++) {
if (gridCells[r][c] && gridCells[r][c] !== bombCell && gridCells[r][c] !== lineCell) {
cellsToDestroy.push(gridCells[r][c]);
}
}
}
} else {
// vertical
// Destroy 3 columns centered on the bomb's column
for (var r = extraRows; r < gridSize + extraRows; r++) {
for (var c = Math.max(0, bombCell.col - 1); c <= Math.min(gridSize - 1, bombCell.col + 1); c++) {
if (gridCells[r][c] && gridCells[r][c] !== bombCell && gridCells[r][c] !== lineCell) {
cellsToDestroy.push(gridCells[r][c]);
}
}
}
}
// Mark special memes for destruction
bombCell.beingDestroyed = true;
lineCell.beingDestroyed = true;
// Schedule destruction after the swap animation completes
LK.setTimeout(function () {
LK.getSound('Explosion').play();
// Destroy the collected cells
if (cellsToDestroy.length > 0) {
destroyCells(cellsToDestroy);
}
// Destroy the special memes
LK.effects.flashObject(bombCell, 0xFFFFFF, 200);
LK.effects.flashObject(lineCell, 0xFFFFFF, 200);
gridContainer.removeChild(bombCell);
gridContainer.removeChild(lineCell);
bombCell.destroy();
lineCell.destroy();
gridCells[bombCell.row][bombCell.col] = null;
gridCells[lineCell.row][lineCell.col] = null;
}, 250);
}
// Check if two line special memes were swapped (horizontal and vertical)
else if (lineSpecialCells.length === 2) {
var cellsToDestroy = [];
// Collect cells in both row and column
var row1, col1, row2, col2;
var activatedSpecial;
// Determine which special meme was moved by the player (based on original positions)
if (lineSpecialCells[0] === cell1) {
activatedSpecial = lineSpecialCells[0];
row1 = lineSpecialCells[0].row;
col1 = lineSpecialCells[0].col;
} else {
activatedSpecial = lineSpecialCells[1];
row1 = lineSpecialCells[1].row;
col1 = lineSpecialCells[1].col;
}
// Add cells from the activated special's row or column
for (var row = extraRows; row < gridSize + extraRows; row++) {
// Add cells from column
if (gridCells[row][col1] && gridCells[row][col1] !== lineSpecialCells[0] && gridCells[row][col1] !== lineSpecialCells[1]) {
cellsToDestroy.push(gridCells[row][col1]);
}
}
// Add cells from the activated special's row
for (var col = 0; col < gridSize; col++) {
// Add cells from row
if (col !== col1 && gridCells[row1][col] && gridCells[row1][col] !== lineSpecialCells[0] && gridCells[row1][col] !== lineSpecialCells[1]) {
cellsToDestroy.push(gridCells[row1][col]);
}
}
// Mark special memes for destruction
lineSpecialCells.forEach(function (specialMeme) {
specialMeme.beingDestroyed = true;
});
// Schedule destruction after the swap animation completes
LK.setTimeout(function () {
LK.getSound('Explosion').play();
// Destroy the collected cells
if (cellsToDestroy.length > 0) {
destroyCells(cellsToDestroy);
}
// Destroy the special memes
lineSpecialCells.forEach(function (specialMeme) {
LK.effects.flashObject(specialMeme, 0xFFFFFF, 200);
gridContainer.removeChild(specialMeme);
specialMeme.destroy();
gridCells[specialMeme.row][specialMeme.col] = null;
});
}, 250);
}
// Check if greenSpecialCell was swapped with a line-clearing special meme or bomb
else if (greenSpecialCell && regularCell) {
// Check if regularCell is a line-clearing special meme
if (regularCell.isSpecial && (regularCell.specialType === 'horizontal' || regularCell.specialType === 'vertical')) {
var targetType = regularCell.value;
var cellsToTransform = [];
// Find all cells with the same type as the swapped line-clearing meme
for (var row = extraRows; row < gridSize + extraRows; row++) {
for (var col = 0; col < gridSize; col++) {
var cell = gridCells[row][col];
if (cell && cell.value === targetType && cell !== greenSpecialCell && cell !== regularCell && !cell.isSpecial) {
cellsToTransform.push(cell);
}
}
}
// Mark special memes for destruction
greenSpecialCell.beingDestroyed = true;
// Schedule transformation and activation after the swap animation completes
LK.setTimeout(function () {
LK.getSound('Explosion').play();
LK.effects.flashObject(greenSpecialCell, 0xFFFFFF, 200);
// Transform all cells of the same type into line-clearing memes
cellsToTransform.forEach(function (cell) {
cell.isSpecial = true;
// Randomly assign horizontal or vertical
cell.specialType = Math.random() < 0.5 ? 'horizontal' : 'vertical';
// Apply tint
cell.sprite.tint = 0xFF8800; // Orange tint for line special memes
LK.effects.flashObject(cell, 0xFFFFFF, 200);
// Activate each special meme with a slight delay
LK.setTimeout(function () {
cell.activateSpecialPower();
}, 100 + Math.random() * 300);
});
// Remove the green special meme
gridContainer.removeChild(greenSpecialCell);
greenSpecialCell.destroy();
gridCells[greenSpecialCell.row][greenSpecialCell.col] = null;
// Activate the original line-clearing meme last
LK.setTimeout(function () {
regularCell.activateSpecialPower();
}, 500);
}, 250);
} else if (regularCell.isSpecial && regularCell.specialType === 'bomb') {
// Green special + bomb special interaction
var targetType = regularCell.value;
var cellsToTransform = [];
// Find all cells with the same type as the bomb meme
for (var row = extraRows; row < gridSize + extraRows; row++) {
for (var col = 0; col < gridSize; col++) {
var cell = gridCells[row][col];
if (cell && cell.value === targetType && cell !== greenSpecialCell && cell !== regularCell && !cell.isSpecial) {
cellsToTransform.push(cell);
}
}
}
// Mark green special meme for destruction
greenSpecialCell.beingDestroyed = true;
// Schedule transformation and activation after swap animation
LK.setTimeout(function () {
LK.getSound('Explosion').play();
LK.effects.flashObject(greenSpecialCell, 0xFFFFFF, 200);
// Transform all cells of same type into bomb memes
cellsToTransform.forEach(function (cell) {
cell.isSpecial = true;
cell.specialType = 'bomb';
// Apply blue tint for bomb memes
cell.sprite.tint = 0x0088FF;
LK.effects.flashObject(cell, 0xFFFFFF, 200);
// Activate each bomb with slight delay
LK.setTimeout(function () {
cell.activateSpecialPower();
}, 100 + Math.random() * 300);
});
// Remove the green special meme
gridContainer.removeChild(greenSpecialCell);
greenSpecialCell.destroy();
gridCells[greenSpecialCell.row][greenSpecialCell.col] = null;
// Activate the original bomb last
LK.setTimeout(function () {
regularCell.activateSpecialPower();
}, 500);
}, 250);
} else {
var targetType = regularCell.value;
var cellsToDestroy = [];
// Find all cells with the same type as the swapped meme
for (var row = extraRows; row < gridSize + extraRows; row++) {
for (var col = 0; col < gridSize; col++) {
var cell = gridCells[row][col];
if (cell && cell.value === targetType && cell !== greenSpecialCell) {
cellsToDestroy.push(cell);
}
}
}
// Also destroy the green special meme itself
greenSpecialCell.beingDestroyed = true;
// Schedule destruction after the swap animation completes
LK.setTimeout(function () {
if (cellsToDestroy.length > 0) {
LK.getSound('Explosion').play();
LK.effects.flashObject(greenSpecialCell, 0xFFFFFF, 200);
destroyCells(cellsToDestroy);
gridContainer.removeChild(greenSpecialCell);
greenSpecialCell.destroy();
gridCells[greenSpecialCell.row][greenSpecialCell.col] = null;
}
}, 250);
}
}
tween(cell1, {
x: pos2_x,
y: pos2_y
}, {
duration: 200
});
tween(cell2, {
x: pos1_x,
y: pos1_y
}, {
duration: 200
});
selectedCell = null;
LK.setTimeout(function () {
checkForAndDestroyMatches(cell1, cell2);
if (!window.destructionInProgress && !window.gravityInProgress && !window.fillInProgress) {
isAnimating = false;
}
}, 250);
}
function getMatches() {
var matches = [];
function findDirectionalMatches(isHorizontal) {
var primary, secondary;
var primaryMax = isHorizontal ? gridSize + extraRows : gridSize;
var secondaryMax = isHorizontal ? gridSize : gridSize + extraRows;
for (primary = isHorizontal ? extraRows : 0; primary < primaryMax; primary++) {
if (!gridCells[primary]) {
continue;
}
for (secondary = 0; secondary < secondaryMax;) {
if (secondary > secondaryMax - 3) {
secondary++;
continue;
}
var cell1 = isHorizontal ? gridCells[primary] ? gridCells[primary][secondary] : null : gridCells[secondary] ? gridCells[secondary][primary] : null;
if (!cell1 || !cell1.value || cell1.value === 99) {
secondary++;
continue;
}
var currentMatchValue = cell1.value;
var currentMatchCells = [cell1];
for (var k = secondary + 1; k < secondaryMax; k++) {
var nextCell = isHorizontal ? gridCells[primary] ? gridCells[primary][k] : null : gridCells[k] ? gridCells[k][primary] : null;
if (nextCell && nextCell.value === currentMatchValue && nextCell.value !== 99) {
currentMatchCells.push(nextCell);
} else {
// If no new matches found, reset combo counter
LK.setTimeout(function () {
if (!window.gravityInProgress && !window.fillInProgress) {
comboInProgress = false;
comboCounter = 0;
}
}, 500);
break;
}
}
if (currentMatchCells.length >= 3) {
var validCells = currentMatchCells.filter(function (cell) {
return cell && gridCells[cell.row] && gridCells[cell.row][cell.col] === cell;
});
if (validCells.length >= 3) {
var visibleCells = validCells.filter(function (cell) {
return cell.row >= extraRows;
});
var invisibleCells = validCells.filter(function (cell) {
return cell.row < extraRows;
});
// Either all cells are visible, or all cells are invisible, or there are at least 3 visible cells
if (visibleCells.length === 0 || invisibleCells.length === 0 || visibleCells.length >= 3) {
// Add isHorizontal and matchType to the match data
validCells.isHorizontal = isHorizontal;
validCells.matchType = currentMatchValue;
matches.push(validCells);
}
}
}
secondary += currentMatchCells.length > 0 ? currentMatchCells.length : 1;
}
}
}
findDirectionalMatches(true);
findDirectionalMatches(false);
return matches;
}
function destroyCells(cellsToDestroy) {
isAnimating = true;
// Create a unique ID for this destruction process
var destructionId = Date.now() + Math.random();
// Check if match crosses visible/invisible boundary
var visibleCells = cellsToDestroy.filter(function (cell) {
return cell.row >= extraRows;
});
var invisibleCells = cellsToDestroy.filter(function (cell) {
return cell.row < extraRows;
});
// If mixed visibility and only one cell is visible, don't destroy any
if (visibleCells.length > 0 && invisibleCells.length > 0 && (visibleCells.length === 1 || invisibleCells.length === 1)) {
isAnimating = false;
return;
}
// Reset timer if we're in Fast Mode and destroying visible cells
if (game.gameMode === 'fast' && visibleCells.length > 0) {
resetTimer();
}
// Award points for visible matches
var pointsToAdd = 0;
var visibleCellsToDestroy = cellsToDestroy.filter(function (cell) {
return cell.row >= extraRows && cell && gridCells[cell.row] && gridCells[cell.row][cell.col] === cell;
});
if (visibleCellsToDestroy.length > 0) {
// 10 points per cell, bonus for combos
pointsToAdd = visibleCellsToDestroy.length * 10;
if (visibleCellsToDestroy.length >= 4) {
pointsToAdd += 10;
}
if (visibleCellsToDestroy.length >= 5) {
pointsToAdd += 20;
}
if (visibleCellsToDestroy.length >= 6) {
pointsToAdd += 30;
}
updateScore(pointsToAdd);
}
// Find the center cell (the one that triggered the match)
var centerCell = null;
// If we have the cells from a swap, use one of those as the center
if (arguments.length > 1 && arguments[1]) {
centerCell = arguments[1];
} else if (cellsToDestroy.length > 0) {
// Otherwise use the middle cell of the match
centerCell = cellsToDestroy[Math.floor(cellsToDestroy.length / 2)];
}
// Group cells by meme type
var cellsByType = {};
visibleCellsToDestroy.forEach(function (cell) {
if (!cellsByType[cell.value]) {
cellsByType[cell.value] = [];
}
cellsByType[cell.value].push(cell);
});
// Count unique groups for combo sound
var uniqueGroupCount = Object.keys(cellsByType).length;
if (uniqueGroupCount > 0) {
// Increment combo counter only if this is part of a continuous combo
if (!comboInProgress) {
comboCounter = uniqueGroupCount;
comboInProgress = true;
} else {
comboCounter += uniqueGroupCount;
}
// Update seek mode combo counter if we're in seek mode
if (game && game.gameMode === 'seekmode' && !seekModeBlockActive && game.seekModeForceSeekSprite) {
seekModeComboCount++;
// Create or update combo text
if (!seekModeComboText) {
seekModeComboText = new Text2("Combos: " + seekModeComboCount + "/3", {
size: 120,
fill: 0xDD5500,
font: "'GillSans-Bold',Impact,'Arial Black',Tahoma"
});
seekModeComboText.anchor.set(0.5, 0);
seekModeComboText.x = 2048 / 2;
seekModeComboText.y = 2732 - 120; // Place just below the wait text
game.addChild(seekModeComboText);
} else {
seekModeComboText.setText("Combos: " + seekModeComboCount + "/3");
}
// Check if we've reached 3 combos
if (seekModeComboCount >= 3) {
// Reset combo counter
seekModeComboCount = 0;
// Show all memes for 3 seconds
for (var row = 0; row < gridSize + extraRows; row++) {
var _loop = function _loop() {
cell = gridCells[row][col];
if (cell && cell.sprite) {
// Remove old seek sprite
cell.removeChild(cell.sprite);
// Attach original meme sprite based on value
// Use global selectedSet for cosmetics
if (typeof selectedSet !== "number") selectedSet = 1;
if (selectedSet === 1) {
spriteId = 'meme' + cell.value;
} else if (selectedSet === 2) {
spriteId = 'meme' + cell.value + '-2';
} else if (selectedSet === 3) {
spriteId = 'meme' + cell.value + '-3';
} else {
spriteId = 'meme' + cell.value;
}
cell.sprite = LK.getAsset(spriteId, {
anchorX: 0.5,
anchorY: 0.5
});
// Scale to fit cell
padding = 20;
maxWidth = cellSize - padding * 2;
maxHeight = cellSize - padding * 2;
scaleX = maxWidth / cell.sprite.width;
scaleY = maxHeight / cell.sprite.height;
scale = Math.min(scaleX, scaleY);
cell.sprite.scale.set(scale, scale);
cell.addChild(cell.sprite);
if (cell.isSpecial) {
// Remove any previous overlays
if (cell.specialOverlay && cell.children.indexOf(cell.specialOverlay) !== -1) {
cell.removeChild(cell.specialOverlay);
cell.specialOverlay = null;
}
if (cell.specialType === 'bomb') {
// Overlay habilidadBomba sprite
cell.specialOverlay = LK.getAsset('habilidadBomba', {
anchorX: 0.5,
anchorY: 0.5
});
padding = 20;
maxWidth = cellSize - padding * 2;
maxHeight = cellSize - padding * 2;
scaleX = maxWidth / cell.specialOverlay.width;
scaleY = maxHeight / cell.specialOverlay.height;
scale = Math.min(scaleX, scaleY);
cell.specialOverlay.scale.set(scale, scale);
cell.addChild(cell.specialOverlay);
// --- Color sync: animate overlay tint with background ---
if (typeof colorTweenTargets !== "undefined" && typeof currentColorIndex !== "undefined") {
var _tweenBombOverlayColor2 = function tweenBombOverlayColor() {
if (!cell.specialOverlay) {
return;
}
var nextIndex = (currentColorIndex + 1) % colorTweenTargets.length;
var nextColor = colorTweenTargets[nextIndex];
cell._specialOverlayTween = tween(cell.specialOverlay, {
tint: nextColor
}, {
duration: 14000,
easing: tween.easeInOutQuad,
onFinish: function onFinish() {
if (cell.specialOverlay) {
_tweenBombOverlayColor2();
}
}
});
};
if (cell._specialOverlayTween) {
cell._specialOverlayTween.stop && cell._specialOverlayTween.stop();
cell._specialOverlayTween = null;
}
cell.specialOverlay.tint = colorTweenTargets[currentColorIndex];
_tweenBombOverlayColor2();
}
} else if (cell.specialType === 'green') {
// Use 'habilidadVerde' asset for green special meme
if (cell.sprite) {
cell.removeChild(cell.sprite);
}
if (game.seekModeForceSeekSprite) {
// Si estamos en modo seek ocultando memes, no mostrar habilidad verde
cell.sprite = null;
} else {
cell.sprite = LK.getAsset('habilidadVerde', {
anchorX: 0.5,
anchorY: 0.5
});
padding = 20;
maxWidth = cellSize - padding * 2;
maxHeight = cellSize - padding * 2;
scaleX = maxWidth / cell.sprite.width;
scaleY = maxHeight / cell.sprite.height;
scale = Math.min(scaleX, scaleY);
cell.sprite.scale.set(scale, scale);
cell.addChild(cell.sprite);
}
} else if (cell.specialType === 'clear' || cell.specialType === 'vertical' || cell.specialType === 'horizontal') {
// Overlay habilidadClear sprite for clear/line specials
cell.specialOverlay = LK.getAsset('HabilidadClear', {
anchorX: 0.5,
anchorY: 0.5
});
// Rotate overlay to match direction
if (cell.specialType === 'horizontal') {
cell.specialOverlay.rotation = 0;
} else if (cell.specialType === 'vertical') {
cell.specialOverlay.rotation = Math.PI / 2;
} else {
cell.specialOverlay.rotation = 0;
}
padding = 20;
maxWidth = cellSize - padding * 2;
maxHeight = cellSize - padding * 2;
scaleX = maxWidth / cell.specialOverlay.width;
scaleY = maxHeight / cell.specialOverlay.height;
scale = Math.min(scaleX, scaleY);
cell.specialOverlay.scale.set(scale, scale);
cell.addChild(cell.specialOverlay);
// --- Color sync: animate overlay tint with background ---
if (typeof colorTweenTargets !== "undefined" && typeof currentColorIndex !== "undefined") {
var _tweenClearOverlayColor2 = function tweenClearOverlayColor() {
if (!cell.specialOverlay) {
return;
}
var nextIndex = (currentColorIndex + 1) % colorTweenTargets.length;
var nextColor = colorTweenTargets[nextIndex];
cell._specialOverlayTween = tween(cell.specialOverlay, {
tint: nextColor
}, {
duration: 14000,
easing: tween.easeInOutQuad,
onFinish: function onFinish() {
if (cell.specialOverlay) {
_tweenClearOverlayColor2();
}
}
});
};
if (cell._specialOverlayTween) {
cell._specialOverlayTween.stop && cell._specialOverlayTween.stop();
cell._specialOverlayTween = null;
}
cell.specialOverlay.tint = colorTweenTargets[currentColorIndex];
_tweenClearOverlayColor2();
}
} else {
cell.sprite.tint = 0xFF8800;
}
}
}
},
cell,
selectedSet,
spriteId,
padding,
maxWidth,
maxHeight,
scaleX,
scaleY,
scale,
padding,
maxWidth,
maxHeight,
scaleX,
scaleY,
scale,
padding,
maxWidth,
maxHeight,
scaleX,
scaleY,
scale,
padding,
maxWidth,
maxHeight,
scaleX,
scaleY,
scale;
for (var col = 0; col < gridSize; col++) {
_loop();
}
}
// Display countdown text
if (seekModeComboText) {
seekModeComboText.setText("MEMES VISIBLE: 3");
if (seekModeComboText.style) {
seekModeComboText.style.size = 120;
seekModeComboText.style.fill = 0xDD5500;
seekModeComboText.style.font = "'GillSans-Bold',Impact,'Arial Black',Tahoma";
}
seekModeComboText.y = 2732 - 120; // Ensure position is below wait text
}
// Start countdown
var showAllSeconds = 3;
var countdownInterval = LK.setInterval(function () {
showAllSeconds--;
if (seekModeComboText) {
seekModeComboText.setText("MEMES VISIBLE: " + showAllSeconds);
if (seekModeComboText.style) {
seekModeComboText.style.size = 120;
seekModeComboText.style.fill = 0xDD5500;
seekModeComboText.style.font = "'GillSans-Bold',Impact,'Arial Black',Tahoma";
}
seekModeComboText.y = 2732 - 120; // Ensure position is below wait text
}
if (showAllSeconds <= 0) {
// Clear interval
LK.clearInterval(countdownInterval);
// Set all memes back to seek sprite
for (var row = 0; row < gridSize + extraRows; row++) {
var _loop2 = function _loop2() {
cell = gridCells[row][col];
if (cell && cell.sprite) {
// Remove old sprite
cell.removeChild(cell.sprite);
// Attach new 'seek' sprite
cell.sprite = LK.getAsset('seek', {
anchorX: 0.5,
anchorY: 0.5
});
// Scale to fit cell
padding = 20;
maxWidth = cellSize - padding * 2;
maxHeight = cellSize - padding * 2;
scaleX = maxWidth / cell.sprite.width;
scaleY = maxHeight / cell.sprite.height;
scale = Math.min(scaleX, scaleY);
cell.sprite.scale.set(scale, scale);
cell.addChild(cell.sprite);
// Preserve special tints if needed
if (cell.isSpecial) {
// Remove any previous overlays
if (cell.specialOverlay && cell.children.indexOf(cell.specialOverlay) !== -1) {
cell.removeChild(cell.specialOverlay);
cell.specialOverlay = null;
}
if (cell.specialType === 'bomb') {
// Overlay habilidadBomba sprite
cell.specialOverlay = LK.getAsset('habilidadBomba', {
anchorX: 0.5,
anchorY: 0.5
});
padding = 20;
maxWidth = cellSize - padding * 2;
maxHeight = cellSize - padding * 2;
scaleX = maxWidth / cell.specialOverlay.width;
scaleY = maxHeight / cell.specialOverlay.height;
scale = Math.min(scaleX, scaleY);
cell.specialOverlay.scale.set(scale, scale);
cell.addChild(cell.specialOverlay);
// --- Color sync: animate overlay tint with background ---
if (typeof colorTweenTargets !== "undefined" && typeof currentColorIndex !== "undefined") {
var _tweenBombOverlayColor3 = function tweenBombOverlayColor() {
if (!cell.specialOverlay) {
return;
}
var nextIndex = (currentColorIndex + 1) % colorTweenTargets.length;
var nextColor = colorTweenTargets[nextIndex];
cell._specialOverlayTween = tween(cell.specialOverlay, {
tint: nextColor
}, {
duration: 14000,
easing: tween.easeInOutQuad,
onFinish: function onFinish() {
if (cell.specialOverlay) {
_tweenBombOverlayColor3();
}
}
});
};
if (cell._specialOverlayTween) {
cell._specialOverlayTween.stop && cell._specialOverlayTween.stop();
cell._specialOverlayTween = null;
}
cell.specialOverlay.tint = colorTweenTargets[currentColorIndex];
_tweenBombOverlayColor3();
}
} else if (cell.specialType === 'green') {
// Use 'habilidadVerde' asset for green special meme
if (cell.sprite) {
cell.removeChild(cell.sprite);
}
if (game.seekModeForceSeekSprite) {
// Si estamos en modo seek ocultando memes, no mostrar habilidad verde
cell.sprite = null;
} else {
cell.sprite = LK.getAsset('habilidadVerde', {
anchorX: 0.5,
anchorY: 0.5
});
padding = 20;
maxWidth = cellSize - padding * 2;
maxHeight = cellSize - padding * 2;
scaleX = maxWidth / cell.sprite.width;
scaleY = maxHeight / cell.sprite.height;
scale = Math.min(scaleX, scaleY);
cell.sprite.scale.set(scale, scale);
cell.addChild(cell.sprite);
}
} else if (cell.specialType === 'clear' || cell.specialType === 'vertical' || cell.specialType === 'horizontal') {
// Overlay habilidadClear sprite for clear/line specials
cell.specialOverlay = LK.getAsset('HabilidadClear', {
anchorX: 0.5,
anchorY: 0.5
});
// Rotate overlay to match direction
if (cell.specialType === 'horizontal') {
cell.specialOverlay.rotation = 0;
} else if (cell.specialType === 'vertical') {
cell.specialOverlay.rotation = Math.PI / 2;
} else {
cell.specialOverlay.rotation = 0;
}
padding = 20;
maxWidth = cellSize - padding * 2;
maxHeight = cellSize - padding * 2;
scaleX = maxWidth / cell.specialOverlay.width;
scaleY = maxHeight / cell.specialOverlay.height;
scale = Math.min(scaleX, scaleY);
cell.specialOverlay.scale.set(scale, scale);
cell.addChild(cell.specialOverlay);
// --- Color sync: animate overlay tint with background ---
if (typeof colorTweenTargets !== "undefined" && typeof currentColorIndex !== "undefined") {
var _tweenClearOverlayColor3 = function tweenClearOverlayColor() {
if (!cell.specialOverlay) {
return;
}
var nextIndex = (currentColorIndex + 1) % colorTweenTargets.length;
var nextColor = colorTweenTargets[nextIndex];
cell._specialOverlayTween = tween(cell.specialOverlay, {
tint: nextColor
}, {
duration: 14000,
easing: tween.easeInOutQuad,
onFinish: function onFinish() {
if (cell.specialOverlay) {
_tweenClearOverlayColor3();
}
}
});
};
if (cell._specialOverlayTween) {
cell._specialOverlayTween.stop && cell._specialOverlayTween.stop();
cell._specialOverlayTween = null;
}
cell.specialOverlay.tint = colorTweenTargets[currentColorIndex];
_tweenClearOverlayColor3();
}
} else {
cell.sprite.tint = 0xFF8800;
}
}
}
},
cell,
padding,
maxWidth,
maxHeight,
scaleX,
scaleY,
scale,
padding,
maxWidth,
maxHeight,
scaleX,
scaleY,
scale,
padding,
maxWidth,
maxHeight,
scaleX,
scaleY,
scale,
padding,
maxWidth,
maxHeight,
scaleX,
scaleY,
scale;
for (var col = 0; col < gridSize; col++) {
_loop2();
}
}
// Reset combo text
if (seekModeComboText) {
seekModeComboText.setText("Combos: 0/3");
if (seekModeComboText.style) {
seekModeComboText.style.size = 120;
seekModeComboText.style.fill = 0xDD5500;
seekModeComboText.style.font = "'GillSans-Bold',Impact,'Arial Black',Tahoma";
}
seekModeComboText.y = 2732 - 120; // Ensure position is below wait text
}
}
}, 1000);
}
}
// Stop any currently playing combo sounds before playing a new one
LK.getSound('Combo1').stop();
LK.getSound('Combo2').stop();
LK.getSound('Combo3').stop();
LK.getSound('Combo4').stop();
LK.getSound('Combo5').stop();
if (comboCounter >= 9) {
LK.getSound('Combo5').play();
} else if (comboCounter >= 6) {
LK.getSound('Combo4').play();
} else if (comboCounter >= 4) {
LK.getSound('Combo3').play();
} else if (comboCounter >= 3) {
LK.getSound('Combo2').play();
} else if (comboCounter >= 2) {
LK.getSound('Combo1').play();
}
}
var specialCell = null;
var isHorizontalMatch = false;
var isVerticalMatch = false;
for (var type in cellsByType) {
var typeCells = cellsByType[type];
// --- Prevent special abilities from creating new special abilities ---
// If any cell in this group is a special, do not create a new special meme
var groupHasSpecial = false;
for (var i = 0; i < typeCells.length; i++) {
if (typeCells[i].isSpecial) {
groupHasSpecial = true;
break;
}
}
if (groupHasSpecial) {
// Do not create a new special meme for this group
continue;
}
if (typeCells.length >= 6) {
// Check if a special ability is currently being used before creating a green special
var specialAbilityInUse = false;
// Loop through all cells to check if any special is activated
for (var r = 0; r < gridSize + extraRows; r++) {
for (var c = 0; c < gridSize; c++) {
if (gridCells[r] && gridCells[r][c] && gridCells[r][c].isSpecial && gridCells[r][c].beingDestroyed) {
specialAbilityInUse = true;
break;
}
}
if (specialAbilityInUse) {
break;
}
}
// Only create a green special meme if no other special ability is in use
if (!specialAbilityInUse) {
// Create green special meme for 6 or more matches
if (centerCell && centerCell.value === parseInt(type)) {
specialCell = centerCell;
} else {
specialCell = typeCells[0];
}
specialCell.isSpecial = true;
specialCell.specialType = 'green';
specialCell.value = 99; // Assign unique value for green special
specialCell.value = 99; // Assign unique value for green special
specialCell.beingDestroyed = false;
// Award bonus points for creating a green special meme
updateScore(100);
// Remove special cell from cells to destroy
visibleCellsToDestroy = visibleCellsToDestroy.filter(function (cell) {
return cell !== specialCell;
});
}
break; // Only create one special meme
} else if (typeCells.length === 5) {
// Create bomb special meme (blue)
if (centerCell && centerCell.value === parseInt(type)) {
specialCell = centerCell;
} else {
specialCell = typeCells[0];
}
specialCell.isSpecial = true;
specialCell.specialType = 'bomb';
specialCell.beingDestroyed = false;
// Award bonus points for creating a bomb special meme
updateScore(75);
// Remove special cell from cells to destroy
visibleCellsToDestroy = visibleCellsToDestroy.filter(function (cell) {
return cell !== specialCell;
});
break; // Only create one special meme
} else if (typeCells.length === 4) {
// Determine if match is horizontal or vertical
var allInSameRow = true;
var allInSameCol = true;
var firstCell = typeCells[0];
for (var i = 1; i < typeCells.length; i++) {
if (typeCells[i].row !== firstCell.row) {
allInSameRow = false;
}
if (typeCells[i].col !== firstCell.col) {
allInSameCol = false;
}
}
isHorizontalMatch = allInSameRow;
isVerticalMatch = allInSameCol;
// Create special meme only if it's a clean horizontal or vertical match
if (isHorizontalMatch || isVerticalMatch) {
// Use center cell if it matches the type, otherwise use the first cell of this type
if (centerCell && centerCell.value === parseInt(type)) {
specialCell = centerCell;
} else {
specialCell = typeCells[0];
}
specialCell.isSpecial = true;
specialCell.specialType = isHorizontalMatch ? 'horizontal' : 'vertical';
specialCell.beingDestroyed = false;
// Award bonus points for creating a line-clearing special meme
updateScore(50);
// Remove special cell from cells to destroy
visibleCellsToDestroy = visibleCellsToDestroy.filter(function (cell) {
return cell !== specialCell;
});
break; // Only create one special meme
}
}
}
// Sort cells by distance from center cell for ripple effect
if (centerCell && visibleCellsToDestroy.length > 0) {
visibleCellsToDestroy.sort(function (a, b) {
var distA = Math.abs(a.row - centerCell.row) + Math.abs(a.col - centerCell.col);
var distB = Math.abs(b.row - centerCell.row) + Math.abs(b.col - centerCell.col);
return distA - distB;
});
}
var delay = 0;
var delayIncrement = 50;
var totalDestructionTime = visibleCellsToDestroy.length * delayIncrement;
// Mark cells as being destroyed to prevent them from being part of new matches
visibleCellsToDestroy.forEach(function (cell) {
if (cell) {
cell.beingDestroyed = true;
// Check if any of these cells are matched with a special meme
if (cell.isSpecial) {
// Special meme is being destroyed, activate its power
LK.setTimeout(function () {
cell.activateSpecialPower();
}, 100);
}
}
});
// If we have a special meme, apply the appropriate overlay or tint
if (specialCell && specialCell.isSpecial) {
// Remove any previous overlays
if (specialCell.specialOverlay && specialCell.children.indexOf(specialCell.specialOverlay) !== -1) {
specialCell.removeChild(specialCell.specialOverlay);
specialCell.specialOverlay = null;
}
if (specialCell.specialType === 'bomb') {
// Overlay habilidadBomba sprite
specialCell.specialOverlay = LK.getAsset('habilidadBomba', {
anchorX: 0.5,
anchorY: 0.5
});
var padding = 20;
var maxWidth = cellSize - padding * 2;
var maxHeight = cellSize - padding * 2;
var scaleX = maxWidth / specialCell.specialOverlay.width;
var scaleY = maxHeight / specialCell.specialOverlay.height;
var scale = Math.min(scaleX, scaleY);
specialCell.specialOverlay.scale.set(scale, scale);
specialCell.addChild(specialCell.specialOverlay);
// --- Color sync: animate overlay tint with background ---
if (typeof colorTweenTargets !== "undefined" && typeof currentColorIndex !== "undefined") {
var _tweenBombOverlayColor4 = function tweenBombOverlayColor() {
if (!specialCell.specialOverlay) {
return;
}
var nextIndex = (currentColorIndex + 1) % colorTweenTargets.length;
var nextColor = colorTweenTargets[nextIndex];
specialCell._specialOverlayTween = tween(specialCell.specialOverlay, {
tint: nextColor
}, {
duration: 14000,
easing: tween.easeInOutQuad,
onFinish: function onFinish() {
if (specialCell.specialOverlay) {
_tweenBombOverlayColor4();
}
}
});
};
if (specialCell._specialOverlayTween) {
specialCell._specialOverlayTween.stop && specialCell._specialOverlayTween.stop();
specialCell._specialOverlayTween = null;
}
specialCell.specialOverlay.tint = colorTweenTargets[currentColorIndex];
_tweenBombOverlayColor4();
}
} else if (specialCell.specialType === 'green') {
// Use 'habilidadVerde' asset for green special meme
if (specialCell.sprite) {
specialCell.removeChild(specialCell.sprite);
}
specialCell.sprite = LK.getAsset('habilidadVerde', {
anchorX: 0.5,
anchorY: 0.5
});
var padding = 20;
var maxWidth = cellSize - padding * 2;
var maxHeight = cellSize - padding * 2;
var scaleX = maxWidth / specialCell.sprite.width;
var scaleY = maxHeight / specialCell.sprite.height;
var scale = Math.min(scaleX, scaleY);
specialCell.sprite.scale.set(scale, scale);
specialCell.addChild(specialCell.sprite);
} else if (specialCell.specialType === 'clear' || specialCell.specialType === 'vertical' || specialCell.specialType === 'horizontal') {
// Overlay habilidadClear sprite for clear/line specials
specialCell.specialOverlay = LK.getAsset('HabilidadClear', {
anchorX: 0.5,
anchorY: 0.5
});
// Rotate overlay to match direction
if (specialCell.specialType === 'horizontal') {
specialCell.specialOverlay.rotation = 0;
} else if (specialCell.specialType === 'vertical') {
specialCell.specialOverlay.rotation = Math.PI / 2;
} else {
specialCell.specialOverlay.rotation = 0;
}
var padding = 20;
var maxWidth = cellSize - padding * 2;
var maxHeight = cellSize - padding * 2;
var scaleX = maxWidth / specialCell.specialOverlay.width;
var scaleY = maxHeight / specialCell.specialOverlay.height;
var scale = Math.min(scaleX, scaleY);
specialCell.specialOverlay.scale.set(scale, scale);
specialCell.addChild(specialCell.specialOverlay);
// --- Color sync: animate overlay tint with background ---
if (typeof colorTweenTargets !== "undefined" && typeof currentColorIndex !== "undefined") {
var _tweenClearOverlayColor4 = function tweenClearOverlayColor() {
if (!specialCell.specialOverlay) {
return;
}
var nextIndex = (currentColorIndex + 1) % colorTweenTargets.length;
var nextColor = colorTweenTargets[nextIndex];
specialCell._specialOverlayTween = tween(specialCell.specialOverlay, {
tint: nextColor
}, {
duration: 14000,
easing: tween.easeInOutQuad,
onFinish: function onFinish() {
if (specialCell.specialOverlay) {
_tweenClearOverlayColor4();
}
}
});
};
if (specialCell._specialOverlayTween) {
specialCell._specialOverlayTween.stop && specialCell._specialOverlayTween.stop();
specialCell._specialOverlayTween = null;
}
specialCell.specialOverlay.tint = colorTweenTargets[currentColorIndex];
_tweenClearOverlayColor4();
}
} else {
specialCell.sprite.tint = 0xFF8800; // Orange tint for others
}
LK.effects.flashObject(specialCell, 0xFFFFFF, 300);
}
visibleCellsToDestroy.forEach(function (cell) {
LK.setTimeout(function () {
if (cell && cell.beingDestroyed && gridCells[cell.row] && gridCells[cell.row][cell.col] === cell) {
LK.getSound('Explosion').play();
LK.effects.flashObject(cell, 0xFFFFFF, 200);
// --- PARTICLE EFFECT START ---
if (particlesEnabled) {
// Emit 8-12 particles per meme
var numParticles = 8 + Math.floor(Math.random() * 5);
for (var p = 0; p < numParticles; p++) {
var particle = LK.getAsset('particula', {
anchorX: 0.5,
anchorY: 0.5
});
// Randomize color (RGB)
var r = Math.floor(128 + Math.random() * 127);
var g = Math.floor(128 + Math.random() * 127);
var b = Math.floor(128 + Math.random() * 127);
var rgb = r << 16 | g << 8 | b;
particle.tint = rgb;
// Start at cell position
particle.x = cell.x;
particle.y = cell.y;
// Random velocity and direction
var angle = Math.random() * Math.PI * 2;
var speed = 6 + Math.random() * 6;
var vx = Math.cos(angle) * speed;
var vy = Math.sin(angle) * speed;
// Animate particle
(function (particle, vx, vy) {
var lifetime = 200 + Math.random() * 150;
var startAlpha = 0.9 + Math.random() * 0.1;
particle.alpha = startAlpha;
gridContainer.addChild(particle);
var elapsed = 0;
var updateFn = function updateFn() {
particle.x += vx;
particle.y += vy;
// Fade out
particle.alpha -= 0.04 + Math.random() * 0.02;
// Shrink
particle.scale.x *= 0.93;
particle.scale.y *= 0.93;
elapsed += 16;
if (elapsed > lifetime || particle.alpha <= 0.05) {
if (particle.parent) {
particle.parent.removeChild(particle);
}
LK.clearInterval(intervalId);
}
};
var intervalId = LK.setInterval(updateFn, 16);
})(particle, vx, vy);
}
}
// --- PARTICLE EFFECT END ---
gridContainer.removeChild(cell);
cell.destroy();
gridCells[cell.row][cell.col] = null;
}
}, delay);
delay += delayIncrement;
});
// After all cells in this group are destroyed, check if we need to apply gravity
LK.setTimeout(function () {
// Check if all destructions are complete before applying gravity
var allCellsDestroyed = true;
for (var r = 0; r < gridSize + extraRows; r++) {
for (var c = 0; c < gridSize; c++) {
if (gridCells[r] && gridCells[r][c] && gridCells[r][c].beingDestroyed) {
allCellsDestroyed = false;
}
}
}
// Only the last destruction process should trigger gravity
if (allCellsDestroyed && !window.gravityInProgress && !window.fillInProgress) {
applyGravity();
}
}, totalDestructionTime + 50);
}
function applyGravity() {
isAnimating = true;
var cellsToFall = [];
if (window.gravityInProgress) {
return;
}
window.gravityInProgress = true;
for (var col = 0; col < gridSize; col++) {
for (var row = gridSize + extraRows - 1; row >= extraRows; row--) {
if (!gridCells[row][col]) {
var sourceRow = row - 1;
while (sourceRow >= 0 && !gridCells[sourceRow][col]) {
sourceRow--;
}
if (sourceRow >= 0) {
var cellToMove = gridCells[sourceRow][col];
if (cellToMove) {
cellsToFall.push({
cell: cellToMove,
fromRow: sourceRow,
toRow: row,
col: col
});
gridCells[row][col] = cellToMove;
gridCells[sourceRow][col] = null;
cellToMove.row = row;
if (sourceRow < extraRows) {
gridContainer.addChild(cellToMove);
}
}
}
}
}
}
var longestDelay = 0;
var baseDelay = 25;
cellsToFall.sort(function (a, b) {
if (a.col !== b.col) {
return a.col - b.col;
}
return b.toRow - a.toRow;
});
cellsToFall.forEach(function (fallInfo, index) {
var delay = index * baseDelay;
var newPos = getCellPosition(fallInfo.toRow, fallInfo.col);
// Calculate duration based on distance
var distance = Math.abs(newPos.y - fallInfo.cell.y);
var duration = 100 + distance * 0.35; // Reduced base time + smaller distance multiplier for faster falls
var totalTime = delay + duration;
if (totalTime > longestDelay) {
longestDelay = totalTime;
}
LK.setTimeout(function () {
if (fallInfo.cell && gridCells[fallInfo.cell.row] && gridCells[fallInfo.cell.row][fallInfo.cell.col] === fallInfo.cell) {
tween(fallInfo.cell, {
y: newPos.y
}, {
duration: duration,
easing: tween.linear
});
}
}, delay);
});
LK.setTimeout(function () {
window.gravityInProgress = false;
if (!window.destructionInProgress) {
fillEmptySpacesWithNewMemes();
}
}, longestDelay + 50);
}
function fillEmptySpacesWithNewMemes() {
if (window.fillInProgress || window.gravityInProgress) {
return;
}
window.fillInProgress = true;
var anyNewMemeAdded = false;
var newCellsToAdd = [];
for (var col = 0; col < gridSize; col++) {
for (var row = 0; row < gridSize + extraRows; row++) {
if (!gridCells[row][col]) {
anyNewMemeAdded = true;
var newCell = getGridCell();
var pos = getCellPosition(row, col);
newCell.x = pos.x;
newCell.y = pos.y - 400;
var randomValue = Math.floor(Math.random() * 5) + 1;
newCell.setValue(randomValue);
newCell.row = row;
newCell.col = col;
gridCells[row][col] = newCell;
newCellsToAdd.push({
cell: newCell,
destY: pos.y,
row: row,
col: col
});
if (row >= extraRows) {
gridContainer.addChild(newCell);
}
}
}
}
var longestDelay = 0;
var baseDelay = 15;
var constantDuration = 250;
newCellsToAdd.sort(function (a, b) {
if (a.col !== b.col) {
return a.col - b.col;
}
return b.row - a.row;
});
newCellsToAdd.forEach(function (cellData, index) {
var delay = index * baseDelay;
var totalTime = delay + constantDuration;
if (totalTime > longestDelay) {
longestDelay = totalTime;
}
LK.setTimeout(function () {
if (cellData.cell && gridCells[cellData.row] && gridCells[cellData.row][cellData.col] === cellData.cell) {
tween(cellData.cell, {
y: cellData.destY
}, {
duration: constantDuration,
easing: tween.linear
});
}
}, delay);
});
if (anyNewMemeAdded) {
LK.setTimeout(function () {
window.fillInProgress = false;
if (window.destructionInProgress || window.gravityInProgress) {
isAnimating = false;
return;
}
var visibleMatchGroups = getMatches().filter(function (group) {
// Check if the match has cells in both visible and invisible areas
var visibleCells = group.filter(function (cell) {
return cell.row >= extraRows;
});
var invisibleCells = group.filter(function (cell) {
return cell.row < extraRows;
});
// Don't count groups with both visible and invisible cells unless there are at least 3 visible cells
if (visibleCells.length > 0 && invisibleCells.length > 0 && visibleCells.length < 3) {
return false;
}
return visibleCells.length >= 3; // At least 3 visible cells make a valid visible match
});
var newMatches = visibleMatchGroups;
if (newMatches.length > 0) {
// Group by meme type
var matchesByType = {};
newMatches.forEach(function (group) {
if (group.length > 0) {
var type = group[0].value;
if (!matchesByType[type]) {
matchesByType[type] = [];
}
matchesByType[type].push(group);
}
});
var newCellsToDestroy = [];
var newCellTracker = {};
// Process each type separately
for (var type in matchesByType) {
var typeGroups = matchesByType[type];
// Find a central cell for this type
var centerCell = null;
if (typeGroups.length > 0 && typeGroups[0].length > 0) {
// Pick the center of the first match group of this type
var matchGroup = typeGroups[0];
centerCell = matchGroup[Math.floor(matchGroup.length / 2)];
}
// Collect all cells of this type
var typeCells = [];
typeGroups.forEach(function (group) {
group.forEach(function (cell) {
var cellKey = cell.row + "_" + cell.col;
if (!newCellTracker[cellKey] && cell.row >= extraRows && cell && gridCells[cell.row] && gridCells[cell.row][cell.col] === cell) {
typeCells.push(cell);
newCellTracker[cellKey] = true;
}
});
});
// Destroy cells of this type
if (typeCells.length) {
destroyCells(typeCells, centerCell);
}
}
if (Object.keys(matchesByType).length === 0) {
isAnimating = false;
}
} else {
isAnimating = false;
}
}, longestDelay + 50);
} else {
window.fillInProgress = false;
isAnimating = false;
// Reset combo tracking when no more matches are being created
comboInProgress = false;
comboCounter = 0;
}
}
// Timer management functions
function startTimer() {
// Clear any existing timer
if (timerInterval) {
LK.clearInterval(timerInterval);
timerInterval = null;
}
// Calculate initial max timer value based on score
// This ensures proper timer initialization when starting a game with existing score
var maxTimer = 10;
// Use exponential thresholds for slower decrease
if (score >= 100) {
maxTimer = 9;
}
if (score >= 500) {
maxTimer = 8;
}
if (score >= 1000) {
maxTimer = 7;
}
if (score >= 3500) {
maxTimer = 6;
}
if (score >= 10000) {
maxTimer = 5;
}
if (score >= 25000) {
maxTimer = 4;
}
if (score >= 50000) {
maxTimer = 3;
}
// Only set timer to max when initializing new game, not when resuming
if (!game.timerInitialized) {
timerSeconds = maxTimer;
game.timerInitialized = true;
}
// Update timer display initially
if (timerText) {
timerText.setText("Time: " + timerSeconds.toFixed(1));
}
// Start countdown timer with decimals (100ms interval)
timerInterval = LK.setInterval(function () {
timerSeconds -= 0.1;
timerSeconds = Math.max(0, parseFloat(timerSeconds.toFixed(1))); // Fix floating point issues
// Update timer display
if (timerText) {
timerText.setText("Time: " + timerSeconds.toFixed(1));
}
// Check for game over
if (timerSeconds <= 0) {
// Stop timer
LK.clearInterval(timerInterval);
timerInterval = null;
// Instead of showing game over screen, trigger the custom game over
game.onGameOver();
}
}, 100);
}
function resetTimer() {
// Only reset timer in Fast Mode
if (game.gameMode === 'fast') {
// Calculate max timer value based on score
// Start with 10 seconds, decrease as score increases, minimum of 3 seconds
var maxTimer = 10;
// Use exponential thresholds for slower decrease
if (score >= 100) {
maxTimer = 9;
}
if (score >= 500) {
maxTimer = 8;
}
if (score >= 1000) {
maxTimer = 7;
}
if (score >= 3500) {
maxTimer = 6;
}
if (score >= 10000) {
maxTimer = 5;
}
if (score >= 25000) {
maxTimer = 4;
}
if (score >= 50000) {
maxTimer = 3;
}
// Set timer to calculated max
timerSeconds = maxTimer;
if (timerText) {
timerText.setText("Time: " + timerSeconds.toFixed(1));
}
}
}
// Handle game over events to return to menu
game.onGameOver = function () {
// Save high score one last time if it's better
if (game.gameMode === 'classic' && score > highScoreClassic) {
highScoreClassic = score;
storage.highScoreClassic = highScoreClassic;
} else if (game.gameMode === 'fast' && score > highScoreFast) {
highScoreFast = score;
storage.highScoreFast = highScoreFast;
} else if (game.gameMode === 'seekmode' && score > highScoreSeek) {
highScoreSeek = score;
storage.highScoreSeek = highScoreSeek;
}
// Stop timer if running
if (timerInterval) {
LK.clearInterval(timerInterval);
timerInterval = null;
}
// Clean up seek mode block timer and text
seekModeBlockActive = false;
if (seekModeBlockTimer) {
LK.clearInterval(seekModeBlockTimer);
seekModeBlockTimer = null;
}
if (seekModeBlockText) {
game.removeChild(seekModeBlockText);
seekModeBlockText.destroy();
seekModeBlockText = null;
}
// Clean up seek mode combo counter and show-all timer
if (seekModeComboText) {
game.removeChild(seekModeComboText);
seekModeComboText.destroy();
seekModeComboText = null;
}
if (seekModeShowAllTimer) {
LK.clearTimeout(seekModeShowAllTimer);
seekModeShowAllTimer = null;
}
seekModeComboCount = 0;
// --- FIX: Reset seekModeForceSeekSprite so memes use correct sprite after game over ---
game.seekModeForceSeekSprite = false;
// Stop periodic save interval
if (saveScoreInterval) {
LK.clearInterval(saveScoreInterval);
saveScoreInterval = null;
}
// Clear music interval
if (game.musicInterval) {
LK.clearInterval(game.musicInterval);
game.musicInterval = null;
// Stop any currently playing music
LK.stopMusic();
}
// For Fast Mode, show a custom high score popup instead of the game over screen
if (game.gameMode === 'fast') {
// Create popup container
var popupContainer = new Container();
// Create popup background
var popupBg = LK.getAsset('button', {
anchorX: 0.5,
anchorY: 0.5,
scaleX: 4,
scaleY: 4.5
});
popupBg.tint = 0x0088FF; // Blue tint for Fast Mode
// Create popup title
var popupTitle = new Text2("GAME OVER", {
size: 100,
fill: 0xFFFFFF
});
popupTitle.anchor.set(0.5, 0);
popupTitle.y = -350;
// Show current score in Fast Mode game over popup
var currentScoreText = new Text2("Score: " + score, {
size: 90,
fill: 0xffffff
});
currentScoreText.anchor.set(0.5, 0);
currentScoreText.y = -200;
// Show high score
var highScoreText = new Text2("High Score: " + highScoreFast, {
size: 90,
fill: 0xFFFF00
});
highScoreText.anchor.set(0.5, 0);
highScoreText.y = -100;
// Update high score if needed
if (score > highScoreFast) {
highScoreFast = score;
highScoreText.setText("High Score: " + score + " (New!)");
}
// Create button to return to menu
var menuButton = new Container();
var menuButtonBg = LK.getAsset('button', {
anchorX: 0.5,
anchorY: 0.5,
scaleX: 3,
scaleY: 1.5
});
menuButtonBg.tint = 0xFF5500;
var menuButtonText = new Text2("BACK TO MENU", {
size: 70,
fill: 0xFFFFFF
});
menuButtonText.anchor.set(0.5, 0.5);
menuButton.addChild(menuButtonBg);
menuButton.addChild(menuButtonText);
menuButton.y = 250;
// Add all elements to popup
popupContainer.addChild(popupBg);
popupContainer.addChild(popupTitle);
popupContainer.addChild(highScoreText);
popupContainer.addChild(currentScoreText);
popupContainer.addChild(menuButton);
// Position popup in center of screen
popupContainer.x = 2048 / 2;
popupContainer.y = 2732 / 2;
game.addChild(popupContainer);
// Add button interaction
menuButton.interactive = true;
menuButton.down = function (x, y, obj) {
LK.effects.flashObject(menuButtonBg, 0xFFFFFF, 200);
// Clear the game board
while (gridContainer.children.length > 0) {
var child = gridContainer.children[0];
gridContainer.removeChild(child);
child.destroy();
}
if (scoreText) {
game.removeChild(scoreText);
scoreText = null;
}
if (timerText) {
game.removeChild(timerText);
timerText = null;
}
// Remove popup
game.removeChild(popupContainer);
// Clean up any game UI elements
if (game.modeText) {
game.removeChild(game.modeText);
game.modeText = null;
}
if (game.pauseButton) {
game.removeChild(game.pauseButton);
game.pauseButton = null;
}
game.timerInitialized = false;
// Show menu
initializeMenu();
};
} else {
// For Classic Mode, use the standard game over screen
LK.setTimeout(function () {
// Clear the game board
while (gridContainer.children.length > 0) {
var child = gridContainer.children[0];
gridContainer.removeChild(child);
child.destroy();
}
if (scoreText) {
game.removeChild(scoreText);
scoreText = null;
}
if (timerText) {
game.removeChild(timerText);
timerText = null;
}
// Clean up any game UI elements
if (game.modeText) {
game.removeChild(game.modeText);
game.modeText = null;
}
if (game.pauseButton) {
game.removeChild(game.pauseButton);
game.pauseButton = null;
}
game.timerInitialized = false;
// Show menu
initializeMenu();
}, 500);
}
};
function checkForAndDestroyMatches(swappedCellA, swappedCellB) {
if (window.gravityInProgress || window.fillInProgress) {
return;
}
var allMatchGroupsOnBoard = getMatches();
if (!allMatchGroupsOnBoard.length) {
return;
}
var relevantMatchGroups = allMatchGroupsOnBoard.filter(function (group) {
// Check if the match has cells in both visible and invisible areas
var visibleCells = group.filter(function (cell) {
return cell.row >= extraRows;
});
var invisibleCells = group.filter(function (cell) {
return cell.row < extraRows;
});
// Don't count groups with both visible and invisible cells unless there are at least 3 visible cells
if (visibleCells.length > 0 && invisibleCells.length > 0 && visibleCells.length < 3) {
return false;
}
return group.some(function (cellInGroup) {
return (cellInGroup === swappedCellA || cellInGroup === swappedCellB) && cellInGroup.row >= extraRows;
});
});
if (!relevantMatchGroups.length) {
return;
}
// Group by meme type
var matchesByType = {};
relevantMatchGroups.forEach(function (group) {
if (group.length > 0) {
var type = group[0].value;
if (!matchesByType[type]) {
matchesByType[type] = [];
}
matchesByType[type].push(group);
}
});
var uniqueCellTracker = {};
var cellsToDestroy = [];
// Process each type separately
for (var type in matchesByType) {
var typeGroups = matchesByType[type];
// Flatten all groups of this type
var typeCells = [];
typeGroups.forEach(function (group) {
group.forEach(function (cell) {
if (cell.row >= extraRows) {
typeCells.push(cell);
}
});
});
// Add each cell of this type to cellsToDestroy
typeCells.forEach(function (cell) {
var cellKey = cell.row + "_" + cell.col;
if (!uniqueCellTracker[cellKey] && cell.row >= extraRows && cell && gridCells[cell.row] && gridCells[cell.row][cell.col] === cell) {
cellsToDestroy.push(cell);
uniqueCellTracker[cellKey] = true;
}
});
}
;
if (cellsToDestroy.length) {
// Pass the swapped cell that created the match as the center for the ripple effect
var centerCell = swappedCellA && relevantMatchGroups.some(function (group) {
return group.includes(swappedCellA);
}) ? swappedCellA : swappedCellB;
destroyCells(cellsToDestroy, centerCell);
LK.setTimeout(function () {
if (window.gravityInProgress || window.fillInProgress) {
return;
}
var visibleMatchGroups = getMatches().filter(function (group) {
// Check if the match has cells in both visible and invisible areas
var visibleCells = group.filter(function (cell) {
return cell.row >= extraRows;
});
var invisibleCells = group.filter(function (cell) {
return cell.row < extraRows;
});
// Don't count groups with both visible and invisible cells unless there are at least 3 visible cells
if (visibleCells.length > 0 && invisibleCells.length > 0 && visibleCells.length < 3) {
return false;
}
return visibleCells.length >= 3; // At least 3 visible cells make a valid visible match
});
var newMatches = visibleMatchGroups;
if (newMatches.length > 0) {
// Group by meme type
var matchesByType = {};
newMatches.forEach(function (group) {
if (group.length > 0) {
var type = group[0].value;
if (!matchesByType[type]) {
matchesByType[type] = [];
}
matchesByType[type].push(group);
}
});
// Process each type separately
for (var type in matchesByType) {
var typeGroups = matchesByType[type];
var newCellsToDestroy = [];
var newCellTracker = {};
// Collect all cells of this type
typeGroups.forEach(function (group) {
group.forEach(function (cell) {
var cellKey = cell.row + "_" + cell.col;
if (!newCellTracker[cellKey] && cell.row >= extraRows && cell && gridCells[cell.row] && gridCells[cell.row][cell.col] === cell) {
newCellsToDestroy.push(cell);
newCellTracker[cellKey] = true;
}
});
});
if (newCellsToDestroy.length) {
// Find center cell of this type
var centerCell = newCellsToDestroy[Math.floor(newCellsToDestroy.length / 2)];
destroyCells(newCellsToDestroy, centerCell);
}
}
}
}, 400);
}
}
var gridSize = 7;
var extraRows = 9;
var cellSpacing = 12;
var cellSize = 240;
var gridCells = [];
var totalGridWidth = gridSize * cellSize + (gridSize - 1) * cellSpacing;
var totalVisibleGridHeight = totalGridWidth;
var totalGridHeight = totalVisibleGridHeight + extraRows * (cellSize + cellSpacing);
var startX = (2048 - totalGridWidth) / 2 + cellSize / 2;
var startY = (-1600 - totalVisibleGridHeight) / 2 + cellSize / 2 + extraRows * (cellSize + cellSpacing);
function getCellPosition(row, col) {
return {
x: startX + col * (cellSize + cellSpacing),
y: startY + row * (cellSize + cellSpacing) - extraRows * (cellSize + cellSpacing)
};
}
function initializeGrid() {
// Add background image behind grid cells
if (gridContainer.gridBackground) {
gridContainer.removeChild(gridContainer.gridBackground);
gridContainer.gridBackground = null;
}
var gridBackground = LK.getAsset('Bg3', {
anchorX: 0.5,
anchorY: 0.5,
x: 2048 / 2,
y: 2732 / 2 + 100,
alpha: 0.5
});
var scaleX = 2.2;
var scaleY = 2.2;
var scale = Math.max(scaleX, scaleY);
gridBackground.scale.set(scale, scale);
gridContainer.gridBackground = gridBackground;
gridContainer.addChildAt(gridBackground, 0);
// --- CUADRICULAS OBJETO PARA LUGARES MOVIBLES ---
// Elimina cuadriculas previas si existen
if (typeof cuadriculas !== "undefined" && cuadriculas && cuadriculas.parent) {
cuadriculas.parent.removeChild(cuadriculas);
}
cuadriculas = new Container();
// Dibuja cuadricula solo en la zona visible (no en extraRows)
for (var row = extraRows; row < gridSize + extraRows; row++) {
for (var col = 0; col < gridSize; col++) {
var pos = getCellPosition(row, col);
var cuadriculaSprite = LK.getAsset('cuadricula', {
anchorX: 0.5,
anchorY: 0.5,
scaleX: 1.05,
scaleY: 1.05,
alpha: 0.7
});
cuadriculaSprite.x = pos.x;
cuadriculaSprite.y = pos.y;
cuadriculas.addChild(cuadriculaSprite);
}
}
// Añade cuadriculas detrás de las celdas
gridContainer.addChildAt(cuadriculas, 1);
gridCells = [];
for (var row = 0; row < gridSize + extraRows; row++) {
gridCells[row] = [];
for (var col = 0; col < gridSize; col++) {
var pos = getCellPosition(row, col);
var cell = getGridCell ? getGridCell() : new GridCell();
cell.x = pos.x;
cell.y = pos.y;
cell.row = row;
cell.col = col;
var randomValue;
var attempts = 0;
do {
randomValue = Math.floor(Math.random() * 5) + 1;
attempts++;
var leftMatchCount = 0;
var aboveMatchCount = 0;
if (col >= 2) {
if (gridCells[row][col - 1].value === randomValue && gridCells[row][col - 2].value === randomValue) {
leftMatchCount = 2;
}
}
if (row >= 2) {
if (gridCells[row - 1][col].value === randomValue && gridCells[row - 2][col].value === randomValue) {
aboveMatchCount = 2;
}
}
} while ((leftMatchCount >= 2 || aboveMatchCount >= 2) && attempts < 10);
cell.setValue(randomValue);
if (row >= extraRows) {
gridContainer.addChild(cell);
}
gridCells[row][col] = cell;
}
}
}
// --- PUNTERO DRAG ---
// Variable global para habilitar/deshabilitar el drag de memes
var dragMemeEnabled = true;
// Puntero visual que sigue el dedo mientras está presionado
var pointerActive = false;
var pointerSprite = LK.getAsset('Puntero', {
anchorX: 0.5,
anchorY: 0.5,
x: 2048 / 2,
y: 2732 / 2
});
pointerSprite.visible = false;
pointerSprite.zIndex = 9999; // Asegura que esté encima
game.addChild(pointerSprite);
// --- CHECK CON ASSET PUNTERO ENCIMA DE TODAS LAS COLUMNAS DE MEMES ---
var checkPointers = [];
var checkRow = extraRows; // Fila visible superior
for (var checkCol = 0; checkCol < gridSize; checkCol++) {
var checkPos = getCellPosition(checkRow, checkCol);
var checkPointer = LK.getAsset('Puntero', {
anchorX: 0.5,
anchorY: 1,
x: checkPos.x,
y: checkPos.y - cellSize / 2 - 110,
// Encima de la celda, con margen
scaleX: 2,
scaleY: 2,
alpha: 0
});
checkPointer.zIndex = 9998; // Debajo del puntero drag, encima de la grilla
game.addChild(checkPointer);
checkPointers.push(checkPointer);
}
// Evento down: activa el puntero y lo posiciona
game.down = function (x, y, obj) {
pointerActive = true;
pointerSprite.visible = true;
pointerSprite.x = x;
pointerSprite.y = y;
if (typeof handleCellTap === "function") {
// Si hay una celda debajo, permite la selección normal
// (esto mantiene la funcionalidad original)
// handleCellTap puede ser llamada aquí si se desea
}
};
// Evento move: si está activo, sigue el dedo
game.move = function (x, y, obj) {
if (pointerActive) {
pointerSprite.x = x;
pointerSprite.y = y;
// --- SWAP POR ARRASTRE ---
if (dragMemeEnabled && selectedCell && gridCells[selectedCell.row] && gridCells[selectedCell.row][selectedCell.col] === selectedCell) {
// Calcula la posición central de la celda seleccionada
var cellPos = getCellPosition(selectedCell.row, selectedCell.col);
var dx = x - cellPos.x;
var dy = y - cellPos.y;
var dist = Math.sqrt(dx * dx + dy * dy);
if (dist > 100) {
// Determina la dirección principal (horizontal o vertical)
var dir;
if (Math.abs(dx) > Math.abs(dy)) {
dir = dx > 0 ? "right" : "left";
} else {
dir = dy > 0 ? "down" : "up";
}
var targetRow = selectedCell.row;
var targetCol = selectedCell.col;
if (dir === "right" && selectedCell.col < gridSize - 1) {
targetCol++;
} else if (dir === "left" && selectedCell.col > 0) {
targetCol--;
} else if (dir === "down" && selectedCell.row < gridSize + extraRows - 1) {
targetRow++;
} else if (dir === "up" && selectedCell.row > 0) {
targetRow--;
} else {
// No hay celda adyacente válida
return;
}
var targetCell = gridCells[targetRow][targetCol];
// Solo intercambia si la celda destino existe y no está siendo destruida
if (targetCell && !targetCell.beingDestroyed) {
// Llama a la lógica de swap como si se hubiera hecho tap en la celda adyacente
handleCellTap(targetCell);
}
}
}
}
};
// Evento up: desactiva el puntero
game.up = function (x, y, obj) {
pointerActive = false;
pointerSprite.visible = false;
};
// --- INTRODUCTION SCREEN WITH DARK TRANSITIONS ---
// Show a black transition overlay, then introduction, then fade out and show menu
var introTransition = null;
var introImage = null;
var introTimeout = null;
// --- INTRO OPTION: persistently store intro enabled/disabled ---
// Load dragMemeEnabled from storage if available, otherwise default to true
var dragMemeEnabled = typeof storage.dragMemeEnabled === "boolean" ? storage.dragMemeEnabled : true;
storage.dragMemeEnabled = dragMemeEnabled;
// Load introEnabled from storage if available, otherwise default to true
var introEnabled = typeof storage.introEnabled === "boolean" ? storage.introEnabled : true;
storage.introEnabled = introEnabled;
// Load backgroundColorAnimEnabled from storage if available, otherwise default to true
var backgroundColorAnimEnabled = typeof storage.backgroundColorAnimEnabled === "boolean" ? storage.backgroundColorAnimEnabled : true;
storage.backgroundColorAnimEnabled = backgroundColorAnimEnabled;
// Load particlesEnabled from storage if available, otherwise default to true
var particlesEnabled = typeof storage.particlesEnabled === "boolean" ? storage.particlesEnabled : true;
storage.particlesEnabled = particlesEnabled;
// Function to show the introduction and then the menu
function showIntroductionAndMenu() {
if (!introEnabled) {
// If intro is disabled, go straight to menu
initializeMenu();
return;
}
// 1. Create black overlay (full screen)
introTransition = LK.getAsset('transicion', {
anchorX: 0.5,
anchorY: 0.5,
x: 2048 / 2,
y: 2732 / 2,
scaleX: 1,
scaleY: 1,
alpha: 1
});
introTransition.zIndex = 99999;
game.addChild(introTransition);
// 2. Fade in (already black), then show intro image
LK.setTimeout(function () {
// 3. Show introduction image
introImage = LK.getAsset('introduction', {
anchorX: 0.5,
anchorY: 0.5,
x: 2048 / 2,
y: 2732 / 2,
scaleX: 0.7,
scaleY: 0.7,
alpha: 0
});
introImage.zIndex = 100000;
game.addChild(introImage);
// Fade in intro image
tween(introImage, {
alpha: 1
}, {
duration: 800,
easing: tween.easeInOutQuad
});
// 4. Wait for 2.5 seconds, then fade out intro image, then fade out overlay after a delay
introTimeout = LK.setTimeout(function () {
// Fade out intro image
tween(introImage, {
alpha: 0
}, {
duration: 700,
easing: tween.easeInOutQuad,
onFinish: function onFinish() {
if (introImage && introImage.parent) {
game.removeChild(introImage);
introImage = null;
}
// Fade out black overlay after intro image is gone (extra delay)
LK.setTimeout(function () {
tween(introTransition, {
alpha: 0
}, {
duration: 1000,
easing: tween.easeInOutQuad,
onFinish: function onFinish() {
if (introTransition && introTransition.parent) {
game.removeChild(introTransition);
introTransition = null;
}
// Now show the menu
initializeMenu();
}
});
}, 400); // 400ms extra so overlay lasts longer than image
}
});
}, 2500);
}, 400);
}
// Call introduction instead of menu directly
showIntroductionAndMenu();
function ensureNoInitialMatches() {
var matches = getMatches();
if (matches.length > 0) {
matches.forEach(function (group) {
group.forEach(function (cell) {
var currentValue = cell.value;
var newValue;
do {
newValue = Math.floor(Math.random() * 5) + 1;
} while (newValue === currentValue);
cell.setValue(newValue);
});
});
ensureNoInitialMatches();
}
}
ensureNoInitialMatches(); ===================================================================
--- original.js
+++ change.js
@@ -892,9 +892,9 @@
self.removeChild(self.seekScoreText);
self.seekScoreText = null;
}
// Create mode buttons with high scores
- function createModeButton(modeName, score, color, posY, buttonType) {
+ function createModeButton(modeName, score, color, posY) {
var button = new Container();
var buttonBg = LK.getAsset('button', {
anchorX: 0.5,
anchorY: 0.5,
@@ -918,31 +918,91 @@
button.addChild(modeText);
button.addChild(scoreText);
button.x = 2048 / 2;
button.y = posY;
+ // --- Easter Egg 3 logic ---
+ if (typeof window.easterEgg3Counters === "undefined") {
+ window.easterEgg3Counters = {
+ zen: 0,
+ fast: 0,
+ seek: 0
+ };
+ }
+ if (typeof window.easterEgg3Active === "undefined") {
+ window.easterEgg3Active = false;
+ }
+ if (typeof window.easterEgg3Container === "undefined") {
+ window.easterEgg3Container = null;
+ }
button.interactive = true;
button.down = function (x, y, obj) {
- LK.effects.flashObject(buttonBg, 0xFFFFFF, 200);
- LK.getSound('ButtonSound').play();
- // Track taps for Easter Egg 3
- if (buttonType === 'zen') {
- easterEgg3ZenTaps++;
- } else if (buttonType === 'seek') {
- easterEgg3SeekTaps++;
- } else if (buttonType === 'fast') {
- easterEgg3FastTaps++;
+ // Identify which button was pressed by modeName
+ if (modeName === "Zen Mode") {
+ window.easterEgg3Counters.zen++;
+ if (window.easterEgg3Counters.zen > 2) window.easterEgg3Counters.zen = 2;
+ } else if (modeName === "Fast Mode") {
+ window.easterEgg3Counters.fast++;
+ if (window.easterEgg3Counters.fast > 3) window.easterEgg3Counters.fast = 3;
+ } else if (modeName === "Seek Mode") {
+ window.easterEgg3Counters.seek++;
+ if (window.easterEgg3Counters.seek > 1) window.easterEgg3Counters.seek = 1;
}
- // Check if taps match the pattern: zen=2, seek=1, fast=3
- if (easterEgg3ZenTaps === 2 && easterEgg3SeekTaps === 1 && easterEgg3FastTaps === 3 && !easterEgg3Active) {
- easterEgg3Active = true;
- showEasterEgg3();
+ // Check if all conditions are met
+ if (window.easterEgg3Counters.zen === 2 && window.easterEgg3Counters.fast === 3 && window.easterEgg3Counters.seek === 1 && !window.easterEgg3Active) {
+ window.easterEgg3Active = true;
+ // Show easterEgg3 asset centered and above all
+ if (window.easterEgg3Container && window.easterEgg3Container.parent) {
+ window.easterEgg3Container.parent.removeChild(window.easterEgg3Container);
+ }
+ window.easterEgg3Container = new Container();
+ var egg3 = LK.getAsset('easterEgg3', {
+ anchorX: 0.5,
+ anchorY: 0.5,
+ x: 2048 / 2,
+ y: 2732 / 2,
+ scaleX: 1,
+ scaleY: 1,
+ alpha: 0
+ });
+ window.easterEgg3Container.addChild(egg3);
+ // Fade in
+ tween(egg3, {
+ alpha: 1
+ }, {
+ duration: 600
+ });
+ // Add to records screen
+ if (typeof game !== "undefined" && game.children && game.children.indexOf(self) !== -1) {
+ self.addChild(window.easterEgg3Container);
+ } else if (typeof game !== "undefined") {
+ game.addChild(window.easterEgg3Container);
+ }
+ // Fade out and remove after 5 seconds
+ LK.setTimeout(function () {
+ tween(egg3, {
+ alpha: 0
+ }, {
+ duration: 500
+ });
+ LK.setTimeout(function () {
+ if (window.easterEgg3Container && window.easterEgg3Container.parent) {
+ window.easterEgg3Container.parent.removeChild(window.easterEgg3Container);
+ }
+ window.easterEgg3Container = null;
+ window.easterEgg3Active = false;
+ // Reset counters so it can be triggered again
+ window.easterEgg3Counters.zen = 0;
+ window.easterEgg3Counters.fast = 0;
+ window.easterEgg3Counters.seek = 0;
+ }, 600);
+ }, 5000);
}
};
return button;
}
- self.addChild(createModeButton("Zen Mode", highScoreClassic, 0x00AA00, 800, 'zen'));
- self.addChild(createModeButton("Fast Mode", highScoreFast, 0x0088FF, 1100, 'fast'));
- self.addChild(createModeButton("Seek Mode", highScoreSeek, 0xDD5500, 1400, 'seek'));
+ self.addChild(createModeButton("Zen Mode", highScoreClassic, 0x00AA00, 800));
+ self.addChild(createModeButton("Fast Mode", highScoreFast, 0x0088FF, 1100));
+ self.addChild(createModeButton("Seek Mode", highScoreSeek, 0xDD5500, 1400));
};
// Refresh scores when created
self.refreshHighScores();
// Back button
@@ -1481,13 +1541,8 @@
recordsScreen.refreshHighScores();
}
game.addChild(recordsScreen);
}
-// Easter egg variables to track taps on high scores
-var easterEgg3ZenTaps = 0;
-var easterEgg3SeekTaps = 0;
-var easterEgg3FastTaps = 0;
-var easterEgg3Active = false;
// --- COSMETICS: Track selected cosmetic set globally and persistently ---
// Load selectedSet from storage if available, otherwise default to 1
var selectedSet = typeof storage.selectedSet === "number" ? storage.selectedSet : 1;
storage.selectedSet = selectedSet; // Ensure it's always persisted on load
@@ -3453,54 +3508,8 @@
game.musicInterval = null;
// Stop any currently playing music
LK.stopMusic();
}
- // Function to show Easter Egg 3
- var showEasterEgg3 = function showEasterEgg3() {
- // Create easter egg container
- var easterEgg3Container = new Container();
- // Create easter egg image
- var egg = LK.getAsset('easterEgg3', {
- anchorX: 0.5,
- anchorY: 0.5,
- x: 2048 / 2,
- y: 2732 / 2,
- scaleX: 1,
- scaleY: 1,
- alpha: 0
- });
- easterEgg3Container.addChild(egg);
- // Fade in the easter egg
- tween(egg, {
- alpha: 1
- }, {
- duration: 600
- });
- // Play explosion sound for effect
- LK.getSound('Explosion').play();
- // Add to game
- game.addChild(easterEgg3Container);
- // Set timeout to remove the easter egg after 5 seconds
- LK.setTimeout(function () {
- // Fade out
- tween(egg, {
- alpha: 0
- }, {
- duration: 500,
- onFinish: function onFinish() {
- if (easterEgg3Container.parent) {
- game.removeChild(easterEgg3Container);
- }
- easterEgg3Container = null;
- easterEgg3Active = false;
- // Reset tap counters
- easterEgg3ZenTaps = 0;
- easterEgg3SeekTaps = 0;
- easterEgg3FastTaps = 0;
- }
- });
- }, 5000);
- };
// For Fast Mode, show a custom high score popup instead of the game over screen
if (game.gameMode === 'fast') {
// Create popup container
var popupContainer = new Container();
la figura de una casa color blanca simple para una interfaz. In-Game asset. 2d. High contrast. No shadows
haz el fondo color morado
circular check logo. In-Game asset. 2d. High contrast. No shadows
Cuadrado con los bordes redondeado negro. In-Game asset. 2d. High contrast. No shadows
hazlo un gris claro
Que sea blanco
Que sea blanco